Files
healer-man/src/game/romWarriorCurrentCoaMechanics.test.ts
T
2026-10-02 10:38:12 -04:00

176 lines
6.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { AbilityDefinition, AbilityEffect } from "./abilityCatalog";
import {
ROM_COA_HOLY_POWER_EXPLOSION_ID,
ROM_COA_HOLY_SEAL_NO_DOT_ABILITY_IDS,
ROM_COA_BLOCKING_STANCE_ID,
ROM_COA_RESIST_ID,
ROM_LOCAL_ACTIVE_BLOCKING_STANCE_AURA_ID,
romCurrentCoaBlockingStanceModifiers,
romCurrentCoaHolyPowerExplosionThreatMultiplier,
romCurrentCoaResistModifiers,
romCurrentCoaThreatFactors,
withoutCurrentCoaHolySealPeriodicDamage,
} from "./romWarriorCurrentCoaMechanics";
const damage: AbilityEffect = { kind: "damage", coefficient: 1, school: "physical" };
const dot: AbilityEffect = { kind: "dot", coefficient: 0.25, ticks: 5, intervalMs: 2_000 };
const combo: AbilityEffect = { kind: "combo", amount: 1 };
const knightAction = { source: "runewaker", classId: "rom-knight" } as Pick<
AbilityDefinition,
"source" | "classId"
>;
describe("current CoA Warrior/Knight mechanics", () => {
it.each(ROM_COA_HOLY_SEAL_NO_DOT_ABILITY_IDS)(
"removes the obsolete Holy Seal periodic damage from %i while preserving hit and combo effects",
(sourceSkillId) => {
const effects: AbilityEffect[] = [damage, dot, combo];
expect(withoutCurrentCoaHolySealPeriodicDamage(sourceSkillId, effects)).toEqual([damage, combo]);
},
);
it("leaves unrelated ability effects and non-Holy-Seal periodic effects unchanged", () => {
const effects: AbilityEffect[] = [damage, dot, combo];
expect(withoutCurrentCoaHolySealPeriodicDamage(490152, effects)).toBe(effects);
});
it("applies Holy Power Explosion's 2.98 threat multiplier to Knight actions only when learned", () => {
expect(romCurrentCoaHolyPowerExplosionThreatMultiplier(knightAction, [ROM_COA_HOLY_POWER_EXPLOSION_ID]))
.toBe(2.98);
expect(romCurrentCoaHolyPowerExplosionThreatMultiplier(knightAction, [])).toBe(1);
expect(romCurrentCoaHolyPowerExplosionThreatMultiplier(
{ source: "runewaker", classId: "rom-warrior" },
[ROM_COA_HOLY_POWER_EXPLOSION_ID],
)).toBe(1);
expect(romCurrentCoaHolyPowerExplosionThreatMultiplier(
{ source: "core", classId: "rom-knight" },
[ROM_COA_HOLY_POWER_EXPLOSION_ID],
)).toBe(1);
});
it("keeps each CoA aggro factor separate and leaves their overlap unmodeled", () => {
const ability = { source: "runewaker" as const, classId: "rom-knight" as const };
const holyPower = romCurrentCoaThreatFactors({
ability,
classId: "rom-knight",
learnedPassiveSpellIds: [490172],
blockingStanceAuraActive: false,
});
expect(holyPower).toMatchObject({ holyPowerExplosionMultiplier: 2.98, resolvedMultiplier: 2.98, overlapUnresolved: false });
const blocking = romCurrentCoaThreatFactors({
ability: { source: "runewaker", classId: "rom-warrior" },
classId: "rom-warrior",
secondaryClassId: "rom-knight",
learnedPassiveSpellIds: [493287],
blockingStanceAuraActive: true,
});
expect(blocking).toMatchObject({ blockingStanceMultiplier: 1.754, resolvedMultiplier: 1.754, overlapUnresolved: false });
const resist = romCurrentCoaThreatFactors({
ability: { source: "runewaker", classId: "rom-warrior" },
classId: "rom-warrior",
secondaryClassId: "rom-knight",
learnedPassiveSpellIds: [493287, 493251],
blockingStanceAuraActive: true,
});
expect(resist).toMatchObject({ resistMultiplier: 1.8, resolvedMultiplier: 1, overlapUnresolved: true });
const overlapping = romCurrentCoaThreatFactors({
ability,
classId: "rom-warrior",
secondaryClassId: "rom-knight",
learnedPassiveSpellIds: [490172, 493287, 493251],
blockingStanceAuraActive: true,
});
expect(overlapping).toMatchObject({
holyPowerExplosionMultiplier: 2.98,
blockingStanceMultiplier: 1.754,
resistMultiplier: 1.8,
resolvedMultiplier: 1,
overlapUnresolved: true,
});
});
it("enables Resist's +80% aggro and 20% physical reduction only for learned Warrior/Knight under CoA stance", () => {
expect(romCurrentCoaResistModifiers({
classId: "rom-warrior",
secondaryClassId: "rom-knight",
learnedPassiveSpellIds: [ROM_COA_RESIST_ID, ROM_COA_BLOCKING_STANCE_ID],
blockingStanceAuraActive: true,
})).toEqual({ threatMultiplier: 1.8, physicalDamageTakenMultiplier: 0.8 });
});
it("applies CoA Blocking Stance's sourced static modifiers only while its passive and active aura are both present", () => {
const stance = {
classId: "rom-warrior" as const,
secondaryClassId: "rom-knight" as const,
learnedPassiveSpellIds: [ROM_COA_BLOCKING_STANCE_ID],
blockingStanceAuraActive: true,
};
expect(romCurrentCoaBlockingStanceModifiers(stance)).toEqual({
parryRateBonusPercent: 8,
receivedDamageReductionPercent: 18.9,
aggroBonusPercent: 75.4,
});
expect(romCurrentCoaBlockingStanceModifiers({
...stance,
learnedPassiveSpellIds: [],
})).toEqual({
parryRateBonusPercent: 0,
receivedDamageReductionPercent: 0,
aggroBonusPercent: 0,
});
expect(romCurrentCoaBlockingStanceModifiers({
...stance,
blockingStanceAuraActive: false,
})).toEqual({
parryRateBonusPercent: 0,
receivedDamageReductionPercent: 0,
aggroBonusPercent: 0,
});
});
it("exposes the stable local 491480 aura ID without treating it as CoA passive 493287", () => {
expect(ROM_LOCAL_ACTIVE_BLOCKING_STANCE_AURA_ID).toBe("rom-aura-491480-502007-0-parry");
expect(romCurrentCoaBlockingStanceModifiers({
classId: "rom-warrior",
secondaryClassId: "rom-knight",
learnedPassiveSpellIds: [],
blockingStanceAuraActive: true,
})).toEqual({
parryRateBonusPercent: 0,
receivedDamageReductionPercent: 0,
aggroBonusPercent: 0,
});
});
it("requires learned Resist, learned CoA Blocking Stance, the active stance aura, and Warrior/Knight", () => {
const baseline = { threatMultiplier: 1, physicalDamageTakenMultiplier: 1 };
const state = {
classId: "rom-warrior" as const,
secondaryClassId: "rom-knight" as const,
learnedPassiveSpellIds: [ROM_COA_RESIST_ID, ROM_COA_BLOCKING_STANCE_ID],
blockingStanceAuraActive: true,
};
expect(romCurrentCoaResistModifiers({ ...state, learnedPassiveSpellIds: [] })).toEqual(baseline);
expect(romCurrentCoaResistModifiers({
...state,
learnedPassiveSpellIds: [ROM_COA_RESIST_ID],
})).toEqual(baseline);
expect(romCurrentCoaResistModifiers({
...state,
blockingStanceAuraActive: false,
})).toEqual(baseline);
expect(romCurrentCoaResistModifiers({
...state,
classId: "rom-knight",
secondaryClassId: "rom-warrior",
})).toEqual(baseline);
});
});