more info on train moves in history. train info added to tooltip on timetable and division map. support for multiple trains in area switching. more info on train7/8 wrt location of coach on initial train build.
This commit is contained in:
+69
-5
@@ -69,8 +69,27 @@ let soundOn = false;
|
||||
* ended or what happened in between. Reported exactly that way.
|
||||
*/
|
||||
let lastPhase: string | null = null;
|
||||
/**
|
||||
* WHICH CREW THE BOARD IS DRAWING, when the district holds more than one.
|
||||
*
|
||||
* Reported from play: "make it clear which train you are switching — it is possible to have more
|
||||
* than one train available." A train standing on an A/D track while a local shunts is ordinary, and
|
||||
* the board used to highlight whichever crew came first out of the map while the action list offered
|
||||
* every crew's moves under one heading.
|
||||
*
|
||||
* Display state, deliberately not in the game: which train a player is looking at is not a fact
|
||||
* about the railroad, and in a multiplayer game two players may reasonably be looking at different
|
||||
* ones. Cleared whenever the named crew stops being one of the choices.
|
||||
*/
|
||||
let selectedCrew: string | null = null;
|
||||
const FOCUS_PHASES = new Set(['localOps', 'loadUnload']);
|
||||
|
||||
/** The crew whose squares the board is drawing: the chosen one, or the only one there is. */
|
||||
function pickedCrew(f: Frame): Frame['moves'][number] | null {
|
||||
if (f.moves.length === 0) return null;
|
||||
return f.moves.find((m) => m.trayId === selectedCrew) ?? f.moves[0] ?? null;
|
||||
}
|
||||
|
||||
const $ = (id: string): HTMLElement => {
|
||||
const el = document.getElementById(id);
|
||||
if (!el) throw new Error(`missing element: ${id}`);
|
||||
@@ -311,14 +330,20 @@ function render(): void {
|
||||
* WHERE IT IS, WHERE IT MAY GO, AND WHY NOT THE REST. A blocked card carries its reason in its own
|
||||
* tooltip, so "why can I not get into that industry?" is answered by hovering the industry.
|
||||
*/
|
||||
if (f.moves && !forPlay) {
|
||||
const here = grid.querySelector(`g[data-cell="${f.moves.from.row},${f.moves.from.col}"]`);
|
||||
/**
|
||||
* ONE CREW'S SQUARES AT A TIME. Drawing every crew's reachable squares at once is worse than
|
||||
* drawing one crew's: the highlights merge into a single blob and stop meaning "here is where
|
||||
* THIS train can go", which is the whole reason they are on the board.
|
||||
*/
|
||||
const crew = pickedCrew(f);
|
||||
if (crew && !forPlay) {
|
||||
const here = grid.querySelector(`g[data-cell="${crew.from.row},${crew.from.col}"]`);
|
||||
if (here) here.classList.add('bs-from');
|
||||
for (const c of f.moves.to) {
|
||||
for (const c of crew.to) {
|
||||
const g = grid.querySelector(`g[data-cell="${c.row},${c.col}"]`);
|
||||
if (g) g.classList.add('bs-focus');
|
||||
}
|
||||
for (const b of f.moves.blocked) {
|
||||
for (const b of crew.blocked) {
|
||||
const g = grid.querySelector(`g[data-cell="${b.coord.row},${b.coord.col}"]`);
|
||||
if (!g) continue;
|
||||
// Two different things wearing two different marks. A turnout you cannot STOP on is not in
|
||||
@@ -711,6 +736,26 @@ function renderActions(
|
||||
// no worker able to act, the only thing offered is "End my Cargo phase".
|
||||
let html = `<h3 class="actions-hd">Actions</h3>${scheduledNote}${movesNote}`;
|
||||
|
||||
/**
|
||||
* WHICH TRAIN AM I SWITCHING? Only asked when there is more than one crew to be switching, so a
|
||||
* solitaire opening — one crew, no ambiguity — is unchanged. The chosen one is the crew whose
|
||||
* reachable squares the board draws, so this row and the highlights are the same statement.
|
||||
*/
|
||||
if (f.moves.length > 1) {
|
||||
const chosen = pickedCrew(f);
|
||||
html +=
|
||||
`<div class="grp crewpick"><h3>Which train are you switching?</h3>` +
|
||||
f.moves
|
||||
.map(
|
||||
(m) =>
|
||||
`<button class="act crew${m.trayId === chosen?.trayId ? ' on' : ''}" data-crew="${esc(m.trayId)}" ` +
|
||||
`data-tip="Draw this crew's reachable squares on the board, and show its moves below. ${esc(m.label)} is standing at (${m.from.row}, ${m.from.col}) with ${m.to.length} square${m.to.length === 1 ? '' : 's'} it can reach.">` +
|
||||
`${esc(m.label)} <span class="dim">(${m.from.row}, ${m.from.col})</span></button>`,
|
||||
)
|
||||
.join('') +
|
||||
`</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* WHAT IS LEFT IN THE ACTION LIST.
|
||||
*
|
||||
@@ -757,6 +802,17 @@ function renderActions(
|
||||
? 'The Division Yard is bare, so there is nothing to add. Send the train out as it stands.'
|
||||
: 'Nothing in the Division Yard may join this train, and §7 does not allow passing while the yard holds cars.') +
|
||||
`</div>` +
|
||||
/**
|
||||
* WHICH ORDER TO ADD THEM IN, when the order is what decides whether the train can work.
|
||||
*
|
||||
* Only ever present for a train the order can lock — 7/8 Local — so this is not a standing
|
||||
* caption a player learns to skip. Reported from play as "I can't drop a car at all": the
|
||||
* Local made up ENGINE, freight, coach cannot set anything out for the rest of the game, and
|
||||
* nothing on screen said so until the crew was out on the district with no button to press.
|
||||
*/
|
||||
(menu.makeUp.advice
|
||||
? `<div class="makeup-advice ${menu.makeUp.advice.tone}">${esc(menu.makeUp.advice.text)}</div>`
|
||||
: '') +
|
||||
(menu.makeUp.pass !== null
|
||||
? `<button class="act" data-i="${menu.makeUp.pass}" data-tip="§8.2 — a train may depart with FEWER cars than its card lists, but never with the wrong ones. This sends it out as it stands.">no more cars — send it out</button>`
|
||||
: '') +
|
||||
@@ -817,7 +873,15 @@ function renderActions(
|
||||
|
||||
for (const b of Array.from(el.querySelectorAll('button.act'))) {
|
||||
const node = b as HTMLElement;
|
||||
node.onclick = () => apply(Number(node.dataset['i']));
|
||||
// The crew buttons choose what the board draws; they submit nothing, so they must not fall
|
||||
// through to `apply` with an undefined index.
|
||||
const crewId = node.dataset['crew'];
|
||||
node.onclick = crewId
|
||||
? () => {
|
||||
selectedCrew = crewId;
|
||||
render();
|
||||
}
|
||||
: () => apply(Number(node.dataset['i']));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user