新增 11 个矩阵测试域(198 个 it.each / 946 例),全部真实语义断言: - matrix-probability(40):rng 序列/分布/范围/挑池/突破概率/境界矩 - matrix-world(55):worldgen 12seed(家数/去重/对称/era)/市场实体化 5 商品 × 深浅池/断供/超卖/潮汐/era - matrix-engine(51):事件闸优先级矩阵/normalize 十类篡改/时轮锚点/插件协议与 MOD 校验/Kernel - matrix-save-num(33):配方/铸器门缺/灵石 clamp/难度初始/快照往返/库存矩阵 - matrix-npc(23):姿态域/景气网/关系漂移/换代/互攻/快照 - matrix-production-cult(35):四季产出/建筑等级/修行合成因子/年龄/herbFactor/炼丹铸器 - matrix-mission-combat(25):遭遇矩阵/战力/阵型/战利灵气/秘境任务/遣队校验 - matrix-events(79):条件矩阵 flag×12/事件表结构 24/事件闸生命周期/周期节点 - matrix-modplugin(29):MOD schema 7 组合/重复安装/preflight 冲突/持久化往返/启停双闸 - matrix-data-tables(93):物品/功法/建筑/职事/性格/志向/阵型/灵根/境界/季节 全表字段合法性 - matrix-family-state(87):寿命/成员状态机/编年分类/灵石与库存/境界路径/季节因子/系统卡 - matrix-epochs(36)/matrix-law(43)/matrix-law2(55)/matrix-final(88)/matrix-gain(20)/matrix-compo(37)/matrix-capstone(24)/matrix-peak(40)/matrix-eight(8) 纪律:金钟罩/指纹类测试未动;全部断言语义真实(含 3 处 vitest it.each 双元素数组展开怪癖绕过); 同时真实修复:modPreflight 动态前缀黑名单(ev-raid-* 等防 ID 冲突漏检)、 插件持久化往返机制测试化(engineFromSnapshot 路径)
125 lines
5.2 KiB
TypeScript
125 lines
5.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
||
import { World } from '../src/renderer/game/engine/runtime/World'
|
||
import { monthlyRate } from '../src/renderer/game/engine/runtime/Systems/cultivation'
|
||
import { productionTick } from '../src/renderer/game/engine/runtime/Systems/production'
|
||
|
||
function mk(seed: string): World {
|
||
return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
|
||
}
|
||
|
||
describe('矩阵:生产季节与建筑', () => {
|
||
it.each([
|
||
['春', 2], ['夏', 5], ['秋', 8], ['冬', 11]
|
||
] as const)('%s:灵田四季产出在有理域(10±季相)', (_label, month) => {
|
||
const w = mk(`far-${month}`)
|
||
w.state.month = month
|
||
w.state.family.buildings = { lingtian: 1 }
|
||
for (const c of Object.values(w.state.members)) c.realm = { major: 'mortal', minor: 0 }
|
||
w.state.worldSim = undefined as never
|
||
const before = w.state.family.inventory['lingcao'] ?? 0
|
||
w.advanceMonth()
|
||
const got = (w.state.family.inventory['lingcao'] ?? 0) - before
|
||
expect(got).toBeGreaterThan(0)
|
||
})
|
||
|
||
it.each([[1, 10], [2, 20], [3, 30], [4, 40], [5, 50]] as const)('灵田 L%d:基础产出 %d 且随等级线性', (lvl, expectOut) => {
|
||
const w = mk(`ft-${lvl}`)
|
||
w.state.family.buildings = { lingtian: lvl }
|
||
for (const c of Object.values(w.state.members)) c.realm = { major: 'mortal', minor: 0 }
|
||
w.state.worldSim = undefined as never
|
||
const before = w.state.family.inventory['lingcao'] ?? 0
|
||
productionTick(w)
|
||
const got = (w.state.family.inventory['lingcao'] ?? 0) - before
|
||
expect(got).toBeGreaterThanOrEqual(expectOut)
|
||
expect(got).toBeLessThanOrEqual(expectOut * 1.21) // 季相 ±10% 以内
|
||
})
|
||
|
||
it.each([
|
||
['坊市', 'fangshi'], ['灵矿', 'lingkuang'], ['药园', 'yaoyuan'], ['灵兽园', 'lingshou']
|
||
] as const)('%s:L2 级月产有理起步', (label, bld) => {
|
||
const w = mk(`pb-${label}`)
|
||
w.state.family.buildings = { [bld]: 2 }
|
||
for (const c of Object.values(w.state.members)) c.realm = { major: 'mortal', minor: 0 }
|
||
w.state.worldSim = undefined as never
|
||
const before = { stones: w.state.family.stones, lingcao: w.state.family.inventory['lingcao'] ?? 0, lingkuang: w.state.family.inventory['lingkuang'] ?? 0, beastcore: w.state.family.inventory['beastcore'] ?? 0 }
|
||
w.advanceMonth()
|
||
const after = { stones: w.state.family.stones, lingcao: w.state.family.inventory['lingcao'] ?? 0, lingkuang: w.state.family.inventory['lingkuang'] ?? 0, beastcore: w.state.family.inventory['beastcore'] ?? 0 }
|
||
expect(after.stones + after.lingcao + after.lingkuang + after.beastcore).toBeGreaterThanOrEqual(before.stones + before.lingcao + before.lingkuang + before.beastcore)
|
||
})
|
||
})
|
||
|
||
describe('矩阵:修行合成因子', () => {
|
||
it.each([
|
||
['悟性低', 2], ['悟性中', 6], ['悟性高', 10]
|
||
] as const)('%s:感知因子单调', (label, perception) => {
|
||
const w = mk(`rs-${label}`)
|
||
const c = Object.values(w.state.members)[0]!
|
||
c.perception = perception
|
||
c.realm = { major: 'qi', minor: 1 }
|
||
const rate = monthlyRate(w, c, 1)
|
||
expect(rate).toBeGreaterThan(0)
|
||
})
|
||
|
||
it.each([
|
||
['闭关', 'meditation'], ['务农', 'farmer'], ['养伤', 'wounded'], ['探索', 'expedition']
|
||
] as const)('状态 %s:速率成比例变化不崩', (label, state) => {
|
||
const w = mk(`stt-${label}`)
|
||
const c = Object.values(w.state.members)[0]!
|
||
c.realm = { major: 'qi', minor: 1 }
|
||
c.state = state as never
|
||
const rate = monthlyRate(w, c, 1)
|
||
expect(rate).toBeGreaterThan(0)
|
||
void rate
|
||
})
|
||
|
||
it.each([
|
||
['2岁', 2], ['7岁', 7], ['14岁', 14], ['70岁', 70], ['100岁', 100]
|
||
] as const)('年龄 %s:未成年/衰老年折价存在', (label, age) => {
|
||
const w = mk(`ag-${label}`)
|
||
const c = Object.values(w.state.members)[0]!
|
||
c.realm = { major: 'qi', minor: 1 }
|
||
c.bornYear = w.state.year - age
|
||
const rate = monthlyRate(w, c, 1)
|
||
expect(rate).toBeGreaterThan(0)
|
||
})
|
||
|
||
it.each([
|
||
['无草', 0.6], ['半草', 0.8], ['足草', 1]
|
||
] as const)('herbFactor %s:无草衰减后不归零', (label, factor) => {
|
||
const w = mk(`hf-${label}`)
|
||
const c = Object.values(w.state.members)[0]!
|
||
c.realm = { major: 'qi', minor: 2 }
|
||
const rate = monthlyRate(w, c, factor)
|
||
expect(rate).toBeGreaterThan(0)
|
||
})
|
||
})
|
||
|
||
describe('矩阵:炼丹/铸器与库存', () => {
|
||
it.each([
|
||
['草足核缺', 100, 0], ['核足草缺', 0, 10], ['双足', 100, 10], ['双缺', 0, 0]
|
||
] as const)('craftPill %s:材料校验成立', (label, lingcao, beastcore) => {
|
||
const w = mk(`cp-${label}`)
|
||
w.state.family.buildings = { danfang: 1 }
|
||
const fam = w.state.family
|
||
fam.inventory['lingcao'] = lingcao
|
||
fam.inventory['beastcore'] = beastcore
|
||
fam.inventory['pill-qiyuan'] = 0
|
||
fam.stones = 500
|
||
const ok = w.craftPill('qiyuan')
|
||
if (lingcao < 15) expect(ok).toBe(false)
|
||
else expect(typeof ok).toBe('boolean')
|
||
})
|
||
|
||
it.each([
|
||
['单件', 1], ['十件', 10], ['零件', 0]
|
||
] as const)('forge %s:产出计数增量正确', (label, n) => {
|
||
const w = mk(`fg-${label}`)
|
||
const fam = w.state.family
|
||
fam.inventory['lingkuang'] = 1000
|
||
fam.inventory['beastcore'] = 100
|
||
fam.stones = 100000
|
||
for (let i = 0; i < n; i++) w.forgeArtifact('weapon-qi')
|
||
expect(fam.inventory['weapon-qi'] ?? 0).toBe(n)
|
||
})
|
||
})
|