import { createHash } from "node:crypto"; import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { gunzipSync, strFromU8 } from "fflate"; import { describe, expect, it } from "vitest"; import { createDungeonEncounterSnapshot, reduceDungeonEncounter, resetDungeonEncounterSnapshot, validateDungeonEncounterDefinition, } from "./dungeonEncounterRuntime"; import type { DungeonDefinition, DungeonEncounterSpawnGroupDefinition } from "./dungeonTypes"; import type { DungeonEncounterDefinition, DungeonEncounterSnapshot } from "./dungeonEncounterTypes"; import { validateDungeonWorldObject } from "./dungeonWorldObjects"; import compressedCampaign from "./generated/dungeonCampaignCatalog.compressed"; import { WOW_CLASSIC_ENCOUNTER_BATCH_TWO_REVIEWS, withWowClassicEncounterBatchTwo, } from "./wowClassicEncounterBatchTwoCatalog"; function decodeBase64(value: string): Uint8Array { const decoded = atob(value); const bytes = new Uint8Array(decoded.length); for (let index = 0; index < decoded.length; index += 1) bytes[index] = decoded.charCodeAt(index); return bytes; } const campaign = JSON.parse(strFromU8(gunzipSync(decodeBase64(compressedCampaign)))) as { readonly definitions: readonly DungeonDefinition[]; }; function original(id: string): DungeonDefinition { const definition = campaign.definitions.find((candidate) => candidate.id === id); if (!definition) throw new Error(`Missing generated dungeon ${id}`); return definition; } function adapted(id: string): DungeonDefinition { return withWowClassicEncounterBatchTwo(original(id)); } function encounter(definition: DungeonDefinition): DungeonEncounterDefinition { const value = definition.encounters?.find((candidate) => candidate.id === `${definition.id}:classic-batch-two`); if (!value) throw new Error(`Missing Classic batch-two encounter for ${definition.id}`); return value; } function group(definition: DungeonDefinition, id: string): DungeonEncounterSpawnGroupDefinition { const value = definition.encounterSpawnGroups?.find((candidate) => candidate.id === id); if (!value) throw new Error(`Missing encounter group ${id}`); return value; } function objectBySpawn(definition: DungeonDefinition, spawnId: number) { const matches = definition.serverGameObjects.filter((object) => object.source?.spawnId === spawnId); if (matches.length !== 1) throw new Error(`${definition.id} expected one source object ${spawnId}, found ${matches.length}`); return matches[0]; } function killGroup( definition: DungeonEncounterDefinition, snapshot: DungeonEncounterSnapshot, spawnGroup: DungeonEncounterSpawnGroupDefinition, now: number, ) { const entityIds = spawnGroup.spawns.map((spawn) => spawn.id); return reduceDungeonEncounter(definition, snapshot, { kind: "tick", now, facts: { registeredEntityIds: entityIds, deadEntityIds: entityIds }, }).snapshot; } function staticEntries(definition: DungeonDefinition): readonly number[] { return definition.staticSpawns.flatMap((spawn) => { const entry = definition.entities[spawn.entityId]?.combat?.serverEntry; return entry === undefined ? [] : [entry]; }); } describe("Classic source-backed encounter batch two", () => { it("pins exact source hashes, validates every reference, suppresses event actors, and stays idempotent", () => { const cases = [ ["sunken-temple", [8_580, 8_443, 5_709]], ["blackrock-depths", [9_035, 9_038, 9_040, 9_037, 9_036, 9_034, 9_039]], ["scholomance", [1_853]], ["stratholme", [10_440]], ] as const; expect(WOW_CLASSIC_ENCOUNTER_BATCH_TWO_REVIEWS.map((review) => review.dungeonId)) .toEqual(cases.map(([id]) => id)); const verifiedPaths = new Set(); for (const review of WOW_CLASSIC_ENCOUNTER_BATCH_TWO_REVIEWS) { expect(review.fidelity).toBe("source-backed-adapted"); expect(review.adaptations.length).toBeGreaterThan(0); expect(review.remainingGaps.length).toBeGreaterThan(0); for (const sourceFile of review.sourceFiles) { expect(sourceFile.sha256).toMatch(/^[a-f0-9]{64}$/); expect(sourceFile.anchors.length).toBeGreaterThan(0); expect(sourceFile.anchors.every((anchor) => /lines? \d+/.test(anchor))).toBe(true); if (!verifiedPaths.has(sourceFile.path)) { const actualHash = createHash("sha256").update(readFileSync(resolve(sourceFile.path))).digest("hex"); expect(actualHash, sourceFile.path).toBe(sourceFile.sha256); verifiedPaths.add(sourceFile.path); } } } for (const [id, suppressedEntries] of cases) { const definition = adapted(id); const scripted = encounter(definition); validateDungeonEncounterDefinition(scripted); expect(withWowClassicEncounterBatchTwo(definition)).toBe(definition); expect(staticEntries(definition)).not.toEqual(expect.arrayContaining([...suppressedEntries])); const spawnIds = new Set([ ...definition.staticSpawns.map((spawn) => spawn.id), ...(definition.encounterSpawnGroups ?? []).flatMap((spawnGroup) => spawnGroup.spawns.map((spawn) => spawn.id)), ]); const spawnGroupIds = new Set(definition.encounterSpawnGroups?.map((spawnGroup) => spawnGroup.id)); const objectIds = new Set(definition.serverGameObjects.map((object) => object.id)); const objectiveIds = new Set(definition.bosses.map((objective) => objective.id)); for (const spawnGroup of definition.encounterSpawnGroups ?? []) { for (const spawn of spawnGroup.spawns) { expect(definition.entities[spawn.entityId], `${id}:${spawnGroup.id}:${spawn.id}`).toBeDefined(); } } for (const rule of scripted.rules) { if (rule.trigger.kind === "interact") expect(objectIds.has(rule.trigger.objectId), `${id}:${rule.id}`).toBe(true); if (rule.trigger.kind === "entity-death" || rule.trigger.kind === "entity-engaged" || rule.trigger.kind === "entity-health") { expect(spawnIds.has(rule.trigger.entityId), `${id}:${rule.id}:${rule.trigger.entityId}`).toBe(true); } if (rule.trigger.kind === "entities-dead") { expect(rule.trigger.entityIds.every((entityId) => spawnIds.has(entityId)), `${id}:${rule.id}`).toBe(true); } for (const action of rule.actions) { if (action.kind === "activate-spawn-group" || action.kind === "deactivate-spawn-group") { expect(spawnGroupIds.has(action.spawnGroupId), `${id}:${rule.id}:${action.id}`).toBe(true); } if (action.kind === "set-world-object-state") { const object = definition.serverGameObjects.find((candidate) => candidate.id === action.objectId); expect(object, `${id}:${rule.id}:${action.id}`).toBeDefined(); expect(object?.states.some((state) => state.id === action.state), `${id}:${rule.id}:${action.id}`).toBe(true); } if (action.kind === "complete-objective") { expect(objectiveIds.has(action.objectiveId), `${id}:${rule.id}:${action.id}`).toBe(true); } } } const sourceSpawnIds = definition.serverGameObjects .flatMap((object) => object.source?.spawnId === undefined ? [] : [object.source.spawnId]); expect(new Set(sourceSpawnIds).size).toBe(sourceSpawnIds.length); for (const object of definition.serverGameObjects.filter((candidate) => ( scripted.initialState?.worldObjectStates?.[candidate.id] !== undefined ))) { validateDungeonWorldObject(object); expect(object.visual?.hidden).not.toBe(true); } expect(definition.validation.warnings.some((warning) => warning.includes("remain"))).toBe(true); } }); it("runs Sunken Temple's ordered statues, ritual, defender gate, and Eranikus recovery", () => { const definition = adapted("sunken-temple"); const scripted = encounter(definition); const statues = [27_898, 27_899, 28_111, 28_112, 28_113, 28_114] .map((spawnId) => objectBySpawn(definition, spawnId)); const forcefield = objectBySpawn(definition, 268_932); const altar = objectBySpawn(definition, 11_922); const flames = [47_561, 47_562, 47_563, 47_564].map((spawnId) => objectBySpawn(definition, spawnId)); let snapshot = createDungeonEncounterSnapshot(scripted); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: statues[1].id, now: 1 }).snapshot; expect(snapshot.counters["statue-progress"]).toBe(0); for (let index = 0; index < statues.length; index += 1) { snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: statues[index].id, now: index + 2, }).snapshot; } expect(snapshot).toMatchObject({ phase: "atal-alarion-active", counters: { "statue-progress": 6 } }); expect(snapshot.activeSpawnGroupIds).toContain("sunken-temple:atal-alarion"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 20); expect(snapshot).toMatchObject({ phase: "recovery", counters: { "statue-progress": 6 }, activeSpawnGroupIds: [] }); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 20 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain("sunken-temple:atal-alarion"); snapshot = killGroup(scripted, snapshot, group(definition, "sunken-temple:atal-alarion"), 21); const atalAlarion = definition.bosses.find((objective) => objective.name === "Atal'alarion")!; expect(snapshot.completedObjectiveIds).toContain(atalAlarion.id); const defenderIds = ["creature-39843", "creature-39844", "creature-39845", "creature-39846", "creature-34522", "creature-39847"]; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 22, facts: { registeredEntityIds: defenderIds, deadEntityIds: defenderIds }, }).snapshot; expect(snapshot.worldObjectStates[forcefield.id]).toBe("open"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: altar.id, now: 30 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain("sunken-temple:hakkar-pack-1"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 31); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 31 }).snapshot; expect(snapshot).toMatchObject({ phase: "idle", activeSpawnGroupIds: [] }); expect(snapshot.worldObjectStates[altar.id]).toBe("ready"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: altar.id, now: 40 }).snapshot; for (let index = 0; index < 4; index += 1) { const ritualGroup = group(definition, `sunken-temple:hakkar-pack-${index + 1}`); snapshot = killGroup(scripted, snapshot, ritualGroup, 41 + index * 2); expect(snapshot.worldObjectStates[flames[index].id]).toBe("ready"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: flames[index].id, now: 42 + index * 2, }).snapshot; } expect(snapshot.activeSpawnGroupIds).toContain("sunken-temple:avatar-of-hakkar"); snapshot = killGroup(scripted, snapshot, group(definition, "sunken-temple:avatar-of-hakkar"), 60); const avatar = definition.bosses.find((objective) => objective.name === "Avatar of Hakkar")!; expect(snapshot.completedObjectiveIds).toContain(avatar.id); expect(flames.every((flame) => snapshot.worldObjectStates[flame.id] === "doused")).toBe(true); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: "creature-39737", now: 70 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain("sunken-temple:shade-of-eranikus"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 71); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 71 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain("sunken-temple:shade-of-eranikus"); snapshot = killGroup(scripted, snapshot, group(definition, "sunken-temple:shade-of-eranikus"), 72); const eranikus = definition.bosses.find((objective) => objective.name === "Shade of Eranikus")!; expect(snapshot.completedObjectiveIds).toContain(eranikus.id); expect(snapshot.checkpointId).toBe("sunken-temple-eranikus"); }); it("runs BRD's deterministic arena, twelve-coffer vault, and exact seven-stage tomb with retry", () => { const definition = adapted("blackrock-depths"); const scripted = encounter(definition); const arenaGate4 = objectBySpawn(definition, 15_309); const arenaGate3 = objectBySpawn(definition, 15_295); const arenaGroups = [ group(definition, "blackrock-depths:ring-wave-1"), group(definition, "blackrock-depths:ring-wave-2"), group(definition, "blackrock-depths:ring-boss"), ]; expect(arenaGroups.map((spawnGroup) => spawnGroup.spawns.length)).toEqual([3, 3, 1]); let snapshot = reduceDungeonEncounter(scripted, createDungeonEncounterSnapshot(scripted), { kind: "interact", objectId: arenaGate4.id, now: 0, }).snapshot; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 5_000 }).snapshot; snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 5_001); expect(snapshot.worldObjectStates[arenaGate4.id]).toBe("ready"); expect(snapshot.activeSpawnGroupIds).toEqual([]); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: arenaGate4.id, now: 6_000 }).snapshot; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 11_000 }).snapshot; snapshot = killGroup(scripted, snapshot, arenaGroups[0], 11_001); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 16_001 }).snapshot; snapshot = killGroup(scripted, snapshot, arenaGroups[1], 16_002); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 21_002 }).snapshot; snapshot = killGroup(scripted, snapshot, arenaGroups[2], 21_003); expect(snapshot.completedObjectiveIds).toContain("blackrock-depths:ring-of-law-gorosh"); expect(snapshot.worldObjectStates[arenaGate3.id]).toBe("open"); expect(snapshot.worldObjectStates[arenaGate4.id]).toBe("open"); const coffers = [15_306, 15_329, 15_330, 15_331, 15_363, 15_364, 15_365, 15_536, 17_904, 35_801, 35_864, 39_924] .map((spawnId) => objectBySpawn(definition, spawnId)); for (let index = 0; index < 6; index += 1) { snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: coffers[index].id, now: 30 + index }).snapshot; } snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 40); expect(snapshot.counters["opened-coffers"]).toBe(6); expect(coffers.slice(0, 6).every((coffer) => snapshot.worldObjectStates[coffer.id] === "open")).toBe(true); for (let index = 6; index < coffers.length; index += 1) { snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: coffers[index].id, now: 41 + index }).snapshot; } snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 60 }).snapshot; const watchman = group(definition, "blackrock-depths:vault-watchman"); expect(snapshot.activeSpawnGroupIds).toContain(watchman.id); snapshot = killGroup(scripted, snapshot, watchman, 61); expect(snapshot.completedObjectiveIds).toContain("blackrock-depths:watchman-doomgrip"); expect(snapshot.worldObjectStates[objectBySpawn(definition, 43_094).id]).toBe("open"); const marker = definition.serverGameObjects.find((object) => object.id === "blackrock-depths:doomrel-marker")!; const tombGroups = Array.from({ length: 7 }, (_, index) => group(definition, `blackrock-depths:tomb-spectral-${index + 1}`)); expect(tombGroups.map((spawnGroup) => spawnGroup.spawns.length)).toEqual([1, 1, 1, 1, 1, 1, 1]); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: marker.id, now: 100 }).snapshot; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 1_100 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain(tombGroups[0].id); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 1_101); expect(snapshot).toMatchObject({ phase: "idle", counters: { "tomb-kills": 0 }, activeSpawnGroupIds: [] }); expect(snapshot.worldObjectStates[marker.id]).toBe("ready"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: marker.id, now: 2_000 }).snapshot; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 3_000 }).snapshot; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: tombGroups[0].spawns[0].id, now: 3_001, }).snapshot; for (let index = 1; index < tombGroups.length; index += 1) { snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: snapshot.phaseStartedAt + 30_000, }).snapshot; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: tombGroups[index].spawns[0].id, now: snapshot.phaseStartedAt + 1, }).snapshot; } snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: snapshot.phaseStartedAt + 2 }).snapshot; expect(snapshot.completedObjectiveIds).toContain("blackrock-depths:tomb-of-seven"); expect(snapshot.worldObjectStates[objectBySpawn(definition, 67_872).id]).toBe("available"); expect(snapshot.worldObjectStates[objectBySpawn(definition, 15_334).id]).toBe("open"); }); it("gates Scholomance completion on six minibosses and a wipe-safe Gandling reveal", () => { const definition = adapted("scholomance"); const scripted = encounter(definition); const brazier = objectBySpawn(definition, 43_208); const kirtonosGate = objectBySpawn(definition, 18_892); const gandlingEntrance = objectBySpawn(definition, 43_201); const progression = definition.encounters?.find((candidate) => candidate.id === "scholomance:boss-progression")!; expect(progression.rules.some((rule) => rule.id === "all-required-bosses-defeated")).toBe(false); let snapshot = reduceDungeonEncounter(scripted, createDungeonEncounterSnapshot(scripted), { kind: "interact", objectId: brazier.id, now: 0, }).snapshot; expect(snapshot.worldObjectStates[kirtonosGate.id]).toBe("closed"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 1); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 1 }).snapshot; expect(snapshot.worldObjectStates[brazier.id]).toBe("ready"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "interact", objectId: brazier.id, now: 2 }).snapshot; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 5_002 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain("scholomance:kirtonos"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: "scholomance:kirtonos-the-herald", now: 5_003, }).snapshot; expect(snapshot.completedObjectiveIds).toContain("scholomance:kirtonos-the-herald"); expect(snapshot.worldObjectStates[kirtonosGate.id]).toBe("open"); const miniBossIds = ["creature-48867", "creature-48925", "creature-48946", "creature-48863", "creature-48857", "creature-48854"]; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 6_000, facts: { registeredEntityIds: miniBossIds, deadEntityIds: miniBossIds }, }).snapshot; expect(snapshot.phase).toBe("gandling-reveal"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 6_001); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 6_001 }).snapshot; expect(snapshot).toMatchObject({ phase: "gandling-ready", flags: { "gandling-unlocked": true } }); expect(snapshot.activeSpawnGroupIds).toContain("scholomance:gandling"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-engaged", entityId: "creature-247104", now: 6_002, }).snapshot; expect(snapshot.worldObjectStates[gandlingEntrance.id]).toBe("closed"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 6_003); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 6_003 }).snapshot; expect(snapshot.worldObjectStates[gandlingEntrance.id]).toBe("open"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: "creature-247104", now: 6_004, }).snapshot; expect(snapshot.completedObjectiveIds).toContain("creature-247104"); const fleetRequired = definition.bosses.filter((objective) => !objective.optional && !objective.eventOnly); for (const objective of fleetRequired) { snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: objective.id, now: snapshot.revision + 10_000, }).snapshot; } snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 20_000 }).snapshot; expect(snapshot).toMatchObject({ phase: "complete", flags: { "dungeon-complete": true } }); }); it("persists and resumes Stratholme's exact 3-to-13-to-1-to-33-to-5 slaughter chain", () => { const definition = adapted("stratholme"); const scripted = encounter(definition); const acolytes = Array.from({ length: 3 }, (_, index) => group(definition, `stratholme:ziggurat-${index + 1}-acolyte`)); const zigguratBosses = ["creature-54238", "creature-54239", "creature-54240"]; const zigguratDoors = [11_415, 11_414, 11_416].map((spawnId) => objectBySpawn(definition, spawnId)); const mindless = group(definition, "stratholme:mindless-undead"); const guards = group(definition, "stratholme:black-guards"); expect(acolytes.map((spawnGroup) => spawnGroup.spawns.length)).toEqual([1, 1, 1]); expect(mindless.spawns).toHaveLength(33); expect(guards.spawns).toHaveLength(5); let snapshot = createDungeonEncounterSnapshot(scripted); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: zigguratBosses[0], now: 1 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain(acolytes[0].id); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 2); expect(snapshot.worldObjectStates[zigguratDoors[0].id]).toBe("open"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 2 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain(acolytes[0].id); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: acolytes[0].spawns[0].id, now: 3, }).snapshot; for (let index = 1; index < 3; index += 1) { snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: zigguratBosses[index], now: 4 + index * 2, }).snapshot; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: acolytes[index].spawns[0].id, now: 5 + index * 2, }).snapshot; } snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 20 }).snapshot; expect(snapshot.flags["ziggurats-complete"]).toBe(true); expect(snapshot.worldObjectStates[objectBySpawn(definition, 6_911).id]).toBe("open"); expect(snapshot.worldObjectStates[objectBySpawn(definition, 6_908).id]).toBe("open"); const slaughterIds = [ "creature-53969", "creature-54002", "creature-54018", "creature-54019", "creature-54020", "creature-54021", "creature-54022", "creature-54026", "creature-54027", "creature-54039", "creature-54040", "creature-54041", "creature-54050", ]; snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 21, facts: { registeredEntityIds: slaughterIds, deadEntityIds: slaughterIds }, }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain("stratholme:ramstein"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 22); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 22 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain("stratholme:ramstein"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: "stratholme:ramstein-the-gorger", now: 23, }).snapshot; expect(snapshot.phase).toBe("mindless-delay"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "checkpoint", 24); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 24 }).snapshot; expect(snapshot.phase).toBe("mindless-delay"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 5_024 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain(mindless.id); snapshot = killGroup(scripted, snapshot, mindless, 5_025); expect(snapshot.phase).toBe("black-guard-delay"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 5_026); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 5_026 }).snapshot; expect(snapshot.phase).toBe("black-guard-delay"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 25_026 }).snapshot; expect(snapshot.activeSpawnGroupIds).toContain(guards.id); expect(snapshot.worldObjectStates[objectBySpawn(definition, 11_808).id]).toBe("open"); snapshot = killGroup(scripted, snapshot, guards, 25_027); expect(snapshot.activeSpawnGroupIds).toContain("stratholme:baron-rivendare"); expect(snapshot.worldObjectStates[objectBySpawn(definition, 35_848).id]).toBe("open"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-engaged", entityId: "creature-54241", now: 25_028, }).snapshot; expect(snapshot.worldObjectStates[objectBySpawn(definition, 35_848).id]).toBe("closed"); snapshot = resetDungeonEncounterSnapshot(scripted, snapshot, "boss-wipe", 25_029); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "tick", now: 25_029 }).snapshot; expect(snapshot).toMatchObject({ phase: "baron-ready", flags: { "guards-defeated": true } }); expect(snapshot.worldObjectStates[objectBySpawn(definition, 35_848).id]).toBe("open"); snapshot = reduceDungeonEncounter(scripted, snapshot, { kind: "entity-death", entityId: "creature-54241", now: 25_030, }).snapshot; expect(snapshot.completedObjectiveIds).toContain("creature-54241"); expect(snapshot.checkpointId).toBe("creature-54241"); }); });