More bug fixes. Show the timetable, and stop the arrival message contradicting itself. Fixed division point in labels. And highlighted discard as targets.
This commit is contained in:
@@ -402,6 +402,7 @@ describe('the replay behaves like the game it is replaying', () => {
|
||||
// board and only history said where it went.
|
||||
assert.ok(kinds.has('couple'), 'coupling a cut never made a sound');
|
||||
assert.ok(kinds.has('drop'), 'setting cars out never made a sound');
|
||||
assert.ok(kinds.has('schedule'), 'the 1D12 that sets a train\'s departure Stage landed silently');
|
||||
|
||||
// One CLOCK cue per Stage boundary, the bell replacing the whistle at a Day — the same
|
||||
// accounting the live game is held to. The switching cues are counted separately: they follow
|
||||
|
||||
+71
-7
@@ -14,6 +14,7 @@ import { dirname, join, resolve } from 'node:path';
|
||||
import { cardDescription, cardName, describeIntent, variantLabel } from '../src/sim/view.ts';
|
||||
import { variantsFor } from '../src/engine/track.ts';
|
||||
import { divisionSvg, officeSvg } from '../src/sim/board-svg.ts';
|
||||
import { timetableHtml } from '../src/web/panels.ts';
|
||||
import { record, renderHtml } from '../src/sim/replay.ts';
|
||||
import { snapshot } from '../src/sim/view.ts';
|
||||
import { createGame as createEngineGame } from '../src/engine/setup.ts';
|
||||
@@ -343,18 +344,54 @@ describe('the board shows freight work happening', () => {
|
||||
);
|
||||
};
|
||||
|
||||
assert.deepEqual(filled(), ['green=FULL', 'maw', 'maw', 'maw', 'red'], 'the waiting load is not drawn');
|
||||
// A Mine Tipple only ships OUT, so it has no red Unloading box at all — only the boxes an
|
||||
// industry actually uses are drawn now.
|
||||
assert.deepEqual(filled(), ['green=FULL', 'maw', 'maw', 'maw'], 'the waiting load is not drawn');
|
||||
|
||||
game.state.clock.phase = 'loadUnload';
|
||||
game.state.clock.currentActor = 0;
|
||||
assert.ok(submit(game, { type: 'laborer.startLoad', at: { row: -1, col: 0 } }));
|
||||
assert.deepEqual(filled(), ['green', 'maw=FULL', 'maw', 'maw', 'red'], 'starting a load is invisible');
|
||||
assert.deepEqual(filled(), ['green', 'maw=FULL', 'maw', 'maw'], 'starting a load is invisible');
|
||||
|
||||
assert.ok(submit(game, { type: 'laborer.advanceLoad', at: { row: -1, col: 0 }, box: 0 }));
|
||||
assert.deepEqual(filled(), ['green', 'maw', 'maw=FULL', 'maw', 'red'], 'advancing a load is invisible');
|
||||
assert.deepEqual(filled(), ['green', 'maw', 'maw=FULL', 'maw'], 'advancing a load is invisible');
|
||||
|
||||
assert.ok(submit(game, { type: 'laborer.advanceLoad', at: { row: -1, col: 0 }, box: 1 }));
|
||||
assert.deepEqual(filled(), ['green', 'maw', 'maw', 'maw=FULL', 'red'], 'the load did not reach WORK');
|
||||
assert.deepEqual(filled(), ['green', 'maw', 'maw', 'maw=FULL'], 'the load did not reach WORK');
|
||||
});
|
||||
|
||||
it('draws the pipeline the way the freight actually flows', () => {
|
||||
// REPORTED after unloading at a warehouse: "it went W, A, M, and then to the red box at the far
|
||||
// right." §9.3 runs loading Green → MEN → AT → WORK → car, and unloading the other way entirely:
|
||||
// car → WORK → AT → MEN → red. So green and red BOTH sit beside MEN and the car sits beside
|
||||
// WORK — but red was drawn at the far right, which is exactly where the car is, so an unload
|
||||
// looked like it ran backwards across the row and landed on the end it came from.
|
||||
const game = newGame(5);
|
||||
const area = game.state.officeAreas.get(0)!;
|
||||
const fac = (kind: string, out: boolean, into: boolean) => ({
|
||||
geometry: { kind: 'facility', facility: kind },
|
||||
baseOperationalRail: true, standing: [], modifiers: [], enhancements: [],
|
||||
facility: {
|
||||
kind: 'freight', subtype: kind,
|
||||
allows: { outbound: out, inbound: into },
|
||||
outboundBox: [], inboundBox: [], capacity: { outbound: out ? 1 : 0, inbound: into ? 1 : 0 },
|
||||
menAtWork: [null, null, null], industryTrack: { length: 2, cars: [] },
|
||||
laborers: 1, porters: 0, usedThisStage: { laborers: 0, porters: 0 },
|
||||
},
|
||||
});
|
||||
area.grid.set('-1,0', fac('grocersWarehouse', false, true) as never);
|
||||
area.grid.set('-1,1', fac('mineTipple', true, false) as never);
|
||||
|
||||
const cells = view(game).cells;
|
||||
const order = (row: number, col: number): string[] => {
|
||||
const cell = cells.find((c) => c.row === row && c.col === col)!;
|
||||
return [...officeSvg([cell], 0).matchAll(/class="bs-wb (bs-\w+)/g)].map((m) => m[1]!.replace('bs-', ''));
|
||||
};
|
||||
|
||||
// Receives only: the red box sits BEFORE the sign, which is the end an unload arrives at.
|
||||
assert.deepEqual(order(-1, 0), ['red', 'maw', 'maw', 'maw'], 'the red box is not beside MEN');
|
||||
// Ships out only: green before the sign, and no red box at all.
|
||||
assert.deepEqual(order(-1, 1), ['green', 'maw', 'maw', 'maw'], 'the green box is not beside MEN');
|
||||
});
|
||||
|
||||
it('names where the work has got to, in the tooltip', () => {
|
||||
@@ -1465,6 +1502,32 @@ describe('the static build', () => {
|
||||
assert.notEqual(front, back, 'the two ends still read identically, so one is dropped from the list');
|
||||
});
|
||||
|
||||
it('shows where a played train card landed on the timetable', () => {
|
||||
// REPORTED: playing a train card rolls 1D12 for its departure Stage and the card simply left the
|
||||
// hand — the answer arrived only as one line in the history panel. The twelve slots have been in
|
||||
// the Frame all along and only the standalone replay ever drew them.
|
||||
const game = newGame(430);
|
||||
let landed: number | null = null;
|
||||
for (let i = 0; i < 900 && currentActor(game) !== null; i++) {
|
||||
const { options } = actionGroups(game);
|
||||
if (options.length === 0 || !submit(game, options[0]!)) break;
|
||||
if (game.scheduled !== null) {
|
||||
landed = game.scheduled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert.ok(landed !== null, 'no train was ever scheduled');
|
||||
const f = view(game);
|
||||
assert.ok(f.timetable[landed!] !== null, 'the slot the roll reported is empty');
|
||||
// The roll gets a sound, because it is the one die a player rolls and it landed silently.
|
||||
assert.ok(game.cues.includes('schedule'), 'scheduling a train made no sound');
|
||||
// And the panel flashes the slot that changed, marking the moment rather than the state.
|
||||
const html = timetableHtml(f, landed);
|
||||
assert.match(html, /tt-slot[^"]*fresh/, 'the new slot is not flagged');
|
||||
assert.equal((timetableHtml(f, null).match(/fresh/g) ?? []).length, 0, 'the flash must not persist');
|
||||
assert.match(html, new RegExp(`T${f.timetable[landed!]}`), 'the train is not named in its slot');
|
||||
});
|
||||
|
||||
it('draws the side panels from one place, on both screens', () => {
|
||||
// A replay is the game being WATCHED rather than played, so it should look like the game. The
|
||||
// site's viewer had three panels against the play page's eight — no facilities, no blockers, no
|
||||
@@ -1632,12 +1695,13 @@ describe('the Division map shows the whole route', () => {
|
||||
|
||||
it('draws the Division as a line with two ends, never as a loop', () => {
|
||||
// Seating players around a table invites exactly one misreading: that the route joins up. It
|
||||
// does not — trains enter at one Division Point and leave at the other.
|
||||
// does not. Both ends are labelled as ends, not as an entrance and an exit: odd trains run west
|
||||
// and even run east, so each Division Point is a way on AND a way off.
|
||||
for (const players of [1, 2, 3, 4]) {
|
||||
const svg = divisionFor(players);
|
||||
assert.equal((svg.match(/class="bs-stop"/g) ?? []).length, 2, `${players}p has no pair of buffer stops`);
|
||||
assert.match(svg, /trains enter/, `${players}p does not label where trains enter`);
|
||||
assert.match(svg, /trains leave/, `${players}p does not label where trains leave`);
|
||||
assert.match(svg, /west end · in and out/, `${players}p does not label the west end`);
|
||||
assert.match(svg, /east end · in and out/, `${players}p does not label the east end`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user