Collapse the two tunnel buttons into a single Tunnel button whose ghost
resolves between Tunnel Entry and Tunnel Exit based on the hovered
position, with a green connection preview.
- Add pure core helper TunnelCompletion (firstTunnelFacing +
resolveTunnelCompletion): the entry/exit completion scans and the
sub-tile cursor tie-break, unit-tested in TunnelCompletionTest.
- Dedup BeltSystem::reevaluateTunnelPairing onto firstTunnelFacing so the
pairing scan rule lives in one place.
- GameWorldView: resolve the ghost type on hover/rotate (matching built
tunnels and construction sites), place the resolved type (drop the old
auto-switch), and draw the matched partner + between-tiles in green.
Hotkey 3 = Tunnel, 4 unused.
- BuildButtonGrid: one "Tunnel" button; tunnel_exit stays player-placeable
so blueprints and cost totals still account for exits.
- Add the green tunnel_preview overlay color (VisualsConfig/Loader/toml).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
Replace REQ-BLD-TUNNEL-AUTO-SWITCH with REQ-BLD-TUNNEL-MODE: one Tunnel
button whose ghost defaults to Tunnel Entry and auto-switches to Tunnel
Exit based on which end the hovered position would complete (via
REQ-BLD-TUNNEL-PAIR), with a green connection preview and sub-tile
mouse-proximity tie-break. Update REQ-UI-HOTKEYS (3 = Tunnel, 4 unused)
and REQ-UI-BUILD-GRID (shared Tunnel button).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
When a belt drag ends with the cursor over a non-belt building or construction
site, the end tile now snaps to the input-capable adjacent tile closest to the
cursor and points into the target, instead of showing an invalid ghost on the
occupied tile.
Adds BuildingSystem::getInputPorts(id) (reusing computeInputPorts, refactored
into a bodyCells+outputPorts core) as the single source of truth for a target's
input-capable adjacent tiles; works for both operational buildings (stored
inputPorts) and construction sites (mask-derived). GameWorldView tracks the
cursor world position and, in recomputeBeltDragPath, picks the nearest input
port and overrides the end tile's rotation. Ghost preview, resolve, and apply
consume the snapped path unchanged.
Implements REQ-BLD-BELT-DRAG snapping-to-a-building.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
Extend REQ-BLD-BELT-DRAG: dragging a belt onto a building/construction site
snaps the end tile to the input-capable adjacent tile closest to the cursor
(geometrically closest, always), with that tile's belt pointing into the
target across the shared input edge, overriding the final-tile orientation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
REQ-BLD-BELT-DRAG now states that rotating the belt with R/Shift+R while a
drag is in progress re-picks the path's primary axis immediately and
re-derives the path, rather than waiting for the next cursor movement.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
Pressing R/Shift+R during a belt drag now re-picks the path's primary axis
right away instead of waiting for the next mouse move, so the previewed L
flips as soon as the belt orientation changes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
Belts are no longer placed on hover during a drag. Left-press anchors the
drag; as the cursor moves, a rectilinear (L-shaped) path of belt ghosts is
previewed from the anchor to the cursor — first leg parallel to the belt's
current orientation, then orthogonal — with each tile auto-oriented to follow
the path. Construction sites are placed on release: new valid tiles are placed
(subject to cumulative affordability), tiles holding only a belt are re-oriented
in place, and occupied/invalid tiles are skipped. Unaffordable tiles show no
ghost. Right-click during a drag cancels it without leaving belt build mode.
Path geometry is factored into a pure computeBeltDragPath() in lib/core with
Catch2 coverage; GameWorldView owns the classification, affordability, and
rendering against live sim state.
Implements REQ-BLD-BELT-DRAG.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
Deferred, L-shaped drag placement for belts: ghosts along the path,
placement on mouse release, auto-oriented tiles, right-click cancels
the drag without exiting belt build mode. Occupied belt cells are
re-oriented in place; unaffordable tiles show no ghost.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc