import { DataSource } from 'typeorm'; import { DEMO_CHARACTER_ID } from '../../demo/demo-character.constants'; import { Character } from '../../characters/entities/character.entity'; import { ItemDefinition } from '../../items/entities/item-definition.entity'; import { LootTableEntry } from '../../loot/entities/loot-table-entry.entity'; import { LootTable } from '../../loot/entities/loot-table.entity'; import { EncounterType } from '../../monsters/entities/encounter-type.enum'; import { LocationMonster } from '../../monsters/entities/location-monster.entity'; import { MonsterDefinition } from '../../monsters/entities/monster-definition.entity'; import { LocationConnection } from '../../world/entities/location-connection.entity'; import { LocationDefinition } from '../../world/entities/location-definition.entity'; import { ASH_RAT_LOOT_TABLE_ID, ROAD_BANDIT_LOOT_TABLE_ID, } from './item.constants'; import { ITEM_DEFINITIONS, LOOT_TABLES, LOOT_TABLE_ENTRIES } from './item-content'; import { ASH_RAT_MONSTER_ID, BURNED_ROAD_ID, ROAD_BANDIT_MONSTER_ID, SOUTH_GATE_ID, } from './vertical-slice.constants'; export async function seedVisibleVerticalSlice( dataSource: DataSource, ): Promise { const locationRepository = dataSource.getRepository(LocationDefinition); const connectionRepository = dataSource.getRepository(LocationConnection); const characterRepository = dataSource.getRepository(Character); const monsterRepository = dataSource.getRepository(MonsterDefinition); const locationMonsterRepository = dataSource.getRepository(LocationMonster); const itemRepository = dataSource.getRepository(ItemDefinition); const lootTableRepository = dataSource.getRepository(LootTable); const lootEntryRepository = dataSource.getRepository(LootTableEntry); const locations = [ { id: SOUTH_GATE_ID, key: 'south-gate', name: 'Südtor von Graufurt', description: 'Am schwarzen Südtor endet der Schutz Graufurts. Hinter den Wachtfeuern beginnt die stille Weite der Aschenfelder.', regionKey: 'ashen-fields', minRecommendedLevel: 1, maxRecommendedLevel: 1, dangerLevel: 0, isSafe: true, huntingEnabled: false, artworkPath: '/images/backgrounds/Suedtor.png', }, { id: BURNED_ROAD_ID, key: 'burned-road', name: 'Verbrannte Straße', description: 'Die alte Handelsstraße führt durch verkohlte Felder. Zwischen Asche und zerbrochenen Wagen warten die ersten Gefahren.', regionKey: 'ashen-fields', minRecommendedLevel: 1, maxRecommendedLevel: 2, dangerLevel: 1, isSafe: false, huntingEnabled: true, artworkPath: '/images/backgrounds/Aschestrasse.png', }, ]; let southGateId = SOUTH_GATE_ID; let burnedRoadId = BURNED_ROAD_ID; for (const location of locations) { const existing = await locationRepository.findOneBy({ key: location.key, }); const { id, key, ...definition } = location; const persistedId = existing?.id ?? id; if (existing) { await locationRepository.update(existing.id, definition); } else { await locationRepository.insert(location); } if (key === 'south-gate') { southGateId = persistedId; } else { burnedRoadId = persistedId; } } await connectionRepository.upsert( [ { fromLocationId: southGateId, toLocationId: burnedRoadId, travelDurationSeconds: 10, ambushChance: '0.0500', enabled: true, }, { fromLocationId: burnedRoadId, toLocationId: southGateId, travelDurationSeconds: 10, ambushChance: '0.0500', enabled: true, }, ], ['fromLocationId', 'toLocationId'], ); // Content is upserted by its stable key so re-running never duplicates rows // and never touches player-owned character_items or combat_rewards. await itemRepository.upsert(ITEM_DEFINITIONS, ['key']); await lootTableRepository.upsert(LOOT_TABLES, ['key']); await lootEntryRepository.upsert(LOOT_TABLE_ENTRIES, [ 'lootTableId', 'itemDefinitionId', ]); const monsters = [ { id: ASH_RAT_MONSTER_ID, key: 'ash-rat', name: 'Aschenratte', level: 1, maxHp: 45, attack: 5, armor: 0, experienceReward: 8, silverMin: 4, silverMax: 7, artworkPath: '/images/monsters/ash-rat.png', lootTableId: ASH_RAT_LOOT_TABLE_ID, }, { id: ROAD_BANDIT_MONSTER_ID, key: 'road-bandit', name: 'Straßenräuber', level: 2, maxHp: 75, attack: 9, armor: 5, experienceReward: 16, silverMin: 9, silverMax: 15, artworkPath: '/images/monsters/road-bandit.png', lootTableId: ROAD_BANDIT_LOOT_TABLE_ID, }, ]; let ashRatId = ASH_RAT_MONSTER_ID; let roadBanditId = ROAD_BANDIT_MONSTER_ID; for (const monster of monsters) { const existingMonster = await monsterRepository.findOneBy({ key: monster.key, }); const { id, key, ...definition } = monster; const persistedId = existingMonster?.id ?? id; if (existingMonster) { await monsterRepository.update(existingMonster.id, definition); } else { await monsterRepository.insert(monster); } if (key === 'ash-rat') { ashRatId = persistedId; } else { roadBanditId = persistedId; } } await locationMonsterRepository.upsert( [ { locationId: burnedRoadId, monsterId: ashRatId, weight: 70, encounterType: EncounterType.NORMAL, enabled: true, }, { locationId: burnedRoadId, monsterId: roadBanditId, weight: 30, encounterType: EncounterType.NORMAL, enabled: true, }, ], ['locationId', 'monsterId'], ); const existing = await characterRepository.findOneBy({ id: DEMO_CHARACTER_ID, }); if (!existing) { await characterRepository.insert({ id: DEMO_CHARACTER_ID, name: 'Aric Duskwalker', level: 1, experience: 0, silver: 0, baseHp: 100, baseAttack: 6, currentHp: 100, currentLocationId: southGateId, }); } }