133 lines
5.8 KiB
JavaScript
133 lines
5.8 KiB
JavaScript
/**
|
|
* Visual probe for a screenshot + numeric overlap report (headless brave,
|
|
* via dev/cdp-shot.mjs): boots the game, lands, opens the shop, opens the
|
|
* trade scout on a BUY row that has remote exits, and STOPS THERE (the
|
|
* scout panel is the shot's subject — no exit tapped, no dialog). It
|
|
* measures every text box in the panel (local coords) and reports any
|
|
* pairs whose bounds intersect, so text overlap is verifiable numerically
|
|
* and visually.
|
|
*
|
|
* /opt/brave.com/brave/brave --headless --disable-gpu --remote-debugging-port=9333 about:blank &
|
|
* python3 -m http.server 8129
|
|
* node dev/cdp-shot.mjs http://127.0.0.1:8129/dev/scout-overlap.html \
|
|
* /tmp/scout-overlap.png 'window.__SCOUT_OVERLAP__ && 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';
|
|
|
|
// A fixed galaxy seed (GameScene.ensureGalaxy honors it) so before/after
|
|
// runs of this probe compare the SAME system names / world names.
|
|
globalThis.__ORBIT_DEV_SEED = 'scout-overlap-probe';
|
|
|
|
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.__SCOUT_OVERLAP__ = { pass: false, 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.__SCOUT_OVERLAP__ = { pass: false, 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.__SCOUT_OVERLAP__ = { pass: false, error: 'no shopView' }; return; }
|
|
sv.setTab('trade');
|
|
await sleep(900); // the slide-in
|
|
|
|
// Open the scout on a BUY row that has a REMOTE profitable exit — the
|
|
// fullest panel state (chips + 3 exit rows). Do NOT tap an exit row.
|
|
const visited = [...gs.visitedSystems];
|
|
let row = null, exits = null;
|
|
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) { row = r; exits = d.exits; break; }
|
|
}
|
|
if (!row || !exits) { window.__SCOUT_OVERLAP__ = { pass: false, error: 'no remote exit to open' }; return; }
|
|
|
|
sv._onRowTap(row);
|
|
await sleep(400);
|
|
const panel = sv._scout;
|
|
if (!panel) { window.__SCOUT_OVERLAP__ = { pass: false, error: 'no scout panel' }; return; }
|
|
|
|
// Collect every text box in the panel (container-local coords). In this
|
|
// Giedi build the panel's own `_content` array is the flat list of
|
|
// per-show objects (text/graphics/chips). Convert origin-anchored x/y to
|
|
// the true top-left (left = x - origin.x*width) so right-/center-aligned
|
|
// text (price, profit, footer) measures correctly.
|
|
const texts = [];
|
|
const isText = (o) => o && o.text != null && typeof o.width === 'number';
|
|
const take = (o) => {
|
|
if (isText(o)) {
|
|
const ox = o.originX ?? o.origin?.x ?? 0, oy = o.originY ?? o.origin?.y ?? 0;
|
|
texts.push({
|
|
text: String(o.text).slice(0, 60),
|
|
left: Math.round(o.x - ox * o.width), top: Math.round(o.y - oy * o.height),
|
|
w: Math.round(o.width), h: Math.round(o.height),
|
|
});
|
|
}
|
|
else for (const c of o?.list ?? o?.children?.list ?? []) take(c); // containers (chips)
|
|
};
|
|
for (const o of panel._content ?? []) take(o);
|
|
texts.sort((a, b) => (a.top - b.top) || (a.left - b.left));
|
|
|
|
// Pairwise overlap of the true text boxes (ignore sub-pixel kissing).
|
|
const overlaps = [];
|
|
for (let i = 0; i < texts.length; i++) {
|
|
for (let j = i + 1; j < texts.length; j++) {
|
|
const a = texts[i], b = texts[j];
|
|
const ix = Math.min(a.left + a.w, b.left + b.w) - Math.max(a.left, b.left);
|
|
const iy = Math.min(a.top + a.h, b.top + b.h) - Math.max(a.top, b.top);
|
|
if (ix > 2 && iy > 2) overlaps.push({ a: a.text, b: b.text, ix: Math.round(ix), iy: Math.round(iy) });
|
|
}
|
|
}
|
|
|
|
window.__SCOUT_OVERLAP__ = {
|
|
pass: overlaps.length === 0,
|
|
panel: { width: panel.width, height: panel.height, rows: panel._exitRows?.length },
|
|
good: row?.id,
|
|
exits: exits.map((e) => ({ sys: e.systemName, world: e.objectName, cls: e.cls, price: e.price, profit: e.profit, hops: e.hops })),
|
|
texts,
|
|
overlaps,
|
|
};
|
|
console.info('[scout-overlap] texts=' + texts.length + ' overlaps=' + overlaps.length);
|
|
})().catch((err) => { window.__SCOUT_OVERLAP__ = { pass: false, error: String(err && err.message || err) }; });
|