v0.4.2 fixed passenger trains not stopping at office. changeed revenue for train completing run - 1 point to every player when train exits division
This commit is contained in:
+71
-26
@@ -269,11 +269,13 @@ export function narrate(e: GameEvent, ctx: NarrateContext = {}): Narration {
|
||||
text: `Train ${e.trainNumber} DIVERTED to ${e.to} — ${e.reason}`,
|
||||
};
|
||||
case 'trainCompleted':
|
||||
// The one line in the log that is good news for everybody, so it is not 'quiet'.
|
||||
return {
|
||||
tone: 'quiet',
|
||||
tone: 'good',
|
||||
text:
|
||||
`Train ${e.trainNumber} finished its run and left the Division carrying ` +
|
||||
`${carsLabel(e.consist)} — the crew is free again`,
|
||||
`Train ${e.isExtra ? 'X' : ''}${e.trainNumber} has completed its run, leaving via the ` +
|
||||
`${e.side === 'east' ? 'Eastern' : 'Western'} Division Point carrying ${carsLabel(e.consist)}. ` +
|
||||
`All players get 1 Revenue. The crew is free again.`,
|
||||
};
|
||||
|
||||
// -- freight agent
|
||||
@@ -533,42 +535,82 @@ export function impediments(s: GameState, player: PlayerIndex = 0): Impediment[]
|
||||
}
|
||||
|
||||
/**
|
||||
* WHY THE PASSENGERS ARE NOT GETTING OFF.
|
||||
* WHY THE PASSENGERS ARE NOT MOVING — boarding as well as de-training.
|
||||
*
|
||||
* 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.
|
||||
* Reported first as "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.
|
||||
* Reported again as "passenger trains arrive at my Office and move on before I can load or unload
|
||||
* them", which turned out to be three separate silences. This block only looked at trains carrying
|
||||
* a LOADED coach, so a train arriving to PICK UP said nothing at all. A Whistle Post's Office card
|
||||
* carries a passenger facility with zero Porters, so the engine answered `RESOURCE_SPENT` — "all
|
||||
* Porters used" — to a player who had used none. And an expedited train leaves at the end of the
|
||||
* Stage it arrives, so its one Load/Unload phase is now-or-never and nothing said which trains
|
||||
* those are.
|
||||
*
|
||||
* §9.2 also requires an empty coach in the DIVISION YARD to swap into the train, which no panel
|
||||
* mentioned at all.
|
||||
*/
|
||||
const office = area.grid.get(coordKey(area.officeCoord));
|
||||
const pf = office?.facility;
|
||||
if (pf && pf.kind === 'passenger') {
|
||||
const waiting = area.adOccupancy
|
||||
const coachTrains = 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(
|
||||
.filter((t): t is NonNullable<typeof t> => !!t && t.consist.some((c) => c.type === 'coach'));
|
||||
|
||||
if (coachTrains.length > 0) {
|
||||
const label = (t: (typeof coachTrains)[number]): string =>
|
||||
t.trainNumber === null ? 'the local crew' : `Train ${t.trainIsExtra ? 'X' : ''}${t.trainNumber}`;
|
||||
const say = (why: string, severity: Impediment['severity'] = 'waiting'): void => {
|
||||
out.push({ where: 'Office — passengers', why, severity });
|
||||
};
|
||||
|
||||
const boarding = pf.outboundBox.some((c) => c.type === 'coach' && c.loaded);
|
||||
const emptyOnTrain = coachTrains.some((t) => t.consist.some((c) => c.type === 'coach' && !c.loaded));
|
||||
const loadedOnTrain = coachTrains.some((t) => t.consist.some((c) => c.type === 'coach' && c.loaded));
|
||||
|
||||
if (pf.porters < 1) {
|
||||
say(
|
||||
'this Office has NO Porters — a Whistle Post is not a Passenger Facility (§9) and cannot ' +
|
||||
'work passengers at all. Upgrade it to a Depot or better.',
|
||||
'stuck',
|
||||
);
|
||||
} else if (portersLeft(pf) < 1) {
|
||||
say(
|
||||
`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)',
|
||||
);
|
||||
} else {
|
||||
if (boarding && !emptyOnTrain) {
|
||||
say('passengers are waiting to board, but every coach standing here is already full');
|
||||
}
|
||||
if (!boarding && !loadedOnTrain) {
|
||||
say('nobody waiting to travel and no loaded coach to set down — stock the platform with a Freight Agent action');
|
||||
}
|
||||
if (loadedOnTrain && pf.inboundBox.length >= pf.capacity.inbound) {
|
||||
say(
|
||||
`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 (loadedOnTrain && !s.yards.divisionYard.some((c) => c.type === 'coach' && !c.loaded)) {
|
||||
say('no EMPTY coach in the Division Yard to swap into the train (§9.2 requires one)');
|
||||
}
|
||||
}
|
||||
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',
|
||||
|
||||
// NOW OR NEVER. An expedited train leaves at the end of this Stage, so this is the only
|
||||
// Load/Unload phase it will ever stand for — the exact thing the playtest report was about.
|
||||
for (const t of coachTrains) {
|
||||
if (!t.departsThisStage) continue;
|
||||
say(
|
||||
`${label(t)} is EXPEDITED — it leaves at the END of this Stage, so this is the only ` +
|
||||
'Load/Unload phase it will stand for. Work it now or not at all.',
|
||||
'risk',
|
||||
);
|
||||
}
|
||||
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' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,6 +687,9 @@ export function cuesFor(events: readonly GameEvent[]): string[] {
|
||||
// The 1D12 that sets a train's departure Stage. It is the one roll a player makes and it landed
|
||||
// silently, so the card was gone and the answer to "when does it run?" was a line of history.
|
||||
if (e.type === 'trainScheduled') out.push('schedule');
|
||||
// A train running the whole length of the Division pays every player, and it is the one event
|
||||
// nobody made happen on the turn it lands. It should be heard, not found in the log.
|
||||
if (e.type === 'trainCompleted') out.push('completed');
|
||||
if (e.type === 'stageBegan') {
|
||||
// A Stage BEGINNING is the previous one ending — except the first, which is the game opening
|
||||
// and has nothing behind it. A Day boundary rings the bell only: sounding both would collide,
|
||||
|
||||
Reference in New Issue
Block a user