Files
healer-man/src/game/wailingCavernsParity.test.ts
T
2026-09-09 11:21:33 -04:00

167 lines
7.3 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import { WAILING_CAVERNS_DEFINITION } from "./dungeons/wailingCaverns";
import referenceData from "./generated/azerothCoreReference.json";
import { WAILING_CAVERNS_STATIC_SPAWNS } from "./mobPopulation";
import {
useWailingEncounterStore,
wailingEventSpawns,
wailingStaticSpawnsForPhase,
} from "./wailingCavernsEncounter";
interface WailingReferenceShape {
readonly creature: {
readonly templates: Readonly<Record<string, {
readonly mechanicImmunities: readonly string[];
}>>;
};
readonly wailingCaverns: {
readonly requiredBossEntries: readonly number[];
readonly despawnOnInitializeEntries: readonly number[];
readonly unsupportedRequiredBossActions: readonly unknown[];
readonly abilitiesByEntry: Readonly<Record<string, readonly {
readonly id: string;
readonly name: string;
readonly target: string;
readonly initialCooldownMs: readonly [number, number];
readonly repeatCooldownMs: readonly [number, number];
readonly maximumCasts?: number;
readonly condition: Readonly<Record<string, unknown>>;
readonly effect: Readonly<Record<string, unknown>>;
}[]>>;
};
}
const REFERENCE = referenceData as unknown as WailingReferenceShape;
const deadMob = { dead: true } as never;
describe("AzerothCore-backed Wailing Caverns parity slice", () => {
afterEach(() => useWailingEncounterStore.getState().reset());
it("uses exactly the server's eight required bosses and classifies Serpentis as a boss", () => {
expect(WAILING_CAVERNS_DEFINITION.objectiveOrder.map((boss) => boss.name)).toEqual([
"Lady Anacondra",
"Kresh",
"Lord Cobrahn",
"Lord Pythas",
"Skum",
"Lord Serpentis",
"Verdan the Everliving",
"Mutanus the Devourer",
]);
expect(REFERENCE.wailingCaverns.requiredBossEntries).toEqual([
3671, 3669, 3653, 3670, 3674, 3673, 5775, 3654,
]);
expect(WAILING_CAVERNS_DEFINITION.entities["lord-serpentis"].kind).toBe("boss");
expect(REFERENCE.wailingCaverns.despawnOnInitializeEntries).toEqual([5912]);
expect(REFERENCE.wailingCaverns.unsupportedRequiredBossActions).toEqual([]);
});
it("imports exact Fanglord targets, health gates, one-shot forms, and cooldown ranges", () => {
const cobrahn = REFERENCE.wailingCaverns.abilitiesByEntry["3669"];
expect(cobrahn.find((ability) => ability.id === "spell-9532")).toMatchObject({
target: "primary",
initialCooldownMs: [0, 0],
repeatCooldownMs: [2_400, 3_800],
effect: { kind: "damage" },
});
expect(cobrahn.find((ability) => ability.id === "spell-8040")).toMatchObject({
target: "random-party",
initialCooldownMs: [8_000, 11_000],
repeatCooldownMs: [10_000, 20_000],
effect: { kind: "control", mechanic: "sleep" },
});
expect(cobrahn.find((ability) => ability.id === "spell-5187")).toMatchObject({
target: "lowest-health-friendly",
initialCooldownMs: [0, 0],
repeatCooldownMs: [12_000, 18_000],
condition: { kind: "friendly-missing-health", amount: 400, range: 40 },
effect: { kind: "heal" },
});
expect(cobrahn.find((ability) => ability.id === "spell-7965")).toMatchObject({
target: "self",
maximumCasts: 1,
condition: { kind: "self-health-percent", minimum: 0, maximum: 30 },
effect: { kind: "transform", form: "serpent" },
});
});
it("uses imported immunities instead of treating every boss as fear-immune", () => {
expect(REFERENCE.creature.templates["3653"].mechanicImmunities).not.toContain("fear");
expect(REFERENCE.creature.templates["3671"].mechanicImmunities).not.toContain("fear");
expect(REFERENCE.creature.templates["3671"].mechanicImmunities).toContain("sleep");
});
it("never gives a server-backed Wailing creature a synthetic Surge", () => {
const attacks = Object.values(WAILING_CAVERNS_DEFINITION.entities)
.flatMap((entity) => entity.combat?.attacks ?? []);
expect(attacks.some((attack) => /surge/i.test(attack.name))).toBe(false);
});
it("keeps Faerie Dragon despawned and makes Mutanus event-only", () => {
const locked = wailingStaticSpawnsForPhase(WAILING_CAVERNS_STATIC_SPAWNS, "locked");
expect(locked.some((spawn) => spawn.id === "faerie-dragon-spawn")).toBe(false);
expect(locked.some((spawn) => spawn.id === "mutanus-spawn")).toBe(false);
const mutanus = wailingStaticSpawnsForPhase(WAILING_CAVERNS_STATIC_SPAWNS, "mutanus");
expect(mutanus.some((spawn) => spawn.id === "mutanus-spawn")).toBe(true);
});
it("gates Naralex behind the Fanglords, summons exact waves, and recovers from soft locks", () => {
const encounter = useWailingEncounterStore.getState();
encounter.advance({
"lady-anacondra-spawn": deadMob,
"lord-cobrahn-spawn": deadMob,
"lord-pythas-spawn": deadMob,
"lord-serpentis-spawn": deadMob,
}, 1_000);
expect(useWailingEncounterStore.getState().phase).toBe("ready");
expect(useWailingEncounterStore.getState().start(2_000)).toBe(true);
useWailingEncounterStore.getState().advance({}, 10_000);
expect(useWailingEncounterStore.getState().phase).toBe("ravager-wave");
expect(wailingEventSpawns("ravager-wave")).toHaveLength(2);
useWailingEncounterStore.getState().advance({}, 70_001);
expect(useWailingEncounterStore.getState().phase).toBe("escort-serpents");
useWailingEncounterStore.getState().advance({}, 82_001);
expect(useWailingEncounterStore.getState().phase).toBe("serpent-wave");
expect(wailingEventSpawns("serpent-wave")).toHaveLength(3);
useWailingEncounterStore.getState().advance({}, 142_002);
expect(useWailingEncounterStore.getState().phase).toBe("cleansing");
useWailingEncounterStore.getState().advance({}, 174_502);
expect(useWailingEncounterStore.getState().phase).toBe("nightmare-wave");
expect(wailingEventSpawns("nightmare-wave")).toHaveLength(6);
useWailingEncounterStore.getState().advance({}, 264_503);
expect(useWailingEncounterStore.getState().phase).toBe("mutanus");
useWailingEncounterStore.getState().advance({ "mutanus-spawn": deadMob }, 264_504);
expect(useWailingEncounterStore.getState().phase).toBe("complete");
expect(useWailingEncounterStore.getState().flags["dungeon-complete"]).toBe(true);
expect(useWailingEncounterStore.getState().checkpointId).toBe("mutanus-spawn");
});
it("restores the Naralex unlock after a checkpoint reload suppresses the cleared Fanglords", () => {
useWailingEncounterStore.getState().advance({
"lady-anacondra-spawn": deadMob,
"lord-cobrahn-spawn": deadMob,
"lord-pythas-spawn": deadMob,
"lord-serpentis-spawn": deadMob,
}, 1_000);
expect(useWailingEncounterStore.getState()).toMatchObject({
phase: "ready",
flags: { "fanglords-complete": true },
});
useWailingEncounterStore.getState().reset("checkpoint", 2_000);
expect(useWailingEncounterStore.getState()).toMatchObject({
phase: "locked",
flags: { "fanglords-complete": true },
});
// A loaded checkpoint intentionally has no live Fanglord runtime ids: the
// progression provider has already suppressed those completed bosses.
useWailingEncounterStore.getState().advance({}, 2_100);
expect(useWailingEncounterStore.getState().phase).toBe("ready");
});
});