156 lines
6.1 KiB
JavaScript
156 lines
6.1 KiB
JavaScript
// dev/escort-compass.test.mjs — the ESCORT destination compass → autopilot
|
|
// chain, verified headless (node dev/escort-compass.test.mjs).
|
|
//
|
|
// Replicates the real click path:
|
|
// escortCompassTarget() → { kind:'destination', objectId }
|
|
// updateDiscovery pushes → id `escort:obj:<objectId>`
|
|
// chip click → autopilotTo('escort:obj:<objectId>')
|
|
// and asserts the ship's target lands on the destination world's rim —
|
|
// for a PLANET destination (discoveryId = its NAME) and a STATION
|
|
// destination (discoveryId = settlement id).
|
|
|
|
process.env.NODE_ENV = 'dev';
|
|
import { pathToFileURL } from 'node:url';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { dirname, join } from 'node:path';
|
|
import assert from 'node:assert/strict';
|
|
import './phaser-loader.mjs'; // ../vendor/phaser.js -> ./phaser-stub.mjs (Node only)
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const { config } = await import(pathToFileURL(join(__dirname, '../js/config/Config.js')).href);
|
|
const fs = await import('node:fs');
|
|
const configData = {};
|
|
for (const f of fs.readdirSync(join(__dirname, '../data'))) {
|
|
if (!f.endsWith('.json') || f === 'manifest.json') continue;
|
|
configData[f.replace(/\.json$/i, '')] = JSON.parse(fs.readFileSync(join(__dirname, '../data', f), 'utf8'));
|
|
}
|
|
config.init(configData);
|
|
|
|
const { GameScene } = await import(pathToFileURL(join(__dirname, '../js/scenes/GameScene.js')).href);
|
|
|
|
function makeScene(dest) {
|
|
const s = Object.create(GameScene.prototype);
|
|
const route = {
|
|
kind: 'escort',
|
|
targetSystemId: 'sys-dest',
|
|
waypoints: [[120, 340]], // the RENDEZVOUS point (origin system's coords)
|
|
credits: 100,
|
|
xp: 10,
|
|
escort: {
|
|
phase: 'transit',
|
|
originSystemId: 'sys-home',
|
|
destSystemId: 'sys-dest',
|
|
destObjectType: dest.objectType,
|
|
destObjectId: dest.objectId,
|
|
destObjectName: dest.objectName,
|
|
hops: 1,
|
|
},
|
|
};
|
|
s.ship = { x: 0, y: 0, radius: 12, setTarget: (x, y) => { s.aim = { x, y }; } };
|
|
s.systemRecord = { id: 'sys-dest' };
|
|
s.systemContent = { planets: dest.planets, settlements: dest.settlements };
|
|
s.systemPlanets = dest.planets.map((p) => ({
|
|
x: p.x, y: p.y, radius: p.radius,
|
|
name: p.class ?? 'gas', // the Planet entity's `name` is its CLASS label
|
|
discoveryId: p.name, discoveryName: p.name,
|
|
}));
|
|
s.systemStations = dest.settlements.map((st) => ({
|
|
x: st.x, y: st.y, bound: st.bound, discoveryId: st.id,
|
|
discoveryName: st.name, settlement: { id: st.id },
|
|
}));
|
|
s.solids = [
|
|
...s.systemPlanets.map((p) => ({ discoveryId: p.discoveryId, clearance: 30, edgePoint: () => ({ x: p.x - 42, y: p.y }), aimPoint: (x, y) => ({ x, y }) })),
|
|
...s.systemStations.map((st) => ({ discoveryId: st.discoveryId, clearance: 40, edgePoint: () => ({ x: st.x - 80, y: st.y }), aimPoint: (x, y) => ({ x, y }) })),
|
|
];
|
|
s.asteroidClusters = [];
|
|
s.systemGates = [];
|
|
s.planet = null;
|
|
s.sideQuestState = {
|
|
activeId: 'sq-job',
|
|
isCompleted: () => false,
|
|
isClaimed: () => false,
|
|
routeFor: () => route,
|
|
};
|
|
s.tetherField = { clampPoint: (x, y) => ({ x, y }) };
|
|
s.showTargetMarker = (x, y) => { s.marker = { x, y }; };
|
|
s.hideHint = () => {};
|
|
s._commInputBlocked = () => false;
|
|
s.menuSubBar = null;
|
|
return s;
|
|
}
|
|
|
|
// --- PLANET destination (discoveryId = the planet's NAME) ---------------
|
|
{
|
|
const s = makeScene({
|
|
objectType: 'planet',
|
|
objectId: 'p3',
|
|
objectName: 'Kepler-6',
|
|
planets: [{ id: 'p3', name: 'Kepler-6', x: 900, y: 400, radius: 60 }],
|
|
settlements: [],
|
|
});
|
|
const t = s.escortCompassTarget();
|
|
assert.ok(t, 'compass target stands');
|
|
assert.equal(t.kind, 'destination');
|
|
assert.equal(t.objectId, 'Kepler-6', 'objectId is the live entity discoveryId (the name)');
|
|
const id = `escort:obj:${t.objectId}`;
|
|
s.autopilotTo(id);
|
|
assert.deepEqual(s.aim, { x: 858, y: 400 }, 'autopilot aims at the planet rim');
|
|
console.log('planet destination: OK —', id, '→ aim', JSON.stringify(s.aim));
|
|
}
|
|
|
|
// --- STATION destination (discoveryId = settlement id) -------------------
|
|
{
|
|
const s = makeScene({
|
|
objectType: 'station',
|
|
objectId: 's2',
|
|
objectName: 'Relay 9',
|
|
planets: [],
|
|
settlements: [{ id: 's2', name: 'Relay 9', x: 700, y: 700, bound: 80 }],
|
|
});
|
|
const t = s.escortCompassTarget();
|
|
assert.ok(t, 'compass target stands');
|
|
assert.equal(t.kind, 'destination');
|
|
assert.equal(t.objectId, 's2');
|
|
const id = `escort:obj:${t.objectId}`;
|
|
s.autopilotTo(id);
|
|
assert.deepEqual(s.aim, { x: 620, y: 700 }, 'autopilot aims at the station keepout');
|
|
console.log('station destination: OK —', id, '→ aim', JSON.stringify(s.aim));
|
|
}
|
|
|
|
// --- the OLD bug must stay fixed: a `patrol:wp:` click on an escort route
|
|
// must NOT silently fly the rendezvous coordinates (it resolves
|
|
// route.waypoints[0] — here (120,340) — which in the destination system
|
|
// is a random void point).
|
|
{
|
|
const s = makeScene({
|
|
objectType: 'planet',
|
|
objectId: 'p3',
|
|
objectName: 'Kepler-6',
|
|
planets: [{ id: 'p3', name: 'Kepler-6', x: 900, y: 400, radius: 60 }],
|
|
settlements: [],
|
|
});
|
|
s.autopilotTo('patrol:wp:0'); // what the escort used to emit
|
|
assert.deepEqual(s.aim, { x: 120, y: 340 }, 'patrol:wp:0 = the rendezvous point (the old wrong aim)');
|
|
console.log('old id shape still resolves to the rendezvous (documented):', JSON.stringify(s.aim));
|
|
}
|
|
|
|
// --- STALE payload shape (a content RECORD id, as the compass stood before
|
|
// the discoveryId fix — or a pre-update entry in a live session):
|
|
// the autopilot must map it onto the world's discovery entry instead
|
|
// of silently no-oping.
|
|
{
|
|
const s = makeScene({
|
|
objectType: 'planet',
|
|
objectId: 'p3',
|
|
objectName: 'Kepler-6',
|
|
planets: [{ id: 'p3', name: 'Kepler-6', x: 900, y: 400, radius: 60 }],
|
|
settlements: [],
|
|
});
|
|
s.aim = null;
|
|
s.autopilotTo('escort:obj:p3'); // the record id, NOT the discovery name
|
|
assert.deepEqual(s.aim, { x: 858, y: 400 }, 'stale record-id payload still resolves to the planet rim');
|
|
console.log('stale record-id payload: OK — escort:obj:p3 → aim', JSON.stringify(s.aim));
|
|
}
|
|
|
|
console.log('\nall escort compass → autopilot checks passed');
|