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:
@@ -450,7 +450,7 @@ describe('the view shows one seat at a time', () => {
|
||||
for (let n = 0; n < p; n++) {
|
||||
area.grid.set(coordKey({ row: area.runningRow - 1, col: n }), {
|
||||
geometry: { kind: 'track', geometry: 'straight' },
|
||||
baseOperationalRail: true, standing: [], facility: null, modifiers: [], enhancements: [],
|
||||
baseOperationalRail: true, standing: [], standingWest: 0, facility: null, modifiers: [], enhancements: [],
|
||||
});
|
||||
}
|
||||
s.decks.hands.set(p, source.slice(0, p + 1));
|
||||
@@ -527,7 +527,7 @@ describe('the view shows one seat at a time', () => {
|
||||
readyToLeave(s, 1, 'crew-1', 'east');
|
||||
|
||||
const withTray = (p: PlayerIndex): number =>
|
||||
snapshot(s, [], null, null, null, false, p).cells.filter((c) => c.tray != null).length;
|
||||
snapshot(s, [], null, null, null, false, p).cells.filter((c) => c.trains.length > 0).length;
|
||||
assert.equal(withTray(1), 1, "the crew is not on its own seat's board");
|
||||
assert.deepEqual([withTray(0), withTray(2)], [0, 0], "a crew was drawn onto another seat's board");
|
||||
});
|
||||
@@ -594,7 +594,7 @@ describe('scoring lands on the right seat', () => {
|
||||
const sizeBefore = areaAtSeat(s, 2).grid.size;
|
||||
mine.grid.set(coordKey({ row: mine.runningRow - 1, col: 0 }), {
|
||||
geometry: { kind: 'track', geometry: 'straight' },
|
||||
baseOperationalRail: true, standing: [], facility: null, modifiers: [], enhancements: [],
|
||||
baseOperationalRail: true, standing: [], standingWest: 0, facility: null, modifiers: [], enhancements: [],
|
||||
});
|
||||
assert.equal(areaAtSeat(s, 2).grid.size, sizeBefore, "one seat's track appeared in another's district");
|
||||
assert.notEqual(areaAtSeat(s, 1), areaAtSeat(s, 2), 'two seats share one Office Area object');
|
||||
|
||||
Reference in New Issue
Block a user