import { describe, expect, it } from 'vitest' import { World, normalizeGameState } from '../src/renderer/game/engine/runtime/World' import { marryNpcFamily, makePeace } from '../src/renderer/game/engine/runtime/Systems/diplomacy' import { sendMission, recallAll } from '../src/renderer/game/engine/runtime/Systems/missions' import { applyEventChoice } from '../src/renderer/game/engine/runtime/Systems/events' import { GameState } from '../src/renderer/game/types/domain' import { resetSaveBus, attachLogSink } from './world.helpers' describe('0.1.3 audit regression', () => { it('marries a npc family once only (allied lock)', () => { const w = World.create({ seed: 'hy', surname: '卫', familyName: '卫家', motto: 'm', difficulty: 'normal' }) const npcId = Object.keys(w.state.npcFamilies)[0]! const npc = w.state.npcFamilies[npcId] npc.relation = 60 // 姑且让长子成年(18岁可婚) w.state.members['x3'].bornYear = 1 - 18 expect(marryNpcFamily(w, npcId)).toBe(true) expect(npc.allied).toBe(true) expect(marryNpcFamily(w, npcId)).toBe(false) }) it('or same-mother siblings cannot marry (candidates + direct)', () => { const w = World.create({ seed: 'kin', surname: '陆', familyName: '陆家', motto: 'm', difficulty: 'normal' }) const a = w.state.members['x3'] const b = w.state.members['x5'] // 人为制造同母异父关系 a.motherId = 'x2' b.motherId = 'x2' a.fatherId = undefined b.fatherId = undefined expect(w.marriageCandidatesOf(a.id).map((c) => c.id)).not.toContain(b.id) expect(w.marryTo(a.id, b.id)).toBe(false) }) it('peace cements relation to a floor above zero', () => { const w = World.create({ seed: 'peace', surname: '华', familyName: '华家', motto: 'm', difficulty: 'normal' }) const npcId2 = Object.keys(w.state.npcFamilies)[0]! const npc = w.state.npcFamilies[npcId2] npc.relation = -80 w.state.family.stones = 900 expect(makePeace(w, npcId2)).toBe(true) expect(npc.relation).toBeGreaterThanOrEqual(30) }) it('event negative resource cannot sink stones below zero', () => { const w = World.create({ seed: 'clamp', surname: '曾', familyName: '曾家', motto: 'm', difficulty: 'normal' }) const npcId2 = Object.keys(w.state.npcFamilies)[0]! w.state.family.stones = 30 applyEventChoice(w, `ev-raid-${npcId2}`, 1) // 割地求和 -250 expect(w.state.family.stones).toBe(0) }) it('expedition squad releases members and drops wounded', () => { const w = World.create({ seed: 'exp', surname: '纪', familyName: '纪家', motto: 'm', difficulty: 'normal' }) resetSaveBus() attachLogSink(w) const ok = sendMission(w, 'm-anmoku', ['x1', 'x3']) expect(ok).toBe(true) const m = w.state.missions[0] expect(m.memberIds.length).toBe(2) // 制造重伤:让一人带伤退出 const c = w.state.members['x3'] c.health = 10 c.state = 'wounded' w.advanceMonth() expect(m.memberIds).not.toContain('x3') expect(w.state.members['x3'].state).toBe('wounded') // 剩余的 x1 一人 ≥ minMembers=1 可以继续;test recall releases recallAll(w, m.id) expect(w.state.members['x1'].state).toBe('idle') }) it('squad disband when members run short', () => { const w = World.create({ seed: 'exp2', surname: '窦', familyName: '窦家', motto: 'm', difficulty: 'normal' }) resetSaveBus() attachLogSink(w) const ok = sendMission(w, 'm-xuangu', ['x1', 'x3']) // minMembers 1 expect(ok).toBe(true) const m = w.state.missions[0] // 两人同时重伤离队 w.state.members['x1'].health = 10 w.state.members['x1'].state = 'wounded' w.state.members['x3'].health = 10 w.state.members['x3'].state = 'wounded' w.advanceMonth() expect(m.done).toBe(true) expect(m.result).toBe('disband') }) it('long run 600 months stays sane', () => { const w = World.create({ seed: 'long', surname: '丁', familyName: '丁家', motto: 'm', difficulty: 'normal' }) resetSaveBus() attachLogSink(w) for (let i = 0; i < 600; i++) { if (w.state.gameOver) break w.advanceMonth() } const s = w.state expect(Number.isNaN(s.family.stones)).toBe(false) expect(s.year).toBeGreaterThan(30) for (const c of Object.values(s.members)) { expect(Number.isNaN(c.realmProgress)).toBe(false) expect(Number.isNaN(c.health)).toBe(false) } }) })