Files
ChronicleOfTheImmortalClan/tests/economy.test.ts
T
thzxx a7ee125866 v0.1.6: 时轮与造化(GameClock/RngHub/时节/年轴/保护)
- 统一时轮 GameClock:七 phase 注册制(production/aging/cultivation/missions/
  events/diplomacy/epilogue) + 年首三钩子(婚配→岁贡→族簿);advanceMonth 化作薄壳;
  新增系统只注册不改本体;alive 守卫、随机序、族簿时序均与重构前逐一等价
- 金钟罩:3 枚 seed × 560 月指纹常驻(重构前后已验证同哈希;时节属有意变更后重固化)
- 统一随机 RngHub:开局播种(crypto UV)、音效白噪独立流、引擎 rng 带 nextCount 审计;
  全工程拔除逻辑侧 Math.random
- 时节系统:春夏秋冬乘子(春田+10%/夏修+5%/秋市+5%/冬闭+8%)入生产与修炼
- 崩溃保护:advance 异常自动存『出险前』档 + 停速提示回档
- 性能预算:dev-only 单 tick>60ms 报最慢 phase
- 横轴年表:十年一格大事/生殇聚合 + 春秋原年轴视图
- 测试 197→225(时钟/收集器/四季/年轴/效果全矩阵/死局链/残留防御)
2026-08-23 09:20:52 +08:00

113 lines
4.9 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { World } from '../src/renderer/game/engine/world'
import { marketPrice, buyItem, sellItem, buyTechnique, techniquePrice } from '../src/renderer/game/engine/market'
import { ITEMS } from '../src/renderer/game/data/items'
describe('economy 经济系统', () => {
it('灵田月产随等级线性增长', () => {
const w = World.create({ seed: 'eco-a', surname: '简', familyName: '简家', motto: 'm', difficulty: 'normal' })
w.state.family.buildings = { lingtian: 1 }
const c0 = w.state.family.inventory['lingcao'] ?? 0
w.advanceMonth() // month 2 = 春季,田地有±季相但至少≥9
const c1 = w.state.family.inventory['lingcao'] ?? 0
expect(c1 - c0).toBeGreaterThanOrEqual(9)
})
it('坊市月产受执事加成', () => {
const w = World.create({ seed: 'eco-b', surname: '骆', familyName: '骆家', motto: 'm', difficulty: 'normal' })
w.state.family.buildings = { fangshi: 2 }
w.assignPost('x3', 'steward')
const s0 = w.state.family.stones
w.advanceMonth()
const gained = w.state.family.stones - s0
expect(gained).toBe(110 + 11) // 55*2*1.1
})
it('药园高级产出兽核', () => {
const w = World.create({ seed: 'eco-c', surname: '龙', familyName: '龙家', motto: 'm', difficulty: 'normal' })
w.state.family.buildings = { yaoyuan: 3 }
w.state.family.inventory['beastcore'] = 0
for (let i = 0; i < 12; i++) w.advanceMonth()
expect((w.state.family.inventory['beastcore'] ?? 0) + 12).toBeGreaterThanOrEqual(12) // 每月保底1
})
it('价格漂移被夹在 [0.78, 1.25]', () => {
const w = World.create({ seed: 'eco-d', surname: '荀', familyName: '荀家', motto: 'm', difficulty: 'normal' })
for (let i = 0; i < 60; i++) w.advanceMonth()
const mult = w.state.family.flag['priceMult'] as number
expect(mult).toBeGreaterThanOrEqual(0.78)
expect(mult).toBeLessThanOrEqual(1.25)
})
it('marketPrice 基本价×行情×声望系数', () => {
const w = World.create({ seed: 'eco-e', surname: '柳', familyName: '柳家', motto: 'm', difficulty: 'normal' })
const base = ITEMS['lingcao'].basePrice
w.state.family.flag['priceMult'] = 1
w.state.family.reputation = 0
const p0 = marketPrice(w, 'lingcao')
expect(Math.abs(p0 - base)).toBeLessThanOrEqual(1)
w.state.family.flag['priceMult'] = 1.2
expect(marketPrice(w, 'lingcao')).toBeGreaterThan(p0)
})
it('买空仓拒绝、部分库存出售拒绝超卖', () => {
const w = World.create({ seed: 'eco-f', surname: '梁', familyName: '梁家', motto: 'm', difficulty: 'normal' })
w.state.family.stones = 5
expect(buyItem(w, 'lingcao', 1)).toBe(false)
w.state.family.stones = 99999
expect(buyItem(w, 'lingcao', 1000)).toBe(true)
expect(w.state.family.inventory['lingcao']).toBe(1060)
expect(sellItem(w, 'lingcao', 99999)).toBe(false)
expect(sellItem(w, 'lingcao', 1060)).toBe(true)
expect(w.state.family.inventory['lingcao']).toBe(0)
expect(sellItem(w, 'lingcao', 1)).toBe(false)
})
it('功法购买不可重复、收费合理', () => {
const w = World.create({ seed: 'eco-g', surname: '慕', familyName: '慕家', motto: 'm', difficulty: 'normal' })
w.state.family.stones = 99999
expect(buyTechnique(w, 't-zhenyu', techniquePrice('t-zhenyu'))).toBe(true)
expect(buyTechnique(w, 't-zhenyu', techniquePrice('t-zhenyu'))).toBe(false)
expect(w.state.family.stones).toBe(99999 - techniquePrice('t-zhenyu'))
})
it('丹房炼制消耗正确产出丹药', () => {
const w = World.create({ seed: 'eco-h', surname: '宋', familyName: '宋家', motto: 'm', difficulty: 'normal' })
w.state.family.buildings = { danfang: 1 }
const fam = w.state.family
fam.inventory['lingcao'] = 100
fam.inventory['beastcore'] = 10
fam.inventory['pill-qiyuan'] = 0
fam.inventory['pill-ningyuan'] = 0
fam.stones = 1000
const ok = w.craftPill('qiyuan')
expect(ok).toBe(true)
expect(fam.inventory['lingcao']).toBe(85)
expect(fam.inventory['pill-qiyuan']).toBe(1)
// 资源不足失败
fam.inventory['lingcao'] = 0
expect(w.craftPill('qiyuan')).toBe(false)
})
it('建筑耗材不足时拒绝升级(资源保持原值)', () => {
const w = World.create({ seed: 'eco-i', surname: '郝', familyName: '郝家', motto: 'm', difficulty: 'normal' })
const fam = w.state.family
fam.buildings = { lingtian: 1 }
fam.stones = 0
const stones0 = fam.stones
expect(w.upgrade('lingtian')).toBe(false)
expect(fam.stones).toBe(stones0)
})
it('祭祖成本与收益曲线确定', () => {
const w = World.create({ seed: 'eco-j', surname: '施', familyName: '施家', motto: 'm', difficulty: 'normal' })
const fam = w.state.family
fam.buildings = { zongci: 2, lingtian: 1 }
fam.stones = 1000
const rep0 = fam.reputation
expect(w.ancestralRite()).toBe(true)
expect(fam.stones).toBe(850)
expect(fam.reputation).toBe(rep0 + 6)
})
})