87 lines
3.7 KiB
JavaScript
87 lines
3.7 KiB
JavaScript
/**
|
||
* Dev-only: the quest tracker's READY state (the "A + C" attract), shot live.
|
||
*
|
||
* Boots the GameScene (deterministic seed), waits for the open dossier to
|
||
* auto-fold (the tracker slides in), then completes the starter quest all
|
||
* at once — the flip fires the one-shot moment (flash + ◆ burst) and the
|
||
* same-frame repaint goes READY (amber row). `window.__QUEST_READY__` is
|
||
* set the instant the burst is still alive, so the capture lands on it:
|
||
*
|
||
* node dev/server.mjs 8080
|
||
* node dev/shot-firefox.mjs http://localhost:8080/dev/quest-ready.html \
|
||
* "window.__QUEST_READY__" /tmp/quest-ready.png 45000
|
||
*/
|
||
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 { GameScene } from '../js/scenes/GameScene.js';
|
||
import { SurfaceScene } from '../js/scenes/SurfaceScene.js';
|
||
|
||
const data = await ConfigLoader.load();
|
||
config.init(data);
|
||
const gameConfig = createGameConfig();
|
||
globalThis.__ORBIT_DEV_SEED = '7'; // deterministic galaxy — reproducible shots
|
||
|
||
// Dev: surface console errors on the flag (a shot with a READY row AND a
|
||
// console error is a regression, even if the shot looks fine).
|
||
const __errors = [];
|
||
if (typeof window !== 'undefined') {
|
||
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)));
|
||
}
|
||
|
||
gameConfig.scene = [GameScene, SurfaceScene];
|
||
const game = new Phaser.Game(gameConfig);
|
||
window.game = game;
|
||
|
||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||
const until = async (fn, ms = 30000) => {
|
||
const t0 = Date.now();
|
||
for (;;) {
|
||
const v = fn();
|
||
if (v) return v;
|
||
if (Date.now() - t0 > ms) return null;
|
||
await sleep(200);
|
||
}
|
||
};
|
||
|
||
setTimeout(async () => {
|
||
try {
|
||
const s = await until(() => (game.scene.getScene('GameScene')?.questTracker ? game.scene.getScene('GameScene') : null));
|
||
if (!s) { window.__QUEST_READY__ = { error: 'scene never became ready' }; return; }
|
||
|
||
// Wait for the open dossier to auto-fold → the tracker slides in
|
||
// (the tracker's first poll establishes its READY baseline while the
|
||
// quest is still open, so the flip below is a true transition).
|
||
await until(() => s.questTracker.shown === true);
|
||
await sleep(250); // let the slide fully settle
|
||
|
||
// Complete the starter quest (all four checks), live — the flip:
|
||
s.totalMined = 200;
|
||
s.researchState.isUnlocked = (cat, node) => true;
|
||
s.tetherLevelFor = (name) => 2;
|
||
s.discoveredWorldCount = () => 1;
|
||
s._questRefresh(); // toast + chime + tracker repaint (the same frame)
|
||
await sleep(380); // inside the burst's life (700–1000 ms) — catch the glyphs
|
||
|
||
const snap = s.questSnapshot();
|
||
const q = snap.quests.find((x) => x.id === 'start_your_journey');
|
||
window.__QUEST_READY__ = {
|
||
trackerShown: s.questTracker.shown,
|
||
questComplete: q?.complete === true,
|
||
questClaimed: q?.claimed === true,
|
||
baselineHasStarter: s.questTracker._readyBaseline?.has('start_your_journey') === true,
|
||
errors: __errors.slice(0, 3),
|
||
};
|
||
// This geckodriver can't read the flag back (execute/sync → null), so
|
||
// paint the verdict on the canvas too — the screenshot IS the readout.
|
||
s.add.text(16, 690, `READY-FLAG ${JSON.stringify(window.__QUEST_READY__)}`,
|
||
{ fontFamily: 'monospace', fontSize: '11px', color: '#7ce8a4', align: 'left' })
|
||
.setOrigin(0, 1).setScrollFactor(0).setDepth(9000);
|
||
} catch (err) {
|
||
window.__QUEST_READY__ = { error: String(err?.stack ?? err) };
|
||
}
|
||
}, 400);
|