Files
healer-man/src/game/wow335MageFrostWardingRuntime.test.ts
T
2026-10-02 10:38:12 -04:00

226 lines
9.3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { abilityAtLevel, abilityById } from "./abilityCatalog";
import { WOW335_ABILITIES_BY_CLASS } from "./wow335AbilityCatalog";
import {
WOW335_MAGE_FROST_WARDING_ARMOR_ABILITIES,
WOW335_MAGE_FROST_WARDING_ARMOR_TAG,
WOW335_MAGE_FROST_WARDING_TALENT_ID,
WOW335_MAGE_FROST_WARDING_WARD_ABILITIES,
wow335MageFrostWardingArmorAuraEffect,
wow335MageFrostWardingProcPlan,
wow335MageFrostWardingProfile,
} from "./wow335MageFrostWardingRuntime";
const procEvent = (overrides: Partial<Parameters<typeof wow335MageFrostWardingProcPlan>[1]> = {}) => ({
wardOwnerClassId: "mage",
eventKind: "spell-damage",
wardAbilityId: WOW335_MAGE_FROST_WARDING_WARD_ABILITIES.fire.abilityId,
wardRankSpellId: 43010,
wardAuraActive: true,
damageSchool: "fire",
spellDamage: 200,
roll: 0,
...overrides,
});
describe("WoW 3.3.5a Mage Frost Warding", () => {
it("reads the generated rank chance, reduction, Mana refund, and armor/resistance values", () => {
expect(WOW335_MAGE_FROST_WARDING_TALENT_ID).toBe("talent-70");
expect([1, 2].map(wow335MageFrostWardingProfile)).toEqual([
{
rank: 1,
rankSpellId: 11189,
armorAndResistanceBonusPercent: 25,
wardProcChancePercent: 25,
wardDamageReductionPercent: 50,
manaRefundPerDamageReduced: 1,
},
{
rank: 2,
rankSpellId: 28332,
armorAndResistanceBonusPercent: 50,
wardProcChancePercent: 50,
wardDamageReductionPercent: 50,
manaRefundPerDamageReduced: 1,
},
]);
expect(wow335MageFrostWardingProfile(0)).toBeNull();
expect(wow335MageFrostWardingProfile(3)).toBeNull();
});
it.each([
{
armor: "frost" as const,
rank: 1,
spellId: 7301,
expected: { armor: 250 },
},
{
armor: "frost" as const,
rank: 2,
spellId: 7301,
expected: { armor: 300 },
},
{
armor: "ice" as const,
rank: 1,
spellId: 43008,
expected: { armor: 1162.5, "resistance:frost": 50 },
},
{
armor: "ice" as const,
rank: 2,
spellId: 43008,
expected: { armor: 1395, "resistance:frost": 60 },
},
])("scales only the exact local $armor armor aura at Frost Warding rank $rank", ({ armor, rank, spellId, expected }) => {
const row = WOW335_MAGE_FROST_WARDING_ARMOR_ABILITIES[armor];
const baseAbility = abilityById(row.abilityId);
if (!baseAbility) throw new Error(`Missing local ${row.name} ability.`);
const ability = abilityAtLevel(baseAbility, 80);
expect(ability.dbcSpellId).toBe(spellId);
const armorEffects = ability.effects.filter((effect) => effect.kind === "apply-aura"
&& effect.sourceAuraType === 22);
expect(armorEffects.length).toBeGreaterThan(0);
const actual: Record<string, number> = {};
for (const effect of armorEffects) {
if (effect.kind !== "apply-aura") continue;
const applied = wow335MageFrostWardingArmorAuraEffect(ability, rank, effect);
expect(applied.aura.utilityTags).toContain(WOW335_MAGE_FROST_WARDING_ARMOR_TAG);
for (const modifier of applied.aura.modifiers ?? []) {
if (modifier.kind === "stat" && (modifier.stat === "armor" || modifier.stat.startsWith("resistance:"))) {
actual[modifier.stat] = (actual[modifier.stat] ?? 0) + modifier.value;
}
}
}
expect(actual).toEqual(expected);
});
it("requires a learned rank and the exact local Mage Frost/Ice Armor source aura", () => {
const baseAbility = abilityById(WOW335_MAGE_FROST_WARDING_ARMOR_ABILITIES.ice.abilityId)!;
const ability = abilityAtLevel(baseAbility, 80);
const effect = ability.effects.find((candidate) => candidate.kind === "apply-aura"
&& candidate.sourceAuraType === 22)!;
if (effect.kind !== "apply-aura") throw new Error("Ice Armor has no stat aura.");
expect(wow335MageFrostWardingArmorAuraEffect(ability, 0, effect)).toBe(effect);
expect(wow335MageFrostWardingArmorAuraEffect({ ...ability, classId: "warlock" }, 2, effect)).toBe(effect);
expect(wow335MageFrostWardingArmorAuraEffect({ ...ability, dbcSpellId: 12345 }, 2, effect)).toBe(effect);
const wrongAuraType = { ...effect, sourceAuraType: 42 };
expect(wow335MageFrostWardingArmorAuraEffect(ability, 2, wrongAuraType)).toBe(wrongAuraType);
expect(wow335MageFrostWardingArmorAuraEffect(ability, 2, {
...effect,
sourceAuraType: 42,
})).toMatchObject({ sourceAuraType: 42 });
expect(wow335MageFrostWardingArmorAuraEffect(ability, 2, {
...effect,
aura: {
...effect.aura,
modifiers: [
{ kind: "stat", stat: "armor", operation: "flat", value: 0 },
{ kind: "stat", stat: "resistance:frost", operation: "flat", value: -5 },
{ kind: "stat", stat: "spell-power", operation: "flat", value: 25 },
],
},
})).toMatchObject({ aura: { modifiers: [
{ kind: "stat", stat: "armor", value: 0 },
{ kind: "stat", stat: "resistance:frost", value: -5 },
{ kind: "stat", stat: "spell-power", value: 25 },
] } });
});
it("keeps the ward school selector separate from rank-specific chance", () => {
expect(WOW335_MAGE_FROST_WARDING_WARD_ABILITIES.fire.school).toBe("fire");
expect(WOW335_MAGE_FROST_WARDING_WARD_ABILITIES.frost.school).toBe("frost");
expect(wow335MageFrostWardingProfile(1)?.wardProcChancePercent).toBe(25);
expect(wow335MageFrostWardingProfile(2)?.wardProcChancePercent).toBe(50);
const frostEvent = procEvent({
wardAbilityId: WOW335_MAGE_FROST_WARDING_WARD_ABILITIES.frost.abilityId,
wardRankSpellId: 43012,
damageSchool: "frost",
roll: 0.249,
});
expect(wow335MageFrostWardingProcPlan(1, frostEvent)?.wardAbilityId)
.toBe(WOW335_MAGE_FROST_WARDING_WARD_ABILITIES.frost.abilityId);
expect(wow335MageFrostWardingProcPlan(1, { ...frostEvent, damageSchool: "fire" })).toBeNull();
});
it("binds its supported Fire and Frost Wards to local Mage Spell.dbc ability rows", () => {
const mageRows = new Map(WOW335_ABILITIES_BY_CLASS.mage.map((ability) => [ability.id, ability]));
expect(mageRows.get(WOW335_MAGE_FROST_WARDING_WARD_ABILITIES.fire.abilityId)?.name).toBe("Fire Ward");
expect(mageRows.get(WOW335_MAGE_FROST_WARDING_WARD_ABILITIES.frost.abilityId)?.name).toBe("Frost Ward");
for (const ward of Object.values(WOW335_MAGE_FROST_WARDING_WARD_ABILITIES)) {
const row = mageRows.get(ward.abilityId);
expect(row?.source).toBe("wow335-progression");
expect(row?.ranks?.map((rank) => rank.spellId)).toEqual(ward.rankSpellIds);
}
const otherClassRows = new Map(WOW335_ABILITIES_BY_CLASS.warlock.map((ability) => [ability.name, ability]));
expect(otherClassRows.get("Shadow Ward")?.id).toBe("wow335-warlock-shadow-ward");
expect(mageRows.get("wow335-mage-arcane-ward")).toBeUndefined();
});
it.each([
{
rank: 1,
event: procEvent({ roll: 0.249 }),
expectedRankSpellId: 11189,
},
{
rank: 2,
event: procEvent({ roll: 0.499 }),
expectedRankSpellId: 28332,
},
{
rank: 2,
event: procEvent({
wardAbilityId: WOW335_MAGE_FROST_WARDING_WARD_ABILITIES.frost.abilityId,
wardRankSpellId: 43012,
damageSchool: "Frost",
roll: 0.2,
}),
expectedRankSpellId: 28332,
},
])("plans a matching ward proc at the generated rank chance", ({ rank, event, expectedRankSpellId }) => {
expect(wow335MageFrostWardingProcPlan(rank, event)).toEqual({
rankSpellId: expectedRankSpellId,
wardAbilityId: event.wardAbilityId,
wardDamageReductionPercent: 50,
manaRefundPerDamageReduced: 1,
});
});
it("uses an exclusive upper roll boundary for 25% and 50% proc chances", () => {
expect(wow335MageFrostWardingProcPlan(1, procEvent({ roll: 0.25 }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ roll: 0.5 }))).toBeNull();
});
it("requires the Mage owner, a learned rank, an active matching ward, and positive spell damage", () => {
expect(wow335MageFrostWardingProcPlan(2, procEvent({ wardOwnerClassId: "warlock" }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(0, procEvent())).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ wardAuraActive: false }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ wardRankSpellId: 43012 }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ damageSchool: "frost" }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ eventKind: "weapon-damage" }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ spellDamage: 0 }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ spellDamage: -1 }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ roll: Number.NaN }))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({ roll: 1 }))).toBeNull();
});
it("does not synthesize support for the tooltip's absent Mage Arcane/Shadow Ward rows", () => {
expect(wow335MageFrostWardingProcPlan(2, procEvent({
wardAbilityId: "wow335-warlock-shadow-ward",
wardRankSpellId: 47891,
damageSchool: "shadow",
}))).toBeNull();
expect(wow335MageFrostWardingProcPlan(2, procEvent({
wardAbilityId: "wow335-mage-arcane-ward",
wardRankSpellId: 43020,
damageSchool: "arcane",
}))).toBeNull();
});
});