Files
thzxx 4dfa07cc9f v0.1.32: 万宝琳琅——物品六类化 + 新材料七种 + 循环接入 + 测试 5009
【资源物品大扩容】
- ItemKind 6 值:resource/material/pill/talisman/brew/artifact——市场分群/背包/售卖/modSchema 全链
- 新材料七种:灵玉/灵木/兽皮/灵果(POOL_BASE+MARKET_IDS+worldgen 偏移四同步入世界池)、
  灵露/丹砂/符纸(道具料)
- 循环接入:新建筑灵果园(灵果)/灵木坊(灵木);productionTick 泛化逐建筑读 produceTable 全键;
  秘境掉落材料化(灵玉/兽皮/灵木);材料类同向微漂(物产同源生态)

【新用途】
- 符箓:war 战斗开战武备自动消耗(talismanWarPrep 零 rng)
- 灵酿:渡劫伤后自动回气 +5
- 新丹方和灵丹/虚元丹 + 玉澜刃/灵酿铸器配方

【测试 5009】86 套件(+1000:matrix-treasure-a/b 950 + 断链修整);
【金钟罩】0.1.32 基线重算(物品/池/生产泛化受控变更);build 通过
2026-08-23 21:05:03 +08:00

160 lines
5.7 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { ITEMS, ARTIFACT_POWER } from '../src/renderer/game/data/items'
import { TECHNIQUES } from '../src/renderer/game/data/techniques'
import { BUILDINGS } from '../src/renderer/game/data/buildings'
import { MISSIONS, ENEMIES } from '../src/renderer/game/data/secrets'
import { NPCS } from '../src/renderer/game/data/npcs'
import { EVENTS } from '../src/renderer/game/data/events'
import { POSTS } from '../src/renderer/game/data/posts'
import { TRAITS } from '../src/renderer/game/data/traits'
import { ROOT_GRADES } from '../src/renderer/game/data/elements'
import { MAJORS, MAJOR_ORDER } from '../src/renderer/game/data/realms'
import { SEASON, seasonOf } from '../src/renderer/game/data/season'
describe('物品表逐行矩阵', () => {
it.each(Object.entries(ITEMS).map(([id, v]) => [id, v.name, v.basePrice, v.kind] as const))(
'物品 %s 名称/价格/类别合法',
(_id, name, price, kind) => {
expect(name.length).toBeGreaterThan(0)
expect(price).toBeGreaterThan(0)
expect(['resource', 'material', 'pill', 'talisman', 'brew', 'artifact']).toContain(kind)
}
)
it.each(Object.entries(ITEMS).filter(([, v]) => v.kind === 'artifact').map(([id]) => [id] as const))(
'法器 %s 有战力修正',
(id) => {
expect(ARTIFACT_POWER[id]).toBeGreaterThan(0)
}
)
})
describe('功法表逐行矩阵', () => {
it.each(TECHNIQUES.map((t) => [t.id, t.grade, t.powerBonus, t.expBonus, t.path] as const))(
'功法 %s 参数板面合法',
(id, grade, pow, exp, path) => {
expect(id.startsWith('t-')).toBe(true)
expect(grade).toBeGreaterThanOrEqual(1)
expect(grade).toBeLessThanOrEqual(4)
expect(pow).toBeGreaterThan(0)
expect(exp).toBeGreaterThan(0)
expect(path.length).toBeGreaterThan(0)
}
)
it('功法 id 全局唯一', () => {
expect(new Set(TECHNIQUES.map((t) => t.id)).size).toBe(TECHNIQUES.length)
})
})
describe('建筑表逐行矩阵', () => {
it.each(Object.entries(BUILDINGS).map(([id, v]) => [id, v.maxLevel, v.kind] as const))(
'建筑 %s 等级/类型合法',
(id, max, kind) => {
expect(id.length).toBeGreaterThan(1)
expect(max).toBeGreaterThanOrEqual(3)
expect(['produce', 'function']).toContain(kind)
}
)
it.each(Object.entries(BUILDINGS).map(([id, v]) => [id, v.upgradeCost(1), v.upgradeCost(v.maxLevel)] as const))(
'建筑 %s 升级成本随级递增',
(_id, c1, cMax) => {
expect(cMax.stones).toBeGreaterThan(c1.stones)
expect(cMax.lingkuang).toBeGreaterThan(c1.lingkuang)
}
)
})
describe('秘境表逐行矩阵', () => {
it.each(MISSIONS.map((m) => [m.id, m.name] as const))('秘境 %s 存在启程摘要', (id, name) => {
expect(id.startsWith('m-')).toBe(true)
expect(name.length).toBeGreaterThan(1)
})
it.each(
MISSIONS.flatMap((m) =>
m.stages.map(
(st, i) => [m.id, i, st.kind, st.months] as const
)
)
)('秘境 %s 第%i 阶段类型/月数合法', (_id, _i, kind, months) => {
expect(['event', 'combat', 'resource', 'boss']).toContain(kind)
expect(months).toBeGreaterThan(0)
})
it.each(ENEMIES.map((e) => [e.id, e.realm] as const))('敌人 %s 境界关联存在', (id, realm) => {
expect(id.startsWith('e-')).toBe(true)
expect(MAJOR_ORDER).toContain(realm)
})
})
describe('势力表逐行矩阵', () => {
it.each(NPCS.map((n) => [n.id, n.name] as const))('势力 %s 命名与风格', (id, name) => {
expect(id.startsWith('n-')).toBe(true)
expect(name).toContain('氏')
})
it.each(NPCS.map((n) => [n.id, n.initialPower] as const))('势力 %s 初始战力为正', (_id, p) => {
expect(p).toBeGreaterThan(0)
})
it.each(NPCS.map((n) => [n.id, n.sells ?? [], n.buys ?? []] as const))('势力 %s 交易品类引用合法', (_id, sells, buys) => {
for (const s of sells) {
expect(ITEMS[s] ?? TECHNIQUES.find((t) => t.id === s)).toBeTruthy()
}
void buys
})
})
describe('事件表逐选项矩阵', () => {
it.each(EVENTS.flatMap((e) => e.options.map((o, idx) => [e.id, idx, o.label.length] as const)))(
'事件 %s 选项%i 有文案',
(_id, _idx, len) => {
expect(len).toBeGreaterThan(0)
}
)
it.each(EVENTS.map((e) => [e.id, e.weight] as const))('事件 %s 权重为正', (_id, w) => {
expect(w).toBeGreaterThan(0)
})
it.each(EVENTS.filter((e) => e.cond?.minBuilding).map((e) => [e.id, e.cond!.minBuilding!.id] as const))(
'事件 %s 建筑条件引用存在',
(_id, b) => {
expect(BUILDINGS[b]).toBeTruthy()
}
)
})
describe('职事/秉性/灵根/境界矩阵', () => {
it.each(Object.values(POSTS).map((p) => [p.id, p.name, p.max] as const))('职事 %s %s 上限合法', (id, name, max) => {
expect(id.length).toBeGreaterThan(0)
expect(name.length).toBeGreaterThan(0)
expect(max).toBeGreaterThanOrEqual(1)
})
it.each(Object.entries(TRAITS).map(([id, t]) => [id, t.danger] as const))('秉性 %s 危险度在界', (_id, d) => {
expect(d).toBeGreaterThanOrEqual(0)
expect(d).toBeLessThanOrEqual(1)
})
it.each(Object.entries(ROOT_GRADES).map(([k, v]) => [Number(k), v.expBonus] as const))('灵根品阶%i 加成递增', (grade, exp) => {
expect(exp).toBeGreaterThan(0)
if (grade > 0) {
expect(exp).toBeGreaterThan(ROOT_GRADES[grade - 1].expBonus)
}
})
it.each(MAJOR_ORDER.map((m) => [m, MAJORS[m].lifespan] as const))('大境界 %s 寿元为正', (_m, l) => {
expect(l).toBeGreaterThan(0)
})
})
describe('时节数学矩阵', () => {
it.each([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map((m) => [m, seasonOf(m)] as const))('%i月 归季 %s', (m, s) => {
const mod = SEASON[s]
expect(mod.name.length).toBeGreaterThan(0)
})
})