Refine archive world spawn and interaction handling
All checks were successful
Build Org Website / build (push) Successful in 38s

This commit is contained in:
gitea-actions
2026-07-30 10:22:23 +01:00
parent 2f125f32ae
commit dc1ca5c00e
11 changed files with 112 additions and 33 deletions

View File

@@ -9,6 +9,11 @@ test("fresh v2 state applies safe defaults", () => {
assert.equal(fresh.name, "Ada");
assert.equal(fresh.palette, "moss");
assert.equal(fresh.position.area, "town");
assert.deepEqual(
{ x: fresh.position.x, y: fresh.position.y },
data.AREAS.town.safeSpawns.gate
);
assert.ok(fresh.position.y > data.AREAS.town.gates[0].y + data.AREAS.town.gates[0].height);
assert.equal(fresh.health, 100);
assert.equal(fresh.settings.soundEnabled, false);
assert.deepEqual(fresh.sigils, []);

View File

@@ -102,6 +102,31 @@ test("invalid collision positions resolve to a named safe spawn", () => {
assert.ok(["gate", "square", "library", "study", "inn", "workshop", "playroom", "museum", "garden"].includes(safe.spawn));
});
test("locked-gate saves inside town recover to the outside opening spawn", () => {
const current = state.fresh("Ada", "brass");
current.position = { area: "town", spawn: "square", x: 724, y: 555, facing: "south" };
const safe = systems.safeSpawnForState(current);
assert.deepEqual(
{ area: safe.area, spawn: safe.spawn, x: safe.x, y: safe.y },
{ area: "town", spawn: "gate", ...data.AREAS.town.safeSpawns.gate }
);
current.sigils.push("gate");
const unlocked = systems.safeSpawnForState(current);
assert.equal(unlocked.spawn, "saved");
assert.equal(unlocked.y, 555);
});
test("interaction ranges are type-specific and NPC conversations require close approach", () => {
const npc = { type: "npc", id: "orin", x: 0, y: 0 };
const landmark = { type: "landmark", id: "gate", x: 56, y: 0 };
assert.equal(systems.interactionRadius(npc), 46);
assert.equal(systems.nearestInteraction([npc], 47, 0), null);
assert.equal(systems.nearestInteraction([npc], 45, 0), npc);
assert.equal(systems.nearestInteraction([npc, landmark], 0, 0), npc);
assert.equal(systems.nearestInteraction([landmark], 0, 0), landmark);
});
test("all declared safe spawns and enemy homes are outside collision geometry", () => {
Object.entries(data.AREAS).forEach(([areaId, area]) => {
Object.entries(area.safeSpawns).forEach(([spawnId, spawn]) => {
@@ -125,3 +150,11 @@ test("town landmarks and NPC interaction points remain reachable", () => {
assert.equal(systems.isSafe("town", x, y), true, `npc:${npcId}`);
});
});
test("town safe spawns do not place the player inside an NPC body", () => {
Object.entries(data.AREAS.town.safeSpawns).forEach(([spawnId, spawn]) => {
data.AREAS.town.npcs.forEach(([npcId, x, y]) => {
assert.ok(Math.hypot(spawn.x - x, spawn.y - y) >= 30, `${spawnId} overlaps npc:${npcId}`);
});
});
});