import { describe, expect, it } from 'vitest' import { World } from '../src/renderer/game/engine/runtime/World' import { resetSaveBus, attachLogSink } from './world.helpers' describe('World engine', () => { it('creates a valid starting family', () => { const w = World.create({ seed: 't1', surname: '林', familyName: '林家', motto: 'm', difficulty: 'normal' }) expect(Object.values(w.state.members).length).toBe(5) expect(w.aliveMembers().length).toBe(5) expect(w.state.family.headId).toBe('x1') expect(w.ageOf(w.head())).toBe(35) }) it('survives 20 years (240 months) without NaN or throws', () => { const w = World.create({ seed: 'smoke', surname: '沈', familyName: '沈氏', motto: 'x', difficulty: 'normal' }) resetSaveBus() attachLogSink(w) for (let i = 0; i < 240; i++) { if (w.state.gameOver) break w.advanceMonth() } const s = w.state expect(Number.isNaN(s.family.stones)).toBe(false) expect(s.year).toBeGreaterThan(10) for (const c of Object.values(s.members)) { expect(Number.isNaN(c.realmProgress)).toBe(false) expect(Number.isNaN(c.health)).toBe(false) } }) it('same seed plays identically (deterministic)', () => { const a = World.create({ seed: 'det', surname: '苏', familyName: '苏家', motto: 'm', difficulty: 'easy' }) const b = World.create({ seed: 'det', surname: '苏', familyName: '苏家', motto: 'm', difficulty: 'easy' }) resetSaveBus() attachLogSink(a) resetSaveBus() attachLogSink(b) const ignoreRng = (state: { rng: unknown }) => JSON.parse(JSON.stringify(state)) for (let i = 0; i < 60; i++) { a.advanceMonth() b.advanceMonth() } a.state.pendingEvent && (a.state.pendingEvent = undefined) b.state.pendingEvent && (b.state.pendingEvent = undefined) const x = ignoreRng({ ...a.state, pendingEvent: undefined }) const y = ignoreRng({ ...b.state, pendingEvent: undefined }) expect(JSON.stringify(x)).toBe(JSON.stringify(y)) }) it('families grow over time (births occur)', () => { const w = World.create({ seed: 'grow', surname: '叶', familyName: '叶家', motto: 'm', difficulty: 'easy' }) resetSaveBus() attachLogSink(w) for (let i = 0; i < 240; i++) { if (w.state.gameOver) break w.advanceMonth() } expect(Object.keys(w.state.members).length).toBeGreaterThan(5) }) it('game over when everyone dies', () => { const w = World.create({ seed: 'diehard', surname: '麦', familyName: '麦家', motto: 'm', difficulty: 'hard' }) resetSaveBus() attachLogSink(w) for (const c of Object.values(w.state.members)) { c.alive = false } for (let i = 0; i < 5; i++) w.advanceMonth() expect(w.state.gameOver).toBeTruthy() }) it('building upgrade consumes resources', () => { const w = World.create({ seed: 'bld', surname: '金', familyName: '金家', motto: 'm', difficulty: 'easy' }) const before = w.state.family.inventory['lingkuang'] ?? 0 w.state.family.inventory['lingkuang'] = (w.state.family.inventory['lingkuang'] ?? 0) + 100 const ok = w.build('fangshi') expect(ok).toBe(true) const upgraded = w.upgrade('fangshi') expect(upgraded).toBe(true) expect(w.state.family.buildings['fangshi']).toBe(2) expect((w.state.family.inventory['lingkuang'] ?? 0) - before).toBeLessThan(100) }) })