v0.7.9.1 — the engine was right twice; the screen was not
Gitea#22: the Division map drew every westbound train in the wrong half of its Mainline card. `regionOfTransit` counts from the end a train entered, which is what the collision rules ask; the map wanted "which printed box, left to right" and used the same number, so an eastbound train came out right by luck and a westbound one came out mirrored. It cost a collision — Train 3 was cleared to follow T5 and ran into TX17, which the picture had drawn ahead of T5 rather than behind it. One mirror in `view.ts`, at the boundary the map is drawn from; the collision rules are untouched. Gitea#21: a second tank car would not come off at a refinery, and "Blocked — why nothing is moving" answered by describing the refinery's green box. The real answer was Train 3's printed rule — the Express works one freight car per location — so the refusal was correct and the panel sent the player to spend a Freight Agent action that could not have helped. No rule changed. The panel now names the budget, asking the reducer's own predicate so its words cannot drift from the rule. Both were replayed from the saves attached to the issues and verified in the exact position each report names. The map fix is proved by mutation: reverting the mirror fails two tests, and making the renderer ignore the region fails a third. Every existing region test ran eastbound, where the mirror is the identity, which is why the bug survived them. 891 tests pass, up from 884. Closes #21 Closes #22 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3Qk7uresKCHksdZajXCLg
This commit is contained in:
co-authored by
Claude Opus 5
parent
6058f6c17e
commit
7ade60e21f
+16
-1
@@ -607,7 +607,8 @@ function freightWorkedKey(trayId: TrayId, at: GridCoord): string {
|
||||
return `${trayId}@${coordKey(at)}`;
|
||||
}
|
||||
|
||||
const isFreight = (c: RollingStock): boolean => c.type !== 'coach' && c.type !== 'caboose';
|
||||
/** Exported so the Blocked panel counts a freight car the same way the reducers do (Gitea#21). */
|
||||
export const isFreight = (c: RollingStock): boolean => c.type !== 'coach' && c.type !== 'caboose';
|
||||
|
||||
/**
|
||||
* IS THIS CAR CARRYING A LOAD? A CABOOSE NEVER IS, whatever its `loaded` flag says.
|
||||
@@ -657,6 +658,20 @@ function switchingRefusal(tray: CrewTray): RejectionCode | null {
|
||||
return rulesOf(tray).noSwitching ? 'NO_SWITCHING' : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* WHETHER TRAINS 3/4's PRINTED RULE IS WHAT IS STOPPING THIS CREW WHERE IT STANDS (Gitea#21).
|
||||
*
|
||||
* Exported for the Blocked panel, which needs to say so — and asks `freightBudgetLeft`, the same
|
||||
* predicate the reducer refuses on, rather than rebuilding the key for itself. `narrate.ts` cannot
|
||||
* then drift from the rule it is describing, which is the whole premise of that panel.
|
||||
*/
|
||||
export function freightRuleSpentHere(s: GameState, player: PlayerIndex, trayId: TrayId): boolean {
|
||||
const tray = s.trays.get(trayId);
|
||||
if (!tray || !rulesOf(tray).oneFreightPerLocation) return false;
|
||||
if (tray.position.at !== 'grid') return false;
|
||||
return !freightBudgetLeft(s, player, tray, tray.position.coord, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge freight cars against this train's per-location budget (trains 3/4).
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user