import { describe, expect, it } from 'vitest' import { World } from '../src/renderer/game/engine/runtime/World' import { createWorldState, NewGameOptions, findInheritor } from '../src/renderer/game/engine/runtime/creation' import { resetSaveBus, attachLogSink } from './world.helpers' function opts(seed: string, difficulty: 'easy' | 'normal' | 'hard' = 'normal', surname = '彭'): NewGameOptions { return { seed, surname, familyName: `${surname}家`, motto: 'm', difficulty } } describe('World 生命周期与初始态', () => { it('三种难度初始资源与 NPC 强度梯度正确', () => { // 同 seed 不同难度(worldgen 由 seed 决定——三世界名单一致,可比) const easy = createWorldState(opts('st-diff', 'easy')) const normal = createWorldState(opts('st-diff', 'normal')) const hard = createWorldState(opts('st-diff', 'hard')) expect(easy.family.stones).toBeGreaterThan(normal.family.stones) expect(normal.family.stones).toBeGreaterThan(hard.family.stones) const someId = Object.keys(normal.npcFamilies)[0]! expect(easy.npcFamilies[someId].power).toBeLessThan(normal.npcFamilies[someId].power) expect(normal.npcFamilies[someId].power).toBeLessThan(hard.npcFamilies[someId].power) }) it('创建后基本不变量的存在性', () => { const w = World.create(opts('st-b')) const s = w.state expect(s.family.headId).toBe('x1') expect(s.family.buildings['lingtian']).toBe(1) expect(s.family.buildings['zongci']).toBe(1) expect(s.family.techniques.length).toBe(2) expect(s.seq).toBeGreaterThanOrEqual(10) expect(s.chronicle.length).toBe(1) // 立家 }) it('findInheritor 子代优先,其次高境界', () => { const w = World.create(opts('st-fi')) const heir = findInheritor(w) expect(['x3', 'x5']).toContain(heir?.id) }) }) describe('World 推进元心与数据保全', () => { it('推进后 seq/months/总tick 单调增长', () => { const w = World.create(opts('adv-a')) const seq0 = w.state.seq const t0 = w.state.totalTicks w.advanceMonth() expect(w.state.totalTicks).toBe(t0 + 1) expect(w.state.seq).toBeGreaterThanOrEqual(seq0) }) it('月份跨年正确且 yearStart 触发', () => { const w = World.create(opts('adv-b')) for (let i = 0; i < 11; i++) w.advanceMonth() // 到 12 月 expect(w.state.month).toBe(12) w.advanceMonth() // 跨年 expect(w.state.month).toBe(1) expect(w.state.year).toBe(2) expect(w.state.yearlyReports.length).toBe(1) }) it('gameOver 后 advance 不继续崩', () => { const w = World.create(opts('adv-c')) for (const c of Object.values(w.state.members)) c.alive = false w.advanceMonth() expect(w.state.gameOver).toBeTruthy() w.advanceMonth() // 不再抛 expect(w.state.year).toBeGreaterThanOrEqual(1) }) it('年度报告的 power 值始终有效', () => { const w = World.create(opts('adv-d')) for (let i = 0; i < 30; i++) w.advanceMonth() expect(w.state.yearlyReports.every((r) => r.power > 0)).toBe(true) }) }) describe('存档重建后继续运行一致性', () => { it('json 往返后 100 月演进无异常且继续确定', () => { const w = World.create(opts('rid-a')) for (let i = 0; i < 25; i++) w.advanceMonth() w.syncRng() const clone = JSON.parse(JSON.stringify(w.state)) const w2 = new World(clone) for (let i = 0; i < 75; i++) { if (w.state.gameOver) break w.advanceMonth() w2.advanceMonth() } expect(w2.state.year).toBe(w.state.year) expect(w2.state.family.stones).toBe(w.state.family.stones) }) })