Files
healer-man/src/game/enemyPeriodicDamage.test.ts
T
2026-10-06 22:25:34 -04:00

111 lines
4.3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { creatureTemplateBaseDamage } from "./azerothCoreReference";
import {
enemyPeriodicDamageSource,
enemyPeriodicDamageTickAmount,
enemyPeriodicTickTimes,
} from "./enemyPeriodicDamage";
describe("source-backed Stockade Rend periodic damage", () => {
it.each([
["ascension-patch-d", 6547, 13, 14, false],
["ascension-patch-d", 16509, 26, 27, true],
["epoch-client", 6547, 9, 10, false],
["epoch-client", 16509, 26, 27, true],
] as const)("resolves %s spell %i", (profile, spellId, basePoints, baseTickAmount, scales) => {
const source = enemyPeriodicDamageSource(spellId, profile);
expect(source).toMatchObject({
spellId,
sourceProfile: profile,
durationMs: 15_000,
tickIntervalMs: 3_000,
tickCount: 5,
school: "physical",
schoolMask: 1,
damageClass: 2,
attackKind: "melee",
effectType: 6,
auraType: 3,
mechanic: 15,
implicitTargetA: 6,
implicitTargetB: 0,
durationIndex: 8,
stackAmount: 0,
effectBasePoints: basePoints,
effectDieSides: 1,
effectRealPointsPerLevel: 0,
spellLevel: 20,
baseLevel: 20,
scalesWithCreatureLevel: scales,
dbcBaseTickAmount: baseTickAmount,
periodicIgnoresArmor: true,
sameCasterRefresh: "duration-and-tick-count-reset-phase",
triggeredNoPeriodicResetRefresh: "duration-and-tick-count-preserve-phase",
differentCasterStacking: "independent",
});
});
it("schedules five ticks at three-second intervals, ending at the sourced duration", () => {
const source = enemyPeriodicDamageSource(16509, "ascension-patch-d");
expect(source).toBeDefined();
expect(enemyPeriodicTickTimes(source!, 1_000)).toEqual([4_000, 7_000, 10_000, 13_000, 16_000]);
});
it("uses the sourced creature base-damage ratio only for Rend 16509 and truncates like core", () => {
const scaledRend = enemyPeriodicDamageSource(16509, "ascension-patch-d");
const fixedRend = enemyPeriodicDamageSource(6547, "ascension-patch-d");
expect(scaledRend).toBeDefined();
expect(fixedRend).toBeDefined();
const level20 = creatureTemplateBaseDamage(1707, 20);
const level23 = creatureTemplateBaseDamage(1707, 23);
expect(level20).toMatchObject({ entry: 1707, level: 20, unitClass: 1, expansion: 0, baseDamage: 9.6823 });
expect(level23).toMatchObject({ entry: 1707, level: 23, unitClass: 1, expansion: 0, baseDamage: 10.8099 });
const scaledAmount = enemyPeriodicDamageTickAmount(1707, 23, scaledRend!);
expect(scaledAmount.status).toBe("resolved");
if (scaledAmount.status === "resolved") {
expect(scaledAmount.creatureLevelScale).toBeCloseTo(10.8099 / 9.6823, 12);
expect(scaledAmount.tickAmount).toBe(30);
expect(scaledAmount.tickAmount).toBe(Math.trunc(27 * (10.8099 / 9.6823)));
}
expect(enemyPeriodicDamageTickAmount(1708, 23, fixedRend!)).toMatchObject({
status: "resolved",
tickAmount: 14,
creatureLevelScale: 1,
});
});
it("fails closed when a required 16509 creature template or source row is missing", () => {
const scaledRend = enemyPeriodicDamageSource(16509, "ascension-patch-d");
expect(scaledRend).toBeDefined();
expect(enemyPeriodicDamageTickAmount(999_999, 23, scaledRend!)).toEqual({
status: "unsupported",
reason: "creature-template-missing",
});
expect(enemyPeriodicDamageTickAmount(1707, 81, scaledRend!)).toEqual({
status: "unsupported",
reason: "invalid-creature-level",
});
expect(enemyPeriodicDamageTickAmount(1707, 23, scaledRend!)).toMatchObject({
status: "resolved",
tickAmount: 30,
});
});
it("does not apply creature template damage modifiers to the 16509 source ratio", () => {
const scaledRend = enemyPeriodicDamageSource(16509, "ascension-patch-d");
expect(scaledRend).toBeDefined();
expect(enemyPeriodicDamageTickAmount(1707, 23, scaledRend!)).toMatchObject({
status: "resolved",
tickAmount: 30,
});
});
it("returns no descriptor for spell/profile pairs outside the audited rows", () => {
expect(enemyPeriodicDamageSource(8242, "ascension-patch-d")).toBeUndefined();
expect(enemyPeriodicDamageSource(6547, "epoch-client")).toMatchObject({ spellId: 6547 });
});
});