feat(content): migrate ItemType, seed Räuberabzeichen/Grenzwacht/turn-ins, zero direct monster rewards
This commit is contained in:
@@ -17,7 +17,6 @@ export interface SeedItemDefinition {
|
|||||||
equipmentSlot: EquipmentSlot | null;
|
equipmentSlot: EquipmentSlot | null;
|
||||||
rarity: ItemRarity;
|
rarity: ItemRarity;
|
||||||
tier: number;
|
tier: number;
|
||||||
requiredLevel: number;
|
|
||||||
weaponDamage: number;
|
weaponDamage: number;
|
||||||
bonusHp: number;
|
bonusHp: number;
|
||||||
bonusAttack: number;
|
bonusAttack: number;
|
||||||
@@ -33,7 +32,12 @@ function item(
|
|||||||
type: ItemType,
|
type: ItemType,
|
||||||
equipmentSlot: EquipmentSlot | null,
|
equipmentSlot: EquipmentSlot | null,
|
||||||
rarity: ItemRarity,
|
rarity: ItemRarity,
|
||||||
stats: Partial<Pick<SeedItemDefinition, 'weaponDamage' | 'bonusHp' | 'bonusAttack' | 'bonusArmor'>> = {},
|
stats: Partial<
|
||||||
|
Pick<
|
||||||
|
SeedItemDefinition,
|
||||||
|
'weaponDamage' | 'bonusHp' | 'bonusAttack' | 'bonusArmor'
|
||||||
|
>
|
||||||
|
> = {},
|
||||||
): SeedItemDefinition {
|
): SeedItemDefinition {
|
||||||
return {
|
return {
|
||||||
id: ITEM_IDS[key],
|
id: ITEM_IDS[key],
|
||||||
@@ -44,7 +48,6 @@ function item(
|
|||||||
equipmentSlot,
|
equipmentSlot,
|
||||||
rarity,
|
rarity,
|
||||||
tier: 1,
|
tier: 1,
|
||||||
requiredLevel: 1,
|
|
||||||
weaponDamage: stats.weaponDamage ?? 0,
|
weaponDamage: stats.weaponDamage ?? 0,
|
||||||
bonusHp: stats.bonusHp ?? 0,
|
bonusHp: stats.bonusHp ?? 0,
|
||||||
bonusAttack: stats.bonusAttack ?? 0,
|
bonusAttack: stats.bonusAttack ?? 0,
|
||||||
@@ -62,7 +65,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'worn-short-sword',
|
'worn-short-sword',
|
||||||
'Abgenutztes Kurzschwert',
|
'Abgenutztes Kurzschwert',
|
||||||
'Die Klinge eines Rekruten, öfter geschliffen als geführt.',
|
'Die Klinge eines Rekruten, öfter geschliffen als geführt.',
|
||||||
ItemType.WEAPON,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.WEAPON,
|
EquipmentSlot.WEAPON,
|
||||||
ItemRarity.COMMON,
|
ItemRarity.COMMON,
|
||||||
{ weaponDamage: 8 },
|
{ weaponDamage: 8 },
|
||||||
@@ -71,7 +74,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'bandit-blade',
|
'bandit-blade',
|
||||||
'Räuberklinge',
|
'Räuberklinge',
|
||||||
'Eine grob gezahnte Klinge, geschmiedet für schnelle Überfälle.',
|
'Eine grob gezahnte Klinge, geschmiedet für schnelle Überfälle.',
|
||||||
ItemType.WEAPON,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.WEAPON,
|
EquipmentSlot.WEAPON,
|
||||||
ItemRarity.COMMON,
|
ItemRarity.COMMON,
|
||||||
{ weaponDamage: 11, bonusAttack: 1 },
|
{ weaponDamage: 11, bonusAttack: 1 },
|
||||||
@@ -80,7 +83,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'ash-blade',
|
'ash-blade',
|
||||||
'Aschenklinge',
|
'Aschenklinge',
|
||||||
'In der Glut der Aschenfelder gehärtet; die Schneide glimmt noch.',
|
'In der Glut der Aschenfelder gehärtet; die Schneide glimmt noch.',
|
||||||
ItemType.WEAPON,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.WEAPON,
|
EquipmentSlot.WEAPON,
|
||||||
ItemRarity.RARE,
|
ItemRarity.RARE,
|
||||||
{ weaponDamage: 15, bonusAttack: 2 },
|
{ weaponDamage: 15, bonusAttack: 2 },
|
||||||
@@ -89,7 +92,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'bandit-hood',
|
'bandit-hood',
|
||||||
'Räuberhaube',
|
'Räuberhaube',
|
||||||
'Vernarbtes Leder, das Gesicht und Absicht des Trägers verbirgt.',
|
'Vernarbtes Leder, das Gesicht und Absicht des Trägers verbirgt.',
|
||||||
ItemType.ARMOR,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.HEAD,
|
EquipmentSlot.HEAD,
|
||||||
ItemRarity.COMMON,
|
ItemRarity.COMMON,
|
||||||
{ bonusArmor: 3, bonusHp: 5 },
|
{ bonusArmor: 3, bonusHp: 5 },
|
||||||
@@ -98,7 +101,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'reinforced-leather-jacket',
|
'reinforced-leather-jacket',
|
||||||
'Verstärkte Lederjacke',
|
'Verstärkte Lederjacke',
|
||||||
'Mit Eisenplatten benähtes Leder, schwer und verlässlich.',
|
'Mit Eisenplatten benähtes Leder, schwer und verlässlich.',
|
||||||
ItemType.ARMOR,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.CHEST,
|
EquipmentSlot.CHEST,
|
||||||
ItemRarity.RARE,
|
ItemRarity.RARE,
|
||||||
{ bonusArmor: 7, bonusHp: 10 },
|
{ bonusArmor: 7, bonusHp: 10 },
|
||||||
@@ -107,7 +110,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'raider-gloves',
|
'raider-gloves',
|
||||||
'Plündererhandschuhe',
|
'Plündererhandschuhe',
|
||||||
'Beschlagene Handschuhe, abgegriffen von fremdem Gut.',
|
'Beschlagene Handschuhe, abgegriffen von fremdem Gut.',
|
||||||
ItemType.ARMOR,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.HANDS,
|
EquipmentSlot.HANDS,
|
||||||
ItemRarity.COMMON,
|
ItemRarity.COMMON,
|
||||||
{ bonusArmor: 3, bonusAttack: 1 },
|
{ bonusArmor: 3, bonusAttack: 1 },
|
||||||
@@ -116,7 +119,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'guardsman-legs',
|
'guardsman-legs',
|
||||||
'Wachmannsbeinkleid',
|
'Wachmannsbeinkleid',
|
||||||
'Beinzeug der Grenzwacht, an den Knien geflickt.',
|
'Beinzeug der Grenzwacht, an den Knien geflickt.',
|
||||||
ItemType.ARMOR,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.LEGS,
|
EquipmentSlot.LEGS,
|
||||||
ItemRarity.RARE,
|
ItemRarity.RARE,
|
||||||
{ bonusArmor: 5, bonusHp: 5 },
|
{ bonusArmor: 5, bonusHp: 5 },
|
||||||
@@ -125,7 +128,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'ash-boots',
|
'ash-boots',
|
||||||
'Aschenstiefel',
|
'Aschenstiefel',
|
||||||
'Stiefel, die durch glimmende Felder getragen wurden und blieben.',
|
'Stiefel, die durch glimmende Felder getragen wurden und blieben.',
|
||||||
ItemType.ARMOR,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.FEET,
|
EquipmentSlot.FEET,
|
||||||
ItemRarity.RARE,
|
ItemRarity.RARE,
|
||||||
{ bonusArmor: 4, bonusHp: 5 },
|
{ bonusArmor: 4, bonusHp: 5 },
|
||||||
@@ -134,7 +137,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'borderwatch-sigil',
|
'borderwatch-sigil',
|
||||||
'Zeichen der Grenzwacht',
|
'Zeichen der Grenzwacht',
|
||||||
'Das Wappen eines Turms, den es nicht mehr gibt.',
|
'Das Wappen eines Turms, den es nicht mehr gibt.',
|
||||||
ItemType.ARMOR,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.AMULET,
|
EquipmentSlot.AMULET,
|
||||||
ItemRarity.RARE,
|
ItemRarity.RARE,
|
||||||
{ bonusAttack: 3, bonusHp: 10 },
|
{ bonusAttack: 3, bonusHp: 10 },
|
||||||
@@ -143,7 +146,7 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
'burned-captain-pendant',
|
'burned-captain-pendant',
|
||||||
'Anhänger des verbrannten Hauptmanns',
|
'Anhänger des verbrannten Hauptmanns',
|
||||||
'Ein Schädel aus Schlacke, in dem die Glut nie erlosch.',
|
'Ein Schädel aus Schlacke, in dem die Glut nie erlosch.',
|
||||||
ItemType.ARMOR,
|
ItemType.EQUIPMENT,
|
||||||
EquipmentSlot.AMULET,
|
EquipmentSlot.AMULET,
|
||||||
ItemRarity.EPIC,
|
ItemRarity.EPIC,
|
||||||
{ bonusAttack: 3, bonusHp: 15, bonusArmor: 2 },
|
{ bonusAttack: 3, bonusHp: 15, bonusArmor: 2 },
|
||||||
@@ -158,11 +161,21 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
null,
|
null,
|
||||||
ItemRarity.COMMON,
|
ItemRarity.COMMON,
|
||||||
),
|
),
|
||||||
|
// A Trade Good (spec §17): turned in to the Grenzwacht for Silver and
|
||||||
|
// reputation rather than crafted with.
|
||||||
item(
|
item(
|
||||||
'ash-pelt',
|
'ash-pelt',
|
||||||
'Aschenfell',
|
'Aschenfell',
|
||||||
'Versengtes Fell, zäh wie Leder und grau von Ascheflug.',
|
'Versengtes Fell, zäh wie Leder und grau von Ascheflug.',
|
||||||
ItemType.MATERIAL,
|
ItemType.TRADE_GOOD,
|
||||||
|
null,
|
||||||
|
ItemRarity.COMMON,
|
||||||
|
),
|
||||||
|
item(
|
||||||
|
'bandit-insignia',
|
||||||
|
'Räuberabzeichen',
|
||||||
|
'Ein grob geprägtes Zeichen, das einen Straßenräuber als Mitglied seiner Bande auswies.',
|
||||||
|
ItemType.TROPHY,
|
||||||
null,
|
null,
|
||||||
ItemRarity.COMMON,
|
ItemRarity.COMMON,
|
||||||
),
|
),
|
||||||
@@ -170,7 +183,11 @@ export const ITEM_DEFINITIONS: SeedItemDefinition[] = [
|
|||||||
|
|
||||||
export const LOOT_TABLES = [
|
export const LOOT_TABLES = [
|
||||||
{ id: ASH_RAT_LOOT_TABLE_ID, key: 'ash-rat-loot', name: 'Aschenratte Beute' },
|
{ id: ASH_RAT_LOOT_TABLE_ID, key: 'ash-rat-loot', name: 'Aschenratte Beute' },
|
||||||
{ id: ROAD_BANDIT_LOOT_TABLE_ID, key: 'road-bandit-loot', name: 'Straßenräuber Beute' },
|
{
|
||||||
|
id: ROAD_BANDIT_LOOT_TABLE_ID,
|
||||||
|
key: 'road-bandit-loot',
|
||||||
|
name: 'Straßenräuber Beute',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export interface SeedLootTableEntry {
|
export interface SeedLootTableEntry {
|
||||||
@@ -213,4 +230,5 @@ export const LOOT_TABLE_ENTRIES: SeedLootTableEntry[] = [
|
|||||||
entry(ROAD_BANDIT_LOOT_TABLE_ID, 'bandit-blade', 1, '0.1800'),
|
entry(ROAD_BANDIT_LOOT_TABLE_ID, 'bandit-blade', 1, '0.1800'),
|
||||||
entry(ROAD_BANDIT_LOOT_TABLE_ID, 'bandit-hood', 2, '0.1200'),
|
entry(ROAD_BANDIT_LOOT_TABLE_ID, 'bandit-hood', 2, '0.1200'),
|
||||||
entry(ROAD_BANDIT_LOOT_TABLE_ID, 'raider-gloves', 3, '0.0800'),
|
entry(ROAD_BANDIT_LOOT_TABLE_ID, 'raider-gloves', 3, '0.0800'),
|
||||||
|
entry(ROAD_BANDIT_LOOT_TABLE_ID, 'bandit-insignia', 4, '0.4000'),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export const ITEM_IDS = {
|
|||||||
'burned-captain-pendant': '50000000-0000-4000-8000-00000000000a',
|
'burned-captain-pendant': '50000000-0000-4000-8000-00000000000a',
|
||||||
'small-healing-potion': '50000000-0000-4000-8000-00000000000b',
|
'small-healing-potion': '50000000-0000-4000-8000-00000000000b',
|
||||||
'ash-pelt': '50000000-0000-4000-8000-00000000000c',
|
'ash-pelt': '50000000-0000-4000-8000-00000000000c',
|
||||||
|
'bandit-insignia': '50000000-0000-4000-8000-00000000000d',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type ItemKey = keyof typeof ITEM_IDS;
|
export type ItemKey = keyof typeof ITEM_IDS;
|
||||||
|
|||||||
25
apps/api/src/database/seeds/reputation-content.ts
Normal file
25
apps/api/src/database/seeds/reputation-content.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
export const BORDER_GUARD_FACTION_ID = '80000000-0000-4000-8000-000000000001';
|
||||||
|
|
||||||
|
export interface SeedReputationFaction {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
regionKey: string;
|
||||||
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only Grenzwacht is seeded and usable in Slice 0.6.5 (spec §8). Dämmerjäger
|
||||||
|
// ('dusk-hunters') and Letzte Wacht ('last-watch') are future-region keys,
|
||||||
|
// intentionally not seeded yet.
|
||||||
|
export const REPUTATION_FACTIONS: SeedReputationFaction[] = [
|
||||||
|
{
|
||||||
|
id: BORDER_GUARD_FACTION_ID,
|
||||||
|
key: 'border-guard',
|
||||||
|
name: 'Grenzwacht',
|
||||||
|
description:
|
||||||
|
'Die letzten organisierten Wächter der Aschenfelder, die verbliebene Handelsrouten und Außenposten schützen.',
|
||||||
|
regionKey: 'ashen-fields',
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
38
apps/api/src/database/seeds/turn-in-content.ts
Normal file
38
apps/api/src/database/seeds/turn-in-content.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { ITEM_IDS } from './item.constants';
|
||||||
|
import { BORDER_GUARD_FACTION_ID } from './reputation-content';
|
||||||
|
|
||||||
|
export interface SeedTurnInDefinition {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
itemDefinitionId: string;
|
||||||
|
factionId: string;
|
||||||
|
silverRewardPerItem: number;
|
||||||
|
reputationRewardPerItem: number;
|
||||||
|
repeatable: boolean;
|
||||||
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial development values (spec §21), kept in content so they can be
|
||||||
|
// tuned without touching TurnInService's logic (spec §42).
|
||||||
|
export const TURN_IN_DEFINITIONS: SeedTurnInDefinition[] = [
|
||||||
|
{
|
||||||
|
id: '90000000-0000-4000-8000-000000000001',
|
||||||
|
key: 'ash-pelt-border-guard',
|
||||||
|
itemDefinitionId: ITEM_IDS['ash-pelt'],
|
||||||
|
factionId: BORDER_GUARD_FACTION_ID,
|
||||||
|
silverRewardPerItem: 4,
|
||||||
|
reputationRewardPerItem: 1,
|
||||||
|
repeatable: true,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '90000000-0000-4000-8000-000000000002',
|
||||||
|
key: 'bandit-insignia-border-guard',
|
||||||
|
itemDefinitionId: ITEM_IDS['bandit-insignia'],
|
||||||
|
factionId: BORDER_GUARD_FACTION_ID,
|
||||||
|
silverRewardPerItem: 12,
|
||||||
|
reputationRewardPerItem: 4,
|
||||||
|
repeatable: true,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -9,8 +9,14 @@ 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 { ReputationFaction } from '../../reputation/entities/reputation-faction.entity';
|
||||||
|
import { TurnInDefinition } from '../../turn-in/entities/turn-in-definition.entity';
|
||||||
import { DEMO_CHARACTER_STARTING_WEAPON_ITEM_ID } from '../../demo/demo-character.constants';
|
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';
|
||||||
|
|
||||||
type Row = Record<string, unknown>;
|
type Row = Record<string, unknown>;
|
||||||
@@ -81,6 +87,8 @@ function createDataSource(
|
|||||||
lootEntryRepository: InMemoryRepository = new InMemoryRepository(),
|
lootEntryRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
characterItemRepository: InMemoryRepository = new InMemoryRepository(),
|
characterItemRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
characterEquipmentRepository: InMemoryRepository = new InMemoryRepository(),
|
characterEquipmentRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
|
reputationFactionRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
|
turnInDefinitionRepository: InMemoryRepository = new InMemoryRepository(),
|
||||||
): DataSource {
|
): DataSource {
|
||||||
return {
|
return {
|
||||||
getRepository: jest.fn((entity: unknown) => {
|
getRepository: jest.fn((entity: unknown) => {
|
||||||
@@ -94,6 +102,8 @@ function createDataSource(
|
|||||||
if (entity === LootTableEntry) return lootEntryRepository;
|
if (entity === LootTableEntry) return lootEntryRepository;
|
||||||
if (entity === CharacterItem) return characterItemRepository;
|
if (entity === CharacterItem) return characterItemRepository;
|
||||||
if (entity === CharacterEquipment) return characterEquipmentRepository;
|
if (entity === CharacterEquipment) return characterEquipmentRepository;
|
||||||
|
if (entity === ReputationFaction) return reputationFactionRepository;
|
||||||
|
if (entity === TurnInDefinition) return turnInDefinitionRepository;
|
||||||
|
|
||||||
throw new Error('Unexpected repository');
|
throw new Error('Unexpected repository');
|
||||||
}),
|
}),
|
||||||
@@ -119,7 +129,7 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
Object.assign(characterRepository.rows[0], {
|
Object.assign(characterRepository.rows[0], {
|
||||||
currentLocationId: BURNED_ROAD_ID,
|
currentLocationId: BURNED_ROAD_ID,
|
||||||
currentHp: 57,
|
currentHp: 57,
|
||||||
experience: 39,
|
renown: 1,
|
||||||
});
|
});
|
||||||
await seedVisibleVerticalSlice(dataSource);
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
|
||||||
@@ -158,7 +168,7 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
currentLocationId: BURNED_ROAD_ID,
|
currentLocationId: BURNED_ROAD_ID,
|
||||||
currentHp: 57,
|
currentHp: 57,
|
||||||
experience: 39,
|
renown: 1,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -173,9 +183,8 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
maxHp: 45,
|
maxHp: 45,
|
||||||
attack: 5,
|
attack: 5,
|
||||||
armor: 0,
|
armor: 0,
|
||||||
experienceReward: 8,
|
silverMin: 0,
|
||||||
silverMin: 4,
|
silverMax: 0,
|
||||||
silverMax: 7,
|
|
||||||
artworkPath: '/images/monsters/ash-rat.png',
|
artworkPath: '/images/monsters/ash-rat.png',
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -185,9 +194,8 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
maxHp: 75,
|
maxHp: 75,
|
||||||
attack: 9,
|
attack: 9,
|
||||||
armor: 5,
|
armor: 5,
|
||||||
experienceReward: 16,
|
silverMin: 0,
|
||||||
silverMin: 9,
|
silverMax: 0,
|
||||||
silverMax: 15,
|
|
||||||
artworkPath: '/images/monsters/road-bandit.png',
|
artworkPath: '/images/monsters/road-bandit.png',
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -400,13 +408,13 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
await seedVisibleVerticalSlice(dataSource);
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
await seedVisibleVerticalSlice(dataSource);
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
|
||||||
expect(itemRepository.rows).toHaveLength(12);
|
expect(itemRepository.rows).toHaveLength(13);
|
||||||
expect(itemRepository.rows).toEqual(
|
expect(itemRepository.rows).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
key: 'bandit-blade',
|
key: 'bandit-blade',
|
||||||
name: 'Räuberklinge',
|
name: 'Räuberklinge',
|
||||||
type: 'WEAPON',
|
type: 'EQUIPMENT',
|
||||||
equipmentSlot: 'WEAPON',
|
equipmentSlot: 'WEAPON',
|
||||||
rarity: 'COMMON',
|
rarity: 'COMMON',
|
||||||
weaponDamage: 11,
|
weaponDamage: 11,
|
||||||
@@ -417,14 +425,20 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
key: 'ash-pelt',
|
key: 'ash-pelt',
|
||||||
name: 'Aschenfell',
|
name: 'Aschenfell',
|
||||||
type: 'MATERIAL',
|
type: 'TRADE_GOOD',
|
||||||
|
equipmentSlot: null,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: 'bandit-insignia',
|
||||||
|
name: 'Räuberabzeichen',
|
||||||
|
type: 'TROPHY',
|
||||||
equipmentSlot: null,
|
equipmentSlot: null,
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(lootTableRepository.rows).toHaveLength(2);
|
expect(lootTableRepository.rows).toHaveLength(2);
|
||||||
expect(lootEntryRepository.rows).toHaveLength(5);
|
expect(lootEntryRepository.rows).toHaveLength(6);
|
||||||
expect(lootEntryRepository.rows).toEqual(
|
expect(lootEntryRepository.rows).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -451,8 +465,14 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
|
|
||||||
expect(monsterRepository.rows).toEqual(
|
expect(monsterRepository.rows).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({ key: 'ash-rat', lootTableId: ASH_RAT_LOOT_TABLE_ID }),
|
expect.objectContaining({
|
||||||
expect.objectContaining({ key: 'road-bandit', lootTableId: ROAD_BANDIT_LOOT_TABLE_ID }),
|
key: 'ash-rat',
|
||||||
|
lootTableId: ASH_RAT_LOOT_TABLE_ID,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
key: 'road-bandit',
|
||||||
|
lootTableId: ROAD_BANDIT_LOOT_TABLE_ID,
|
||||||
|
}),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -522,7 +542,8 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
|
|
||||||
await seedVisibleVerticalSlice(dataSource);
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
// Simulate the player having equipped earned loot instead.
|
// Simulate the player having equipped earned loot instead.
|
||||||
characterEquipmentRepository.rows[0]['characterItemId'] = 'earned-bandit-blade-item-id';
|
characterEquipmentRepository.rows[0]['characterItemId'] =
|
||||||
|
'earned-bandit-blade-item-id';
|
||||||
|
|
||||||
await seedVisibleVerticalSlice(dataSource);
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
|
||||||
@@ -577,4 +598,53 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('seeds the Grenzwacht faction', async () => {
|
||||||
|
const reputationFactionRepository = new InMemoryRepository();
|
||||||
|
const dataSource = createDataSource(
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
reputationFactionRepository,
|
||||||
|
);
|
||||||
|
|
||||||
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
|
||||||
|
const faction = await dataSource
|
||||||
|
.getRepository(ReputationFaction)
|
||||||
|
.findOneBy({ key: 'border-guard' });
|
||||||
|
|
||||||
|
expect(faction).toMatchObject({ name: 'Grenzwacht', enabled: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('seeds both turn-in definitions', async () => {
|
||||||
|
const turnInDefinitionRepository = new InMemoryRepository();
|
||||||
|
const dataSource = createDataSource(
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
new InMemoryRepository(),
|
||||||
|
turnInDefinitionRepository,
|
||||||
|
);
|
||||||
|
|
||||||
|
await seedVisibleVerticalSlice(dataSource);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
turnInDefinitionRepository.rows.map((row: Row) => row.key).sort(),
|
||||||
|
).toEqual(['ash-pelt-border-guard', 'bandit-insignia-border-guard']);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ 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 { ITEM_DEFINITIONS, LOOT_TABLES, LOOT_TABLE_ENTRIES } from './item-content';
|
import { ReputationFaction } from '../../reputation/entities/reputation-faction.entity';
|
||||||
|
import { TurnInDefinition } from '../../turn-in/entities/turn-in-definition.entity';
|
||||||
|
import {
|
||||||
|
ITEM_DEFINITIONS,
|
||||||
|
LOOT_TABLES,
|
||||||
|
LOOT_TABLE_ENTRIES,
|
||||||
|
} from './item-content';
|
||||||
import {
|
import {
|
||||||
ASH_RAT_LOOT_TABLE_ID,
|
ASH_RAT_LOOT_TABLE_ID,
|
||||||
ITEM_IDS,
|
ITEM_IDS,
|
||||||
@@ -26,6 +32,8 @@ import {
|
|||||||
BURNED_ROAD_LOCAL_CONTENT,
|
BURNED_ROAD_LOCAL_CONTENT,
|
||||||
SOUTH_GATE_LOCAL_CONTENT,
|
SOUTH_GATE_LOCAL_CONTENT,
|
||||||
} from './local-location.content';
|
} from './local-location.content';
|
||||||
|
import { REPUTATION_FACTIONS } from './reputation-content';
|
||||||
|
import { TURN_IN_DEFINITIONS } from './turn-in-content';
|
||||||
import {
|
import {
|
||||||
ASH_RAT_MONSTER_ID,
|
ASH_RAT_MONSTER_ID,
|
||||||
BURNED_ROAD_ID,
|
BURNED_ROAD_ID,
|
||||||
@@ -46,6 +54,9 @@ export async function seedVisibleVerticalSlice(
|
|||||||
const itemRepository = dataSource.getRepository(ItemDefinition);
|
const itemRepository = dataSource.getRepository(ItemDefinition);
|
||||||
const lootTableRepository = dataSource.getRepository(LootTable);
|
const lootTableRepository = dataSource.getRepository(LootTable);
|
||||||
const lootEntryRepository = dataSource.getRepository(LootTableEntry);
|
const lootEntryRepository = dataSource.getRepository(LootTableEntry);
|
||||||
|
const reputationFactionRepository =
|
||||||
|
dataSource.getRepository(ReputationFaction);
|
||||||
|
const turnInDefinitionRepository = dataSource.getRepository(TurnInDefinition);
|
||||||
|
|
||||||
const locations = [
|
const locations = [
|
||||||
{
|
{
|
||||||
@@ -125,6 +136,8 @@ export async function seedVisibleVerticalSlice(
|
|||||||
'lootTableId',
|
'lootTableId',
|
||||||
'itemDefinitionId',
|
'itemDefinitionId',
|
||||||
]);
|
]);
|
||||||
|
await reputationFactionRepository.upsert(REPUTATION_FACTIONS, ['key']);
|
||||||
|
await turnInDefinitionRepository.upsert(TURN_IN_DEFINITIONS, ['key']);
|
||||||
|
|
||||||
const monsters = [
|
const monsters = [
|
||||||
{
|
{
|
||||||
@@ -135,9 +148,8 @@ export async function seedVisibleVerticalSlice(
|
|||||||
maxHp: 45,
|
maxHp: 45,
|
||||||
attack: 5,
|
attack: 5,
|
||||||
armor: 0,
|
armor: 0,
|
||||||
experienceReward: 8,
|
silverMin: 0,
|
||||||
silverMin: 4,
|
silverMax: 0,
|
||||||
silverMax: 7,
|
|
||||||
artworkPath: '/images/monsters/ash-rat.png',
|
artworkPath: '/images/monsters/ash-rat.png',
|
||||||
iconPath: '/images/combat/icons/ash-rat-128.png',
|
iconPath: '/images/combat/icons/ash-rat-128.png',
|
||||||
lootTableId: ASH_RAT_LOOT_TABLE_ID,
|
lootTableId: ASH_RAT_LOOT_TABLE_ID,
|
||||||
@@ -150,9 +162,8 @@ export async function seedVisibleVerticalSlice(
|
|||||||
maxHp: 55,
|
maxHp: 55,
|
||||||
attack: 7,
|
attack: 7,
|
||||||
armor: 0,
|
armor: 0,
|
||||||
experienceReward: 11,
|
silverMin: 0,
|
||||||
silverMin: 5,
|
silverMax: 0,
|
||||||
silverMax: 9,
|
|
||||||
artworkPath: '/images/monsters/wild-road-dog.png',
|
artworkPath: '/images/monsters/wild-road-dog.png',
|
||||||
iconPath: '/images/combat/icons/wild-road-dog-128.png',
|
iconPath: '/images/combat/icons/wild-road-dog-128.png',
|
||||||
// Shares the beast table: both are scorched road animals that leave a
|
// Shares the beast table: both are scorched road animals that leave a
|
||||||
@@ -167,9 +178,8 @@ export async function seedVisibleVerticalSlice(
|
|||||||
maxHp: 75,
|
maxHp: 75,
|
||||||
attack: 9,
|
attack: 9,
|
||||||
armor: 5,
|
armor: 5,
|
||||||
experienceReward: 16,
|
silverMin: 0,
|
||||||
silverMin: 9,
|
silverMax: 0,
|
||||||
silverMax: 15,
|
|
||||||
artworkPath: '/images/monsters/road-bandit.png',
|
artworkPath: '/images/monsters/road-bandit.png',
|
||||||
iconPath: '/images/combat/icons/road-bandit-128.png',
|
iconPath: '/images/combat/icons/road-bandit-128.png',
|
||||||
lootTableId: ROAD_BANDIT_LOOT_TABLE_ID,
|
lootTableId: ROAD_BANDIT_LOOT_TABLE_ID,
|
||||||
@@ -182,9 +192,8 @@ export async function seedVisibleVerticalSlice(
|
|||||||
maxHp: 85,
|
maxHp: 85,
|
||||||
attack: 11,
|
attack: 11,
|
||||||
armor: 6,
|
armor: 6,
|
||||||
experienceReward: 20,
|
silverMin: 0,
|
||||||
silverMin: 12,
|
silverMax: 0,
|
||||||
silverMax: 19,
|
|
||||||
artworkPath: '/images/monsters/charred-looter.png',
|
artworkPath: '/images/monsters/charred-looter.png',
|
||||||
iconPath: '/images/combat/icons/charred-looter-128.png',
|
iconPath: '/images/combat/icons/charred-looter-128.png',
|
||||||
// Shares the raider table: same gear, taken from the same caravans.
|
// Shares the raider table: same gear, taken from the same caravans.
|
||||||
@@ -237,8 +246,7 @@ export async function seedVisibleVerticalSlice(
|
|||||||
await characterRepository.insert({
|
await characterRepository.insert({
|
||||||
id: DEMO_CHARACTER_ID,
|
id: DEMO_CHARACTER_ID,
|
||||||
name: 'Aric Duskwalker',
|
name: 'Aric Duskwalker',
|
||||||
level: 1,
|
renown: 1,
|
||||||
experience: 0,
|
|
||||||
silver: 0,
|
silver: 0,
|
||||||
baseHp: 100,
|
baseHp: 100,
|
||||||
baseAttack: 6,
|
baseAttack: 6,
|
||||||
@@ -248,7 +256,8 @@ export async function seedVisibleVerticalSlice(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const characterItemRepository = dataSource.getRepository(CharacterItem);
|
const characterItemRepository = dataSource.getRepository(CharacterItem);
|
||||||
const characterEquipmentRepository = dataSource.getRepository(CharacterEquipment);
|
const characterEquipmentRepository =
|
||||||
|
dataSource.getRepository(CharacterEquipment);
|
||||||
|
|
||||||
// Starting loadout is weapon-only -- no starter armor piece exists in
|
// Starting loadout is weapon-only -- no starter armor piece exists in
|
||||||
// content yet -- so the demo character's effective armor (sum of equipped
|
// content yet -- so the demo character's effective armor (sum of equipped
|
||||||
|
|||||||
Reference in New Issue
Block a user