Say who is playing, what you can press, and where you are in the Stage

Mostly presentation, plus one rules fix found on the way.
This commit is contained in:
Jesse
2026-08-04 08:37:42 -04:00
parent 982952fd6c
commit ec792dfc15
12 changed files with 392 additions and 62 deletions
+24 -6
View File
@@ -604,9 +604,9 @@ function checkPlay(
case 'modifier': {
if (!placement) return 'NO_PLACEMENT';
if (area.grid.has(coordKey(placement))) return 'NOT_CONNECTED';
// §9 — a Modifier is not track. It must sit adjacent to a Facility (one of the nine nearby
// spots) or it does nothing at all, so placing it anywhere else is not a legal play.
return adjacentFacilityCoord(area, placement) ? null : 'NOT_CONNECTED';
// §9 — a Modifier is not track. It must sit adjacent to a Facility THAT CAN HOST IT (one of
// the nine nearby spots) or it does nothing at all, so anywhere else is not a legal play.
return adjacentFacilityCoord(area, placement, card.kind.modifier) ? null : 'NOT_CONNECTED';
}
case 'enhancement': {
if (!placement) return 'NO_PLACEMENT';
@@ -1423,15 +1423,33 @@ function buildFreightFacility(kind: FreightKind): Facility {
* Facility found instead. Modelling the per-Stage choice needs an extra decision point in the
* Load/Unload phase and is not worth it until the mechanic has been played.
*/
function adjacentFacilityCoord(area: OfficeArea, coord: GridCoord): GridCoord | null {
/**
* The neighbouring Facility a Modifier would attach to — and, when a Modifier is named, only one it
* is actually ALLOWED to attach to.
*
* Every Modifier prints its host: a Waiting Area, a Restaurant and a Hotel go beside a Passenger
* Facility, Forklifts beside a Freight House or Packing Sheds, and so on. That was not checked. Any
* square touching ANY facility was offered — so a Waiting Area was legal beside a Mine Tipple and
* `applyModifier` then handed its extra Porter to whichever facility the scan reached first, which
* could be a different one again. The player saw three legal spots for a card that has one.
*/
function adjacentFacilityCoord(
area: OfficeArea,
coord: GridCoord,
modifier?: ModifierKind,
): GridCoord | null {
// Q7 — nothing exists above the Running Track, so §9's "nine nearby spots" is really six.
if (coord.row > area.runningRow) return null;
const hosts = modifier ? modifierProfile(modifier).hosts : null;
for (let dr = -1; dr <= 1; dr++) {
for (let dc = -1; dc <= 1; dc++) {
if (dr === 0 && dc === 0) continue;
const c = { row: coord.row + dr, col: coord.col + dc };
if (c.row > area.runningRow) continue;
if (area.grid.get(coordKey(c))?.facility) return c;
const f = area.grid.get(coordKey(c))?.facility;
if (!f) continue;
if (hosts && !hosts.includes(f.subtype)) continue;
return c;
}
}
return null;
@@ -1583,7 +1601,7 @@ export function isLockedOut(area: OfficeArea, kind: FreightKind): boolean {
/** Applies a Modifier's printed effect to the Facility it was placed beside (content.ts). */
function applyModifier(area: OfficeArea, coord: GridCoord, modifier: ModifierKind): void {
const target = adjacentFacilityCoord(area, coord);
const target = adjacentFacilityCoord(area, coord, modifier);
if (!target) return;
const f = area.grid.get(coordKey(target))?.facility;
if (!f) return;