import { beforeEach, describe, expect, it } from "vitest"; import { abilityById } from "./abilityCatalog"; import { PLAYER_AGGRO_ID } from "./aggro"; import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry"; import { useCombatStore, equipmentAdjustedCombatAmount } from "./combatStore"; import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime"; import { clearPartyRuntimeRegistry, registerPartyRuntimePosition, updatePartyRuntimeTargetVisibility } from "./partyRuntimeRegistry"; import { createConfiguredPartyMember, usePartyStore } from "./partyStore"; import { ROM_PRIEST_HOLY_BLESSING_TAG, romPriestHolyBlessingStats } from "./romPriestHolyBlessingRuntime"; import { resolveDamageValue } from "./combatAuras"; import { deriveCharacterStats } from "./wotlkStats"; const spell = abilityById("rom-priest-general-1"); const spellEffect = spell?.effects.find((effect) => effect.kind === "damage"); function damageWithSchool(targetId: string, sourceActorId: string, school: "holy" | "nature", now: number) { return useCombatStore.getState().damageMob( targetId, 1_000, now, { actorId: sourceActorId, role: "damage" }, school, { attackKind: "spell", seed: `holy-blessing:${sourceActorId}:${school}:${now}`, rules: { canMiss: false, canCrit: false, canDodge: false, canParry: false, canBlock: false, }, }, ).amount; } describe("RoM Priest Holy Blessing combat integration", () => { beforeEach(() => { clearMobRuntimeRegistry(); clearPartyRuntimeRegistry(); resetPartyRuntimeClock(); useCombatStore.getState().initializeCharacter({ classId: "rom-priest", raceId: "rom-human", level: 80, role: "healer", }); usePartyStore.getState().initializeParty( "rom-priest-holy-blessing-integration", 80, useCombatStore.getState().health, "healer", 2, "rom", ); for (const id of ["holy-blessing-holy-target", "holy-blessing-nature-target"]) { useCombatStore.getState().registerMob(id, { name: id, maxHealth: 100_000, level: 80 }); setMobPosition(id, [3, 0, 0]); } }); it("adds the Wisdom-derived spell power to a real player spell amount and buffs only Holy damage", () => { if (!spell || spellEffect?.kind !== "damage") throw new Error("Missing generated Priest spell damage row"); const state = useCombatStore.getState(); const passiveAura = state.auras.find((aura) => aura.targetId === PLAYER_AGGRO_ID && aura.definition.utilityTags?.includes(ROM_PRIEST_HOLY_BLESSING_TAG)); expect(passiveAura).toBeDefined(); const base = deriveCharacterStats("rom-priest", 80, state.gearStats, state.raceId, {}, state.secondaryClassId); const bonus = romPriestHolyBlessingStats(base, state.auras).spellPowerBonus; const expectedAmount = equipmentAdjustedCombatAmount(spellEffect, 80, state.gearStats, "rom-priest", spell, bonus); const unblessedAmount = equipmentAdjustedCombatAmount(spellEffect, 80, state.gearStats, "rom-priest", spell); const playerSourceAuras = state.auras.filter((aura) => aura.targetId === PLAYER_AGGRO_ID); const expectedCombatAmount = resolveDamageValue(expectedAmount, playerSourceAuras, { direction: "dealt", school: "frost", attackKind: "spell", }); const unblessedCombatAmount = resolveDamageValue( unblessedAmount, playerSourceAuras.filter((aura) => !aura.definition.utilityTags?.includes(ROM_PRIEST_HOLY_BLESSING_TAG)), { direction: "dealt", school: "frost", attackKind: "spell" }, ); expect(bonus).toBeGreaterThan(0); expect(expectedCombatAmount).toBeGreaterThan(unblessedCombatAmount); useCombatStore.getState().selectMob("holy-blessing-nature-target"); expect(useCombatStore.getState().castAbility(spell.id, undefined, 1_000)).toMatchObject({ ok: true }); useCombatStore.getState().tick(3, 5_000); const damage = useCombatStore.getState().combatEvents.find((event) => event.kind === "damage" && event.sourceActorId === PLAYER_AGGRO_ID && event.abilityId === spell.id); expect(damage).toBeDefined(); expect(damage?.rawAmount).toBe(Math.round(expectedCombatAmount * (damage?.critical ? 1.5 : 1))); const holy = damageWithSchool("holy-blessing-holy-target", PLAYER_AGGRO_ID, "holy", 21_000); const nature = damageWithSchool("holy-blessing-nature-target", PLAYER_AGGRO_ID, "nature", 22_000); expect(holy).toBe(2_009); expect(nature).toBe(1_000); }); it("adds the Wisdom-derived spell power to a generated-companion spell and buffs only Holy damage", () => { if (!spell || spellEffect?.kind !== "damage") throw new Error("Missing generated Priest spell damage row"); const seed = "rom-priest-holy-blessing-companion"; const priest = createConfiguredPartyMember({ name: "Holy Blessing Priest", classId: "rom-priest", specialization: "Primary", role: "healer", }, 80, 0, seed); usePartyStore.setState({ members: [{ ...priest, status: "attacking", resource: 10_000, maxResource: 10_000, resourcePools: { ...priest.resourcePools, mana: 10_000 }, activeCast: { abilityId: spell.id, school: "frost", mode: "cast", startedAt: 500, completesAt: 1_000, originalDurationMs: 500, pushbackHits: 0, origin: [0, 0, 0], targetId: "holy-blessing-nature-target", }, activeCastTargetId: "holy-blessing-nature-target", }] }); registerPartyRuntimePosition(priest.id, [0, 0, 0]); updatePartyRuntimeTargetVisibility(priest.id, "holy-blessing-nature-target", true); usePartyStore.getState().setCommand("attack"); useCombatStore.getState().synchronizeActors(); const beforeCastAuras = useCombatStore.getState().auras.filter((aura) => aura.targetId === priest.id); expect(beforeCastAuras.some((aura) => aura.definition.utilityTags?.includes(ROM_PRIEST_HOLY_BLESSING_TAG))) .toBe(false); advanceDungeonPartyCombat(1_000); const state = useCombatStore.getState(); const companionAura = state.auras.filter((aura) => aura.targetId === priest.id); expect(companionAura.some((aura) => aura.definition.utilityTags?.includes(ROM_PRIEST_HOLY_BLESSING_TAG))) .toBe(true); const base = deriveCharacterStats( priest.classId, priest.level, priest.gearStats, priest.raceId, {}, priest.secondaryClassId, ); const bonus = romPriestHolyBlessingStats(base, companionAura).spellPowerBonus; const expectedAmount = equipmentAdjustedCombatAmount(spellEffect, 80, priest.gearStats, "rom-priest", spell, bonus); const unblessedAmount = equipmentAdjustedCombatAmount(spellEffect, 80, priest.gearStats, "rom-priest", spell); expect(bonus).toBeGreaterThan(0); expect(expectedAmount).toBeGreaterThan(unblessedAmount); const damage = state.combatEvents.find((event) => event.kind === "damage" && event.sourceActorId === priest.id && event.abilityId === spell.id); expect(damage).toBeDefined(); expect(damage?.rawAmount).toBe(expectedAmount); const holy = damageWithSchool("holy-blessing-holy-target", priest.id, "holy", 5_000); const nature = damageWithSchool("holy-blessing-nature-target", priest.id, "nature", 6_000); expect(holy).toBe(2_009); expect(nature).toBe(1_000); }); });