import { describe, expect, it } from 'vitest' import { World } from '../src/renderer/game/engine/runtime/World' import { fire, applyEventChoice } from '../src/renderer/game/engine/runtime/Systems/events' import { ERA_CONF, ERA_DURA, WORLDSIM, WorldSimState } from '../src/renderer/game/engine/sim/worldsim-data' import { stateFingerprint } from './fingerprint.helper' describe('0.1.20 万世无谬', () => { it('fire 高优可顶替普通 pending,被顶替者入队不丢失', () => { const w = World.create({ seed: 'a1', surname: '岳', familyName: '岳家', motto: 'm', difficulty: 'normal' }) w.advanceMonth() w.state.pendingEvent = undefined // 清月度事件闸(测试隔离) fire(w, 'ev-legacypass') // 普通占位 expect(w.state.pendingEvent).toBe('ev-legacypass') const ok = fire(w, 'ev-raid-n-nulei', 1) // 高优顶替 expect(ok).toBe(true) expect(w.state.pendingEvent).toBe('ev-raid-n-nulei') expect(w.state.eventQueue).toContain('ev-legacypass') // 未丢失 }) it('fire 普通被占则 false(调用方可冷却)', () => { const w = World.create({ seed: 'a2', surname: '满', familyName: '满家', motto: 'm', difficulty: 'normal' }) w.advanceMonth() w.state.pendingEvent = undefined fire(w, 'ev-legacypass') expect(fire(w, 'ev-legacypass')).toBe(false) }) it('名宿传薪同一年仅一次(年锚 flag)', () => { const w = World.create({ seed: 'a3', surname: '贺', familyName: '贺家', motto: 'm', difficulty: 'normal' }) w.state.year = 4 // year%8===4 w.state.completedEvents = [] let n = 0 for (let i = 0; i < 12; i++) { if (w.state.year % 8 === 4 && !w.state.family.flag[`legacyDone-${w.state.year}`]) { if (fire(w, 'ev-legacypass')) { w.state.family.flag[`legacyDone-${w.state.year}`] = true n++ } w.applyEventChoice(w.state.pendingEvent ?? 'ev-legacypass', 0) } w.state.month++ if (w.state.month > 12) { w.state.month = 1; w.state.year++ } } expect(n).toBeLessThanOrEqual(1) }) it('二次结算防线:陈旧 Modal 选择被忽略(pending 已清/易主)', () => { const w = World.create({ seed: 'a4', surname: '冼', familyName: '冼家', motto: 'm', difficulty: 'normal' }) w.advanceMonth() fire(w, 'ev-legacypass') const before = w.state.pendingEvent // 恶意重复选择:pending 已易主(自动压制)时 apply 不得落盘 w.state.pendingEvent = undefined let threw = false try { applyEventChoice(w, before!, 0) } catch { threw = true } expect(threw).toBe(false) // 不崩 expect(w.state.pendingEvent).toBeUndefined() // 未二次应用 }) it('era 有延续档:flow 权重和 < 1(不再每届必换)', () => { for (const k of Object.keys(ERA_CONF) as Array) { const sum = ERA_CONF[k].flow.reduce((a, [, wgt]) => a + wgt, 0) expect(sum).toBeLessThan(1) } expect(ERA_DURA.pingshi[0]).toBeLessThan(ERA_DURA.pingshi[1]) }) it('潮汐供给正号:tide>1 → 供给乘 >1(灵涨必丰)', () => { const multAt = (tide: number): number => Math.max(0.75, Math.min(1.35, 1 + (tide - 1) * WORLDSIM.tideSupplySpan)) expect(multAt(1.3)).toBeGreaterThan(1) expect(multAt(0.7)).toBeLessThan(1) }) it('断供/池底单常量一致:拒单阈值 == poolFloorPct', () => { expect(WORLDSIM.tradeFloorPct).toBe(WORLDSIM.poolFloorPct) }) it('rebalance 弱锚定:供需可撬动价格(1200 月池有超过 ±25% 振幅的时机)', () => { const w = World.create({ seed: 'a9', surname: '郄', familyName: '郄家', motto: 'm', difficulty: 'normal' }) let min = Infinity let max = -Infinity for (let i = 0; i < 1200; i++) { w.advanceMonth() const pool = (w.state.worldSim as WorldSimState | undefined)?.marketPool?.['lingcao'] ?? 600 min = Math.min(min, pool / 600) max = Math.max(max, pool / 600) } expect(max - min).toBeGreaterThan(0.5) // 弱锚定下真实起伏 }) it('指纹含世界轴(era/stance 变更会红)', () => { const w = World.create({ seed: 'a10', surname: '苻', familyName: '苻家', motto: 'm', difficulty: 'normal' }) for (let i = 0; i < 240; i++) w.advanceMonth() const f1 = stateFingerprint(w.state) const ws = w.state.worldSim as WorldSimState ws.era = ws.era === 'mofa' ? 'shengshi' : 'mofa' // 确保改成异值 ws.npcDyn['n-xuanying']!.stance = ws.npcDyn['n-xuanying']!.stance === 'expand' ? 'endure' : 'expand' const f2 = stateFingerprint(w.state) expect(f1).not.toBe(f2) }) })