orbit/dev/scout-dest-shot.mjs

102 lines
4.3 KiB
JavaScript

/**
* Visual probe for a screenshot (headless brave, via dev/cdp-shot.mjs):
* boots the game, lands, opens the shop, opens the trade scout on a BUY
* row, and taps a REMOTE best-exit row — the "SET DESTINATION" popup sits
* open over the shop screen (the shot's subject). The exit rows are
* tappable (hand cursor) and the section label carries the hint.
*
* /opt/brave.com/brave/brave --headless --disable-gpu --remote-debugging-port=9333 about:blank &
* python3 -m http.server 8128
* node dev/cdp-shot.mjs http://127.0.0.1:8128/dev/scout-dest-shot.html \
* /tmp/scout-dest.png 'window.__SHOT_READY__ && true' 90000
*/
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';
import { scoutGood } from '../js/economy/TradeScout.js';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const data = await ConfigLoader.load();
config.init(data);
const gameConfig = createGameConfig();
gameConfig.scene = [GameScene, SurfaceScene];
const game = new Phaser.Game(gameConfig);
window.game = game;
(async () => {
let gs = null;
for (let i = 0; i < 300; i++) {
gs = game.scene?.getScene('GameScene') ?? null;
if (gs && gs.ship) break;
await sleep(100);
}
if (!gs || !gs.ship) { window.__SHOT_READY__ = { error: 'no GameScene' }; return; }
// The probe drives the trade panel on the home world — lift the TRADE gate
// (the 'Special Delivery' capital-landing witness) so Buy/Sell is live.
gs.story.capitalLanded = true;
// A known ledger + cargo (something to sell), and the run has ENTERED
// every system — the scout then has remote exits to offer.
const goods = config.get('goods.goods', []);
gs.ship.credits = 10000;
gs.ship.cargo.add([goods[0].id]);
const sysId = gs.systemRecord.id;
for (const id of gs.galaxy.byId.keys()) gs.visitedSystems.add(id);
gs.startLanding(gs.commsTargetFor(gs.planet));
await sleep(300);
const ss = game.scene.getScene('SurfaceScene');
if (!ss) { window.__SHOT_READY__ = { error: 'no SurfaceScene' }; return; }
for (let i = 0; i < 120 && ss.sys.getStatus() !== 5; i++) await sleep(250);
ss.startSurface();
for (let i = 0; i < 40 && ss.phase !== 'surface'; i++) await sleep(100);
await sleep(900); // the planet HUD decode
ss.toggleShop();
await sleep(200);
if (!ss.shopView) ss.buildShopView();
const sv = ss.shopView;
if (!sv) { window.__SHOT_READY__ = { error: 'no shopView' }; return; }
sv.setTab('trade');
await sleep(900); // the slide-in
// Pick a BUY row with a REMOTE profitable exit, open its scout, and tap
// that exit row — the SET DESTINATION popup opens and STAYS open (the
// shot's subject).
const visited = [...gs.visitedSystems];
let row = null, exit = null, best = -Infinity;
for (const r of sv.buyList.rows) {
const d = scoutGood(r.id, { galaxy: gs.galaxy, systemId: sysId, cls: sv.cls, buyUnit: r.price, visited, topN: 3 });
if (!d) continue;
const rem = d.exits.find((e) => e.systemId !== sysId && e.profit > 0);
if (rem && rem.profit > best) { row = r; exit = rem; best = rem.profit; }
}
if (!row || !exit) { window.__SHOT_READY__ = { error: 'no remote exit to offer' }; return; }
sv._onRowTap(row);
await sleep(300);
const i = sv._scout._exitRows.findIndex((x) => x.exit.systemId === exit.systemId);
if (i < 0) { window.__SHOT_READY__ = { error: 'no exit row for the picked exit' }; return; }
sv._scout._exitRows[i].onTap({ stopPropagation() {} });
// Wait for the open animation to land (title decoded, buttons up).
const dlg = ss._setDestDialog;
if (!dlg) { window.__SHOT_READY__ = { error: 'no dialog' }; return; }
const t0 = Date.now();
while (dlg.state !== 'shown' && Date.now() - t0 < 5000) await sleep(50);
await sleep(700); // the title decode + button flicker settle
window.__SHOT_READY__ = {
state: dlg.state,
title: dlg.title.text,
body: dlg.bodyTexts.map((t) => t.text),
exit: { systemId: exit.systemId, systemName: exit.systemName, price: exit.price, profit: exit.profit },
hops: ss._setDest?.hops,
};
})().catch((err) => { window.__SHOT_READY__ = { error: String(err && err.message || err) }; });