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); }); });