fixed train# specific rules. cleaned up display topline and train display on division map
This commit is contained in:
+61
-1
@@ -66,7 +66,20 @@ export type CellView = {
|
||||
* `cars` runs nose first, matching the tray; `engineAt` is where the locomotive sits in it, and
|
||||
* `facing` is the port it points at on this card.
|
||||
*/
|
||||
train: { label: string; cars: string[]; engineAt: number; facing: string } | null;
|
||||
train: {
|
||||
label: string;
|
||||
cars: string[];
|
||||
engineAt: number;
|
||||
facing: string;
|
||||
/**
|
||||
* WHAT THIS PARTICULAR TRAIN'S CARD SAYS.
|
||||
*
|
||||
* Reported from a playtest: the Circus Train arrived and there was no way to find out what made
|
||||
* it a Circus Train. A special train is special only if the player can read the rule while it is
|
||||
* standing in front of them — the card is face down in a box somewhere by then.
|
||||
*/
|
||||
what: string;
|
||||
} | null;
|
||||
/**
|
||||
* Office card only: A/D tracks taken and how many the tier has.
|
||||
*
|
||||
@@ -424,6 +437,7 @@ function trainOnCard(s: GameState, key: string): CellView['train'] {
|
||||
cars: t.consist.map(carLabel),
|
||||
engineAt: Math.max(0, Math.min(t.consist.length, t.engineAt)),
|
||||
facing: t.facing ?? (t.direction === 'west' ? 'w' : 'e'),
|
||||
what: t.trainNumber === null ? 'A local crew — no timetable, no card, no special rules.' : trainRules(t),
|
||||
};
|
||||
void id;
|
||||
}
|
||||
@@ -657,6 +671,8 @@ export function describeIntent(s: GameState, i: Intent): string {
|
||||
return 'End Local Operations';
|
||||
case 'switch.end':
|
||||
return 'End Local Operations';
|
||||
case 'freightAgent.end':
|
||||
return 'End Local Operations — leave the Freight Agent idle';
|
||||
case 'loadUnload.end':
|
||||
return 'End my Cargo phase';
|
||||
case 'newTrain.passCar':
|
||||
@@ -1049,6 +1065,50 @@ export function cardDescription(s: GameState, id: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EVERYTHING THIS TRAIN'S CARD PRINTS, in one line.
|
||||
*
|
||||
* The name, its class, what its consist should be, and — the part that prompted this — whatever
|
||||
* special rule the card carries. Nine of the twelve rule flags are declared on the profiles and read
|
||||
* by nothing in the engine, so those are marked as not yet implemented rather than quietly listed:
|
||||
* telling a player a rule applies when it does not is worse than saying nothing.
|
||||
*/
|
||||
export function trainRules(t: {
|
||||
trainNumber: number | null;
|
||||
trainIsExtra: boolean;
|
||||
}): string {
|
||||
const p = trainProfile(t.trainNumber ?? 0, t.trainIsExtra);
|
||||
if (!p) return '';
|
||||
const parts: string[] = [`${p.isExtra ? 'Extra X' : 'Train '}${p.number} “${p.name}” · ${p.speed}`];
|
||||
|
||||
const consist: string[] = [];
|
||||
if (p.consist.freight > 0) {
|
||||
consist.push(`${p.consist.freight} ${p.consist.freightTypes?.join('/') ?? 'freight'}${p.consist.emptiesOnly ? ' (empties only)' : ''}`);
|
||||
}
|
||||
if (p.consist.coach > 0) consist.push(`${p.consist.coach} coach${p.consist.coach > 1 ? 'es' : ''}`);
|
||||
if (p.consist.caboose > 0) consist.push(`${p.consist.caboose} caboose`);
|
||||
parts.push(`its card calls for ${consist.join(' + ') || 'no cars'}`);
|
||||
|
||||
if (p.rules.note) parts.push(p.rules.note);
|
||||
|
||||
// Only `expedite` and the consist restrictions are actually enforced today (§7, §8.2), plus the
|
||||
// Circus Train's point for standing still. The rest are printed on the profile and read nowhere.
|
||||
const unbuilt: string[] = [];
|
||||
if (p.rules.noSwitching) unbuilt.push('no switching');
|
||||
if (p.rules.terminalsOnly) unbuilt.push('terminals only');
|
||||
if (p.rules.coachStaysOnStationTrack) unbuilt.push('the coach stays on the station track');
|
||||
if (p.rules.oneFreightPerLocation) unbuilt.push('one freight car per location');
|
||||
if (p.rules.noPassengerWork) unbuilt.push('no passenger work');
|
||||
if (p.rules.dropOnly) unbuilt.push('may drop but not pick up');
|
||||
if (p.rules.pickUpEmptiesOnly) unbuilt.push('may pick up empties only');
|
||||
if (p.rules.stopThenExpedite) unbuilt.push('stops, then runs expedited');
|
||||
if (unbuilt.length > 0) parts.push(`NOT YET ENFORCED BY THE ENGINE: ${unbuilt.join('; ')}`);
|
||||
|
||||
if (p.rules.expedite) parts.push('EXPEDITED — it departs in the same Stage it arrives (§7)');
|
||||
if (p.rules.stopEarnsPoint) parts.push('EARNS A POINT for one Stage spent standing still, once');
|
||||
return parts.join(' · ');
|
||||
}
|
||||
|
||||
/** The train riding a Crew Tray, for anything that has to talk about it. */
|
||||
export function trainName(s: GameState, trayId: string): string {
|
||||
const tray = s.trays.get(trayId);
|
||||
|
||||
Reference in New Issue
Block a user