172 lines
6.7 KiB
TypeScript
172 lines
6.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import generatedData from "./wow335AbilityData.generated.json";
|
|
import {
|
|
WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_DURATION_MS,
|
|
WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_AURA,
|
|
WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_ABILITY_ID,
|
|
WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_EXCLUDED_UTILITY_SPELLS,
|
|
WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_DAMAGE_MULTIPLIER,
|
|
WOW335_DEATH_KNIGHT_DEATH_COIL_DAMAGE_SPELL_ID,
|
|
wow335DeathKnightDancingRuneWeaponCanMirrorEvent,
|
|
wow335DeathKnightDancingRuneWeaponDamage,
|
|
wow335DeathKnightDancingRuneWeaponExcludedUtilitySpellForName,
|
|
wow335DeathKnightDancingRuneWeaponIsActive,
|
|
type Wow335DeathKnightDancingRuneWeaponOwnerEvent,
|
|
} from "./wow335DeathKnightDancingRuneWeaponRuntime";
|
|
|
|
describe("WoW Death Knight Dancing Rune Weapon runtime", () => {
|
|
it("uses the sourced 12-second duration and 50% reduced-damage child payload", () => {
|
|
const dancingRuneWeapon = generatedData.classes["death-knight"].find((ability) =>
|
|
ability.ranks.some((rank) => rank.spellId === 49_028),
|
|
);
|
|
const rank = dancingRuneWeapon?.ranks.find((candidate) => candidate.spellId === 49_028);
|
|
|
|
expect(rank?.description).toContain("50% reduced damage");
|
|
expect(rank).toMatchObject({ durationMs: 12_000, cooldownMs: 90_000, powerCost: 600 });
|
|
expect(rank?.effects[2]).toMatchObject({
|
|
effectType: 6,
|
|
auraType: 4,
|
|
basePoints: 10,
|
|
});
|
|
expect(WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_DURATION_MS).toBe(12_000);
|
|
expect(WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_DAMAGE_MULTIPLIER).toBe(0.5);
|
|
expect(WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_ABILITY_ID)
|
|
.toBe("wow335-death-knight-dancing-rune-weapon");
|
|
expect(WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_AURA).toMatchObject({
|
|
durationMs: 12_000,
|
|
maxStacks: 1,
|
|
utilityTags: ["wow335-death-knight-dancing-rune-weapon"],
|
|
});
|
|
});
|
|
|
|
it("is active at summon and expires exactly at 12 seconds", () => {
|
|
expect(wow335DeathKnightDancingRuneWeaponIsActive(1_000, 1_000)).toBe(true);
|
|
expect(wow335DeathKnightDancingRuneWeaponIsActive(1_000, 12_999)).toBe(true);
|
|
expect(wow335DeathKnightDancingRuneWeaponIsActive(1_000, 13_000)).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponIsActive(1_000, 999)).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponIsActive(Number.NaN, 1_000)).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponIsActive(1_000, Number.POSITIVE_INFINITY)).toBe(false);
|
|
});
|
|
|
|
it("allows a living hostile modeled melee event", () => {
|
|
const event: Wow335DeathKnightDancingRuneWeaponOwnerEvent = {
|
|
kind: "melee",
|
|
targetAlive: true,
|
|
targetHostile: true,
|
|
};
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent(event)).toBe(true);
|
|
});
|
|
|
|
it("requires a living hostile target for every event kind", () => {
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({
|
|
kind: "melee",
|
|
targetAlive: false,
|
|
targetHostile: true,
|
|
})).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({
|
|
kind: "melee",
|
|
targetAlive: true,
|
|
targetHostile: false,
|
|
})).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({
|
|
kind: "spell",
|
|
spellId: 49_895,
|
|
ownerKnowsSpell: true,
|
|
targetAlive: true,
|
|
targetHostile: false,
|
|
isPositiveSpell: false,
|
|
hasSummonEffect: false,
|
|
isAreaTargeted: false,
|
|
actionTargetIsOwner: false,
|
|
})).toBe(false);
|
|
});
|
|
|
|
it("requires learned spells except for Death Coil's damage child", () => {
|
|
const event: Wow335DeathKnightDancingRuneWeaponOwnerEvent = {
|
|
kind: "spell",
|
|
spellId: 49_895,
|
|
ownerKnowsSpell: false,
|
|
targetAlive: true,
|
|
targetHostile: true,
|
|
isPositiveSpell: false,
|
|
hasSummonEffect: false,
|
|
isAreaTargeted: false,
|
|
actionTargetIsOwner: false,
|
|
};
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent(event)).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({
|
|
...event,
|
|
spellId: WOW335_DEATH_KNIGHT_DEATH_COIL_DAMAGE_SPELL_ID,
|
|
})).toBe(true);
|
|
});
|
|
|
|
it("rejects each source-listed DK utility spell", () => {
|
|
const baseEvent: Wow335DeathKnightDancingRuneWeaponOwnerEvent = {
|
|
kind: "spell",
|
|
spellId: 49_895,
|
|
ownerKnowsSpell: true,
|
|
targetAlive: true,
|
|
targetHostile: true,
|
|
isPositiveSpell: false,
|
|
hasSummonEffect: false,
|
|
isAreaTargeted: false,
|
|
actionTargetIsOwner: false,
|
|
};
|
|
|
|
for (const excludedUtilitySpell of WOW335_DEATH_KNIGHT_DANCING_RUNE_WEAPON_EXCLUDED_UTILITY_SPELLS) {
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({
|
|
...baseEvent,
|
|
excludedUtilitySpell,
|
|
})).toBe(false);
|
|
}
|
|
});
|
|
|
|
it("maps generated spell names to source utility exclusions", () => {
|
|
expect(wow335DeathKnightDancingRuneWeaponExcludedUtilitySpellForName("Death and Decay"))
|
|
.toBe("death-and-decay");
|
|
expect(wow335DeathKnightDancingRuneWeaponExcludedUtilitySpellForName("Anti-Magic Shell"))
|
|
.toBe("anti-magic-shell");
|
|
expect(wow335DeathKnightDancingRuneWeaponExcludedUtilitySpellForName("Death Strike")).toBeUndefined();
|
|
});
|
|
|
|
it("rejects positive spells, summons, and repeated area events on secondary targets", () => {
|
|
const baseEvent: Wow335DeathKnightDancingRuneWeaponOwnerEvent = {
|
|
kind: "spell",
|
|
spellId: 49_895,
|
|
ownerKnowsSpell: true,
|
|
targetAlive: true,
|
|
targetHostile: true,
|
|
isPositiveSpell: false,
|
|
hasSummonEffect: false,
|
|
isAreaTargeted: false,
|
|
actionTargetIsOwner: false,
|
|
};
|
|
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({ ...baseEvent, isPositiveSpell: true })).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({ ...baseEvent, hasSummonEffect: true })).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({
|
|
...baseEvent,
|
|
isAreaTargeted: true,
|
|
actionTargetIsOwner: false,
|
|
})).toBe(false);
|
|
expect(wow335DeathKnightDancingRuneWeaponCanMirrorEvent({
|
|
...baseEvent,
|
|
isAreaTargeted: true,
|
|
actionTargetIsOwner: true,
|
|
})).toBe(true);
|
|
});
|
|
|
|
it("mirrors an attack at half damage and floors to whole damage", () => {
|
|
expect(wow335DeathKnightDancingRuneWeaponDamage(101)).toBe(50);
|
|
expect(wow335DeathKnightDancingRuneWeaponDamage(100)).toBe(50);
|
|
expect(wow335DeathKnightDancingRuneWeaponDamage(1)).toBe(0);
|
|
});
|
|
|
|
it("returns zero for non-positive or non-finite attack damage", () => {
|
|
expect(wow335DeathKnightDancingRuneWeaponDamage(0)).toBe(0);
|
|
expect(wow335DeathKnightDancingRuneWeaponDamage(-2)).toBe(0);
|
|
expect(wow335DeathKnightDancingRuneWeaponDamage(Number.NaN)).toBe(0);
|
|
expect(wow335DeathKnightDancingRuneWeaponDamage(Number.POSITIVE_INFINITY)).toBe(0);
|
|
});
|
|
});
|