Name the caboose, the train and the Running Track hazard

This commit is contained in:
Jesse
2026-08-01 07:03:21 -04:00
parent dd300ac154
commit d1f689d4fc
2 changed files with 77 additions and 6 deletions
+14 -6
View File
@@ -287,11 +287,13 @@ export function describeIntent(s: GameState, i: Intent): string {
case 'porter.detrain':
return `detrain passengers at ${at(i.at)}`;
case 'newTrain.placeCar':
return `add ${i.loaded ? 'loaded' : 'empty'} ${i.carType}`;
// carLabel knows a caboose carries the crew, not freight. Formatting it here by hand put
// "add loaded caboose" on a button.
return `add ${carLabel({ type: i.carType, loaded: i.loaded })}`;
case 'mainline.modify':
return `${cardName(s, i.cardId)} on Mainline card ${i.node}`;
case 'maneuver.redFlags':
return `Red Flags on ${i.trayId}`;
return `set Red Flags to protect ${trainName(s, i.trayId)} — an approaching train must stop short`;
case 'maneuver.flyingSwitch':
return `Flying Switch ${i.count} car(s) into ${at(i.to)}`;
case 'mainline.clearance': {
@@ -325,7 +327,7 @@ export function describeIntent(s: GameState, i: Intent): string {
case 'redFlag.play':
return 'play your red flag';
case 'maneuver.redFlags':
return `Red Flags on ${i.trayId}`;
return `set Red Flags to protect ${trainName(s, i.trayId)} — an approaching train must stop short`;
default: {
// Every Intent now has a sentence, so `i` narrows to never here. Keeping the assignment makes
// that a COMPILE error the day someone adds an intent without describing it — the playable UI
@@ -385,7 +387,7 @@ export function snapshot(
kind,
label,
running: row === area.runningRow,
what: cellDescription(card, officeProfile(area.tier).name),
what: cellDescription(card, officeProfile(area.tier).name, row === area.runningRow),
enhancements: card.enhancements.map(prettyKey),
tray: trayAt.get(key) ?? null,
cars: (card.facility?.industryTrack.length ? card.facility.industryTrack.cars : card.standing).map(carLabel),
@@ -579,7 +581,7 @@ export function trainName(s: GameState, trayId: string): string {
}
/** What a card on the board does, in one short line. */
function cellDescription(card: TrackCard, officeName: string): string {
function cellDescription(card: TrackCard, officeName: string, onRunning: boolean): string {
const g = card.geometry;
switch (g.kind) {
case 'limits':
@@ -612,7 +614,13 @@ function cellDescription(card: TrackCard, officeName: string): string {
if (f.kind === 'passenger') return 'passengers board and detrain here';
const p = industryProfile(g.facility as never);
const flow = p.flow === 'both' ? 'ships out AND receives' : p.flow === 'outbound' ? 'ships out' : 'receives';
return `${flow} ${p.carTypes.join('/')} · spot a matching car on its siding to work a load`;
// §11.2 — "Facility cards carry their own rails", so an industry on the Running Track does not
// block anything. It does inherit the Running Track's hazard: §10 makes cars left standing
// between the Limits and the Office a collision when a train arrives.
const where = onRunning
? ' · ON THE RUNNING TRACK — trains pass straight through, but a car left standing here is hit by the next arrival'
: '';
return `${flow} ${p.carTypes.join('/')} · spot a matching car on its siding to work a load${where}`;
}
case 'track':
switch (g.geometry) {