v0.8.0.11 — sixteen fixes from the second multiplayer playtest

Arrivals name whose Office they reached, and no longer tell every seat they can
work the train. The turn chart follows the animation queue, so being five behind
looks five behind across the whole screen rather than half of it. Pause sits
beside Skip and preserves the dwell a held step still owed. A one-render look at
another player's Office Area. The district summary counts the board being shown.
LIMITS is printed beneath its card instead of through its border. The Mainline
region divider is visible. Only Hilly mentions FAST/SLOW, because it is the only
card that reads it. A passenger Modifier on a Whistle Post reports itself dormant
rather than claiming the facility "only receives". An automatic phase says what
the Division is doing instead of answering by negation. The version appears once
in the header rather than twice on every .s9pk. Save files carry the join code,
the Stage and the date.

The New Train phase, reviewed before being changed: the make-up panel now says
what the train STILL needs rather than only what its card calls for, explains
that a player adds one car before the round passes on, marks the train being
loaded on the Division map, and gives an addable car in the yard the same amber
every other clickable thing on the page wears.

Reasoning, measurements and the reports behind each are in CHANGELOG.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017nnuCv8UodHucFfx3LWEoX
This commit is contained in:
Jesse.Markowitz
2026-09-16 16:06:01 -04:00
co-authored by Claude Opus 5
parent 4adf149ba5
commit 9a9e50b3c6
21 changed files with 701 additions and 44 deletions
+19 -6
View File
@@ -343,12 +343,25 @@ export function narrate(e: GameEvent, ctx: NarrateContext = {}): Narration {
* arrival; the only difference is what happens if it is left on Secondary Track when the next
* Mainline Phase begins (`expediteFault`).
*/
return {
tone: 'plain',
text: e.expedited
? `Train ${e.trainNumber} ARRIVED at the ${e.office} carrying ${carsLabel(e.consist)} — its card prints EXPEDITE, so keep it on the Office square: parked anywhere else in the district when the next Mainline Phase begins costs a Revenue point. It works and switches normally in the meantime.`
: `Train ${e.trainNumber} ARRIVED at the ${e.office} carrying ${carsLabel(e.consist)} — it stands here for the rest of this Stage. You can work it in Cargo now, switch it in the NEXT Stage's Local Operations, and it departs in that Stage's Mainline Phase.`,
};
/**
* WHOSE OFFICE, AND WHOSE TRAIN TO WORK — Jesse, playtest 2026-09-16.
*
* This said "ARRIVED at the Whistle Post" and then "You can work it in Cargo now". Both halves
* are wrong at a table of four: every seat has an Office, so the tier alone does not say which
* district the train is standing in, and the reader is usually NOT its Station Master — the
* line was telling three players they could work a train they cannot touch.
*/
{
const name = ctx.playerName?.(e.owner) ?? null;
const whose = name === null ? `the ${e.office}` : `${name}'s ${e.office}`;
const worker = name === null ? 'Its Station Master' : name;
return {
tone: 'plain',
text: e.expedited
? `Train ${e.trainNumber} ARRIVED at ${whose} carrying ${carsLabel(e.consist)} — its card prints EXPEDITE, so it must stay on the Office square: parked anywhere else in that district when the next Mainline Phase begins costs a Revenue point. It works and switches normally in the meantime.`
: `Train ${e.trainNumber} ARRIVED at ${whose} carrying ${carsLabel(e.consist)} — it stands there for the rest of this Stage. ${worker} can work it in Cargo now and switch it in the NEXT Stage's Local Operations, and it departs in that Stage's Mainline Phase.`,
};
}
case 'expediteFault':
return {
tone: 'bad',