Analysis and reimplementation of Railroad Tycoon 3 The old executable is at ./rt3_wineprefix/drive_c/rt3/RT3.exe Our first task is to understand the executable's high-level control loops and subsystem boundaries well enough to choose good rewrite targets. As we go, we document evidence, keep a curated function map, and stand up Rust tooling that can validate artifacts and later host replacement code. The long-term direction is still a DLL we can inject into the original executable, patching in individual functions as we build them out. The active implementation milestone is now a headless runtime rehost layer that can execute deterministic world work, compare normalized state, and grow subsystem breadth without depending on the shell or presentation path. The current packed-event frontier is broader real grouped-descriptor coverage on top of the existing save-slice, snapshot, overlay-import, compact-control, and symbolic company-target workflows. The runtime already carries selected-company and controller-role context through overlay imports, and real descriptors `2` `Company Cash`, `13` `Deactivate Company`, and `16` `Company Track Pieces Buildable` now parse and execute through the ordinary runtime path, and descriptors `1` `Player Cash` and `14` `Deactivate Player` now join that batch through the same service engine. Synthetic packed records still exercise the same runtime without a parallel packed executor. The first grounded condition-side unlock now exists for negative-sentinel `raw_condition_id = -1` company scopes, and the first ordinary nonnegative condition batch now executes too: numeric-threshold company finance, company track, aggregate territory track, and company-territory track rows can import through overlay-backed runtime context. Exact named-territory binding now executes, and the runtime now also carries the minimal event-owned train roster and opaque economic-status lane needed for real descriptors `8` `Economic Status`, `9` `Confiscate All`, and `15` `Retire Train` to execute through the same path. Descriptor `3` `Territory - Allow All` now executes too, reinterpreted as company-to-territory access rights rather than a territory-owned policy bit. Whole-game ordinary-condition execution now exists too: special-condition thresholds, candidate-availability thresholds, and economic-status-code thresholds now gate imported runtime records through the same service path, and that world-side condition batch now decodes from checked-in metadata instead of fixture-only ids: real special-condition label ids, real economic-status ids, and the recovered `%1 Avail.` candidate template plus candidate-name side strings all lower into the runtime condition model. Checked-in whole-game descriptor metadata now drives the first real world-side effect batch too: special-condition and candidate-availability setters import natively, and descriptor `110` `Disable Stock Buying and Selling` now lowers into the keyed runtime flag `world.disable_stock_buying_and_selling`. The recovered whole-game toggle batch is broader now too: descriptors `111..138`, with descriptor `122` `Limited Track Building Amount` now landing in the bounded `world_restore.limited_track_building_amount` scalar and the remaining boolean lanes lowering into keyed `world_flags`, cover finance/trading, construction, and governance restrictions. Explicit the late recovered special-condition toggles now execute too where current evidence is equally strong: `Use Bio-Accelerator Cars`, `Disable Cargo Economy`, `Disable Train Crashes`, `Disable Train Crashes AND Breakdowns`, and `AI Ignore Territories At Startup`. Whole-game condition decode is broader now too: checked-in world-flag condition ids can lower into `world_flag_equals` gates for boolean equality/inequality forms, so real packed records can gate whole-game effects on existing `world_flags` without fixture-authored placeholder ids. The tracked parity save-slice no longer depends on a raw `unsupported_framing` placeholder either: its remaining residue is now one recovered locomotives-page `real_packed_v1` record that lands in the explicit `blocked_unmapped_world_descriptor` bucket. The next recovered descriptor band is now partially executable too: descriptors `454..456` (`All Steam/Diesel/Electric Locos Avail.`) now lower through checked-in metadata into keyed `world_flags`, while the wider locomotive availability/cost scalar bands are now split more cleanly: the boolean `0/1` availability subset can import through an overlay-backed `RuntimeState.locomotive_catalog` into `RuntimeState.named_locomotive_availability`, while non-boolean availability payloads still remain parity-only. The runtime still carries the save-owned named locomotive availability table directly too: checked-in save-slice documents can populate `RuntimeState.named_locomotive_availability`, and imported runtime effects can mutate that map through the ordinary event-service path without needing full Trainbuy or live-locomotive parity. A parallel event-owned named locomotive cost map now exists too: recovered locomotive-cost descriptors from bands `352..451` and `475..500` can import through the same overlay-backed locomotive catalog into `RuntimeState.named_locomotive_cost`, while cargo-production and territory-access-cost rows remain metadata-rich parity-only families until a later slice grounds an honest landing surface. Explicit unmapped world-condition and world-descriptor frontier buckets still remain where current checked-in metadata stops. Shell purchase-flow, Trainbuy refresh, cached locomotive-rating recomputation, and selected-profile parity remain out of scope. Mixed supported/unsupported real rows still stay parity-only. The PE32 hook remains useful as capture and integration tooling, but it is no longer the main execution milestone. ## Project Docs Bootstrap design and workflow documents live in `docs/`. - `docs/README.md`: handbook index and target hashes - `docs/control-loop-atlas.md`: compatibility index for the split atlas - `docs/control-loop-atlas/`: canonical atlas section files - `docs/setup-workstation.md`: toolchain baseline and local setup - `docs/re-workflow.md`: repeatable reverse-engineering workflow - `docs/function-map.md`: canonical function-map schema and conventions The first committed exports for the canonical 1.06 executable live in `artifacts/exports/rt3-1.06/`. ## Rust Workspace The Rust workspace is split into focused crates: - `rrt-model`: shared types for addresses, function-map rows, and control-loop concepts - `rrt-runtime`: headless runtime state, stepping, normalized event service, and persistence-facing runtime types - `rrt-fixtures`: fixture schemas, loading, normalization, and diff helpers for rehost validation - `rrt-cli`: validation, runtime fixture execution, state-diff tools, and repo-health checks - `rrt-hook`: minimal Windows DLL scaffold for low-risk in-process loading, capture, and later integration experiments under Wine For the current headless runtime smoke path, use `cargo run -p rrt-cli -- runtime summarize-fixture fixtures/runtime/minimal-world-step-smoke.json` or one of the broader runtime fixtures under `fixtures/runtime/`. For the current hook smoke test, run `tools/run_hook_smoke_test.sh`. It builds the PE32 proxy, copies it into the local RT3 install, launches the game briefly under Wine with `WINEDLLOVERRIDES=dinput8=n,b`, and expects `rrt_hook_attach.log` to appear.