import { describe, expect, it } from 'vitest'; import type { ScenarioDefinition } from '../src/scenario/types.js'; import type { MapDefinition, UnitSetDefinition } from '../src/world/types.js'; import { buildScenarioBootstrap } from '../src/world/bootstrap.js'; describe('scenario bootstrap', () => { it('builds snapshot and seed from scenario/map inputs', () => { const scenario: ScenarioDefinition = { title: 'Test Scenario', startYear: 200, life: null, fiction: null, history: [], config: { stat: { total: 100, min: 10, max: 70, npcTotal: 80, npcMax: 60, npcMin: 5, chiefMin: 50, }, iconPath: '.', map: {}, const: {}, environment: { mapName: 'test-map', unitSet: 'test-unit', }, }, nations: [ { id: 1, name: 'TestNation', color: '#123456', gold: 5000, rice: 3000, infoText: 'Test nation', tech: 100, type: 'Test', level: 3, cities: ['Alpha'], }, ], diplomacy: [], generals: [ { affinity: 10, name: 'TestGeneral', picture: 101, nation: 1, city: 'Alpha', leadership: 50, strength: 60, intelligence: 55, officerLevel: 1, birthYear: 180, deathYear: 240, personality: 'Calm', special: 'Special', text: 'Test line', }, ], generalsEx: [], generalsNeutral: [], cities: [], events: [], initialEvents: [], ignoreDefaultEvents: false, }; const map: MapDefinition = { id: 'test-map', name: 'test-map', cities: [ { id: 1, name: 'Alpha', level: 3, region: 1, position: { x: 10, y: 20 }, connections: [], max: { population: 100000, agriculture: 20000, commerce: 20000, security: 15000, defence: 5000, wall: 3000, }, initial: { population: 50000, agriculture: 10000, commerce: 10000, security: 8000, defence: 2500, wall: 1500, }, }, ], }; const unitSet: UnitSetDefinition = { id: 'test-unit', name: 'test-unit', defaultCrewTypeId: 1200, }; const result = buildScenarioBootstrap({ scenario, map, unitSet }); expect(result.warnings).toHaveLength(0); expect(result.snapshot.nations).toHaveLength(2); expect(result.seed.nations).toHaveLength(1); expect(result.snapshot.cities[0]?.nationId).toBe(1); expect(result.seed.cities[0]?.nationId).toBe(1); expect(result.snapshot.generals[0]?.cityId).toBe(1); expect(result.snapshot.generals[0]?.crewTypeId).toBe(1200); expect(result.snapshot.generals[0]?.role.specialDomestic).toBe('Special'); expect(result.snapshot.generals[0]?.role.specialWar).toBeNull(); expect(result.snapshot.generals[0]?.meta).toMatchObject({ specage: 25, specage2: 30 }); expect(result.seed.generals[0]?.meta).toMatchObject({ specage: 25, specage2: 30 }); expect(result.seed.generals[0]?.npcType).toBe(2); expect(result.snapshot.scenarioMeta?.title).toBe('Test Scenario'); }); it('defers future generals into birth-year registration events and omits expired rows', () => { const general = ( name: string, birthYear: number, deathYear: number, nation: number | string | null = 1 ): ScenarioDefinition['generals'][number] => ({ affinity: 0, name, picture: null, nation, city: null, leadership: 50, strength: 60, intelligence: 40, officerLevel: 3, birthYear, deathYear, personality: null, special: '', text: '', }); const scenario: ScenarioDefinition = { title: 'Delayed generals', startYear: 200, life: null, fiction: null, history: [], config: { stat: { total: 100, min: 10, max: 70, npcTotal: 80, npcMax: 60, npcMin: 5, chiefMin: 50 }, iconPath: '.', map: {}, const: {}, environment: { mapName: 'test-map', unitSet: 'test-unit' }, }, nations: [ { id: 1, name: 'TestNation', color: '#123456', gold: 5_000, rice: 3_000, infoText: '', tech: 100, type: 'Test', level: 3, cities: ['Alpha'], }, ], diplomacy: [], generals: [ general('현재', 180, 240), general('미래1', 190, 250, 'TestNation'), general('만료', 170, 200), ], generalsEx: [general('미래확장', 190, 260)], generalsNeutral: [general('미래재야', 191, 260, 0)], cities: [], events: [['Month', 500, ['Date', '>=', 200, 1], ['Existing']]], initialEvents: [], ignoreDefaultEvents: false, }; const map: MapDefinition = { id: 'test-map', name: 'test-map', cities: [ { id: 1, name: 'Alpha', level: 3, region: 1, position: { x: 0, y: 0 }, connections: [], max: { population: 100_000, agriculture: 20_000, commerce: 20_000, security: 15_000, defence: 5_000, wall: 3_000, }, initial: { population: 50_000, agriculture: 10_000, commerce: 10_000, security: 8_000, defence: 2_500, wall: 1_500, }, }, ], }; const result = buildScenarioBootstrap({ scenario, map }); expect(result.seed.generals.map((row) => row.name)).toEqual(['현재']); expect(result.snapshot.generals.map((row) => row.name)).toEqual(['현재']); expect(result.seed.events).toEqual([ ['Month', 500, ['Date', '>=', 200, 1], ['Existing']], [ 'Month', 1_000, ['Date', '>=', 204, 1], ['RegNPC', 0, '미래1', null, 1, null, 50, 60, 40, 3, 190, 250, null, '', ''], ['RegNPC', 0, '미래확장', null, 1, null, 50, 60, 40, 3, 190, 260, null, '', ''], ['DeleteEvent'], ], [ 'Month', 1_000, ['Date', '>=', 205, 1], ['RegNeutralNPC', 0, '미래재야', null, 0, null, 50, 60, 40, 191, 260, null, '', ''], ['DeleteEvent'], ], ]); expect(result.snapshot.events).toEqual(result.seed.events); expect(result.seed.events.flat(3)).not.toContain('만료'); }); });