Draw freight on the card, and teach the bot to build a railroad
This commit is contained in:
@@ -12,6 +12,7 @@ import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
|
||||
import { cardDescription, describeIntent } from '../src/sim/view.ts';
|
||||
import { officeSvg } from '../src/sim/board-svg.ts';
|
||||
import {
|
||||
actionGroups,
|
||||
actionMenu,
|
||||
@@ -188,6 +189,100 @@ describe('the action menu presents choices the way they are made', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('the board shows freight work happening', () => {
|
||||
it('moves the load across MEN | AT | WORK on the card itself', () => {
|
||||
// Advancing a load changed only the side panel, so the card being worked showed nothing. The
|
||||
// load crossing green -> MEN|AT|WORK -> a spotted car IS freight; the printed cards put these
|
||||
// squares under the track for exactly this reason.
|
||||
const game = newGame(5);
|
||||
const area = game.state.officeAreas.get(0)!;
|
||||
area.grid.set('-1,0', {
|
||||
geometry: { kind: 'facility', facility: 'mineTipple', axis: 'ns' },
|
||||
baseOperationalRail: true, standing: [], modifiers: [], enhancements: [],
|
||||
facility: {
|
||||
kind: 'freight', subtype: 'mineTipple',
|
||||
allows: { outbound: true, inbound: false },
|
||||
outboundBox: [{ type: 'hopper', loaded: true }], inboundBox: [],
|
||||
capacity: { outbound: 1, inbound: 0 },
|
||||
menAtWork: [null, null, null],
|
||||
industryTrack: { length: 2, cars: [{ type: 'hopper', loaded: false }] },
|
||||
laborers: 3, porters: 0, usedThisStage: { laborers: 0, porters: 0 },
|
||||
},
|
||||
} as never);
|
||||
|
||||
const filled = (): string[] => {
|
||||
const cell = view(game).cells.find((c) => c.row === -1 && c.col === 0)!;
|
||||
const svg = officeSvg([cell], 0);
|
||||
return [...svg.matchAll(/class="bs-wb (bs-\w+)( bs-occ)?"/g)].map(
|
||||
(m) => m[1]!.replace('bs-', '') + (m[2] ? '=FULL' : ''),
|
||||
);
|
||||
};
|
||||
|
||||
assert.deepEqual(filled(), ['green=FULL', 'maw', 'maw', 'maw', 'red'], '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.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.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');
|
||||
});
|
||||
|
||||
it('names where the work has got to, in the tooltip', () => {
|
||||
const game = newGame(5);
|
||||
const area = game.state.officeAreas.get(0)!;
|
||||
area.grid.set('-1,0', {
|
||||
geometry: { kind: 'facility', facility: 'mineTipple', axis: 'ns' },
|
||||
baseOperationalRail: true, standing: [], modifiers: [], enhancements: [],
|
||||
facility: {
|
||||
kind: 'freight', subtype: 'mineTipple',
|
||||
allows: { outbound: true, inbound: false },
|
||||
outboundBox: [], inboundBox: [],
|
||||
capacity: { outbound: 1, inbound: 0 },
|
||||
menAtWork: [null, { type: 'hopper', dir: 'out' }, null],
|
||||
industryTrack: { length: 2, cars: [] },
|
||||
laborers: 2, porters: 0, usedThisStage: { laborers: 0, porters: 0 },
|
||||
},
|
||||
} as never);
|
||||
const cell = view(game).cells.find((c) => c.row === -1 && c.col === 0)!;
|
||||
assert.match(cell.what, /a load is on AT/, 'the card does not say where the work has got to');
|
||||
});
|
||||
|
||||
it('keeps the enhancement label clear of the pipeline squares', () => {
|
||||
// `overpass` and `facingPointLocks` are placed `onCard`, so they can land on a facility. At its
|
||||
// old baseline the label printed straight through the green/MEN|AT|WORK/red row.
|
||||
const game = newGame(5);
|
||||
const area = game.state.officeAreas.get(0)!;
|
||||
area.grid.set('-1,0', {
|
||||
geometry: { kind: 'facility', facility: 'mineTipple', axis: 'ns' },
|
||||
baseOperationalRail: true, standing: [], modifiers: [], enhancements: ['overpass'],
|
||||
facility: {
|
||||
kind: 'freight', subtype: 'mineTipple',
|
||||
allows: { outbound: true, inbound: false },
|
||||
outboundBox: [], inboundBox: [],
|
||||
capacity: { outbound: 1, inbound: 0 },
|
||||
menAtWork: [null, null, null],
|
||||
industryTrack: { length: 2, cars: [] },
|
||||
laborers: 2, porters: 0, usedThisStage: { laborers: 0, porters: 0 },
|
||||
},
|
||||
} as never);
|
||||
const cell = view(game).cells.find((c) => c.row === -1 && c.col === 0)!;
|
||||
const svg = officeSvg([cell], 0);
|
||||
|
||||
const enhY = Number(/class="bs-enh" x="\d+" y="(\d+)"/.exec(svg)?.[1]);
|
||||
const boxTop = Math.min(
|
||||
...[...svg.matchAll(/class="bs-wb [^"]*" x="\d+" y="(\d+)"/g)].map((m) => Number(m[1])),
|
||||
);
|
||||
assert.ok(Number.isFinite(enhY) && Number.isFinite(boxTop), 'label or squares are not drawn');
|
||||
// 9px text sits roughly 9px above its baseline, so the baseline itself must clear the squares.
|
||||
assert.ok(enhY <= boxTop, `enhancement label at y=${enhY} prints over the squares at y=${boxTop}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('board highlighting', () => {
|
||||
it('gives every spot a coordinate to highlight', () => {
|
||||
const game = newGame(555);
|
||||
|
||||
Reference in New Issue
Block a user