111 lines
5.4 KiB
TypeScript
111 lines
5.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { ROM_ALL_ABILITIES } from "./romAbilityCatalog";
|
|
import { romEffectsForCast } from "./romCombatMechanics";
|
|
import {
|
|
romWarlockPriestSpreadingPainCriticalMultiplier,
|
|
romWarlockPriestSpreadingPainEffects,
|
|
ROM_WARLOCK_PRIEST_SPREADING_PAIN_CRIT_TAG,
|
|
ROM_WARLOCK_PRIEST_SPREADING_PAIN_HEALING_BONUS,
|
|
ROM_WARLOCK_PRIEST_SPREADING_PAIN_HEALING_DURATION_MS,
|
|
ROM_WARLOCK_PRIEST_SPREADING_PAIN_ID,
|
|
ROM_WARLOCK_PRIEST_SPREADING_PAIN_MAGIC_ATTACK_BONUS,
|
|
ROM_WARLOCK_PRIEST_SPREADING_PAIN_MAGIC_BUFF_DURATION_MS,
|
|
} from "./romWarlockPriestSpreadingPain";
|
|
|
|
function spreadingPain() {
|
|
const result = ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === ROM_WARLOCK_PRIEST_SPREADING_PAIN_ID);
|
|
expect(result).toBeDefined();
|
|
return result!;
|
|
}
|
|
|
|
describe("RoM Warlock/Priest Spreading Pain source effects", () => {
|
|
it("routes the exact pair through the cast pipeline and retains RuneWaker cost/range", () => {
|
|
const ability = spreadingPain();
|
|
const castEffects = romEffectsForCast(ability, {
|
|
sealStacks: 0,
|
|
bleedCount: 0,
|
|
charged: false,
|
|
mainHandDagger: false,
|
|
casterMaxHealth: 1_000,
|
|
targetHealthPercent: 1,
|
|
});
|
|
const auras = castEffects.filter((effect) => effect.kind === "apply-aura");
|
|
|
|
expect(ability.costs).toEqual([{ resource: "focus", amount: 15 }]);
|
|
expect(ability.range).toMatchObject({ min: 0, max: 22.5 });
|
|
expect(ability.description).toContain("10% MP cost plus 15 Focus and range 150");
|
|
expect(castEffects.filter((effect) => effect.kind === "trigger-spell").map((effect) => (
|
|
effect.kind === "trigger-spell" ? effect.spellId : 0
|
|
)).sort((a, b) => a - b)).toEqual([497_959, 497_960, 497_964]);
|
|
expect(auras).toHaveLength(3);
|
|
expect(auras.map((effect) => effect.kind === "apply-aura" ? effect.aura.durationMs : null))
|
|
.toEqual([30_000, 30_000, 20_000]);
|
|
});
|
|
|
|
it("keeps the three RuneWaker child spells and adds only the current CoA caster buffs", () => {
|
|
const ability = spreadingPain();
|
|
const originalTriggers = ability.effects.filter((effect) => effect.kind === "trigger-spell");
|
|
expect(originalTriggers).toHaveLength(3);
|
|
expect(originalTriggers.map((effect) => effect.kind === "trigger-spell" ? effect.spellId : 0).sort((a, b) => a - b))
|
|
.toEqual([497_959, 497_960, 497_964]);
|
|
|
|
const effects = romWarlockPriestSpreadingPainEffects(ability, ability.effects);
|
|
expect(effects).toHaveLength(ability.effects.length + 3);
|
|
expect(effects?.filter((effect) => effect.kind === "trigger-spell")).toEqual(originalTriggers);
|
|
|
|
const auras = effects?.filter((effect) => effect.kind === "apply-aura") ?? [];
|
|
expect(auras).toHaveLength(3);
|
|
expect(auras).toEqual(expect.arrayContaining([
|
|
expect.objectContaining({
|
|
recipient: "caster",
|
|
aura: expect.objectContaining({
|
|
durationMs: ROM_WARLOCK_PRIEST_SPREADING_PAIN_MAGIC_BUFF_DURATION_MS,
|
|
utilityTags: [ROM_WARLOCK_PRIEST_SPREADING_PAIN_CRIT_TAG],
|
|
modifiers: [expect.objectContaining({
|
|
kind: "stat", stat: "critical-damage", operation: "percent", value: 0.25,
|
|
})],
|
|
}),
|
|
}),
|
|
expect.objectContaining({
|
|
recipient: "caster",
|
|
aura: expect.objectContaining({
|
|
durationMs: ROM_WARLOCK_PRIEST_SPREADING_PAIN_MAGIC_BUFF_DURATION_MS,
|
|
modifiers: [expect.objectContaining({
|
|
kind: "stat", stat: "magical-attack", operation: "percent", value: ROM_WARLOCK_PRIEST_SPREADING_PAIN_MAGIC_ATTACK_BONUS,
|
|
})],
|
|
}),
|
|
}),
|
|
expect.objectContaining({
|
|
recipient: "caster",
|
|
aura: expect.objectContaining({
|
|
durationMs: ROM_WARLOCK_PRIEST_SPREADING_PAIN_HEALING_DURATION_MS,
|
|
modifiers: [expect.objectContaining({
|
|
kind: "healing", direction: "done", operation: "percent", value: ROM_WARLOCK_PRIEST_SPREADING_PAIN_HEALING_BONUS,
|
|
})],
|
|
}),
|
|
}),
|
|
]));
|
|
|
|
// Patch 10.6.1 says Spreading Pain grants the healing portion of Healing
|
|
// Fortune; its independent Wisdom and Warp Charge clauses are not copied.
|
|
expect(auras.some((effect) => effect.kind === "apply-aura"
|
|
&& effect.aura.modifiers?.some((modifier) => modifier.kind === "stat" && modifier.stat === "wisdom"))).toBe(false);
|
|
});
|
|
|
|
it("requires the exact local Warlock/Priest pairing and spell ID", () => {
|
|
const ability = spreadingPain();
|
|
expect(romWarlockPriestSpreadingPainEffects({ ...ability, secondaryClassId: "rom-warrior" }, ability.effects)).toBeNull();
|
|
expect(romWarlockPriestSpreadingPainEffects({ ...ability, classId: "rom-priest" }, ability.effects)).toBeNull();
|
|
expect(romWarlockPriestSpreadingPainEffects({ ...ability, name: "Reused ID" }, ability.effects)).toBeNull();
|
|
expect(romWarlockPriestSpreadingPainEffects({ ...ability, dbcSpellId: 499_858 }, ability.effects)).toBeNull();
|
|
expect(romWarlockPriestSpreadingPainEffects({ ...ability, source: "coa-tree" }, ability.effects)).toBeNull();
|
|
});
|
|
|
|
it("adds 25% to magical spell critical bonus damage, not crit chance or ordinary hits", () => {
|
|
expect(romWarlockPriestSpreadingPainCriticalMultiplier(2, true, true)).toBe(2.25);
|
|
expect(romWarlockPriestSpreadingPainCriticalMultiplier(1.5, true, true)).toBe(1.625);
|
|
expect(romWarlockPriestSpreadingPainCriticalMultiplier(2, false, true)).toBe(2);
|
|
expect(romWarlockPriestSpreadingPainCriticalMultiplier(2, true, false)).toBe(2);
|
|
});
|
|
});
|