Files
healer-man/src/game/romMageRuntime.test.ts
T
2026-09-30 09:57:13 -04:00

155 lines
7.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { abilityById } from "./abilityCatalog";
import {
ROM_MAGE_KNIGHT_LIGHT_OF_DAY,
ROM_MAGE_KNIGHT_LIGHT_OF_DAY_COOLDOWN_EFFECT,
ROM_MAGE_MEDITATIVE_CURRENT,
ROM_MAGE_MEDITATIVE_CURRENT_COOLDOWN_EFFECT,
romMageKnightLightOfDayProc,
romMageKnightLightOfDayReadyAt,
romMageMeditativeCurrentReadyAt,
romMageMeditativeCurrentProc,
} from "./romMageRuntime";
const passiveIds = [ROM_MAGE_MEDITATIVE_CURRENT.passiveSpellId];
describe("RoM Mage runtime", () => {
it("grants Meditative Current only after landed Flame or Plasma Arrow hits with the passive learned", () => {
for (const dbcSpellId of ROM_MAGE_MEDITATIVE_CURRENT.triggerSpellIds) {
const result = romMageMeditativeCurrentProc(
"rom-mage",
{ source: "runewaker", dbcSpellId },
passiveIds,
true,
1_000,
1_000,
);
expect(result.nextReadyAt).toBe(31_000);
expect(result.effect).toMatchObject({
kind: "apply-aura",
recipient: "caster",
triggerSpellId: 493_262,
aura: {
id: "rom-mage-meditative-current",
durationMs: 10_000,
maxStacks: 1,
stackBehavior: "refresh",
modifiers: [{
kind: "stat",
stat: "spell-haste",
operation: "flat",
value: 10,
}],
},
});
}
});
it("preserves readiness and rejects misses, other spells/classes, unlearned passives, and non-RuneWaker rows", () => {
const rejectedInputs = [
{ classId: "rom-mage", ability: { source: "runewaker", dbcSpellId: 491_150 }, passives: [], landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", ability: { source: "runewaker", dbcSpellId: 490_204 }, passives: passiveIds, landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", ability: { source: "runewaker", dbcSpellId: 491_169 }, passives: passiveIds, landed: false, readyAt: 100, now: 100 },
{ classId: "rom-priest", ability: { source: "runewaker", dbcSpellId: 491_169 }, passives: passiveIds, landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", ability: { source: "core", dbcSpellId: 491_169 }, passives: passiveIds, landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", ability: { source: "runewaker", dbcSpellId: 491_169 }, passives: passiveIds, landed: true, readyAt: 101, now: 100 },
] as const;
for (const input of rejectedInputs) {
expect(romMageMeditativeCurrentProc(
input.classId,
input.ability,
input.passives,
input.landed,
input.readyAt,
input.now,
)).toEqual({ effect: null, nextReadyAt: input.readyAt });
}
});
it("reads the active cooldown per caster from its marker aura", () => {
const aura = {
targetId: "mage-one",
expiresAt: 30_000,
definition: ROM_MAGE_MEDITATIVE_CURRENT_COOLDOWN_EFFECT.aura,
};
expect(romMageMeditativeCurrentReadyAt([aura], "mage-one", 10_000)).toBe(30_000);
expect(romMageMeditativeCurrentReadyAt([aura], "mage-two", 10_000)).toBe(10_000);
expect(romMageMeditativeCurrentReadyAt([aura], "mage-one", 31_000)).toBe(31_000);
});
it("suppresses Light of Day's generic aura and grants its source values on either landed trigger", () => {
expect(abilityById("rom-mage-rom-knight-elite-45")?.effects).toEqual([]);
for (const dbcSpellId of ROM_MAGE_KNIGHT_LIGHT_OF_DAY.triggerSpellIds) {
const result = romMageKnightLightOfDayProc(
"rom-mage",
"rom-knight",
{ classId: "rom-mage", secondaryClassId: "rom-knight", source: "runewaker", dbcSpellId },
[ROM_MAGE_KNIGHT_LIGHT_OF_DAY.passiveSpellId],
true,
4_000,
4_000,
);
expect(result.nextReadyAt).toBe(24_000);
expect(result.effect).toMatchObject({
kind: "apply-aura",
recipient: "caster",
triggerSpellId: 493_034,
aura: {
id: "rom-mage-knight-light-of-day",
durationMs: 15_000,
maxStacks: 1,
stackBehavior: "refresh",
modifiers: [{
kind: "damage",
direction: "dealt",
school: "holy",
operation: "percent",
value: 0.08,
}],
},
});
}
});
it("rejects Light of Day misses, other builds or spells, nonlocal rows, and hits on cooldown", () => {
const passiveIds = [ROM_MAGE_KNIGHT_LIGHT_OF_DAY.passiveSpellId];
const rejectedInputs = [
{ classId: "rom-mage", secondaryClassId: "rom-knight", ability: { classId: "rom-mage", secondaryClassId: "rom-knight", source: "runewaker", dbcSpellId: 491_594 }, passives: [], landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", secondaryClassId: "rom-knight", ability: { classId: "rom-mage", secondaryClassId: "rom-knight", source: "runewaker", dbcSpellId: 490_204 }, passives: passiveIds, landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", secondaryClassId: "rom-knight", ability: { classId: "rom-mage", secondaryClassId: "rom-knight", source: "runewaker", dbcSpellId: 491_594 }, passives: passiveIds, landed: false, readyAt: 100, now: 100 },
{ classId: "rom-mage", secondaryClassId: "rom-warrior", ability: { classId: "rom-mage", secondaryClassId: "rom-knight", source: "runewaker", dbcSpellId: 491_594 }, passives: passiveIds, landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", secondaryClassId: "rom-knight", ability: { classId: "rom-mage", secondaryClassId: "rom-warrior", source: "runewaker", dbcSpellId: 491_594 }, passives: passiveIds, landed: true, readyAt: 100, now: 100 },
{ classId: "rom-priest", secondaryClassId: "rom-knight", ability: { classId: "rom-mage", secondaryClassId: "rom-knight", source: "runewaker", dbcSpellId: 491_594 }, passives: passiveIds, landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", secondaryClassId: "rom-knight", ability: { classId: "rom-mage", secondaryClassId: "rom-knight", source: "core", dbcSpellId: 491_594 }, passives: passiveIds, landed: true, readyAt: 100, now: 100 },
{ classId: "rom-mage", secondaryClassId: "rom-knight", ability: { classId: "rom-mage", secondaryClassId: "rom-knight", source: "runewaker", dbcSpellId: 491_594 }, passives: passiveIds, landed: true, readyAt: 101, now: 100 },
] as const;
for (const input of rejectedInputs) {
expect(romMageKnightLightOfDayProc(
input.classId,
input.secondaryClassId,
input.ability,
input.passives,
input.landed,
input.readyAt,
input.now,
)).toEqual({ effect: null, nextReadyAt: input.readyAt });
}
});
it("reads Light of Day's cooldown separately for each caster", () => {
const aura = {
targetId: "knight-mage-one",
expiresAt: 20_000,
definition: ROM_MAGE_KNIGHT_LIGHT_OF_DAY_COOLDOWN_EFFECT.aura,
};
expect(romMageKnightLightOfDayReadyAt([aura], "knight-mage-one", 5_000)).toBe(20_000);
expect(romMageKnightLightOfDayReadyAt([aura], "knight-mage-two", 5_000)).toBe(5_000);
expect(romMageKnightLightOfDayReadyAt([aura], "knight-mage-one", 20_000)).toBe(20_000);
});
});