67 lines
2.7 KiB
JavaScript
67 lines
2.7 KiB
JavaScript
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");
|
||
|
|
});
|