71 lines
2.8 KiB
TypeScript
71 lines
2.8 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
import {
|
|
DUNGEON_SIMULATION_FIXED_STEP_MS,
|
|
fixedSimulationTickCount,
|
|
useDungeonSimulationStore,
|
|
} from "./dungeonSimulationStore";
|
|
import { createSpectatorDungeonParty } from "./partyStore";
|
|
import { routeHasExactApproval } from "./dungeonRoutes";
|
|
import type { DungeonRouteDefinitionV1, DungeonSimulationSpeed } from "./dungeonSimulationTypes";
|
|
|
|
const route: DungeonRouteDefinitionV1 = {
|
|
schemaVersion: 1,
|
|
id: "primary",
|
|
dungeonId: "test-dungeon",
|
|
mapId: 1,
|
|
hash: "a".repeat(64),
|
|
generationStatus: "Candidate",
|
|
generationIssues: [],
|
|
legs: [{
|
|
id: "leg-1",
|
|
objectiveId: "boss-1",
|
|
objectiveName: "Boss",
|
|
checkpoints: [[0, 0, 0], [4, 0, 0]],
|
|
expectedDistance: 4,
|
|
corridorPlanarDistance: 10,
|
|
corridorVerticalDistance: 4,
|
|
actions: [],
|
|
}],
|
|
};
|
|
|
|
describe("dungeon simulation fixed clock", () => {
|
|
beforeEach(() => useDungeonSimulationStore.getState().leave());
|
|
|
|
it("produces the same ordered ticks at every playback speed", () => {
|
|
const speeds: readonly DungeonSimulationSpeed[] = [0.5, 1, 2, 4];
|
|
for (const speed of speeds) {
|
|
const wallDuration = 500 / speed;
|
|
const result = fixedSimulationTickCount(0, wallDuration, speed);
|
|
expect(result.ticks).toBe(500 / DUNGEON_SIMULATION_FIXED_STEP_MS);
|
|
expect(result.accumulatorMs).toBe(0);
|
|
}
|
|
});
|
|
|
|
it("freezes while paused and advances exactly one tick per step", () => {
|
|
const store = useDungeonSimulationStore.getState();
|
|
store.startLive({ dungeonId: route.dungeonId, route, mode: "navigation-only", seed: "clock", startedAt: 10_000 });
|
|
store.setRunning(false);
|
|
expect(useDungeonSimulationStore.getState().consumeTicks(5_000)).toEqual([]);
|
|
expect(useDungeonSimulationStore.getState().elapsedMs).toBe(0);
|
|
useDungeonSimulationStore.getState().step();
|
|
expect(useDungeonSimulationStore.getState().consumeTicks(0)).toEqual([10_050]);
|
|
expect(useDungeonSimulationStore.getState().elapsedMs).toBe(50);
|
|
});
|
|
});
|
|
|
|
describe("spectator roster and exact-hash approvals", () => {
|
|
it("creates a stable tank, healer, and three damage dealers", () => {
|
|
const first = createSpectatorDungeonParty("same-seed", 80, "wow");
|
|
const second = createSpectatorDungeonParty("same-seed", 80, "wow");
|
|
expect(second).toEqual(first);
|
|
expect(first.map((member) => member.role)).toEqual(["tank", "healer", "damage", "damage", "damage"]);
|
|
});
|
|
|
|
it("rejects stale hashes and generator-rejected routes", () => {
|
|
const approval = { dungeonId: route.dungeonId, routeId: route.id, routeHash: route.hash, reviewedAt: 1 };
|
|
expect(routeHasExactApproval(route, [approval])).toBe(true);
|
|
expect(routeHasExactApproval({ ...route, hash: "b".repeat(64) }, [approval])).toBe(false);
|
|
expect(routeHasExactApproval({ ...route, generationStatus: "Rejected" }, [approval])).toBe(false);
|
|
});
|
|
});
|