import { beforeEach, describe, expect, it } from "vitest"; import { useCombatStore } from "./combatStore"; import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry"; import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime"; import { clearPartyRuntimeRegistry, registerPartyRuntimePosition, updatePartyRuntimeTargetVisibility } from "./partyRuntimeRegistry"; import { createConfiguredPartyMember, usePartyStore } from "./partyStore"; import { abilityById } from "./abilityCatalog"; import { EMPTY_ITEM_STATS } from "./itemStats"; describe("Knight/Rogue God's Vengeance linked Punishment", () => { beforeEach(() => { clearMobRuntimeRegistry(); clearPartyRuntimeRegistry(); resetPartyRuntimeClock(); useCombatStore.getState().initializeCharacter({ classId: "rom-knight", secondaryClassId: "rom-rogue", raceId: "rom-human", level: 80, }); usePartyStore.getState().initializeParty( "knight-rogue-gods-vengeance", 80, useCombatStore.getState().health, "damage", 2, "rom", ); }); it("resets only the owning companion's Shadow Step cooldown after its landed exact-four Seal child cast", () => { const punishment = abilityById("rom-knight-rom-rogue-elite-50-499909")!; const shadowStep = abilityById("rom-rogue-general-7")!; const member = createConfiguredPartyMember({ name: "Knight/Rogue", classId: "rom-knight", secondaryClassId: "rom-rogue", raceId: "rom-human", specialization: "Knight/Rogue", specializationId: "rom-knight:rom-rogue", talentTreeId: "rom-knight-rom-rogue", role: "damage", }, 80, 0, "knight-rogue-gods-vengeance"); const targetId = "knight-rogue-gods-vengeance-target"; useCombatStore.getState().registerMob(targetId, { name: targetId, level: 1, maxHealth: 1_000_000, xpReward: 0 }); setMobPosition(targetId, [2, 0, 0]); useCombatStore.getState().damageMob(targetId, 1, 100); usePartyStore.setState({ members: [{ ...member, gearStats: { ...member.gearStats, ...EMPTY_ITEM_STATS, hitRating: 1_000_000 }, comboPoints: 4, comboTargetId: targetId, cooldowns: { ...member.cooldowns, [shadowStep.id]: 30_000 }, activeCast: { abilityId: punishment.id, school: "holy", mode: "cast", startedAt: 1_000, completesAt: 1_000, originalDurationMs: 0, pushbackHits: 0, origin: [0, 0, 0], targetId, }, activeCastTargetId: targetId, status: "attacking", nextActionAt: 1_000, }] }); registerPartyRuntimePosition(member.id, [0, 0, 0]); updatePartyRuntimeTargetVisibility(member.id, targetId, true); useCombatStore.getState().synchronizeActors(); advanceDungeonPartyCombat(1_000); const updated = usePartyStore.getState().members.find((candidate) => candidate.id === member.id)!; expect(updated.comboPoints).toBe(0); expect(updated.cooldowns[shadowStep.id]).toBe(0); expect(useCombatStore.getState().actors[member.id]?.cooldowns[shadowStep.id]).toBe(0); const hit = useCombatStore.getState().combatEvents.find((event) => event.kind === "damage" && event.abilityId === punishment.id && event.targetActorId === targetId); expect(hit?.effectiveAmount).toBeGreaterThan(0); }); });