109 lines
4.4 KiB
JavaScript
109 lines
4.4 KiB
JavaScript
/**
|
|
* Dev-only: TETHER-L2 BUILD FLOW — plays the real flow end-to-end
|
|
* (menu → NEW GAME → land on the home world → build Tether - Level 2 →
|
|
* the build completes) and reports what the tether field does with it:
|
|
*
|
|
* before: home tether id/level/radius
|
|
* build: beginBuild() result (ok / refusal reason)
|
|
* after : home tether id/level/radius, tetherLevelFor(home),
|
|
* the surface HUD's cached level, built records
|
|
*
|
|
* node dev/server.mjs 8080
|
|
* node dev/cdp-firefox.mjs http://127.0.0.1:8080/dev/tether-flow.html \
|
|
* 'return window.__TETHER_FLOW__;' 40000
|
|
*/
|
|
import Phaser from '../js/vendor/phaser.js';
|
|
import { config } from '../js/config/Config.js';
|
|
import { ConfigLoader } from '../js/config/ConfigLoader.js';
|
|
import { createGameConfig } from '../js/config/GameConfig.js';
|
|
import { MenuScene } from '../js/scenes/MenuScene.js';
|
|
import { GameScene } from '../js/scenes/GameScene.js';
|
|
import { SurfaceScene } from '../js/scenes/SurfaceScene.js';
|
|
|
|
const data = await ConfigLoader.load();
|
|
config.init(data);
|
|
|
|
const errors = [];
|
|
const origWarn = console.warn.bind(console);
|
|
console.warn = (...a) => { errors.push(a.map(String).join(' ')); origWarn(...a); };
|
|
const origErr = console.error.bind(console);
|
|
console.error = (...a) => { errors.push(a.map(String).join(' ')); origErr(...a); };
|
|
window.addEventListener('error', (e) => errors.push(String(e.message)));
|
|
window.addEventListener('unhandledrejection', (e) => errors.push(`rejection: ${e.reason}`));
|
|
|
|
const game = new Phaser.Game({ ...createGameConfig(), scene: [MenuScene, GameScene, SurfaceScene] });
|
|
window.game = game;
|
|
|
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
async function waitFor(fn, tries = 200, everyMs = 100) {
|
|
for (let i = 0; i < tries; i++) {
|
|
const v = fn();
|
|
if (v) return v;
|
|
await sleep(everyMs);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const tetherInfo = (gs) => {
|
|
const home = gs.planet?.discoveryName;
|
|
const t = gs.tetherField?.tethers?.find(
|
|
(tt) => tt.label === home || (tt.x === 0 && tt.y === 0),
|
|
);
|
|
return t ? { id: t.id, x: t.x, y: t.y, level: t.level, radius: t.radius } : null;
|
|
};
|
|
|
|
try {
|
|
// 1) Menu → NEW GAME (the real entry).
|
|
const menu = await waitFor(() => game.scene.getScene('MenuScene')?.newGameBtn ? game.scene.getScene('MenuScene') : null);
|
|
if (!menu) throw new Error('menu never booted');
|
|
menu.startNewGame();
|
|
const gs = await waitFor(() => { const g = game.scene.getScene('GameScene'); return g?.ship && g?.buildState && g?.tetherField ? g : null; }, 300);
|
|
if (!gs) throw new Error('GameScene never booted');
|
|
await sleep(500);
|
|
const home = gs.planet.discoveryName;
|
|
const before = tetherInfo(gs);
|
|
const beforeLevel = gs.tetherLevelFor(home);
|
|
|
|
// 2) Research is done (the build's only research gate).
|
|
gs.researchState.unlock('exploration', 'tether_l2');
|
|
|
|
// 3) Land on the home world the game's own way, wait for the surface
|
|
// stage (the stall guard advances after ~5 s without a clip).
|
|
gs.startLanding(gs.commsTargetFor(gs.planet));
|
|
const ss = await waitFor(() => { const c = game.scene.getScene('SurfaceScene'); return c?.phase === 'surface' ? c : null; }, 150, 200);
|
|
if (!ss) throw new Error('surface stage never reached');
|
|
await sleep(300);
|
|
|
|
// 4) Start the Tether - Level 2 build (the scene-side rules apply).
|
|
// The cost (200 minerals) is covered — a fresh ship holds none.
|
|
gs.ship.setMinerals(200);
|
|
const res = gs.beginBuild(ss.planetName, 'tether-l2', game.loop.now);
|
|
const active = gs.buildState.getActive();
|
|
|
|
// 5) Fast-forward the build to completion (the test does not wait out
|
|
// the 20 s), then let the surface's own tick apply the effects.
|
|
if (active) active.startedAt -= active.durationMs;
|
|
// …and let the HUD line finish re-decoding to the new level.
|
|
await sleep(2500);
|
|
|
|
const after = tetherInfo(gs);
|
|
const out = {
|
|
home,
|
|
before,
|
|
beforeLevel,
|
|
build: { res, active: active ?? null },
|
|
after,
|
|
afterLevel: gs.tetherLevelFor(home),
|
|
hudLevel: ss.tetherLevel,
|
|
hudLine: ss.hudLine ? ss.hudLine.text : null,
|
|
built: gs.buildState.isBuilt(ss.planetName, 'tether-l2'),
|
|
arcs: after ? gs.tetherField._arcs.get(after.id).length : null,
|
|
errors: errors.slice(0, 5),
|
|
};
|
|
window.__TETHER_FLOW__ = out;
|
|
console.info('tether-flow:', JSON.stringify(out));
|
|
} catch (err) {
|
|
window.__TETHER_FLOW__ = { fatal: String(err.message), errors: errors.slice(0, 5) };
|
|
console.error('tether-flow: fatal', err);
|
|
}
|