import { describe, expect, it } from 'vitest' import { World } from '../src/renderer/game/engine/runtime/World' import { resolveEncounter, combatPowerOf, rollWarbooty } from '../src/renderer/game/engine/runtime/Systems/combat' import { sendMission } from '../src/renderer/game/engine/runtime/Systems/missions' import { MISSIONS } from '../src/renderer/game/data/secrets' import { FORMATIONS } from '../src/renderer/game/data/formations' import { WorldSim } from '../src/renderer/game/engine/sim/WorldSim' function mk(seed: string): World { return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' }) } const ENEMIES_SAMPLE = [ { id: 'e-huiyuan', name: '灰狼王', realm: 'qi', strength: 0.8, icon: '狼', desc: 'x' }, { id: 'e-tiebei', name: '铁背熊罴', realm: 'qi', strength: 1.1, icon: '熊', desc: 'x' }, { id: 'e-muche', name: '赤瞳木魅', realm: 'foundation', strength: 1.0, icon: '木', desc: 'x' }, { id: 'e-baiqi', name: '白骨修士', realm: 'foundation', strength: 1.2, icon: '骨', desc: 'x' } ] describe('矩阵:遭遇战', () => { it.each(ENEMIES_SAMPLE.map((e) => [e.id, e.strength] as const))( '敌人 %s:风险 0.5 下遭遇结算合法(胜负/平三向)', (id, strength) => { const w = mk(`enc-${id}`) const team = [w.state.members['x1']!, w.state.members['x2']!, w.state.members['x3']!, w.state.members['x4']!] for (const c of team) { c.realm = { major: 'core', minor: 0 }; c.health = 100 } const res = resolveEncounter(w, { title: '遭遇', enemy: { id, name: '敌', realm: 'qi', strength, icon: '险', desc: 'x' }, risk: 0.5, team, kind: 'mission', year: 1, month: 1 }) expect(['win', 'draw', 'lose'].includes(res.win ? 'win' : res.draw ? 'draw' : 'lose')).toBe(true) }) it.each([ ['四人满编', 4, 'core'], ['两人', 2, 'core'], ['一人', 1, 'core'], ['低境界队', 4, 'qi'] ] as const)('%s:combatPower 正且随境界升', (label, n, realm) => { const w = mk(`cp-${label}`) const team = Object.values(w.state.members).slice(0, n) for (const c of team) c.realm = { major: realm as never, minor: 0 } const powers = team.map((c) => combatPowerOf(w, c)) for (const p of powers) expect(p).toBeGreaterThan(0) }) it.each([ ['锋阵', 'vanguard'], ['雁行', 'echelon'], ['蛇行', 'serpent'] ] as const)('阵型 %s:列阵战力合成非负', (label, fid) => { const w = mk(`ff-${label}`) const team = [w.state.members['x1']!, w.state.members['x2']!] for (const c of team) c.realm = { major: 'foundation', minor: 1 } expect(FORMATIONS[fid as never]).toBeTruthy() expect(combatPowerOf(w, team[0]!)).toBeGreaterThan(0) }) it.each([ ['灵盛', 1.5], ['灵中', 0.9], ['灵竭', 0.5] ] as const)('战利 %s:qiRatio 缩放大不越界', (label, qr) => { const w = mk(`loot-${label}`) const loot = rollWarbooty(w, { resources: { lingcao: [20, 60], lingkuang: [5, 15] }, artifactChance: 0.05, techniqueChance: 0.03 }, qr) for (const v of Object.values(loot)) { if (typeof v === 'number') expect(v).toBeGreaterThanOrEqual(0) } }) }) describe('矩阵:探险任务', () => { it.each(MISSIONS.map((m) => [m.id, m.name, m.minMembers, m.maxMembers, m.realmHint] as const))( '秘境 %s:可遣队且有段/成员参数', (id, name, min, max, hint) => { const w = mk(`ms-${id}`) const squad = Object.values(w.state.members).slice(0, Math.min(max, 4)) const ok = sendMission(w, id, squad.map((c) => c.id)) expect(typeof ok).toBe('boolean') expect(name.length).toBeGreaterThan(0) expect(min).toBeGreaterThanOrEqual(1) void hint }) it.each([ ['未满员', 1], ['达标', 2], ['满编', 4] ] as const)('遣队 %s:要求校验(不足拒绝/达标放行)', (label, squadN) => { const w = mk(`sq-${label}`) const def = MISSIONS.find((m) => m.id === 'm-anmoku')! const squad = Object.values(w.state.members).slice(0, squadN) const ok = sendMission(w, def.id, squad.map((c) => c.id)) if (squadN < def.minMembers) expect(ok).toBe(false) else expect(ok).toBe(true) }) it.each([ ['草灵丰饶', 100], ['半枯', 50], ['将竭', 10] ] as const)('灵气 %s:secretQiOf 值域与折减合法', (label, qi) => { const w = mk(`qi-${label}`) const sim = new WorldSim(w) expect(sim.secretQiOf('m-anmoku')).toBeGreaterThanOrEqual(0) expect(sim.secretQiOf('m-anmoku')).toBeLessThanOrEqual(100) }) })