155 lines
7.1 KiB
TypeScript
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);
|
|
});
|
|
});
|