import { beforeEach, describe, expect, it } from "vitest"; import { PLAYER_AGGRO_ID } from "./aggro"; import { abilityById } from "./abilityCatalog"; import { useCombatStore } from "./combatStore"; import { advanceDungeonPartyCombat, resetPartyRuntimeClock, } from "./partyRuntime"; import { registerPartyRuntimePosition, clearPartyRuntimeRegistry } from "./partyRuntimeRegistry"; import { createConfiguredPartyMember, usePartyStore } from "./partyStore"; import { partyAbilityCosts } from "./partyAbilityAi"; import { ROM_ROGUE_ENERGIZED_HANDS_AURA_TAG, ROM_ROGUE_ENERGIZED_HANDS_COOLDOWN_REDUCTION_MS, ROM_ROGUE_ENERGIZED_HANDS_SKILL_ID, ROM_ROGUE_POISONOUS_HANDS_EXCLUSIVE_GROUP, } from "./romRogueEnergizedHandsRuntime"; import { ROM_ROGUE_POISON_AURA_TAG, ROM_ROGUE_POISON_SKILL_ID } from "./romRoguePoisonRuntime"; describe("RoM Rogue current CoA Hands skills", () => { beforeEach(() => { clearPartyRuntimeRegistry(); resetPartyRuntimeClock(); useCombatStore.getState().initializeCharacter({ classId: "rom-rogue", raceId: "rom-human", level: 50, xp: 0 }); useCombatStore.setState({ playerPosition: [0, 0, 0] }); }); it("replaces the local 490347 Numbing Dagger row with Energized Hands and applies its player mechanics", () => { const energized = abilityById("rom-rogue-primary-5")!; const poisoned = abilityById("rom-rogue-primary-6")!; expect(energized).toMatchObject({ dbcSpellId: ROM_ROGUE_ENERGIZED_HANDS_SKILL_ID, name: "Energized Hands", target: "self", castTimeMs: 1_000, cooldownMs: 0, }); expect(energized.description).toContain("maximum Energy by 50%"); expect(poisoned).toMatchObject({ dbcSpellId: ROM_ROGUE_POISON_SKILL_ID, name: "Poisonous Hands", target: "self" }); const poisonAura = poisoned.effects.find((effect) => effect.kind === "apply-aura"); expect(poisonAura?.kind === "apply-aura" && poisonAura.aura.exclusiveGroup) .toBe(ROM_ROGUE_POISONOUS_HANDS_EXCLUSIVE_GROUP); expect(energized.description).toContain("0.1 seconds"); expect(useCombatStore.getState().castAbility(energized.id, undefined, 1_000).ok).toBe(true); useCombatStore.getState().tick(1.1, 2_100); expect(useCombatStore.getState().maxResourcePools.energy).toBe(150); expect(useCombatStore.getState().auras.some((aura) => aura.targetId === PLAYER_AGGRO_ID && aura.definition.utilityTags?.includes(ROM_ROGUE_ENERGIZED_HANDS_AURA_TAG))).toBe(true); expect(useCombatStore.getState().castAbility("rom-rogue-primary-14", undefined, 3_600).ok).toBe(true); expect(useCombatStore.getState().cooldowns["rom-rogue-primary-14"]) .toBe(3_600 + 120_000 - ROM_ROGUE_ENERGIZED_HANDS_COOLDOWN_REDUCTION_MS); }); it("replaces Energized Hands with Poisonous Hands and restores the base Energy maximum", () => { expect(useCombatStore.getState().castAbility("rom-rogue-primary-5", undefined, 1_000).ok).toBe(true); useCombatStore.getState().tick(1.1, 2_100); expect(useCombatStore.getState().maxResourcePools.energy).toBe(150); expect(useCombatStore.getState().castAbility("rom-rogue-primary-6", undefined, 3_600).ok).toBe(true); useCombatStore.getState().tick(1.1, 4_700); const auras = useCombatStore.getState().auras.filter((aura) => aura.targetId === PLAYER_AGGRO_ID && aura.definition.exclusiveGroup === ROM_ROGUE_POISONOUS_HANDS_EXCLUSIVE_GROUP); expect(auras).toHaveLength(1); expect(auras[0]?.definition.utilityTags).toContain(ROM_ROGUE_POISON_AURA_TAG); expect(useCombatStore.getState().maxResourcePools.energy).toBe(100); }); it("applies Energized Hands Energy capacity, cost, and regeneration to a generated companion", () => { const member = createConfiguredPartyMember({ name: "Rogue companion", classId: "rom-rogue", specialization: "Primary", role: "damage", }, 50, 0, "rogue-energized-hands"); const energized = abilityById("rom-rogue-primary-5")!; const effect = energized.effects.find((candidate) => candidate.kind === "apply-aura"); if (effect?.kind !== "apply-aura") throw new Error("Missing Energized Hands aura effect."); usePartyStore.getState().initializeParty("rogue-energized-hands", 50, 1_000, "damage", 1, "rom"); usePartyStore.setState({ command: "stop", members: [{ ...member, nextActionAt: 100_000 }] }); registerPartyRuntimePosition(member.id, [0, 0, 0]); useCombatStore.getState().synchronizeActors(); expect(useCombatStore.getState().applyActorAura(member.id, member.id, energized, effect, 1_000)).toBe(true); let current = usePartyStore.getState().members[0]!; expect(current.maxResource).toBe(150); expect(useCombatStore.getState().actors[member.id]?.resources.energy?.maximum).toBe(150); const costProbe = { ...abilityById("rom-rogue-primary-14")!, cost: { resource: "energy" as const, amount: 25 }, costs: [{ resource: "energy" as const, amount: 25 }], }; expect(partyAbilityCosts(current, costProbe, 1_000)).toEqual([{ resource: "energy", amount: 30 }]); const reduced = { ...current, resource: 50, resourcePools: { ...current.resourcePools, energy: 50 } }; usePartyStore.setState({ members: [reduced] }); useCombatStore.getState().commitCompanionActors([reduced]); resetPartyRuntimeClock(); advanceDungeonPartyCombat(2_000); advanceDungeonPartyCombat(3_000); current = usePartyStore.getState().members[0]!; expect(current.resource).toBe(70); expect(useCombatStore.getState().actors[member.id]?.resources.energy?.maximum).toBe(150); }); });