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
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
Add deterministic record/playback for a run.
Recording captures `(seed, config hash, ordered tick-tagged commands)` and re-simulates on playback — no state snapshots. `DotaFactory.exe --replay <file>` re-plays a recorded run view-only with manual speed/pause.
Reviewed-on: #4
Co-authored-by: Malte Langkabel <malte.langkabel@gmail.com>
Co-committed-by: Malte Langkabel <malte.langkabel@gmail.com>