More bug fixes. Show the timetable, and stop the arrival message contradicting itself. Fixed division point in labels. And highlighted discard as targets.

This commit is contained in:
Jesse
2026-08-05 23:08:03 -04:00
parent 543584a2ca
commit f4c0f49604
13 changed files with 381 additions and 50 deletions
+38 -4
View File
@@ -7,7 +7,7 @@
import { BOARD_CSS, divisionSvg, officeSvg } from '../sim/board-svg.ts';
import { TURNCHART_CSS, turnChartHtml } from '../sim/turnchart.ts';
import { PANEL_CSS, blockedHtml, facilitiesHtml, pilesHtml, yardHtml } from './panels.ts';
import { PANEL_CSS, blockedHtml, facilitiesHtml, pilesHtml, timetableHtml, yardHtml } from './panels.ts';
import { TOOLTIP_CSS, installTooltips } from './tooltip.ts';
import { playCue } from './sound.ts';
import type { Game } from './game.ts';
@@ -293,6 +293,9 @@ function render(): void {
? menu.hand.find((h) => `hand:${h.cardId}` === selected)
: undefined;
if (discarding) {
// Dim the piles that are not targets, so the three that are read as a choice being offered
// rather than as four cards that happen to be there.
$('depts').classList.add('aiming');
for (const el of Array.from($('depts').querySelectorAll('[data-dept]'))) {
const node = el as HTMLElement;
const slot = Number(node.dataset['dept']);
@@ -309,6 +312,10 @@ function render(): void {
}
}
else {
$('depts').classList.remove('aiming');
}
// -- making up a train: the Division Yard chip that shows the car IS the button.
if (menu.makeUp) {
for (const el of Array.from($('divyard').querySelectorAll('[data-car]'))) {
@@ -326,6 +333,16 @@ function render(): void {
}
}
/**
* THE TIMETABLE, with the slot the die just filled flashed.
*
* `scheduled` is cleared as it is consumed, so the flash marks the moment rather than the state —
* it is gone by the next render, which is what makes it read as "that just happened".
*/
const justSet = game.scheduled;
game.scheduled = null;
$('timetable').innerHTML = timetableHtml(f, justSet);
$('blocked').innerHTML = blockedHtml(f);
// -- log
@@ -354,7 +371,7 @@ function render(): void {
lastPhase = f.phaseKey;
renderDistrict(f);
renderActions(menu, f);
renderActions(menu, f, justSet);
// Drain whatever the last batch of events earned. Cleared either way, so turning sound on does
// not then play a backlog of everything that happened while it was off.
@@ -413,7 +430,11 @@ function renderDistrict(f: ReturnType<typeof view>): void {
};
}
function renderActions(menu: ReturnType<typeof actionMenu>, f: ReturnType<typeof view>): void {
function renderActions(
menu: ReturnType<typeof actionMenu>,
f: ReturnType<typeof view>,
justSet: number | null,
): void {
const el = $('actions');
if (game.state.status !== 'active') {
@@ -474,6 +495,19 @@ function renderActions(menu: ReturnType<typeof actionMenu>, f: ReturnType<typeof
* the count belongs beside the buttons. It was reported only in the history panel, which is the
* one place a player is not looking while switching.
*/
/**
* WHAT THE DIE DID, said where the player is looking.
*
* Playing a train card rolls 1D12 for its departure Stage, and the card simply left the hand — the
* answer arrived only in the history panel, one line among many. The timetable now shows it and
* flashes the slot; this says it in words at the same moment.
*/
const scheduledNote =
justSet !== null && f.timetable[justSet] != null
? `<div class="scheduled" data-tip="§7 — the Stage is rolled on 1D12 when the card is played; if that Stage is taken the train works down the column to the next free one. From now on it runs at this time every Day.">` +
`Train ${f.timetable[justSet]} is scheduled to depart at Stage ${justSet + 1} — see the Timetable</div>`
: '';
const movesNote =
f.movesLeft !== null
? `<div class="moves${f.movesLeft === 0 ? ' spent' : ''}" data-tip="§6.1 — six Moves a turn. A Move runs any distance in one direction; changing direction costs another, which is why a run-around has to be planned inside the count.">` +
@@ -483,7 +517,7 @@ function renderActions(menu: ReturnType<typeof actionMenu>, f: ReturnType<typeof
// A heading over the buttons, so the panel says what it is before it says what is in it. The
// list below is already phase-specific: it comes from `legalActions`, so in the Cargo phase with
// no worker able to act, the only thing offered is "End my Cargo phase".
let html = `<h3 class="actions-hd">Actions</h3>${movesNote}`;
let html = `<h3 class="actions-hd">Actions</h3>${scheduledNote}${movesNote}`;
/**
* WHAT IS LEFT IN THE ACTION LIST.