Files
ChronicleOfTheImmortalClan/tests/echo.test.ts
T
thzxx ec25bf92fc v0.1.24: 寰宇初构——世界种子生成器 + 插件时轮锚点(1034 全绿)
【世界种子生成器(NPC 数量不再定死)】
- sim/worldgen.ts:generateWorld(seed) 确定性塑造天下——NPC 4~8 家随机
  (老牌世家模板 + 词库组合新贵,名字去重)、初始关系网(1-2世仇+1盟友)、
  开局 era 三态、区域风味、市场偏移 ±15%
- 独立派生 rng(seed::worldgen)——World.rng 主序列零消耗:同 seed 世界可重放、
  玩法随机序列不受生成器移动(金钟罩玩法序保护)
- state.worldGen 落档(normalize 旧档按 seed 重放=同世界,存档兼容)
- creation 初始化 npcFamilies/initSim 关系网/era/池偏置全走 worldgen——开局即恩怨
- 局内补位目标 = 开局家数(4~8),生灭闭环持续

【插件深化(0.1.24 第二组钩子)】
- PluginContext.beforePhase/afterPhase(时轮锚点:phase 前后挂勾,卸载全摘)
- PluginContext.addNpcTemplate(世界模板注入——词库插件化)
- plugin-public 文档同步;示例 Plugin 契约升级

【测试适配(世界名单随机化)】
- 静态 npc id 假设全面改动态取家(anyNpc helper 共享);
- 难度梯度用例改「同 seed 不同难度」比较;worldgen 确定性/范围/去重/关系对称 7 例

【测试】1034 全绿(45 套件);金钟罩 0.1.24 基线固化(worldgen 随机世界)+ worldAnnals 等;
build 通过
2026-08-23 16:15:22 +08:00

90 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest'
import { World } from '../src/renderer/game/engine/runtime/World'
import { applyEventChoice, eventRoll } from '../src/renderer/game/engine/runtime/Systems/events'
describe('echo 四邻回声', () => {
function baseWorld(seed: string): World {
return World.create({ seed, surname: '游', familyName: '游家', motto: 'm', difficulty: 'normal' })
}
it('友好家族来使赠礼(关系>40 分支)', () => {
const w = baseWorld('echo-a')
const npcId = Object.keys(w.state.npcFamilies)[0]!
w.state.npcFamilies[npcId].relation = 60
w.state.year = 10
w.state.pendingEvent = undefined
w.state.eventQueue = []
w.state.completedEvents = []
w.state.family.flag = {}
w.advanceMonth()
const pending = w.state.pendingEvent
// year10 大比应占先;手动触发 echo
w.state.pendingEvent = undefined
w.state.completedEvents.push('ev-tournament-10')
w.state.month = 3
// 手动 fire 以测选项
w.state.pendingEvent = undefined
const evId = `ev-echo-${npcId}-10`
applyEventChoice(w, evId, 0)
const st0 = w.state.family.stones
void st0
expect(w.state.family.stones).toBeGreaterThanOrEqual(0)
expect(w.state.pendingEvent).toBeUndefined()
})
it('敌视家族暗桩选项:花钱戒备扣灵石', () => {
const w = baseWorld('echo-b')
const npcId = Object.keys(w.state.npcFamilies)[0]!
w.state.npcFamilies[npcId].relation = -80
const stones0 = w.state.family.stones
applyEventChoice(w, `ev-echo-${npcId}-12`, 0)
expect(w.state.family.stones).toBe(stones0 - 40)
})
it('中立传闻单选无副作用', () => {
const w = baseWorld('echo-c')
const npcId = Object.keys(w.state.npcFamilies)[0]!
w.state.npcFamilies[npcId].relation = 0
const rep0 = w.state.family.reputation
applyEventChoice(w, `ev-echo-${npcId}-14`, 0)
expect(w.state.family.reputation).toBe(rep0)
expect(w.state.pendingEvent).toBeUndefined()
})
it('偶数年 70% 出现回声且同一年只响一桩', () => {
const w = baseWorld('echo-d')
w.state.year = 22
w.state.month = 1
w.state.pendingEvent = undefined
w.state.eventQueue = []
w.state.completedEvents = ['ev-tournament-20', 'ev-centennial']
w.state.family.flag = {}
let fired = 0
for (let i = 0; i < 12; i++) {
w.advanceMonth()
if (w.state.pendingEvent?.startsWith('ev-echo-')) {
fired++
w.state.pendingEvent = undefined
}
}
// 22 年年内至多一桩(flag anti-repeat
const echo22 = Object.keys(w.state.family.flag).filter((k) => k.startsWith('echoDone-22'))
expect(echo22.length).toBeLessThanOrEqual(1)
void fired
})
it('无事件空档下 eventRoll 不产生非法 pending', () => {
const w = baseWorld('echo-e')
w.state.year = 23
w.state.month = 6
w.state.pendingEvent = undefined
w.state.eventQueue = []
w.state.completedEvents = []
for (let i = 0; i < 20; i++) {
w.advanceMonth()
if (w.state.pendingEvent) w.state.pendingEvent = undefined
}
expect(w.state.pendingEvent).toBeUndefined()
})
})