v0.4.9 — X,Y coordinates, no-switching can still clear the mainline, Q3 corrected, a clearance bug, three sounds, and the box art
A playtest review of seed 58228926 (day 6), plus one long-standing display complaint and the first real audio beyond a placeholder. - Coordinate labels read X,Y everywhere shown to a player, not the internal Y,X storage order. Display-only. - "No switching" now means may not add or drop cars, not "never touch it" — these trains can still be moved onto Secondary Track to clear the mainline. - Q3 corrected: Expedite governs WHERE a train may be left standing, not WHEN it leaves. The forced same-Stage departure is gone; a new fault costs 1 Revenue if an expedited train is left off the station when a Mainline Phase begins. Resolves "3/4 Express prints a rule it can never use" as a side effect. - evaluateClearance now checks every occupant on a Mainline card before offering a judgment call, instead of returning on whichever it found first — found while explaining a playtest report, fixed with a regression test. - Three new synthesised sounds: arrive, depart, crash. - The splash page shows the box art. Full detail, measurements and reasoning in CHANGELOG.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvU99NEakShRMg3nN3fHAZ
This commit is contained in:
+14
-5
@@ -486,11 +486,14 @@ function freightBudgetLeft(
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a train may do switching work at all (§7).
|
||||
* Whether a train may set out or sort cars (§7).
|
||||
*
|
||||
* Six cards print "no switching" — the two expresses, the Light Engine, the Campaign, Circus and
|
||||
* Military trains. They run the Division; they do not shunt. This covers moving, setting out and
|
||||
* sorting alike, because all three are switching.
|
||||
* Military trains — which means they may not ADD or DROP cars, not that they may never be touched: a
|
||||
* train held at the Office may still need to clear onto Secondary Track ahead of other traffic. So
|
||||
* this covers `switch.dropCars` and `switch.sortConsist` only; `switch.move` handles `noSwitching`
|
||||
* itself, the same way it handles `dropOnly`, because the restriction has to bite on the pick-up a
|
||||
* move would make, not on the move itself.
|
||||
*/
|
||||
function switchingRefusal(tray: CrewTray): RejectionCode | null {
|
||||
return rulesOf(tray).noSwitching ? 'NO_SWITCHING' : null;
|
||||
@@ -626,8 +629,6 @@ export function check(s: GameState, player: PlayerIndex, i: Intent): RejectionCo
|
||||
if (turnOf(s, player).movesRemaining < 1) return 'NO_MOVES_REMAINING';
|
||||
const tray = s.trays.get(i.trayId);
|
||||
if (!tray) return 'NO_SUCH_TRAY';
|
||||
const noSwitch = switchingRefusal(tray);
|
||||
if (noSwitch) return noSwitch;
|
||||
const from = trayCoord(s, i.trayId);
|
||||
if (!from) return 'ILLEGAL_MOVE';
|
||||
const dests = destinationsFor(s, player, i.trayId, from, i.reverse);
|
||||
@@ -652,6 +653,14 @@ export function check(s: GameState, player: PlayerIndex, i: Intent): RejectionCo
|
||||
*/
|
||||
const fresh = dest.couples.slice(ownCutFor(s, player, i.trayId, i.reverse).length);
|
||||
if (fresh.length > 0) {
|
||||
/**
|
||||
* "NO SWITCHING" MEANS NO ADDING OR DROPPING CARS, not "never move". A no-switching train
|
||||
* held at the Office may still need to clear onto Secondary Track ahead of other traffic —
|
||||
* §7 governs coupling, setting out and sorting, and a move that picks nothing up is none of
|
||||
* those. Handled here, alongside `dropOnly`, rather than as a blanket refusal on the intent:
|
||||
* the restriction has to bite on the pick-up itself, the same reasoning as the comment above.
|
||||
*/
|
||||
if (rules.noSwitching) return 'PICKUP_NOT_ALLOWED';
|
||||
if (rules.dropOnly) return 'PICKUP_NOT_ALLOWED';
|
||||
if (rules.pickUpEmptiesOnly && fresh.some((c) => c.loaded)) return 'EMPTIES_ONLY';
|
||||
const freight = fresh.filter(isFreight).length;
|
||||
|
||||
Reference in New Issue
Block a user