v0.4.4 — New Game dialog for the opening hand and the three revenue rates, Yard renamed Interchange, and two movement bugs behind a mirrored consist
This commit is contained in:
+69
-1
@@ -12,7 +12,8 @@ import { applyIntent, areaOf } from '../src/engine/apply.ts';
|
||||
import { HAND_LIMIT, STAGES_PER_DAY, lengthProfile, TOTAL_ROLLING_STOCK } from '../src/engine/content.ts';
|
||||
import { legalActions } from '../src/engine/legal.ts';
|
||||
import { createGame } from '../src/engine/setup.ts';
|
||||
import type { GameConfig, GameState } from '../src/engine/state.ts';
|
||||
import type { CrewTray, GameConfig, GameState } from '../src/engine/state.ts';
|
||||
import { railFacingOf } from '../src/engine/state.ts';
|
||||
|
||||
const baseConfig = (over: Partial<GameConfig> = {}): GameConfig => ({
|
||||
mode: 'solitaire',
|
||||
@@ -230,6 +231,14 @@ describe('Mainline Phase (§8)', () => {
|
||||
|
||||
it('moves trains one region per Stage (§8.2)', () => {
|
||||
const s = game();
|
||||
/**
|
||||
* PIN THE TERRAIN. This used to rely on whatever card the seed happened to lay down, and the
|
||||
* moment the RNG stream moved — a different opening deal draws a different number of cards
|
||||
* before the Division is built — seed 1 dealt a 60 card instead of a 30 and the train crossed in
|
||||
* one Stage. What is under test is that crossing takes the card's time, so the card has to be
|
||||
* the test's own: Curves is a 30, which is two Stages for a fast train.
|
||||
*/
|
||||
for (const n of s.division.nodes) if (n.kind === 'mainline') n.card = 'curves';
|
||||
scheduleTrain(s, 1, 2);
|
||||
s.clock.phase = 'newTrain';
|
||||
pump(s);
|
||||
@@ -612,3 +621,62 @@ describe('X18 Circus Train — a point for standing still', () => {
|
||||
assert.ok(!paidAgain(), 'the Circus Train collected a second time for the same set-up');
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('a train on the Division points the way it is running', () => {
|
||||
/**
|
||||
* Nothing reset `facing` when a train left a district, so a crew that had been shunted onto a
|
||||
* north-south spur carried a compass port — 'n' or 's' — out onto the Division with it.
|
||||
*
|
||||
* The Division is east-west, and so is every Office card, so that port exists nowhere the train is
|
||||
* about to be. `movesFor` explores from `facing` and from its opposite, and a card with neither
|
||||
* yields nothing at all: the train arrived at the next Office **unable to switch at all**. It also
|
||||
* drew a ▲ on the Division map, where there is no north.
|
||||
*
|
||||
* A train running the Division has its engine at one end of an east-west railroad, so this is not
|
||||
* a repair applied after the fact — it is the only thing `facing` can mean out there.
|
||||
*/
|
||||
const runningOnTheDivision = (spurFacing: 'n' | 's', direction: 'east' | 'west'): CrewTray => {
|
||||
const s = game();
|
||||
// Straight onto the Mainline card west of the first Office, as a departure would.
|
||||
const index = s.division.nodes.findIndex((n) => n.kind === 'mainline');
|
||||
const node = s.division.nodes[index]!;
|
||||
assert.equal(node.kind, 'mainline');
|
||||
const id = 'shunted';
|
||||
s.trays.set(id, {
|
||||
id, trainNumber: 2, trainIsExtra: false, engineAt: 0, consist: [],
|
||||
direction,
|
||||
// What a Move round a district leaves behind: a real port on the card it was standing on.
|
||||
facing: spurFacing,
|
||||
railFacing: 'w',
|
||||
position: { at: 'grid', seat: 0, coord: areaOf(s, 0).officeCoord },
|
||||
movesUsed: 0,
|
||||
});
|
||||
const tray = s.trays.get(id)!;
|
||||
// Depart it: the Mainline Phase's own path onto the card.
|
||||
s.clock.phase = 'mainline';
|
||||
s.movedThisPhase = new Set();
|
||||
for (let i = 0; i < 3 && tray.position.at === 'grid'; i++) {
|
||||
s.clock.phase = 'mainline';
|
||||
s.movedThisPhase = new Set();
|
||||
advance(s);
|
||||
}
|
||||
assert.notEqual(tray.position.at, 'grid', 'the train never left the district');
|
||||
return tray;
|
||||
};
|
||||
|
||||
it('drops the spur port the moment it reaches the Mainline', () => {
|
||||
for (const spur of ['n', 's'] as const) {
|
||||
for (const direction of ['east', 'west'] as const) {
|
||||
const tray = runningOnTheDivision(spur, direction);
|
||||
assert.equal(
|
||||
tray.facing,
|
||||
direction === 'east' ? 'e' : 'w',
|
||||
`a ${direction}bound train left the district still facing ${spur}`,
|
||||
);
|
||||
assert.equal(railFacingOf(tray), direction === 'east' ? 'e' : 'w');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user