104 lines
4.1 KiB
JavaScript
104 lines
4.1 KiB
JavaScript
// Master of Vega — the "New Turn" popup. Lists everything notable that
|
|
// happened since the player's last turn (VegaTurnReport.js classifies and
|
|
// writes the text); click a row to expand its synopsis in place.
|
|
//
|
|
// Lives outside VegaScreens.js because it needs VegaColonyView.js's
|
|
// scrollColumn — importing that back into VegaScreens.js (which every other
|
|
// screen file, including VegaColonyView.js itself, imports chrome FROM)
|
|
// would make the two files import each other. Same one-way-dependency shape
|
|
// as VegaSystemView.js, which already imports from both.
|
|
|
|
import { modalShell, FONT } from './VegaScreens.js';
|
|
import { scrollColumn } from './VegaColonyView.js';
|
|
import { turnToYear } from './VegaRules.js';
|
|
import { Button } from '../../ui/Button.js';
|
|
import { describeEvent, categoryWeight } from './VegaTurnReport.js';
|
|
|
|
const ACCENT = 0x6fc4ff;
|
|
const ROW_BG = 0x142238;
|
|
|
|
export function openTurnReportScreen(scene, rules, state, events, onClose) {
|
|
const shell = modalShell(scene, `New Turn: ${turnToYear(state.turn)}`, onClose, { width: 1180, height: 760 });
|
|
|
|
const ordered = events
|
|
.map((ev, i) => ({ ev, i, desc: describeEvent(rules, state, ev) }))
|
|
.sort((a, b) => categoryWeight(a.ev) - categoryWeight(b.ev) || a.i - b.i);
|
|
|
|
const listH = shell.body.h - 56;
|
|
const col = scrollColumn(scene, shell.layer, shell.body.x, shell.body.y, shell.body.w, listH);
|
|
const w = shell.body.w;
|
|
// Everything starts expanded — the player came here to read the news, not
|
|
// to hunt for it — but each row stays individually collapsible.
|
|
const expanded = new Set(ordered.map((o) => o.i));
|
|
|
|
const render = () => {
|
|
col.content.removeAll(true);
|
|
let cy = 0;
|
|
for (const { i, desc } of ordered) {
|
|
const rowTop = cy;
|
|
const isOpen = expanded.has(i);
|
|
// bg has to be built AFTER the row's text so its final height is known
|
|
// — Rectangle Shapes in this Phaser build don't tolerate a post-construction
|
|
// .setSize() (throws inside Phaser's own setSize). So it's built last and
|
|
// inserted at this index, which puts it behind this row's text instead
|
|
// of on top of it.
|
|
const bgIndex = col.content.length;
|
|
|
|
const tag = scene.add.text(0, cy, desc.category.toUpperCase(), {
|
|
fontFamily: FONT, fontSize: '13px', color: '#7fb8e8',
|
|
});
|
|
col.content.add(tag);
|
|
const chevron = scene.add.text(w - 20, cy, isOpen ? '▾' : '▸', {
|
|
fontFamily: FONT, fontSize: '16px', color: '#7f97b3',
|
|
});
|
|
col.content.add(chevron);
|
|
cy += tag.height + 4;
|
|
|
|
const headline = scene.add.text(0, cy, desc.headline, {
|
|
fontFamily: FONT, fontSize: '19px', color: '#e8f4ff', wordWrap: { width: w - 30 },
|
|
});
|
|
col.content.add(headline);
|
|
cy += headline.height + 10;
|
|
|
|
if (isOpen) {
|
|
for (const ln of desc.lines) {
|
|
const t = scene.add.text(16, cy, ln.text, {
|
|
fontFamily: FONT, fontSize: '15px', color: ln.color ?? '#9fb6cc', wordWrap: { width: w - 46 },
|
|
});
|
|
col.content.add(t);
|
|
cy += t.height + 6;
|
|
}
|
|
cy += 4;
|
|
}
|
|
|
|
const bg = scene.add.rectangle(0, rowTop, w, cy - rowTop, ROW_BG, 0).setOrigin(0, 0)
|
|
.setInteractive({ useHandCursor: true });
|
|
col.content.addAt(bg, bgIndex);
|
|
bg.on('pointerover', () => bg.setFillStyle(ROW_BG, 0.4));
|
|
bg.on('pointerout', () => bg.setFillStyle(ROW_BG, 0));
|
|
// A mask is a rendering concern only — a row scrolled out of the visible
|
|
// band is still hit-testable, so every handler has to ask the column.
|
|
bg.on('pointerup', (p) => {
|
|
if (!col.contains(p)) return;
|
|
if (expanded.has(i)) expanded.delete(i); else expanded.add(i);
|
|
render();
|
|
});
|
|
|
|
col.content.add(scene.add.rectangle(0, cy, w, 1, ACCENT, 0.18).setOrigin(0, 0));
|
|
cy += 16;
|
|
}
|
|
col.contentHeight = cy;
|
|
col.setOffset(col.offset);
|
|
};
|
|
render();
|
|
|
|
const btn = new Button(scene, shell.x + shell.width / 2, shell.y + shell.height - 34, 'Continue', () => {
|
|
col.destroy();
|
|
shell.destroy();
|
|
onClose?.();
|
|
}, { width: 220, height: 44 });
|
|
shell.add(btn);
|
|
|
|
return shell;
|
|
}
|