import { beforeEach, describe, expect, it } from "vitest"; import { ROM_ALL_ABILITIES, romTriggeredAbilityBySpellId } from "./romAbilityCatalog"; import { applyAura, absorbDamage } from "./combatAuras"; import { PLAYER_AURA_ENTITY_ID, useCombatStore } from "./combatStore"; import { clearPartyRuntimeRegistry, registerPartyRuntimePosition } from "./partyRuntimeRegistry"; import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry"; import { DEFAULT_ENEMY_ATTACK } from "./enemyAttacks"; import { createConfiguredPartyMember, usePartyStore } from "./partyStore"; import { EMPTY_ITEM_STATS } from "./itemStats"; import { romEffectsForCast, type RomCastMechanics } from "./romCombatMechanics"; import { ROM_WARDEN_BRIAR_SHIELD_TAG, ROM_WARDEN_DAMAGE_TRANSFER_FRACTION, ROM_WARDEN_DAMAGE_TRANSFER_TAG, ROM_WARDEN_OAK_BLESSING_TAG, ROM_WARDEN_TOUGH_OAK_TAG, ROM_WARDEN_WILL_ATTACK_TAG, romWardenBriarShieldReflectDamage, romWardenBriarShieldReflectFraction, romWardenBriarShieldShouldReflect, } from "./romWardenOverrides"; const emptyContext: RomCastMechanics = { sealStacks: 0, bleedCount: 0, charged: false, mainHandDagger: false, casterMaxHealth: 2_000, targetHealthPercent: 1, }; function effectsFor(spellId: number, context: Partial = {}) { const ability = ROM_ALL_ABILITIES.find((entry) => entry.dbcSpellId === spellId)!; expect(ability).toBeDefined(); return romEffectsForCast(ability, { ...emptyContext, ...context }); } function initializeRomCharacter( classId: "rom-warden" | "rom-warrior" | "rom-druid", secondaryClassId?: "rom-warden" | "rom-warrior" | "rom-mage", ) { useCombatStore.getState().initializeCharacter({ classId, ...(secondaryClassId ? { secondaryClassId } : {}), raceId: classId === "rom-warrior" ? "rom-human" : "rom-elf", level: 80, }); useCombatStore.setState((state) => ({ resource: 1_000, maxResource: 1_000, resourcePools: { ...state.resourcePools, mana: 1_000, rage: 1_000, "nature-power": 0 }, maxResourcePools: { ...state.maxResourcePools, mana: 1_000, rage: 1_000, "nature-power": 100 }, })); } describe("RoM Warden and Warden-linked source behaviors", () => { beforeEach(() => { clearPartyRuntimeRegistry(); clearMobRuntimeRegistry(); useCombatStore.setState({ playerPosition: [0, 0, 0] }); }); it("casts Briar Shield as its source-backed defense aura without an immediate damage hit", () => { initializeRomCharacter("rom-warden"); const ability = ROM_ALL_ABILITIES.find((entry) => entry.dbcSpellId === 493642)!; expect(ability.effects).toHaveLength(1); expect(ability.effects[0]).toMatchObject({ kind: "apply-aura", recipient: "caster", aura: { durationMs: 900_000, modifiers: [{ kind: "stat", stat: "armor", operation: "percent", value: 0.05 }], utilityTags: expect.arrayContaining([ROM_WARDEN_BRIAR_SHIELD_TAG]), }, }); expect(ability.effects.some((effect) => effect.kind === "damage")).toBe(false); const mobId = "briar-shield-cast-target"; useCombatStore.getState().registerMob(mobId, { name: "Briar Shield target", maxHealth: 100_000 }); setMobPosition(mobId, [2, 0, 0]); useCombatStore.getState().selectMob(mobId); const now = 10_000; expect(useCombatStore.getState().castAbility(ability.id, undefined, now)).toMatchObject({ ok: true }); const state = useCombatStore.getState(); expect(state.mobs[mobId]?.health).toBe(100_000); expect(state.auras.find((aura) => aura.targetId === PLAYER_AURA_ENTITY_ID && aura.definition.utilityTags?.includes(ROM_WARDEN_BRIAR_SHIELD_TAG))).toMatchObject({ appliedAt: now, expiresAt: now + 900_000, definition: { modifiers: [{ kind: "stat", stat: "armor", operation: "percent", value: 0.05 }], }, }); }); it("maps Briar Shield's reflected component to source-level main-hand DPS", () => { const weapon = { damageMin: 100, damageMax: 120, damageSchool: "physical" as const, speedMs: 2_000 }; expect(romWardenBriarShieldReflectFraction(80)).toBeCloseTo(0.074); expect(romWardenBriarShieldReflectFraction(105)).toBeCloseTo(0.094); expect(romWardenBriarShieldReflectDamage(80, weapon)).toBe(4); expect(romWardenBriarShieldReflectDamage(105, weapon)).toBe(5); expect(romWardenBriarShieldReflectDamage(80, null)).toBe(0); const validPhysicalHit = { auraActive: true, landed: true, school: "physical", attackKind: "melee" as const, withinRange: true, }; expect(romWardenBriarShieldShouldReflect(validPhysicalHit)).toBe(true); expect(romWardenBriarShieldShouldReflect({ ...validPhysicalHit, attackKind: "ranged" })).toBe(true); expect(romWardenBriarShieldShouldReflect({ ...validPhysicalHit, school: "fire" })).toBe(false); expect(romWardenBriarShieldShouldReflect({ ...validPhysicalHit, attackKind: "spell" })).toBe(false); expect(romWardenBriarShieldShouldReflect({ ...validPhysicalHit, landed: false })).toBe(false); expect(romWardenBriarShieldShouldReflect({ ...validPhysicalHit, auraActive: false })).toBe(false); expect(romWardenBriarShieldShouldReflect({ ...validPhysicalHit, withinRange: false })).toBe(false); }); it("reflects landed physical projectiles, but not magic or attacks beyond 50 range", () => { const reflectedFrom = (school: "physical" | "fire", attackerDistance: number) => { clearMobRuntimeRegistry(); initializeRomCharacter("rom-warden"); const weapon = { damageMin: 100, damageMax: 120, damageSchool: "physical" as const, speedMs: 2_000 }; useCombatStore.setState((state) => ({ gearStats: { ...state.gearStats, meleeWeapon: weapon }, })); const mobId = `briar-reflect-${school}-${attackerDistance}`; useCombatStore.getState().registerMob(mobId, { name: "Briar Shield attacker", maxHealth: 100_000, level: 100, attacks: [{ ...DEFAULT_ENEMY_ATTACK, id: `briar-reflect-${school}`, delivery: "projectile", school, range: 100, initialCooldownMs: [0, 0], }], }); setMobPosition(mobId, [attackerDistance, 0, 0]); useCombatStore.getState().selectMob(mobId); expect(useCombatStore.getState().castAbility("rom-warden-general-1", undefined, 1_000)) .toMatchObject({ ok: true }); expect(useCombatStore.getState().castAbility("rom-warden-primary-11", undefined, 3_000)) .toMatchObject({ ok: true }); useCombatStore.getState().damageMob(mobId, 1, 3_000); const healthBeforeIncomingHit = useCombatStore.getState().mobs[mobId]!.health; const incomingDamage = useCombatStore.getState().advanceMobCombat(3_450, [0, 0, 0]); const healthAfterIncomingHit = useCombatStore.getState().mobs[mobId]!.health; return { incomingDamage, reflectedDamage: healthBeforeIncomingHit - healthAfterIncomingHit }; }; const physicalHit = reflectedFrom("physical", 2); expect(physicalHit.incomingDamage).toBeGreaterThan(0); expect(physicalHit.reflectedDamage).toBe(4); const magicHit = reflectedFrom("fire", 2); expect(magicHit.incomingDamage).toBeGreaterThan(0); expect(magicHit.reflectedDamage).toBe(0); const outOfRangePhysicalHit = reflectedFrom("physical", 60); expect(outOfRangePhysicalHit.incomingDamage).toBeGreaterThan(0); expect(outOfRangePhysicalHit.reflectedDamage).toBe(0); }); it("uses Briar Shield's defense aura against physical enemy attacks", () => { const incomingDamage = (withBriarShield: boolean) => { clearMobRuntimeRegistry(); initializeRomCharacter("rom-warden", "rom-warrior"); const mobId = "briar-shield-defense-attacker"; useCombatStore.getState().registerMob(mobId, { name: "Briar Shield attacker", maxHealth: 100_000, level: 100, attacks: [{ ...DEFAULT_ENEMY_ATTACK, id: "briar-shield-physical-swing", delivery: "projectile", initialCooldownMs: [0, 0] }], }); setMobPosition(mobId, [2, 0, 0]); useCombatStore.getState().selectMob(mobId); if (withBriarShield) { expect(useCombatStore.getState().castAbility("rom-warden-general-1", undefined, 1_000)) .toMatchObject({ ok: true }); } expect(useCombatStore.getState().castAbility("rom-warden-primary-11", undefined, 3_000)) .toMatchObject({ ok: true }); useCombatStore.getState().damageMob(mobId, 1, 3_000); return useCombatStore.getState().advanceMobCombat(3_450, [0, 0, 0]); }; const withoutBriarShield = incomingDamage(false); const withBriarShield = incomingDamage(true); expect(withoutBriarShield).toBeGreaterThan(0); expect(withBriarShield).toBeGreaterThan(0); expect(withBriarShield).toBeLessThan(withoutBriarShield); }); it("gates Will Attack's 10% damage reduction on the passive and places it on Frantic Briar's target", () => { const passive = effectsFor(494610).find((effect) => effect.kind === "apply-aura"); expect(passive?.kind).toBe("apply-aura"); if (passive?.kind === "apply-aura") { expect(passive.aura.utilityTags).toContain(ROM_WARDEN_WILL_ATTACK_TAG); expect(passive.aura.modifiers ?? []).toHaveLength(0); } const withoutPassive = effectsFor(493391); expect(withoutPassive.some((effect) => effect.kind === "apply-aura" && effect.sourceAuraType === 173)).toBe(false); expect(withoutPassive.some((effect) => effect.kind === "apply-aura" && effect.sourceAuraType === 24)).toBe(true); expect(withoutPassive.filter((effect) => effect.kind === "damage")).toHaveLength(2); const withPassive = effectsFor(493391, { passiveTags: [ROM_WARDEN_WILL_ATTACK_TAG] }); expect(withPassive.filter((effect) => effect.kind === "damage")).toHaveLength(2); expect(withPassive.filter((effect) => effect.kind === "apply-aura" && effect.sourceAuraType === 173)).toHaveLength(1); expect(withPassive.find((effect) => effect.kind === "apply-aura" && effect.aura.id === "rom-warden-will-attack")) .toMatchObject({ kind: "apply-aura", recipient: "ability-target", aura: { name: "Will Attack", disposition: "debuff", durationMs: 10_000, modifiers: [{ kind: "damage", direction: "dealt", attackKind: "melee", operation: "percent", value: -0.1 }], }, }); }); it("reduces a Frantic Briar target's melee hit only while Will Attack is learned", () => { const incomingDamage = (withWillAttack: boolean) => { clearMobRuntimeRegistry(); initializeRomCharacter("rom-warden", "rom-warrior"); if (!withWillAttack) { useCombatStore.setState((state) => ({ auras: state.auras.filter((aura) => !aura.definition.utilityTags?.includes(ROM_WARDEN_WILL_ATTACK_TAG)), })); } const mobId = "will-attack-target"; useCombatStore.getState().registerMob(mobId, { name: "Will Attack target", maxHealth: 100_000, attacks: [{ ...DEFAULT_ENEMY_ATTACK, id: "will-attack-swing", initialCooldownMs: [0, 0] }], }); setMobPosition(mobId, [2, 0, 0]); useCombatStore.getState().selectMob(mobId); const hasPassive = useCombatStore.getState().auras.some((aura) => ( aura.targetId === PLAYER_AURA_ENTITY_ID && aura.definition.utilityTags?.includes(ROM_WARDEN_WILL_ATTACK_TAG) )); expect(hasPassive).toBe(withWillAttack); expect(useCombatStore.getState().castAbility("rom-warden-primary-11", undefined, 1_000)) .toMatchObject({ ok: true }); const targetDebuff = useCombatStore.getState().auras.some((aura) => ( aura.targetId === mobId && aura.definition.id === "rom-warden-will-attack" )); expect(targetDebuff).toBe(withWillAttack); useCombatStore.getState().damageMob(mobId, 1, 1_000); return useCombatStore.getState().advanceMobCombat(1_450, [0, 0, 0]); }; const normalDamage = incomingDamage(false); const reducedDamage = incomingDamage(true); expect(normalDamage).toBeGreaterThan(0); expect(reducedDamage).toBeCloseTo(normalDamage * 0.9, 0); }); it("reduces Warden Punch and Sepal Stab cooldowns by one second with Tough Oak", () => { expect(effectsFor(493382).some((effect) => effect.kind === "cooldown-reset")).toBe(false); initializeRomCharacter("rom-warden", "rom-mage"); const state = useCombatStore.getState(); const toughOak = state.abilities.find((ability) => ability.dbcSpellId === 494207); expect(toughOak).toMatchObject({ passive: true, secondaryClassId: "rom-mage" }); expect(state.auras.some((aura) => aura.targetId === PLAYER_AURA_ENTITY_ID && aura.definition.utilityTags?.includes(ROM_WARDEN_TOUGH_OAK_TAG))).toBe(true); const mobId = "tough-oak-target"; useCombatStore.getState().registerMob(mobId, { name: "Tough Oak target", maxHealth: 100_000 }); setMobPosition(mobId, [3, 0, 0]); useCombatStore.getState().selectMob(mobId); expect(useCombatStore.getState().castAbility("rom-warden-primary-2", undefined, 1_000).ok).toBe(true); expect(useCombatStore.getState().cooldowns["rom-warden-primary-2"]).toBe(5_000); expect(useCombatStore.getState().castAbility("rom-warden-primary-14", undefined, 2_500).ok).toBe(true); expect(useCombatStore.getState().cooldowns["rom-warden-primary-14"]).toBe(6_500); }); it("activates Oak Blessing's attack and periodic-healing riders only with Heart of the Oak", () => { initializeRomCharacter("rom-warden", "rom-mage"); const passive = useCombatStore.getState().abilities.find((ability) => ability.dbcSpellId === 494011)!; expect(passive).toMatchObject({ passive: true, secondaryClassId: "rom-mage" }); expect(passive.effects).toHaveLength(1); expect(passive.effects[0]).toMatchObject({ kind: "apply-aura", aura: { utilityTags: [ROM_WARDEN_OAK_BLESSING_TAG] }, }); expect(useCombatStore.getState().auras.some((aura) => aura.targetId === PLAYER_AURA_ENTITY_ID && aura.definition.utilityTags?.includes(ROM_WARDEN_OAK_BLESSING_TAG))).toBe(true); expect(useCombatStore.getState().auras.some((aura) => aura.targetId === PLAYER_AURA_ENTITY_ID && aura.definition.modifiers?.some((modifier) => modifier.kind === "stat" && modifier.stat === "attack-power"))).toBe(false); const now = 10_000; expect(useCombatStore.getState().castAbility("rom-warden-primary-10", undefined, now)).toMatchObject({ ok: true }); const stateAfterCast = useCombatStore.getState(); expect(stateAfterCast.auras.find((aura) => aura.targetId === PLAYER_AURA_ENTITY_ID && aura.definition.modifiers?.some((modifier) => modifier.kind === "stat" && modifier.stat === "attack-power"))).toMatchObject({ expiresAt: now + 60_000, definition: { modifiers: [{ kind: "stat", stat: "attack-power", operation: "percent", value: 0.05 }], }, }); expect(stateAfterCast.effects.find((effect) => effect.kind === "hot" && effect.sourceAbilityId === "rom-warden-primary-10")).toMatchObject({ remainingTicks: 20, intervalMs: 3_000, nextTickAt: now + 3_000, percentMaxHealth: 0.01, }); const healthBefore = stateAfterCast.maxHealth - 200; useCombatStore.setState({ health: healthBefore }); useCombatStore.getState().tick(3, now + 3_000); expect(useCombatStore.getState().health).toBe(healthBefore + Math.round(stateAfterCast.maxHealth * 0.01)); }); it("keeps Nature Crystal active and makes its owner immune while blocking attack skills", () => { initializeRomCharacter("rom-warden"); const now = Date.now(); expect(useCombatStore.getState().castAbility("rom-warden-primary-6", undefined, now)).toMatchObject({ ok: true }); useCombatStore.getState().tick(4, now + 4_000); const crystal = useCombatStore.getState().summons.find((summon) => summon.creatureId === 102325)!; expect(crystal.expiresAt).toBeGreaterThan(now + 60_000); const health = useCombatStore.getState().health; expect(useCombatStore.getState().damagePlayer(100, "fire")).toBe(0); expect(useCombatStore.getState().health).toBe(health); useCombatStore.getState().registerMob("warden-crystal-target", { name: "Target", maxHealth: 10_000 }); useCombatStore.getState().selectMob("warden-crystal-target"); expect(useCombatStore.getState().castAbility("rom-warden-primary-0", undefined, now + 6_000)) .toMatchObject({ ok: false, reason: "condition-not-met" }); }); it("scales Crystalline Protection to 10% of each recipient's own maximum health", () => { initializeRomCharacter("rom-warden"); usePartyStore.getState().initializeParty("warden-crystalline-protection", 80, useCombatStore.getState().health, "healer", 3, "rom"); const [first, second] = usePartyStore.getState().members; expect(first).toBeDefined(); expect(second).toBeDefined(); const members = usePartyStore.getState().members.map((member, index) => ({ ...member, maxHealth: index === 0 ? 2_000 : 5_000, health: index === 0 ? 1_000 : 2_500, })); usePartyStore.setState({ members }); members.forEach((member, index) => registerPartyRuntimePosition(member.id, [2 + index, 0, 0])); const playerMaxHealthBeforeCast = useCombatStore.getState().maxHealth; expect(useCombatStore.getState().castAbility("rom-warden-primary-23", undefined, Date.now())).toMatchObject({ ok: true }); const auras = useCombatStore.getState().auras; const absorbFor = (targetId: string) => auras.find((aura) => aura.targetId === targetId && aura.definition.name === "Crystalline Protection")?.absorbs[0]?.remaining; expect(absorbFor(PLAYER_AURA_ENTITY_ID)).toBe(Math.round(playerMaxHealthBeforeCast * 0.1)); expect(absorbFor(members[0]!.id)).toBe(200); expect(absorbFor(members[1]!.id)).toBe(500); }); it("absorbs exactly two Heart of the Oak attack packets and leaves ordinary point shields unchanged", () => { initializeRomCharacter("rom-warden"); expect(useCombatStore.getState().castAbility("rom-warden-primary-10", undefined, Date.now())).toMatchObject({ ok: true }); expect(useCombatStore.getState().damagePlayer(100, "physical")).toBe(0); expect(useCombatStore.getState().damagePlayer(100, "fire")).toBe(0); expect(useCombatStore.getState().damagePlayer(100, "physical")).toBeGreaterThan(0); const flatShield = applyAura([], { definition: { id: "test:flat-absorb", name: "Flat absorb", disposition: "buff", durationMs: 10_000, absorbs: [{ id: "pool", amount: 5 }], }, sourceId: "test-source", targetId: "target", now: 1, }).auras; const result = absorbDamage(flatShield, { targetId: "target", amount: 10, school: "physical", now: 2, countsAsAttack: true, }); expect(result).toMatchObject({ absorbed: 5, remainingDamage: 5 }); }); it("transfers 30% of incoming damage to a nearby Warden pet and disables the reduction without one", () => { const incomingHealthLoss = (withPet: boolean, petDistance = 0) => { initializeRomCharacter("rom-warden"); const now = Date.now(); if (withPet) { const summonAbility = ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === 493333)!; expect(useCombatStore.getState().castAbility(summonAbility.id, undefined, now)).toMatchObject({ ok: true }); const summonCast = useCombatStore.getState().activeCast; if (summonCast) useCombatStore.getState().tick(0.1, summonCast.completesAt); useCombatStore.setState((state) => ({ summons: state.summons.map((summon) => summon.creatureId === 102297 ? { ...summon, expiresAt: now + 20_000 } : summon), })); } const petBefore = useCombatStore.getState().summons.find((summon) => summon.creatureId === 102297); if (petBefore && petDistance > 0) { useCombatStore.setState((state) => ({ summons: state.summons.map((summon) => summon.id === petBefore.id ? { ...summon, position: [petDistance, 0, 0] } : summon), })); } const transferAbility = ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === 493399)!; expect(useCombatStore.getState().castAbility(transferAbility.id, undefined, now + 6_000)).toMatchObject({ ok: true }); const playerHealthBefore = useCombatStore.getState().health; const petHealthBefore = useCombatStore.getState().summons.find((summon) => summon.creatureId === 102297)?.health ?? 0; useCombatStore.getState().damagePlayer(500, "physical", 80, now + 7_000); const state = useCombatStore.getState(); const petHealthAfter = state.summons.find((summon) => summon.creatureId === 102297)?.health ?? 0; return { playerDamage: playerHealthBefore - state.health, petDamage: petHealthBefore - petHealthAfter, }; }; const unshared = incomingHealthLoss(false); const unsharedDamage = unshared.playerDamage; const outOfRange = incomingHealthLoss(true, 301); expect(unshared.petDamage).toBe(0); expect(outOfRange.playerDamage).toBe(unsharedDamage); expect(outOfRange.petDamage).toBe(0); const shared = incomingHealthLoss(true); expect(shared.petDamage).toBeGreaterThan(0); expect(shared.playerDamage + shared.petDamage).toBeCloseTo(unsharedDamage, -1); expect(shared.petDamage / (shared.playerDamage + shared.petDamage)) .toBeCloseTo(ROM_WARDEN_DAMAGE_TRANSFER_FRACTION, 1); }); it("transfers party Warden damage once to a live pet within 300 range, and respects pet expiry", () => { const resolvePartyHit = (options: { readonly petDistance?: number; readonly petExpiresAt?: number; readonly transferAura?: boolean; } = {}) => { const seed = "warden-party-damage-transfer"; const now = 1_000; const hitAt = 1_450; initializeRomCharacter("rom-warden"); usePartyStore.getState().initializeParty(seed, 80, useCombatStore.getState().health); const warden = createConfiguredPartyMember({ name: "Warden Companion", classId: "rom-warden", specialization: "Primary", specializationId: "rom-warden:primary", talentTreeId: "rom-warden-primary", role: "tank", }, 80, 0, seed); usePartyStore.setState({ members: [{ ...warden, gearStats: EMPTY_ITEM_STATS }] }); registerPartyRuntimePosition(warden.id, [0, 0, 0]); useCombatStore.getState().synchronizeActors(); const summonAbility = ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === 493333)!; const summonEffect = summonAbility.effects.find((effect) => effect.kind === "summon"); expect(summonEffect?.kind).toBe("summon"); if (!summonEffect || summonEffect.kind !== "summon") throw new Error("Warden summon effect missing"); const petId = useCombatStore.getState().summonActor( warden.id, summonAbility, summonEffect, [options.petDistance ?? 0, 0, 0], null, now, ); expect(petId).toBeTruthy(); useCombatStore.setState((state) => ({ summons: state.summons.map((summon) => summon.id === petId ? { ...summon, expiresAt: options.petExpiresAt ?? now + 20_000 } : summon), })); const transferEffects = effectsFor(493399).filter((effect) => effect.kind === "apply-aura" && effect.aura.utilityTags?.includes(ROM_WARDEN_DAMAGE_TRANSFER_TAG)); expect(transferEffects).toHaveLength(2); expect(transferEffects.every((effect) => effect.kind === "apply-aura" && effect.aura.durationMs === 10_000)).toBe(true); if (options.transferAura !== false) { useCombatStore.setState((state) => ({ auras: transferEffects.reduce((auras, effect) => { if (effect.kind !== "apply-aura") return auras; return applyAura(auras, { definition: effect.aura, sourceId: warden.id, targetId: warden.id, now, }).auras; }, state.auras) })); } const mobId = "warden-party-transfer-attacker"; useCombatStore.getState().registerMob(mobId, { name: "Warden transfer attacker", maxHealth: 100_000, level: 100, attacks: [{ ...DEFAULT_ENEMY_ATTACK, id: "warden-party-transfer-swing", delivery: "projectile", range: 100, initialCooldownMs: [0, 0] }], }); setMobPosition(mobId, [2, 0, 0]); useCombatStore.getState().damageMob(mobId, 1, now, { actorId: warden.id, role: "tank" }); const memberBefore = usePartyStore.getState().members.find((member) => member.id === warden.id)!.health; const petBefore = useCombatStore.getState().summons.find((summon) => summon.id === petId)?.health ?? 0; useCombatStore.getState().advanceMobCombat(hitAt, [0, 0, 0]); const state = useCombatStore.getState(); const memberAfter = usePartyStore.getState().members.find((member) => member.id === warden.id)!.health; const petAfter = state.summons.find((summon) => summon.id === petId)?.health ?? 0; const hitEvents = state.combatEvents.filter((event) => event.occurredAt === hitAt && event.abilityId === "warden-party-transfer-swing"); return { memberDamage: memberBefore - memberAfter, petDamage: petBefore - petAfter, petEvents: hitEvents.filter((event) => event.targetActorId === petId), ownerEvents: hitEvents.filter((event) => event.targetActorId === warden.id), petAlive: state.actors[petId!]?.alive ?? false, }; }; const baseline = resolvePartyHit({ transferAura: false }); const inRange = resolvePartyHit({ petDistance: 300 }); expect(baseline.memberDamage).toBeGreaterThan(0); expect(inRange.memberDamage).toBeGreaterThan(0); expect(inRange.petDamage).toBeGreaterThan(0); expect(inRange.memberDamage + inRange.petDamage).toBeCloseTo(baseline.memberDamage, 0); expect(inRange.petDamage / (inRange.memberDamage + inRange.petDamage)) .toBeCloseTo(ROM_WARDEN_DAMAGE_TRANSFER_FRACTION, 1); expect(inRange.ownerEvents).toHaveLength(1); expect(inRange.petEvents).toHaveLength(1); expect(inRange.petAlive).toBe(true); const outOfRange = resolvePartyHit({ petDistance: 301 }); expect(outOfRange.memberDamage).toBe(baseline.memberDamage); expect(outOfRange.petDamage).toBe(0); expect(outOfRange.petEvents).toHaveLength(0); const expired = resolvePartyHit({ petExpiresAt: 1_450 }); expect(expired.memberDamage).toBe(baseline.memberDamage); expect(expired.petDamage).toBe(0); expect(expired.petEvents).toHaveLength(0); }); it("removes the unquantified Weak Point Strike bonus and models Awakening immunity and next critical", () => { const weakPoint = effectsFor(494043); expect(weakPoint.filter((effect) => effect.kind === "damage")).toHaveLength(1); const awakening = effectsFor(499495); const auras = awakening.filter((effect) => effect.kind === "apply-aura"); expect(auras).toHaveLength(2); expect(auras).toEqual(expect.arrayContaining([ expect.objectContaining({ recipient: "caster", aura: expect.objectContaining({ durationMs: 10_000, controlImmunities: ["root", "slow"] }), }), expect.objectContaining({ recipient: "caster", aura: expect.objectContaining({ durationMs: null, utilityTags: expect.arrayContaining(["next-offensive-critical"]), }), }), ])); expect(auras.some((effect) => effect.kind === "apply-aura" && effect.control)).toBe(false); }); it("spends one Nature Power for Healing Ripple's additional heal", () => { const baseline = effectsFor(494323, { naturePower: 0 }); const empowered = effectsFor(494323, { naturePower: 1 }); expect(baseline.filter((effect) => effect.kind === "heal")).toHaveLength(1); expect(baseline.some((effect) => effect.kind === "resource-drain")).toBe(false); expect(empowered.filter((effect) => effect.kind === "heal")).toHaveLength(2); expect(empowered).toContainEqual({ kind: "resource-drain", amount: 1, burn: false, resource: "nature-power", recipient: "caster" }); }); it("scales Gift Pulse by spent Nature Power and targets nearby party members", () => { expect(effectsFor(499936, { naturePower: 0 })).toEqual([]); const empowered = effectsFor(499936, { naturePower: 3 }); const empoweredHeal = empowered.find((effect) => effect.kind === "heal"); expect(empoweredHeal?.kind).toBe("heal"); if (empoweredHeal?.kind === "heal") expect(empoweredHeal.percentMaxHealth).toBeCloseTo(0.3); expect(empowered.find((effect) => effect.kind === "resource-drain")) .toEqual({ kind: "resource-drain", amount: 3, burn: false, resource: "nature-power", recipient: "caster" }); expect(effectsFor(499936, { naturePower: 20 }).find((effect) => effect.kind === "heal")) .toMatchObject({ percentMaxHealth: 1 }); expect(ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === 499936)) .toMatchObject({ targeting: { shape: "circle", radius: 10 } }); }); it("puts Mysterious Grace modifier auras on the party, and leaves the Revival HolyHeal child unresolved", () => { const grace = effectsFor(494372); const modifierAuras = grace.filter((effect) => effect.kind === "apply-aura" && effect.aura.modifiers?.length); expect(modifierAuras.length).toBeGreaterThan(0); expect(modifierAuras.every((effect) => effect.kind === "apply-aura" && effect.scope === "party")).toBe(true); expect(grace.filter((effect) => effect.kind === "apply-aura" && !effect.aura.modifiers?.length) .every((effect) => effect.kind === "apply-aura" && effect.scope === undefined)).toBe(true); expect(romTriggeredAbilityBySpellId(499545)).toBeNull(); }); });