Files
healer-man/src/game/dungeonWorldObjects.test.ts
2026-09-08 10:40:26 -04:00

51 lines
2.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
dungeonWorldObjectState,
nearestDungeonWorldInteraction,
validateDungeonWorldObject,
type DungeonWorldObjectDefinition,
} from "./dungeonWorldObjects";
const door: DungeonWorldObjectDefinition = {
id: "test-door",
name: "Test Door",
kind: "door",
position: [3, 0, 0],
halfExtents: [1, 2, 0.25],
initialState: "closed",
states: [
{ id: "closed", label: "Closed", visible: true, blocksMovement: true, interactionEnabled: true },
{ id: "open", label: "Open", visible: false, blocksMovement: false, interactionEnabled: false },
],
interaction: {
prompt: "Open door",
range: 4,
signalId: "open-test-door",
allowedStates: ["closed"],
},
};
describe("dungeon world objects", () => {
it("resolves authored and fallback object states", () => {
expect(dungeonWorldObjectState(door, "open").blocksMovement).toBe(false);
expect(dungeonWorldObjectState(door, "missing").id).toBe("closed");
});
it("selects the nearest enabled visible interaction in range and line of sight", () => {
const farther = { ...door, id: "far-door", position: [3.5, 0, 0] as const };
expect(nearestDungeonWorldInteraction([farther, door], {}, [0, 0, 0])?.object.id).toBe("test-door");
expect(nearestDungeonWorldInteraction([door], { "test-door": "open" }, [0, 0, 0])).toBeNull();
expect(nearestDungeonWorldInteraction([door], {}, [0, 0, 0], () => false)).toBeNull();
});
it("rejects malformed geometry, state, and interaction contracts", () => {
expect(() => validateDungeonWorldObject(door)).not.toThrow();
expect(() => validateDungeonWorldObject({ ...door, halfExtents: [0, 2, 1] })).toThrow("invalid geometry");
expect(() => validateDungeonWorldObject({ ...door, initialState: "missing" })).toThrow("does not define");
expect(() => validateDungeonWorldObject({
...door,
interaction: { ...door.interaction!, range: 0 },
})).toThrow("invalid interaction");
});
});