85 lines
4.0 KiB
TypeScript
85 lines
4.0 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
||
import { abilitiesForClass, abilityAtLevel } from "./abilityCatalog";
|
||
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
|
||
import { useCombatStore } from "./combatStore";
|
||
import { clearPartyRuntimeRegistry, registerPartyRuntimePosition } from "./partyRuntimeRegistry";
|
||
import { usePartyStore } from "./partyStore";
|
||
|
||
const HEALING_STREAM_RANKS = [
|
||
{ level: 20, spellId: 5394, heal: 6 },
|
||
{ level: 30, spellId: 6375, heal: 8 },
|
||
{ level: 40, spellId: 6377, heal: 10 },
|
||
{ level: 50, spellId: 10462, heal: 12 },
|
||
{ level: 60, spellId: 10463, heal: 14 },
|
||
{ level: 69, spellId: 25567, heal: 18 },
|
||
{ level: 71, spellId: 58755, heal: 20 },
|
||
{ level: 76, spellId: 58756, heal: 23 },
|
||
{ level: 80, spellId: 58757, heal: 25 },
|
||
] as const;
|
||
|
||
function healingStreamAbility() {
|
||
const ability = abilitiesForClass("shaman").find((candidate) => candidate.name === "Healing Stream Totem");
|
||
expect(ability, "Healing Stream Totem").toBeDefined();
|
||
return ability!;
|
||
}
|
||
|
||
describe("WoW Shaman Healing Stream Totem", () => {
|
||
beforeEach(() => {
|
||
clearMobRuntimeRegistry();
|
||
clearPartyRuntimeRegistry();
|
||
useCombatStore.getState().initializeCharacter({ classId: "shaman", level: 80, xp: 0 });
|
||
useCombatStore.getState().setPlayerPosition([0, 0, 0]);
|
||
usePartyStore.getState().initializeParty("wow-healing-stream-test", 80, useCombatStore.getState().health);
|
||
});
|
||
|
||
it("uses each source rank’s 2-second heal amount", () => {
|
||
const base = healingStreamAbility();
|
||
for (const expected of HEALING_STREAM_RANKS) {
|
||
const ranked = abilityAtLevel(base, expected.level);
|
||
const summon = ranked.effects.find((effect) => effect.kind === "summon");
|
||
expect(ranked.dbcSpellId).toBe(expected.spellId);
|
||
expect(summon?.kind).toBe("summon");
|
||
if (summon?.kind !== "summon") continue;
|
||
expect(summon.healingPulse).toEqual({ amount: expected.heal, intervalMs: 2_000, radius: 10 });
|
||
expect(summon.durationMs).toBe(300_000);
|
||
}
|
||
});
|
||
|
||
it("heals every nearby party member and never attacks the selected enemy", () => {
|
||
const state = useCombatStore.getState();
|
||
const members = usePartyStore.getState().members;
|
||
useCombatStore.setState((current) => ({ health: current.maxHealth - 25 }));
|
||
usePartyStore.setState((current) => ({
|
||
members: current.members.map((member) => ({ ...member, health: member.maxHealth - 25 })),
|
||
}));
|
||
members.forEach((member, index) => {
|
||
registerPartyRuntimePosition(member.id, index === 0 ? [5, 0, 0] : index === 1 ? [9, 0, 0] : [10.1 + index, 0, 0]);
|
||
});
|
||
useCombatStore.getState().registerMob("healing-stream-nearby-enemy", { name: "Nearby enemy", maxHealth: 10_000 });
|
||
setMobPosition("healing-stream-nearby-enemy", [4, 0, 0]);
|
||
useCombatStore.getState().selectMob("healing-stream-nearby-enemy");
|
||
|
||
const cast = useCombatStore.getState().castAbility(healingStreamAbility().id, undefined, 1_000);
|
||
expect(cast.ok, JSON.stringify(cast)).toBe(true);
|
||
const totem = useCombatStore.getState().summons.find((summon) => (
|
||
summon.sourceAbilityId === healingStreamAbility().id
|
||
));
|
||
expect(totem).toBeDefined();
|
||
expect(totem?.kind).toBe("totem");
|
||
expect(totem?.maxHealth).toBe(5);
|
||
expect(totem?.attackDamage).toBe(0);
|
||
expect(totem?.expiresAt).toBe(301_000);
|
||
|
||
useCombatStore.getState().tick(0, 3_000);
|
||
|
||
const after = useCombatStore.getState();
|
||
expect(after.health).toBe(after.maxHealth);
|
||
expect(usePartyStore.getState().members[0]?.health).toBe(usePartyStore.getState().members[0]?.maxHealth);
|
||
expect(usePartyStore.getState().members[1]?.health).toBe(usePartyStore.getState().members[1]?.maxHealth);
|
||
expect(usePartyStore.getState().members[2]?.health).toBe((usePartyStore.getState().members[2]?.maxHealth ?? 0) - 25);
|
||
expect(after.mobs["healing-stream-nearby-enemy"]?.health).toBe(10_000);
|
||
expect(after.combatEvents.filter((event) => event.kind === "healing"
|
||
&& event.abilityId === healingStreamAbility().id)).toHaveLength(3);
|
||
});
|
||
});
|