user card Hand becomes the action surface, the board shows the train, and a reverse stops turning it around, other bug fixes too.
This commit is contained in:
+192
@@ -10,6 +10,198 @@ The target is 20 Revenue over 5 Days.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### A playtest report, worked through
|
||||
|
||||
**Backing up turned the train around.** `facing` is which way the ENGINE points, and it was reset to
|
||||
the direction of travel on every move — so one reverse move silently spun the train about, everything
|
||||
read "forward" again, and a run-around became pointless: you could change ends for free by backing up
|
||||
twice. Running forward the engine leads and points the way it went; backing up it trails, still
|
||||
pointing the way it came, which is the port it arrived through. Both hold around a curve.
|
||||
|
||||
**"drop 1 car(s)" hid an option entirely.** It never said which car, and it read identically for a
|
||||
nose drop and a tail drop — so the action list's duplicate-label filter discarded one outright, and
|
||||
setting out from the front of the train could not be chosen at all. The same failure as the turnout
|
||||
rotation earlier, in a feature added two commits ago to fix the make-up deadlock. Now: *"set out the
|
||||
caboose off the back"*.
|
||||
|
||||
**ABS Signals offered the Office Area.** The card says "any Mainline card", and
|
||||
`checkEnhancementPlacement` reads `placement.col` as a Division NODE index for it — while the
|
||||
candidate list handed it occupied grid cells. So "(0, 1)" was accepted because node 1 happened to be
|
||||
a Mainline card: the label and the meaning were different things. It now offers the Mainline cards by
|
||||
name, *"on the Uncontrolled Siding, out on the Mainline"*.
|
||||
|
||||
**Two T10 chips on one Office.** A train standing at the Office is on the Office grid card AND on an
|
||||
A/D track, so it arrived in both lists and was drawn twice.
|
||||
|
||||
**The train was invisible on the board**, which is what made the switching game unplayable: every
|
||||
decision is about car ORDER — which car comes off next, which end a cut couples onto — and the card
|
||||
showed a name badge. The train is now drawn as it sits in the tray: engine in its place with an arrow
|
||||
for which way it points, cars in order, loaded solid and empty hollow. That arrow is also what makes
|
||||
"(reverse)" mean something.
|
||||
|
||||
**Modifier effects were applied and invisible.** The Ice House and Local Small Groceries both worked
|
||||
— `capacity.outbound` and `laborers` went up — but the card draws `Math.max(1, greenCap)` green
|
||||
boxes, so 0 → 1 looked identical, and laborers were never drawn at all. The Facilities panel now
|
||||
shows laborers, outbound and inbound as numbers with what a Modifier added (`2 +1`), names the
|
||||
Modifier cards beside the industry, and says in the tooltip what the card itself prints. Laborers had
|
||||
been in a hover tooltip only, which is the wrong place for the number that decides every Cargo phase.
|
||||
|
||||
**Coupling was silent and left no trace.** A car simply vanished from the board with only a line of
|
||||
history to say where it went. There are now two new sounds — a knuckle-coupler clank for coupling and
|
||||
a quieter one for setting out — alongside the whistle, bell and conductor.
|
||||
|
||||
**Moves left were reported only in the history panel**, which is the one place a player is not
|
||||
looking while switching. Now beside the buttons, and struck red at zero.
|
||||
|
||||
**A/D tracks were a tooltip.** "3 A/D tracks" with nothing on the card — the number that decides
|
||||
whether the next arrival is an automatic collision. Drawn as pips, filled for taken; there is no room
|
||||
on the card for more rails and the count is what matters.
|
||||
|
||||
**The phase changed under you.** Local Operations ends the moment the last Move is spent and the
|
||||
automatic phases then run themselves, so the page could change between two clicks with no notice. A
|
||||
banner now names the phase it moved to.
|
||||
|
||||
#### What was already right, from the same report
|
||||
|
||||
The car type and colour on the board (read as "cab in red" without being told), the Blocked panel
|
||||
explaining a full industry track, the Facilities panel's accepted car types and spotted cars, and the
|
||||
Division chip's `T10 (2)` with its consist on hover. All four were reported as useful, and none of
|
||||
them changed.
|
||||
|
||||
### Softlock: a train being made up with no visible way to make it up
|
||||
|
||||
Reported at Stage 10 of seed 775569289 — Train 10 at the West Division Point, history saying "now
|
||||
taking cars", and **nothing at all under Your Move**.
|
||||
|
||||
Moving train make-up onto the Division Yard chips took the "Making up …" group out of the action
|
||||
list, and everything that was not a car went with it: the heading naming the train and what its card
|
||||
calls for, and the "no more cars" button. The nine cars the train could take WERE clickable on the
|
||||
yard chips the whole time — nothing on screen said so, and the panel a player looks at was empty.
|
||||
|
||||
The panel is back, and now says where to click: *"Click a car in the Division Yard below to add it —
|
||||
9 kinds it may take are highlighted there."* It carries the pass button when passing is legal, which
|
||||
§7 allows only when the Division Yard is bare — "must make every effort to find a suitable car".
|
||||
|
||||
**The engine was never at fault.** 2065 New Train decisions across 60 campaign games, and not one
|
||||
offered zero options; the pass/place pair covers the phase. The panel still words the third case
|
||||
honestly rather than implying a button that is not there.
|
||||
|
||||
**Two guards, because the obvious one would not have caught it.** A menu-level invariant — every
|
||||
option the engine offers must be reachable through something the menu exposes — passes on this bug,
|
||||
because `makeUp.pass` was in the menu and correct all along. What failed was the page never reading
|
||||
it. So there is also a coarse check that `main.ts` references every field the menu offers: a field
|
||||
nothing reads is either dead or a control that has gone missing. Verified by putting the regression
|
||||
back and watching it fail.
|
||||
|
||||
### Four reports from playing seed 775569289
|
||||
|
||||
**A curve was described as a turnout.** Both read "east-west track with a 45° leg", which is a
|
||||
turnout — a road straight across the card plus a leg off it. A curve has ONE road: in from the east
|
||||
or west edge, along the centre line to the frog, out at 45° through the middle of a north or south
|
||||
edge, and **nothing runs past it**. Which is precisely why it may not be laid in the Running Track,
|
||||
so describing it as though it had a through track contradicted the rule that stops you.
|
||||
|
||||
**A curve in hand showed no preview.** The shapes were read off the card's legal PLACEMENTS, so a
|
||||
card with nowhere legal to go had nothing to draw — and that is exactly when a player most wants to
|
||||
see what the piece is. They now come from the card itself, which is where they belong: what a piece
|
||||
looks like does not depend on whether there is currently a square for it.
|
||||
|
||||
**"Realignment on Mainline card 3"** named a raw node index. It said nothing about which stretch of
|
||||
the Division it meant or what it would do, and it had no tooltip either — because the action list
|
||||
attaches one only when a label happens to contain an em-dash, which this one did not. It now reads
|
||||
|
||||
> Realignment on the Uncontrolled Siding — the second Mainline card west to east; converts it to
|
||||
> Double Track
|
||||
|
||||
and any action naming a card falls back to that card's own description when its label carries no
|
||||
explanation of its own. That was the actual complaint: the same card explained itself perfectly in
|
||||
hand and said nothing in the action list.
|
||||
|
||||
**It offered only one Mainline card, and that was correct.** `REALIGNMENTS` converts Plains, Curves,
|
||||
Uncontrolled Siding and Trestle; the Division on that seed is a Heavy Grade and an Uncontrolled
|
||||
Siding, so only the second could be converted. The engine was right and the label was hiding it —
|
||||
"Mainline card 3" gave no way to tell a considered restriction from a bug. Naming the card fixes the
|
||||
report without changing the rule.
|
||||
|
||||
### The hand is the action surface, and the yard makes up the train
|
||||
|
||||
The action list reached **22 buttons**, and most of it was a cross-product. A card appeared in two
|
||||
panels under two different models: as a *subject* under "Play a card from my hand", which then
|
||||
highlighted squares on the board, and as one flat button per Department under "Discard a card from
|
||||
my hand". Four cards times three Departments was **twelve buttons repeating the same three choices
|
||||
four times**, about 290px of the list. Separately, making up a train offered up to ten buttons
|
||||
reading "add loaded hopper", "add empty boxcar" — while the Division Yard sat on screen already
|
||||
showing exactly those cars by type and load state.
|
||||
|
||||
Both are now on the objects already being looked at, using the pattern board placement always had:
|
||||
**pick the thing, then pick where it goes.**
|
||||
|
||||
- **Every card in hand carries its own verbs.** `play` highlights the squares it may go on, exactly
|
||||
as before; a card needing no square (an Office upgrade, a train, a maneuver) goes down in one
|
||||
click. `discard` lights up the three Department piles as targets — they already show their top
|
||||
card and their depth, which is precisely what you choose between.
|
||||
- **A make-up car is picked off the Division Yard chip** that shows it. The loaded and empty counts
|
||||
are separate targets, because a car of a type and a load state is exactly what the choice is.
|
||||
- The action list keeps what is not about a card or a car: the Local Operations choice, drawing,
|
||||
switching moves, the Freight Agent, and finishing.
|
||||
|
||||
**Measured over a full game of seed 430: the widest action list went from 22 buttons to 5.** A test
|
||||
now walks the same game and fails if it climbs back above 8.
|
||||
|
||||
The rotation step stays where it was and is now the only thing the placement panel shows — the card
|
||||
is picked in the hand and the square on the board, so a rotation is the one question neither of those
|
||||
can ask. Its hover previews, added earlier, are unchanged.
|
||||
|
||||
### A note on the two replay viewers
|
||||
|
||||
`TODO.md` now carries an item to decide between them. The standalone `node src/sim/replay.ts` writes
|
||||
a self-contained HTML file that nothing links to and that `.gitignore` excludes; the site reads JSON
|
||||
saves from `public/replays/`. The standalone one carries the bot's decision trace and a timetable
|
||||
panel, which is debugging material rather than something a player wants. No action taken.
|
||||
|
||||
### A replay now looks like the game it is a replay of
|
||||
|
||||
**"Extra slow" was there and did nothing.** The site's replay viewer builds its interval with
|
||||
whatever the speed select held when play started, and nothing re-read it — so changing pace
|
||||
mid-replay had no effect at all and the pace looked stuck. The standalone replay had always
|
||||
restarted its timer on change; this viewer was missed. Both offer the same five paces, extra slow
|
||||
through very fast, and a test now asserts they stay in step.
|
||||
|
||||
**The turn chart lived on one screen out of three.** Where you are in the Day — the five phases with
|
||||
the violet "you are here" — was in `main.ts` alone, so both replays reported the Day and the phase as
|
||||
two plain strings. The same position looked like a different game depending on which screen you were
|
||||
on. It is now `sim/turnchart.ts`, shared exactly as the board renderers are: the playable page and
|
||||
the site viewer import it, and the standalone replay embeds it by `Function.toString()` because it
|
||||
is a single file with an inline script and cannot import anything.
|
||||
|
||||
**And the side panels were three against eight.** The viewer showed the Division, the Office Area and
|
||||
the log; the play page shows those plus cards in hand, the Department decks, the yards, the blockers
|
||||
and the facilities. A replay could not answer *"why is nothing moving?"* — which is most of what a
|
||||
replay is for. `web/panels.ts` now renders all of them for both pages, and the duplicated CSS is gone
|
||||
from `play.html`.
|
||||
|
||||
Three tests hold it there: both screens must call the same panel renderers, all three must use the
|
||||
shared turn chart and none may keep a private copy of the phase table, and the two viewers must offer
|
||||
the same paces.
|
||||
|
||||
### You could not rotate a turnout at all, and now you can see what you are laying
|
||||
|
||||
**The rotation was being thrown away before it reached the menu.** `actionGroups` drops duplicate
|
||||
labels, and `describeIntent` for a card play said only `play right-hand turnout at (0, 1)` — no
|
||||
rotation in it. So a turnout's two orientations produced the same label and the second was silently
|
||||
discarded. The "choose a rotation" step existed and worked; it was never given more than one
|
||||
rotation to choose between. The label now names the orientation, and both survive.
|
||||
|
||||
**And the buttons are pictures now.** Hovering a rotation draws the piece as it will land on the
|
||||
board, and hovering the card itself draws every shape it could be laid as — which is how a player
|
||||
sees a turnout has two orientations before picking a square at all. Rendered by `officeSvg`, the
|
||||
board's own renderer, on a one-card board: the preview and the board cannot disagree about what the
|
||||
piece looks like, and the rails come from the engine's `connectionsFor`, so a preview cannot promise
|
||||
a shape the placement will not produce.
|
||||
|
||||
`Placeable.spots` carries the links for this. `data-tip-html` on the tooltip renders a figure above
|
||||
the caption; it is only ever set from markup this app builds.
|
||||
|
||||
### Turnouts say what they do, and a curve may not break the Running Track
|
||||
|
||||
**"Right-hand turnout, stem east, through west, diverges north at 45°"** is three pieces of jargon
|
||||
|
||||
Reference in New Issue
Block a user