import { describe, expect, it } from 'vitest' import { World } from '../src/renderer/game/engine/world' import { monthlyRate } from '../src/renderer/game/engine/systems/cultivation' import { MAJORS } from '../src/renderer/game/data/realms' import { applyEventChoice } from '../src/renderer/game/engine/systems/events' import { resetSaveBus, attachLogSink } from './world.helpers' function baseWorld(seed: string): World { const w = World.create({ seed, surname: '莫', familyName: '莫家', motto: 'm', difficulty: 'normal' }) resetSaveBus() attachLogSink(w) return w } describe('0.1.10 数值重建验收', () => { it('修炼速率比 0.1.9 基线快(感知7 qi 期 ≥1.5/月)', () => { const w = baseWorld('pace-a') const c = w.state.members['x5'] c.realm = { major: 'qi', minor: 0 } c.perception = 7 c.roots = { grade: 3, primary: '火', secondary: [] } c.techniqueId = undefined const r = monthlyRate(w, c) expect(r).toBeGreaterThanOrEqual(1.5) }) it('qi 层间累计修为窗口 < 30 年(感知7+凡品+无功法)', () => { const w = baseWorld('pace-b') const c = w.state.members['x5'] c.realm = { major: 'qi', minor: 0 } c.perception = 7 c.roots = { grade: 2, primary: '火', secondary: [] } c.state = 'idle' const r = monthlyRate(w, c) // 9 层总月数 = 100/r × 9(近似) const months = (100 / r) * 9 expect(months).toBeLessThan(30 * 12) }) it('寿元梯度放宽:凡人75 → 化神850', () => { expect(MAJORS['mortal'].lifespan).toBe(75) expect(MAJORS['qi'].lifespan).toBe(150) expect(MAJORS['foundation'].lifespan).toBe(220) expect(MAJORS['core'].lifespan).toBe(340) expect(MAJORS['nascent'].lifespan).toBe(520) expect(MAJORS['spirit'].lifespan).toBe(850) }) it('小层突破失败跌损收窄(26-44%而非40-65%)', () => { const w = baseWorld('pace-c') const c = w.state.members['x3'] c.realm = { major: 'qi', minor: 1 } // 多次失败模拟,跌损应明显小于旧值:检查 resolveBreakthrough 失败后的 progress ≥ 55% // 直接构造必失败环境(心性/健康低) c.realmProgress = 100 c.health = 100 c.mind = 1 c.traits = ['jizao'] // 急躁加大失败伤害 resolveBreakthrough(w, c, -0.4) if (c.realm.minor === 1) { // 若失败在层内,跌损后应 ≥ 45%(旧 40-65 可能到 35%) expect(c.realmProgress).toBeGreaterThanOrEqual(45) } }) it('渡劫成功率上调(筑基期望>0.5)', () => { const w = baseWorld('trib-rate') const c = w.state.members['x5'] c.realm = { major: 'qi', minor: 8 } c.mind = 6 c.health = 100 expect(perTribChance(w, c)).toBeGreaterThan(0.5) }) }) import { resolveBreakthrough } from '../src/renderer/game/engine/systems/cultivation' import { perTribChance } from '../src/renderer/game/engine/systems/tribulation' describe('事件悬置与周期(0.1.10)', () => { it('大比征召 FIFO 不被拍卖/传薪挤掉(20 年三年都触发)', () => { const w = World.create({ seed: 'tourney-q', surname: '龚', familyName: '龚家', motto: 'm', difficulty: 'normal' }) resetSaveBus() attachLogSink(w) const seen: string[] = [] w.out.push({ onLog: () => undefined, onChronicle: () => undefined, onBattle: () => undefined, onPendingEvent: (id) => { if (id.startsWith('ev-tournament-')) seen.push(id) }, onGameOver: () => undefined }) for (let i = 0; i < 20 * 12; i++) { if (w.state.pendingEvent) { applyEventChoice(w, w.state.pendingEvent, 0); w.state.pendingEvent = undefined } w.advanceMonth() } expect(seen).toContain('ev-tournament-10') expect(seen).toContain('ev-tournament-15') expect(seen).toContain('ev-tournament-20') }) it('渡劫玩家处理能晋升(qi8→筑基)', () => { const w = World.create({ seed: 'trib-jump', surname: '桑', familyName: '桑家', motto: 'm', difficulty: 'normal' }) const c = w.state.members['x5'] c.realm = { major: 'qi', minor: 8 } c.realmProgress = 100 c.mind = 9 c.perception = 9 for (let i = 0; i < 60; i++) { if (w.state.pendingEvent) { applyEventChoice(w, w.state.pendingEvent, 0); w.state.pendingEvent = undefined } w.advanceMonth() if (c.realm.major === 'foundation') break } expect(c.realm.major).toBe('foundation') }) })