Files
i-want-to-heal-mmo/src/game/battleSimulation.test.ts
T
2026-07-13 17:21:10 -04:00

44 lines
1.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { createClassInventory } from "./healers";
import { AVAILABLE_BOSS_IDS } from "./bossCatalog";
import { canAddBossToEncounter } from "./bossSelection";
import { useGameStore } from "./store";
import type { BossId } from "./types";
interface BattleResult {
phase: ReturnType<typeof useGameStore.getState>["phase"];
time: number;
damageBySource: ReturnType<typeof useGameStore.getState>["partyCombat"]["combatants"];
}
function simulateControlledBattle(bossIds: readonly [BossId, BossId], maxSeconds = 200): BattleResult {
useGameStore.getState().configureHealer("priest", "Aelia", createClassInventory("priest"), bossIds);
useGameStore.getState().startEncounter();
while (useGameStore.getState().phase === "combat" && useGameStore.getState().time < maxSeconds) {
useGameStore.setState((state) => ({
party: state.party.map((member) => ({ ...member, hp: member.maxHp, absorb: 10_000 })),
}));
useGameStore.getState().tick(0.1);
}
const state = useGameStore.getState();
return { phase: state.phase, time: state.time, damageBySource: state.partyCombat.combatants };
}
describe("full-mechanics dual-boss battle simulations", () => {
const combinations: readonly (readonly [BossId, BossId])[] = AVAILABLE_BOSS_IDS.flatMap((first, index) =>
AVAILABLE_BOSS_IDS.slice(index + 1)
.filter((second) => canAddBossToEncounter([first], second))
.map((second) => [first, second] as const),
);
it.each(combinations)("party rotations defeat %s + %s", (first, second) => {
const result = simulateControlledBattle([first, second]);
expect(result.phase).toBe("victory");
expect(result.time).toBeGreaterThanOrEqual(50);
expect(result.time).toBeLessThanOrEqual(100);
for (const memberId of ["brann", "nia", "orin", "vale"] as const) expect(result.damageBySource[memberId].damageDone).toBeGreaterThan(0);
});
});