const test = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const data = require("../assets/scripts/pages/princess-lima-data.js"); const state = require("../assets/scripts/pages/princess-lima-state.js"); const systems = require("../assets/scripts/pages/princess-lima-systems.js"); const intro = require("../assets/scripts/pages/princess-lima-intro.js"); const root = path.resolve(__dirname, ".."); const rpgSource = fs.readFileSync(path.join(root, "play/rpg.org"), "utf8"); const sceneSource = fs.readFileSync(path.join(root, "assets/scripts/pages/princess-lima-scenes.js"), "utf8"); test("all nine regions use the exact atlas artwork and valid collision-safe transitions", () => { const mapsSource = fs.readFileSync(path.join(root, "assets/scripts/pages/princess-lima-maps.js"), "utf8"); data.MAP_IDS.forEach((region) => { assert.match(mapsSource, new RegExp(`${region}:\\s*\\d`)); Object.values(data.MAPS[region].spawns).forEach((spawn) => { assert.ok(spawn.x > 0 && spawn.x < data.WIDTH); assert.ok(spawn.y > 0 && spawn.y < data.HEIGHT); }); data.MAPS[region].exits.forEach((exit) => { assert.ok(data.MAPS[exit.target]); assert.ok(data.MAPS[exit.target].spawns[exit.spawn]); }); }); assert.equal(data.WIDTH, data.HEIGHT); assert.match(mapsSource, /\.setAlpha\(1\)/); assert.doesNotMatch(mapsSource, /tilemap|tileSprite|add\.circle|add\.ellipse|drawDecor|drawObstacle/); assert.doesNotMatch(sceneSource, /lima-world-tiles|world-tiles\.png/); }); test("all authored actors and interaction points sit outside visible terrain collision", () => { const auditState = state.fresh("Collision audit", "azure"); auditState.unlockedRoutes = ["bridge_repaired"]; data.MAP_IDS.forEach((region) => { const map = data.MAPS[region]; const points = [ ...Object.entries(map.spawns).map(([name, point]) => [`spawn:${name}`, point.x, point.y]), ...(map.npcs || []).map(([name, x, y]) => [`npc:${name}`, x, y]), ...(map.enemies || []).map((enemy, index) => [`enemy:${enemy.type}:${index}`, enemy.x, enemy.y]), ...(map.pickups || []).map(([name, x, y], index) => [`pickup:${name}:${index}`, x, y]), ...(map.puzzle ? map.puzzle.objects.map(([name, x, y]) => [`puzzle:${name}`, x, y]) : []) ]; points.forEach(([name, x, y]) => { assert.equal(systems.isSafePosition(auditState, region, x, y), true, `${region} ${name} must be collision-safe`); }); }); }); test("keyboard-only page contains one left HUD and no touch controls", () => { assert.match(rpgSource, /class="lima-hud"/); assert.match(rpgSource, /Inventory I<\/kbd>/); assert.match(rpgSource, /Menu M<\/kbd>/); assert.doesNotMatch(rpgSource, /data-lima-touch|data-lima-move|Touch controls|data-lima-attack/); }); test("opening cinematic is complete, replayable and accessible", () => { assert.equal(intro.BEATS.length, 5); assert.ok(intro.BEATS.reduce((total, beat) => total + beat.duration, 0) >= 60000); assert.ok(intro.BEATS.every((beat) => beat.subtitle.length > 20)); assert.match(rpgSource, /data-lima-replay-intro/); assert.match(rpgSource, /data-lima-intro-pause/); assert.match(rpgSource, /Hold Escape to skip/); });