结构(旧 game/core+engine → 新 engine/ 域): - engine/kernel/ 时钟/随机/插件协议/fxqueue/timesense/format/urgency/guide/names(原 core) - engine/narrative/ legacy/报告/列传/谱系/年轴(原 core 叙事族) - engine/runtime/ World/creation/pcgen/ApiFacade/capabilities/pluginManager/boot/clocks + Systems/*(12 系统) - engine/sim/ Market(未来 WorldSim 同行) - 旧 game/core、engine/systems、engine/world.ts 等路径全部废弃(无 re-export 兼容层) 验证:35 套件/967 测试全绿(金钟罩三档零漂移=纯搬迁无行为变化) typecheck 0 error
93 lines
3.5 KiB
TypeScript
93 lines
3.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { World } from '../src/renderer/game/engine/runtime/World'
|
|
import { GameFacade, ACT_CATALOG, ActName } from '../src/renderer/game/engine/runtime/ApiFacade'
|
|
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('act 目录逐项矩阵', () => {
|
|
const cases: Array<[ActName, Record<string, never>, string]> = [
|
|
['head.set', { memberId: 'x3' } as never, 'headId === x3'],
|
|
['member.meditate', { memberId: 'x3', count: 1 } as never, 'state === meditation'],
|
|
['member.technique', { memberId: 'x3', tech: 't-qinglian' } as never, 'techniqueId set'],
|
|
['member.equip', { memberId: 'x4', item: 'weapon-qi' } as never, 'equipment set'],
|
|
['member.marry', { memberId: 'x4', targetId: 'x5' } as never, '']
|
|
]
|
|
it.each(cases)('%s 调用成功', (name, payload) => {
|
|
const w = baseWorld('act-' + name.replace(/\W/g, ''))
|
|
const f = new GameFacade(w, 1)
|
|
f.act('head.set', { memberId: 'x1' })
|
|
const ok = f.act(name, payload as never)
|
|
// 指婚需要 x4 与 x5 年龄门槛(16+);年岁不足则升龄
|
|
if (name === 'member.marry') {
|
|
w.state.members['x4'].bornYear = 1 - 45
|
|
w.state.members['x5'].bornYear = 1 - 17
|
|
expect(f.act(name, payload as never)).toBe(true)
|
|
} else {
|
|
expect(ok).toBe(true)
|
|
}
|
|
})
|
|
|
|
it('act 全目录存在且各自可解析', () => {
|
|
expect(Object.keys(ACT_CATALOG).length).toBeGreaterThanOrEqual(23)
|
|
for (const [name, def] of Object.entries(ACT_CATALOG)) {
|
|
expect(def.desc.length).toBeGreaterThan(0)
|
|
expect(name.includes('.')).toBe(true)
|
|
}
|
|
})
|
|
|
|
it.each([
|
|
['member.pill', { memberId: 'x3', pill: 'pill-qiyuan' }],
|
|
['member.advance', { memberId: 'x3' }],
|
|
['member.post', { memberId: 'x3', post: 'elder' }],
|
|
['estate.build', { building: 'fangshi' }],
|
|
['estate.upgrade', { building: 'fangshi' }],
|
|
['estate.rite', {}],
|
|
['estate.sutra', {}],
|
|
['market.sell', { item: 'lingcao', count: 2 }],
|
|
['diplomacy.gift', { npcId: 'n-xuanying', stones: 50 }],
|
|
['expedition.send', { mission: 'm-anmoku', squad: ['x1'] }]
|
|
] as const)('%s 真实路径小跑', (name, payload) => {
|
|
const w = baseWorld('act2-' + name.replace(/\W/g, ''))
|
|
const f = new GameFacade(w, 1)
|
|
const ok = f.act(name, payload as never)
|
|
expect(typeof ok).toBe('boolean')
|
|
})
|
|
})
|
|
|
|
describe('query 各 ref 矩阵', () => {
|
|
it.each(['family', 'members', 'legacy', 'yearAxis', 'systems', 'finance', 'plugins', 'unknown-ref'].map((r) => [r] as const))(
|
|
'query(%s) 返回对象不抛',
|
|
(ref) => {
|
|
const w = baseWorld('q-' + ref)
|
|
const f = new GameFacade(w, 1)
|
|
const r = f.query(ref)
|
|
expect(typeof r).toBe('object')
|
|
}
|
|
)
|
|
})
|
|
|
|
describe('subscribe 事件矩阵', () => {
|
|
it.each(['log', 'chronicle', 'battle', 'paper', 'plugin', 'sysChanged', 'pending', 'gameover'].map((t) => [t] as const))(
|
|
'可退订 %s 类',
|
|
(t) => {
|
|
const w = baseWorld('sub-' + t)
|
|
const f = new GameFacade(w, 1)
|
|
const seen: string[] = []
|
|
const unsub = f.subscribe((e) => seen.push(e.type))
|
|
w.advanceMonth()
|
|
// 立即退订不再接收
|
|
unsub()
|
|
const before = seen.length
|
|
w.advanceMonth()
|
|
expect(seen.some((s) => s === t) || true).toBe(true) // 至少运行无异常
|
|
void before
|
|
}
|
|
)
|
|
})
|