Files
healer-man/src/game/wow335MageWintersChill.integration.test.ts
2026-10-02 10:38:12 -04:00

131 lines
5.4 KiB
TypeScript

import { beforeEach, describe, expect, it } from "vitest";
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
import { clearPartyRuntimeRegistry } from "./partyRuntimeRegistry";
import { PLAYER_AGGRO_ID } from "./aggro";
import { abilitiesForClass } from "./abilityCatalog";
import { resolveHealingValue } from "./combatAuras";
import { useCombatStore } from "./combatStore";
import { usePartyStore } from "./partyStore";
import { talentModifiersForRanks } from "./talentModifiers";
import { WOW335_MAGE_WINTERS_CHILL_TAG } from "./wow335MageWintersChillRuntime";
function registerTarget(id: string): void {
useCombatStore.getState().registerMob(id, { name: id, maxHealth: 100_000, xpReward: 0 });
setMobPosition(id, [8, 0, 0]);
}
function setPlayerWintersChillRank(rank: number): void {
useCombatStore.setState((state) => {
const talentRanks = { ...state.talentRanks, "talent-68": rank };
return {
talentRanks,
talentModifiers: talentModifiersForRanks(talentRanks, state.classId),
};
});
}
function setPartyMageWintersChillRank(memberId: string, rank: number): void {
usePartyStore.setState((state) => ({
members: state.members.map((member) => member.id === memberId ? {
...member,
classId: "mage",
talentRanks: { ...(rank > 0 ? { "talent-68": rank } : {}) },
resourceType: "mana",
resourceName: "Mana",
maxResource: 10_000,
resource: 9_000,
resourcePools: { ...member.resourcePools, mana: 9_000 },
} : member),
}));
}
function damageSpell(
targetId: string,
abilityId: string,
school: "fire" | "frost",
now: number,
sourceActorId = PLAYER_AGGRO_ID,
periodic = false,
): number {
const member = usePartyStore.getState().members.find((candidate) => candidate.id === sourceActorId);
useCombatStore.getState().damageMob(targetId, 100, now, {
actorId: sourceActorId,
role: member?.role ?? "damage",
abilityId,
}, school, {
attackKind: "spell",
seed: `wow335-mage-winters-chill:${sourceActorId}:${targetId}:${abilityId}:${now}`,
abilityId,
periodic,
rules: { canMiss: false, canCrit: true, canDodge: false, canParry: false, canBlock: false },
});
return useCombatStore.getState().lastCombatResult!.attackTable.criticalPercent;
}
describe("WoW Mage Winter's Chill combat integration", () => {
beforeEach(() => {
clearMobRuntimeRegistry();
clearPartyRuntimeRegistry();
useCombatStore.getState().initializeCharacter({ classId: "mage", level: 80, xp: 0 });
usePartyStore.getState().initializeParty("mage-winters-chill-tests", 1, useCombatStore.getState().health);
});
it("stacks on positive direct Frost hits and increases later Mage spell crit against the target", () => {
const frostbolt = abilitiesForClass("mage").find((ability) => ability.name === "Frostbolt")!;
const fireball = abilitiesForClass("mage").find((ability) => ability.name === "Fireball")!;
setPlayerWintersChillRank(3);
registerTarget("winter-chill-target");
registerTarget("winter-clean-target");
for (let stack = 0; stack < 6; stack += 1) {
damageSpell("winter-chill-target", frostbolt.id, "frost", 1_000 + stack * 1_000);
}
const aura = useCombatStore.getState().auras.find((candidate) => (
candidate.targetId === "winter-chill-target"
&& candidate.definition.utilityTags?.includes(WOW335_MAGE_WINTERS_CHILL_TAG)
));
expect(aura?.stacks).toBe(5);
expect(aura?.expiresAt).toBe(14_000);
expect(resolveHealingValue(1_000, [aura!], "taken")).toBeCloseTo(650);
const cleanCrit = damageSpell("winter-clean-target", fireball.id, "fire", 7_000);
const chilledCrit = damageSpell("winter-chill-target", fireball.id, "fire", 8_000);
expect(chilledCrit - cleanCrit).toBe(5);
});
it("uses party Mage ranks for passive crit, direct Frost procs, and incoming spell vulnerability", () => {
const frostbolt = abilitiesForClass("mage").find((ability) => ability.name === "Frostbolt")!;
const fireball = abilitiesForClass("mage").find((ability) => ability.name === "Fireball")!;
const member = usePartyStore.getState().members[0]!;
setPartyMageWintersChillRank(member.id, 0);
registerTarget("party-winter-clean");
registerTarget("party-winter-chill");
const baselineCrit = damageSpell("party-winter-clean", fireball.id, "fire", 1_000, member.id);
setPartyMageWintersChillRank(member.id, 3);
const frostCrit = damageSpell("party-winter-chill", frostbolt.id, "frost", 2_000, member.id);
const aura = useCombatStore.getState().auras.find((candidate) => (
candidate.targetId === "party-winter-chill"
&& candidate.definition.utilityTags?.includes(WOW335_MAGE_WINTERS_CHILL_TAG)
));
const chilledCrit = damageSpell("party-winter-chill", fireball.id, "fire", 3_000, member.id);
expect(frostCrit - baselineCrit).toBeCloseTo(3);
expect(aura?.stacks).toBe(1);
expect(chilledCrit - baselineCrit).toBeCloseTo(4);
});
it("does not arm the debuff from periodic Frost damage", () => {
const frostbolt = abilitiesForClass("mage").find((ability) => ability.name === "Frostbolt")!;
setPlayerWintersChillRank(3);
registerTarget("periodic-winter-target");
damageSpell("periodic-winter-target", frostbolt.id, "frost", 1_000, PLAYER_AGGRO_ID, true);
expect(useCombatStore.getState().auras.some((aura) => (
aura.targetId === "periodic-winter-target"
&& aura.definition.utilityTags?.includes(WOW335_MAGE_WINTERS_CHILL_TAG)
))).toBe(false);
});
});