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>; }; readonly wailingCaverns: { readonly requiredBossEntries: readonly number[]; readonly despawnOnInitializeEntries: readonly number[]; readonly unsupportedRequiredBossActions: readonly unknown[]; readonly abilitiesByEntry: Readonly>; readonly effect: Readonly>; }[]>>; }; } 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"); }); });