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 }); }); });