Add Galaxy tab legend key and faction tooltips
- Key the lane/region colors and draw the faction rings/capital seat in the GALAXY legend, live from factions.json - Name a hovered star's standing in the tooltip: territory, capital, or wild space - Add a dev screenshot harness to smoke-test the legend and tooltip
This commit is contained in:
parent
32215fa737
commit
608ffb7077
|
|
@ -205,6 +205,13 @@
|
|||
"capitalAlpha": 0.9,
|
||||
"capitalOuter": 2.8
|
||||
},
|
||||
"legend": {
|
||||
"_comment": "The GALAXY tab's legend key (js/ui/MapWindow.js → _buildGalaxyLegend / _paintLegendGalaxy) — two labeled rows in the stats slot: row 1 = the lane states (map.galaxy.edges) + the CHARTED region swatch (map.galaxy.hull); row 2 = the FACTIONS key, drawn LIVE from data/factions.json (a star dot in a ring of each faction's color = its territory, mirroring the plate's ring layer) + the double-ring CAPITAL seat glyph. laneLabels/regionLabel/factionPrefix/capitalLabel = the key's wording (defaults in code). The SYSTEM tab keeps its own glyph key (map.legend.items) in the same slot — each tab overwrites the other's on switch.",
|
||||
"laneLabels": { "used": "TRAVELED", "frontier": "FRONTIER", "unexplored": "UNEXPLORED" },
|
||||
"regionLabel": "CHARTED",
|
||||
"factionPrefix": "FACTIONS",
|
||||
"capitalLabel": "CAPITAL"
|
||||
},
|
||||
"flow": {
|
||||
"_comment": "Flow packets drifting along the TRAVELED lanes — the routes the player flew (the lane's history). size = plate-px; cycleMs = one traversal (a per-lane seeded stagger desyncs them).",
|
||||
"enabled": true,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<base href="../" />
|
||||
<title>Orbit — Galaxy legend (dev shot)</title>
|
||||
<style>
|
||||
html, body { margin: 0; height: 100%; background: #04060d; overflow: hidden; }
|
||||
#game { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
|
||||
</style>
|
||||
<script src="lib/phaser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="game"></div>
|
||||
<script type="module" src="dev/galaxy-legend-shot.mjs"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* Dev-only: boot GameScene, open the MAP console on the GALAXY tab and
|
||||
* verify the legend key + the tooltip's FACTION line:
|
||||
* - win.gLeg built: the lane row (used/frontier/unexplored + region) and
|
||||
* the FACTIONS row drawn from data/factions.json (+ the capital seat)
|
||||
* - the slot's label ownership flips with the tab (gLegTexts up on
|
||||
* GALAXY, legendTexts up back on CURRENT SYSTEM)
|
||||
* - hovering a star names its standing: "<FACTION> TERRITORY" /
|
||||
* "<FACTION> CAPITAL" / "WILD SPACE" in the faction's color
|
||||
* - console errors
|
||||
*
|
||||
* node dev/server.mjs 8083 # static server
|
||||
* node dev/shot-firefox.mjs \
|
||||
* "http://127.0.0.1:8083/dev/galaxy-legend-shot.html" \
|
||||
* "window.__GAL_SHOT ? window.__GAL_SHOT.ready : null" \
|
||||
* GAL_LEGEND_SHOT.png 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 { GameScene } from '../js/scenes/GameScene.js';
|
||||
|
||||
const data = await ConfigLoader.load();
|
||||
config.init(data);
|
||||
|
||||
// Capture console errors + uncaught exceptions for the report.
|
||||
const errors = [];
|
||||
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 gameConfig = createGameConfig();
|
||||
gameConfig.scene = [GameScene];
|
||||
const game = new Phaser.Game(gameConfig);
|
||||
window.game = game;
|
||||
|
||||
// The report lives OUTSIDE the canvas — a DOM <pre> the screenshot can
|
||||
// always read (headless canvases don't have to cooperate).
|
||||
const report = document.createElement('pre');
|
||||
report.id = 'report';
|
||||
report.style.cssText = 'position:fixed;left:10px;top:10px;z-index:9999;max-width:70%;margin:0;padding:8px 12px;font:13px/1.5 monospace;color:#eaf6ff;background:rgba(6,20,16,0.92);border:1px solid #1b3a5a;white-space:pre-wrap;';
|
||||
document.body.appendChild(report);
|
||||
const setReport = (lines) => { report.textContent = (Array.isArray(lines) ? lines : [lines]).join('\n'); };
|
||||
setReport('booting…');
|
||||
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
async function waitScene() {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const s = game.scene.getScene('GameScene');
|
||||
if (s && s.ship && s.mapWindow) return s;
|
||||
await sleep(100);
|
||||
}
|
||||
throw new Error('GameScene never booted');
|
||||
}
|
||||
|
||||
try {
|
||||
const s = await waitScene();
|
||||
await sleep(800); // let the boot settle
|
||||
|
||||
// Open the console (the deck MAP button does exactly this).
|
||||
s.deckAction('map');
|
||||
await sleep(1400); // the boot reveal + first chart paint
|
||||
|
||||
const win = s.mapWindow;
|
||||
|
||||
// ── 1 — the legend key is built (from data/factions.json) ──────────
|
||||
const L = win.gLeg;
|
||||
const legendOk = !!(
|
||||
L &&
|
||||
L.lanes?.length === 3 &&
|
||||
L.lanes.every((it) => it.x >= 0 && it.label) &&
|
||||
L.region?.label === 'CHARTED' &&
|
||||
L.facs?.length >= 1 &&
|
||||
L.facs.every((f) => typeof f.color === 'number' && f.label) &&
|
||||
L.capital?.label === 'CAPITAL'
|
||||
);
|
||||
const factions = config.get('factions.factions', {});
|
||||
const factionNames = Object.values(factions).map((f) => f.label).join(' / ');
|
||||
|
||||
// ── 2 — switch to the GALAXY tab and let the first poll run ────────
|
||||
const gal = win.tabs.find((t) => t.id === 'galaxy');
|
||||
win._tabHit(gal);
|
||||
win._pollNext = 0;
|
||||
await sleep(2600); // the reveal ripple + the poll's stats/legend paint
|
||||
const gv = win._galaxy;
|
||||
const galMode = win._mode === 'galaxy';
|
||||
const textsUp = gv ? win.gLegTexts.filter((t) => t.visible).length : -1;
|
||||
const sysTextsHidden = win.legendTexts.filter((t) => !t.visible).length === win.legendTexts.length;
|
||||
|
||||
// ── 3 — hover a star: the tooltip must name its standing ───────────
|
||||
let hoverLine = 'no stars built';
|
||||
if (gv?.update) {
|
||||
// a faction star first (the interesting case), a capital next, else
|
||||
// any star (wild space)
|
||||
const st =
|
||||
gv._stars.find((x) => x.capital && x.capital !== 'neutral') ??
|
||||
gv._stars.find((x) => x.capital) ??
|
||||
gv._stars.find((x) => x.faction) ??
|
||||
gv._stars[0];
|
||||
if (st) {
|
||||
gv._setHover({ x: st.lx, y: st.ly });
|
||||
gv.update(s.time.now + 16); // one paint pass
|
||||
await sleep(120);
|
||||
const standing = gv._hover === st ? (gv.ttFaction.text || '—') : 'hover missed';
|
||||
hoverLine = `hover ${st.id.toUpperCase()} → "${standing}"${st.capital ? ' [capital]' : st.faction ? ' [territory]' : ' [wild]'}`;
|
||||
}
|
||||
gv._setHover(null);
|
||||
}
|
||||
|
||||
// ── 4 — back to CURRENT SYSTEM: the slot hands back to its key ──────
|
||||
win._tabHit(win.tabs.find((t) => t.id === 'currentSystem'));
|
||||
await sleep(300);
|
||||
const backOk =
|
||||
win._mode === 'currentSystem' &&
|
||||
win.gLegTexts.every((t) => !t.visible) &&
|
||||
win.legendTexts.every((t) => t.visible);
|
||||
|
||||
const lines = [
|
||||
errors.length === 0 ? 'SMOKE OK — no console errors' : `ERRORS:\n${errors.slice(0, 4).join('\n')}`,
|
||||
`mode after galaxy: ${win._mode} · galaxy view=${!!gv}`,
|
||||
`legend: ${legendOk ? 'built ✓' : 'MISSING ✗'} · lanes=${L?.lanes?.length} · region="${L?.region?.label}" · facs=${L?.facs?.map((f) => f.label).join('/')} · capital="${L?.capital?.label}"`,
|
||||
`factions.json: ${factionNames}`,
|
||||
`galaxy slot labels: ${textsUp}/${win.gLegTexts.length} up · system labels hidden=${sysTextsHidden}`,
|
||||
hoverLine,
|
||||
`switch back: ${backOk ? 'slot restored ✓' : '✗'}`,
|
||||
];
|
||||
setReport(lines);
|
||||
window.__GAL_SHOT = { ready: true, lines, errors };
|
||||
console.info('galaxy-legend-shot: report painted');
|
||||
} catch (err) {
|
||||
errors.push(`FATAL: ${err.message}`);
|
||||
setReport(['FATAL: ' + err.message, ...errors.slice(0, 4)]);
|
||||
window.__GAL_SHOT = { ready: true, fatal: String(err.message), errors };
|
||||
console.error('galaxy-legend-shot: fatal', err);
|
||||
}
|
||||
|
|
@ -479,7 +479,12 @@ planets.png frames 18..21 — data/planets.json → capitals; the
|
|||
the reputation seam). The plate's FACTION LAYER (js/ui/GalaxyView.js →
|
||||
`_redrawFactions`, data/map.json → galaxy.factions) rings every
|
||||
territory system in its faction's color and marks the capitals with the
|
||||
double-ring seat. The 'Leaving the Nest' quest rides it: Trestle's last
|
||||
double-ring seat. The GALAXY tab's legend row (data/map.json →
|
||||
galaxy.legend) keys those colors — a star dot in a faction ring = its
|
||||
territory, double ring = the capital seat, drawn live from
|
||||
data/factions.json so a new faction keys itself — and the star tooltip
|
||||
names the hovered system's standing ("APEX TERRITORY" / "WILD SPACE").
|
||||
The 'Leaving the Nest' quest rides it: Trestle's last
|
||||
brief (data/comms.json: trestle-brief-3 — "this star cluster's capital")
|
||||
sets the player's destination to the neutral capital's seat on the
|
||||
acknowledgment (js/comms/CommsHub.js → onEnd, js/scenes/GameScene.js →
|
||||
|
|
|
|||
|
|
@ -34,8 +34,10 @@
|
|||
* • ambient dust + the galaxy's core glow (depth, structure).
|
||||
*
|
||||
* Interaction (the MapWindow plate idiom): WHEEL zoom about the cursor,
|
||||
* DRAG pan, double-tap 1×, HOVER = ring + tooltip (name, type, gate
|
||||
* count, charted state, link state to the current system) — STARS ONLY,
|
||||
* DRAG pan, double-tap 1×, HOVER = ring + tooltip (name, FACTION
|
||||
* standing — territory / capital seat / wild space, map.galaxy's legend
|
||||
* key names the colors), type, gate count, charted state, link state to
|
||||
* the current system) — STARS ONLY,
|
||||
* and only the star ITSELF: the zone is the dot's own scale (a 2px
|
||||
* floor at 1× zoom, growing with it), so the lanes and the open space
|
||||
* between the dots never trigger it (a 5px mouse pad around a 2px dot
|
||||
|
|
@ -275,6 +277,15 @@ export class GalaxyView {
|
|||
letterSpacing: 1.5,
|
||||
})
|
||||
.setScrollFactor(0);
|
||||
this.ttFaction = s
|
||||
.text(0, 0, '', {
|
||||
fontFamily: BODY,
|
||||
fontSize: '9px',
|
||||
color: toCss(C.dim),
|
||||
fontStyle: 'bold',
|
||||
letterSpacing: 2,
|
||||
})
|
||||
.setScrollFactor(0);
|
||||
this.ttHint = s
|
||||
.text(0, 0, '', {
|
||||
fontFamily: BODY,
|
||||
|
|
@ -284,7 +295,7 @@ export class GalaxyView {
|
|||
})
|
||||
.setScrollFactor(0);
|
||||
this.ttCont = new Phaser.GameObjects.Container(this.scene, 0, 0);
|
||||
this.ttCont.add([this.ttPlate, this.ttName, this.ttSub, this.ttHint]);
|
||||
this.ttCont.add([this.ttPlate, this.ttName, this.ttFaction, this.ttSub, this.ttHint]);
|
||||
this.ttCont.setVisible(false).setDepth(1.8);
|
||||
win.add(this.ttCont);
|
||||
|
||||
|
|
@ -1256,8 +1267,34 @@ export class GalaxyView {
|
|||
this.ttHint.setText(hint);
|
||||
this.ttHint.setColor(toCss(hintColor));
|
||||
|
||||
const ttW = Math.max(this.ttName.width, this.ttSub.width, this.ttHint.width) + 26;
|
||||
const ttH = 46;
|
||||
// the FACTION line — what the ring around THIS star means, just in
|
||||
// time (the legend row keys the colors, the tooltip names this one):
|
||||
// the faction's territory, its CAPITAL seat, or WILD SPACE (the
|
||||
// neutral ring right outside home + the branch tips). Hidden while
|
||||
// the faction layer is off (no rings on the plate to explain).
|
||||
const fcfg = this._cfg.factions ?? {};
|
||||
const factions = config.get('factions.factions', {});
|
||||
let factionStr = null;
|
||||
let factionColor = C.dim;
|
||||
if (fcfg.enabled !== false) {
|
||||
if (st.capital) {
|
||||
const f = factions?.[st.capital] ?? {};
|
||||
factionStr = `${String(f.label ?? st.capital).toUpperCase()} CAPITAL`;
|
||||
factionColor = toColor(f.color ?? 0xb9c4d6);
|
||||
} else if (st.faction) {
|
||||
const f = factions?.[st.faction] ?? {};
|
||||
factionStr = `${String(f.label ?? st.faction).toUpperCase()} TERRITORY`;
|
||||
factionColor = toColor(f.color ?? 0xb9c4d6);
|
||||
} else {
|
||||
factionStr = 'WILD SPACE';
|
||||
factionColor = toColor(factions?.neutral?.color ?? 0xb9c4d6);
|
||||
}
|
||||
this.ttFaction.setText(factionStr);
|
||||
this.ttFaction.setColor(toCss(factionColor));
|
||||
}
|
||||
const hasFaction = !!factionStr;
|
||||
const ttW = Math.max(this.ttName.width, this.ttFaction.width, this.ttSub.width, this.ttHint.width) + 26;
|
||||
const ttH = hasFaction ? 58 : 46;
|
||||
let tx = st.lx;
|
||||
let ty = st.ly - r - 12;
|
||||
tx = Phaser.Math.Clamp(tx, this.px + ttW / 2 + 6, this.px + this.pw - ttW / 2 - 6);
|
||||
|
|
@ -1270,9 +1307,13 @@ export class GalaxyView {
|
|||
this.ttPlate.strokeRoundedRect(tx - ttW / 2, ty - ttH, ttW, ttH, 4);
|
||||
this.ttName.setPosition(tx, ty - ttH + 9);
|
||||
this.ttName.setOrigin(0.5, 0);
|
||||
this.ttSub.setPosition(tx, ty - ttH + 25);
|
||||
if (hasFaction) {
|
||||
this.ttFaction.setPosition(tx, ty - ttH + 25);
|
||||
this.ttFaction.setOrigin(0.5, 0);
|
||||
}
|
||||
this.ttSub.setPosition(tx, ty - ttH + (hasFaction ? 37 : 25));
|
||||
this.ttSub.setOrigin(0.5, 0);
|
||||
this.ttHint.setPosition(tx, ty - ttH + 36);
|
||||
this.ttHint.setPosition(tx, ty - ttH + (hasFaction ? 48 : 36));
|
||||
this.ttHint.setOrigin(0.5, 0);
|
||||
this.ttCont.setVisible(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1434,6 +1434,7 @@ export class MapWindow extends Phaser.GameObjects.Container {
|
|||
// legitimate sits under the plate to show through.
|
||||
this.mapImg.setAlpha(1);
|
||||
this.legendTexts?.forEach((t) => t.setVisible(true));
|
||||
this.gLegTexts?.forEach((t) => t.setVisible(false));
|
||||
this.navLabel.setText(this._navLabel0);
|
||||
this.resLabel.setText(this._resLabel0);
|
||||
this.navMetaTxt?.setVisible(true);
|
||||
|
|
@ -1522,35 +1523,146 @@ export class MapWindow extends Phaser.GameObjects.Container {
|
|||
this._drawBar(this.statsG, this.resBarY, st.lanes ?? 0, frontier, toColor(C.amber));
|
||||
}
|
||||
|
||||
/** The GALAXY tab's legend — the three lane states + the region swatch. */
|
||||
/** The GALAXY tab's legend key — two labeled rows in the stats slot
|
||||
* (the SYSTEM tab's glyph key, map.legend.items, overwrites this one
|
||||
* on switch back — the same legendG slot, see _switchMode):
|
||||
* row 1 — the lane states (map.galaxy.edges) + the CHARTED region
|
||||
* swatch (map.galaxy.hull): TRAVELED / FRONTIER /
|
||||
* UNEXPLORED / CHARTED
|
||||
* row 2 — the FACTIONS key, drawn live from data/factions.json:
|
||||
* a star dot ringed in each faction's color (its territory —
|
||||
* mirroring the plate's ring layer) + the double-ring
|
||||
* CAPITAL seat glyph. Wording: map.galaxy.legend.
|
||||
*/
|
||||
_paintLegendGalaxy() {
|
||||
const { statsX, statsY, statsH } = this.geo;
|
||||
const legY = statsY + statsH - 16;
|
||||
const L = this.gLeg;
|
||||
const g = this.legendG;
|
||||
g.clear();
|
||||
let x = statsX + 14;
|
||||
const drawRow = (o) => {
|
||||
if (!o.color) return;
|
||||
if (!L) return;
|
||||
// the slot's labels: this tab's up, the system tab's down
|
||||
this.gLegTexts?.forEach((t) => t.setVisible(true));
|
||||
this.legendTexts?.forEach((t) => t.setVisible(false));
|
||||
// row 1 — the lanes (each swatch is the lane's own config, as on the
|
||||
// plate) + the charted-region fill
|
||||
for (const key of ['used', 'frontier', 'unexplored']) {
|
||||
const o = config.get(`map.galaxy.edges.${key}`, {});
|
||||
const e = L.lanes?.find((it) => it.key === key);
|
||||
if (!o.color || !e) continue;
|
||||
const c = toColor(o.color);
|
||||
const w = o.width ?? 1;
|
||||
const a = o.alpha ?? 0.5;
|
||||
g.lineStyle(w + 4, c, a * 0.15);
|
||||
g.lineBetween(x, legY + 4, x + 12, legY + 4);
|
||||
g.lineBetween(e.x, L.laneY + 4, e.x + 12, L.laneY + 4);
|
||||
g.lineStyle(Math.max(0.8, w), c, a);
|
||||
g.lineBetween(x, legY + 4, x + 12, legY + 4);
|
||||
x += 40;
|
||||
};
|
||||
drawRow(config.get('map.galaxy.edges.used', {}));
|
||||
drawRow(config.get('map.galaxy.edges.frontier', {}));
|
||||
drawRow(config.get('map.galaxy.edges.unexplored', {}));
|
||||
g.lineBetween(e.x, L.laneY + 4, e.x + 12, L.laneY + 4);
|
||||
}
|
||||
const hull = config.get('map.galaxy.hull', {});
|
||||
if (hull.color) {
|
||||
if (hull.color && L.region) {
|
||||
const c = toColor(hull.color);
|
||||
g.fillStyle(c, Math.min(1, (hull.fillAlpha ?? 0.055) * 4));
|
||||
g.fillRoundedRect(x, legY - 2, 12, 12, 2);
|
||||
g.fillRoundedRect(L.region.x, L.laneY - 2, 12, 12, 2);
|
||||
g.lineStyle(1, c, Math.min(1, (hull.outlineAlpha ?? 0.28) * 2.2));
|
||||
g.strokeRoundedRect(x, legY - 2, 12, 12, 2);
|
||||
g.strokeRoundedRect(L.region.x, L.laneY - 2, 12, 12, 2);
|
||||
}
|
||||
// row 2 — the FACTIONS key (data/factions.json) + the capital's seat
|
||||
const dotC = toColor(C.dim);
|
||||
for (const f of L.facs ?? []) {
|
||||
const cx = f.x + 7;
|
||||
const cy = L.facY + 4;
|
||||
g.fillStyle(dotC, 0.9); // the star's dot (its own color varies by type)
|
||||
g.fillCircle(cx, cy, 2.2);
|
||||
g.lineStyle(1.3, f.color, 0.9); // the territory ring, as on the plate
|
||||
g.strokeCircle(cx, cy, 5.5);
|
||||
}
|
||||
if (L.capital) {
|
||||
const cx = L.capital.x + 7;
|
||||
const cy = L.facY + 4;
|
||||
g.fillStyle(dotC, 0.9);
|
||||
g.fillCircle(cx, cy, 2.2);
|
||||
// the double-ring seat — the plate's capital mark, faction-neutral
|
||||
g.lineStyle(1.4, toColor(C.dim), 0.95);
|
||||
g.strokeCircle(cx, cy, 4.4);
|
||||
g.lineStyle(1, toColor(C.dim), 0.5);
|
||||
g.strokeCircle(cx, cy, 6.3);
|
||||
}
|
||||
}
|
||||
|
||||
/** Build the GALAXY legend's labels once (they are config-static; the
|
||||
* glyphs are redrawn by _paintLegendGalaxy whenever the tab owns the
|
||||
* slot). The texts start hidden — the SYSTEM tab's glyph key
|
||||
* (legendTexts) owns the slot until the player switches over. */
|
||||
_buildGalaxyLegend() {
|
||||
const { statsX, statsY, statsW, statsH } = this.geo;
|
||||
const s = this.scene.add;
|
||||
const lc = config.get('map.galaxy.legend', {});
|
||||
const x0 = statsX + 14;
|
||||
const legY = statsY + statsH - 16;
|
||||
this.gLegTexts = [];
|
||||
const probe = s.text(0, 0, '', { fontFamily: BODY, fontSize: '9px', color: toCss(C.faint), letterSpacing: 1.5 });
|
||||
this.add(probe);
|
||||
const tw = (str) => {
|
||||
probe.setText(str);
|
||||
return probe.width;
|
||||
};
|
||||
const mk = (x, y, str, color) => {
|
||||
const t = s
|
||||
.text(x, y, str, {
|
||||
fontFamily: BODY,
|
||||
fontSize: '9px',
|
||||
color: toCss(color),
|
||||
letterSpacing: 1.5,
|
||||
})
|
||||
.setScrollFactor(0)
|
||||
.setDepth(2);
|
||||
t.setVisible(false); // the GALAXY tab claims the slot on switch
|
||||
this.add(t);
|
||||
this.gLegTexts.push(t);
|
||||
return t;
|
||||
};
|
||||
const L = (this.gLeg = { laneY: legY - 18, facY: legY, lanes: [], facs: [] });
|
||||
|
||||
// row 1 — the lane states + the charted region
|
||||
let x = x0;
|
||||
const laneItem = (key, fb) => {
|
||||
const label = String((lc.laneLabels ?? {})[key] ?? fb).toUpperCase();
|
||||
L.lanes.push({ key, x, label });
|
||||
mk(x + 17, L.laneY, label, C.faint);
|
||||
x += 17 + tw(label) + 16;
|
||||
};
|
||||
laneItem('used', 'TRAVELED');
|
||||
laneItem('frontier', 'FRONTIER');
|
||||
laneItem('unexplored', 'UNEXPLORED');
|
||||
L.region = { x, label: String(lc.regionLabel ?? 'CHARTED').toUpperCase() };
|
||||
mk(x + 17, L.laneY, L.region.label, C.faint);
|
||||
|
||||
// row 2 — the FACTIONS key (data/factions.json — a new faction keys
|
||||
// itself automatically) + the capital's double-ring seat. The row is
|
||||
// measured first; on a narrow window the prefix drops so the names
|
||||
// (the point of the key) always fit.
|
||||
const prefix = String(lc.factionPrefix ?? 'FACTIONS').toUpperCase();
|
||||
const capitalLabel = String(lc.capitalLabel ?? 'CAPITAL').toUpperCase();
|
||||
const facs = Object.entries(config.get('factions.factions', {})).map(([id, f]) => ({
|
||||
color: toColor(f?.color ?? 0xb9c4d6),
|
||||
label: String(f?.label ?? id).toUpperCase(),
|
||||
}));
|
||||
const row2W = (withPrefix) => {
|
||||
let w = withPrefix ? tw(prefix) + 20 : 0;
|
||||
for (const f of facs) w += 19 + tw(f.label) + 16;
|
||||
return w + 19 + tw(capitalLabel);
|
||||
};
|
||||
let fx = x0;
|
||||
if (row2W(true) <= statsW - 28) {
|
||||
mk(fx, L.facY, prefix, C.dim);
|
||||
fx += tw(prefix) + 20;
|
||||
}
|
||||
for (const f of facs) {
|
||||
L.facs.push({ x: fx, color: f.color, label: f.label });
|
||||
mk(fx + 19, L.facY, f.label, C.faint);
|
||||
fx += 19 + tw(f.label) + 16;
|
||||
}
|
||||
L.capital = { x: fx, label: capitalLabel };
|
||||
mk(fx + 19, L.facY, capitalLabel, C.faint);
|
||||
probe.setVisible(false);
|
||||
}
|
||||
|
||||
/** The GALAXY tab's status strip (under the feed). */
|
||||
|
|
@ -1944,6 +2056,10 @@ export class MapWindow extends Phaser.GameObjects.Container {
|
|||
}
|
||||
probe.setVisible(false);
|
||||
this._paintLegend();
|
||||
// the GALAXY tab's legend key (two labeled rows — lanes + the
|
||||
// FACTIONS key from data/factions.json), built once, hidden until the
|
||||
// tab claims the slot (_paintLegendGalaxy)
|
||||
this._buildGalaxyLegend();
|
||||
}
|
||||
|
||||
/** Re-draw the SYSTEM tab's legend glyphs (the glyph key under the
|
||||
|
|
@ -2454,6 +2570,7 @@ export class MapWindow extends Phaser.GameObjects.Container {
|
|||
this._paintLegendGalaxy();
|
||||
this._paintStatusStripGalaxy(snap);
|
||||
this.legendTexts?.forEach((t) => t.setVisible(false));
|
||||
this.gLegTexts?.forEach((t) => t.setVisible(true));
|
||||
this.navMetaTxt?.setVisible(false);
|
||||
this.resMetaTxt?.setVisible(false);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue