Files

67 lines
2.7 KiB
JavaScript
Raw Permalink Normal View History

2026-10-18 00:29:36 +00:00
import { test } from "node:test";
import assert from "node:assert/strict";
import { compile } from "../src/core/loader.js";
import { VerbResolver } from "../src/core/verbs.js";
import { GameWorld } from "../src/core/world.js";
import { readFileSync } from "node:fs";
const example = JSON.parse(readFileSync(new URL("../example/game.json", import.meta.url), "utf8"));
function setup() {
const c = compile(example);
const w = new GameWorld(c);
const r = new VerbResolver(c);
r.bindWorld(w);
return { c, w, r };
}
test("exact noun beats tag beats wildcard", () => {
const { r } = setup();
const it = r.resolve("look", { kind: "object", id: "post", tags: [] });
assert.equal(it.response, "Sturdy. Smells of rope and regret.");
const tagIt = r.resolve("look", { kind: "character", id: "barkeep", tags: ["talker"] });
assert.ok(tagIt.response.includes("rather not be looked at"));
});
test("conditions gate matches and fall through to next candidate", () => {
const { w, r } = setup();
// give-with-mug: first candidate requires not-gaveMug
let it = r.resolve("give", { kind: "character", id: "barkeep", tags: ["talker"] }, "mug");
assert.ok(it.effects.some((e) => e.setFlag === "gaveMug"));
w.flags.gaveMug = true;
it = r.resolve("give", { kind: "character", id: "barkeep", tags: ["talker"] }, "mug");
assert.equal(it.response, "You already handed it over.");
});
test("with-item matching is strict both ways", () => {
const { r } = setup();
// give without item: no give-with interaction matches
assert.equal(r.resolve("give", { kind: "character", id: "barkeep", tags: [] }, null), null);
// give with wrong item: no match
assert.equal(r.resolve("give", { kind: "character", id: "barkeep", tags: [] }, "rope"), null);
});
test("conditional look on taken mug", () => {
const { w, r } = setup();
let it = r.resolve("look", { kind: "object", id: "mug", tags: ["container"] });
assert.ok(it.response.includes("suspicious"));
w.give("mug");
it = r.resolve("look", { kind: "object", id: "mug", tags: ["container"] });
assert.ok(it.response.includes("pocket"));
});
test("default responses per verb", () => {
const { r } = setup();
assert.equal(r.defaultResponse("use", { kind: "object", id: "post" }), "That doesn't seem to work.");
assert.equal(r.resolve("nope", { kind: "object", id: "post" }), null);
});
test("priority overrides order at equal specificity", () => {
const spec = structuredClone(example);
spec.interactions.unshift({ verb: "look", noun: "post", response: "HIGH", priority: 100 });
const c = compile(spec);
const w = new GameWorld(c);
const r = new VerbResolver(c); r.bindWorld(w);
const it = r.resolve("look", { kind: "object", id: "post", tags: [] });
assert.equal(it.response, "HIGH");
});