the Roster Pass: every train at the Office visible
Builds "The Roster Pass" / "Two Trains, One Card" (station display for multiple trains at one Office). The Office is the one square where more than one train may legally stand at once (one per A/D track), and CellView.train had room for exactly one — a second train at a busy Station was counted in the old A/D pips and never drawn. CellView.train -> CellView.trains: TrainView[], seat-filtered and collecting every match rather than the first (fixes a latent cross-district leak in the process: trainOnCard never checked seat). The A/D pips are replaced with one roster chip per A/D track, always, free or occupied; clicking a chip sets selectedCrew, wiring the board and the action panel to the same value. standingWest moves from CrewTray to TrackCard: two trays sharing one Office card need one shared split, not one each, and there is no such thing as "west of one particular A/D track". No save migration — Save replays through the engine — and a stale value on an emptied card is inert because nothing reads a split with no train standing there. The Division map's Office cell is now sized by A/D capacity rather than occupancy, so it holds still as trains arrive and leave; chips lay into fixed slots instead of centre-spreading onto the Limits cards either side. 584 tests, 0 failures. Verified end-to-end against the built app and a direct render of a 4-train Terminal (screenshotted). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SAt2YCXgd5qCjBcF2x34aK
This commit is contained in:
+13
-7
@@ -56,6 +56,7 @@ const straight = (standing: TrackCard['standing'] = []): TrackCard => ({
|
||||
geometry: { kind: 'track', geometry: 'straight' },
|
||||
baseOperationalRail: true,
|
||||
standing,
|
||||
standingWest: 0,
|
||||
facility: null,
|
||||
modifiers: [],
|
||||
enhancements: [],
|
||||
@@ -445,6 +446,7 @@ describe('Freight Agent operations (§6.3)', () => {
|
||||
geometry: { kind: 'facility', facility: 'mineTipple' },
|
||||
baseOperationalRail: true,
|
||||
standing: [],
|
||||
standingWest: 0,
|
||||
facility: {
|
||||
kind: 'freight',
|
||||
subtype: 'mineTipple',
|
||||
@@ -576,6 +578,7 @@ describe('Load/Unload: the four-action freight pipeline (§9.3)', () => {
|
||||
geometry: { kind: 'facility', facility: 'mineTipple' },
|
||||
baseOperationalRail: true,
|
||||
standing: [],
|
||||
standingWest: 0,
|
||||
facility: {
|
||||
kind: 'freight',
|
||||
subtype: 'mineTipple',
|
||||
@@ -757,6 +760,7 @@ describe('legalActions shares its rules with apply (component 6)', () => {
|
||||
geometry: { kind: 'facility', facility: 'mineTipple' },
|
||||
baseOperationalRail: true,
|
||||
standing: [],
|
||||
standingWest: 0,
|
||||
facility: {
|
||||
kind: 'freight',
|
||||
subtype: 'mineTipple',
|
||||
@@ -944,7 +948,7 @@ describe('the Limits bound the district, and the nine spots reach round a Facili
|
||||
const area = areaOf(s, 0);
|
||||
const plain = (geometry: object): TrackCard => ({
|
||||
geometry: geometry as TrackCard['geometry'],
|
||||
baseOperationalRail: true, standing: [], facility: null, modifiers: [], enhancements: [],
|
||||
baseOperationalRail: true, standing: [], standingWest: 0, facility: null, modifiers: [], enhancements: [],
|
||||
});
|
||||
const col = area.limitsEast.col;
|
||||
area.grid.set(coordKey(at(area.runningRow, col)), plain({
|
||||
@@ -1294,7 +1298,7 @@ describe('Industry cards go on a stub, and lock each other out', () => {
|
||||
const area = areaOf(s, 0);
|
||||
const plain = (geometry: object): TrackCard => ({
|
||||
geometry: geometry as TrackCard['geometry'],
|
||||
baseOperationalRail: true, standing: [], facility: null, modifiers: [], enhancements: [],
|
||||
baseOperationalRail: true, standing: [], standingWest: 0, facility: null, modifiers: [], enhancements: [],
|
||||
});
|
||||
const col = area.limitsEast.col;
|
||||
area.grid.set(coordKey(at(area.runningRow, col)), plain({
|
||||
@@ -1326,7 +1330,7 @@ describe('Industry cards go on a stub, and lock each other out', () => {
|
||||
function build(s: GameState, kind: string, coord: GridCoord): void {
|
||||
areaOf(s, 0).grid.set(coordKey(coord), {
|
||||
geometry: { kind: 'facility', facility: kind as never },
|
||||
baseOperationalRail: true, standing: [], facility: null, modifiers: [], enhancements: [],
|
||||
baseOperationalRail: true, standing: [], standingWest: 0, facility: null, modifiers: [], enhancements: [],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1621,8 +1625,9 @@ describe('the engine is drawn pointing east or west, whatever track it is standi
|
||||
addCard(s, at(0, 0), straight());
|
||||
reduce(s, moved(id, 's'));
|
||||
const cell = snapshot(s, [], null).cells.find((c) => c.row === 0 && c.col === 0);
|
||||
assert.ok(cell?.train, 'the train should be on the card');
|
||||
assert.ok(cell.train.facing === 'e' || cell.train.facing === 'w', `got ${cell.train.facing}`);
|
||||
const train = cell?.trains[0];
|
||||
assert.ok(train, 'the train should be on the card');
|
||||
assert.ok(train.facing === 'e' || train.facing === 'w', `got ${train.facing}`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1646,6 +1651,7 @@ describe('a train that rounds a curve points where the curve took it', () => {
|
||||
geometry: { kind: 'track', geometry: 'curved', arc, hand: 'right' },
|
||||
baseOperationalRail: true,
|
||||
standing: [],
|
||||
standingWest: 0,
|
||||
facility: null,
|
||||
modifiers: [],
|
||||
enhancements: [],
|
||||
@@ -1782,11 +1788,11 @@ describe('the switching job a player actually does: put a car in a siding, take
|
||||
*/
|
||||
const curve = (arc: 'ne' | 'nw' | 'se' | 'sw'): TrackCard => ({
|
||||
geometry: { kind: 'track', geometry: 'curved', arc, hand: 'right' },
|
||||
baseOperationalRail: true, standing: [], facility: null, modifiers: [], enhancements: [],
|
||||
baseOperationalRail: true, standing: [], standingWest: 0, facility: null, modifiers: [], enhancements: [],
|
||||
});
|
||||
const turnout = (o: { stem: 'n' | 's' | 'e' | 'w'; through: 'n' | 's' | 'e' | 'w'; diverge: 'n' | 's' | 'e' | 'w' }): TrackCard => ({
|
||||
geometry: { kind: 'track', geometry: 'turnout', turnout: o, hand: 'right' },
|
||||
baseOperationalRail: true, standing: [], facility: null, modifiers: [], enhancements: [],
|
||||
baseOperationalRail: true, standing: [], standingWest: 0, facility: null, modifiers: [], enhancements: [],
|
||||
});
|
||||
|
||||
it('takes a cut off the Running Track into a siding and sets it out', () => {
|
||||
|
||||
Reference in New Issue
Block a user