import { beforeEach, describe, expect, it } from "vitest"; import { abilitiesForCharacter } from "./abilityCatalog"; import { useCombatStore, stableCombatUnit } from "./combatStore"; import { ROM_PRIEST_CHAMPION_REGENERATE_PROC_AURA_ID } from "./romPriestChampionOverrides"; import { createConfiguredPartyMember, usePartyStore } from "./partyStore"; import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime"; import { clearPartyRuntimeRegistry, registerPartyRuntimePosition } from "./partyRuntimeRegistry"; describe("RoM Priest/Champion Protection Rune Seal companion reset", () => { beforeEach(() => { clearPartyRuntimeRegistry(); resetPartyRuntimeClock(); useCombatStore.getState().initializeCharacter({ classId: "rom-warrior", raceId: "rom-human", level: 80, }); usePartyStore.getState().initializeParty("priest-protection-rune-seal", 80, useCombatStore.getState().health, "damage", 1, "rom"); }); it("resets only its Priest/Champion owner's Heart Rune Energy on a successful Regenerate heal tick", () => { const member = createConfiguredPartyMember({ name: "Priest Champion", classId: "rom-priest", secondaryClassId: "rom-champion", specialization: "Healer", role: "healer", talentRanks: {}, }, 80, 0, "protection-rune-seal"); const abilities = abilitiesForCharacter(member.classId, member.secondaryClassId); const regenerate = abilities.find((ability) => ability.dbcSpellId === 490_269)!; const heartRuneEnergy = abilities.find((ability) => ability.dbcSpellId === 498_612)!; const unrelatedCooldowns = { ...member.cooldowns, [heartRuneEnergy.id]: 33_333 }; const readyAtFirstTick = { ...member, cooldowns: unrelatedCooldowns, activeCast: { abilityId: regenerate.id, school: "nature" as const, mode: "cast" as const, startedAt: 1_000, completesAt: 1_000, originalDurationMs: 0, pushbackHits: 0, origin: [0, 0, 0] as const, targetId: member.id, }, activeCastTargetId: member.id, status: "healing" as const, }; usePartyStore.setState({ members: [readyAtFirstTick] }); useCombatStore.setState((state) => ({ cooldowns: { ...state.cooldowns, [heartRuneEnergy.id]: 22_222 }, })); registerPartyRuntimePosition(member.id, [0, 0, 0]); useCombatStore.getState().synchronizeActors(); advanceDungeonPartyCombat(1_000); const protectionAura = useCombatStore.getState().auras.find((aura) => ( aura.definition.id === ROM_PRIEST_CHAMPION_REGENERATE_PROC_AURA_ID )); expect(protectionAura).toMatchObject({ sourceId: member.id, targetId: member.id }); const hot = useCombatStore.getState().effects.find((effect) => ( effect.kind === "hot" && effect.sourceActorId === member.id && effect.sourceAbilityId === regenerate.id )); expect(hot).toBeDefined(); const partyCooldown = () => usePartyStore.getState().members .find((candidate) => candidate.id === member.id)!.cooldowns[heartRuneEnergy.id]; expect(partyCooldown()).toBe(33_333); useCombatStore.getState().tick(0, 2_999); expect(partyCooldown()).toBe(33_333); // The actor-owned proc rolls below the established local 8% boundary at this first tick. expect(stableCombatUnit( `${protectionAura!.instanceId}:rom-priest-protection-rune-seal-reset:periodic:${regenerate.id}:${member.id}:3000`, )).toBeLessThan(0.08); useCombatStore.getState().tick(0, 3_000); expect(partyCooldown()).toBe(0); expect(useCombatStore.getState().cooldowns[heartRuneEnergy.id]).toBe(22_222); }); });