fixed train# specific rules. cleaned up display topline and train display on division map

This commit is contained in:
Jesse
2026-08-09 19:44:18 -04:00
parent 4a800a053a
commit 6ead39c530
14 changed files with 316 additions and 57 deletions
+47
View File
@@ -231,6 +231,13 @@ export function narrate(e: GameEvent, ctx: NarrateContext = {}): Narration {
tone: 'good',
text: `${e.isExtra ? `EXTRA X${e.trainNumber}` : `TRAIN ${e.trainNumber}`} MADE UP at the ${e.at}, running ${e.direction} — crew assigned, now taking cars`,
};
case 'trainStoodStill':
return {
tone: 'good',
text:
`Train ${e.trainNumber} stood still for a whole Stage at ${e.where} and earned a point — ` +
'its card pays for the stop, not for the run (circus set-up)',
};
case 'trainHeld':
return {
tone: 'bad',
@@ -525,6 +532,46 @@ export function impediments(s: GameState, player = 0): Impediment[] {
}
}
/**
* WHY THE PASSENGERS ARE NOT GETTING OFF.
*
* Reported: "I can't figure out how to have a train with three passenger coaches unload all three
* at my depot." You cannot — a Depot has ONE Porter and ONE red slot, so it works one coach a
* Stage and then needs a Freight Agent action to clear the box before the next. A Station does two
* and a Terminal three. That is the Office ladder doing its job, and nothing on screen said so.
*
* §9.2 also requires an empty coach in the DIVISION YARD to swap into the train, which is a
* requirement the engine only started enforcing recently and which no panel mentions at all.
*/
const office = area.grid.get(coordKey(area.officeCoord));
const pf = office?.facility;
if (pf && pf.kind === 'passenger') {
const waiting = area.adOccupancy
.map((id) => s.trays.get(id))
.filter((t) => t?.consist.some((c) => c.type === 'coach' && c.loaded));
if (waiting.length > 0) {
const reasons: string[] = [];
if (portersLeft(pf) < 1) {
reasons.push(
`all ${pf.porters} Porter${pf.porters === 1 ? '' : 's'} used this Stage — one works one coach, ` +
'and the Office tier is the Porter count (Depot 1, Station 2, Terminal 3)',
);
}
if (pf.inboundBox.length >= pf.capacity.inbound) {
reasons.push(
`the red Unloading box is full (${pf.capacity.inbound} slot${pf.capacity.inbound === 1 ? '' : 's'}) — ` +
'a Freight Agent action clears it, which costs a whole Local Operations turn',
);
}
if (!s.yards.divisionYard.some((c) => c.type === 'coach' && !c.loaded)) {
reasons.push('no EMPTY coach in the Division Yard to swap into the train (§9.2 requires one)');
}
for (const why of reasons) {
out.push({ where: 'passengers waiting to de-train', why, severity: 'waiting' });
}
}
}
// Trains held for want of a Crew Tray (§7) — the scarcity mechanic, made visible.
const due = s.timetable[s.clock.stage - 1];
if (due !== null && due !== undefined && s.freeTrays.length === 0) {