feat(api): seed the starting sword as a real, equipped CharacterItem
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { Character } from '../../characters/entities/character.entity';
|
import { Character } from '../../characters/entities/character.entity';
|
||||||
|
import { CharacterEquipment } from '../../equipment/entities/character-equipment.entity';
|
||||||
|
import { CharacterItem } from '../../items/entities/character-item.entity';
|
||||||
import { ItemDefinition } from '../../items/entities/item-definition.entity';
|
import { ItemDefinition } from '../../items/entities/item-definition.entity';
|
||||||
import { LootTableEntry } from '../../loot/entities/loot-table-entry.entity';
|
import { LootTableEntry } from '../../loot/entities/loot-table-entry.entity';
|
||||||
import { LootTable } from '../../loot/entities/loot-table.entity';
|
import { LootTable } from '../../loot/entities/loot-table.entity';
|
||||||
@@ -7,6 +9,7 @@ import { LocationMonster } from '../../monsters/entities/location-monster.entity
|
|||||||
import { MonsterDefinition } from '../../monsters/entities/monster-definition.entity';
|
import { MonsterDefinition } from '../../monsters/entities/monster-definition.entity';
|
||||||
import { LocationConnection } from '../../world/entities/location-connection.entity';
|
import { LocationConnection } from '../../world/entities/location-connection.entity';
|
||||||
import { LocationDefinition } from '../../world/entities/location-definition.entity';
|
import { LocationDefinition } from '../../world/entities/location-definition.entity';
|
||||||
|
import { DEMO_CHARACTER_STARTING_WEAPON_ITEM_ID } from '../../demo/demo-character.constants';
|
||||||
import { ASH_RAT_LOOT_TABLE_ID, ITEM_IDS, ROAD_BANDIT_LOOT_TABLE_ID } from './item.constants';
|
import { ASH_RAT_LOOT_TABLE_ID, ITEM_IDS, ROAD_BANDIT_LOOT_TABLE_ID } from './item.constants';
|
||||||
import { seedVisibleVerticalSlice } from './vertical-slice.seed';
|
import { seedVisibleVerticalSlice } from './vertical-slice.seed';
|
||||||
|
|
||||||
@@ -74,6 +77,8 @@ function createDataSource(
|
|||||||
itemRepository: InMemoryRepository = new InMemoryRepository(),
|
itemRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
lootTableRepository: InMemoryRepository = new InMemoryRepository(),
|
lootTableRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
lootEntryRepository: InMemoryRepository = new InMemoryRepository(),
|
lootEntryRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
|
characterItemRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
|
characterEquipmentRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
): DataSource {
|
): DataSource {
|
||||||
return {
|
return {
|
||||||
getRepository: jest.fn((entity: unknown) => {
|
getRepository: jest.fn((entity: unknown) => {
|
||||||
@@ -85,6 +90,8 @@ function createDataSource(
|
|||||||
if (entity === ItemDefinition) return itemRepository;
|
if (entity === ItemDefinition) return itemRepository;
|
||||||
if (entity === LootTable) return lootTableRepository;
|
if (entity === LootTable) return lootTableRepository;
|
||||||
if (entity === LootTableEntry) return lootEntryRepository;
|
if (entity === LootTableEntry) return lootEntryRepository;
|
||||||
|
if (entity === CharacterItem) return characterItemRepository;
|
||||||
|
if (entity === CharacterEquipment) return characterEquipmentRepository;
|
||||||
|
|
||||||
throw new Error('Unexpected repository');
|
throw new Error('Unexpected repository');
|
||||||
}),
|
}),
|
||||||
@@ -336,4 +343,80 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('seeds the starting sword as a real, equipped CharacterItem idempotently', async () => {
|
||||||
|
const locationRepository = new InMemoryRepository();
|
||||||
|
const connectionRepository = new InMemoryRepository();
|
||||||
|
const characterRepository = new InMemoryRepository();
|
||||||
|
const monsterRepository = new InMemoryRepository();
|
||||||
|
const locationMonsterRepository = new InMemoryRepository();
|
||||||
|
const characterItemRepository = new InMemoryRepository();
|
||||||
|
const characterEquipmentRepository = new InMemoryRepository();
|
||||||
|
const dataSource = createDataSource(
|
||||||
|
locationRepository,
|
||||||
|
connectionRepository,
|
||||||
|
characterRepository,
|
||||||
|
monsterRepository,
|
||||||
|
locationMonsterRepository,
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
characterItemRepository,
|
||||||
|
characterEquipmentRepository,
|
||||||
|
);
|
||||||
|
|
||||||
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
|
||||||
|
expect(characterItemRepository.rows).toHaveLength(1);
|
||||||
|
expect(characterItemRepository.rows[0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
characterId: DEMO_CHARACTER_ID,
|
||||||
|
itemDefinitionId: ITEM_IDS['worn-short-sword'],
|
||||||
|
quantity: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(characterEquipmentRepository.rows).toHaveLength(1);
|
||||||
|
expect(characterEquipmentRepository.rows[0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
characterId: DEMO_CHARACTER_ID,
|
||||||
|
slot: 'WEAPON',
|
||||||
|
characterItemId: DEMO_CHARACTER_STARTING_WEAPON_ITEM_ID,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('never re-equips the starting sword once the player has equipped different gear', async () => {
|
||||||
|
const locationRepository = new InMemoryRepository();
|
||||||
|
const connectionRepository = new InMemoryRepository();
|
||||||
|
const characterRepository = new InMemoryRepository();
|
||||||
|
const monsterRepository = new InMemoryRepository();
|
||||||
|
const locationMonsterRepository = new InMemoryRepository();
|
||||||
|
const characterItemRepository = new InMemoryRepository();
|
||||||
|
const characterEquipmentRepository = new InMemoryRepository();
|
||||||
|
const dataSource = createDataSource(
|
||||||
|
locationRepository,
|
||||||
|
connectionRepository,
|
||||||
|
characterRepository,
|
||||||
|
monsterRepository,
|
||||||
|
locationMonsterRepository,
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
characterItemRepository,
|
||||||
|
characterEquipmentRepository,
|
||||||
|
);
|
||||||
|
|
||||||
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
// Simulate the player having equipped earned loot instead.
|
||||||
|
characterEquipmentRepository.rows[0]['characterItemId'] = 'earned-bandit-blade-item-id';
|
||||||
|
|
||||||
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
|
||||||
|
expect(characterEquipmentRepository.rows).toHaveLength(1);
|
||||||
|
expect(characterEquipmentRepository.rows[0]['characterItemId']).toBe(
|
||||||
|
'earned-bandit-blade-item-id',
|
||||||
|
);
|
||||||
|
expect(characterItemRepository.rows).toHaveLength(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { DEMO_CHARACTER_ID } from '../../demo/demo-character.constants';
|
import {
|
||||||
|
DEMO_CHARACTER_ID,
|
||||||
|
DEMO_CHARACTER_STARTING_WEAPON_EQUIPMENT_ID,
|
||||||
|
DEMO_CHARACTER_STARTING_WEAPON_ITEM_ID,
|
||||||
|
} from '../../demo/demo-character.constants';
|
||||||
import { Character } from '../../characters/entities/character.entity';
|
import { Character } from '../../characters/entities/character.entity';
|
||||||
|
import { CharacterEquipment } from '../../equipment/entities/character-equipment.entity';
|
||||||
|
import { CharacterItem } from '../../items/entities/character-item.entity';
|
||||||
|
import { EquipmentSlot } from '../../items/equipment-slot.enum';
|
||||||
import { ItemDefinition } from '../../items/entities/item-definition.entity';
|
import { ItemDefinition } from '../../items/entities/item-definition.entity';
|
||||||
import { LootTableEntry } from '../../loot/entities/loot-table-entry.entity';
|
import { LootTableEntry } from '../../loot/entities/loot-table-entry.entity';
|
||||||
import { LootTable } from '../../loot/entities/loot-table.entity';
|
import { LootTable } from '../../loot/entities/loot-table.entity';
|
||||||
@@ -11,6 +18,7 @@ import { LocationConnection } from '../../world/entities/location-connection.ent
|
|||||||
import { LocationDefinition } from '../../world/entities/location-definition.entity';
|
import { LocationDefinition } from '../../world/entities/location-definition.entity';
|
||||||
import {
|
import {
|
||||||
ASH_RAT_LOOT_TABLE_ID,
|
ASH_RAT_LOOT_TABLE_ID,
|
||||||
|
ITEM_IDS,
|
||||||
ROAD_BANDIT_LOOT_TABLE_ID,
|
ROAD_BANDIT_LOOT_TABLE_ID,
|
||||||
} from './item.constants';
|
} from './item.constants';
|
||||||
import { ITEM_DEFINITIONS, LOOT_TABLES, LOOT_TABLE_ENTRIES } from './item-content';
|
import { ITEM_DEFINITIONS, LOOT_TABLES, LOOT_TABLE_ENTRIES } from './item-content';
|
||||||
@@ -205,4 +213,32 @@ export async function seedVisibleVerticalSlice(
|
|||||||
currentLocationId: southGateId,
|
currentLocationId: southGateId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const characterItemRepository = dataSource.getRepository(CharacterItem);
|
||||||
|
const characterEquipmentRepository = dataSource.getRepository(CharacterEquipment);
|
||||||
|
|
||||||
|
const existingStartingSword = await characterItemRepository.findOneBy({
|
||||||
|
id: DEMO_CHARACTER_STARTING_WEAPON_ITEM_ID,
|
||||||
|
});
|
||||||
|
if (!existingStartingSword) {
|
||||||
|
await characterItemRepository.insert({
|
||||||
|
id: DEMO_CHARACTER_STARTING_WEAPON_ITEM_ID,
|
||||||
|
characterId: DEMO_CHARACTER_ID,
|
||||||
|
itemDefinitionId: ITEM_IDS['worn-short-sword'],
|
||||||
|
quantity: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingWeaponEquipment = await characterEquipmentRepository.findOneBy({
|
||||||
|
characterId: DEMO_CHARACTER_ID,
|
||||||
|
slot: EquipmentSlot.WEAPON,
|
||||||
|
});
|
||||||
|
if (!existingWeaponEquipment) {
|
||||||
|
await characterEquipmentRepository.insert({
|
||||||
|
id: DEMO_CHARACTER_STARTING_WEAPON_EQUIPMENT_ID,
|
||||||
|
characterId: DEMO_CHARACTER_ID,
|
||||||
|
slot: EquipmentSlot.WEAPON,
|
||||||
|
characterItemId: DEMO_CHARACTER_STARTING_WEAPON_ITEM_ID,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,5 @@
|
|||||||
export const DEMO_CHARACTER_ID = '10000000-0000-4000-8000-000000000001';
|
export const DEMO_CHARACTER_ID = '10000000-0000-4000-8000-000000000001';
|
||||||
|
export const DEMO_CHARACTER_STARTING_WEAPON_ITEM_ID =
|
||||||
|
'10000000-0000-4000-8000-000000000002';
|
||||||
|
export const DEMO_CHARACTER_STARTING_WEAPON_EQUIPMENT_ID =
|
||||||
|
'10000000-0000-4000-8000-000000000003';
|
||||||
|
|||||||
Reference in New Issue
Block a user