Files
ChronicleOfTheImmortalClan/tests/legacy-tournament.test.ts
T
thzxx 98b60076f0 v0.1.4: 百年定局(终局/大比/寄读/春秋原)
- 望气定鼎:stats 追踪四维(人兴/道兴/威名/香火)+ 十二称号分档 + 铭文诗
  春秋原页预演称号,落印定局(青册留档,不阻继续游历)
- 太虚大比:每五年征召,点将三关(初试/拔擢/问鼎)复用战斗结算,
  名次四档红利(声望/灵石/全场好感),史书战报自动落笔
- 宗门寄读:随机宗门收徒(适龄少年),寄读 2-4 年期间每季寄资源,
  期满三选:归来精进(可触发突破+随机机运)或续读深造;低概率择师不回
- 求经台:藏书阁≥3 解锁,两年一访得稀有功法
- 春秋原复盘页:气数四维图/岁末族簿汇编/生卒与突破年表/大比年表
- 修复:大比征召曾因月份条件错过整年;抢在百年庆典前的优先级倒置
- 测试 161→176(评分边界/称号分档/大比三轨/寄读全链/求经冷却)
2026-08-23 09:00:17 +08:00

191 lines
6.9 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { World } from '../src/renderer/game/engine/world'
import { computeLegacy, resolveLegacy, peakRealmIndex, grandTechniqueCount } from '../src/renderer/game/core/legacy'
import { runTournament, buildApprentice, finalizeApprentice, apprenticeCandidates } from '../src/renderer/game/engine/systems/tournament'
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('legacy 望气评分', () => {
it('四维分随面板数据单调增(声望峰)', () => {
const w = baseWorld('leg-s1')
const d0 = computeLegacy(w.state)
w.state.stats.repPeak = 78
const d1 = computeLegacy(w.state)
expect(d1.weiMing).toBeGreaterThan(d0.weiMing)
})
it('peakRealmIndex 与 grandTechniqueCount 计算正确', () => {
const w = baseWorld('leg-s2')
w.state.members['x4'].realm = { major: 'core', minor: 0 }
expect(peakRealmIndex(w.state.members)).toBe(30)
w.state.members['x3'].techniqueRank = 2
expect(grandTechniqueCount(w.state.members)).toBe(1)
})
it('十二称号分档边界正确', () => {
const w = baseWorld('leg-s3')
w.state.stats.feishengCount = 1
expect(resolveLegacy(w.state).title).toBe('飞升之资')
w.state.stats.feishengCount = 0
// 强制高分档 150+
w.state.stats.repPeak = 80
w.state.stats.maxRealmIdx = 60 // 化神
w.state.stats.popPeak = 45
w.state.stats.techniqueGrand = 12
w.state.year = 250
const arch = resolveLegacy(w.state)
expect(['仙朝遗脉', '中州望族']).toContain(arch.title)
})
it('极弱家族落入冢中枯骨档', () => {
const w = baseWorld('leg-s4')
w.state.stats.repPeak = 0
w.state.stats.maxRealmIdx = -1
w.state.stats.popPeak = 1
w.state.year = 3
w.state.stats.feishengCount = 0
expect(resolveLegacy(w.state).title).toBe('冢中枯骨')
})
it('定局落印单次生效且写入史书', () => {
const w = baseWorld('leg-s5')
const c0 = w.state.chronicle.length
const arch = w.resolveLegacyNow()
expect(arch.title).toBeTruthy()
expect(w.state.family.flag['resolved']).toBe(true)
expect(w.state.stats.resolvedYear).toBe(w.state.year)
expect(w.state.stats.resolveTitle).toBe(arch.title)
expect(w.state.chronicle.length).toBe(c0 + 1)
})
})
describe('tournament 太虚大比', () => {
it('十年(year%5=0 & year>=10)触发征召事件', () => {
const w = baseWorld('tr-a')
w.state.year = 9
w.state.month = 12
w.advanceMonth()
expect(w.state.pendingEvent).toBe('ev-tournament-10')
w.state.pendingEvent = undefined
w.advanceMonth()
expect(w.state.pendingEvent).toBe('ev-tournament-10') // 已火后完成列表保护内一月再次 fire
// 完成记入后不再
w.state.completedEvents.push('ev-tournament-10')
w.state.pendingEvent = undefined
w.advanceMonth()
expect(w.state.pendingEvent).not.toBe('ev-tournament-10')
})
it('点将赛出:三关全胜计入 rank1 与声望红利', () => {
const w = baseWorld('tr-b')
w.state.members['x3'].realm = { major: 'foundation', minor: 0 }
runTournament(w, ['x3'])
const rec = w.state.stats.tourneyHistory[w.state.stats.tourneyHistory.length - 1]
expect(rec).toBeTruthy()
expect(rec!.year).toBe(w.state.year)
expect(rec!.rank).toBeGreaterThanOrEqual(1)
expect(rec!.rank).toBeLessThanOrEqual(4)
expect(w.state.battles.length).toBeGreaterThanOrEqual(1)
})
it('无人可遣时告假缺席不崩溃', () => {
const w = baseWorld('tr-c')
for (const c of Object.values(w.state.members)) {
c.state = 'apprentice'
}
runTournament(w)
expect(w.state.stats.tourneyHistory.length).toBe(0)
})
it('称病不出选项:声望-3 且有最低记账', () => {
const w = baseWorld('tr-d')
w.state.year = 10
const rep0 = w.state.family.reputation
applyEventChoice(w, 'ev-tournament-10', 2) // 称病
expect(w.state.family.reputation).toBe(rep0 - 3)
})
})
describe('apprentice 宗门寄读', () => {
it('招生条件与派遣', () => {
const w = baseWorld('ap-a')
w.state.members['x5'].bornYear = 1 - 15 // 15 岁
const cands = apprenticeCandidates(w)
expect(cands.length).toBeGreaterThan(0)
buildApprentice(w)
const apprentice = Object.values(w.state.members).find((c) => c.state === 'apprentice')
expect(apprentice).toBeTruthy()
expect(apprentice!.apprentice?.untilYear).toBeGreaterThan(w.state.year)
})
it('寄读者不修炼不婚配', () => {
const w = baseWorld('ap-b')
const c = w.state.members['x5']
c.bornYear = 1 - 15
buildApprentice(w)
const p0 = c.realmProgress
w.advanceMonth()
expect(c.realmProgress).toBe(p0)
// candidates 不含
expect(w.marriageCandidatesOf('x3').map((x) => x.id)).not.toContain(c.id)
})
it('到期归家:境界推进与状态复原', () => {
const w = baseWorld('ap-c')
const c = w.state.members['x3']
c.bornYear = 1 - 30
c.state = 'apprentice'
c.apprentice = { sect: '云栖宗', untilYear: 1, quiet: false }
finalizeApprentice(w, c.id, 'return')
expect(c.state).toBe('idle')
expect(c.apprentice).toBeUndefined()
// 归来必定取得进步:要么修为涨,要么已突破
const advanced = c.realmProgress >= 60 || c.realm.minor > 1 || c.realm.major !== 'qi'
expect(advanced).toBe(true)
})
it('续读再延二年', () => {
const w = baseWorld('ap-d')
const c = w.state.members['x3']
c.state = 'apprentice'
c.apprentice = { sect: '太谷书院', untilYear: 5, quiet: false }
finalizeApprentice(w, c.id, 'stay')
expect(c.apprentice?.untilYear).toBe(Math.max(5, w.state.year + 2))
expect(c.state).toBe('apprentice')
})
it('寄读期满自动推事件', () => {
const w = baseWorld('ap-e')
const c = w.state.members['x3']
c.state = 'apprentice'
c.apprentice = { sect: '丹霞洞天', untilYear: w.state.year, quiet: false }
w.advanceMonth()
const queued = w.state.eventQueue.some((id) => id.startsWith('ev-apprentice-'))
expect(queued).toBe(true)
// smoke保证 year%4 的招生在年份匹配时也 fire(不影响上述)
})
})
describe('seekSutra 求经台', () => {
it('藏书阁>=3 才可、两年冷却、收获入藏', () => {
const w = baseWorld('sk-a')
w.state.family.buildings = { cangshu: 2 }
expect(w.seekSutra()).toBe(false)
w.state.family.buildings = { cangshu: 3 }
w.state.family.stones = 1000
const before = w.state.family.techniques.length
expect(w.seekSutra()).toBe(true)
expect(w.state.family.techniques.length).toBeGreaterThanOrEqual(before)
expect(w.seekSutra()).toBe(false) // 冷却
w.state.year += 2
expect(w.seekSutra()).toBe(true)
})
})