diff --git a/README.md b/README.md index 2039bc1..81ad8f1 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ minimal PE32 Rust hook that can load into RT3 under Wine without changing behavi Bootstrap design and workflow documents live in `docs/`. - `docs/README.md`: handbook index and target hashes -- `docs/control-loop-atlas.md`: high-level loop and subsystem atlas +- `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 diff --git a/docs/README.md b/docs/README.md index 0ef3327..1776bb6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,7 +16,8 @@ project is already mature. - `setup-workstation.md`: toolchain baseline and local environment setup. - `re-workflow.md`: how to analyze the binary, record findings, and export reusable artifacts. - `function-map.md`: canonical schema and conventions for function-by-function mapping. -- `control-loop-atlas.md`: curated atlas of top-level loops, gateways, and subsystem handoffs. +- `control-loop-atlas.md`: compatibility index for the split atlas, preserving legacy anchors. +- `control-loop-atlas/`: canonical section files for the atlas narrative. - `runtime-rehost-plan.md`: bottom-up runtime replacement plan and milestone breakdown. ## Repo Conventions diff --git a/docs/atlas/README.md b/docs/atlas/README.md index 4b15e56..015728a 100644 --- a/docs/atlas/README.md +++ b/docs/atlas/README.md @@ -1,7 +1,9 @@ # Atlas Notes -These notes are a finer-grained navigation layer over the canonical longform atlas in -[control-loop-atlas.md](/home/jan/projects/rrt/docs/control-loop-atlas.md). +These notes are a finer-grained navigation layer over the canonical split atlas in +[docs/control-loop-atlas/](/home/jan/projects/rrt/docs/control-loop-atlas/README.md), with +[control-loop-atlas.md](/home/jan/projects/rrt/docs/control-loop-atlas.md) retained as a +compatibility index. Current subsystem views: @@ -16,7 +18,9 @@ Scope policy: - [function-map.csv](/home/jan/projects/rrt/artifacts/exports/rt3-1.06/function-map.csv) remains the single canonical ledger. -- [control-loop-atlas.md](/home/jan/projects/rrt/docs/control-loop-atlas.md) remains the canonical - longform narrative. +- [docs/control-loop-atlas/](/home/jan/projects/rrt/docs/control-loop-atlas/README.md) is the + canonical atlas narrative. +- [control-loop-atlas.md](/home/jan/projects/rrt/docs/control-loop-atlas.md) remains the + compatibility index for older links. - These files are curated subsystem views intended to keep active reverse-engineering passes smaller and easier to navigate. diff --git a/docs/atlas/company-and-ledger.md b/docs/atlas/company-and-ledger.md index c7f1376..9990725 100644 --- a/docs/atlas/company-and-ledger.md +++ b/docs/atlas/company-and-ledger.md @@ -2,7 +2,7 @@ Primary atlas sources: -- [control-loop-atlas.md#input-saveload-and-simulation](/home/jan/projects/rrt/docs/control-loop-atlas.md#input-saveload-and-simulation) +- [input-save-load-and-simulation.md](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md) This view isolates the company-side shell panes, linked-transit company maintenance, city-connection news, and annual finance-policy thresholds. diff --git a/docs/atlas/editor-and-site-service.md b/docs/atlas/editor-and-site-service.md index 8f16c5e..61ad918 100644 --- a/docs/atlas/editor-and-site-service.md +++ b/docs/atlas/editor-and-site-service.md @@ -2,8 +2,8 @@ Primary atlas sources: -- [control-loop-atlas.md#input-saveload-and-simulation](/home/jan/projects/rrt/docs/control-loop-atlas.md#input-saveload-and-simulation) -- [control-loop-atlas.md#station-detail-overlay](/home/jan/projects/rrt/docs/control-loop-atlas.md#station-detail-overlay) +- [input-save-load-and-simulation.md](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md) +- [input-save-load-and-simulation.md#station-detail-overlay](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md#station-detail-overlay) This view isolates the map-editor page families, candidate and site-service runtime chain, and the station-detail or station-list read-side consumers. diff --git a/docs/atlas/multiplayer.md b/docs/atlas/multiplayer.md index e798325..1084c5e 100644 --- a/docs/atlas/multiplayer.md +++ b/docs/atlas/multiplayer.md @@ -2,7 +2,7 @@ Primary atlas source: -- [control-loop-atlas.md#multiplayer-session-and-transport-flow](/home/jan/projects/rrt/docs/control-loop-atlas.md#multiplayer-session-and-transport-flow) +- [multiplayer-session-and-transport-flow.md](/home/jan/projects/rrt/docs/control-loop-atlas/multiplayer-session-and-transport-flow.md) Current grounded owners: diff --git a/docs/atlas/route-entry-and-trackers.md b/docs/atlas/route-entry-and-trackers.md index bdea53f..f52e915 100644 --- a/docs/atlas/route-entry-and-trackers.md +++ b/docs/atlas/route-entry-and-trackers.md @@ -2,7 +2,7 @@ Primary atlas sources: -- [control-loop-atlas.md#input-saveload-and-simulation](/home/jan/projects/rrt/docs/control-loop-atlas.md#input-saveload-and-simulation) +- [input-save-load-and-simulation.md](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md) This note isolates the lower route-entry, linked-site, route-link, and auxiliary tracker families that are easy to lose inside the broader runtime section. diff --git a/docs/atlas/runtime-and-world-tools.md b/docs/atlas/runtime-and-world-tools.md index 36f9e2c..10a83e4 100644 --- a/docs/atlas/runtime-and-world-tools.md +++ b/docs/atlas/runtime-and-world-tools.md @@ -2,7 +2,7 @@ Primary atlas sources: -- [control-loop-atlas.md#input-saveload-and-simulation](/home/jan/projects/rrt/docs/control-loop-atlas.md#input-saveload-and-simulation) +- [input-save-load-and-simulation.md](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md) This view keeps together the runtime-side shell input path, world-view tool surfaces, world bring-up pipeline, and the large shell-window families that hang off the recurring frame owner. diff --git a/docs/atlas/startup-shell-and-content.md b/docs/atlas/startup-shell-and-content.md index 65acd05..08957c6 100644 --- a/docs/atlas/startup-shell-and-content.md +++ b/docs/atlas/startup-shell-and-content.md @@ -2,11 +2,11 @@ Primary atlas source: -- [control-loop-atlas.md#crt-and-process-startup](/home/jan/projects/rrt/docs/control-loop-atlas.md#crt-and-process-startup) -- [control-loop-atlas.md#bootstrap-and-shell-service-bring-up](/home/jan/projects/rrt/docs/control-loop-atlas.md#bootstrap-and-shell-service-bring-up) -- [control-loop-atlas.md#shell-ui-command-and-deferred-work-flow](/home/jan/projects/rrt/docs/control-loop-atlas.md#shell-ui-command-and-deferred-work-flow) -- [control-loop-atlas.md#presentation-overlay-and-frame-timing](/home/jan/projects/rrt/docs/control-loop-atlas.md#presentation-overlay-and-frame-timing) -- [control-loop-atlas.md#map-and-scenario-content-load](/home/jan/projects/rrt/docs/control-loop-atlas.md#map-and-scenario-content-load) +- [crt-and-process-startup.md](/home/jan/projects/rrt/docs/control-loop-atlas/crt-and-process-startup.md) +- [bootstrap-and-shell-service-bring-up.md](/home/jan/projects/rrt/docs/control-loop-atlas/bootstrap-and-shell-service-bring-up.md) +- [shell-ui-command-and-deferred-work-flow.md](/home/jan/projects/rrt/docs/control-loop-atlas/shell-ui-command-and-deferred-work-flow.md) +- [presentation-overlay-and-frame-timing.md](/home/jan/projects/rrt/docs/control-loop-atlas/presentation-overlay-and-frame-timing.md) +- [map-and-scenario-content-load.md](/home/jan/projects/rrt/docs/control-loop-atlas/map-and-scenario-content-load.md) Current grounded owners: diff --git a/docs/control-loop-atlas.md b/docs/control-loop-atlas.md index 473da04..b88c1e9 100644 --- a/docs/control-loop-atlas.md +++ b/docs/control-loop-atlas.md @@ -1,3875 +1,60 @@ # Control-Loop Atlas -This atlas is the high-level map for RT3 1.06. It is intentionally broader than the function map: -each section explains who owns a loop, where it starts, what dispatches it, which state blocks -anchor it, and where control is handed to neighboring subsystems. +This atlas is now split by top-level section under +[docs/control-loop-atlas/](/home/jan/projects/rrt/docs/control-loop-atlas/README.md). +This file remains the compatibility index and keeps the original top-level anchors stable for +older links. -Subsystem notes now live under [docs/atlas](/home/jan/projects/rrt/docs/atlas/README.md) for -faster navigation. The longform atlas remains the canonical narrative reference during this -transition. +Subsystem notes still live under [docs/atlas](/home/jan/projects/rrt/docs/atlas/README.md) for +faster cross-cut navigation. + +## Section Index + +- [CRT and Process Startup](/home/jan/projects/rrt/docs/control-loop-atlas/crt-and-process-startup.md) +- [Bootstrap and Shell Service Bring-Up](/home/jan/projects/rrt/docs/control-loop-atlas/bootstrap-and-shell-service-bring-up.md) +- [Shell UI Command and Deferred Work Flow](/home/jan/projects/rrt/docs/control-loop-atlas/shell-ui-command-and-deferred-work-flow.md) +- [Presentation, Overlay, and Frame Timing](/home/jan/projects/rrt/docs/control-loop-atlas/presentation-overlay-and-frame-timing.md) +- [Map and Scenario Content Load](/home/jan/projects/rrt/docs/control-loop-atlas/map-and-scenario-content-load.md) +- [Multiplayer Session and Transport Flow](/home/jan/projects/rrt/docs/control-loop-atlas/multiplayer-session-and-transport-flow.md) +- [Input, Save/Load, and Simulation](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md) +- [Next Mapping Passes](/home/jan/projects/rrt/docs/control-loop-atlas/next-mapping-passes.md) ## CRT and Process Startup -- Roots: `entry` at `0x005a313b`, CRT helpers in the `0x005a2d..0x005ad4..` range, and - `app_bootstrap_main` at `0x00484440`. -- Trigger/Cadence: single process startup path before shell or engine services exist. -- Key Dispatchers: `startup_init_tls_state`, `startup_init_file_handle_table`, - `startup_run_init_callback_table`, `__setenvp`, `startup_build_argv`, - `___crtGetEnvironmentStringsA`, then `app_bootstrap_main`. -- State Anchors: CRT heap and file-handle tables; process environment and argv storage. -- Subsystem Handoffs: exits the generic CRT path at `app_bootstrap_main`, which becomes the first - RT3-owned coordinator. -- Evidence: `artifacts/exports/rt3-1.06/startup-call-chain.md`, - `artifacts/exports/rt3-1.06/function-map.csv`. -- Open Questions: exact ownership boundary between compiler CRT shims and the first game-owned - bootstrap helper; whether any nontrivial startup callbacks seed game globals before - `app_bootstrap_main`. +Detailed section: +[crt-and-process-startup.md](/home/jan/projects/rrt/docs/control-loop-atlas/crt-and-process-startup.md) ## Bootstrap and Shell Service Bring-Up -- Roots: `app_bootstrap_main` at `0x00484440`, `bootstrap_init_shell_window_services` at - `0x004840e0`, and `shell_install_global_controller` at `0x0051ff90`. -- Trigger/Cadence: one-time bootstrap handoff immediately after CRT completion. -- Key Dispatchers: `app_bootstrap_main`, `bootstrap_init_shell_window_services`, - `shell_install_global_controller`, `shell_service_pump_iteration`, graphics config load or - default-init helpers, runtime capability probes, and early shell service initializers under the - `0x004610..0x0053f0..` branch. -- State Anchors: global shell controller pointer `0x006d4024`, sibling display/runtime globals under - `0x006d402c` and `0x006d4030`, and host capability flags gathered by - `bootstrap_probe_system_profile`. -- Subsystem Handoffs: after the global shell controller has been installed the bootstrap path enters - the repeating `shell_service_pump_iteration` loop, which services shell-state work and hands each - iteration down into the controller frame path; when the shell lifetime ends this same bootstrap - path tears the shell bundle down and returns to `app_bootstrap_main`. -- Evidence: `startup-call-chain.md`, function-map rows for `app_bootstrap_main`, - `bootstrap_init_shell_window_services`, `shell_install_global_controller`, - `shell_service_pump_iteration`, `shell_load_graphics_config_or_init_defaults`, - `shell_reset_display_runtime_defaults`, and related graphics setup helpers. -- Open Questions: whether gameplay or in-engine world stepping later escapes this bootstrap-owned - shell loop entirely, or whether gameplay entry still rendezvous with the same outer coordinator - before the shell bundle is destroyed. +Detailed section: +[bootstrap-and-shell-service-bring-up.md](/home/jan/projects/rrt/docs/control-loop-atlas/bootstrap-and-shell-service-bring-up.md) ## Shell UI Command and Deferred Work Flow -- Roots: shell callback paths that converge on `shell_dispatch_ui_command` at `0x00464410`. -- Trigger/Cadence: event-driven UI command dispatch plus deferred-message queue flushing during - shell activity. -- Key Dispatchers: `shell_dispatch_ui_command`, `shell_enqueue_deferred_work_message`, - `shell_post_deferred_message_type5`, `shell_post_deferred_message_type6`, - `shell_enqueue_deferred_message_type4`, `shell_enqueue_deferred_message_type1`. -- State Anchors: shell object at `0x0062be68`, queue roots around `[this+0x11369d]`, - `[this+0x1136a1]`, and `[this+0x1136a5]`, global routing gates at `0x006d4034`, and the separate - detail-panel controller rooted at `0x006d0818`. -- Subsystem Handoffs: routes into graphics config, scenario-text export, overlay generation, - multiplayer UI, shell detail windows such as `EditorPanel.win` and `TrainDetail.win`, and - presentation-facing deferred work later drained by `shell_service_frame_cycle`. -- Evidence: function-map shell rows around `0x00464410`, `0x004d4500`, `0x004ddbd0`, and - `0x0051f1d0..0x0051f460`. -- Open Questions: whether the shell command dispatcher is also used by hotkeys or only by UI - callback tables; the current `0x006d0818` detail-panel path looks shell-only and does not yet - explain gameplay world entry. +Detailed section: +[shell-ui-command-and-deferred-work-flow.md](/home/jan/projects/rrt/docs/control-loop-atlas/shell-ui-command-and-deferred-work-flow.md) ## Presentation, Overlay, and Frame Timing -- Roots: the bootstrap-owned `shell_service_pump_iteration` at `0x00483f70`, the shell-state service - pass `shell_state_service_active_mode_frame` at `0x00482160`, the installed global shell - controller at `0x006d4024`, the pending frame-cycle owner `shell_service_frame_cycle` at - `0x00520620`, and the frame-time history path under `shell_update_frame_time_history` at - `0x0051fd70`. -- Trigger/Cadence: recurring bootstrap-owned shell service work once the active mode, controller - window, and display runtime are live; special modal or content-building paths can also force - immediate frame servicing inside that broader cadence. -- Key Dispatchers: `shell_service_pump_iteration`, `shell_state_service_active_mode_frame`, - `shell_service_frame_cycle`, `shell_refresh_presentation_frame`, - `shell_update_frame_time_history`, `shell_get_smoothed_frame_scalar`, - `shell_set_gamma_ramp_scalar`, and overlay builders such as - `shell_queue_single_world_anchor_overlay`, `shell_queue_world_anchor_overlay_list`, and - `shell_queue_indexed_world_anchor_marker`. -- State Anchors: shell state at `0x006cec74`, active mode pointer `0x006cec78`, shell frame history - ring at `0x006d403c`, display/runtime state inside the controller block near `[this+0x114282]` and - `[this+0x11428a]`, presentation service pointer at `[this+0x0c]`, and the native controller window - handle at `[this+0x00]`. -- Subsystem Handoffs: the bootstrap-owned pump runs shell-bundle polling and shell-state maintenance - before the shell-state pass synchronizes active-mode helpers and modal-status work and dispatches - the controller frame cycle, which then consumes world/object state for overlays and presentation - refresh, uses the controller window handle for one-time `ShowWindow` and related UI interaction, - and drains the deferred work queues at the end of the cycle. -- Evidence: function-map rows for `shell_service_pump_iteration`, - `shell_state_service_active_mode_frame`, `shell_service_frame_cycle`, - `shell_flush_deferred_work_queues`, frame history, gamma ramp, world-anchor overlay builders, and - graphics runtime helpers. -- Open Questions: how simulation cadence rendezvous with the shell presentation cadence once - gameplay takes over and whether gameplay stepping exits this shell-owned controller path entirely. +Detailed section: +[presentation-overlay-and-frame-timing.md](/home/jan/projects/rrt/docs/control-loop-atlas/presentation-overlay-and-frame-timing.md) ## Map and Scenario Content Load -- Roots: `shell_map_file_entry_coordinator` at `0x00445ac0`, the larger active-mode profile owner - `shell_active_mode_run_profile_startup_and_load_dispatch` at `0x00438890`, the shell-mode - switcher `shell_transition_mode` at `0x00482ec0`, the first grounded world-entry branch - `world_entry_transition_and_runtime_bringup` at `0x00443a50`, - `shell_map_file_world_bundle_coordinator` at `0x00445de0`, reference-database setup via - `map_bundle_open_reference_databases` at `0x00444dd0`, and narrower loaders such as - `map_load_geographic_label_database` and `map_load_city_database`. -- Trigger/Cadence: shell tutorial launch, editor or detail-panel file actions through `fileopt.win`, - map-scenario open paths, and scenario-text export batch commands. -- Key Dispatchers: `shell_map_file_entry_coordinator`, - `shell_active_mode_run_profile_startup_and_load_dispatch`, `shell_transition_mode`, - `world_entry_transition_and_runtime_bringup`, `world_runtime_release_global_services`, `shell_map_file_world_bundle_coordinator`, - `map_bundle_open_reference_databases`, `map_load_geographic_label_database`, - `map_load_city_database`, `scenario_text_export_build_language_file`, - `scenario_text_export_report_language_file`, `scenario_text_export_batch_process_maps`. -- State Anchors: shell-side file staging buffers at `0x0062bee0` and `0x0062bec4`, shell and mode - globals at `0x006cec74` and `0x006cec78`, world object root `0x0062c120`, map bundle state - allocated through `0x00530c80`, and geography tables rooted at `0x0062b2fc` and `0x0062b268`. -- Subsystem Handoffs: the shared `fileopt.win` dialog rooted at `0x004dc670` now looks like the - shell-side selector above the two broad file coordinators. Its message handler sets `0x006d07f8` - for the load or restore side or `0x006d07ec` for the save or package side before the detail-panel - transition manager routes into `shell_map_file_entry_coordinator` or - `shell_map_file_world_bundle_coordinator`. The former unresolved third flag at `0x006d07f0` is now - accounted for too: it escapes into the standalone `SettingsWindow.win` path through - `shell_open_settings_window` rather than another map or save verb. The broad coordinators now hand - their interactive work through the shared `filerqst.win` helper at `0x004dd010`, and that helper - gives the extension split a firmer shape. The paired editor-map path is now grounded as `.gmp` - through load mode `4` and save mode `3`. The remaining non-editor families are no longer anonymous - either: `.gmc` is the campaign-scenario branch, backed both by the campaign-screen resignation - prompt on `0x006cec7c+0xc5` and by the numbered `%s%02d.gmc` save helper at `0x00517c70`; `.gmx` - is the sandbox branch, backed by the shell-side `The briefing is not available in sandbox games.` - restriction on `0x006cec7c+0x82`; and the default `.gms` branch is therefore the standalone - scenario family. When a live runtime world is already active the same helper bypasses those - non-runtime extensions and forces the `.smp` runtime-state branch instead. The auxiliary save-side - mode `11` is tighter now too: it still maps to `.gmt`, but instead of looking like another - gameplay save family it conditionally diverts into the same `.gmt` preview-surface pipeline owned - by the Multiplayer preview dataset object at `0x006cd8d8`, and only falls back to the normal - reference-bundle path when that dataset object is absent. The shell-side mode owner above those - file coordinators is clearer now too. `shell_transition_mode` no longer reads like a generic mode - switch: its ABI is now grounded as a `thiscall` with two stack arguments because the body reads - the requested mode from `[esp+0x0c]` and returns with `ret 8`. The grounded world-entry - load-screen call shape is `(4, 0)`, not a one-arg mode switch. The second stack argument is now - tighter too: current local evidence reads it as an old-active-mode teardown flag, because the - `0x482fc6..0x482fff` branch only runs when it is nonzero and then releases the prior active-mode - world through `0x434300`, `0x433730`, and the common free path before clearing `0x006cec78`. - The later world-entry reactivation branch correspondingly uses `(1, esi)` rather than `(1, 0)`. - The current live hook probes now push the remaining auto-load gap much later too: on the - hook-driven path `shell_transition_mode(4, 0)` returns cleanly, and the full old-mode teardown - stack under `0x5389c0` now returns too, including `0x5400c0`, the `0x53fe00 -> 0x53f860` - remove-node sweep over `[object+0x74]`, and the nearby mode-`2` teardown helper `0x00502720`. - The same live run now also reaches and returns from `shell_load_screen_window_construct` - `0x004ea620` and the immediate shell publish through `0x00538e50`. - Its constructor jump table is tighter now too: mode `1` is not the direct `Game.win` - constructor, but the startup-dispatch arm rooted at `0x483012`; mode `2` enters `Setup.win`, - mode `3` enters `Video.win`, mode `4` enters the plain `LoadScreen.win` branch at `0x4832e5`, - mode `5` enters `Multiplayer.win`, mode `6` enters `Credits.win`, and mode `7` enters - `Campaign.win`. The important static correction is that the startup-runtime slice - `0x004ea710 -> 0x0053b070(0x46c40) -> 0x004336d0 -> 0x00438890` belongs to mode `1`, not mode - `4`. Mode `4` only constructs and publishes the `LoadScreen.win` object through `0x004ea620` - and `0x00538e50`. The older hook-driven `(4, 0)` path therefore was not mysteriously skipping - the startup-runtime object; it was entering the wrong jump-table arm for that work. The caller - split above that owner is tighter now too: - `world_entry_transition_and_runtime_bringup` reaches the same owner at `0x443b57` with `(0, 0)` - after dismissing the current shell detail panel and servicing `0x4834e0(0, 0)`, while the - saved-runtime path at `0x446d7f` does the same before immediately building the `.smp` bundle - payloads through `0x530c80/0x531150/0x531360`. That makes the `LoadScreen.win` startup lane the - only currently grounded caller that enters `0x438890` with `(1, 0)` instead of `(0, 0)`. The - remaining runtime uncertainty is narrower now too: the plain-run logs still show the plain - `LoadScreen.win` state under `(4, 0)`, and the corrected allocator-window run now reinforces the - same read because the post-construct allocator stream stays empty instead of showing the expected - `0x46c40` startup-runtime allocation. The first lower allocator probe on `0x005a125d` was not - trustworthy because that shared cdecl body sits behind the thunk and the initial hook used the - wrong entry shape, and the first direct thunk hook was also not trustworthy because a copied - relative-`jmp` thunk cannot be replayed through an ordinary trampoline. But the later corrected - thunk run plus the jump-table decode now agree: the next meaningful hook-driven test is mode - `1`, not mode `4`. - `mode_id = 2`, and it never advanced into `ready gate passed`, staging, or transition. So that - run did not actually exercise the `0x0053b070 -> 0x004336d0 -> 0x00438890` subchain at all. - The next runtime pass now lowers the ready-poll defaults to `1` and `0` and adds an explicit - ready-count log so the mode-`4` startup lane either stages immediately or shows exactly how far - the gate gets. That adjustment worked on the next run: the hook now stages and completes the - `shell_transition_mode` path again, with `LoadScreen.win` construction and publish returning - cleanly. But the post-publish startup subchain is still unresolved: there is still no trusted - `0x46c40` allocator hit, no direct `0x004336d0` entry, and no direct `0x00438890` entry. So - the next clean runtime boundary is the tiny `LoadScreen.win` scalar setter at `0x004ea710`, - which sits immediately before the `0x0053b070` allocation in the static mode-`4` branch. The - immediate next runtime check is even more concrete than the helper hook, though: inspect the - state that `0x004ea710` should leave behind. The hook now logs the post-transition - `LoadScreen.win` singleton, its field `[+0x78]`, `0x006cec78`, the shell state's `[+0x0c]` - active-mode object field, and the startup selector. If `0x004ea710` really ran on the mode-`4` - branch, `[LoadScreen.win+0x78]` should no longer be zero after `shell_transition_mode` returns. - The latest run answered that directly: after transition return, `field_active_mode_object` is - still the `LoadScreen.win` singleton, `0x006cec78` is still null, `[LoadScreen.win+0x78]` is - still zero, and the startup selector is still `3`. So the current best read is that RT3 is - still parked in the plain `LoadScreen.win` state at transition return rather than having entered - the separate runtime-object path yet. That shifts the best next runtime boundary from “deeper - inside `shell_transition_mode`” to “what later active-mode service tick, if any, promotes the - load-screen object into the startup-dispatch path.” The next run now logs the first few - shell-state service ticks after auto-load is attempted with that same state tuple - (`0x006cec78`, `[shell_state+0x0c]`, `0x006d10b0`, `[LoadScreen.win+0x78]`, selector), so the - next question is very narrow: does one later service tick finally promote the plain - `LoadScreen.win` state into the startup-runtime object path, or does it stay frozen as-is? The - internal selector split in `0x438890` is tighter now too: `[0x006cec7c+0x01]` is a separate - seven-way startup selector, not the shell mode id. Values `1` and `7` load `Tutorial_2.gmp` and - `Tutorial_1.gmp`, values `3/5/6` collapse into the same profile-seeded file-load lane through - `0x445ac0([0x006cec7c]+0x11, 4, &out_success)`, value `2` is a world-root initialization lane - that allocates `0x0062c120` and then forces selector `3`, and value `4` is the setup-side world - reset or regeneration lane that rebuilds `0x0062c120` from `0x006d14cc/0x006d14d0` before later - world setup continues. The write side is tighter now too: `Campaign.win` writes selector `6`, - `Multiplayer.win` writes selector `3` on one pending-status path, and the larger `Setup.win` - dispatcher writes selectors `2`, `3`, `4`, and `5` on its validated launch branches. That makes - the file-load subfamily read less like one generic save-open branch and more like a shared - profile-file lane reused by setup, multiplayer, and campaign owners. The world-entry owner - boundary is tighter now too: `world_entry_transition_and_runtime_bringup` at `0x00443a50` no - longer stops at the initial shell transition and world allocation head. The same grounded - function continues through the larger post-load generation tail up to `0x00444dc2`, which means - the later `Setting up Players and Companies...` and neighboring post-load passes are not - floating raw callsites after all. That same owner now clearly covers the event-runtime refresh - through `0x433130`, chairman-profile materialization through `0x437220`, neighboring route and - tracker refresh families, and the one-shot kind-`8` runtime-effect service through `0x432f40` - before clearing shell-profile latch `[0x006cec7c+0x97]`. The `Setup.win` dispatcher - is less opaque now too: the early `0x0bc1..0x0c24` family is mostly fixed submode selection above - `0x00502c00`, except for the separate `0x0bc2/0x0bc5/0x0bc6/0x0bc7` shell-open quartet above - `0x00501f20`; `0x0c1f` is the settings-window escape; `0x0c1e/0x0c20/0x0c22` are direct shell - requests into `0x00482150`; the fixed submode buttons now have concrete lower targets such as - `0x0bc1/0x0bc8 -> 15`, `0x0bc3 -> 16`, `0x0bc4 -> 1`, `0x0c80 -> 13`, `0x0c1c -> 17`, - `0x0c1d -> 2`, `0x0c24 -> 14`, `0x0c81 -> 14`, `0x0c82 -> 6`, `0x0c83 -> 10`, and - `0x0c84 -> 12`; the - `0x0ce6/0x0ce7/0x0d49/0x0d4a/0x0e82/0x0e83` branches are bounded list or slider adjustments on - staged setup fields; and the later `0x0dca/0x0dcb/0x0de9/0x0df3/0x0e81/0x0f6f/0x0f70` controls - are the explicit selector-writing launch buttons rather than one anonymous validated-launch blob. - The constructor-side callbacks are tighter too: control `0x0ce8` is a table-driven payload-label - draw callback above `0x00502030`, not another launch root, and controls `0x0e86` and `0x0e87` - do not select more setup roots; they update the persisted shell-state selector pairs at - `[0x006cec74+0x233/+0x237]` and `[0x006cec74+0x23b/+0x23f]` through `0x00502160` and - `0x005021c0`, then immediately save config through `0x00484910(1)`. The constructor body is - tighter too: it seeds the initial `Setup.win` state by running `0x502910`, `0x502550`, and - `0x502c00(1)` before the user interacts with the window, installs `0x0c80..0x0c86` and - `0x0f6f..0x0f71` as homogeneous button bands, and treats `0x0e88` as one separate special - control with retuned float fields rather than another ordinary launch root. The remaining - optional constructor child `0x0bd0` is tighter now too: it is built from a separate template - block and optional owned heap object before registration, not another hidden setup-root button. - The generic shell helper layer beneath that constructor is tighter now too: `0x53fa50` is the - shared resource-bind and child-list initialization helper, `0x53f830` is the child-control - lookup-by-id helper over the intrusive list at `[this+0x70]`, `0x558130` is the child-control - finalizer that stamps the owner pointer and resolves localized captions before the control goes - live, and `0x53f9c0` is the ordered child-control registration helper used by the optional - `0x0bd0` branch and other shell dialogs. - The submode selector itself is tighter now too because its button-state lane is mostly decoded: - `0xbc5` tracks submode `15`, `0xbc6` tracks `16`, `0xbba` tracks `2`, `0xbbb` tracks `3`, - `0xbc3` tracks `13`, `0xbbc` groups `3/4/5`, `0xbbd` tracks `4`, `0xbbe` tracks `5`, `0xbbf` - groups `6/12/14`, `0xbc0` tracks `7`, `0xbc1` tracks `8`, `0xbc2` tracks `9`, `0xe75` tracks - `10`, and `0xf6e` tracks `17`. RT3.lng and the setup art families now also make several of those - top-level roots read less like anonymous ids and more like real menu panels: submode `1` is the - strongest current landing-panel fit, `2` is the `Single Player` root, `7/8/9` are the - `Editor` / `New Map` / `Load Map` family, `15` is `Extras`, and `17` is `Tutorial`. By - elimination against the separate shell `Credits.win` mode, the remaining top-level `Setup.win` - roots now most safely read as `13 = Multi Player` and `16 = High Scores`. - The file-backed side is tighter too: `0x502c00` now maps submodes exactly as `4 -> dataset 5`, - `9 -> 4`, `6 -> 8`, `10 -> 6`, `12 -> 10`, and `14 -> 9`, so the saved-game-backed family is - no longer one blurred list pane but a small set of stable dataset variants above - `0x4333f0/0x4336a0`. - The file-list builder under that pair is tighter too: `0x4333f0` no longer just emits unsorted - `0x25a`-byte rows with raw names at `+0x0` and normalized labels at `+0x12d`. After the scan it - now clearly re-enters `0x51dc60`, which is a generic adjacent-swap insertion sort over fixed - records; in this setup-side caller it receives `record_size = 0x25a` and `key_offset = 0x12d`, - so the resulting `Setup.win` rows are sorted by display label rather than by the raw filename. - The file-backed header split is tighter too: `0x5027b0` now maps the top header-control ids as - `4 -> 0xd4b`, `9 -> 0xde8`, `6/12/14 -> 0xdf2`, and `10 -> 0xe85`. RT3.lng closes one earlier - mistake here: those values are local setup control or resource ids, not localized text ids. - The setup art bundle now tightens that family split one step further too: under `rt3_2WIN.PK4` - the distinct file-backed setup art families are the shared `Setup_Load` lane and the separate - `Setup_Sandbox` lane, which matches the selector-side evidence that mode `10` is the - sandbox-backed `new` list while mode `12` is its `load` sibling. Combined with the builder at - `0x4333f0`, that shows only submodes `4` and `10` using the alternate localized-stem list-label - path; `6`, `9`, `12`, and `14` keep the direct filename-normalization lane. - The `rt3_2WIN.PK4` extraction path is grounded a bit more cleanly now too: current `pack4` - samples use a shared `0x03eb` header, a fixed `0x4a`-byte directory entry stride, and a payload - base at `8 + entry_count * 0x4a`. In the checked UI bundle the entry table is contiguous and - `Campaign.win` extracts cleanly at directory index `3` with payload length `0x306a`. - The extracted `.win` payload family now has one narrow shared shape too: `Campaign.win`, - `CompanyDetail.win`, and `setup.win` all share the same first `0x50` bytes at offsets - `0x00`, `0x0c`, `0x10`, `0x14`, `0x34`, `0x38`, `0x40`, and `0x48`, while - `CompanyDetail.win` and `setup.win` also carry an inline root `.imb` name immediately at - `0x51`. Current resource scans show `Campaign.win` embedding the `litCamp*/Ribbon*` family, - `CompanyDetail.win` embedding mainly `CompanyDetail.imb`, `GameWindow.imb`, and `Portrait.imb`, - and `setup.win` embedding the broader `Setup_Background/Buttons/New_Game/Load/Sandbox` art - families. The control records between those strings are still undecoded, but the resource-record - shell itself is tighter now: all checked `.win` samples use the same three-word prelude prefix - `0x0bb8, 0x0, 0x0bb9`, and the fourth prelude word matches `resource_name_len + 1`. The next - word after the terminating NUL then behaves like a per-record selector lane. In `setup.win` - the dominant `Setup_Buttons.imb` family alternates between `0x00040000` and the incrementing - `0x00010c1c..0x00010c86` series with dominant inter-record strides `0xb7/0xdb`; in - `Campaign.win` the `litCamp*/Ribbon*` family carries the incrementing `0x0004c372..0x0004c38e` - selector block with dominant `0x158/0x159` and `0xb2/0xb3` strides. That campaign lane is now - directly aligned to the executable-side control ids too: the low 16 bits of - `litCamp1..16` map exactly to `0xc372..0xc381`, and the low 16 bits of `Ribbon1..16` map - exactly to `0xc382..0xc391`, matching the `Campaign.win` progress and selector control bases - already grounded from `RT3.exe`. The fuller selector export now tightens the auxiliary families - too: `litArrows.imb` covers `0xc36c..0xc371` exactly and `litExits.imb` covers - `0xc397..0xc39a` exactly, matching the constructor-side six-control arrow strip and four-control - exit strip. The second post-name dword is tighter now too: its middle 16-bit lane groups those - same `Campaign.win` records under `0xc368`, `0xc369`, `0xc36a`, and `0xc36b`, which matches the - four page-strip controls and cleanly buckets the first five campaign entries, the next five, the - next three, and the final three under the same page families. There are still no `.imb` - selector records for `0xc393..0xc396` or `0xc39b`, which makes those message-side page-write - controls look more like structural buttons than art-backed repeated resource records. - The grouped `3/4/5` family is narrower now too: `0x0ce5` is no longer part of it, because that - control writes selector `3` and then selects submode `9` as the `Load Map` sibling. The nearby - `0x0dcb` branch instead conditionally selects submode `5` or `3`, which keeps `3` as the - strongest current `New Game` / `Options` companion and `5` as the strongest current `Sandbox` - companion. The file-backed single-player side is tighter in the same way now: modes `4` and `10` - are the only siblings using the alternate localized-stem row-label path, so they now read most - safely as the two setup-local template or profile list variants rather than ordinary save lists. - Mode `10` is the stronger one of the pair because neighboring validated launch control `0x0e81` - both routes into selector `5` and sets sandbox byte `[0x006cec7c+0x82] = 1`, which makes it the - strongest current fit for the setup-local `New Sandbox` list. The distinct `Setup_Sandbox` art - family in `rt3_2WIN.PK4` now reinforces that same split one step further, which makes mode `12` - the strongest closed fit for the paired `Load Sandbox` lane; mode `4` is therefore the strongest - remaining non-sandbox peer in that same pair and now most safely reads as the setup-local `New - Scenario`-style chooser. Modes `6`, `12`, and `14` now tighten one step further as the three - selector-`3` direct-filename setup-local `load` siblings because they stay on the direct - filename-normalization lane, share the same `0xdf2` header family, and clear the same - presence-style latch `[0x006cec7c+0x97]`; mode `14` is the strongest current landing panel for - that cluster because `0x0c24` jumps to it directly while `0x0c82` and `0x0c84` only reach the - sibling modes `6` and `12` from inside the same load family. Current control-pairing and - setup-art evidence now make `12 = Load Sandbox` the strongest closed per-submode assignment. The - remaining non-sandbox pair is closed now too: the deeper bundle filter at `0x433260` - distinguishes dataset `9` from dataset `8` by one extra nonzero payload-flag family, and the - editor-side metadata path now grounds `[0x006cec78+0x66de]` as the direct `Campaign Scenario` - checkbox bit because `editorDetail.win` ties control `0x5b6e` to localized ids `3160/3161`. - That makes dataset `9` the campaign-designated load family and dataset `8` the ordinary scenario - load family, so `14 = Load Campaign` and `6 = Load Scenario` now read as grounded rather than - residual. `0x502910` is - tighter in a - corrective way too: it is not a mode-`3`-only helper after all, but the shared non-file-backed - payload panel that formats - `0xcf3/0xcf4/0xcf5/0xd4f`, mirrors option byte `[0x006cec7c+0x7d]` into `0x0ce9..0x0ced`, - rebuilds row host `0x0ce8` from payload bytes `[+0x31b/+0x31c]`, and mirrors live row markers - into `[0x006cec7c+0x87]`. That makes mode `3` just one user of the shared payload-driven panel, - not the sole owner of it. - The payload-helper cluster under that panel is tighter now too: `0x502220` does not just - republish labels and the preview surface. It first re-enters - `shell_setup_load_selected_profile_bundle_into_payload_record` `0x442400`, which clears one full - `0x100f2`-byte setup payload record, builds a rooted path from the staged profile stem, opens the - selected bundle through `0x530c80`, and then reads either the ordinary saved-profile chunk family - or the map-style chunk family through `0x531150/0x531360` depending on the selected extension - shape. Only after that does `0x502220` copy payload fields `+0x14/+0x3b2/+0x3ba/+0x20` into the - staged runtime profile through `0x47be50`, which in turn normalizes the payload category bytes at - `[payload+0x31a + row*9]` and the local marker-slot bytes at `[payload+0x2c9..]` through - `0x47bc80`. The copied-field consumer split is tighter now too: payload `+0x14` becomes staged - profile `[0x006cec7c+0x77]`, which is the visible setup scalar later formatted into controls - `0x0e84` and `0x0d4f` and adjusted by the `0x0d49/0x0d4a` pair; payload `+0x3b2` becomes - `[0x006cec7c+0x79]`, the live-row threshold that the payload-row draw callback uses to choose - style slot `0x18` versus `0x19`; and payload `+0x3ba` becomes `[0x006cec7c+0x7b]`, the current - scroll or row-index lane adjusted by the `0x0ce6/0x0ce7` pair. So the known setup-side payload - consumers still stop well before the later candidate table, but the early copied lanes are no - longer anonymous. The adjacent region-side worker family is tighter in a negative way too: the setup - payload path now gives one useful upper bound on the newer candidate-availability source block - too. The map-style setup loader is definitely pulling chunk families `0x0004/0x2ee0/0x2ee1` - into one large `0x100f2`-byte payload record, and the fixed `0x6a70..0x73c0` candidate table - clearly lives inside the same broad file family; but the grounded setup-side consumers we can - actually name after that load still only touch earlier payload offsets such as `+0x14`, - `+0x20`, `+0x2c9`, `+0x31a`, `+0x3ae`, `+0x3b2`, and `+0x3ba`. So the current evidence is - strong enough to say the candidate table is probably housed inside the setup payload family, but - not yet strong enough to name one setup-side consumer that reads the `0x6a70` header or the - fixed-width entries directly. The newer fixed-offset compare pass tightens that lower setup slice - too: across the checked map/save pairs `Alternate USA.gmp -> Autosave.gms`, - `Southern Pacific.gmp -> p.gms`, and `Spanish Mainline.gmp -> g.gms`, the known setup payload - lanes `+0x14` and `+0x3b2` are preserved map-to-save on the same scenario-family split as the - later candidate-table headers (`0x0771/0x0001`, `0x0746/0x0006`, `0x0754/0x0001`), while - `+0x3ae` stays fixed at `0x0186` and `+0x3ba` stays fixed at `1` across all six files. By - contrast, `+0x20` does not survive as one shared source value (`0xd3 -> 0xb4`, - `0x6f -> 0x65`, `0xe3 -> 0x78` across those same pairs). So the current best read is that the - setup payload mixes preserved scenario metadata and later save-variant state well before the - `0x6a70` candidate table, rather than acting as one uniformly copied prelude. - The adjacent region-side worker family is tighter in a negative way too: the setup - payload loader is now clearly separate from the broader region-building and placement cluster - around `0x422320..0x423d30`, whose current grounded helpers now include `0x422320`, `0x4228b0`, - `0x422900`, `0x422a70`, `0x422be0`, `0x422ee0`, `0x4234e0`, `0x4235c0`, and - `world_region_refresh_cached_category_totals_and_weight_slots` `0x423d30` rather than one hidden - setup-only panel. The leading region helper is no longer unnamed either: `0x422320` is now - bounded as the recurring cached-structure-scalar normalization pass that writes - `[region+0x2e2/+0x2e6/+0x2ea/+0x2ee]`, while `0x422a70` is the shared placement-validation and - commit gate beneath both the per-region worker and one second world-side placement loop. The - neighboring `0x4234e0` accessor is tighter too: it is the shared projected structure-count scalar - query by category that later feeds both the per-region placement family and the map-editor city - count stats report. So the remaining gap is no longer “what are these setup payload helpers - doing,” but only how aggressive we want to be when naming the last top-level setup roots from - mostly RT3.lng and asset-side evidence. - The adjacent summary helper is tighter too: `0x502550` is not another hidden submode owner. It - republishes the staged path tail in `0xe7f`, the scalar summary in `0xe84`, the two persisted - selector lists in `0xe86/0xe87`, and the config toggles in `0xe88/0xe89/0xe8a`. - The remaining top-level gap is cleaner now too: submode `16` still has no distinct downstream - helper or launch branch in the local selector/refresh family, but it is no longer a blank bucket. - Current evidence now bounds it as the `0x0bc3 -> 16` top-level button whose visual-state lane is - surfaced through control `0xbc6`, and the strongest residual fit is `High Scores` because - `Credits` already lives in separate shell mode `6`. - The validated launch lane is tighter now too: it no longer just writes selector `3` or `5` as - one undifferentiated blob, and it no longer includes `0x0ce5` or `0x0dcb`. `0x0ce5` is the - `Load Map` selector because it writes selector `3` and then selects submode `9`, while `0x0dcb` - is the later conditional `5/3` companion-selector sibling rather than a file launch. The actual - validated staged-profile lane is now bounded more narrowly: `0x0cf6` and `0x0e81` are the - selector-`5` siblings, while the neighboring selector-`3` validated lane is at least shared by - `0x0de9` and `0x0df3`; the shared bridge at `0x4425d0` then forces `[0x006cec7c+0xc5] = 1`, - mirrors payload bytes into `[profile+0xc4]`, `[profile+0x7d]`, and `[profile+0xc6..+0xd5]`, and - only then issues shell request `0x0cc`. The file-side staging bytes in that bridge are now - tighter too: across the checked `Alternate USA`, `Southern Pacific`, and `Spanish Mainline` - map/save pairs, payload `+0x33` stays `0`, but payload `+0x22` and token block `+0x23..+0x32` - do not preserve the earlier map-to-save pairing seen at `+0x14/+0x3b2`. Instead they split by - the finer file family, with examples `Alternate USA.gmp = 0x53 / 0131115401...` versus - `Autosave.gms = 0xae / 01439aae01...`, `Southern Pacific.gmp = 0xeb / 00edeeeb...` versus - `p.gms = 0x21 / 0100892101...`, and `Spanish Mainline.gmp = 0x5b / 0044f05b...` versus - `g.gms = 0x7a / 0022907a...`. So the validated launch bridge now looks more like a file-family - staging lane than a simple copy-forward of the earlier setup summary fields. The destination-side - consumers are tighter now too: `[profile+0xc4]` is no longer just an unnamed staged byte, but the - campaign-progress slot later consumed by the numbered `%s%02d.gmc` save helper `0x00517c70`; - `[profile+0x7d]` is the same compact option byte mirrored back into the `Setup.win` option - controls `0x0ce9..0x0ced`; and the campaign-side selector block is no longer only a one-byte - anchor. Direct `RT3.exe` disassembly of the campaign-side dispatcher at `0x004b89c0` now shows - the exact mirror shape: when the local campaign-page selector `[window+0x78] <= 4`, the helper - writes one highlighted progress control `0x0c372 + [profile+0xc4]` and then mirrors the full - sixteen-byte band `[profile+0xc6..+0xd5]` into controls `0x0c382..0x0c391` through repeated - `0x540120` calls. The same body also treats `[profile+0xc4]` as an index into the fixed - sixteen-entry scenario-name table at `0x00621cf0`, whose observed entries include `Go West!`, - `Germantown`, `Central Pacific`, `Texas Tea`, `War Effort`, `State of Germany`, `Britain`, - `Crossing the Alps`, `Third Republic`, `Orient Express`, `Argentina Opens Up`, - `Rhodes Unfinished`, `Japan Trembles`, `Greenland Growing`, `Dutchlantis`, and - `California Island`. On the launch-side branch the same helper writes startup selector `6`, - copies the resolved campaign filename into `[profile+0x11]`, forces `[profile+0xc5] = 1`, and - then issues shell request `0x0cc`. The lower refresh tail at `0x004b8d49..0x004b8d69` also - shows the observed page-band split over the same progress byte: values `< 5` pair with campaign - page `1`, values `5..9` with page `2`, values `10..12` with page `3`, and values `>= 13` with - page `4`. So `[profile+0xc6..+0xd5]` is no longer a generic opaque span at all, but the staged - sixteen-byte per-scenario campaign selector or unlock band consumed directly by `Campaign.win`. - The message-dispatch side is tighter now too. The local classifier at `0x004b91d8` routes the - control range `0x0c352..0x0c39b` through five concrete case classes: `0x0c352..0x0c361` enter - the shared selector or launch branch, `0x0c362..0x0c367` force local page `1`, - `0x0c368..0x0c392` force local page `2`, `0x0c393..0x0c396` force local page `0`, and - `0x0c39b` alone forces local page `3`. That matches the constructor and refresh shape: the - sixteen scenario selector controls live at `0x0c352..0x0c361`, the four page-strip controls - live at `0x0c368..0x0c36b`, the six-arrow auxiliary strip lives at `0x0c36c..0x0c371`, the - progress band lives at `0x0c372..0x0c381`, the ribbon or selector band lives at - `0x0c382..0x0c391`, the string or voice target lane lives at `0x0c392`, the four exit controls - live at `0x0c397..0x0c39a`, and `0x0c39b` remains the one-off special action control that - spawns or dismisses the campaign-side companion object. The `Campaign.win` blob now exposes that - structural split directly too: alongside the art-backed `0x0004c3xx` records it carries - anonymous zero-name records with the same `0x0bb8 / 0 / 0x0bb9` prelude but selector words in - the `0x0010c3xx` family. Current local extraction shows exactly - `0x0010c352..0x0010c361`, `0x0010c362..0x0010c367`, `0x0010c393..0x0010c396`, and one - `0x0010c39b` record, which is the same non-`.imb` band the message dispatcher treats as the - structural selector and page-write family. Their second selector word then buckets those records - under the same page-strip ids as the art-backed records: `0xc368` for - `0xc352..0xc356`, `0xc362`, `0xc393`, and `0xc39b`; `0xc369` for `0xc357..0xc35b`, - `0xc363`, and `0xc394`; `0xc36a` for `0xc35c..0xc35e`, `0xc365..0xc366`, and `0xc395`; and - `0xc36b` for `0xc367`, `0xc35f..0xc361`, and `0xc396`. One final anonymous record at - `0x0002c392` has no page bucket at all, which fits the already-grounded read of `0xc392` as the - one-off string or voice target lane rather than a normal page-cell control. The anonymous body - layout is only partially named, but one file-side distinction is already stable: the ordinary - structural selector/page records all carry footer words `0xd3000000` and `0xd2000007` at - relative `+0x98/+0x9c`, while the lone `0xc392` record carries `0x00000000/0x00000000` there. - So `0xc392` is no longer just “outside the page buckets”; it is also the only current - anonymous-record outlier in that trailing structural footer pair. The structural selector side is - tighter now too: `0xc352..0xc361` partition exactly as `5 + 5 + 3 + 3` across page buckets - `0xc368..0xc36b`, matching the observed campaign page bands for scenario progress values `< 5`, - `5..9`, `10..12`, and `>= 13`. That makes the anonymous selector records the file-side mirror of - the same campaign page split, not a separate unrelated control family. The file-order adjacency - is tighter in the same way: `0xc352..0xc361` each sit immediately after one `RibbonN.imb` - record and before the next `litCamp` record, which makes them the strongest current file-side fit - for the structural selector or click-target siblings of the visible campaign ribbon controls. - The auxiliary anonymous bands line up the same way: `0xc362..0xc367` sit inside the local - `litArrows.imb` clusters, `0xc393..0xc396` sit inside the `litExits.imb` clusters, and - `0xc39b` sits once between the first arrow and first exit group. So the current best read is - that those anonymous records are the structural hitbox or action siblings of the visible arrow, - exit, and selector art families, not an unrelated hidden control layer. The generic record - cadence is tighter now too: in the current `Campaign.win` dump the ordinary anonymous structural - records all span `0x0a7` bytes, while the named art-backed records cluster at `0x0b1`, `0x0b2`, - and `0x0b3`. The only two visible outliers are the leading `0x0080c351` record at `0x0041` - with span `0x0a3`, and the trailing `0x0002c392` record at `0x2fb9` with span `0x0b1`. That - reinforces the current read that `0xc351` and `0xc392` are one-off structural controls flanking - the main selector or page family rather than ordinary repeated art-backed records. - The setup-launch corpus now tightens one corrective caveat there too: when the checked - `Alternate USA`, `Southern Pacific`, and `Spanish Mainline` `.gmp/.gms` files are decoded with - that same campaign-side interpretation, payload byte `+0x22` is always outside the known - campaign progress range `0..15` (`0x53`, `0xeb`, `0x5b`, `0xae`, `0x21`, `0x7a`), so the - ordinary validated setup lane is not simply staging a normal campaign-screen state. The paired - token block `+0x23..+0x32` is still structurally compatible with the campaign selector band, but - in the checked files it only populates a small recurring subset of the sixteen scenario lanes, - chiefly `Go West!`, `Germantown`, `Central Pacific`, `Texas Tea`, and `War Effort`, with - scenario-family-specific byte values rather than a simple `0/1` unlock bitmap. That makes the - setup-side staging bridge look more like one shared destination layout being reused for a broader - launch token family, not a proof that ordinary setup-launched `.gmp/.gms` content is already in - campaign-screen form. - Only `0x0e81` also sets `[0x006cec7c+0x82] = 1`, which is currently the strongest sandbox-side - anchor beneath the later `.gmx` load family. - That launch band is slightly tighter now too: `0x0dca` is the grayscale-map picker branch above - the `TGA Files (*.tga)` / `.\Data\GrayscaleMaps` helper at `0x004eb0b0`, not another ordinary - save-file validator. That launch band is tighter in a second way too: `0x0ddf` is not a lobby - branch after all, but the separate windowed-mode-gated grayscale-heightmap generation path. It - reopens the `TGA Files (*.tga)` / `.\Data\GrayscaleMaps` picker through `0x0042a970`, validates - the chosen image through `0x005411c0`, and only then writes startup selector `2`. The fixed- - button side is tighter too: submode `15` now aligns with the `Extras` family because it sits - above the Readme/Weblinks shell-open quartet and the return-to-extras sibling, while submode - `17` now aligns with the tutorial chooser because it is the only branch that later exposes - startup selectors `1` and `7`, which RT3 uses for `Tutorial_2.gmp` and `Tutorial_1.gmp`. The - map-root family is tighter too: submodes `7/8/9` are the only setup branch that flips the file - root into - `maps\\*.gm*`, with mode `8` specifically the grayscale-heightmap picker and mode `9` the - file-backed map-list sibling. - Submode `13` is slightly tighter now too: current local evidence shows that it stays outside - both the dedicated file-backed pane and the mode-`3` option-heavy pane, so it is best read for - now as one top-level non-file-backed setup branch rather than another saved-game list variant. - The setup-side file roots are tighter now too: the shared file-list builder at `0x4333f0` - formats either `saved games\\*.smp` or `maps\\*.gm*` from the shell-state fields at - `[0x006cec74+0x68/+0x6c]`, with the separate `data\\tutorial` root only appearing on the - tutorial-side `[shell+0x6c] == 2` branch. That means the `Setup.win` submode families are no - longer one generic file pane: the ordinary setup-backed `.smp` family is broader than the - narrower file-list pane, because modes `3/4/5/6/10/12/14` stay on the ordinary saved-game side - while only `4/6/9/10/12/14` re-enter the dedicated file-list panel at `0x5027b0`; the `maps` - branch is the narrower setup or tutorial launch family above the same shared record builder. -- Evidence: function-map map/scenario rows, analysis-context exports for `0x00445ac0`, `0x00445de0`, - `0x00443a50`, `0x00434300`, and `0x00444dd0`, plus objdump string and mode-table evidence for - `.gmp`, `.gmx`, `.gmc`, `.gms`, `.gmt`, `.smp`, `Quicksave`, the `0x004dd010` mode table at - `0x005f3d58`, the auxiliary-owner presence check at `0x00434050`, and the `.gmt` handoff through - `0x00469d30`, together with localized string evidence from ids `3018` and `3898`. -- Open Questions: bit `0x1` on both broad coordinators now grounds the Quicksave name seed and the - former third `fileopt.win` flag has been ruled out as a file-flow question because it just opens - `SettingsWindow.win`. The old broad extension question is mostly resolved: `.gmp` is the - editor-map pair, `.gms` is the standalone scenario family, `.gmc` is the campaign-scenario family, - `.gmx` is the sandbox family, and `.gmt` is at least bounded as an auxiliary preview-surface - branch rather than another gameplay save family. The higher-value global question is no longer - whether `0x00443a50` is world entry. It is where the long-lived simulation cadence takes over - after this bring-up and whether that cadence still rendezvous with the shell-owned frame path or - escapes into a separate gameplay loop. +Detailed section: +[map-and-scenario-content-load.md](/home/jan/projects/rrt/docs/control-loop-atlas/map-and-scenario-content-load.md) ## Multiplayer Session and Transport Flow -- Roots: `multiplayer_window_init_globals` at `0x004efe80`, `multiplayer_window_service_loop` at - `0x004f03f0`, the Multiplayer.win session-event callback table built by - `multiplayer_register_session_event_callbacks` at `0x0046a900`, the active session-event transport - object at `0x006cd970`, the Multiplayer preview dataset object at `0x006cd8d8`, and the lower - pending-template and text-stream helpers around `0x00597880..0x0059caf0`. -- Trigger/Cadence: shell-owned Multiplayer.win frame service plus event-driven session callbacks and - repeated transport pump steps. -- Key Dispatchers: session-event wrappers for actions `1`, `2`, `4`, `7`, `8`; - `multiplayer_register_session_event_callbacks`; `multiplayer_dispatch_requested_action`; - `multiplayer_reset_preview_dataset_and_request_action`; - `multiplayer_preview_dataset_service_frame`; `multiplayer_load_selected_map_preview_surface`; - `multiplayer_flush_session_event_transport`; `multiplayer_transport_service_frame`; - `multiplayer_transport_service_worker_once`; - `multiplayer_transport_service_route_callback_tables`; - `multiplayer_transport_service_status_and_live_routes`; - `multiplayer_transport_text_stream_service_io`; - `multiplayer_transport_dispatch_pending_template_node`; - `multiplayer_transport_service_pending_template_dispatch_store`. -- State Anchors: live session globals at `0x006d40d0`, active session-event transport object at - `0x006cd970`, status latch at `0x006cd974`, session-event mode latch at `0x006cd978`, retry - counter at `0x006cd984`, preview dataset object at `0x006cd8d8`, preview-valid flag at - `0x006ce9bc`, staged preview strings at `0x006ce670` and `[0x006cd8d8+0x8f48]`, Multiplayer.win - backing block at `0x006d1270`, selector-view store root at `[transport+0xab4]`, selector-view - generation counters at `[transport+0xab8]..[transport+0xac0]`, selector-view backing arrays around - `[transport+0xad0]..[transport+0xae4]`, selector-view entry probe-request id at `[entry+0x50]`, - live-state gate at `[entry+0x58]`, third-slot flag word at `[entry+0x64]`, probe-schedule tick at - `[entry+0x68]`, last-success tick at `[entry+0x6c]`, pending-probe latch at `[entry+0x74]`, - success generation at `[entry+0x78]`, consecutive-failure counter at `[entry+0x7c]`, rolling - average at `[entry+0x80]`, recent sample window at `[entry+0x84..]`, bounded sample-count at - `[entry+0x94]`, total-success count at `[entry+0x98]`, pending-template list at - `[transport+0x550]`, dispatch store at `[worker+0x54c]`, and text-stream buffers rooted under - `[worker+0x1c]`. -- Subsystem Handoffs: the Multiplayer.win initializer seeds the backing block at `0x006d1270`, later - reset paths construct the separate preview dataset at `0x006cd8d8`, and the shell-owned - active-mode frame services that dataset every frame through - `multiplayer_preview_dataset_service_frame`. That preview side publishes roster and status - controls through the Multiplayer window control paths, loads `.gmt` preview surfaces through - `multiplayer_load_selected_map_preview_surface`, and is even reused by the map/save coordinator’s - mode-`11` `.gmt` path when the dataset already exists. In parallel, - `multiplayer_register_session_event_callbacks` allocates and registers the separate session-event - transport object at `0x006cd970`. The shell-side bridge into that deeper transport cadence is now - tighter: `multiplayer_window_service_loop` and neighboring reset or initializer branches call - `multiplayer_flush_session_event_transport`, which forces one status flush and then drops into - `multiplayer_transport_flush_and_maybe_shutdown`. That wrapper in turn runs - `multiplayer_transport_service_frame`, the recurring pump that services one worker step through - `multiplayer_transport_service_worker_once`, sweeps the transport-owned callback tables and field - caches through `multiplayer_transport_service_route_callback_tables`, services both the auxiliary - status route and the current live route through - `multiplayer_transport_service_status_and_live_routes`, and then descends one layer farther into - the shared GameSpy route helper `multiplayer_gamespy_route_service_frame` at `0x58d040`. The - transport also owns a separate selector-view sidecar beneath that route cadence. - `multiplayer_transport_ensure_selector_view_store` allocates the keyed selector-view store at - `[transport+0xab4]`, `multiplayer_transport_find_selector_view_entry_by_name` resolves entries - from that store, `multiplayer_transport_upsert_selector_name_entry` marks per-slot activity and - flags inside each entry, and `multiplayer_transport_mark_selector_slot_views_dirty` plus - `multiplayer_transport_reset_selector_view_entry_runtime_state` manage the dirty or refresh fields - at `+0xa0`, `+0xa4`, and `+0xa8`. That selector-view maintenance path is now split more cleanly - too. The recurring owner is `multiplayer_transport_service_selector_view_refresh_cycle`, which - first runs the fast deferred-probe lane: - `multiplayer_transport_collect_refreshable_selector_view_entries` walks the store through - `multiplayer_transport_filter_insert_refreshable_selector_view_entry`, which now shows that - `[entry+0x64]` is not a generic flag bucket but the third selector-slot flag word, parallel to - `[entry+0x5c]` and `[entry+0x60]`. In that collector, the `g` and `a` mode-letter bits produced by - `multiplayer_transport_parse_selector_mode_letters` become mask `0x0c` in the slot-local flag - words, and any third-slot entry carrying those bits at `[entry+0x64]` is excluded from the - refreshable set. Eligible entries then pass slot-aware retry timing on `[entry+0x68]`, - `[entry+0x6c]`, `[entry+0x78]`, and `[entry+0x7c]`, after which the service loop schedules refresh - probes through `multiplayer_transport_schedule_selector_view_entry_refresh_probe`. That fast lane - is narrower now too: the entry-side match key `[entry+0x50]` is no longer just an opaque request - field. The profile-key callback lanes feed - `multiplayer_transport_parse_selector_view_probe_marker`, which decodes one local `X%sX|%d` marker - into a probe request id plus displayed version/build integer, and - `multiplayer_transport_arm_selector_view_probe_tracking` stores those into `[entry+0x50]` and - `[entry+0x54]` before arming the live probe gate at `[entry+0x58]`. The current-selector callback - root at `0x59f8b0` is now bounded as well: it resolves and upserts the active selector name, - optionally reuses a cached `username` marker to arm probe tracking immediately, then submits the - same profile-key bundle with selector context and forwards that selector through callback slot - `17`, with the status-route side able to force route-mode transitions `2 -> 3 -> 4` afterward. One - layer lower, `multiplayer_transport_handle_profile_key_query_result` at `0x596970` now bounds the - per-key result path itself. It treats `username` as the probe-marker field, `b_flags` as the - selector mode-letter field, and `(END)` as a real sentinel that publishes a zeroed slot-`22` - payload instead of a marker pair. The same helper also hashes the selector-name, key-name, and - resolved value text back into the caller table, so the profile-key bundle now looks like a real - bounded handoff rather than an anonymous callback cloud. The deferred callback shim - `multiplayer_transport_dispatch_selector_view_refresh_probe_result` then walks the keyed store - through `multiplayer_transport_finish_selector_view_refresh_probe_if_matching`, which only - completes entries whose pending latch `[entry+0x74]` is still armed and whose parsed marker - request id `[entry+0x50]` matches the finished request. A failed result `-1` clears the pending - latch and increments the consecutive-failure counter at `[entry+0x7c]`. A nonfailure result clears - the pending latch, increments the success generation at `[entry+0x78]` and total-success count - `[entry+0x98]`, clears `[entry+0x7c]`, stamps the last-success tick at `[entry+0x6c]`, appends the - returned sample into the short rolling history at `[entry+0x84..]`, grows the bounded sample-count - `[entry+0x94]` up to four, computes the current average into `[entry+0x80]`, and then publishes - that averaged `ms` sample through `multiplayer_transport_enqueue_callback_slot24_record`. So the - publication boundary is explicit and the request-id ownership is explicit: `[entry+0x80]` now - reads as the averaged millisecond probe sample and `[entry+0x54]` as the displayed version/build - companion integer. The adjacent route-callback side is tighter too, but it is now kept separate: - the staged route-callback path at `0x5958e0` and the later compatibility gate at - `multiplayer_transport_route_binding_matches_route_callback_descriptor_tuple` `0x595d00` operate - on a compact GameSpy-style server or route descriptor family with a primary endpoint tuple at - `[descriptor+0x00]/[+0x04]`, an optional secondary endpoint tuple at `[descriptor+0x08]/[+0x0c]`, - string-key lookups such as `hostname` and `gamever`, and numeric-key lookups such as - `numplayers`, `numservers`, `numwaiting`, and `gsi_am_rating`. The route-binding side uses that - descriptor family's primary dword and host-order port plus the optional secondary tuple against - route-binding offsets `+0x54/+0x58` and route word `+0x30`. Current evidence still does not prove - that descriptor tuple is the same field family as the selector-view marker companion integer at - `[entry+0x54]`. The higher compact decode owners are tighter now too: `0x5907d0` is the - allocate-and-append lane for one self-consistent compact payload, while `0x590d00` is the keyed - upsert-by-primary-endpoint lane that reuses an existing descriptor when possible and then notifies - the owner callback. The route-callback-table runtime above that decode side is tighter now too: - `multiplayer_transport_route_callback_table_construct` `0x5905e0` seeds one transport-owned - table block, `multiplayer_transport_route_callback_table_release_decoded_schema_dictionary` - `0x5906f0` tears down the decoded schema dictionary rooted at `[this+0x08]`, - `multiplayer_route_callback_runtime_acquire_shared_string_copy` `0x590540` and - `multiplayer_route_callback_runtime_release_shared_string_copy` `0x5905a0` now bound the shared - string pool used by that decoded schema, and the higher bring-up owner `0x596090` now clearly - splits between `[transport+0xba4]` with owner callback `0x595a40`, the local field-cache family - `[transport+0x1724]` seeded through `0x5a08f0/0x595b60`, and `[transport+0x1164]` with owner - callback `0x595bc0`, while - `multiplayer_transport_route_callback_table_service_receive_decode_state_machine` `0x5908c0` - is the current live receive/decode state machine serviced by `0x591290` in table states `2/3`. - The callback-owner mode split above that runtime is now explicit too: append-notify `0x590370` - publishes mode `0`, compact upsert `0x590d00` publishes mode `1`, remove-notify `0x590430` - publishes mode `2`, and the live receive/decode path `0x5908c0` publishes modes `6`, `5`, and - `3`. - The route-handle lifecycle above that decode path is tighter now too: `0x590740` cleanly resets - one table's live route plus decode-side runtime without destroying the outer object; `0x5907a0` - is the broader destroy path that also releases the active descriptor collection; `0x590ed0` - opens the live route handle into `[this+0x4a0]`, stages the initial outbound request, and seeds - state `3` plus the staged receive buffer; `0x5911e0` is the state-`2/3` socket-service wrapper - that reads new bytes, grows the staged buffer, and re-enters `0x5908c0`; `0x5912c0` is the - one-shot send-with-reopen-retry helper; and `0x590ea0` is the shared disconnect publication and - reset tail. The recurring service helper `0x591290` is tighter too: it now first clears the - staged intrusive descriptor list through `0x590490` before entering the state-driven seed-or- - receive branch. The upstream owners are tighter too: `0x5962e0` is now the field-subscription - route-table opener above `[transport+0xba4]`, while `0x596530` is the `gsi_am_rating` reopen - path above `[transport+0x18bc]`. On that latter branch, `0x590dc0` is now bounded as the - state-`0` raw-endpoint seed pass over the live route handle, repeatedly pulling endpoint tuples - through `0x58bc7e` record type `0x1f3` before stamping descriptor flag byte `0x15` with `0x11`. - That makes the remaining source-flag meaning narrower too: current evidence now supports reading - byte-`0x15` bit `0x1` as a primary-endpoint-seed or endpoint-only marker. In the `gsi_am_rating` - dispatcher, clear-bit descriptors can take the richer direct transition lane, while set-bit - descriptors are staged through the queued enrichment path and still suppress that direct - transition even after the ready bit arrives. - The adjacent capacity-descriptor side is tighter too: `0x595bc0` now clearly publishes a - descriptor block from live descriptor properties `hostname`, `numwaiting`, `maxwaiting`, - `numservers`, and `numplayers` plus three carried sidecar scalars. That sidecar at - `[transport+0x1778]` is tighter now too: current evidence says it behaves as one cached pointer - into the transient work-record family at `[transport+0x1780]`, because every meaningful branch - in `0x595bc0` reads the same `+0x0c/+0x10/+0x18` metadata triplet and replay modes later consume - the pointer through `0x5933a0`. The negative result is stronger too: local text-side xrefs still - show no direct store to `[transport+0x1778]`, and a wider local sweep also failed to show any - obvious `lea`-based replay-band writer. The transient-request lifecycle tightens that further: - `0x593330/0x593370/0x593380/0x5934e0/0x5933a0` now fully bound `[transport+0x1780]`, `0x1784`, - and `0x1788` without ever touching `[transport+0x1778]`, and the neighboring active-opcode reset - helper `0x5929a0` is likewise scoped only to `[transport+0x17fc]`. A broader constructor and - teardown pass tightened that further too: `0x596090`, `0x5961b0`, and `0x5962e0` all touch the - neighboring replay-band fields without ever seeding `[transport+0x1778]`. A full-binary - literal-offset sweep tightens it further still: the only direct `0x1778` hit in `RT3.exe` is - the read in `0x595bc0`. One nearby ambiguity is now closed too: the - mode-`5` mirror path in `0x595a40` and `0x595e10` does not target `[transport+0x1778]`; it - writes `[transport+0x54]` and mirrors the same staged route companion dword only into queue-side - slot `[transport+0x1724+0x24]` through `0x005a0940`. So the sidecar writer remains upstream of this - leaf publisher. Mode `0` is now also tied more cleanly to the generic descriptor append-notify lane - at `0x590370`, while mode `2` stays outside this helper as the separate - remove-notify-and-stage path at `0x590430`. The opcode-`2` payload boundary is tighter too: - `0x592ae0` now grounds that payload - as a seven-dword block with an owned string slot at `+0x08`, so live mode supplies a populated - payload while modes `3` and `5` deliberately enqueue an all-zero payload and reuse only - the wrapper-side sidecar metadata. Those two modes are tighter now too: they are the live - receive-state owner callbacks emitted by `0x5911e0 -> 0x5908c0`, not loose generic replay - guesses. So those paths are better read as delayed metadata replays over one cached work record, - not over a separate anonymous cache blob. The neighboring - capacity-owner split is tighter now too: `0x595bc0` only stages descriptor records for modes - `0`, `3`, and `5`; the upstream route-callback-table owner still delivers modes `1`, `2`, and - `6`, but those are explicit no-ops in this capacity leaf. So the owner wiring itself is no - longer the open edge; only the upstream sidecar producer remains unresolved. The neighboring - work queue is tighter too: `0x593330/0x593370/0x593380` now bound `[transport+0x1780]` as the - construct/clear/destroy owner family, while `0x5933a0`, `0x5934e0`, and `0x593570` ground the - remove, allocate, and completion side over that same collection. The small sibling `0x593400` is - tighter too: it is a pure work-record uniqueness predicate over field `+0x0c`. Its caller is - tighter now too: `0x58d720` is an immediate-drain quiescence gate over one transport context id, - using `0x593400` for the queued work family at `[transport+0x1780]` and `0x592970` for the - active opcode-record collection at `[transport+0x17fc]`. The strongest current read is that - `0x5934c0` seeds that shared drain context id first, then the transport copies it into queued - work field `+0x0c` and active opcode-record field `+0x14` before the immediate-drain roots wait - on one shared disappearance test rather than on a vague settle loop. The currently grounded - roots are `0x58df20`, the neighboring formatted selector-text publish path at `0x58dfb0`, and - callback-table registration at `0x58e200`. The active-opcode side is tighter too: `0x5927b0` - now bounds the per-record service-and-retire path, `0x592800` the wider context-or-idle sweep, - `0x5929a0` the remove-by-opcode-type sweep, and `0x5929f0` the narrower opcode-`3` - field-snapshot removal keyed by the subscribed callback-pair payload. That also corrects - `0x595b80`, whose final cleanup is an active field-snapshot purge rather than a queued-work - drain. The adjacent route-callback descriptor-table lifecycle is tighter too: `0x590410` now - grounds `[table+0x5bc]` as the staged intrusive descriptor-list head, `0x590430` is the generic - remove-notify-and-stage lane, `0x590490` releases the staged list, and `0x5904d0` releases the - active descriptor collection before tearing that staged list down. That also makes the earlier - `0x5962e0` “release active descriptors” step explicit. The callback-table attach side now constrains the - same work-record metadata family a little further too: `0x593650` deliberately duplicates its - first caller metadata dword into both fields `+0x0c` and `+0x10`, while carrying the second - caller metadata dword in `+0x18`. The lower opcode wrappers are tighter now too: `0x592a40` - turned out to be the explicit opcode-`1` trigger wrapper whose constructor is a no-op and whose - active-side service is `0x5913c0`, while `0x592c40` is the real `0x08`-byte explicit opcode-`5` - binding leaf. The earlier opcode-`4` read was just the table-indexing mistake in `0x5928a0`: - selector `4` lands on the row at `0x5e2044`, not the row at `0x5e2034`. The producer side is tighter too: - bound-route requests, selector-text route requests, and the type-`9` text fastpath also stage - that same triplet through `0x5934e0`, and the fastpath shim `0x593d00` now gives the cleanest - proof of the callback split by only re-emitting the follow-on lane when `+0x10` is nonnull and - then forwarding `(+0x10, +0x18, +0x0c)` into `0x593170` as callback function, callback - companion, and trailing drain context. So the replay-side triplet is clearly a broader - transport callback-wrapper family, not one fixed route-only tuple. The nearby - field-subscription side is tighter too: `0x592b50` now clearly uses `[transport+0x1774]` as a - cached progress percentage under `[transport+0xba4]`, and `0x5962e0` seeds that percentage to - `1` just before the first immediate mode-`3` snapshot. The nearby route-callback-table - lifecycle is tighter now too: `0x596090` seeds `[transport+0xba0]` as the callback-plumbing - enable latch, clears staged payload slot `[transport+0xb50]`, and constructs the three owner - branches rooted at `[transport+0xba4]`, `[transport+0x1164]`, and `[transport+0x18bc]`; - `0x596210` is the recurring service sweep over those same three tables plus the local field - cache and queued-descriptor family; `0x596060` is the explicit `gsi_am_rating` reset; and - `0x596530` is the reopen-from-stored-label sibling above that same am-rating table. The - matching local cleanup is tighter too: `0x5962c0` is the explicit staged route-callback payload - clear on `[transport+0xb50]`, while `0x595ce0` now clearly resets only the capacity-descriptor - route callback table at `[transport+0x1164]`, not the field-subscription table at - `[transport+0xba4]`. The remaining gap on the capacity side is therefore narrower: the carried - sidecar fields themselves now read more cleanly as the cached callback-wrapper triplet reused - elsewhere (`drain context id +0x0c`, `callback fn +0x10`, `callback companion +0x18`), and the - negative result is stronger too: nearby replay-band fields `[transport+0x176c]`, - `[transport+0x1770]`, `[transport+0x1774]`, `[transport+0x177c]`, `[transport+0x1780]`, and - `[transport+0x1784]` all have direct local owners while `[transport+0x1778]` still appears only - as the single read in `0x595bc0`; even the broader callback-owner lifecycle now skips it while - seeding, servicing, resetting, reopening, or tearing down those neighboring tables and caches. - The constructor now closes that local search further: `0x58dc50` bulk-zeroes the full transport - body and still never writes a nonzero value into `[transport+0x1778]` before later explicit - neighbor initialization. The callback-binding owner stack now tightens that boundary too: - `0x5934e0` stages the shared work-record metadata triplet, `0x593650` binds it into the - callback-table worker path, and `0x593570` later consumes and republishes it, while - `[transport+0x1778]` still appears only as the borrowed sidecar read in `0x595bc0`. So this - edge is now locally closed, and the remaining producer looks like an upstream callback or worker - handoff rather than one missing ordinary field store in the local cluster. The adjacent staged-route - callback side is tighter too: `0x595860` is now bounded as the - submit-result handler beneath `0x5958e0`, and the old `[transport+0xac0]` ambiguity there is now - gone. That branch is using the already-grounded third selector-generation counter at `[0xac0]` - together with target `[0xb48]` to decide whether staged route-callback traffic can push the - multiplayer route-mode ladder from `2` into `3` and later `4`. The selector-view counter beneath - that gate is tighter now too: `0x594e30` counts slot-`2` entries whose flag dword carries bit - `0x20`, optionally filtered by the current transport name buffer. The selector-view mutation - family under that same lane is tighter too: `0x594a30` is now the direct keyed-store remover, - `0x594fb0` clears one selector-slot ownership pointer plus its slot-local flag dword and drops - the whole entry when no slots remain, `0x595010` rekeys one selector-view entry under a new name - while preserving the `0x40..` runtime band, and callback root `0x59f9c0` now reads as the - sibling lane that clears one named selector-view slot, publishes callback slot `18`, and may - still re-enter the route-mode setter from the same slot-`2` status and generation gates. The - neighboring callback roots are tighter now too: `0x5950a0` clears one selector slot from every - selector-view entry in the keyed store, `0x59fab0` is the rename or relabel sibling above - `0x595010`, `0x59faf0` updates one selector slot's fixed sample-text buffer and refreshes the - active selector object when present, and `0x59fb60` replaces one selector slot's name set, - requests the default profile-key bundle for that slot, and publishes callback slot `20`. Slot - `16` is tighter now too: current grounded caller `0x59f440` forwards the staged route-callback - payload handle from `[transport+0xb50]` through `0x592ea0` just before route mode `5`. The - last adjacent callback root in that block is tighter now too: `0x59fbd0` is the built-in - per-slot profile-key query sibling. It resolves the caller selector name into one slot index, - forwards the caller trio into `0x596b90`, and then publishes callback slot `28`; that lower - helper indexes one slot-specific built-in string pair from `[transport+0x189c]` and - `[transport+0x18ac]`, reuses the generic per-key handler `0x596970`, and only republishes slot - `28` when that lower query path succeeds. - The compact-header side is tighter now too: `0x58fe20` and `0x58ff20` now show that compact - payloads always carry the primary IPv4 dword and that header bit `0x10` only gates whether the - primary port word is inline or inherited from the owner default port. `0x58fe90` now validates - the `0x40` inline keyed-property vector against the owner schema, and `0x58fe50` validates the - signed-`0x80` trailing string-pair tail before decode. `0x58ff60` then grounds bit `0x02` as - the inline secondary IPv4 dword branch, bit `0x20` as the paired secondary-port word branch with - owner-port fallback, bit `0x08` as one still-unresolved auxiliary dword stored at - `[descriptor+0x10]`, bit `0x40` as one inline keyed-property vector decoded through the - property-store writers, and signed bit `0x80` as one trailing string-pair tail. The - descriptor-state side is tighter now too: the shared queue helper at - `0x005a09a0` stamps pending state `0x4` for the local field-cache family `[transport+0x1724]` - and pending state `0x8` for the `gsi_am_rating` queued-descriptor family `[transport+0x1e7c]`, - while later service through `0x005a0c80` promotes those pending tags into ready bits `0x1` and - `0x2` in descriptor byte `[entry+0x14]`. That makes the current transport-side tests cleaner: - `0x58d1c0` is the field-cache ready gate, `0x58d1d0` is the `gsi_am_rating` queued-descriptor - ready gate, and `0x58d230` is the remaining flag-byte split between direct primary-endpoint - handling at `[transport+0x18bc]` and the queued path at `[transport+0x1e7c]`. That byte-`0x14` - story is no longer queue-only either: `0x58ff60` can also OR in bit `0x1` after the inline - keyed-property vector and bit `0x2` after the signed string-pair tail. The flag-byte split is no - longer purely behavioral either: current evidence now says byte `[descriptor+0x15]` bit `0x1` is - a source-side descriptor header bit, explicitly seeded during the primary-endpoint table refresh - around `0x590dc0` and preserved by the compact descriptor decode path at `0x58ff60`, rather than - a queue-generated runtime state. The `gsi_am_rating` dispatcher side is tighter too: that same - bit no longer just looks like a direct-versus-queued routing split, because `0x595e10` also uses - it to suppress the direct `0x595dc0` transition even after queued ready bit `0x2` is present. - The descriptor body is tighter too: `[descriptor+0x20]` is now the intrusive next-link used by - the transport-owned primary-endpoint list headed at `[table+0x5bc]`, and `[descriptor+0x1c]` is - now the special numeric scalar behind the current `queryid`/`ping` fallback pair. The compact-only - auxiliary dword at `[descriptor+0x10]` is tighter in a negative way too: local xref scans now - only show it being preserved by later generic helpers like - `generic_record_0x1c_deep_copy_with_owned_string_at_0x08` `0x591410` and the adjacent - callback-marshaling wrappers `0x591480` and `0x591510`, not read through any dedicated semantic - accessor yet. The route-event dispatcher side is tighter too: the mode-`5` tails in both - callback families do not copy a descriptor-local field but instead mirror the transport-staged - companion dword at `[this+0x490]` into `[this+0x54]` and queue-side slot `[this+0x1724+0x24]`. The - `gsi_am_rating` maintenance lane is tighter now too: after pruning failed descriptors it sorts - the surviving primary-endpoint table through `0x590310` in mode `1` with key `gsi_am_rating`, - then selects the new head through `0x590480` before re-entering the route-transition path. The - same service loop also owns a slower sidecar lane keyed off `[entry+0xa4]`: - `multiplayer_transport_select_stale_selector_view_progress_entry` walks the store through - `multiplayer_transport_pick_stale_selector_view_progress_entry`, picks one stale entry whose - progress latch `[entry+0x9c]` is clear and whose last progress tick `[entry+0x70]` is old enough, - and then hands it to `multiplayer_transport_stage_selector_view_progress_snapshot`. That helper - now looks more bounded too: it rebuilds the core `X%sX` marker text from `[entry+0x50]` through - `multiplayer_transport_format_selector_view_probe_marker_core`, formats one `PNG %s %d` line - around that marker and the entry-local averaged millisecond sample at `[entry+0x80]`, appends bounded - selector-slot `PNG` fragments for live overlapping slots, marks progress-snapshot state in flight - at `[entry+0x9c]`, and stamps both `[entry+0x70]` and the transport-wide throttle tick - `[transport+0xaec]`. So the selector-view sidecar no longer looks like one undifferentiated - refresh bucket: it has a faster deferred-probe lane plus a slower progress-snapshot lane, both - still under the shell-owned multiplayer transport cadence. The two descriptor lanes installed by - `multiplayer_transport_attach_callback_table_descriptor` are now tighter too. The first lane - rooted at `0x59f5c0` can arm deferred-close state on the owner transport and then forward through - callback slot `23`. The second lane is no longer just a loose selector-view bucket: - `multiplayer_transport_callback_dispatch_selector_name_payload_lane` at `0x59f650` classifies - selector payloads through `multiplayer_transport_is_selector_control_line`, routes `@@@NFO` - control lines into `multiplayer_transport_sync_selector_view_nfo_r_flag`, and otherwise publishes - either callback slot `13` or the split token-plus-tail callback slot `14` through - `multiplayer_transport_split_selector_payload_token_and_tail`. That local `@@@NFO` helper is now - bounded more tightly too: it only accepts lines ending in the literal `X\` tail, searches for the - field marker `\$flags$\`, and then sets or clears bit `0x2` in the third selector-slot flag word - at `[entry+0x64]` depending on whether that field contains the letter `r` before the next - backslash. The sibling `multiplayer_transport_callback_dispatch_current_selector_payload_lane` at - `0x59f720` first resolves the active selector through `0x5951a0`, then handles the - current-selector variants of the same control vocabulary: `@@@NFO` continues into the same local - `r`-flag sync helper, `@@@GML` plus mode-`3/4` payloads feed the shared control-token helper - `multiplayer_transport_handle_gml_or_png_selector_control`, and the remaining non-control payloads - publish callback slot `9`. That shared helper now narrows the `GML` and `PNG` split materially: - when the token is `GML` and the tail is `Disconnected`, it requires the active selector-view entry - to pass `multiplayer_transport_selector_view_entry_has_gml_disconnect_gate`, which currently means - the entry participates in the third selector slot and has bit `0x20` set in `[entry+0x64]`, before - it forces one status-pump pass, emits callback slot `16`, and re-enters route mode `5`. Its - sibling `PNG` branch resolves a named selector-view entry from the tail text and, when that entry - overlaps the active selector-slot ownership, refreshes selector-view runtime state through - `0x5948f0` and republishes callback slot `25`. Alongside those dispatchers, one grounded branch at - `0x59f560` still updates selector-view runtime state through `0x5948f0` and forwards the same - selector-name pair through callback slot `25`, while `0x59f850` resets selector text state through - `0x5954b0`, forwards through callback slot `19`, and when selector `2` is active in a nonterminal - route mode re-enters `multiplayer_transport_set_route_mode` with mode `1`. The low-level route - helper still looks like a two-part cycle: - `multiplayer_gamespy_route_service_retry_and_keepalive_timers` handles challenge or retry pressure - and periodic outbound control traffic around the `master.gamespy.com`, `PING`, `natneg`, - `localport`, `localip%d`, and `statechanged` strings, while - `multiplayer_gamespy_route_drain_inbound_packets` drains inbound datagrams and dispatches - semicolon lines, backslash-delimited key bundles, and `0xfe 0xfd` GameSpy control packets. The - transport-owned callback story is now narrower too. The shared route constructor - `multiplayer_gamespy_route_construct_and_seed_callback_vector` seeds `[route+0x88]` through - `[route+0x9c]` from the caller-supplied transport callback table, records the owner transport at - `[route+0x104]`, and explicitly zeroes `[route+0xa0]`, `[route+0xa4]`, and `[route+0xd4]` before - any later patch-up. For the transport-owned status route, - `multiplayer_transport_try_connect_status_route` then patches `[route+0xa0]` through - `multiplayer_gamespy_route_set_extended_payload_callback` to point at - `multiplayer_transport_forward_validated_extended_route_payload` `0x00597330`, which simply - forwards the validated payload wrapper into the owner callback at `[transport+0x17f4]` with - context `[transport+0x17f8]`. The grounded live-route connect path at - `multiplayer_transport_try_connect_live_route` does not currently perform any matching - post-construction patch for `[route+0xa0]`, `[route+0xa4]`, or `[route+0xd4]`, and the higher - route-mode state machine now looks consistent with that: `multiplayer_transport_set_route_mode` - latches the requested small mode at `[this+0x18b8]`, then uses mode `0` for the direct-versus - queued `gsi_am_rating` split, mode `1` for the ready-bit plus queued fallback, mode `2` for - pending-descriptor cleanup, mode `3` for the empty-table fallback, mode `4` for deferred - route-status recovery, and mode `5` for copying the staged route companion dword into `[this+0x54]` - and queue-side slot `[this+0x1724+0x24]`. The current grounded mode transitions still switch by releasing route - objects through `multiplayer_gamespy_route_release_and_free` and rebuilding them through - `multiplayer_transport_try_connect_live_route`, not by mutating callback slots in place. The - parser behavior is now tighter as well: semicolon lines only dispatch when - `[route+0xd4]` is non-null, and the subtype-`6` raw fallback only dispatches when `[route+0xa4]` - is non-null. For the currently grounded transport-owned status and live routes, those two branches - therefore remain optional and can cleanly no-op instead of implying a hidden mandatory callback - path. Inside the packet parser, subtype `4` is no longer an unknown callback hop: after cookie - validation it dispatches through `[route+0x9c]`, which the transport-owned status and live routes - seed to `multiplayer_transport_handle_validated_route_cookie_event` `0x005972c0`. That helper - either marks route progress and re-enters `multiplayer_transport_set_route_mode`, or forwards the - event id plus payload into the owner callback at `[transport+0x17f0]` with context - `[transport+0x17f8]`. The surrounding status-route callback vector is tighter now too: - `0x005970e0` publishes either the active selector text or the averaged probe sample at - `[entry+0x80]` and otherwise falls back to owner callback `[transport+0x17e0]`; - `0x00597180` is a straight owner-forwarding lane through `[transport+0x17e4]`; - `0x005971b0` seeds the local status-control id list and can then notify owner callback - `[transport+0x17e8]`; and `0x00597270` returns the third selector-slot generation counter - `[transport+0xac0]` on its bounded local branch before falling back to owner callback - `[transport+0x17ec]`. Subtype `6` still validates the same cookie, dedupes one 32-bit cookie or - packet id, and then dispatches the trailing payload through the natneg-or-raw callback layer - rooted at `[route+0xa0]` and `[route+0xa4]`. This separates the shell-frame preview refresh at - `0x006cd8d8` from the actual transport cadence at `0x006cd970`, and also separates that transport - cadence from the lower GameSpy route-service and packet-parser layer beneath it. -- Evidence: `function-map.csv`, `pending-template-store-management.md`, - `pending-template-store-functions.csv`, plus objdump caller traces showing - `multiplayer_window_service_loop` reaching `multiplayer_flush_session_event_transport` and the - transport pump chain `multiplayer_flush_session_event_transport -> - multiplayer_transport_flush_and_maybe_shutdown -> multiplayer_transport_service_frame -> - multiplayer_transport_service_worker_once -> multiplayer_transport_drain_request_text_queue`. -- Open Questions: unresolved request-id semantics for `1`, `2`, `4`, and `7`; whether any - non-mode-path helper outside the currently grounded release-and-rebuild flow ever patches - `[route+0xa4]` and `[route+0xd4]` for the transport-owned status/live routes, or whether those - packet families are simply unused in this stack; and how far the Multiplayer preview-dataset - machinery is reused outside `Multiplayer.win` beyond the currently grounded `.gmt` save-mode hook. +Detailed section: +[multiplayer-session-and-transport-flow.md](/home/jan/projects/rrt/docs/control-loop-atlas/multiplayer-session-and-transport-flow.md) ## Input, Save/Load, and Simulation -- Roots: the shell controller window-message ingress `shell_controller_window_message_dispatch` at - `0x0054e3a0`, the shell input-state object initialized at `0x006d4018` through - `shell_input_state_init` `0x0054e710`, the saved-world restore path - `world_load_saved_runtime_state_bundle` at `0x00446d40`, the live-world save path - `world_runtime_serialize_smp_bundle` at `0x00446240`, `world_entry_transition_and_runtime_bringup` - at `0x00443a50`, the frame-owned cadence `simulation_frame_accumulate_and_step_world` at - `0x00439140`, the recurring `GameMessage.win` service branch through - `game_message_window_service_if_present` `0x004e0720`, the world-facing `GameUppermost.win` - overlay branch ensured by `shell_ensure_game_uppermost_window` `0x004e0e40` and serviced through - `game_uppermost_window_service_world_hotspot_band` `0x004e0780`, and the lower step family rooted - at `simulation_advance_to_target_calendar_point` `0x0040ab50` with periodic branches through - `simulation_service_periodic_boundary_work` `0x0040a590`. -- Trigger/Cadence: shell-side input is event-driven by controller-window `WM_*` traffic while save - or load work is triggered either directly from shell commands or through the `fileopt.win` branch - flags into the `.smp` runtime-state family; post-bring-up world service becomes recurring once a - world root exists at `0x0062c120`, but the current grounded top-level cadence still remains the - shell-owned `shell_service_pump_iteration` path, which calls - `simulation_frame_accumulate_and_step_world` directly and lets it accumulate elapsed wall-clock - time into one or more simulation-step quanta. A second ingress is now bounded too: - `simulation_run_chunked_fast_forward_burst` at `0x00437b20` repeatedly calls the same lower - stepper `simulation_advance_to_target_calendar_point`, but current grounded callers put that - helper inside the larger post-load generation pipeline `world_run_post_load_generation_pipeline` - at `0x004384d0` under the `Seeding Economy...` phase rather than under the ordinary player-facing - speed buttons. That setup pipeline is now clearer at the progress-banner level too: on the fuller - setup path it first runs one preliminary named-candidate availability prepass through `0x00437743` - before any visible progress banner is posted. After that, localized id `318` - `Computing Transportation and Pricing...` stays visible while the pipeline runs - `world_compute_transport_and_pricing_grid` `0x0044fb70`, the early collection-owned staging pass - `world_rebuild_secondary_raster_derived_surface_and_companion_planes_in_rect` `0x0044e940`, - `world_setup_building_collection_phase` `0x0041ea50`, and the conditional region pair - `world_region_collection_seed_default_regions` `0x00421b60` plus - `world_region_border_overlay_rebuild` `0x004882e0`. The transport/pricing side is tighter now - too: `0x0044fb70` first routes one null-build path through the preview ensure wrapper - `0x0044faf0`, whose deeper worker `0x0044f840` allocates a default target through - `0x00534930`, seeds five palette entries through `0x0051de10`, maps each target pixel back into - the live secondary raster through `0x00533970/0x00533980`, uses the low-3-bit class split plus a - local `+/-4` neighborhood and `0x0051db80` to choose the preview color, and only then re-enters - `0x0044e940` on the full rectangle. The later `322` side is tighter now too: the top owner - `0x0044d410` rejects while generation counter `[world+0x2205]` is live or when `0x00449e90` - cannot supply a surviving work rect, then forwards that rect into `0x005374d0`, `0x00533e70`, - and `0x00537010`, notifies the shell owner at `0x0062be68`, and refreshes neighboring region or - manager companions through `0x00421f50`, `0x00461770`, and `0x00415340`. The local - companion-float strip under that same owner is tighter now too: `0x0044d4e0` and `0x0044d6e0` - are sibling five-pass cross-neighbor relaxers over `[world+0x1605]`; both clamp the caller - rectangle, average the four cardinal neighbors, subtract the current sample, scale the delta by - one fixed coefficient and caller gain, and then feed the surviving rectangle back into - `0x0044d410`. The first helper only checks raster bit `0x01` in `[world+0x2135]`, while the - second adds the tighter acceptance gate `0x004499c0` and can skip the final `0x0044d410` tail - when its caller disables that refresh. Their center-biased sibling `0x0044d880` is now bounded - too: it seeds one baseline from the current center sample when its caller gain is positive, - expands one square neighborhood by radius, and raises surrounding cells toward that baseline - through the same `0x0051dc00` falloff model before tailing into `0x0044d410`. The local - peak-oriented sibling `0x0044da70` then raises one clamped square neighborhood by quantized - local maxima and on its optional branch also consults `0x00534f00` before keeping the larger - peak. So the `0x0044d4e0/0x0044d6e0/0x0044d880/0x0044da70` band now reads as the local - companion-float refinement layer immediately beneath the shared `Calculating Heights...` owner - rather than a set of unrelated scalar writes. The default-region side is tighter too: - one earlier class-0-only helper `0x0041fb00` now sits directly under that same family too: - it skips nonzero `[region+0x23e]` records, rounds the region center through - `0x00455800/0x00455810/0x005a10d0`, stamps one orientation-dependent local secondary-overlay - pattern through `0x00534e10` plus `0x004497a0`, and then runs one bounded scored refinement pass - through `0x0051db80`, `0x00534040`, `0x005340a0`, `0x00534100`, and `0x00533fe0`. The finalizer - `0x00421730` then clears the per-cell region word at `[world+0x212d] + cell*4 + 1` across the - full live world raster, seeds each live region's cached bounds fields, and repopulates that same - raster by writing the nearest class-0 region id `[region+0x23a]` into empty or weaker cell slots - from one bounded center-and-radius sweep. The region-profile side is tighter too: `0x0041f940` - counts only the current subcollection entries whose backing - candidates pass `0x0041f998`, and that smaller predicate now has one real content split instead - of staying anonymous. Candidates whose subtype byte is not `2` pass immediately, while subtype-2 - candidates only pass when either availability word `[candidate+0xba]` or runtime recipe latch - `[candidate+0x7ac]` is nonzero; `0x00412af0/0x00412b70` now ground the lookup step beneath both - counters as a casefolded profile-label-to-candidate resolver over the global candidate pool - `0x0062b268`; and the stricter year-filtered counter `0x0041f9b0` then stacks the category and - `[profile+0x26] <= year` gates on top of that same availability test. That border - pass is now tighter too: the - outer owner refreshes the companion region set `0x006cfc9c` through the reset-and-assign wrapper - `0x00487650` above the heavier record initializer `0x00487540`, then re-enters `0x004881b0` to - refresh the raw per-region cell-count band from the live world raster, and the inner emitter - `0x00487de0` clears prior chunked segment queues through `0x00533cf0`, scans the live region - raster, and appends fresh border-segment records through `0x00536ea0`. The lower presentation - helper strip under the same owner is now explicit too: `0x00533970/0x00533980` query the cached - world-grid X/Y maxima, `0x00533ae0/0x00533af0/0x00533b00` expose the secondary-raster and - companion byte-raster roots, and `0x00533b20/0x00533b30/0x00533b70/0x00533b90` expose the - normalized coordinate, strip-offset, and sample-triplet tables used by shell-side overlay - staging. If shell-state gate - `[0x006cec74+0x174]` is set it then posts id `320` `Setting Up Buildings...` for - `world_region_collection_run_building_population_pass` `0x00421c20`; if `[0x006cec74+0x178] > 0` - it then posts id `321` `Seeding Economy...` for `simulation_run_chunked_fast_forward_burst` - `0x00437b20`; only after those setup-side gates does the code post id `319` - `Setting up Players and Companies...`. That `319` lane is no longer just a shell-state placeholder: its - earlier hidden prepass is tighter now too: `0x00437743` is the scenario-side named - candidate-availability seeding pass over the live candidate pool `0x0062b268`, feeding the - override collection at `[state+0x66b2]` through `0x00434f20` before any visible banner is posted. - That grounded write path is narrower than the static file evidence, though: the startup reset - helper `world_runtime_reset_startup_dispatch_state_bands` `0x004336d0` explicitly clears - `[state+0x66b2]` before the dispatch path begins, and the current exported write-side callers - we can name after that reset are still just the live-pool preseed `0x00437743`, the sibling - startup lane `0x00436ad7`, and the editor-side `Industry (Overall)` toggle handler - `0x004cf430` through `0x00434f20`. So while the fixed `0x6a70..0x73c0` candidate-availability - block is now well grounded as bundled map/save source data, a direct bulk-import path from that - block into the live runtime collection `[state+0x66b2]` is still not grounded by the current - disassembly notes. - That candidate-side table now has a grounded fixed record layout too: each entry is a `0x22`-byte - blob with a zero-terminated candidate-name slot at `[entry+0x00..+0x1d]` and one trailing - availability dword at `[entry+0x1e]`, read through `0x00434ea0` and mirrored later into - `[candidate+0x7ac]`. The same scenario state keeps a locomotive-side sibling collection at - `[state+0x66b6]`, read through `0x00435030` and updated through `0x004350b0`, which is now the - shared named locomotive-availability lane beneath the `Locomotives` editor page and the - startup-side locomotive seeding branches. That locomotive-side table is the same pattern at a - larger width: each entry is a `0x41`-byte blob with a zero-terminated locomotive-name slot at - `[entry+0x00..+0x3c]` and one trailing availability dword at `[entry+0x3d]`, later mirrored into - `[loco+0x7b]`. Both override dwords now read most safely as simple availability bits rather than - wider mode enums. That `319` lane is no longer just a shell-state placeholder: its - primary grounded work is still the chairman-profile pair - `world_seed_default_chairman_profile_slots` `0x004377a0` plus - `world_build_chairman_profile_slot_records` `0x00437220`, which seed the 16 selector bytes at - `[0x006cec7c+0x87]`, materialize the per-slot chairman records from the scenario selectors, - campaign override flag `[0x006cec7c+0xc5]`, and the static persona table at `0x005f2d28`, and then - publish the selected chairman-profile and linked company summary pair through `[state+0x25]` and - `[state+0x21]`. The local slot-record shape is tighter too because the shell editor panel around - `0x004cc2d0` now surfaces it directly: `[slot+0x00]` is the staged chairman profile id, - `[slot+0x01]` is the Optional-versus-Mandatory byte with nonzero=`Optional` and zero=`Mandatory`, - `[slot+0x02]` combines with the separate per-slot gate at `[world+0x0bc3+slot*9]` to surface - `Human`, `Computer`, and `Human or Computer`, `[slot+0x03]` is the special occupied-seat byte, and - `[slot+0x04]` is the numeric tuning field. Both the selector seeder and the record materializer - treat either `[slot+0x02]` or `[slot+0x03]` as enough to keep a slot live, but current grounded - writes only seed `[slot+0x03]` on slot zero and later move it solely by whole-record compaction. - That makes `[slot+0x03]` the strongest current anchor for the distinguished primary-human-seat - flag rather than a generic role byte. The summary fields are tighter too: current direct accessors - now show `[state+0x25]` as the selected chairman profile id in `0x006ceb9c`, while `[state+0x21]` - is the linked owning company id copied from `[profile+0x1dd]` through - `scenario_state_set_selected_chairman_profile` `0x00434890`. The editor-side scenario setup - surface beside that chairman panel is clearer now too. - `map_editor_scenario_metadata_panel_refresh_controls` `0x004ca790` republishes the scenario - description from `[0x006cec78+0x672e]`, the start-year trio `[+0x66ca]`, `[+0x66d2]`, and - `[+0x66ce]`, the direct campaign-designated bit `[+0x66de]` through control `0x5b6e`, and the - inverse of the paired metadata byte `[+0x66f3]` through control `0x5b74`. The resource-side - anchor is now explicit too: `editorDetail.win` carries localized ids `3160/3161` `Campaign - Scenario` and `If checked, this map will be reserved as a campaign scenario.` inside the control - record rooted at `0x5b6e`, so `[+0x66de]` is now the grounded campaign-scenario flag rather than - an anonymous metadata boolean. `map_editor_scenario_metadata_panel_refresh_briefing_mode` - `0x004ca670` now bounds the single-player versus multiplayer briefing switch by flipping selector - `0x621f50`, publishing localized headings `1491` and `3586`, and refreshing the two briefing texts - from `[state+0x4f30]` and `[+0x5ae9]`. The companion dispatcher - `map_editor_scenario_metadata_panel_handle_message` `0x004cb4a0` makes the year semantics tighter - too: it commits the description and both briefing texts from edit-control payloads, toggles the - same two booleans, and clamps the three year fields to `1829..2100` while maintaining `minimum <= - default <= maximum`, which now lines up directly with the editor strings `Description:` `Minimum - Start Year:` `Default Start Year:` `Maximum Start Year:` `Briefing` and `Multi-Player Briefing`. - The neighboring special-conditions page is clearer as well: - `map_editor_scenario_special_conditions_panel_construct` `0x004cb2b0` now grounds the live owner - for the `Setup_Options_Buttons.imb` list rooted at `0xa7fa`, walks the 49-entry static rule table - at `0x005f3ab0`, counts enabled flags from `[0x006cec78+0x4a7f]`, and publishes the `Special - Conditions In Effect` summary from localized id `1053`. The same page now has a bounded live - dispatcher too: `map_editor_scenario_special_conditions_panel_handle_message` `0x004cb8e0` handles - both bulk selection controls and direct row-state changes, commits them back into - `[0x006cec78+0x4a7f]`, and then re-enters the panel constructor to refresh the summary. That table - is no longer just a raw id run; it now clearly includes the finance and construction restrictions - `2535..2563`, plus later editor toggles such as `Use Bio-Accelerator Cars`, `Disable Cargo - Economy`, `Disable Train Crashes`, `Disable Train Crashes AND Breakdowns`, and `AI Ignore - Territories At Startup`. The neighboring available-chairman page is tighter too. - `map_editor_available_chairman_panel_construct` `0x004ca540` now bounds the shell-side owner for - the 40-entry persona-availability surface under `0x5aa0..0x5b03`: it walks the same persona table - family at `0x005f2d28`, publishes one localized chairman-name row per profile, counts enabled - availability bytes from `[0x006cec78+0x6987..]`, and emits the summary `%1 out of %2 are - selected.` from localized id `1035`. The live state owner beside it is now grounded as well: - `map_editor_available_chairman_panel_handle_message` `0x004cb6f0` handles three bulk-selection - controls `0x5aa1..0x5aa3` by rewriting that same availability-byte array from preset bytes - embedded in the persona table, and it also commits direct per-row toggle changes from - `0x5aaa..0x5b03` back into `[state+0x6987..]` before refreshing the page. So the editor lane now - has three distinct scenario-setup slices rather than one chairman-only blob: chairman slots, - scenario metadata and briefings, plus both a rule-toggle matrix and an available-chairman pool. - There is now one adjacent company-side lane too: current neighboring setup flow conditionally - enters `world_conditionally_seed_named_starting_railroad_companies` `0x0047d440` when the - Multiplayer preview owner `0x006cd8d8` is absent and either sandbox flag `[0x006cec7c+0x82]` is - set or shell-state flag `[0x006cec74+0x14c]` is set while editor-map mode `[0x006cec74+0x68]` is - clear. That helper no longer looks like a generic company refresh. It seeds exactly three fixed - named railroad-company records from `RT3.lng` ids `575..577`: `Missouri Pacific`, `New York - Central`, and `Grand Trunk Railroad`. The first seeded company is tied back to the selected - chairman-profile summary and becomes the selected company id. The second railroad is tighter now - too: it only receives a chairman link when `profile_collection_count_active_chairman_records` - finds at least two live chairman records, and the helper then binds the zero-based second active - chairman through `profile_collection_get_nth_active_chairman_record` with ordinal `1`. The third - railroad currently gets no matching chairman-link branch in the grounded setup flow and therefore - remains an unchaired named company in the live roster. The shell UI above that setup lane is now - tighter as well: `shell_company_list_window_construct` `0x004c7200` builds a live company-list - window over the company collection at `0x0062be10`, `shell_company_list_window_refresh_rows` - `0x004c6c30` formats the active companies with localized strings `267..270`, and only then - conditionally appends one synthetic row id `0x7fff` through - `shell_company_list_format_company_or_start_row` `0x004c6b40` so `<>` appears - as a separate affordance rather than as part of the seeded trio itself. Current shell paging - around that same roster is tighter too because the live company collection now has a grounded - active-only ordinal helper family: `company_collection_count_active_companies` `0x00429a50`, - `company_collection_count_active_companies_before_company_id` `0x004299f0`, and - `company_collection_get_nth_active_company_id` `0x00429990`. Those helpers now anchor the “current - company among active companies” math used by shell-side detail and picker flows rather than - leaving it as anonymous collection glue. `shell_company_list_window_handle_message` `0x004c6f30` - then routes the synthetic row into `start_new_company_dialog_open` `0x0047d080`, whose commit path - now grounds through `start_new_company_dialog_commit_create_company` `0x0047d120`. That lower - helper unlinks any current chairman-owned company, allocates a fresh company id from the live - collection at `0x0062be10`, initializes it through `0x00428420`, and only then publishes the new - selected company. The neighboring compact request helper - `start_new_company_request_create_company` `0x0047d320` does the same fresh-company path from a - request block and is already reached from the startup-company branch at `0x00470e48`. The - immediate sibling shell branch below that roster is still station-oriented: current grounded - resource names and handlers put one branch on `shell_station_detail_window_construct` - `0x005068c0`, another on `shell_station_list_window_construct` `0x005074c0`, and the subordinate - selector helper on `shell_station_pick_window_construct` `0x00507620`. But the broader - company-detail ownership question is no longer open. There is now a separately grounded - `CompanyDetail.win` family rooted at `shell_company_detail_window_construct` `0x004c5540`, with - `shell_company_detail_window_handle_message` `0x004c56a0` as its main dispatcher and - `shell_company_detail_window_refresh_controls` `0x004c2ca0` as the shared repopulation pass for - the selected-company presentation and tabbed control bands around `0x9476..0x9490`. A grounded - shell detail-manager caller reaches that constructor at `0x004dde24`, the first finance-action - layer beneath it is now bounded through `shell_company_detail_issue_bond_offer_flow` `0x004c3890`, - `shell_company_detail_issue_stock_offer_flow` `0x004c3f30`, - `shell_company_detail_buyback_stock_flow` `0x004c46d0`, and - `shell_company_detail_change_dividend_rate_flow` `0x004c5360`, and the first non-finance layer is - now bounded too through `shell_company_detail_resign_chairmanship_flow` `0x004c5a0e`, - `shell_company_detail_bankruptcy_flow` `0x004c5b99`, the territory-access family rooted at - `shell_company_detail_refresh_selected_territory_access_summary` `0x004c1b60` plus - `shell_company_detail_buy_territory_access_rights_flow` `0x004c5fc9`, backed by - `company_clear_selected_chairman_if_current_profile` `0x00428a10`, - `company_declare_bankruptcy_and_halve_bond_debt` `0x00425a90`, - `company_has_territory_access_rights` `0x00424010`, `company_set_territory_access_rights_byte` - `0x00424030`, and `company_can_purchase_territory_access_rights` `0x00426be0`, plus the two - control-transfer lanes. `shell_company_detail_attempt_chairmanship_takeover_flow` `0x0050ccc0` now - grounds the special chairman's election path: it checks the caller's current stock ownership in - the target company, rejects insufficient holdings through localized id `623`, rejects recent - failed attempts through id `624`, and then opens the confirmation under id `625` before seeding - the local takeover-election state or packaging the same request through the multiplayer shell - transport. The follow-on resolver `shell_resolve_chairmanship_takeover_vote_and_commit_outcome` - `0x0050c940` now closes the single-player election loop too: it walks the active chairman profile - collection, computes weighted votes for and against the takeover, compares the affirmative total - against half the target-company value, presents the result through - `shell_present_chairmanship_takeover_vote_outcome_dialog` `0x0050c500` in single-player or - localized id `3082` in multiplayer, and then either transfers chairmanship through `0x00428a30` or - stamps the current year into `[company+0x289]` as the grounded takeover-cooldown field. - `shell_company_detail_attempt_merger_flow` `0x004ec640` now grounds the merger side too: it - rejects empty worlds through id `727`, rejects recent failed attempts through id `728`, checks the - proposed premium against company cash through localized id `3889`, and then commits into the - resolver family. That merger resolver is now bounded too: - `shell_resolve_merger_vote_and_commit_outcome` `0x004ebd10` walks the active chairman profile - collection, computes weighted votes for and against the proposed merger, compares the affirmative - total against half the target-company value, presents the result through - `shell_present_merger_vote_outcome_dialog` `0x004eb890` in single-player or localized id `3059` in - multiplayer, and then either commits the merger through `0x00427e20` or stamps the current year - into `[company+0x15f]` as the grounded merger-cooldown field. The vote-bias side beneath that - resolver is tighter now too: `scenario_state_compute_issue_opinion_multiplier` `0x00436590` is no - longer just an abstract issue table lookup because its merger callsite uses issue id `0x3a`, which - lines up directly with localized id `726` saying merger votes depend on public attitude toward the - management of the two companies. By contrast the broader support-adjusted share-price helper - `company_compute_public_support_adjusted_share_price_scalar` `0x00424fd0` uses issue id `0x37`, - while the finance-side debt helpers now bound `0x38` and `0x39` separately as the explicit - credit-rating and prime-rate lanes. That leaves `0x37` as the broader investor-confidence lane - behind equity support, share price, and adjacent governance pressure, with the strongest current - text anchors coming from the investor-attitude strings `1217` and `3048/3049` about company or - chairman performance rather than from the merger-only management-attitude term. One older local lead is now ruled out too: the - `0x460a90` / `0x473620` setup block is the camera-view hotkey family over localized ids - `3482..3489` (`Select/Assign Camera View 5..8`), not issue-opinion infrastructure, so it should - no longer be used as evidence for the player-facing meaning of issue `0x37`. The editor-side - `Stock Prices` label is also no longer being used as direct evidence here: the `0x4ca980` / - `0x4cadf0` panel owns a separate float-tuning block `[state+0x0bde..0x0bf6]`, with - `[state+0x0bde]` merely mirroring `[state+0x0be2]`, so that label belongs to a different - settings family than the issue table behind `0x37`. A direct shell-resource follow-up now narrows - the remaining caption question too: the extracted `CompanyDetail.win` blob from `rt3_2WIN.PK4` - contains no plain-English investor or finance caption for this lane, which matches the owner-side - read that section-0 is a dynamic `0x947f` text widget fed by - `shell_format_company_governance_and_economy_status_panel` `0x004e5cf0` rather than a separate - fixed label row. The supporting stat layer is bounded more cleanly now too: the - surrounding `0x0b` setup in the merger and takeover offer builders is formatter mode rather than a - player-facing issue number, while the company-side stat wrapper - `company_read_year_or_control_transfer_metric_value` `0x0042a5d0` now reads as a generic - stat-family accessor over year-relative series or the bounded slot family in - `company_read_control_transfer_metric_slot` `0x0042a2e0`. Its recurring family token `0x2329` is - no longer treated as an issue id here either; it is the stat-family selector paired with localized - company-stat label id `2329`. That means the paired raw and scaled helpers at `0x004241e0` and - `0x00424200` now read as narrow control-transfer offer policy totals instead of direct - issue-argument consumers, and the same broader support-and-governance metric family now also feeds - the annual shareholder-revolt and creditor-liquidation lane surfaced by localized ids `300..304`. - The editor-side help text cluster around ids `2433..2437` is no longer floating either: current - grounded map-editor code now has a live economic tuning family beside the chairman-slot panel. - `map_editor_economic_cost_slider_panel_construct` `0x004cadf0` binds six slider controls through - `map_editor_economic_cost_slider_dispatch` `0x004ca980` into the scenario-state float block - `[0x006cec78+0x0be2..0x0bf6]`, while the surrounding descriptor table at `0x00611c70..0x00612220` - pairs that wider editor lane with localized fields `Prime Rate`, `Merger Premium`, and `Build - Stations Cost` through `Steam Engine Cost` plus the comparison or help texts `2433..2437`. The - broader shell-state master flag at `[0x006cec74+0x68]` still sits above the remaining post-load - phases, plus two narrower per-phase gates: `[0x006cec74+0x174]` directly fronts id `320` `Setting - Up Buildings...` and the later region-owned structure-demand and placement pass through - `world_region_collection_run_building_population_pass` `0x00421c20` plus the deeper per-region - worker `world_region_balance_structure_demand_and_place_candidates` `0x004235c0`, while - `[0x006cec74+0x178]` directly fronts id `321` `Seeding Economy...` and the chunked burst helper - `simulation_run_chunked_fast_forward_burst`, whose grounded tail now also sweeps the live region - collection through `world_region_refresh_cached_category_totals_and_weight_slots` `0x00423d30`; - id `322` then fronts `Calculating Heights...`. The - master `+0x68` flag is no longer just structural: the shell load/save coordinators now use the - same flag to force the editor-map `.gmp` family, so current evidence treats it as the broader - editor-map mode above those later setup branches rather than an unnamed generic toggle. That - worker is no longer one opaque building bucket: current grounded categories split into `House`, a - weighted region-profile family surfaced through the `Industry Weightings` stats path, and a third - branch whose low-level fallback token is `Commercial` but whose aligned stats label is `City - Support`. The same placement-commit gate beneath it, `world_region_validate_and_commit_candidate_placement` - `0x00422a70`, is also corroborated by the separate world-side randomized batch helper - `world_try_place_random_structure_batch_from_compact_record` `0x00430270`, which retries - placements around one compact center/radius record rather than the ordinary per-region demand - deficits. That batch placer now sits under a wider compact runtime-effect dispatcher, - `world_apply_compact_runtime_effect_record_to_resolved_targets` `0x00431b20`, so the world-side - branch is no longer just “another caller near `0x43051e`” but one real effect family alongside - the ordinary region-demand worker. Above that, the live scenario event collection at `0x0062be18` - now has a tighter runtime-effect lane too: `scenario_runtime_effect_record_service_and_dispatch_linked_compact_effects` - `0x004323a0` services one live runtime-effect record, dispatches its linked compact effects - through `0x00431b20`, and can synthesize follow-on records through - `scenario_runtime_effect_record_build_followon_effect_from_compact_record_and_targets` - `0x00430b50`, which in turn allocates new live records through - `scenario_event_collection_allocate_runtime_effect_record_from_compact_payload` `0x00432ea0`. - Above that, `scenario_event_collection_service_runtime_effect_records_for_trigger_kind` - `0x00432f40` now bounds the collection-wide loop that services those live runtime-effect records - for one trigger kind. That trigger split is tighter now too: recurring simulation maintenance - drives kinds `1`, `0`, `3`, and `2`; the neighboring route-style follow-on drives `5` and `4`; - startup-company and named-railroad creation branches drive `7`; kind `6` is now bounded as a - mixed post-change family spanning the placed-structure post-create tail, one build-version-gated - company-startup or roster-refresh tail, and the route-entry post-change sweep on `0x006cfca8`; - one world-entry-side one-shot gate drives `8` and then clears shell-profile latch - `[0x006cec7c+0x97]`; the briefing-text query lane is kind `9`; and the collection dirty latch - still forces the internal rerun at kind `0x0a`. - That moves this branch out of the “isolated world-side placement oddity” bucket and into a real - scenario-runtime effect pipeline with a mostly bounded trigger-kind family. - The same lower helper also reappears later on a slower - simulation-side cadence with - scale `1/12`, so it no longer looks like one-time setup glue only. The actual game-speed control - family remains separate, rooted at `world_set_game_speed_mode` `0x00434680`, - `world_adjust_game_speed_mode_delta` `0x00434850`, and `world_toggle_pause_or_restore_game_speed` - `0x00437a60`. -- CompanyDetail addendum: the shared helper `shell_company_detail_resolve_selected_company` at - `0x004c16f0` now bounds the common current-company accessor beneath the whole pane, and the - read-side owner also has a separate active-company navigation family through - `shell_company_detail_step_selected_active_company_delta` at `0x004c3470` plus the next or - previous wrappers at `0x004c3540` and `0x004c3550`. The section switch in - `shell_company_detail_window_refresh_controls` is now grounded too: section index `0x006cfe60` - selects a chairman/governance slice, a debt-and-capital slice, a per-share slice, or a - territory-access slice, published through the tab band around `0x9472..0x9479`, with adjacent - section-navigation controls around `0x947b..0x947c` and `0x948f..0x9490`. -- Key Dispatchers: `shell_controller_window_message_dispatch`, - `shell_input_apply_window_key_transition`, `shell_input_snapshot_dispatch_state`, - `shell_input_cursor_inside_active_view`, `world_load_saved_runtime_state_bundle`, - `world_runtime_serialize_smp_bundle`, `simulation_frame_accumulate_and_step_world`, - `game_message_window_service_if_present`, `game_message_window_service_frame`, - `game_uppermost_window_handle_message`, `game_uppermost_window_service_world_hotspot_band`, - `game_uppermost_window_refresh_controls`, - `world_view_service_keyboard_turn_pan_and_zoom_bindings`, `world_view_step_heading_quadrant`, - `world_view_step_zoom_bucket`, `world_seed_default_chairman_profile_slots`, - `world_build_chairman_profile_slot_records`, - `world_conditionally_seed_named_starting_railroad_companies`, - `scenario_state_set_selected_chairman_profile`, - `scenario_state_get_selected_chairman_profile_record`, - `scenario_state_get_selected_chairman_company_record`, `shell_company_list_window_construct`, - `shell_company_list_window_refresh_rows`, `shell_company_list_window_handle_message`, - `start_new_company_dialog_open`, `start_new_company_dialog_commit_create_company`, - `start_new_company_request_create_company`, `shell_station_detail_window_construct`, - `shell_station_list_window_construct`, `shell_station_list_window_handle_message`, - `shell_station_pick_window_construct`, `shell_station_pick_window_populate_station_rows`, - `map_editor_chairman_slot_panel_construct`, `map_editor_chairman_slot_panel_handle_message`, - `map_editor_chairman_slot_panel_refresh_selected_slot`, - `map_editor_chairman_slot_panel_cycle_selected_slot_profile`, - `map_editor_available_chairman_panel_construct`, - `map_editor_available_chairman_panel_handle_message`, - `map_editor_scenario_metadata_panel_refresh_briefing_mode`, - `map_editor_scenario_metadata_panel_refresh_controls`, - `map_editor_scenario_metadata_panel_handle_message`, - `map_editor_scenario_special_conditions_panel_construct`, - `map_editor_scenario_special_conditions_panel_handle_message`, - `map_editor_economic_cost_slider_panel_construct`, `map_editor_economic_cost_slider_dispatch`, - `station_place_world_surface_sync_and_dispatch`, `station_place_window_handle_message`, - `track_lay_window_refresh_controls`, `track_lay_window_service_frame`, - `track_lay_window_handle_message`, `simulation_advance_to_target_calendar_point`, the smaller - single-step helper at `0x00409e80`, `0x0040a9c0`, `0x0040a910`, and - `simulation_service_periodic_boundary_work`. -- State Anchors: shell input object `0x006d4018`, per-key state table starting at `[input+0x100]`, - packed shell input flags at `[input+0xa8c]` now grounded as Right Shift `0x1`, Left Shift `0x2`, - Control `0x4`, and Alt `0x20`, nested dispatch counter `[input+0xa90]`, global shell controller - `0x006d4024`, active world root `0x0062c120`, `GameMessage.win` object `0x006d081c`, - `GameUppermost.win` overlay object `0x006d0820`, `StationPlace.win` tool object `0x006d1720`, - `TrackLay.win` tool object `0x006d1a8c`, accumulated leftover simulation time at `[this+0x4c80]`, - shell and mode globals at `0x006cec74`, `0x006cec78`, and `0x006cec7c`, world manager collections - at `0x0062be10`, `0x006ceb9c`, `0x006cfcbc`, `0x006cec20`, `0x0062bae0`, and `0x006acd34`, plus - the packed calendar-like tuple fields around `[this+0x0d]`, `[this+0x0f]`, `[this+0x11]`, and - `[this+0x14]`. -- Subsystem Handoffs: the controller window dispatcher now looks like the first grounded input - ingress. It translates keyboard and mouse `WM_*` traffic into shell controller state and the - separate input object at `0x006d4018`; read-side cursor and camera helpers later snapshot that - object through `shell_input_snapshot_dispatch_state` and gate world-relative interaction through - `shell_input_cursor_inside_active_view`. Current grounded consumers around `0x00478cb0`, - `0x004e0780`, `0x0053f450`, and `0x0053fe90` still sit on the shell controller path and consult - `0x006d4024` or the world owner at `0x0062be68`, so there is still no evidence for a distinct - gameplay-only input object after world entry. Instead, the first deeper world-mode interaction - branch now looks like a shared world-view coordinator layered on top of the same shell-fed input - state. Shell_transition_mode ensures the `GameUppermost.win` object at `0x006d0820`; its message - dispatcher `game_uppermost_window_handle_message` owns the narrow action band `0x7918` through - `0x7921`; and the recurring service helper `game_uppermost_window_service_world_hotspot_band` - rate-limits those hotspot actions, rechecks `shell_input_cursor_inside_active_view`, and then pans - the live world view through `world_view_pan_relative_offset_in_camera_plane` `0x0043d130`. The - same lower setter family is also reached from the cursor-drag path through - `world_view_apply_screen_delta_to_focus_position` `0x0043d0c0`. Above both of those sits the - larger recurring service `world_view_service_shell_input_pan_and_hover` `0x0043db00`, which now - has one grounded keyboard branch beneath it: - `world_view_service_keyboard_turn_pan_and_zoom_bindings` `0x0043d740`. That helper resolves four - binding-pair families from the shell input table via `0x0054e7d0`, and the localized labels are - now grounded from `Data/Language/RT3.lng`: `Camera Forward` and `Camera Backward` feed the first - signed pan channel, `Camera Left` and `Camera Right` feed the second signed pan channel, `Camera - Zoom In` and `Camera Zoom Out` feed the signed zoom-step channel that `0x0043db00` smooths into - `world_view_step_zoom_bucket` `0x0043cc30`, and `Camera Rotate Left` plus `Camera Rotate Right` - feed the continuous heading-turn branch through `0x0043c810`. The setup side is now better bounded - too: `world_view_seed_keyboard_binding_slot_pairs` at `0x00439e40` seeds the eight slot pairs at - `[this+0x0a6]` through `[this+0x0e2]` from the global action-binding registry through `0x0045f370` - using the distinct registry keys `0x0043d2a0` through `0x0043d310`, and the registration block at - `0x00460769` through `0x004608e7` shows those roots are defaulted to the expected Up Down Left and - Right virtual keys before runtime polling begins. Beneath that camera stack, the enclosing frame - path now has one grounded non-view sidecar: after `0x0043db00` it reads the active controller-view - object pointer at `[0x006d4024+0x18]+0x366e`, compares it against the latched target at - `[frame_owner+0x66a2]`, fires exit and enter-style vtable callbacks on pointer changes through - slots `+0x64` and `+0x60`, and only latches the new object when the object passes its own slot - `+0x1c` availability test and shell detail control id `0x07d6` on `0x006d0818` has flag bit `0x4`. - That `0x07d6` gate is now more bounded than before: the dedicated `TrackLay.win` tool family - rooted at `0x006d1a8c` special-cases the same control id in both `track_lay_window_service_frame` - and `track_lay_window_handle_message`, uses world hit tests through `0x00448ac0` to arm and - release a drag latch on that surface, and routes the resulting command work through the shared - track-lay mode state at `0x00622b0c`. The surrounding `track_lay_window_refresh_controls` pass now - shows that this is not just one isolated drag handler: the same tool family owns three mutually - exclusive primary mode buttons at `0x985e` `0x985f` and `0x9860`, and current primary evidence now - bounds those values as `Lay single track.` `0x1`, `Lay double track.` `0x4`, and `Bulldoze` `0x40` - from the localized strings 2054 2055 and 1721 plus the matching control-routing branches in - `track_lay_window_handle_message`. The same family also owns the downstream route-entry policy - bridge at `0x004955b0`: current caller evidence says that helper maps the live TrackLay primary - mode into endpoint-synthesis policy `1` or `4` before the tool re-enters `0x00493cf0`, which is - the strongest current bridge from the player-facing single-track versus double-track buttons into - the lower route-builder policy bytes. The same family also owns a bridge-type preference selector - rooted at `0x006cec74+0x138`, two wrapped `Never` through `Common` frequency settings at - `0x006cec74+0x140` and `0x006cec74+0x13c`, two boolean track-lay preference toggles, and the - electrify-all-track action path. Those last two toggles are now tighter than before: current - evidence strongly aligns control `0x986e` and state `0x006cec74+0x144` with `Auto-Hide Trees - During Track Lay` from strings 1838 and 1839, while control `0x986d` and state `0x006cec78+0x4c74` - align with `Auto-Show Grade During Track Lay` from strings 3904 and 3905. That mapping is still - evidence-backed rather than absolutely direct from a recovered resource table, but the state - ownership and control order now make it the strongest current fit. That makes `0x07d6` look like - the shared main-world interaction surface inside a broader TrackLay world-command subsystem, not - an unrelated detail button. The neighboring `StationPlace.win` family is now grounded on that same - surface too: the shell detail-panel constructor family allocates it through - `station_place_window_construct` at `0x00509d80`, publishes it at `0x006d1720`, services it each - frame through `station_place_window_service_frame` at `0x0050a530`, and routes player-facing - commands through `station_place_window_handle_message` at `0x005091b0`. That dispatcher - special-cases the same `0x07d6` control, and the shared helper - `station_place_world_surface_sync_and_dispatch` at `0x00508bb0` either accepts that direct surface - traffic or falls back to the same detail-panel control looked up through `0x006d0818`, rechecks - flag bit `0x4`, hit-tests the world through `0x00448ac0`, stages world coordinates into - `0x006d1738` and `0x006d173c`, refreshes the selected-site summary through - `station_place_format_selected_site_summary`, and updates the live station-placement selection - state at `0x00622af0`, `0x00622aec`, and `0x006d1740`. The category side of that state is now - tighter too: the shared helper `0x0044bd10` quantizes the staged world coordinates into the - current cell, resolves the mixed byte-or-word region id from `[world+0x212d]`, looks up the - owning city-or-region entry through `0x0062bae0`, and returns `[entry+0x272]` with fallback - `5`; the StationPlace world-surface branches at `0x00508b80`, `0x00508d59`, and `0x0050a4e6` - use that result directly to refresh the current selection category latch at `0x00622af0`. - Together with - `station_place_select_category_and_refresh` `0x00508880`, - `station_place_refresh_category_controls` `0x00507b90`, and `station_place_format_preview_panel` - `0x00508730`, that makes StationPlace a second grounded consumer of the shared main-world - interaction surface rather than only a sibling constructor plus frame hook. The StationPlace - control semantics are now tighter too: the top category strip at `0x697c` through `0x6981` now - grounds as small station, medium station, large station, service tower, maintenance facility, and - non-station building from `RT3.lng` strings 2197 through 2202. For the three station categories - only, the secondary strip at `0x6988` and `0x6989` plus display field `0x698c` no longer looks - like another placement mode family; it is a building-style scroller. The click handlers on - `0x6988` and `0x6989` cycle the style override in `0x00622aec`, and the display path builds the - active style token from `StationSml`, `StationMed`, or `StationLrg` plus the localized - architecture styles `Victorian`, `Tudor`, `Southwest`, `Persian`, `Kyoto`, and `Clapboard` from - `RT3.lng` ids 2672 through 2667. One layer lower, the remaining opaque controls are now much - tighter: `0x6985` and `0x6986` are no longer a generic assist toggle but the two station-rotation - policy choices from strings 2207 and 2206, switching between auto-orienting the building to track - or obstacles and strictly obeying the rotation specified by the circle above. The dedicated - control at `0x6987` is the station-rotation circle itself, wired through callback `0x00507a90` and - aligned with `Click to rotate the building. You can also use bracket keys [ and ] to rotate - buildings.` string 2208. That matches the lower behavior too: when the strict-rotation choice is - off, both preview and commit paths route staged coordinates through `0x00508040`, which performs - the extra orientation search before validation; when strict rotation is on, that pass is skipped - and the current angle in `0x006d172c` is used directly. The direct shell UI also exposes the same - discrete view-step family through `world_view_step_heading_quadrant` `0x0043cb00` and - `world_view_step_zoom_bucket` `0x0043cc30`. The neighboring gating predicates - `world_view_should_drive_primary_pan_channel` and `world_view_should_drive_secondary_pan_channel` - test packed shell input bits `0x3`, and `shell_input_apply_window_key_transition` now grounds - those bits as the left and right Shift modifiers from scan codes `0x2a` and `0x36`. That means - cursor drag, overlay hotspots, held Shift state, direct keyboard turn/pan/zoom bindings, the - TrackLay and StationPlace world-command surfaces, and at least one frame-owned hover or - focus-target branch all converge under the same shell-fed world-mode input path rather than a - separate gameplay-input stack. -- Evidence: function-map rows for `shell_controller_window_message_dispatch`, - `shell_drain_pending_window_messages`, `shell_input_state_init`, - `shell_input_apply_window_key_transition`, `shell_input_snapshot_dispatch_state`, - `shell_input_cursor_inside_active_view`, `world_load_saved_runtime_state_bundle`, - `world_runtime_serialize_smp_bundle`, `world_entry_transition_and_runtime_bringup`, - `simulation_frame_accumulate_and_step_world`, `game_message_window_service_if_present`, - `game_message_window_service_frame`, `shell_ensure_game_uppermost_window`, - `game_uppermost_window_construct`, `game_uppermost_window_handle_message`, - `game_uppermost_window_service_world_hotspot_band`, `world_view_set_focus_position_xyz`, - `world_view_apply_screen_delta_to_focus_position`, - `world_view_pan_relative_offset_in_camera_plane`, `world_view_seed_keyboard_binding_slot_pairs`, - `world_view_service_keyboard_turn_pan_and_zoom_bindings`, `world_view_step_heading_quadrant`, - `world_view_step_zoom_bucket`, `world_view_should_drive_primary_pan_channel`, - `world_view_should_drive_secondary_pan_channel`, `world_view_service_shell_input_pan_and_hover`, - `world_seed_default_chairman_profile_slots`, `world_build_chairman_profile_slot_records`, - `world_conditionally_seed_named_starting_railroad_companies`, - `profile_collection_count_active_chairman_records`, - `profile_collection_get_nth_active_chairman_record`, - `scenario_state_set_selected_chairman_profile`, - `scenario_state_get_selected_chairman_profile_record`, - `scenario_state_get_selected_chairman_company_record`, `start_new_company_dialog_open`, - `start_new_company_dialog_commit_create_company`, `start_new_company_request_create_company`, - `shell_company_list_format_company_or_start_row`, - `shell_company_list_activate_or_shift_center_company`, `shell_company_list_window_refresh_rows`, - `shell_company_list_window_handle_message`, `shell_company_list_window_construct`, - `shell_company_detail_window_refresh_controls`, `shell_company_detail_window_construct`, - `shell_company_detail_window_handle_message`, `shell_station_detail_window_construct`, - `shell_station_list_window_construct`, `shell_station_list_window_handle_message`, - `shell_station_pick_window_construct`, `shell_station_pick_window_populate_station_rows`, - `map_editor_chairman_slot_panel_construct`, `map_editor_chairman_slot_panel_refresh_slot_list`, - `map_editor_chairman_slot_panel_refresh_selected_slot`, - `map_editor_chairman_slot_panel_refresh_slot_counters`, - `map_editor_chairman_slot_panel_cycle_selected_slot_profile`, - `map_editor_chairman_slot_panel_handle_message`, `map_editor_available_chairman_panel_construct`, - `map_editor_available_chairman_panel_handle_message`, - `map_editor_scenario_metadata_panel_refresh_briefing_mode`, - `map_editor_scenario_metadata_panel_refresh_controls`, - `map_editor_scenario_metadata_panel_handle_message`, - `map_editor_scenario_special_conditions_panel_construct`, - `map_editor_scenario_special_conditions_panel_handle_message`, - `map_editor_economic_cost_slider_panel_construct`, `map_editor_economic_cost_slider_dispatch`, - `station_place_refresh_category_controls`, `station_place_format_selected_site_summary`, - `station_place_format_preview_panel`, `station_place_select_category_and_refresh`, - `station_place_world_surface_sync_and_dispatch`, `station_place_window_handle_message`, - `station_place_window_construct`, `station_place_window_service_frame`, - `track_lay_window_refresh_controls`, `track_lay_window_construct`, - `track_lay_window_service_frame`, `track_lay_window_handle_message`, and - `simulation_service_periodic_boundary_work`, plus the shell-input disassembly around `0x0054f290`, - the world-view setup and service branches around `0x00439e40`, `0x0043d740`, `0x0043db00`, - `0x0043cb00`, and `0x0043cc30`, the `319` setup-side branches around `0x004377a0`, `0x00437220`, - `0x00477820`, `0x00477860`, `0x0047d440`, `0x004c6c30`, `0x004c6f30`, `0x0047d080`, `0x0047d120`, - `0x0047d320`, `0x004c2ca0`, `0x004c5540`, `0x004c56a0`, `0x005068c0`, `0x005071e0`, `0x005074c0`, - and `0x005076c0`, the direct summary-field helpers around `0x00434870` `0x00434890` and - `0x004348c0`, the company-link writers at `0x00427c70` and `0x00427d74`, the company constructor - at `0x00428420`, the startup-company branch around `0x00470e48`, the shell company-list strings - `266` `<>`, `267` `You are the chairman of the %1!`, `268` `The %1 has no - chairman at the moment.`, `269` `%1 is the chairman of the %2.`, `270` `Double-click for - details.`, and `2992` `Shift-Click to center on this company's primary station.`, the - `CompanyDetail.imb` and `CompanyDetail.win` resource strings in `.rdata`, the `StationDetail.imb`, - `StationDetail.win`, `StationList.win`, and `StationPick.win` resource strings in `.rdata`, the - shell editor window branches around `0x004c9da0`, `0x004ca010`, `0x004ca1c0`, `0x004ca540`, - `0x004ca670`, `0x004ca790`, `0x004ca980`, `0x004cb2b0`, `0x004cb4a0`, `0x004cb6f0`, `0x004cb8e0`, - `0x004cc250`, `0x004cc2d0`, `0x004ceb90`, and `0x004cecc0`, the localized chairman-slot strings - `2997` through `3001` `Optional` `Mandatory` `Human or Computer` `Computer` and `Human`, the - localized scenario-editor strings `1483..1492` `Description:` through `Type the briefing for this - map.`, the localized summary strings `1035` `%1 out of %2 are selected.` and `1053` `Special - Conditions In Effect`, the 40-entry persona availability page under `0x5aa0..0x5b03`, the 36-entry - special-condition table at `0x005f3ab0` covering ids `2535..2563`, `2874`, `3722`, `3835`, `3850`, - `3852`, and `3920`, the static persona table at `0x005f2d28`, the selector array at - `0x006cec7c+0x87`, the persona collection at `0x006ceb9c`, the localized persona strings in - `Data/Language/RT3.lng` including `2730` `Unassigned`, the named-chairman range `2731+`, and the - neighboring biography range `2495+`, plus the seeded railroad-name strings `575` `Missouri - Pacific`, `576` `New York Central`, and `577` `Grand Trunk Railroad`, the StationPlace.win - constructor plus category, dispatcher, rotation-circle, shared-world-surface, preview-build, and - recurring service branches around `0x00507a90`, `0x00507b90`, `0x00508550`, `0x00508730`, - `0x00508880`, `0x00508bb0`, `0x005091b0`, `0x00509d80`, and `0x0050a530`, the StationPlace string - cluster `Place a small station` 2197 `Place a medium station` 2198 `Place a large station` 2199 - `Place a service tower` 2200 `Place a maintenance facility` 2201 `Place a non-station building` - 2202 `Scroll through building styles.` 2203 `When placing the building, it will strictly adhere to - the rotation specified by the circle above.` 2206 `When placing the building, it will rotate - itself as needed to orient to track or avoid obstacles.` 2207 `Click to rotate the building. You - can also use bracket keys [ and ] to rotate buildings.` 2208 and the architecture-style labels - `Clapboard` 2667 `Kyoto` 2668 `Persian` 2669 `Southwest` 2670 `Tudor` 2671 and `Victorian` 2672, - the TrackLay.win constructor and dispatcher family around `0x0050d2d0`, `0x0050e400`, - `0x0050e1e0`, and `0x0050e5c0`, the localized `Never` through `Common` strings 615 through 618, - the track-lay strings `Bulldoze` 1721 `Lay single track.` 2054 `Lay double track.` 2055 and 3114, - and the deeper shared bulldoze helper at `0x0044b160`. That helper is no longer just a vague - proximity scan: it validates the active company unless editor mode is active, emits the exact - RT3.lng bulldoze rejection ladder `419..424`, reads company cash through `0x0042a5d0`, - debits approved bulldoze cost through `0x0042a080`, and then scans nearby route entries, - linked structures, city-or-region records, route blockers, and placed structures before - dispatching the selected delete branch through `0x004937f0`, `0x004941a0`, `0x0048abf0`, or the - surrounding placed-structure virtual slot `+0x58`. That makes the TrackLay `Bulldoze` mode - tighter than before: the tool-side mode latch at `0x00622b0c == 0x40` is only the front-end - selector, while the actual world-side bulldoze choice and failure policy sits under `0x0044b160` - and is reused by neighboring world-surface callers beyond TrackLay itself. - the TrackLay preference strings `Auto-Hide Trees During Track Lay` 1838 `If 'Auto-Hide Trees - During Track Lay' is checked, trees will automatically be reduced to small stumps whenever you are - in track laying mode.` 1839 `Auto-Show Grade During Track Lay` 3904 and `If 'Auto-Show Grade - During Track Lay' is checked, you'll see the grade number over the track while laying track - - useful for trying to keep your slopes to a minimum.` 3905, the electrify-all confirmation and - failure strings 3083 3084 3837 and 3900, the binding-registry lookup path at `0x0045f370`, the - registration block at `0x00460769` through `0x004608e7`, and the localized labels in - `Data/Language/RT3.lng` ids `3466` through `3473`. -- Open Questions: current evidence grounds the shell-controller-backed input and frame path as the - only coordinator after world entry; no separate outer gameplay loop or gameplay-only input - object is grounded yet. The new setup-pipeline evidence also points the same way: the - currently grounded chunked burst path at `0x00437b20` now looks subordinate to - `world_run_post_load_generation_pipeline` rather than to the ordinary speed controls, and even - there it still reuses the same lower stepper and pumps shell work between chunks instead of - revealing a detached gameplay loop owner. The player-facing speed-control family is now cleaner - too: `world_set_game_speed_mode` owns the bounded `Paused` through `Very Fast` ladder plus the - hidden `Ultra Fast 6..9` extension, `world_toggle_pause_or_restore_game_speed` uses `[this+0x1d]` - as the resume slot, and the multiplayer host restriction now looks attached to that same setter - family rather than to the setup-side burst helper. The frame-owned shell coupling is tighter now - too: inside `simulation_frame_accumulate_and_step_world` itself, one direct branch opens or - focuses `LoadScreen.win` through `shell_open_or_focus_load_screen_page`, and the post-step - shell-window ladder also probes several sibling shell windows by the same presence-plus-dirty - pattern, including the live `LoadScreen` singleton, the shared callback-driven custom modal, the - shared file-options dialog, `SettingsWindow.win`, the now-grounded `Overview.win` and - `BuildingDetail.win` singletons, the adjacent tool-window strip now grounded as - `Bulldoze.win`, `ChangeHeight.win`, `ChangeTrees.win`, `PaintRegion.win`, `PaintSound.win`, - `PaintTerrain.win`, `PaintTerritory.win`, and `StockBuy.win`, and now the shell-side - `Trainbuy.win` singleton too. That - train-buy family is no longer just an unnamed probe pair either: the opener path is now grounded - under the same shell-owned cadence through `shell_can_open_trainbuy_window_or_warn` and - `shell_open_or_focus_trainbuy_window`, and its current family semantics already extend beyond a - bare locomotive picker into selected-train upgrade summary and route-edit affordances. The - selected-train side is tighter now too: we have explicit query helpers for the selected train - record, id, validity, and company ownership, plus one explicit ownership-mismatch warning modal. - That same pass also clarified one boundary we should not conflate: the neighboring shell family - rooted at `0x006d3b20` is now grounded separately as `TrainDetail.win`. It reuses the same - selected-train context and some of the same helpers, but it is not the same `Trainbuy.win` - singleton family. The `TrainDetail.win` side now has its own constructor, opener, refresh path, - and message owner above the broader train-command strip. Its inner `0xcb` strip is tighter now - too: one bounded branch is the selected-train engine-replacement or trainbuy handoff lane using - warning ids `593/594`, and another is the selected-train retirement lane using `595/596/597` - with either a local teardown path or multiplayer opcode `0x37`. The remaining train-command - family is narrower too: the shared `0x33`-stride helper trio at `0x004b2f00`, `0x004b3000`, and - `0x004b3160` now looks like a real train route-stop or waypoint list rather than a generic row - buffer, and route-entry flag byte `+0x28` now has one grounded top-level split: sign bit clear - entries are the live placed-structure-backed family, while sign bit set entries use the direct - route-node payload side. The helper `train_route_list_count_live_site_reference_entries` - `0x004b2b80` now counts the first family explicitly. One deeper lower-bit result is grounded too: - both `train_route_list_insert_staged_entry_at_index` and the auxiliary finalize helper - `train_finalize_aux_route_entry_buffer_preserving_subflags` `0x004a94b0` explicitly preserve - bits `0x40`, `0x20`, and `0x10` in the same flag byte during route-entry rewrites. Those bits are - also no longer copy-only: the neighboring shell helper - `shell_building_detail_refresh_flagged_service_capability_rows` `0x004b9a20` now consumes them to - restyle the `BuildingDetail.win` row bands `0x7d07..0x7d1c` and `0x7f58..0x801f`. The exact - player-facing labels for those rows are still open, but the subflags now have one real shell-side - consumer instead of only preservation logic. The broader `BuildingDetail.win` refresh family is - tighter too: `shell_building_detail_refresh_subject_cargo_and_service_rows` `0x004ba3d0` now - clearly owns the selected subject rows around `0x7d06`, `0x7d96..`, and `0x7d0e`, resolving - ordinary ids through the live candidate collection and the special express-side ids through the - embedded `AnyCargo.imb`, `AnyFreight.imb`, and `PassMail.imb` paths. The first fixed triplet is - now table-grounded instead of only inferred: `0x00621df8` seeds the short-label controls - `0x7dc8..0x7dca` with RT3.lng `494..496` `Any Cargo`, `Any Freight`, and `Any Express`, while - `0x00621e10` seeds the adjacent `0x7e90..0x7e92` icon-name triplet with `AnyCargo`, - `AnyFreight`, and `PassMail` before `%1.imb` formatting. RT3.lng also tightens the longer popup - side now: `0x00621e04` feeds the first clickable selector triplet `0x7f58..0x7f5a` with - `494/497/498`, so the help text there is `Any Cargo`, `Any Freight\n(Freight is everything but - Passengers, Mail, and Troops)`, and `Any Express\n(Express is Passengers, Mail, and Troops)`. - The sibling special service rows still align to `Dining Car` and `Caboose`. The extracted - `BuildingDetail.win` blob now sharpens the resource boundary too: its embedded text table is - currently sparse rather than rich, exposing the help line for `0x7d01`, repeated - `BuildingDetail.imb` asset strings, and one standalone caption entry `Cargo`. That makes - `Cargo` the strongest current resource-side anchor for the row header around `0x7d06`. The - ordinary deeper rows are tighter now too: they do not look like hidden caption-table entries, - but like live candidate-derived rows. The current path validates each ordinary id through - `indexed_collection_entry_id_is_live` `0x00517d40`, resolves the concrete candidate record - through `indexed_collection_resolve_live_entry_by_id` `0x00518140`, and then reuses candidate - field `[record+0x04]` as one shared stem for both the row asset `%s.imb` path and the - neighboring display-label lookup through - `localization_lookup_display_label_by_stem_or_fallback` `0x0051c920`. That lookup is now - bounded too: it scans the static stem table at `0x006243c8`, already grounding entries such as - `Alcohol`, `Aluminum Mill`, `Automobiles`, `Bauxite`, and `Big Boy` against RT3.lng - `3202..3220`, and only falls back to localized id `3866` when no table entry matches before the - fixed `0x384..0x386` express-side triplet takes over. One neighboring candidate-side helper is - tighter now too: `structure_candidate_query_route_style_or_local_availability_metric` - `0x0041e650` shares the same route-style byte at `[candidate+0x46]`, returning the cached local - float at `[candidate+0x5a]` for ordinary candidates but switching route-style rows to one - normalized count over the world-side route-link collection `0x006ada90` keyed by candidate class - `[candidate+0x3e]`. That collection is tighter now too: it is constructed during world bring-up - by `placed_structure_route_link_collection_construct` `0x00468110`, and current grounded - creation flow through `placed_structure_route_link_allocate_site_pair_for_candidate_class` - `0x00467f50` seeds class byte `+0x10`, a masked initial state template, and the strongest - current creation-side site-pair fields at `+0x0c` and `+0x0e` before - `placed_structure_route_link_attach_site_owner` `0x00467eb0` links the new route-link record - into the placed-structure-owned chain at `[site+0x272]`. The owner-side split is tighter now - too: route-link field `+0x08` is the separate route-node-style owner anchor used by - `placed_structure_route_link_attach_route_node_owner` `0x00467f20`, while `+0x0a/+0x0c/+0x0e` - now read as the site-reference triple matched by - `placed_structure_route_link_collection_remove_links_touching_site_id` `0x004681f0`. Creation - flow now sharpens that further: `+0x0c` is the strongest current candidate for the stable - first-site field seeded before owner attachment, `+0x0a` is the mutable owner-site anchor - installed by the attach helper, and `+0x0e` is the stable second-site field. One more split is - tighter now too: `placed_structure_route_link_recompute_endpoint_pair_state` `0x00467c30` - currently uses `+0x0a` and `+0x0e` as the active endpoint site pair while recomputing state - byte `+0x12`; `+0x0c` is still not directly read there. The family also has a clearer release - and refresh side now: `placed_structure_route_link_release_and_detach` `0x004680b0` rolls back - the class counters and then tails into `placed_structure_route_link_detach_current_owner_chain` - `0x00467df0`, while - `placed_structure_route_link_collection_recompute_all_endpoint_pair_state` `0x004682c0` - explicitly reruns the per-record endpoint-pair reconciler across the whole live route-link - collection. One layer above that, - `placed_structure_route_link_rebuild_route_style_grid_counters_and_endpoint_state` - `0x00468300` now looks like the full-family refresh owner: it clears three route-style class - lanes in the world-grid tables rooted at `[0x0062c120+0x2129]`, then clears bit `0x2` across - the live route-link records and reruns the endpoint-pair reconciler. That now lines up with the - visible shell split: non-route candidates keep the richer local metric and price lane, while - route-style candidates use one world-side route-link family instead. The emission side is - tighter now too: `placed_structure_try_emit_best_route_style_peer_link_for_candidate_class` - `0x0040fef0` scans the live placed-structure collection for one best peer site by - class-specific weight, distance window, and type gate, then only creates a new route-link - through `placed_structure_route_link_allocate_site_pair_for_candidate_class` `0x00467f50` when - `placed_structure_endpoint_pair_has_shared_route_entry_key` `0x0040fbe0` says the chosen site - pair does not already share a route-entry key. One layer above that, - `placed_structure_rebuild_route_style_candidate_scores_and_peer_links` `0x004101e0` now reads - as the broader per-site owner of this lane: it computes per-class route-style score scalars from - local site state and scenario multipliers, drives the first three route-style emission attempts, - and then continues into a larger descriptor-driven scoring phase. Inside that larger pass, - `placed_structure_accumulate_candidate_metric_or_emit_route_style_peer_link` `0x0042cab0` - now cleanly shows the split between ordinary candidates, which add directly into the local - route-style grid lane at `[site+candidate*4+0x103]`, and remapped route-style candidates, which - re-enter the peer-link emitter. One layer above that, the broader post-create or post-edit site - rebuild `placed_structure_finalize_creation_or_rebuild_local_runtime_state` `0x0040ef10` - conditionally re-enters `0x004101e0` with stack flag `1` when its local latch at `[site+0x29e]` - stays clear, so the route-style lane is no longer floating under an unnamed single-site caller. - The placement side is tighter now too: the direct constructor - `placed_structure_collection_allocate_and_construct_entry` `0x004134d0` is the shared allocator - immediately beneath the current placement-side callers before they hand the new site into - `0x0040ef10`, and the lower constructor - `placed_structure_construct_entry_from_candidate_and_world_args` `0x0040f6d0` now bounds the - actual field-seeding layer beneath that allocator. The old unresolved higher placement chooser is - bounded more cleanly now too: the `0x00403ed5` and `0x0040446b` direct-placement commits sit - inside one larger helper, - `city_connection_try_build_route_with_optional_direct_site_placement` `0x00402cb0`. That shared - heavy builder is now the common target of the compact wrapper `0x00404640`, the peer-route - candidate builder `0x004046a0`, the region-entry pair wrapper - `city_connection_try_build_route_between_region_entry_pair` `0x00404c60`, and the direct retry - paths inside `simulation_try_select_and_publish_company_start_or_city_connection_news` - `0x00404ce0`. Internally it now has three bounded lanes: - an early route-entry search or synthesis attempt through - `route_entry_collection_try_build_path_between_optional_endpoint_entries` `0x004a01a0`, - a single-endpoint direct-placement lane that scans `Maintenance` and `ServiceTower` candidates - and commits through `0x00403ed5 -> 0x004134d0 -> 0x0040ef10`, - and a later paired-endpoint fallback lane that seeds two endpoint candidates from the same stem - family, walks a temporary route-entry list, and commits through - `0x0040446b -> 0x004134d0 -> 0x0040ef10`. - That early lane can now be described more concretely: it can reuse supplied route-entry - endpoints, synthesize a missing leading endpoint from the caller's coordinates, seed the - route-store builder-state block, and then hand off to the deeper path-search core without - placing a new site. The previously vague side family at `0x006cfcb4` is tighter too: current - evidence now bounds it as a small auxiliary route-entry tracker collection with an allocator at - `0x004a42b0`, a refcount or destroy path at `0x004a4340`, a direct route-entry group-id setter - at `0x00489f80`, an endpoint-membership probe at `0x00494ed0`, a boolean-latch refresh or - owner-notify path at `0x00494fb0`, and a two-endpoint merge or bind helper at `0x00494f00`. - One smaller constructor-side ownership split is tighter now too: the cached `u16` chain fields - `[site+0x26e]`, `[site+0x270]`, and `[site+0x383]` are no longer free-floating. Constructor-side - helper `0x0041f7e0` prepends one new peer into that chain by storing the old head from - `[this+0x383]` into `[peer+0x270]` and then replacing `[this+0x383]` with the peer's own - placed-structure id `[peer+0x2a4]`; the direct resolver `0x0041f810` turns the cached head id - back into one live record through `0x0062b26c`; and the removal-side companion `0x0041f850` - removes one peer from the same chain before clearing `[peer+0x26e/+0x270]`. That caller split is - now strong enough to treat this as one cached single-link or predecessor-chain family beneath - placed-structure construction and rebuild rather than as unrelated scratch words. - That bind side is tighter now too: the trackers group route entries only when a route-key-like - value from `0x0048aa70`, the route-entry signature word `+0x22e`, and the boolean latch derived - from byte `+0x44` all agree. The deeper handoff under that lane is no longer anonymous either: - `route_entry_collection_search_path_between_entry_or_coord_endpoints` `0x0049d380` is now - bounded as the internal search core that runs the first candidate sweep, quality gates, and the - later route-extension fallbacks before returning one resolved route-entry id or `-1`. The first - sweep now has a bounded owner at `0x0049bd40`, and the two later fallback helpers are bounded as - the route-entry point-window coverage query `0x00494cb0` and the frontier-extension helper - `0x0049c900`. The math side is bounded more cleanly now too: the family reuses - `math_measure_float_xy_pair_distance` `0x0051db80` for its direct point-to-point scalar, - `math_compute_quadrant_adjusted_heading_angle_from_xy_pair` `0x004952f0` for heading-angle - construction, `math_normalize_subtracted_angle_delta_and_report_wrap` `0x004953c0` for wrapped - angle-delta checks, and `math_abs_double_with_crt_special_case_handling` `0x005a152e` for the - absolute-value side of the quality gates. Current evidence also bounds the threshold shape a - little more tightly: the initial sweep and later extension path both reuse one signed angle-bias - term `+/-0.181000038854627`, and the first sweep switches between a looser `1.4` and stricter - `1.8` quality multiplier depending on route-policy byte `4` or the broader display-runtime - preference `[0x006cec78+0x4c74]`, already grounded elsewhere as `Auto-Show Grade During Track - Lay`. - The small policy-byte semantics are still not fully closed, but current evidence is tighter than - before. Literal byte `1` is now the strongest current match for direct linked-site - endpoint-anchor creation or replacement, because the linked-site constructor and neighboring - repair branches around `0x00480463`, `0x00480a77`, and `0x00480b69` all feed that byte into - `0x00493cf0` before rebinding one chosen route-entry anchor through `0x0048abc0`. Literal byte - `2` now looks broader: the later world-side caller at `0x00480cd0` and the linked-site refresh - helper `placed_structure_refresh_linked_site_display_name_and_route_anchor` `0x00480bb0` both - reach `0x004a01a0` with both optional endpoint-entry ids unset and that byte, so the strongest - current read is a full linked-site route-anchor rebuild between optional endpoint entries rather - than the narrower direct creation lane. The TrackLay side now gives one tighter user-facing - anchor too: the live mode field `0x00622b0c` is already grounded as `Lay single track.` `0x1` - versus `Lay double track.` `0x4`, and the small mapper `0x004955b0` collapses that state into - the endpoint-policy bytes later passed to `0x00493cf0`, so the strongest current read is - `policy 1 = single-track endpoint synthesis` and `policy 4 = double-track endpoint synthesis`. - Bytes `1/2` are still the ones that enable the - auxiliary tracker lane in `0x004a01a0`, while byte `4` now reads more narrowly as the larger - company-side endpoint-synthesis charge inside `0x00493cf0`, because that helper feeds `-1` - versus `-2` into the saturating company counter helper `0x00423ec0` on `[company+0x7680]` - rather than skipping the company branch entirely. That counter is tighter now too: nearby - company initialization seeds it to `50` when scenario byte `0x4aaf` is enabled and to sentinel - `-1` otherwise, while the companion getter `0x004240a0` returns either the live counter or fixed - fallback `29999`. Current language-table correlation also gives `0x4aaf` a stronger - player-facing meaning: it is the live gate behind `Company track laying is limited...` and the - event variable label `Company Track Pieces Buildable`. So the current strongest read is - available track-laying capacity, not an abstract company route-budget. That site-side helper - also closes one adjacent ownership gap: beneath - `placed_structure_finalize_creation_or_rebuild_local_runtime_state` `0x0040ef10`, it rebuilds - one linked site's route-entry anchor and display-name buffer. That path is tighter now than just - “bind anchor then touch `0x006cfcb4`”: after the literal-policy-`2` rebuild succeeds it - re-enters `aux_route_entry_tracker_collection_refresh_route_entry_group_membership` `0x004a45f0`, - which can now be described more concretely. Its early prepass at `0x004a4380` can split one - mismatching adjacent subchain into a fresh tracker group; its later helper at `0x004a4ce0` can - transfer one compatible adjacent chain between neighboring groups; and the repair-side helper at - `0x004a4ff0` can reseed a whole route-entry component into a fresh tracker when the old group id - is missing or invalid. The regrouping pass also still rewrites compatible endpoint slots through - `0x004950f0` and refreshes one nearby cached-match payload band through `0x00495020` before the - helper resumes the name-buffer work. The remaining display-name side still matches the earlier - grounded text family: copy the resolved city name when available, append civic suffixes - `Township`, `New`, `Modern`, or `Renaissance`, append `Service Tower` or `Maintenance Facility` - on the linked-instance class branches, and otherwise fall back through the older - `Junction`..`Center` and `Anytown` text families. - The higher owner-refresh side of that same tracker family is tighter now too. The reusable gate - at `0x004a4c00` no longer looks like a stray predicate: it explicitly requires both route-entry - trackers to keep matching cached fields `+0x18/+0x1c/+0x1d/+0x1e` and both route entries to keep - their special side fields `+0x20e/+0x222` unset before adjacent-chain transfer is allowed. The - collection-wide traversal sweep at `0x004a5fc0` is bounded now as the connected-component refresh - owner over tracker field `+0x0c`, with a temporary queue at `[this+0x94]` and direct fallback - into the reseed helper `0x004a4ff0` whenever one neighboring route entry has lost valid tracker - ownership. Above both of those sits `aux_route_entry_tracker_collection_refresh_owner_adjacent_compatible_group_links` - `0x004a6360`, which now reads as the owner-side latch-change refresher invoked from - `0x00494fb0`: it starts from one owner route-entry id, confirms both bound endpoint entries agree - on the boolean class state implied by route-entry byte `+0x44`, and then probes both endpoint - sides for adjacent route-entry groups that can be absorbed through the `0x004a4c00 -> 0x004a4ce0` - gate-and-transfer pair. The sibling query side is bounded now too: - `aux_route_entry_tracker_collection_query_component_label_by_tracker_id` `0x004a6320` is the - dirty-aware accessor for tracker field `+0x0c`, while - `aux_route_entry_tracker_dispatch_route_entry_pair_metric_query` `0x004a65b0` is the remaining - mode-switched lower metric dispatcher beneath the heavier chooser at `0x004a6630`, forwarding - fixed route-entry-pair candidate sets into either `0x004a5280` or `0x004a5900` depending on the - shared hundredths-scaled build-version query - `runtime_query_hundredths_scaled_build_version` `0x00482e00` over `0x006cec74`. The current - caller thresholds `>= 0x67`, `>= 0x68`, `>= 0x69`, and `>= 0x6a` now line up with executable - build values `1.03`, `1.04`, `1.05`, and `1.06`, and the version source itself can come from - the multiplayer companion path as well as the local executable, so this split is no longer - best-read as a time- or era-side cutover at all. It now reads more cleanly as a pre-`1.03` - versus `1.03+` route-metric compatibility dispatcher. That lower split is tighter now too: - `0x004a5280` is the weighted recursive branch with heuristic ordering, per-tracker best-cost - cache `0x006cfcac`, and prune threshold `0x006cfcb0`, while `0x004a5900` is the alternate - recursive neighbor-walk branch that stays within compatible component labels through - `0x004a62c0` and accumulates step and mismatch penalties over route-entry links - `+0x206/+0x20a/+0x20e`. Above both of them, - `aux_route_entry_tracker_query_best_route_entry_pair_metric_with_endpoint_fallbacks` - `0x004a6630` is now bounded as the real chooser: direct fixed-pair query when both entries pass - `0x0048b870`, otherwise endpoint-pair fallback across the two tracker groups. - The adjacent route-style rebuild side is tighter now too: the same build-version family reaches - `placed_structure_rebuild_route_style_candidate_scores_and_peer_links` `0x004101e0`, where build - `1.04+` keeps one `Recycling Plant` stem-specific compatibility branch alive and build `1.05+` - skips one older descriptor-side attenuation fallback. There is also one neighboring world-side - compatibility lane now bounded below the same family: `placed_structure_collect_connected_component_tile_bounds_with_version_gate` - `0x004160c0` skips one older recursive component-bounds walk through `0x00415f20` on build - `1.03+` when scenario field `[0x006cec78+0x46c38]` is already active. The wrapper above that - path is bounded now too: `placed_structure_map_tile_range_to_connected_component_records_with_optional_bounds_refresh` - `0x00416170` walks the caller rectangle, maps tile keys into the component table rooted at - `0x0062ba7c`, and only re-enters `0x004160c0` when the current owner still has no cached bounds - and the local world or scenario suppressors stay clear. The higher neighboring raster side is - tighter too. `world_grid_refresh_projected_rect_sample_band_and_flag_mask` `0x00418610` is the - shared projected-rectangle helper above `world_grid_refresh_flagged_region_float_extrema_and_mean` - `0x00415020`: it refreshes the temporary sample band at `0x0062b7d0`, publishes the surviving - rectangle through `0x0044d410`, and on the single-sample path re-enters - `world_grid_toggle_flagged_mask_bit0_for_nonsentinel_rect_samples` `0x004185a0` to flip mask bit - `0x01` for the corresponding non-sentinel cells. Current grounded callers for `0x00418610` are - the neighboring placed-structure local-runtime helper `0x00418be0` and the heavier placement - validator `0x004197e0`, so this adjacent family now reads more like projected placement or local - raster prep than an unowned generic world-grid scan. One neighboring caller into the same - height-support band is tighter now too: the world-side branch at `0x00419070..0x004190f0` - walks one admitted local window, dispatches the acceptance-gated relaxer `0x0044d6e0` once per - cell with a one-cell radius and no immediate tail refresh, and only after that outer loop - completes re-enters `0x0044d410` on the full surviving rectangle. The higher owner split is - tighter now too. - `placed_structure_build_local_runtime_record_from_candidate_stem_and_projected_scratch` - `0x00418be0` is the broader construction or rebuild lane: resolve one candidate id from a stem, - build projected scratch through `0x00416ec0`, then publish the projected rectangle and validate - its side windows through `placed_structure_publish_projected_runtime_rect_globals_and_validate_side_windows` - `0x00416620`. That publish pass is bounded now too: it stages `0x0062b308/0x0062b30c/0x0062b310`, - validates the rectangle against route-entry coverage through - `route_entry_collection_query_rect_window_passes_entry_type_gate` `0x00494240`, can branch into - the special projected-slot picker `placed_structure_try_select_projected_rect_profile_slot` - `0x00415570`, and refreshes the compact per-cell side tables through - `world_grid_refresh_projected_rect_surface_and_region_byte_tables` `0x00414e10` before the - finished scratch is copied into one queued runtime record and the new record re-enters - `0x00416170` when its rectangle is valid. The smaller sibling - `0x00419200` is now bounded beneath that same projected-rectangle family too: it is the tiny - getter over the temporary dword cell-value bank at `0x0062b300`, flattening one caller cell - through live world width `[0x0062c120+0x2155]` and returning the corresponding dword when the - bank exists, else `0`. Current grounded caller is the later world-side branch at `0x0048af99`. - The smaller sibling - `placed_structure_clone_template_local_runtime_record_for_subject_and_refresh_component_bounds` - `0x00418a60` now reads as the current-subject clone path above the same connected-component and - mask-refresh helpers, returning the cloned local runtime record later stored into `[site+0x24e]` - by `placed_structure_refresh_cloned_local_runtime_record_from_current_candidate_stem` - `0x0040e450`. The higher wrapper above that clone path is bounded now too: - `placed_structure_collection_refresh_local_runtime_records_and_position_scalars` `0x004133b0` - first drains the temporary site-id queue rooted at `0x0062ba64/0x0062ba6c/0x0062ba70` through - `placed_structure_local_runtime_site_id_queue_count` `0x00414480` and - `placed_structure_local_runtime_site_id_queue_pop_next` `0x00413f50`, rebuilding one cloned - local-runtime record per queued placed structure through `0x0040e450`, and only then sweeps all - live placed structures through the side refresh helper - `placed_structure_refresh_local_runtime_position_triplet_and_linked_anchor_followon` `0x0040ee10`. - The constructor or ownership split beneath that family is tighter now too. The shared allocator - `placed_structure_collection_allocate_and_construct_entry` `0x004134d0` no longer just reaches - an anonymous `0x3e1`-byte scratch object: it first constructs one concrete placed-structure - specialization through `placed_structure_construct_concrete_specialization_vtable_5c8c50` - `0x0040c950`, which calls `0x0045b680` to seed the common base table `0x005cb4c0`, clear the - derived field band `[this+0x23a..+0x26a]`, and re-enter the older base initializer - `0x00455610`, then installs the specialization table `0x005c8c50`. The paired cleanup path at - `0x0040c970` now reads like the matching teardown thunk: it briefly reinstalls `0x005c8c50`, - then immediately demotes the record back to the base table through `0x0045b040 -> - 0x00455650` before the stack object is freed or unwound. The corresponding serializer entry - `0x0040c980` is equally tight now: it simply tails into `0x0045b560`, which first re-enters the - base serializer `0x004559d0` and then emits the derived payload bracketed by tags `0x5dc1` and - `0x5dc2` over `[this+0x23e]`, `[this+0x242]`, `[this+0x246]`, `[this+0x24e]`, and `[this+0x252]`. - One nearby string clue is useful but narrower than it first looked. The specialization table at - `0x005c8c50` is immediately followed by `RadioStation` and `Radio Station`, but the local member - method `0x0040ce60` now shows why: it compares site stem `[this+0x3ae]` against `Radio Station`, - canonicalizes that stem to `RadioStation` on match, and then re-enters `0x0040cd70` plus - `0x0045c150`. So those adjacent strings ground one stem-normalization lane inside the - specialization, not the specialization name by themselves. The small virtual-slot and cached-id - side is tighter now too. The same `0x005c8c50` table carries three literal-false stubs - `0x0040cc10/0x0040cc20/0x0040cc30`, one literal-true stub `0x0040ccc0`, and the narrower - linked-site-id presence predicate `0x0040ccb0`, which simply returns whether `[this+0x2a8]` is - nonzero. Beneath the stem-normalization path, `0x0040cd70` is now bounded as the common cached - source/candidate resolver: it clears `[this+0x3cc]` and `[this+0x3d0]`, scans source collection - `0x0062b2fc` for a stem match against `[this+0x3ae]`, stores the matched source id into - `[this+0x3cc]` plus the linked candidate/profile id from `[source+0x173]` into `[this+0x3d0]`, - and when no match exists formats localized id `0x00ad` through `0x0051e980` with the current - stem buffer. The two tiny followers `0x0040cec0` and `0x0040cee0` then resolve those cached ids - back into concrete source and candidate records through `0x0062b2fc` and `0x0062b268` - respectively. The derived payload and transient family under that same table is tighter now too. - `0x0045c150` is the clear payload-loader - counterpart to `0x0045b560`: it reinitializes the derived field band, opens the `0x5dc1/0x5dc2` - payload bracket, restores the two payload strings into `[this+0x23e]` and `[this+0x242]`, clears - the transient roots `[this+0x24e]`, `[this+0x256]`, `[this+0x25a]`, and `[this+0x25e]`, and then - rebuilds follow-on specialization state through `0x0045b5f0` and `0x0045b6f0`. The neighboring - builder pair is coherent too: `0x0045b210` formats `amb_%1_01.wav`, allocates a `0x141`-byte - transient object, stores it at `[this+0x24a]`, and registers it through `0x0052da00`, while - `0x0045c310` allocates the separate primary transient handle at `[this+0x246]` from payload - strings `[this+0x23e]` and `[this+0x242]`, then publishes it through `0x00530720` and - `0x0052d8a0`. The next rebuild layer is tighter now too. `0x0045b5f0` resolves one current - world-position tuple through `0x0052e720 -> 0x0051f090 -> 0x00534490`, then uses that derived - scalar to refresh the ambient-side transient again through `0x0045b210`. Above that, - `0x0045b6f0` clears the optional handles at `[this+0x25a]` and `[this+0x25e]`, then probes and - materializes a larger named variant family rooted in `[this+0x23e]` through strings such as - `%1_`, `%1_Upgrade1`, `%1_Anim%2.3dp`, `%1_Upgrade1Anim%2.3dp`, and - `%1_Upgrade1Light%2.3dp`, looping across numbered variants and publishing surviving records - through `0x0052d8a0`. One higher timed branch is bounded now too: `0x0045baf0` advances the two - timer-like fields `[this+0x26a]` and `[this+0x266]`, gates on nearby world-distance and - candidate-side checks, and then formats one output around `rnd_%1_%2.wav` plus the same anim or - light string family before dispatching through `0x00531e50` under owner `0x006d402c`. Their - release-side companions `0x0045b160` and `0x0045c3c0` tear down those same transient roots and - payload strings again, and the recurring service slice `0x0045be50` updates the derived scalar - triplet `[this+0x22e]`, `[this+0x232]`, and `[this+0x236]` before republishing it through - `0x00530720`. The string literals `amb_%1_01.wav`, `%1_Anim%2.3dp`, - `%1_Upgrade1Anim%2.3dp`, `%1_Upgrade1Light%2.3dp`, and `rnd_%1_%2.wav` therefore ground the - derived band `[this+0x23e..+0x26a]` as one payload-plus-transient owner family with ambient, - animation, light, and random-sound components, rather than more linked-site or route-entry ids. - One intermediate transient build layer is bounded now too. `0x0040cf00` first requires - creation-mode byte `[this+0x3d4] == 1` and live seed handle `[this+0x24e]`, re-enters - `0x0045b370(1)`, derives one scaled float from current local geometry through `[this+0x14]`, - `[this+0x21]`, `[this+0x3a]`, and `0x005c8cf4`, and then allocates a second transient handle - into `[this+0x25a]` through `0x00475ed0`. It follows that with one current world-position - resolve through `0x00414450` and `0x0052e720`, several local offset-triplet writes through - `0x00475010`, and four numbered channel updates through `0x00475030` with selector ids `1..4`. - That is enough to bound it as another specialization-side transient-handle builder beneath the - same payload family as `0x0045c310` and `0x0045b210`, without yet over-naming the user-facing - subtype or effect semantics of the built handle. - One adjacent helper block is tighter now too, and it should stay separate from the concrete - `0x005c8c50` vtable rather than being folded into it. The small predicates - `0x0040cc40/0x0040cc60/0x0040cc80` all follow the same `[this+0x173] -> 0x0062b268` chain into - one linked candidate/profile record. `0x0040cc40` returns whether candidate subtype byte - `[candidate+0x32]` equals `1`, `0x0040cc60` returns raw candidate byte `[candidate+0xba]`, and - `0x0040cc80` returns the stricter conjunction `subtype == 1 && class == 3` using class byte - `[candidate+0x8c]`. The current grounded caller for all three is - `world_grid_refresh_projected_rect_sample_band_and_flag_mask` `0x00418610`, where they derive - the two boolean mode inputs for `0x00415020`; that makes them a shared candidate-profile helper - cluster adjacent to the specialization family, not direct overrides in the `0x005c8c50` table. - The neighboring `0x0040ccf0` stays on the same “adjacent but not the same vtable” side of the - boundary: it resolves one linked instance through `0x0047de00`, follows that instance's vtable - `+0x80` owner chain, and returns candidate class byte `[candidate+0x8c]`. Current grounded - callers at `0x00480fb5` and `0x004b03ce` compare that returned class against `3` and `4`, so the - current safest note is simply “linked-instance candidate-class reader.” One gated collection-side - scan in the same neighborhood is bounded now too. `0x0040cd10` first requires shell latch - `[0x006cec74+0x1c3]` and creation-mode byte `[this+0x3d4] == 1`, then resolves the current - subject's center world-grid cell through `0x00455f60`, reads the local site roster count and id - list at `[cell+0xeb]` and `[cell+0xef]`, and resolves each listed placed-structure id through - `0x006cec20`. Its current grounded caller is the broader collection sweep at `0x00413860`, so - the strongest current read is a gated center-cell site-roster scan rather than one more direct - specialization override. - One small neighboring world-grid helper is grounded cleanly enough to keep too. `0x0040ccd0` - takes one live world root, one X-like index, and one Y-like index, multiplies the Y-like term by - world width `[world+0x2145]`, adds the X-like term, scales the resulting slot by fixed cell - stride `0x1d7`, and returns the corresponding cell pointer under base `[world+0x2129]`. Current - grounded callers include the placed-structure cargo-service bitset sweep around `0x0042c386` and - several world-grid overlay passes in the `0x004525bc..0x00452bb2` range, so that helper is now - best read as the shared `(x,y) -> world-cell*` resolver rather than another object-specific - method. - The next sibling table at `0x005c9750` is tighter now too, though still not fully decoded. The - structural anchor is `map_load_city_database` `0x00474610`: that loader stages bundle tags - `0x61a9..0x61ab`, iterates one collection, and dispatches each entry through vtable slot `+0x44`. - In `0x005c9750`, that same slot resolves into the sibling record family beside - `0x0041ab70/0x0041ab80`, which is enough to treat the table as the city-database entry family - rather than a generic unresolved runtime object. The small load-side slot `0x0041ab70` simply - jumps into `0x0045c6f0`, which restores two strings into `[this+0x32e]` and `[this+0x332]`, - stages the same `0x61a9/0x61aa/0x61ab` tag family, and iterates the child runtime band rooted at - `[this+0x316]`. The one real behavioral slot we recovered there is `0x0041ab80`: it refreshes - one named handle through owner `0x006d4020`, writes the resulting handle into `[this+0x1c]`, - queries three base floats through `0x0045c480`, and returns one scaled float derived from the - first queried component. That method is currently called from later world-side branches at - `0x0046e4f7`, `0x004aafee`, and `0x004ab020`. The exact user-facing semantics of the handle and - the many constant-return virtuals in the same table are still open, but the family boundary is no - longer arbitrary: this is now the current city-database entry vtable cluster, not another - placed-structure specialization. One correction matters here too: the lower - `0x00455660/0x00455800/0x00455810/0x00455930` helpers are no longer city-only. Local `.rdata` - now shows the same shared slots under both the city-entry table `0x005c9750` and the sibling - `Infrastructure` table `0x005cfd00`, whose constructors at `0x0048a240/0x0048a2dc/0x00490a3c` - all re-enter `0x00455b20`, install `0x005cfd00`, and seed the same scalar-band family through - `0x00455b70` with the literal stem `Infrastructure`. So the safest current family name for those - low helpers is the broader `0x23a` runtime-object band rather than city-entry-only. `0x00455800` - and `0x00455810` are simply the paired normalized coordinate getters over `[this+0x1e2]` and - `[this+0x1ea]`, which explains why they recur all over the city-side, route-link, and - placed-structure placement code. The narrower helper `0x00455660` sits above those getters: it - scales the caller-supplied normalized coordinate pair, converts it through - `0x006d4024 -> 0x0051f090 -> 0x00534490`, adds a caller-supplied integer height bias, optionally - rounds that height through `0x005a10d0` when the auxiliary-preview gate `0x00434050` is active, - and finally publishes the resulting world-anchor triplet through `0x00530720`. One - serializer-side sibling is bounded too. `0x00455930` queries two triplet-like scalar bands - through `0x0052e720` and `0x0052e880` and writes the resulting six dwords through `0x00531030`; - its load-side stream counterpart `0x00455870` reads the same six four-byte lanes back through - `0x00531150`, republishes the first triplet through `0x00530720`, republishes the second through - `0x0052e8b0`, and returns the summed byte count. The tagged load-side mirror `0x004559d0` - restores the same `[this+0x206/+0x20a/+0x20e]` band beneath tags `0x55f1..0x55f3`, then - dispatches vtable slot `+0x4c`. The `Infrastructure` side is tighter now too. The optional child - attach helper `0x0048a1e0` allocates and seeds one fresh `Infrastructure` child and, when the - owner already has more than one child, clones the first child's two triplet bands into that new - child before attaching it. The looped rebuild `0x0048dd50` then rebuilds the owner-visible - `Infrastructure` children one ordinal at a time, tears down the higher extras above ordinal `5`, - refreshes cached primary-child slot `[this+0x248]` when needed, and finishes with the same - world-cell and route-side follow-on family around `0x00448a70`, `0x00493660`, and `0x0048b660`. - The smaller attach helper `0x00490a3c` is now bounded too: it conditionally allocates one - `Infrastructure` child from a caller-supplied payload stem, attaches it to the current owner, and - then seeds three caller-supplied position lanes through `0x00539530` and `0x0053a5b0`. The - direct route-entry side of the same family is no longer anonymous either: `0x0048e140`, - `0x0048e160`, and `0x0048e180` are the three direct resolvers over owner fields - `[this+0x206/+0x20a/+0x20e]` into the live route-entry collection `0x006cfca8`. Another shared - sibling family is tight enough now too: the real - packed-byte-triplet owner is `0x0052e680`, and the two local - wrappers `0x00455820` and `0x00455840` both force its recursion flag on. `0x00455820` forwards - three explicit byte arguments, while `0x00455840` unpacks one packed `u24`-style dword into - three byte lanes first. The downstream setter writes packed byte-triplet lane `[this+0x43]`, - defaults that lane to `0x007f7f7f` when all three bytes are zero, and when recursion is enabled - it walks child list `[this+0x75]` through `0x00556ef0/0x00556f00` and re-applies the same packed - update recursively to every child. The sibling `Infrastructure` table `0x005cfd00` also still - carries three tiny fixed-return slots after the shared formatter thunk `0x00455860`: two return - literal `0x46`, and one returns fixed float `1.25f`, so those slots are now bounded as small - table constants rather than as missing behavior. One other sibling table is bounded enough now - to keep separate too: local `.rdata` at `0x005c9a60` carries the same shared low `0x23a` slots - plus table-specific overrides `0x0041f680`, `0x0041f720`, `0x0041f7b0`, `0x0041f7e0`, - `0x0041f810`, and `0x0041f850`, with nearby literals `(%1)` and `Marker09`. The exact subtype - name behind that table is still open, but the behavior split is strong enough: `0x0041f680` - first refreshes the current global preview/helper owner through `0x00455de0` and then forwards - mode `1` plus handle `[this+0x23a]` into `0x004cf830`; `0x0041f720` formats `[this+0x356]`, - publishes the resulting shell text, and conditionally dispatches `0x00452fa0` with action - `0x12` when world state `[0x0062c120+0x2175]` is `0` or `0x15`; `0x0041f7b0` publishes one - fixed payload and only then jumps to `0x00453510` when that same world state is `0x12`. The - same table also has a tighter adjacent helper strip now: `0x0041f6a0` is the direct - `[this+0x37f] -> 0x00517cf0` slot-count query, `0x0041f6b0` is the rounded normalized-coordinate - world-scalar query above `0x0044afa0`, and that deeper helper is no longer opaque: it first - computes one distance-like term from the current cell to global preview-anchor fields - `[0x0062be68+0x24/+0x1c]` through the precomputed radial helper `0x0051dc00`, samples the - companion float raster `[world+0x1605]` at the current cell plus two 8-direction rings, keeps - the strongest local rise above the center sample, adds one thresholded preview-scalar bias from - `[0x0062be68+0x20]`, and then adds `0x32` more when the small global gate `0x0041fff0` passes. - That gate itself now reads as a shared shell/preview threshold test: it returns true when - `[0x006cec74+0x2bb] == 2`, or when the same mode dword is merely nonzero and preview scalar - `[0x0062be68+0x20]` exceeds the float threshold at `0x005c9a9c`. `0x0041f6e0` resolves the - current center world-grid cell and checks one packed `u16` token through `0x0042b2d0`, and - `0x0041f6f0` is the raw byte getter over `[this+0x42]`. One nearby mode-gated flag reader is - bounded too: `0x0041f910` returns - literal `1` when shell mode gate `0x004338c0` is inactive or the object class dword - `[this+0x23e]` is nonzero, and only on the class-0 path does it return the same byte - `[this+0x42]`. The release side under that same sibling family is bounded too: `0x00420650` - lazily seeds `[this+0x317]` from shell-profile word `[0x006cec78+0x0d]` before re-entering - `0x00420350`, and that body is now bounded as the local scalar refresh over `[this+0x31b]`: - it compares the seeded word against the current shell-profile word, maps the delta through one - bounded piecewise float curve, and applies one extra affine adjustment when `[this+0x23e]` is - nonzero. `0x00420670` then frees the optional dynamic payload at - `[this+0x37f]`, clears the cached `u16` link chain through `0x0041f8d0`, and tails into base - cleanup `0x00455d20`; and the small collection-side wrapper `0x00421700` simply resolves one - entry id, re-enters `0x00420670`, and erases that id from the owning collection. The - city-entry family also now has one tighter - helper-object branch. `0x00474030` - switches over mode enum `0..10`, maps those cases into `0x00475ed0` with selector families - `4/0xd/0xe` and fixed scalar presets `0.5/0.75/1.0/1.5/2.0`, and on success publishes the - caller-supplied world triplet through `[helper+0x4]`. The refresh helper `0x00474260` first - reloads payload through `0x00455fc0`, then samples the current normalized coordinates plus one - world-height scalar from `0x00448bd0`, and rebuilds `[this+0x23a]` through that same - mode-selected helper builder using mode `[this+0x242]`. The surrounding collection-side and - teardown helpers are tight enough now too. `0x004743d0` and `0x00474400` are the two release - siblings over the same helper field `[this+0x23a]`: both destroy that helper through `0x00475100` - when live and clear the field, but `0x004743d0` tails into the smaller base cleanup - `0x00455650`, while `0x00474400` tails into the heavier dynamic-payload cleanup `0x00455d20`. - The small predicate `0x00474430` simply returns `1` unless shell mode gate `0x004338c0` is - active, in which case it returns byte `[this+0x42]`; the exact meaning of that flag byte is still - open, but the mode-gated query itself is bounded now. One level higher, `0x00474450` constructs - the collection rooted at vtable `0x005ce4a8` with fixed parameters `(0,0,0,0x14,0x0a,0,0)`, and - bootstrap caller `0x004487a9` stores that collection into global `0x006cea50`. The collection's - entry path is also bounded now: `0x004744a0` seeds a stack-local temporary entry through - `0x00474110`, allocates one `0x250`-byte live record, resolves it, constructs it through - `0x00474130`, and then tears the temporary entry down through `0x004743d0`; `0x00474510` - resolves one entry id, releases it through `0x00474400`, and removes it from the collection. The - collection-owned load loop at `0x00474540` sits directly beneath `map_load_city_database` - `0x00474610`: it opens the same `0x61a9/0x61aa/0x61ab` bracket on the caller-supplied bundle, - binds the selected path context, iterates the current collection, dispatches each record through - vtable slot `+0x40`, accumulates the returned byte counts, and tears down the temporary entry - after each record. That still leaves broader semantic questions open, but the current static edges - around the city-entry family are now largely exhausted. The adjacent scaffolding is bounded too. - Base helper `0x00455b20` initializes the shared `0x23a`-sized record family by installing base - vtable `0x005cb1c0`, clearing the scalar bands `[+0x206/+0x20a/+0x20e/+0x22e/+0x232]`, zeroing - the seven-dword block `[+0x212..+0x22a]`, and re-entering `0x0052ecd0`; that is why it shows up - not only in the city-entry temporary constructor `0x00474110`, but also in several later object - construction paths outside the city family. The city collection itself now has a bounded teardown - side too: `0x00474480` is the small release-and-free wrapper for the collection rooted at - `0x005ce4a8`, and teardown caller `0x004492c3` uses it before freeing the global collection - pointer at `0x006cea50`. On the load side, `0x00445713`'s broader setup branch re-enters - `map_load_city_database` `0x00474610` on that same global `0x006cea50` collection. Outside the - city-specific branch, the two tiny dispatch wrappers `0x00455a40` and `0x00455a50` are also now - bounded as raw vtable-slot helpers: the first jumps through entry slot `+0x44`, while the second - pushes one caller argument into slot `+0x40` and then clears the global roots - `0x006acd38/0x006acd3c/0x006acd40`. Finally, `0x00455a70` is now bounded as the generic - current-position triplet publisher that queries `0x0052e720`, converts through - `0x006d4024 -> 0x0051f090 -> 0x00534490`, adds a caller-supplied height bias, optionally rounds - under `0x00434050`, and publishes through `0x00530720`. The temporary-entry constructor and live - entry constructor are bounded now too. `0x00474110` is the tiny stack-local initializer: it - re-enters shared base init `0x00455b20`, clears helper fields `[+0x23a]` and `[+0x242]`, - installs vtable `0x005ce428`, and returns. `0x00474130` is the real live-entry constructor: it - stores the entry id into `[+0x23e]`, clears the trailing helper payload block `[+0x246..+0x24e]`, - stores mode `[+0x242]`, derives one world-height scalar from the supplied coordinate pair through - `0x00448bd0`, builds helper field `[+0x23a]` through `0x00474030`, and then seeds the remaining - default scalar or flag tuple through `0x00455b70` using the fixed defaults at - `0x005ce49c/0x005ce4a0/0x005ce4a4`. That broader helper is no longer city-specific either: - `0x00455b70` is now bounded as the shared scalar-band initializer that clears the same - `[+0x206/+0x20a/+0x20e/+0x22e/+0x232]` family, optionally copies up to three caller-supplied - strings into `[+0x206/+0x20a/+0x20e]`, synthesizes one default local token buffer when the middle - string is absent, chooses one effective mode string from the third or first input, derives one - owner handle or transform token through `0x0051f090` unless the caller suppresses that path, and - then seeds the remaining scalar band through `0x0052edf0` and `0x0052e670`. - The same specialization also now has one tighter UI-facing side. The override trio - `0x0040e4e0`, `0x0040e880`, and `0x0040e9d0` all sit in the same `0x005c8c50` table and reuse - the linked-site-capable vtable `+0x70` latch together with creation-mode byte `[this+0x3d4]`. - `0x0040e4e0` is the strongest current owner for contextual status text: it branches across - linked-peer checks, world-mode fields `[0x0062c120+0x2171/+0x2175/+0x2179/+0x2181]`, current - owner state, and candidate or linked-peer display labels, then formats localized ids such as - `0x00af`, `0x00b0`, `0x00b1`, `0x00b2`, `0x00b3`, and `0x0afd` before pushing the result through - shell presenter `0x00538c70`. `0x0040e880` pairs with that publisher on the action side: it - first resets the same presenter through the fixed token at `0x005c87a8`, then dispatches several - world-side follow-ons through `0x00413620`, `0x00453510`, `0x00452db0`, and `0x00452fa0` under - the same linked-peer and world-mode gates. `0x0040e9d0` is the narrower query-style formatter: - when shell branch `[0x006cec74+0x74]` is live it formats one localized label with the fixed - suffix `\nAbsIndex %d`, otherwise it can return one company-side owner label through - `0x00426b10`, and only then falls back to `0x00455860`. So the current best read is that this - concrete specialization owns both the ambient or animation transient family and one linked-peer - status or action UI surface, without yet proving the user-facing subtype name. - One smaller subtype hook cluster is tighter now too. The concrete table also carries - `0x0040d170` and `0x0040d1b0`, both of which resolve the current candidate through cached stem id - `[this+0x3cc]` and then test candidate dword `[candidate+0x4b]`. When that flag is nonzero, - `0x0040d170` tail-calls the primary transient builder `0x0045c310` and `0x0040d1b0` tail-calls - the matching release path `0x0045c3c0`. The same neighborhood now also gives direct cached-record - resolvers instead of more anonymous pointer math: `0x0040d1f0` returns the linked peer from - `[this+0x2a8]` through `0x006cec20`, while `0x0040d210` returns the owner-side record from - `[this+0x276]` through `0x0062be10`. That makes the specialization-side ownership split cleaner: - the `0x005c8c50` family is not only formatting labels and driving side effects, it also has a - direct candidate-flag hook for building or dropping the primary transient handle. - The last lower side reads are tighter now too. `0x0040e450` first seeds the projected-slot cache - through `placed_structure_cache_projected_rect_profile_slot_id` `0x00414470` before it re-enters - `0x00418a60`, and the broader stem-based builder at `0x00418be0` now has one named optional side - renderer instead of an anonymous callsite: - `placed_structure_render_local_runtime_overlay_payload_from_projected_bounds` `0x00418040`. - The side refresh split is bounded now too. `0x0040ee10` publishes one local position or scalar - triplet through the shared setter `0x00530720`, then tails into - `placed_structure_refresh_linked_site_anchor_position_triplet_for_local_runtime` `0x0040e360`; - that smaller follow-on only runs on the current subtype-`1`, class-`3`, linked-site branch, and - recomputes one local-runtime triplet from the linked peer's route-entry anchor when that anchor - is still live. The heavier sibling above that side refresh is bounded now too: - `placed_structure_set_world_coords_and_refresh_local_runtime_side_state` `0x0040eba0` is the - world-coordinate mutation helper that recomputes `[site+0x388]` and `[site+0x38c]`, rewrites the - world-grid owner mapping through `0x0042c9f0` and `0x0042c9a0`, updates the subtype-`4` - proximity-bucket family when needed, rebuilds the same local position or scalar triplet, and - then tails into the linked-site anchor follow-on at `0x0040e360`. One later caller into that - same side-refresh family is bounded now too: `0x00419110` clamps a caller rectangle to the live - world bounds, resolves one per-cell bucket chain through the hashed map at `[arg0+0x88]` and - `0x0053dae0`, and then re-enters `0x0040eba0` for every bucketed site in that rectangle using - the stored per-entry coordinate pair plus two zero flags. Current grounded caller is the edit-side - branch at `0x004bc851`, immediately after the neighboring nibble and companion-float mutations, - so this now looks like a bucket-map-driven local-runtime side-state refresh wrapper rather than - another broad site sweep. - The sibling policy-`1` side is tighter now too. The constructor lane no longer stops at “one - linked site id at `[site+0x2a8]`”: the subtype-`1` branch in - `placed_structure_construct_entry_from_candidate_and_world_args` `0x0040f6d0` now clearly - allocates that linked record through - `placed_structure_collection_allocate_and_construct_linked_site_record` `0x00481390`, whose lower - constructor is `placed_structure_construct_linked_site_record_from_anchor_and_coords` - `0x00480210`. That lower constructor seeds the linked record's own id and anchor-site id, clears - the local route-anchor and display-name fields, projects the anchor footprint into world space, - and then either binds an already-covered route entry through `0x00417b40` or falls through into - the neighboring policy-`1` route-entry synthesis family around `0x00493cf0` before rebinding the - chosen route entry through `0x0048abc0`. - The cleanup side is tighter now too. Linked-site removal now has a bounded owner at - `placed_structure_collection_remove_linked_site_record` `0x004813d0`: it resolves the linked - record through `0x006cec20`, runs the per-record teardown - `placed_structure_teardown_linked_site_runtime_state_before_removal` `0x00480590`, removes the - live entry from the collection, and only then re-enters the still-bounded company-wide follow-on - at `0x00429c10` when the removed record passed the narrower transit-like latch. That per-record - teardown is no longer just “clear some scratch fields.” It now clearly clears the route-style - scratch lane, clears the five proximity buckets at `[site+0x590..0x5b8]`, detaches or invalidates - the current route-entry anchor, frees the three per-site byte arrays at `[site+0x24..0x2c]`, - clears this site's indexed byte from the corresponding arrays of later placed-structure records, - and then re-enters `0x00436040` with the current site id. - That company-side follow-on is no longer just one opaque callback either. It is now bounded as - `company_collection_refresh_active_company_linked_transit_site_peer_caches` `0x00429c10`, which - walks the active company roster and re-enters - `company_rebuild_linked_transit_site_peer_cache` `0x004093d0` on each company. That per-company - fast pass stamps a refresh tick at `[company+0x0d3e]`, clears and repopulates the - placed-structure-side cache cells addressed through `[site+0x5bd][company_id]`, marks the - eligible linked transit sites for that company, allocates one `0x0d`-stride peer table for each - eligible site, and fills those peer rows from - `aux_route_entry_tracker_query_best_route_entry_pair_metric_with_endpoint_fallbacks` - `0x004a6630`. That helper no longer reads as one anonymous route sweep: it either uses the fixed - pair directly or falls back across tracker endpoint combinations before returning the winning - route-entry id, one route-step count, and one companion mismatch count. The fast cache now reads - more cleanly too: peer-record dword `+0x05` stores that step count, while float `+0x09` stores - the normalized continuity share derived from `(steps - mismatches) / max(steps, 1)`, not a raw - delta-per-step ratio. The - adjacent timed wrapper `company_service_linked_transit_site_caches` `0x00409720` now shows the - cadence too: `0x004093d0` is the shorter-interval refresh, while the older heavier sibling at - `0x00407bd0` was only revisited on the longer interval. - That heavier sibling is now bounded too: - `company_rebuild_linked_transit_autoroute_site_score_cache` `0x00407bd0` no longer looks like a - generic tail refresh. It reuses the fast peer tables, rebuilds candidate-local amount bands plus - normalized issue-opinion scales, and then folds the peer-side route metrics back into three - per-site cache floats with a cleaner split: - `+0x12` is the raw surviving site-score total, - `+0x0e` is the continuity-and-step-weighted companion total, - and `+0x16` is the promoted final site-ranking lane chosen from the strongest grouped candidate - bands. - That also closes most of the cross-version impact question: - the pre-`1.03` versus `1.03+` tracker metric split now looks like it mainly perturbs the weighted - `+0x0e` lane and the promoted `+0x16` lane, not the raw `+0x12` total. - That final lane then feeds the neighboring selectors - `company_select_best_owned_linked_transit_site_by_autoroute_score` `0x00408280` and - `company_build_linked_transit_autoroute_entry` `0x00408380`. That makes the company-side follow-on - read more like a linked-transit autoroute cache family than a generic company maintenance pass. - The neighboring reachability gate is tighter now too: - `company_query_cached_linked_transit_route_anchor_entry_id` `0x00401860` caches one company-side - route-entry anchor, and - `placed_structure_is_linked_transit_site_reachable_from_company_route_anchor` `0x004801a0` - uses that anchor to decide whether a foreign linked transit site can still participate in the - current company's fast peer cache. - The first direct train-side consumer above that cache family is bounded now too: - `train_try_append_linked_transit_autoroute_entry` `0x00409770`. After servicing the owning - company's caches, it asks `0x00408380` for one staged `0x33`-byte route entry using the train's - current anchor site, then either appends that entry through `0x004b3160` and refreshes the new - trailing selection through `0x004b2f00`, or rotates one existing slot in place when the local - two-entry cap has already been reached. So this edge now reaches an actual train-side autoroute - append lane rather than stopping at anonymous company-side cache cells. The weighted cache lanes - still do not escape that route-choice family directly: this train-side append path only inherits - the weighted site and peer choice by calling `0x00408380`, not by reading cache `+0x0e/+0x16` - itself. - The train-side follow-on above that seed path is bounded now too. The owning company can count - its live roster through `company_count_owned_trains` `0x004264c0`, measure one aggregate linked - transit site pressure through `company_compute_owned_linked_transit_site_score_total` - `0x00408f70`, and then rebalance that roster through - `company_balance_linked_transit_train_roster` `0x00409950`. - The aggregate helper no longer reads as a raw sum either: - it starts from the site-cache `+0x12` totals, converts that into one tentative roster target - through year and site-count ladders, and on build `1.03+` adds one special distance-side scaling - branch when exactly two eligible linked transit sites survive. - Because it consumes `+0x12` rather than `+0x0e` or `+0x16`, current evidence now says the tracker - compatibility split is more important for seeded route choice and ranked site choice than for the - final company train-count target itself. The local linked-transit chain is now bounded enough to - say that directly: weighted cache lanes feed `0x00408280 -> 0x00408380 -> 0x00409770/0x00409830`, - while the separate pressure or roster lane feeds `0x00408f70 -> 0x00409950` from raw `+0x12`. - The balancer then applies two age bands to company-owned trains: - very old trains are removed when the roster already exceeds target or upgraded when it still - needs capacity, while the mid-age band can trigger one narrower upgrade pass. - After that it fills any remaining deficit by either packaging multiplayer opcode `0x75` or - locally re-entering - `company_try_add_linked_transit_train_and_publish_news` `0x00409830`. The two visible news - helpers under it are bounded too: `0x00409830` emits RT3.lng `2896` for a newly added train, - while `company_publish_train_upgrade_news` `0x00409300` emits RT3.lng `2897` for the upgrade - branch. - The subtype-`4` sibling side is bounded now too. The nearby-site bucket family now has: - `placed_structure_append_nearby_transit_site_distance_bucket_entry` `0x0047fdb0`, - `placed_structure_remove_site_id_from_proximity_bucket_lists` `0x0047dd10`, and - `placed_structure_clear_proximity_bucket_lists` `0x0047dcd0`, plus the two collection sweeps - `placed_structure_collection_append_site_into_all_proximity_bucket_lists` `0x00481480` and - `placed_structure_collection_remove_site_id_from_all_proximity_bucket_lists` `0x004814c0`. - Current evidence says those five buckets store `(peer site id, distance)` pairs for nearby - station-or-transit peers, grouped through the five-way classifier at `0x0040d350`. The older - stream-backed side is bounded too: `placed_structure_collection_load_dynamic_side_buffers_from_stream` - `0x00481430` walks the live placed-structure collection and re-enters - `placed_structure_load_dynamic_side_buffers_from_stream` `0x0047d8e0`, which repopulates the - route-entry list, the three per-site byte arrays, the five proximity buckets, and the trailing - scratch band from the caller-supplied persistence stream. - The linked-site route-entry list itself is tighter now too. The refresh or teardown branch at - `0x0040e102` re-enters `placed_structure_remove_route_entry_key_and_compact` `0x0047d810`, which - removes one matching `u16` key from the six-byte list rooted at `[site+0x462]/[site+0x466]`, - compacts the surviving entries into a replacement buffer, and decrements the stored route-entry - count. - The broader company-side owner above these pieces is tighter now too. The periodic service pass - `company_service_periodic_city_connection_finance_and_linked_transit_lanes` `0x004019e0` now - reads as the current outer owner for this branch: it sequences the city-connection announcement - lanes, the linked-transit train-roster balancer, the acquisition-side sibling - `company_try_buy_unowned_industry_near_city_and_publish_news` `0x004014b0`, the annual finance-policy helper - `company_evaluate_annual_finance_policy_and_publish_news` `0x00401c50`, and the shorter-versus- - longer linked-transit cache refresh tail through `0x004093d0` and `0x00407bd0`. That outer pass - also has one tighter temporary-state role now: it clears company bytes `0x0d17/0x0d18/0x0d56`, - mirrors `0x0d17` into scenario field `0x006cec78+0x4c74` only while the earlier route-building - side runs, and restores the original scenario value on exit. Current evidence now ties `0x0d17` - to the shared preferred-locomotive chooser `0x004078a0`: the override is only armed when that - helper picks one locomotive whose engine-type dword is `2`. That engine-type lane now best reads - as electric rather than an unnamed class slot, because the linked approval helper around - `0x0041d550` now reads as a real locomotive-era and engine-type policy gate, dispatching the same - `0/1/2` field across three scenario-opinion lanes while the local player-facing engine-type - family is explicitly `Steam / Diesel / Electric`. That same gate also now ties the later scenario - bytes `0x4c97..0x4c99` back to the editor-side `Locomotives` page rather than treating them as - anonymous availability flags: they are the live `All Steam Locos Avail.`, `All Diesel Locos - Avail.`, and `All Electric Locos Avail.` policy bytes behind `0x004cd680` / `0x004cf0d0`. The - current logic is also tighter than a plain override tier: a positive engine-family opinion result - can carry the gate by itself only while none of those three editor bytes is enabled; once any of - them is nonzero, `0x0041d550` instead requires one matching intersection between the record-local - family bytes and the enabled editor family bytes. The `WhaleL` carveout is narrower now too: - current data-file correlation ties that stem to the `Orca NX462` / `WhaleL_NE` locomotive family, - and it explicitly zeros that positive-opinion result before the later family-availability checks, - so it loses the shortcut rather than gaining a special approval path. The same - chooser now also has a bounded fallback below it, `locomotive_collection_select_best_era_matched_non_electric_fallback_id` - `0x00461cd0`, which explicitly skips engine-type `2` and chooses the lowest-penalty remaining - locomotive by era mismatch and approval gates. The route-search side is tighter too: this - electric-only override now clearly feeds the first path-sweep branch in `0x0049bd40`, forcing the - larger `1.8` initial quality multiplier instead of `1.4`, which is the same branch otherwise - chosen by explicit route-policy byte `4`. So the later annual finance helper is reading - same-cycle side-channel state from the earlier city-connection and linked-transit branches, not - unrelated long-lived finance fields. The inner - finance helper is not debt-only either. Current grounded outcomes include bankruptcy news - `2881`, the debt restructure family `2882..2886`, a later share-repurchase headline `2887`, and - the dividend-side adjustment branch. The main commit verbs under that helper are now grounded too: - `company_repay_bond_slot_and_compact_debt_table` `0x00423d70`, - `company_issue_bond_and_record_terms` `0x004275c0`, - `company_repurchase_public_shares_and_reduce_capital` `0x004273c0`, and - `company_issue_public_shares_and_raise_capital` `0x00427450`. The threshold side is tighter now - too. The earliest creditor-pressure lane requires scenario mode `0x0c`, the bankruptcy toggle - `[0x006cec78+0x4a8f]` to be clear, at least `13` years since `[company+0x163]`, and at least - `4` years since founding year `[company+0x157]`; it then scans the last three years of the - derived net-profits and revenue lanes `0x2b` and `0x2c`, chooses one negative pressure ladder - `-600000 / -1100000 / -1600000 / - -2000000` from the current slot-`0x2c` bands around `120000 / 230000 / 340000`, requires the - broader support-adjusted share-price or public-support scalar at least `15` or `20` depending on - whether all three sampled years failed, checks the current fuel-cost lane in slot `0x09` against - `0.08` times that ladder, and requires the - three-year slot-`0x2b` total to clear one final `-60000` gate before it falls into the - bankruptcy commit and RT3.lng `2881` headline. - The middle debt-capital layer is split more clearly now too. With `[+0x4a8b]` clear, one annual - bond lane first simulates full repayment through `company_repay_bond_slot_and_compact_debt_table` - and then uses the post-repayment cash window with fixed `-250000` and `-30000` thresholds plus - the broader linked-transit train-service latch `[company+0x0d56]` to decide whether to append one - or more `500000` principal, `30`-year bonds. The repurchase lane is separate again: when the - city-connection announcement-side latch `[company+0x0d18]` is set, growth setting `2` does not - suppress it, and `[+0x4a87]` is clear, it starts from one `1000`-share batch, can replace its - default `1.0` factor with one linked-chairman personality scalar, scales that by `1.6` when - growth setting `1` is active, and then runs one `800000` stock-value gate plus one - support-adjusted-share-price-times-factor-times-`1000`-times-`1.2` affordability gate before the - repeated `1000`-share buyback commits behind RT3.lng `2887`. The ordering above this helper is - tighter now too: - `company_service_periodic_city_connection_finance_and_linked_transit_lanes` clears those latches - first, runs the city-connection and linked-transit branches, and only then enters the annual - finance helper, so these look like same-cycle reaction gates rather than long-lived balance-sheet - flags. - After the earlier debt or bankruptcy outcomes stay inactive, the later stock-capital lane also - has a tighter bounded shape now too: it only opens on build `1.03+`, only after the earlier - bankruptcy, bond, and repurchase outcomes stay inactive, and with the bond and stock toggles - `[+0x4a8b]` and `[+0x4a87]` clear, at least two bond slots live, and at least one year since - founding. It derives one issue batch from outstanding shares rounded down to `1000`-share lots - with floor `2000`, trims that batch until the broader support-adjusted share-price scalar times - batch no longer exceeds the `55000` gate, recomputes the pressured support-adjusted share-price - scalar and the paired `price/book` ratio, then tests the remaining gates in a fixed order: - share-price floor `22`, proceeds floor `55000`, current cash from `0x2329/0x0d` against the - chosen highest-coupon bond principal plus `5000`, one later stock-issue cooldown gate that - converts the current issue mixed-radix calendar tuple at `[company+0x16b/+0x16f]` through - `calendar_point_pack_tuple_to_absolute_counter` `0x0051d3c0` and compares the result against the - active world absolute calendar counter `[world+0x15]`, and only then the coupon-versus-price-to-book - approval ladder `0.07/1.3 -> 0.14/0.35`. The issue mutator preserves the previous tuple in - `[company+0x173/+0x177]` and refreshes the current tuple from `[world+0x0d/+0x11]` on the - derived-pricing lane. On success it issues two - same-sized tranches through repeated `company_issue_public_shares_and_raise_capital` calls and - publishes a separate equity-offering news family rooted at localized id `4053`, not the earlier - debt or buyback headline family. - The dividend side is bounded too: it requires the dividend toggle `[0x006cec78+0x4a93]` to be - clear, mode `0x0c`, at least `1` year since `[company+0x0d2d]`, and at least `2` years since - founding, then averages the last three years of the net-profits lane `0x2b`, folds in the - unassigned-share pool and the current `0x0d` band, applies the map-editor building-growth - setting `[0x006cec78+0x4c7c]`, treats growth setting `1` as a `0.66` scale-down and setting `2` - as a zeroing pass on the current dividend, quantizes surviving adjustments in tenths, and - finally clamps against - `company_compute_board_approved_dividend_rate_ceiling` `0x00426260`. - The linked-transit route-seeding side has one tighter sibling now too: - `company_reset_linked_transit_caches_and_reseed_empty_train_routes` `0x00401940`. It clears the - two company-side linked-transit cache timestamps, forces one immediate cache rebuild through - `0x00409720`, strips route lists from company-owned trains in modes `0x0a/0x13`, and then - re-enters `train_try_append_linked_transit_autoroute_entry` `0x00409770` only when a train's - route list has become empty. - On the wider chooser question, the current evidence is also tighter than before: every recovered - external owner of `0x00402cb0` is still in the city-connection family, so the two later direct - placement lanes currently read as city-connection fallback behavior rather than a broadly shared - world placement service. - It can still unwind through route-state cleanup without committing new placed structures, so the - exact lower helper semantics are not fully closed, but the broader chooser is no longer - anonymous and its main policy split is now visible. The two lower helpers directly under those - commit lanes are bounded now too: - `placed_structure_project_candidate_grid_extent_offset_by_rotation` `0x00417840` is the shared - projected-footprint offset helper over candidate bytes `[candidate+0xb8]` and `[candidate+0xb9]`, - and `placed_structure_validate_projected_candidate_placement` `0x004197e0` is the shared - go-or-no-go validator that checks company, territory, world-tile, and footprint occupancy state - before either direct-placement commit is allowed to fire. Its strongest current subtype branch is - a station-attachment or upgrade-style lane keyed by `[candidate+0x32] == 1`, which now has the - concrete failure family `2901..2906`: blocked upgrade footprint, ground not flat enough, not - your track, insufficient track-laying capacity, cannot connect to existing track, and ground too - steep. That tightens the chooser materially without yet proving that the validator is - station-only for every caller. - The recurring outer owner is tighter now too: - `placed_structure_collection_refresh_quarter_subset_route_style_state` `0x00413580` walks every - fourth live placed structure from a scenario-time-derived offset and re-enters the per-site - rebuild with stack flag `0`, giving the route-style lane a concrete recurring maintenance sweep - under `simulation_service_periodic_boundary_work` rather than only a floating caller note. One - neighboring helper is now bounded on the message side too: - `shell_building_detail_handle_subject_value_row_band_action` `0x004ba270` switches over the - clicked row family `0x7d07..0x7d14`, treats subject bytes `+0x21/+0x22/+0x23` as one current - selection plus one bounded low/high pair, increments the family dirty latch at `0x006cfe0c` on - change, and republishes the refreshed value through the shared shell control helper on code - `0x66`. One neighboring helper is now bounded on the side-list path too: - `shell_building_detail_propagate_selected_subject_state_into_side_list` `0x004b9ec0` walks the - sibling list owner at `0x006cfe08`, copies the active subject state into each side-list record, - mirrors the current service or capability id at `+0x24`, and preserves the `0x40/0x20/0x10` - subflags from the active subject. That means the value-row actions and later selector rows now - read as propagating one shared building-detail state across the sibling list rather than only - mutating one isolated subject record. One neighboring helper is - now bounded separately too: `shell_building_detail_refresh_subject_pair_value_rows` `0x004bad20` - owns the mutually exclusive value-row pairs `0x7d07/0x7d08`, `0x7d11/0x7d12`, and - `0x7d13/0x7d14`, choosing among them from the same selected-subject flag byte and payload fields - at `+0x22/+0x23`, while the larger cargo-or-service row owner also gates the extra visual lanes - `0x7d6a`, `0x7d6b`, and `0x7d9d` from that same subflag family. The asset-string block is tighter - too: that branch family now explicitly uses `AnyCargo.imb`, `AnyFreight.imb`, `PassMail.imb`, - `Caboose.imb`, and `Dining.imb`, with the bit-`0x20` special lane already aligned to - `Caboose.imb` and the sibling bit-`0x10` special lane now aligned to `Dining.imb`. The larger - `0x7f58..0x801f` band is no longer just a styled row family either: - `shell_building_detail_present_flagged_service_capability_popup` `0x004b9fd0` is now grounded as - its explanatory popup callback. It resolves either one fixed express-side row from `0x00621e04` - or one active candidate or service id from `[subject+0x24]`, then formats one popup through the - shell message-box path. The neighboring refresh helper `shell_building_detail_refresh_flagged_service_capability_rows` - `0x004b9a20` is tighter now too: `0x7d07..0x7d1c` is not one anonymous block, but a real mask - partition over subject bits `0x20` and `0x10`, with one zero-mask pair, one bit-`0x20`-only - pair, one exclusive-or pair, and later one-bit and two-bit indicator rows. RT3.lng now closes - the fixed popup text family too: the single-line branch uses - `3922` `%1\nLoads available at %2: %3`, while the richer ordinary-candidate branch uses - `2981` `%1\nLoads available at %2: %3 Current Price: %4` and can append - `2982` `Price at next station, %1: %2 (%3%4)`. The selector band is narrower too: current - refresh-side evidence shows `0x7f58..0x801f` as one selected-ordinal highlight family over the - three fixed express rows plus the ordinary active-candidate rows, not as a generic unstructured - list. The neighboring `0x8020..0x8051` band is tighter too: it is primarily the matching - remove-entry family for the selected subject's live id list, with two special row indices - re-routing into the `0x7d0f/0x7d10` subflag-clearing path instead of ordinary list compaction - when the current `0x20/0x10` service-bit combination demands it. That means the exact captions - are no longer broadly open across the whole selector family: the fixed express-side rows, the - mask partitions, and the add/remove structure are grounded, and the remaining caption gap is - mostly the ordinary candidate rows further down the same band. The top-level toggles are - tighter now too: the paired - `0x7d02/0x7d03` controls are the real mode switch over subject bit `0x40`, choosing between the - bounded pair-value branch and the current-selection/status branch around `0x7d0d/0x7d0e`, while - the smaller `0x7d0f/0x7d10` controls flip the same special-service subflags later rendered as - `Caboose` and `Dining Car`. One adjacent control is tighter now too: the extracted - `BuildingDetail.win` resource contains the plain-English line `Set the initial cargo amount for - 'Disable Cargo Economy' scenarios.`, and the `0x7d01` plus `0x7d09/0x7d0a` message-side branch - can mirror the current subject or selection through - `shell_building_detail_submit_aux_owner_subject_sync_request` `0x004b9e10` into the auxiliary - owner queue at `[0x006cd8d8+0x8f48]`, with side-owner presence now explicitly grounded through - `shell_has_auxiliary_preview_owner` `0x00434050`. That queued request is tighter too: both - current callsites forward the same side-list mirror latch at `[0x006cfe08+0x0c]`, so the - auxiliary owner now clearly sees not just the staged subject but also whether the local - `BuildingDetail` side-list is in mirrored-subject mode. The same `0x7d01` lane also now has one - clear rejection note: localized id `3587` `This option is only available by following the - tutorial.` now sits behind the active tutorial flag at `0x006d3b4c` and the cached previous - tutorial expected-control id at `0x00622b38`, while the neighboring tutorial helper - `tutorial_advance_step_and_refresh_expected_control_ids` `0x00516be0` now grounds - `0x00622b34/0x00622b38/0x00622b3c` as the current and previous expected-control cache rather - than anonymous globals. The last field is tighter now too: `0x00622b3c` is currently best read - as the active tutorial step's alternate-accepted companion control id, because the generic shell - control path compares clicked control ids against it directly and suppresses the `3587` tutorial - rejection when they match. That does not fully close the player-facing caption bind for every - control, but it does bound the neighboring side-owner sync and tutorial-rejection lane instead - of leaving it as anonymous glue. - The extra pre-insert gate is narrower than it - first looked. It is now grounded as tutorial-only: - `tutorial_validate_train_route_station_indicator_step` `0x00516d00` checks the current tutorial - step from the shell tutorial descriptor table at `0x00622b48` before a live station-or-transit - site id can be committed into the staged route entry, and the currently accepted steps align with - localized prompts `3777` and `3778`, the two train-routing tutorial instructions that tell the - player to click the Milan and Turin station indicators. Outside that tutorial state family, the - route-entry insertion path is not gated there. The adjacent validator is tighter now too: - `train_route_list_validate_reachability_and_station_pair` `0x004b2c10` walks that same route list, - resolves placed-structure-backed entries through the live placed-structure and route-node - collections, uses the direct route-node payload branch for the remaining entry family, and fails - with `3089..3091` when the resulting route cannot be traversed or does not preserve a valid - terminal station pair. The post-validation follow-on is bounded too: - `train_current_route_context_uses_strict_reachability_mode` `0x004a9460` is now the small shared - gate above the stricter branch, keyed off the current linked route object's downstream class type, - and `train_set_route_operating_mode_and_scalar` `0x004ab980` now reads as the shared train mode - setter beneath route editing, with the local and multiplayer insertion paths choosing mode - `0x13` only when that stricter second validation succeeds and mode `0x0a` on the looser fallback - path. The first - deeper world-mode interaction branch is now better - bounded: `GameUppermost.win` hotspots, cursor drag, held Shift state, discrete shell view-step - commands, direct keyboard turn/pan/zoom bindings, the `TrackLay.win` and `StationPlace.win` - world-command surfaces, and a frame-owned hover or focus-target transition branch all feed the - same shell-controller-backed path. The remaining uncertainty has moved farther from basic - ownership: the hover-target branch clearly exists, and `0x07d6` now looks like the shared - main-world interaction surface rather than a generic detail button for one tool family only. One - more shell-side consumer is bounded now too: `0x004bc350` is a world-surface brush handler over - that same `0x07d6` control plus the adjacent mode family `0x0faa..0x0faf` and ordinal strip - `0x0fa0..0x0fa7`. That family is no longer just a generic unlabeled brush owner: the - detail-panel manager now grounds the sibling tool-window strip immediately above it as - `Bulldoze.win`, `ChangeHeight.win`, `ChangeTrees.win`, `PaintTerrain.win`, `PaintRegion.win`, - `PaintSound.win`, and `PaintTerritory.win`, each with its own constructor, refresh pass, and - message owner beneath the same controller rooted at `0x006d0818`. Once its local drag latch is - active it dispatches the current mode dword at `[0x006d0818+0x8c]` into the companion-float - helpers `0x0044d4e0`, `0x0044d880`, and `0x0044da70`, or into the secondary-raster nibble path - `0x00448e20 -> 0x00419110`, so the remaining uncertainty has narrowed from ownership to the - exact one-to-one mode-button mapping inside that grounded tool-window strip. The - `PaintTerrain.win` side is tighter now too: constructor `0x004f7ce0` seeds shell singleton - `0x006d1304`, callback root `0x006d1334`, a constructor-time bulk-update latch at - `0x006d1330/0x006d1331`, and the broader terrain mode or scalar state from `0x00622748..0x00622788` - plus `0x006d1308..0x006d1324`; it then registers the callback strip `0x004f5960`, - `0x004f59f0`, `0x004f6070`, and `0x004f69e0` through `0x00540120`. The direct message owner - under that same family is no longer just a loose branch fan-out either: `0x004f6f50` owns - messages `2/0xca/0xcb`, keeps control `0x07d6` as the live world-surface drag latch, routes - explicit undo control `0x2775` into `0x004f5c30`, maps the selector and mode strips - `0x2711..0x2730`, `0x27d9..0x27df`, `0x283d..0x2843`, `0x28a1..0x28e6`, `0x2915..0x291e`, - `0x2964..0x2967`, and `0x29cd..` into the cached terrain lanes, and then fans the active drag - path into preview helpers `0x004f6930`, `0x004fb5e0`, `0x004fc280`, `0x004fc4d0`, and - `0x004fc630` depending on the current terrain mode. Inside that same family - `0x004f5a80/0x004f5c30` are now the bounded local undo snapshot pair, `0x004f5dd0` is the - tiny active-scalar-group selector, `0x004f6b50` owns the ten-entry mode strip rooted at - `0x28dd`, `0x004f6390` is the broad mode-panel repaint owner, `0x004f6250` is the - mode-dependent world-dispatch bridge, `0x004f6930` samples the current preview raster at - world coordinates, and `0x004fb5e0` is the heavier preview-raster rebuild and shell-surface - publish worker. The next local helpers under that same family are tighter now too: - `0x004f5ea0` and `0x004f5ec0` are just the two tiny special-mode predicates - `(mode 5, variant 2)` and `(mode 4, variant 2)`, `0x004f8770` is the weighted RGB sampler - over the current preview or undo-backed raster neighborhood, `0x004f89b0` is the local - byte-grid connected-component grower over the eight-neighbor tables `0x00624b28/0x00624b48`, - and `0x004f8bb0` is the main drag-path preview compositor that consumes the drag sample strip - `[this+0xf0/+0xf4/+0xf8]`, allocates temporary float or byte grids, and then rasterizes the - surviving preview rectangle through the current terrain descriptor tables at `0x005f3500`, - the weighted color sampler `0x004f8770`, the component grower `0x004f89b0`, and several live - world samplers before writing final RGBA pixels back into the preview surface. The late tail - under that same compositor is tighter too: the mode-`4`, variant-`2` path toggles - secondary-raster byte-2 bit `0x20` by comparing current and previous cells through - `0x00534f40`; the broader mode-`4/5` world-facing branch samples class set `2/4/5` through - `0x00534ec0`, re-enters `0x0044de30` and `0x0044df10`, latches pending world coordinates into - `[0x006d1304+0x78/+0x7c]`, and rewrites the low nibble plus the signed overlay-vector planes - through `0x00448df0`, `0x00448e20`, `0x00448ec0`, `0x00448ee0`, `0x00448e60`, and - `0x00448e90`. After the optional mode-`5` smoothing sweep through `0x004f8370`, the publish - tail either materializes one shell preview surface through `0x0051f090 -> 0x00534730` or, for - the mode-`4/5` world-facing variants, converts the surviving preview rectangle back into - world-space bounds and re-enters `0x0044e940`, `0x00452f20`, and `0x0044d410`. The companion - preview-rebuild owner `0x004fb5e0` is tighter on entry, too: `0x004f726c` is the early - rebuild path that first copies the live preview raster into `[this+0x118]` and snapshots undo - state through `0x004f5a80`, while `0x004f7ada` is the later drag-active path that first - allocates a temporary occupancy mask before rebuilding and then conditionally mirrors that - mask through `0x00450520` on the world-mode-`0x17` side path. So the remaining uncertainty - has narrowed again from family ownership to the exact meaning of a few per-mode scalar and - token lanes, not to whether `PaintTerrain.win` itself is still a mixed shell/world owner. The - same brush strip is tighter now too: - `0x004bc210` stores the selected ordinal and refreshes one scalar caption - from table `0x00621e24`, `0x004bc260` exposes the cached world coordinate pair plus the - currently selected scalar, and `0x004bc290` restyles the ordinal strip `0x0fa1..0x0fa7` plus - the mapped mode strip `0x0faa..0x0faf` against the current mode dword `[0x006d0818+0x8c]`. The - next unresolved layer is narrower and more semantic: the setup side now has one grounded - owner, `world_run_post_load_generation_pipeline`, and its building-side branch is no longer just - one opaque block. We now have a region family, a region-border overlay rebuild, a region-owned - structure-demand and placement dispatcher, and a deeper per-region worker that computes category - demand, subtracts existing coverage, and tries candidate placements. The category map is tighter - too: category `0` falls back to `House`, category `2` is the year-gated weighted region-profile - family that also feeds the localized `Industry Weightings` stats panel, and category `3` now - reaches a separate pool-driven picker whose fallback label is `Commercial` but whose aligned - player-facing stats bucket is `City Support`. The normalized region band is tighter too: - `world_region_normalize_cached_structure_balance_scalars` `0x00422320` no longer just writes an - anonymous cached preview band at `[region+0x2e2/+0x2e6/+0x2ea/+0x2ee]`. Current growth-report - evidence now grounds `[region+0x2e2]` as the weighted-profit-margin scalar and `[region+0x2ee]` - as the annual-density-adjust scalar later formatted as a percent in `Stats - City/Region`, with - `[region+0x2e6/+0x2ea]` left as the intermediate normalized-delta and clamped companion slots - beneath that final adjust term. The per-region prepass feeding that normalization is tighter too: - `0x00420d40` clears `[region+0x306/+0x30a/+0x30e]`, walks the linked placed-structure chain from - `[region+0x383]`, accumulates two local placed-structure metrics through `0x0040ca70` and - `0x0040ca80`, and only for class-0 candidates also folds source field `[source+0x141]` through - `0x0040cec0` into the third accumulator before tailing into the later scalar refresh. That tail - helper `0x00420560` is tighter now too: on class-0 regions it revisits the same linked chain and - folds a class-mix contribution into `[region+0x312]`, with one source-derived term for candidate - class `0`, a separate branch keyed by `[candidate+0x78c]` and `[site+0x246]` for class `2`, one - fixed increment for class `3`, and no current contribution from class `1`. The - remaining setup-side uncertainty has therefore narrowed - again: the region seed and border-overlay pair clearly complete before the `Setting up Players and - Companies...` banner is posted; `[0x006cec74+0x174]` now looks like the direct building-population - gate; `[0x006cec74+0x178]` now looks like the direct seeding-burst gate and selected-year-adjust - policy; and `[0x006cec74+0x68]` now aligns with editor-map mode because the same flag forces the - `.gmp` family in the shell file coordinators while suppressing the later building and seeding - branches and diverting the deeper region worker into alternate logic. One write side for that - `[shell+0x178]` policy is now grounded too: inside `shell_dispatch_ui_command` `0x00464410`, - command ids `0x9d26..0x9d28` store `command_id - 0x9d26` directly into `[0x006cec74+0x178]`, - yielding live values `0`, `1`, and `2`. That means the later restore branch is no longer gated - by an abstract hidden shell latch; at least one of its adjustment inputs is an explicit UI - launch policy and current evidence still does not show that value being recovered from saved - state. The `319` lane itself is no longer the - open structural gap; it now clearly owns chairman-profile slot seeding, profile-record - materialization, a shell editor surface over the same local record family, and a separate - live-company presentation path through the company-list window. The later interior order of that - same `319` lane is tighter now too: after the route-entry collection refresh on `0x006cfca8` it - refreshes the auxiliary route-entry tracker collection `0x006cfcb4`, then runs - `placed_structure_collection_refresh_local_runtime_records_and_position_scalars` `0x004133b0`, - then a flagged world-grid cleanup sweep through the compact grid-flag query - `0x00448af0` plus the neighboring local chunk-cell write helper `0x00533fe0`, and only after - that the later route-entry post-pass at `0x00491c20`. The same `319` lane is tighter internally - now too: - before that later world and shell reactivation tail, `world_entry_transition_and_runtime_bringup` - runs one distinct post-bundle status and runtime refresh phase that posts progress ids `0x196` - and `0x197` through `0x005193f0/0x00540120` with paired `0x004834e0` follow-ons, refreshes the - live event collection at `0x0062be18` through - `scenario_event_collection_refresh_runtime_records_from_packed_state` `0x00433130`, rebuilds the - scenario-side port-or-warehouse cargo recipe runtime tables through `0x00435630`, and then runs - the named-candidate availability preseed through `0x00437743`. One later subphase is tighter now - too: before the broad world-reactivation sweep it posts progress ids `0x32dc/0x3714/0x3715`, - reloads one `0x108`-byte packed profile block through `0x00531150`, conditionally copies staged - runtime-profile bytes back into `0x006cec7c` while latch `[profile+0x97]` is set, mirrors the - grounded campaign-scenario bit `[profile+0xc5]` and sandbox bit `[profile+0x82]` into world - bytes `[world+0x66de]` and `[world+0x66f2]`, and restores the selected year/profile lane through - a tighter two-stage calendar path than before. Current local disassembly now shows the raw saved - lane at `[profile+0x77]` first feeding helper `0x0051d3f0` with constant components - `(month=1, day=1, subphase=0, tick=0)`, which writes the resulting Jan-1-style tuple dwords - into `[world+0x05/+0x09]`. Only after that seed does the same lane enter one mode-sensitive - adjustment branch: non-editor startup mode can decrement the lane by `1` or `3` depending on - shell-state editor gate `[0x006cec74+0x68]`, shell-side selected-year-adjust policy - `[0x006cec74+0x178]`, and the saved special-condition slot `[0x006cec78+0x4af7]`, and only that - adjusted lane then feeds - helper `0x0051d390` before `world_set_selected_year_and_refresh_calendar_presentation_state` - `0x00409e80` stores the final absolute counter into `[world+0x15]` and refreshes - `[world+0x0d/+0x11]`. That means the restore no longer reads as a direct - `[profile+0x77] -> [world+0x15]` copy; the raw lane seeds the tuple immediately, but the final - absolute-counter restore still depends on live shell/startup context. That dependency is tighter - now too: current local evidence shows `[shell+0x178] == 1` decrementing the restored lane by - `1`, `[shell+0x178] == 2` subtracting `3`, and otherwise a nonzero - `[0x006cec78+0x4af7]` supplying the fallback `-1` branch. That field is no longer unresolved: - current local disassembly now shows `0x00436d10` bulk-zeroing the dword table rooted at - `[startup+0x4a7f]` through `rep stos`, which includes `+0x4af7`, while the editor-side special - conditions owner at `0x004cb2b0/0x004cb8e0` counts and commits that same 49-entry table from the - static rule descriptors at `0x005f3ab0`. The `.smp` save or restore family now grounds that live - band directly too: `world_runtime_serialize_smp_bundle` `0x00446240` writes `49` dwords from - `[world+0x4a7f..+0x4b3f]` plus one trailing scalar at `[world+0x4b43]`, and - `world_load_saved_runtime_state_bundle` `0x00446d40` restores the same fixed `0xc8`-byte band - symmetrically. Slot `30` in that table is localized pair `3722/3723` - `Disable Cargo Economy`, so `+0x4af7` now reads as the live copy of that saved scenario rule, - not a startup-runtime-only mystery latch. The neighboring fixed reads line up with the same rule - cluster too: `+0x4aef` is slot `28` `Completely Disable Money-Related Things`, `+0x4af3` is slot - `29` `Use Bio-Accelerator Cars`, `+0x4afb` is slot `31` `Use Wartime Cargos`, `+0x4aff` is slot - `32` `Disable Train Crashes`, `+0x4b03` is slot `33` `Disable Train Crashes AND Breakdowns`, and - `+0x4b07` is slot `34` `AI Ignore Territories At Startup`. So the remaining loader gap is - narrower than before: the restore still depends on live shell policy `[shell+0x178]`, but the - `+0x4af7` input itself is save-derived scenario rule data rather than something that requires - runtime tracing to discover. Its read-side family is no longer isolated to the selected-year - restore either: it also shapes the chunk size in - `simulation_run_chunked_fast_forward_burst` `0x00437b20` and appears in candidate/local-service - selection and station-detail-side scoring branches around `0x0047f910`, `0x00410d87`, and - `0x005069c6`, which now makes this whole slot cluster look like broader runtime consumers of - scenario special conditions rather than one startup-only mode enum. One file-side anchor is now - tighter too: the checked classic and 1.05 `gmp/gms/gmx` corpus does expose the same aligned - `0x0d64..0x0e2c` `50`-dword band as the grounded `.smp` runtime save or restore copy into - `[world+0x4a7f..+0x4b43]`, but most checked file families only populate a sparse subset of that - band. The first `36` dwords still behave like the older inferred fixed rule matrix with hidden - slot `35` fixed to sentinel value `1`, while the trailing `13` unlabeled rule lanes plus one - scalar vary much more selectively by file family. Current local corpus scans make that split - concrete: the grounded 1.05 scenario-save family (`p.gms`, `q.gms`) stably lights lanes - `35, 37, 39, 44, 45, 46, 47, 48`; the base 1.05 save family (`Autosave.gms`, `nom.gms`) only - shares lane `35` stably and otherwise varies sparsely through `42`, `45`, and `47`; the checked - grounded 1.05 maps, the lone 1.05 alt save, and the visible sandbox-family `.gmx` files keep - only the sentinel lane `35` nonzero. So the current loader boundary is narrower than before: the - `.smp` path still gives a grounded direct runtime-band restore, and checked `gmp/gms/gmx` files - now show a partially populated projection of that same aligned band rather than a wholly separate - fixed record family. The overlap against the later scalar window is now explicit too: trailing - band indices `36..49` are byte-identical with post-window offsets `0x00..0x34`, so every nonzero - lane in that prefix of the post-sentinel scalar window is also a nonzero lane in the aligned - runtime-rule band. That means the real “other fields” boundary inside the post-sentinel window - starts only at `0x0e2c`: `0x0df4..0x0e2c` is the aligned-band overlap prefix, while - `0x0e2c..0x0f30` is the later tail that still looks like save-side scalar state. Local corpus - scans now make that tail split more specific. The base 1.05 save family - (`Autosave.gms`, `nom.gms`) shares a stable tail subset at relative offsets - `0xb4`, `0xc0`, `0xe0`, `0xfc`, and `0x100`, with additional per-file lanes around them. The - 1.05 scenario-save family (`p.gms`, `q.gms`) has a much denser stable tail covering - `0x08`, `0x0c`, `0x10`, `0x14`, `0x20`, `0x24`, `0x28`, `0x30`, `0x34`, `0x3c`, `0x5c`, - `0x6c`, `0xa0`, `0xa8`, `0xbc`, `0xc0`, `0xc4`, `0xc8`, `0xcc`, `0xdc`, `0xe0`, `0xe4`, - `0xe8`, `0xf4`, `0xf8`, and `0xfc`; those values still differ per save, but the occupancy is - stable. The lone 1.05 alt save (`g.gms`) only lights `0x20`, `0x34`, `0xf0`, and `0xf4`. - Grounded map families and classic saves keep the tail zeroed, while the only current map-side - outlier remains `Tutorial_2.gmp` under the broad unknown map-family bucket. The immediately - following fixed file window at `0x0df4..0x0f30` is now bounded separately as well: checked maps - and classic saves leave that whole post-sentinel band zeroed, - while checked 1.05 saves carry sparse nonzero dwords there, many of which decode cleanly as - normal little-endian `f32` values. That makes the adjacent band look like a 1.05 save-only - runtime band rather than scenario-static payload, even though its semantics are still open. - One numeric alignment inside that band is now exact too: the tail start `0x0e2c` is the same - relative distance from the aligned runtime-rule base `0x0d64` as live object offset `+0x4b47` - is from grounded world-rule base `[world+0x4a7f]`, so the bounded tail window - `0x0e2c..0x0f30` is offset-aligned with live bytes `[world+0x4b47..+0x4c4b]`. The first - grounded live field at that boundary is no longer anonymous. `0x004367c0` sets one outcome mode - in `[world+0x4a73]`, zeros `[world+0x4d]`, snapshots the selected-year lane to `[world+0x4c88]`, - and then copies localized id `2923` `You lose.` or `2924` `You win, cheater...` into - `[world+0x4b47]`; `0x00472dd0` formats localized id `3918` `%1 has won the game!` with one live - profile name and writes that string into the same destination; and one compact runtime-effect - branch inside `world_apply_compact_runtime_effect_record_to_resolved_targets` `0x00431b20` resets - the same destination to the fixed placeholder token at `0x005c87a8`. That gives a grounded live - interpretation for the start of the tail: `[world+0x4b47]` is the start of a victory or outcome - status-text buffer, not a float lane. The same evidence also gives a useful caution: those live - helpers copy up to `0x12c` bytes into `[world+0x4b47..+0x4c73]`, so the current bounded file-tail - window `0x0e2c..0x0f30` cuts through the first `0x104` bytes of a grounded text field rather - than ending on a clean live-field boundary. One small continuation probe now tightens that edge: - the remaining file window `0x0f30..0x0f58` is exactly the last `0x28` bytes needed to reach the - clean live-field boundary at `[world+0x4c73]`, and checked 1.05 saves still carry sparse nonzero - bytes in that continuation window rather than a trailing text-looking suffix. Checked 1.05 save - bytes in the aligned region therefore still do not resemble preserved text; they stay mostly zero - at the beginning and many nonzero lanes decode as ordinary `f32` values. So the safest current - note is: the tail is offset-aligned with the live object beyond `+0x4b43`, but it is not yet a - validated byte-for-byte mirror of the live `[world+0x4b47]` status-text buffer, and the current - nonzero save-side content continues right up to the first clean field edge at `0x0f58`. The next - exact grounded fields after that edge are byte lanes, not restored dwords: `0x0f59` maps to - `[world+0x4c74]` `Auto-Show Grade During Track Lay`, `0x0f5d` maps to `[world+0x4c78]` - `Starting Building Density Level`, `0x0f61` maps to `[world+0x4c7c]` `Building Density Growth`, - `0x0f65` maps to grounded dword `[world+0x4c80]` `leftover simulation time accumulator`, and - `0x0f6d` maps to byte `[world+0x4c88]` `selected-year lane snapshot`. The first later grounded - dword after that is `[world+0x4c8c]` at `0x0f71`. That means the simple 4-byte file-lane model - stops matching grounded live field boundaries immediately after the text-buffer edge: the post- - `0x0f58` file bytes are still offset-correlated to live state, but they are no longer naturally - dword-aligned with the next grounded object fields. The new byte-neighborhood probe makes the - mismatch more concrete. In checked 1.05 scenario saves, the exact grounded byte offsets - themselves do not look like clean selector values: `p.gms` carries `0x33` at `0x0f5d` and `0x8c` - at `0x0f6d`, while `q.gms` carries `0xcc` and `0xba` at those same offsets. The only clean - float-looking starts in that neighborhood instead appear one byte earlier, at `0x0f5c` and - `0x0f6c`: `p.gms` decodes those as roughly `7.6` and `6.0172`, while `q.gms` decodes them as - roughly `23.6` and `44.6824`. That tightens the current read further: the checked save bytes - remain offset-correlated to the live `[world+0x4c74..+0x4c8c]` neighborhood, but they are still - not a validated byte-for-byte mirror of the exact live field layout. Local - A second byte-oriented neighborhood immediately after that now has the same kind of split rather - than a clean restored-field mirror. The earlier grounded anchors in that band all stay zero in - the checked 1.05 saves: exact file offset `0x0f87` maps to selected-year bucket companion scalar - `[world+0x4ca2]`, while `0x0f93` and `0x0f97` map to the two startup-dispatch reset-owned bands - `[world+0x4cae]` and `[world+0x4cb2]`, and the local corpus leaves all three exact dword starts - zeroed. The same is true for the later exact byte-owned policy lanes: file offsets `0x0f78`, - `0x0f7c`, `0x0f7d`, and `0x0f7e` map cleanly to grounded byte fields `[world+0x4c93]` and - `[world+0x4c97..+0x4c99]`: the linked-site removal follow-on gate plus the three editor - locomotives-page policy bytes `All Steam Locos Avail.`, `All Diesel Locos Avail.`, and `All - Electric Locos Avail.`. In the checked 1.05 save corpus those four exact byte lanes all stay - `0`, which is at least structurally clean. The later grounded dword fields in the same - neighborhood are less direct again. Exact file offset `0x0f9f` maps to `[world+0x4cba]` (the - station-list selected-station mirror) and exact offset `0x0fa3` maps to cached - available-locomotive rating `[world+0x4cbe]`, but the checked save bytes at those exact dword - starts do not look like clean preserved ids or floats. The only stable float-looking starts sit - three bytes earlier, at `0x0f9c` and `0x0fa0`: `p.gms` yields roughly `96.8754` and `186.4795`, - `q.gms` yields `329.9467` and the same `0x0fa0`-side candidate shape, `g.gms` yields `7.0` and - `95.8507`, and `Autosave.gms` only shows the later `0x0fa0` candidate at about `68.2629`. So - this later band now has the same conservative read as the post-text one: the save bytes are - still offset-correlated to grounded live fields, but the exact live byte or dword layout is not - yet validated as a direct on-disk mirror. - One more structural cut is now grounded beyond that neighborhood. The aligned scalar plateau - `0x0fa7..0x0fe7` ends exactly at the later recipe-book root `[world+0x0fe7]` already grounded in - the port-or-warehouse cargo editor and runtime rebuild path. We still do not have live semantic - names for the plateau itself, but its aligned dword run now splits cleanly by save family. The - base 1.05 saves (`Autosave.gms`, `nom.gms`) carry one stable signature with - `0x0faf = 0x8000003f`, `0x0fb3 = 0x75c28f3f`, repeated `0x75c28f3c` lanes through `0x0fbf`, a - sign-flipped lane `0x0fc3 = 0xa3d70a3c`, one tiny marker at `0x0fc7 = 0x0000003b`, and - `0x0fcb = 0x00300000`. The scenario-save family (`p.gms`, `q.gms`) carries a different stable - plateau over the same offsets, beginning `0x0faf = 0x4000003f`, `0x0fb3 = 0xe560423f`, then - `0x03126f3b`, `0x1374bc3c`, and paired `0x23d70a3c` lanes at `0x0fbf/0x0fc3`, with - `0x0fc7 = 0x0000003c`. The alt-save family (`g.gms`) follows the base signature through - `0x0fc7`, then diverges sharply into the same `0xcdcdcd..` fill pattern already seen in its - earlier header lanes. So the current best fit for `0x0fa7..0x0fe7` is a family-shaped aligned - scalar plateau that belongs to save-side runtime state and terminates immediately before the - grounded recipe-book block, not one more directly named live-field mirror. One conservative - loader-side summary probe now starts exactly at that recipe root instead of extending the plateau - model further. The fixed recipe-book block spans twelve books from `0x0fe7` with stride `0x4e1`, - and the checked map/save pairs `Alternate USA.gmp -> Autosave.gms`, `Southern Pacific.gmp -> - p.gms`, and `Spanish Mainline.gmp -> g.gms` preserve that rooted block byte-for-byte in the - sampled local corpus. The current probe therefore treats it as preserved scenario payload rather - than save-only runtime drift and only reports per-book signatures: a coarse head kind over the - pre-line region, the raw `book+0x3ed` annual-production dword, and one raw summary for each of - the five fixed `0x30`-byte cargo lines beginning at `book+0x3f1`: coarse line kind, raw mode - dword, raw annual-amount dword, and the raw supplied/demanded cargo-token dwords at `+0x08` and - `+0x1c`. That is enough to separate zero, `0xcd`-filled, and mixed books or lines without - overstating line semantics beyond the grounded editor/runtime ownership already documented below. - Local - corpus clustering now makes the remaining split more specific. The base 1.05 save family - (`Autosave.gms`, `nom.gms`) shares a narrow tail-heavy subset with stable relative offsets - `0xec`, `0xf8`, `0x118`, `0x134`, and `0x138`, while still varying in value across files. The - 1.05 scenario-save family (`p.gms`, `q.gms`) shares a much broader stable set spanning almost the - whole window from `0x04` through `0x134`, again with per-file scalar differences but consistent - occupancy. Pairwise compare runs tighten that read further: `Autosave.gms` vs `nom.gms` does not - preserve one common numeric tail signature even at the shared base-save offsets, and `p.gms` vs - `q.gms` keeps the broad scenario-save occupancy pattern but still changes every shared value, with - `q.gms` additionally lighting two extra lanes at `0x78` and `0x84`. So the current best fit is - “family-shaped live scalar state” rather than family-default constants. The lone 1.05 alt-save - sample (`g.gms`) only lights up four lanes at `0x58`, `0x6c`, - `0x128`, and `0x12c`. The checked 1.05 maps and classic saves stay zero in that same bounded - window, which strengthens the current read that this is runtime-save scalar state rather than - generic map payload. One older unknown map-family outlier in the local corpus does still carry a - populated window: `Tutorial_2.gmp` under the classic install tree. So the safest current note is - “zero for grounded map families and classic save families, nonzero for observed 1.05 save - families, with one older unknown-map exception.” Static consumer grounding is still sparse for - that tail: direct object-offset hits currently only name the trailing scalar `[world+0x4b43]` - through the editor panel and `.smp` save or restore family, while local opcode searches do not - yet surface equally direct reads for the intervening `+0x4b0b..+0x4b3f` tail lanes. So the - save-file family clustering is now strong, but those later tail scalars remain structurally - bounded rather than semantically named. The - same branch is no longer world-entry-only either: current local - disassembly now shows the identical lane-adjust and - `0x51d3f0 -> 0x51d390 -> 0x409e80` sequence in the post-fast-forward selected-year tail at - `0x004370e0`, which lines up with the existing post-fast-forward callers already mapped under - `0x00433bd0`, `0x00435603`, `0x0041e970`, and `0x00436af0`. That restore now - also has some neighboring slot semantics bounded well enough to carry in the loader notes. Slot - `31` `[0x006cec78+0x4afb]` is no longer best read as an unnamed runtime cargo-economy latch: - local disassembly now ties it directly to the saved special-condition table entry `Use Wartime - Cargos`, and the strongest current runtime owner is - `structure_candidate_collection_refresh_cargo_economy_filter_flags` `0x0041eac0`. Inside that - candidate-collection sweep the branch at `0x0041ed37` only activates when slot `31` is set and - then treats the string family `Clothing`, `Cheese`, `Meat`, `Ammunition`, `Weapons`, and - `Diesel` as one special cargo set before writing the live candidate filter byte `[entry+0x56]`. - That makes the old read-side note around `0x00412560` tighter too: the neighboring descriptor - gate is now best understood as using the live copy of the `Use Wartime Cargos` scenario rule, - not an anonymous cargo-economy mode byte. Slot `34` `[0x006cec78+0x4b07]` is similarly bounded - on the runtime side: the wrapper at `0x004013f0`, which sits immediately above the broader - company-start or city-connection chooser `0x00404ce0`, snapshots region dword `[entry+0x2d]` - across all `0x18` live region records in `0x006cfc9c`, zeros that field while the chooser runs, - and then restores the original values on exit. That is a strong current fit for the editor rule - `AI Ignore Territories At Startup`, even though the exact meaning of region field `+0x2d` - remains open. Slot `29` `[0x006cec78+0x4af3]` is less semantically tidy but still worth carrying - as a bounded consumer family: the branch at `0x0041d286` activates one later placed-structure or - building-side scoring path only when that slot is nonzero and the linked candidate or era record - at `[entry+0x41]` equals `5`, while two already-grounded world helpers - `world_scan_secondary_grid_marked_cell_bounds` `0x0044ce60` and - `world_service_secondary_grid_marked_cell_overlay_cache` `0x0044c670` also gate on the same - slot. So the identity of slot `29` as saved rule data is grounded, but the downstream runtime - semantics are still mixed enough that the loader should preserve the raw value without trying to - rename its whole consumer family yet. The neighboring train-safety slots are now bounded enough - to keep as a cautious runtime split too. Slot `33` `[0x006cec78+0x4b03]` - `Disable Train Crashes AND Breakdowns` is the coarse gate in the currently recovered train-side - deterioration family around `0x004af8a0`: the very first branch at `0x004af8ab` jumps straight - to the function tail when the slot is set, bypassing the year-scaled threshold build, the later - random or threshold comparison, and the two follow-on state transitions at `0x004ad7a0` and - `0x004ada00`. Slot `32` `[0x006cec78+0x4aff]` `Disable Train Crashes` is narrower in the same - family: after the threshold path has already run, the branch at `0x004af9c1` uses slot `32` to - suppress only the lower failure-transition path and force the milder follow-on at `0x004ada00`. - That same slot-`33` read also appears in the smaller train-side scalar query at `0x004ac460`, - where setting it returns one fixed float immediately before the ordinary route-object-dependent - calculation runs. So the current best loader-facing read is: slot `33` is the broad train - deterioration bypass, slot `32` is the narrower crash-only branch inside that same family, but - the exact player-facing names of the two unnamed train helpers still need one more naming pass. - That restore now - also has one concrete file-side correlation in the classic `.gms` family: local save inspection - now consistently finds `0x32dc` at `0x76e8`, `0x3714` at `0x76ec`, and `0x3715` at `0x77f8` in - `Autosave.gms`, `kk.gms`, and `hh.gms`, leaving one exact `0x108`-byte span from `0x76f0` to - `0x77f8` between `0x3714` and `0x3715`. That span already carries staged-profile-looking payload - text such as `British Isles.gmp`, so the current static-file evidence now supports the atlas-side - `0x108` packed-profile note for the classic save family even though the exact field layout inside - that block is still unresolved. The same classic corpus is tighter now too: inside that - `0x108` span the map-path C string begins at relative offset `0x13`, the display-name C string - begins at `0x46`, the block is otherwise almost entirely zeroed, and the three local samples are - byte-identical except for the leading dword at `+0x00` (`3` in `Autosave.gms` and `hh.gms`, - `5` in `kk.gms`). The currently atlas-tracked bytes `[profile+0x77]`, `[profile+0x82]`, - `[profile+0x97]`, and `[profile+0xc5]` are all `0` in that classic sample set, so the current - file-side evidence grounds the block boundaries and the embedded strings but does not yet show - live examples of those branch-driving latches being set. One 1.05-era file-side analogue is now - visible too, but only as an inference from repeated save structure rather than a disassembly-side - field map: local `.gms` files in `rt3_105/Saved Games` carry one compact string-bearing block at - `0x73c0` with the same broad shape as the classic profile slab, including a leading dword at - `+0x00`, one map-path string at `+0x10`, one display-name string at `+0x43`, and a small - nonzero tail around `+0x76..+0x88`. In that 1.05 corpus the analogue bytes at relative `+0x77` - and `+0x82` are now nonzero in every checked sample (`Autosave.gms`/`nom.gms` show `0x07` and - `0x4d`; `p.gms`/`q.gms` show `0x07` and `0x90`; `g.gms` shows `0x07` and `0xa3`), while - relative `+0x97` and `+0xc5` remain `0`. The compared 1.05 save set is tighter now too: - `Autosave.gms` and `nom.gms` cluster together on `Alternate USA.gmp` with `+0x82 = 0x4d`, - `g.gms` carries `Spanish Mainline.gmp` with `+0x82 = 0xa3`, and `p.gms`/`q.gms` cluster on - `Southern Pacific.gmp` with `+0x82 = 0x90`; across all five files the same inferred analogue - lane at `+0x77` stays fixed at `0x07`, while the same map- or scenario-sensitive tail word at - `+0x80` tracks those `0x4d/0xa3/0x90` byte lanes (`0x364d0000`, `0x29a30000`, `0x1b900000`). - The leading dword at `+0x00` also splits the same corpus, with `Autosave.gms` alone at `3` and - the other four checked 1.05 saves at `5`. That is enough to say the wider save corpus does - contain nonzero candidates for two of the atlas-tracked profile lanes, and that one of them - varies coherently with the loaded scenario family, but not yet enough to claim that the 1.05 - block reuses the exact same semantic field assignments as the classic one. The loader-side - family split is tighter now too: `p.gms` and `q.gms` no longer live under a generic fallback; - their save headers now classify as one explicit `rt3-105-scenario-save` branch with preamble - words `0x00040001/0x00018000/0x00000746` and the early secondary window - `0x00130000/0x86a00100/0x21000001/0xa0000100`, while `g.gms` now classifies as a second - explicit `rt3-105-alt-save` branch with the different preamble lane - `0x0001c001/.../0x00000754` and early window - `0x00010000/0x49f00100/0x00000002/0xa0000000`. That branch now carries the same bootstrap, - anchor-cycle, named 1.05 trailer, and narrow profile-block extraction path as the other 1.05 - saves. The bridge just below that trailer is now explicit too: the common 1.05 save branch - carries selector/descriptor `0x7110 -> 0x7801` in `Autosave.gms` and `0x7110 -> 0x7401` in - `nom.gms`, and both still reach the same first later candidate at - `span_target + 0x189c`, well before the packed profile at `span_target + 0x3d48`; the - `rt3-105-alt-save` branch instead carries `0x54cd -> 0x5901` and its first later candidate - lands at `packed_profile + 0x104`, essentially on the profile tail; the scenario-save branch - still diverges locally with `0x0001 -> 0x0186` and never enters that later `0x32c8`-spanned - bridge at all. The common-branch bridge payload is narrower now too: both checked base saves - expose the same 0x20-byte primary block at `0x4f14` followed by the same denser secondary block - at `0x671c`, `0x1808` bytes later, and that secondary block now appears to run intact up to the - packed-profile start at `0x73c0` for a total observed span of `0xca4` bytes. The trailing slice - of that secondary block is now typed one level further: a small header at `secondary+0x354` - carries the observed stride `0x22`, capacity `0x44`, and count `0x43`, followed by a fixed-width - 67-entry name table starting at `secondary+0x3b5` and running through names like - `AluminumMill`, `AutoPlant`, `Bakery`, `Port00..11`, and `Warehouse00..11`, with a short footer - (`dc3200001437000000`) after the last entry. The trailing per-entry word is now surfaced too: - most entries carry `0x00000001`, while the currently observed zero-trailer subset is - `Nuclear Power Plant`, `Recycling Plant`, and `Uranium Mine`. That footer is tighter now too: - it parses directly as `0x32dc`, `0x3714`, and one trailing zero byte, so the shared - map/save catalog currently ends on the same two grounded late-rehydrate progress ids that the - classic staged-profile band already exposed. The strongest structural read is therefore that the - entire `0x6a70..0x73c0` catalog region is shared verbatim between `Alternate USA.gmp` and the - derived `Autosave.gms`, not rebuilt independently during save. Combined with the earlier - grounded record-layout work under `0x00437743`, `0x00434ea0`, and `0x00434f20`, the current - safest semantic read is that this shared catalog is the bundled source form of the scenario-side - named candidate-availability table later mirrored into `[state+0x66b2]`, with each entry's - trailing dword now reading as the same availability override bit later copied into - `[candidate+0x7ac]`. The loader-side coverage is tighter now too: the same table parser now - attaches both to the common-save bridge payload and directly to the fixed source range in - `.gmp` files and the non-common `rt3-105-scenario-save` / `rt3-105-alt-save` branches. That - makes the scenario variation explicit instead of anecdotal. `Alternate USA` keeps only three - zero-availability names in this table (`Nuclear Power Plant`, `Recycling Plant`, `Uranium - Mine`), `Southern Pacific` widens the zero set to twelve (`AutoPlant`, `Chemical Plant`, - `Electric Plant`, `Farm Rubber`, `FarmRice`, `FarmSugar`, `Nuclear Power Plant`, `Plastics - Factory`, `Recycling Plant`, `Tire Factory`, `Toy Factory`, `Uranium Mine`), and `Spanish - Mainline` widens it again to forty-two, including `Bauxite Mine`, `Logging Camp`, `Oil Well`, - `Port00`, and the `Warehouse00..11` run while also flipping `Recycling Plant` back to - available. The header lanes just ahead of the table vary coherently with those scenario - branches too: `Alternate USA` carries `header_word_0 = 0x10000000`, `Southern Pacific` - carries `0x00000000`, and `Spanish Mainline` carries `0xcdcdcdcd`, while the structural - fields from `header_word_2` onward remain stable (`0x332e`, `0x1`, `0x22`, `0x44`, `0x43`) - and the 9-byte footer still decodes as `0x32dc`, `0x3714`, `0x00` in all three checked maps. - A wider corpus scan over the visible `.gmp`/`.gms` files makes those two anonymous header - lanes less mysterious too: the parser currently sees only three stable - `(header_word_0, header_word_1)` pairs across 79 files with this table shape, namely - `(0x00000000, 0x00000000)`, `(0x10000000, 0x00009000)`, and - `(0xcdcdcdcd, 0xcdcdcdcd)`. The zero-availability count varies widely underneath the first and - third pairs (`0..56` under the zero pair, `14..67` under the `0xcdcdcdcd` pair), so those two - lanes no longer look like counts or direct availability payload; the safest current read is - that they are coarse scenario-family or source-template markers above the stable - `0x332e/0x22/0x44/0x43` table header, with `0xcdcdcdcd` still plausibly acting as one reused - filler or sentinel lane rather than a meaningful numeric threshold. Current exported - disassembly notes still do not ground one direct loader-side or editor-side consumer of - `header_word_0` or `header_word_1` themselves, so that family-marker read remains an - inference from corpus structure rather than a named field assignment. - The new loader-side compare command makes the save-copy claim sharper too: for the checked - pairs `Alternate USA.gmp -> Autosave.gms`, `Southern Pacific.gmp -> p.gms`, and - `Spanish Mainline.gmp -> g.gms`, the parsed candidate-availability table contents now match - exactly entry-for-entry, with the only reported differences being the outer container family - (`map` vs `save`) and source-kind path (`map-fixed-catalog-range` vs the save-side branch). - has the explicit companion `world_refresh_selected_year_bucket_scalar_band` `0x00433bd0`, which - rebuilds the dependent selected-year bucket floats after the packed year changes; and then - rehydrates the named locomotive availability collection at `[world+0x66b6]` through - `locomotive_collection_refresh_runtime_availability_overrides_and_usage_state` `0x00461e00`. - That locomotive-side restore is tighter now too: its tail explicitly re-enters - `scenario_state_refresh_cached_available_locomotive_rating` `0x00436af0`, which rebuilds one - cached available-locomotive rating at `[state+0x4cbe]` from the current year plus the strongest - surviving available locomotive-side rating scalar `[loco+0x20]`, and the tiny query sibling - `0x00434080` is now bounded as the shell-side clamped read helper over that same cached field, - with the grounded shell-side reader later bucketing that value against `40/50/70/85/100`. The - same rehydrate band also refreshes the live structure-candidate filter and year-visible counts - through `structure_candidate_collection_refresh_filter_and_year_visible_counts` `0x0041e970`, - rebuilding the paired per-slot bands at `[candidates+0x246]` and `[candidates+0x16e]` and the - aggregate counts at `[candidates+0x31a]` and `[candidates+0x242]`; the same late checkpoint also - re-enters `placed_structure_collection_seed_candidate_subtype2_runtime_latch` `0x00434d40`, - which seeds runtime dword `[candidate+0x7b0]` across subtype-`2` candidate records before the - later world-wide reactivation sweep. That checkpoint also now has an explicit shell-facing scalar - publisher: `world_publish_shell_controller_progress_scalar_from_year_thresholds_or_selector_overrides` - `0x004354a0` writes one clamped `0..255` value into the current shell presentation object, - sourcing it either from the shell selector override pairs or from the scenario-side year-threshold - band rooted at `[state+0x3a/+0x51/+0x55/+0x59/+0x5d/+0x61]`; and just ahead of the later - scenario-side recipe rebuild, the same band also re-enters - `scenario_state_ensure_derived_year_threshold_band` `0x00435603`, which only falls into its - heavier rebuild body while `[state+0x3a] < 2` and otherwise leaves the derived year-threshold - companion slots `[state+0x51/+0x55/+0x59/+0x5d/+0x61]` unchanged. The neighboring late status - checkpoints around progress ids `0x196` and `0x197` also share one explicit stage gate now: - `world_query_global_stage_counter_reached_late_reactivation_threshold` `0x00444dc5` compares the - global counter `0x00620e94` against threshold `0x9901`, and the two current callers use a - negative result to clear `[world+0x39]` before the broader world and shell reactivation sweep. - The later reactivation tail is tighter now too: it includes the region-center world-grid flag - reseed pass - `0x0044c4b0`, which clears bit `0x10` across the live grid and then marks one representative - center cell for each class-`0` region through `0x00455f60`; its immediate sibling `0x0044c450` - then reruns `placed_structure_rebuild_candidate_cargo_service_bitsets` `0x0042c690` across every - live grid cell. The small secondary-raster premark helper `0x0044c570` is bounded now too: it - only admits cells whose current raster byte has no bits in mask `0x3e` and whose parallel class - query `0x00534e10` is false, then rewrites that masked class field to `0x02` and widens the same - cached bounds-and-count band `[world+0x21c6..+0x21d6]`. The next helper `0x0044ce60` scans the secondary raster at `[world+0x2135]` - for cells with any bits in mask `0x3e`, caching min/max bounds plus a marked-cell count in - `[world+0x21c6..+0x21d6]`; the larger sibling `0x0044c670` then consumes those cached bounds to - normalize the same raster and rebuild one dependent overlay/cache surface before the later - route-style rebuild, shell-window, and briefing branches. That overlay side is tighter now too: - after `0x0044c670` resolves scaled surface dimensions through `0x00534c50`, it walks one local - `3 x 32` sample lattice through the static offset tables at `0x00624b28/0x00624b48`, keeps only - secondary-raster classes `4..0x0d`, folds several interpolated `0x0051db80` samples into one - strongest local score, writes packed overlay pixels into the staged surface buffer, and only then - publishes that staged overlay through `0x00534af0`. The lower helper layer under that overlay - pass is tighter now too: `0x00534e10` is the reusable secondary-raster class-set - predicate for classes `1/3/4/5`, `0x00534e50` is the smaller neighboring class-subset predicate - for `1/4`, `0x00534ec0` covers `2/4/5`, `0x00534f00` covers `3/5`, `0x00534e90` is the - marked-bit query over the same 3-byte cell family, and the nearby local counter `0x0044bdb0` - is now bounded as the 8-neighbor count companion for that same `2/4/5` subset, walking the - shared `0x00624b28/0x00624b48` offset tables and re-entering `0x00534ec0` on each bounded - neighbor cell. The first caller cluster around `0x0044bf9d..0x0044c37b` therefore reads as a - secondary-raster neighborhood service band rather than a generic map scan. - `0x00533e70` and `0x00534160` are the coarser siblings over the overlay table at `[world+0x1685]`: - the first clears coarse chunk objects across one clamped rectangle, while the second ensures one - chunk object and seeds local marks through its deeper stamp helper. One level up, the neighboring - rect owner `0x005374d0` now reads as the shared secondary-overlay refresh pass: it reruns the - local sample and unsigned-word reducers `0x00536230/0x00536420`, rebuilds the signed vector byte - planes through `0x00536710`, and then rebuilds the multiscale support surfaces through - `0x00533890`, whose inner reducers now explicitly target the packed sample-triplet buffer plus - the float and unsigned-word support planes rooted at the five-entry per-scale families - `[world+0x15f1..+0x1601]`, `[world+0x1605..+0x1615]`, and `[world+0x1619..+0x1629]`. The setup - side of that same family is tighter now too: - `0x005375c0` is the shared ensure-and-seed owner that allocates the sample, sidecar, mask, - raster, vector, and coarse-cell tables together; crucially, it seeds `[world+0x1655]` with byte - `0x02` and `[world+0x1659]` with byte `0x01`, which closes the default-fill split. The local - component-walk owner under the same neighborhood band is tighter now too: `0x0044c200` - allocates a temporary `width*height` visit bitmap at `0x0062c128`, seeds one class-`2/4/5` - starting cell, derives an initial direction index through the remap table `0x005ee5d4`, and then - fans into the deeper recursive walker `0x0044be20`. That deeper walker widens dirty bounds - `[world+0x21ad..+0x21b9]`, stamps one companion-word orientation lane through `0x005ee5cc`, - reuses `0x00534ec0` plus `0x0044bdb0` to filter admissible neighbors, tracks temporary - visitation in `0x0062c128`, and then applies the local byte-1 edge-bit `0x04/0x08` updates - before returning. So the `0x0044bf9d..0x0044c422` cluster now reads as a real connected-component - walk plus edge-flag refresh layer over the secondary raster rather than only a loose group of - local neighbor counters. The adjacent mutation strip is tighter now too: `0x0044dcf0` refreshes - companion-word bit `0x200` in one local rectangle by checking whether any neighbor belongs to - class set `2/4/5`, while `0x0044df10` clears three local sidecar byte planes, demotes class `4` - to `1` and class `5` to `3`, and then reruns that marked-bit refresh over the surrounding - `+/-1` window. One level up, `0x0044e500` is the rect-wide owner that recomputes byte-1 edge - bits `0x04/0x08` for class-`2/4/5` cells, dispatches `0x0044df10` on incompatible local - patterns, and finally consumes the pending global seed pair at `[0x006d1304+0x78/+0x7c]` - through `0x0044c200`. The shell-side owner of that pending pair is tighter now too: - `[0x006d1304]` is the live `PaintTerrain.win` shell singleton while the callback-heavy side also - keeps a second rooted pointer at `0x006d1334`; the tool constructor snapshots the broader - terrain-paint state into both families while the world-side raster owner still only consumes - `[0x006d1304+0x78/+0x7c]` as one pending component-seed pair. Its radial sibling `0x0044e7d0` - is narrower: - after validating world-space - coordinates through `0x00414bd0`, it stamps class-`2` marks into the secondary raster by walking - one clamped bounding box and admitting cells only when the radial falloff helper `0x0051db80` - stays positive before re-entering `0x0044c570`. The two small support predicates under that same - strip are now explicit too: `0x00414bd0` is the float grid-bounds gate, and `0x00449df0` is the - integer rectangle clamp-and-validity helper shared by the local mutation owners. One level up, - the broader rect-scoped owner is tighter now too: - `world_rebuild_secondary_raster_derived_surface_and_companion_planes_in_rect` `0x0044e940` - first reclamps the caller rectangle through `0x00449df0`, reruns the local edge-refresh owner - `0x0044e500`, lazily ensures one presentation target through - `0x0051f090/0x00534910/0x00534920/0x00534930`, and then resolves scaled target dimensions - through `0x00534c50` before allocating one temporary `width*height` mask. Its main scan then - walks the live secondary raster `[world+0x165d]` through the same class predicates - `0x00534e10/0x00534e50/0x00534f00/0x00534ec0`: class-`1/3/4/5` cells force `0xff` into the four - sidecar byte planes `[world+0x1631..+0x163d]`, while the broader per-cell pass writes packed - values into the ensured target through `0x00534730` and also updates nibble lanes at byte offsets - `+0x2` and `+0x5` inside the same three-byte secondary-raster cell family. After the publish it - notifies the shell owner at `0x0062be68`, re-enters `0x00449f80` and `0x004881b0`, frees the - temporary mask, expands the caller rectangle by dirty bounds `[world+0x21ad..+0x21b9]` through - `0x00536710`, and finally seeds companion byte `[world+0x162d]` with `0xc4` on cells selected - from mask plane `[world+0x1655]`. So the `0x0044e500 -> 0x0044e940` band is now a real - derived-surface and companion-plane rebuild family rather than only a loose collection of local - raster mutations. The local - evidence now also supports a stronger negative conclusion: unlike `[world+0x1655]`, that second - mask plane is not part of the actively rebuilt runtime overlay path, and in the grounded local - corpus it behaves only as a separately seeded, cleared, and persisted sibling plane. One level - lower, the - base-plane allocator `0x00532c80` now reads more cleanly too: it is the narrower owner that - clears `[world+0x15e1]`, optionally applies the current grid dimensions, allocates the base - float-summary plane `[world+0x1605]`, the four sidecar byte planes `[world+0x1631..+0x163d]`, - both one-byte mask planes `[world+0x1655/+0x1659]`, and the packed secondary raster - `[world+0x165d]`, then seeds those planes with the same `0x02/0x01/0x00` default split. The - load-side owner for those same planes is tighter now too: the constructor thunk `0x0044e910` - immediately feeds the heavier payload body `0x0044cfb0`, which reads the rooted chunk families - `0x2ee2/0x2ee3/0x2ef4/0x2ef5/0x2ef6/0x2ee4/0x2ee5/0x2f43/0x2f44`, allocates the core world-grid - and secondary-raster arrays `[world+0x2129..+0x2141]` plus the route-entry collection - `0x006cfca8`, initializes every grid-cell record through `0x0042ae50`, and only then hands off - into `world_compute_transport_and_pricing_grid` `0x0044fb70`, the neighboring presentation - refresh `0x00449f20`, and the shell-mode pulse `0x00484d70`. So the `0x0044e910 -> 0x0044cfb0` - load side is now bounded as the heavy world-grid and secondary-raster bundle-load body rather - than just another anonymous constructor tail. One - level higher again, the broader world-presentation reinitializer `0x00537e60` now sits above - that base allocator and the larger support-family ensure path `0x005375c0`: it stores the live - grid dimensions, hard-resets the whole overlay runtime family through `0x00532590`, - reinitializes the secondary-overlay family for those dimensions, and then republishes the - neighboring overlay constants and support owners used by both the world-side reattach branch and - the `.smp` restore-side presentation rebuild path, including several owners that all funnel - through the shared static-template slot allocator `0x00532ad0` over the local `0x100` pointer - band at `[world+0x08]`. Those neighboring owners are tighter now too: `0x00535070` is the small - primary overlay-surface-or-template setup owner, while `0x005356e0` and `0x00535890` seed two - larger static-template slot bands rooted at `[world+0x1568/+0x156c/+0x1574/+0x1578]` and - `[world+0x1560/+0x1564]` respectively; the remaining heavier sibling `0x00535430` now reads as a - shared four-slot overlay-surface rebuild owner that resamples one source or fallback descriptor - into a short local slot strip above `[world+0x155c]`. The tail of that same reinitializer is - tighter now too: after the larger support-family setup it seeds one seven-entry default overlay - companion set through `0x005373b0`, whose inner allocator `0x00535950` populates the local - `0x1b`-entry slot table from the static template rows `0x005dd300..0x005dd378`. The lifecycle - side is tighter in the same way now: `0x00536044` is the shared teardown owner that frees those same - three five-entry support families together with both mask planes, the packed secondary raster, - the vector-byte planes, the local staging buffer, and the neighboring sidecar or coarse-cell - tables. The remaining base-float lane is tighter too: the larger rebuild owner - `0x00538360` now clearly writes one base float-summary field into `[world+0x1605]`, clears both - one-byte mask planes, and then only repopulates the primary mask plane `[world+0x1655]` for the - qualifying class-`1` interior cells before re-entering `0x00532d90` to normalize that base - float-summary plane globally and `0x00532f60` to expand positive cells through one caller radius. - That asymmetry is now enough to close the local semantic edge: `[world+0x1655]` is the actively - rebuilt primary overlay mask, while `[world+0x1659]` is only the separately seeded and persisted - secondary mask sibling with no comparably grounded distinct read-side consumer. The only grounded - getter call to its root accessor `0x00533b60` is the shell staging branch at `0x00525bad`, and - that branch immediately discards the returned pointer. The bundle side is now explicit too: - `.smp` save-load treats the two mask planes as separate payloads with chunk ids `0x2cee` for - `[world+0x1655]` and `0x2d51` for `[world+0x1659]`, while the neighboring `0x2d49/0x2d50` - branches are the separate packed secondary-raster import lanes rather than alternate consumers - of the second mask plane. So, in the mapped local code, `0x1659` is best treated as a persisted - compatibility or seed-state sibling, not as a second actively consumed runtime overlay mask. The event - side is tighter too: - that `0x00433130` pass in turn materializes each live event record through - `scenario_event_refresh_runtime_record_from_packed_state` `0x0042db20`. Current shell-side xrefs - now tighten that event branch too: the first rebuilt linked row family under `0x0042db20` aligns - with the standalone condition list later queried by `EventConditions.win`, while the second - rebuilt family aligns with the four grouped effect lists later deep-copied through - `scenario_event_clone_runtime_record_deep_copy` `0x0042e050` during event duplication and effect - staging. The condition side is tighter now too: the tiny helper cluster - `0x0042df30/0x0042df70/0x0042dfb0/0x0042dff0` is no longer just "some adjacent list scans". - Current evidence bounds it as four predicates over the standalone `0x1e`-row condition list, - testing class bits `0x01`, `0x02`, `0x04`, or any of those bits in the static table - `0x005f3e04 + id*0x81`, with special fallback checks through event fields `[event+0x7f9]`, - `[event+0x7fa]`, and `[event+0x7f0] == 0x63`. The shell side is tighter too: vtable slot - `0x005d0cd8` now binds `shell_event_conditions_window_handle_message` `0x004d59e0`, and vtable - slot `0x005d0cf8` binds `shell_event_effects_window_handle_message` `0x004d7060`. The effects - side is tighter too: the lower helper trio is no longer anonymous. `0x004d5d00` now reads as the - effect-type selector refresh under control family `0x4fb2`, `0x004d5f50` reads as the selected - effect parameter-row repaint, `0x004d6090` is the heavier staged-effect editor refresh over the - `0x4fc7/0x4fce/0x4ff6/0x4ff9/0x4ffc/0x5041/0x5044/0x5046/0x5047` bands, and `0x004d67f0` - commits the current editor state back into the staged effect row at `[this+0x78]`. The verb side - is tighter now too: `shell_open_event_conditions_modal_and_return_result` `0x004d9dc0` and - `shell_open_event_effects_modal_and_return_result` `0x004d9e40` are the shared modal openers - above the two editor windows; `0x004da640`, `0x004da700`, and `0x004d9ed0` now read as the add, - edit, and remove verbs for standalone condition rows; `0x004da7c0`, `0x004da860`, and - `0x004da920` are the matching add, edit, and remove verbs for grouped effect rows; and - `0x004d8120` is now the heavier condition-row list panel refresh those condition-side verbs - re-enter after mutation. The conditions-side refresh split is tighter too: `0x0042d700` - aggregates standalone condition-list class or modifier flags, `0x0042d740` aggregates grouped - effect-row type flags for one selected grouped list, `0x004d9970` owns the condition-class - summary and grouped-row status bands, `0x004d77b0` owns the grouped summary-band affordance gate - for `0x4fed..0x4ff0` when selector `0x5000` lands on `0x5002`, `0x004d9d10` owns the smaller - grouped-effect territory-target affordance on control `0x500b`, `0x004d9f50` owns the selected-event mode - strip and summary text panels, and `0x004d9390` is the mode-dependent detail-row switch beneath - that strip. `0x004da0f0` is tighter too: selector `0x5001` now has the strongest current - RT3.lng fit as the condition-side `Test against...` mode above `0x004d9970`, while selector - `0x5002` has the strongest current fit as the grouped-effect-side `Apply effects...` mode. - That `0x5002` branch now clearly builds control `0x5014` from RT3.lng `1160..1164` as `to the - company/player/player (i.e. chairman)/territory for which the condition is TRUE` before - enabling the adjacent `0x5005`, `0x500a`, and `0x5014..0x501c` family. The strongest current - RT3.lng fit for the remaining visible target-scope strip is now `0x5015 = to the whole game`, - `0x5016..0x5018 = to all/human/AI companies`, `0x5019 + 0x500b = to territories`, and - `0x501a..0x501c = to all/human/AI players`; the grouped effect-row type mask matches that split - directly through bits `0x08`, `0x01`, `0x04`, and `0x02`. The - selected-event strip is tighter now too: `0x004db120` is the broader selected-event repaint and - navigation refresh above those smaller helpers, `0x004db520` and `0x004db5e0` are the previous - and next selected-event stepping verbs, `0x004db8b0` is the add-or-clone event modal helper, - `0x004dba90` is the rename verb, `0x004d9360` is the delete verb, `0x004db6a0` is the live - selected-event id setter behind control `0x4e84`, and `0x004db6f0` is the callback-binding plus - pending-selection bootstrap path that seeds the strip during window bring-up. The larger - dispatcher at `0x004dbb80` now makes the strip explicit: `0x4e85..0x4e8a` are previous, next, - add blank, clone selected, rename, and delete event, while the later grouped band commits current - summary state through `0x004d8d50` before changing grouped selector `[this+0x9c]` via `0x004dbf93`. - The selection bootstrap side is tighter too: `0x004daf40` is now the placeholder reset helper for - the selected-event summary controls `0x4eaf`, `0x4eac`, `0x4ed9`, `0x4edb`, and `0x4fdf..0x4fe2`. - The grouped target-scope side is tighter too: `0x004d8ea0` now reads as the commit helper for current - selected-event text panels before selection or grouped-action changes, `0x004d8d50` now records - the hidden selector family `0x5006..0x500e -> 0..8`, and `0x004dab60` projects that ordinal - one-to-one onto the visible grouped-effect target-scope display strip `0x5014..0x501c`. That - split is firmer now: `0x5006..0x500e` are the canonical hidden selectors that get stored into - `[event + group + 0x7fb]`, while `0x5014..0x501c` are the visible mirror rows republished from - that same ordinal rather than a second independently named selector family. The grouped row and - stored-summary refresh side is tighter too: `0x004d88f0` is now the selected grouped-effect - row-list renderer for `0x4ed5`, formatting the grouped `0x28`-byte rows through RT3.lng - `1154..1159`, and `0x004da9a0` is the current grouped-summary-state republisher that reloads - `0x500a`, `0x500b`, and visible action selection `0x5014..0x501c` from `[event + group + ...]` - before tailing back into `0x004da0f0`, - `0x004dbfca` as the grouped target-scope mode selector that persists the chosen control id into - `0x00622074`, with `0x5001/0x5002` now strongest-fit as `Test against...` and - `Apply effects...`, `0x004dbeeb` as the pending shared summary-text triplet publish helper for - `0x4eac/0x4ed9/0x4edb`, - `0x004d91e0` as the selected-event summary-header and grouped-mode commit helper above - `0x004d8d50`, and `0x004dbe7a` as the narrower `0x4ec6/0x4ec7` choice-event single-player-only - warning modal branch rooted at RT3.lng `3887`. The remaining gaps on - this lane are narrower again because the grouped-band `0x4dc09c` table now closes one earlier - overclaim: controls `0x5001/0x5002` are the only `0x4fed..0x501c` entries that route into - `0x004dbfca` on the `0xcf` side, while visible rows `0x5014..0x501c` only route to the smaller - `0x004d9d10` affordance path and the rest of `0x4ff1..0x5013` are default no-ops. The open - question is therefore no longer whether those visible target-scope rows are direct selector verbs; - current evidence says they are not. - The local slot records are rooted at - `[world+0x69d8]`, - `[slot+0x01]` polarity and the external role gate at `[world+0x0bc3+slot*9]` are now grounded, and - `[slot+0x03]` now looks like the distinguished primary-human-seat marker because current grounded - writes seed it only on slot zero and later logic moves it solely by whole-record compaction. The - open question is no longer whether the seeded trio lands in the visible shell company roster; - current evidence says it does, and ordinary `Start New Company` now looks like a fresh-company - allocator through `start_new_company_dialog_commit_create_company` and - `start_new_company_request_create_company`, not like the path that claims one of the seeded named - railroads. The immediate post-roster station branch is now clearly separate: current grounded - resource names and handlers put mode `8` on `StationDetail.win`, mode `5` on `StationList.win`, - and the subordinate selector helper on `StationPick.win`. The company-side ownership question has - therefore moved down a layer rather than staying open. We now have a recovered `CompanyDetail.win` - owner family through `shell_company_detail_window_refresh_controls`, - `shell_company_detail_window_construct`, and `shell_company_detail_window_handle_message`; the - same owner now has one broader bounded read-side lane too, because control `0x9470` uses - `shell_company_detail_render_financial_history_panel` to draw the five-step Revenue or Expenses or - Interest or Profit or Lifetime strip, sibling control `0x9471` reuses - `shell_format_company_financial_summary_card` through - `shell_company_detail_render_company_summary_card`, controls `0x947d` and `0x947e` now ground a - bond maturity and repay panel through `shell_company_detail_render_bond_maturity_and_repay_panel`, - control `0x9488` now grounds the debt or credit or rate summary block through - `shell_company_detail_render_debt_credit_and_rate_summary_panel`, control `0x948a` now grounds the - share-value and dividend-payout block through - `shell_company_detail_render_share_value_and_dividend_summary_panel`, while the broader six-row - per-share stock-data family is now bounded under `shell_format_company_stock_data_panel`, and the - adjacent territory selector lane is bounded through - `shell_company_detail_select_territory_access_row`, - `shell_company_detail_render_territory_access_row`, - `shell_company_detail_sync_selected_territory_from_picker`, and - `shell_company_detail_refresh_selected_territory_access_summary`; the first finance-action layer - beneath it is bounded through the bond, stock-issue, stock-buyback, and dividend-rate helpers; the - territory-access side is bounded too through - `shell_company_detail_refresh_selected_territory_access_summary`, - `shell_company_detail_buy_territory_access_rights_flow`, and the underlying company access-rights - helpers; and the full takeover and merger vote-result lane is now grounded through - `shell_resolve_chairmanship_takeover_vote_and_commit_outcome`, - `shell_present_chairmanship_takeover_vote_outcome_dialog`, - `shell_resolve_merger_vote_and_commit_outcome`, and `shell_present_merger_vote_outcome_dialog`. - The remaining company-side uncertainty is therefore narrower than before: the broader support and - valuation side is now tighter too because - `company_compute_cached_recent_per_share_performance_subscore`, - `company_compute_five_year_weighted_shareholder_return`, and - `company_compute_public_support_adjusted_share_price_scalar` bound the recent per-share - performance and investor-support/share-price blend beneath those vote resolvers; the recent - per-share feeder now has a grounded four-lane tail too, with current partial-year weight - `(5 * [world+0x0f]) - 5`, prior full-year weights `48/36/24/12` on `0x1f/0x1e`, dividend - non-decline pair weights `9/8/7/6` on `0x20`, lane weights `40/10/20/30`, the startup age ramp - `0/0/0/100 -> 25/25/35/100 -> 50/50/65/100 -> 75/75/85/100 -> 100/100/100/100`, a strongest-lane - `*1.25` boost, a weakest-lane `*0.8` reduction, and separate bounded-intermediate versus final - difficulty applications under `0x005f33b8`; the next consumer `0x00424fd0` is also tighter now, - with the young-company interpolation against `[company+0x57]`, caller pressure clamped to - `[-0.2, 0.2]`, one `(shares / 20000)^0.33` share-count growth term, and the later threshold - ladder `0.6 / 0.45 / 0.3 / 1.7 / 2.5 / 4.0 / 6.0` before the issue-`0x37` multiplier, - `scenario_state_compute_issue_opinion_multiplier` now bounds the - next layer of optional company, chairman, and territory-specific opinion overrides on the active - scenario state, and the broader stat-reader family around - `company_read_control_transfer_metric_slot` and - `company_read_year_or_control_transfer_metric_value` is no longer just a merger-premium helper. - Current grounded callers show the same metric family feeding the annual shareholder-revolt and - creditor-liquidation lane surfaced by localized ids `300..304`, while the debt-side shell and - bond lane now separately close `0x38` as `Credit Rating` and `0x39` as `Prime Rate`. That means - the remaining gap is now mostly gone on the UI side too: issue `0x37` is already bounded to the - same investor-confidence family as the equity-support and governance-pressure paths, and current - grounded UI evidence still stops at the investor-attitude sentence family rather than one - standalone caption. The calendar side is tighter now too: - `[world+0x15]` is the absolute counter for the same mixed-radix `12 x 28 x 3 x 60` - year-plus-subfield tuple packed by `0x0051d3c0` and unpacked by `0x0051d460`, not just a vague - “calendar-like” blob. The `TrackLay.win` family now clearly owns `Lay single track.` `Lay double track.` - and `Bulldoze` as its three primary modes, its bridge selector, its wrapped frequency preferences, - and a strongly aligned pair of `Auto-Hide Trees During Track Lay` and `Auto-Show Grade During - Track Lay` toggles; the `StationPlace.win` family now clearly owns its six top-level category - buttons, the station-style scroller, and the station-rotation controls. The older `Building - placement center` string 671 no longer looks like a live StationPlace control label in the current - recovered flow, because the active constructor, preview, refresh, and dispatcher paths all use - neighboring ids such as 669 and 2208 without a direct recovered lookup of 671. On save or load the - broad serialize-versus-restore split is now grounded, the non-Quicksave `.gmp/.gmx/.gmc/.gms` - families are separated, and the auxiliary `.gmt` path is at least bounded to the preview-surface - side owner. The higher-value shell-facing gap has therefore shifted upward to the remaining - semantics of the post-load generation phases, the later recurring structure-population cadence, - the deeper vote-weight formulas inside takeover and merger resolution, and the still-open meaning - of the packed simulation calendar tuple. - -- CompanyDetail, tighter section ownership: the shell detail family now has an explicit - section-selector lane in addition to the read-side panels already mapped. Controls - `0x9472..0x9475` directly select the four visible CompanyDetail sections through `0x006cfe60`, - `0x9476..0x9479` are the companion visual controls for that same tab strip, and section `0` is now - bounded more tightly as the chairman or governance slice around the portrait-backed chairman band - on `0x9480` plus the dynamic overview widget `0x947f`. That widget is no longer just a vague - status line: the section-0 refresh binds it through a dedicated stack-built dynamic text path, - and the strongest current shared formatter candidate is - `shell_format_company_governance_and_economy_status_panel` at `0x004e5cf0`, which first renders a - five-line company-metric preamble through localized ids `1211..1215`: `Revenues` from slot - `0x2c`, `Profits` from slot `0x2b`, `Load miles hauled` from slot `0x17`, `Revenue per load - mile` from the derived `slot 0x2c / slot 0x17` branch, and `Average speed` from slot `0x26` - rendered through `1216` `%1 m.p.h.`. It then splits the governance summary more concretely: no - linked chairman emits `3045`, wholly owned companies emit `3046` for the scenario-selected - chairman or `3047` for another linked chairman, and investor-owned companies emit the - investor-attitude lines `3048/3049` with one adjective from the table at `0x00622170`. That - branch is no longer using unnamed helpers either: `company_get_linked_chairman_profile_record` - `0x00426ef0` resolves the linked chairman profile and `chairman_profile_owns_all_company_shares` - `0x004768c0` is the full-ownership test behind the `3046/3047` split. The salary side is tighter - too: the formatter computes one signed delta from `[company+0x14f]` and `[company+0x0d59]`, then - chooses `3050..3052` for the scenario-selected chairman or `3053..3055` for another linked - chairman depending on whether that delta is negative, positive, or zero. The bonus line is - narrower still: it only appears when the display year matches `[company+0x34f]`, using amount - `[company+0x353]` with `3056` or `3057`. It then appends the - `1218` `Economy status - %1.` tail caption and stages the adjacent selected-company report or - list help-title pairs `1219/1220` `Income Statement`, `1221/1222` `Balance Sheet`, - `1223/1224` `Haulage Report`, `1225/1226` `Stock Report`, `1227/1228` `Train List`, - `1229/1230` `Station List`, `1231/1232` `Industry List`, and `1233/1234` `Cargo List`. - Current evidence still does not recover separate `CompanyDetail.win` action controls for that - strip under `shell_company_detail_window_handle_message`, so it currently reads as staged - overview text or help content rather than as a closed launcher family. The direct `0x947f` - formatter call is still indirect, but the widget boundary is tighter too: the generic shell - helpers `shell_control_refresh_matching_dynamic_text_payload` `0x00540a47` and - `shell_control_release_dynamic_text_payload` `0x005639d2` now show that type `0x6f` controls - free or swap one heap-backed text payload and then short-circuit as a special dynamic-text case, - which strengthens the reading of `0x947f` as a display-only overview widget rather than a normal - callback control. One adjacent boundary is tighter now too: the broader overview wrapper at - `shell_render_company_overview_panel_header_and_optional_change_affordance` `0x004e5a80` owns - the fallback no-company texts `1210`, `3043`, and `3888`, styles controls `0x3f06` and `0x3f07`, - and on the narrower selected-company branch appends `3044` `Click to change company name and - logo.` plus the neighboring `1941` `Change` affordance before falling through into the shared - `0x004e5cf0` text body. That keeps the name/logo affordance outside the ordinary - `CompanyDetail.win` action dispatcher and makes the `0x947f` alignment cleaner. The message-side - action band is tighter too: `0x94b5` grounds - territory-access purchase, `0x94b6` grounds bankruptcy, `0x94cf..0x94d2` ground bond issue, stock - issue, stock buyback, and dividend-rate changes, `0x9493` routes into the destructive - company-clear helper that deactivates the selected company and clears chairman/share links, - `0x94d6` grounds bankruptcy, `0x94d7..0x94da` ground bond issue, stock issue, stock buyback, and - dividend-rate changes, `0x94db` grounds merger, `0x94dc` grounds resignation, and `0x9538` grounds - chairmanship takeover. The finance-side dialog family is tighter too: the bond-issue lane now has - the dedicated modal renderer `shell_company_detail_render_issue_bond_offer_dialog` `0x004c3560` - for underwriter terms `968..972`, the stock-issue lane has - `shell_company_detail_render_issue_stock_offer_dialog` `0x004c3b50` for the staged offer lines - `975..978`, and the buyback lane has - `shell_company_detail_render_stock_buyback_offer_dialog` `0x004c4300` for broker lines - `981..984`. The compact summary card on sibling control `0x9471` is tighter too: - `shell_format_company_financial_summary_card` at `0x004bfb30` now clearly renders `Cash:`, - `Revenue:`, and `Profits:` from company slots `0x0d`, `0x2c`, and `0x2b`, rather than one looser - unnamed finance block. The dividend lane is now split the same way: - `shell_company_detail_setup_dividend_rate_adjust_controls` `0x004c4c70` binds the paired adjust - controls `0x99e8` and `0xc0f9`, - `shell_company_detail_render_change_dividend_rate_dialog` `0x004c4e30` renders localized ids - `988..990`, and - `shell_company_detail_handle_change_dividend_rate_dialog_message` `0x004c5140` clamps the staged - dividend rate against `company_compute_board_approved_dividend_rate_ceiling` `0x00426260` and - raises localized id `991` when the board refuses a higher dividend, all before the existing - company commit path. All four finance verbs now converge through the shared - callback-driven modal opener `shell_open_custom_modal_dialog_with_callbacks` `0x004c98a0`, which - is also reused by the multiplayer staged text-entry lane. The front controls in section `0` are - tighter too: `0x948b` is a - tutorial-guarded escape or back control that shows localized id `3724` `This option is disabled in - the tutorial.` before falling back to the shell detail-manager escape path, `0x9491` and `0x9492` - only restyle the paired visuals `0x948f` and `0x9490`, and `0x9494` opens localized id `3635` - `Enter the amount that your company's cash should be` and writes the accepted value directly into - the selected company cash pair. The neighboring debt section is tighter now too: controls - `0x947d` and `0x947e` no longer read as one-off bond widgets, but as the owners of two repayable - bond-slot row bands, `0x94e8..0x950f` and `0x9510..0x9537`. Those row controls now clearly - converge on the same repayment path in the message dispatcher: they reject unaffordable repayment - through localized id `2990`, open the early-repayment confirmation rooted at `2991`, and then - either commit through `company_repay_bond_slot_and_compact_debt_table` `0x00423d70` or package - the request through the multiplayer shell transport. The render-side owner is tighter too: - `shell_company_detail_render_bond_maturity_and_repay_panel` formats `Due %1` and `Repay this - bond.` for the selected debt slot while the tiny binder - `shell_company_detail_bind_bond_row_band_for_active_panel` switches between the two row bands. - Current `0xcb` dispatch does not treat `0x948f`, `0x9490`, `0x94d4`, or `0x94d5` as standalone - action cases. The message-side jump table now makes that passive/action split explicit too: in the - dispatch byte map rooted at `0x004c6640`, controls `0x94d6..0x94dc` map to cases `0x06..0x0c`, - control `0x9538` maps to case `0x0d`, and the neighboring companion rows `0x94d4` and `0x94d5` - stay on the default path. The refresh-side ownership is tighter too: the helper now explicitly - loops over `0x94d4..0x9537` as the selected-company-owned band and over `0x9538..0x959b` as the - linked-chairman-owned band, and those two loops do not use the same style polarity. - `0x94d4..0x9537` take style `0x65` when the selected company matches the scenario-selected - company and `0x87` when it differs, while `0x9538..0x959b` take style `0x87` when the selected - company's linked chairman matches the scenario-selected chairman and `0x65` otherwise. The - selected-company action side - is tighter now too: scenario toggle `0x006cec78+0x4a8f` re-enables bankruptcy `0x94d6` together - with passive companion row `0x94d4`, `+0x4a8b` re-enables issue bonds `0x94d7` together with - passive companion row `0x94d5`, `+0x4a87` re-enables stock issue and stock buyback - `0x94d8..0x94d9`, `+0x4a93` re-enables dividend `0x94da` together with the same passive - companion row `0x94d5`, `+0x4adb` re-enables merger `0x94db`, `+0x4acb` re-enables resignation - `0x94dc`, and `+0x4acf` re-enables chairmanship takeover `0x9538`. That makes `0x94d4/0x94d5` - read more like passive companion or heading widgets than hidden verbs. The constructor boundary - is tighter too: current `CompanyDetail.win` setup still only binds explicit callbacks for - `0x9470`, `0x9471`, `0x947d`, `0x947e`, and `0x948c..0x948e`, not for the wider section-0 row - bands. That keeps the remaining `0x94d4..0x959b` content looking more like resource-defined - display rows that are gated and restyled by refresh than like individually code-rendered widgets. - That leaves the main remaining CompanyDetail-specific shell edge at the exact `0x947f` formatter - binding plus the still-unsplit render-side governance rows inside `0x94d4..0x959b`. -- Adjacent `LoadScreen.win` report family: the neighboring shell lane around controls - `0x3ef6..0x4073` is now separated from `CompanyDetail` instead of being treated as one more - extension of the `0x947f` overview path. The real outer owner is - `shell_load_screen_window_construct` `0x004ea620`, which binds `LoadScreen.win`, randomizes the - `LoadScreen%d.imb` background family, stores the singleton at `0x006d10b0`, and seeds the first - visible page-strip controls. Above the older page-specific work, the real message owner is now - `shell_load_screen_window_handle_message` `0x004e3a80`: it owns page id `[this+0x78]`, - page-local substate `[this+0x7c]`, page-kind `[this+0x80]`, current company `[this+0x88]`, - current chairman profile `[this+0x8c]`, display year `[this+0x9c]`, and the page-local report - row latch `[this+0x118]`, then fans back into the shared selector - `shell_load_screen_select_page_subject_and_refresh` `0x004e2c10`, the company-step helper - `0x004e3a00`, and narrower page branches such as `0x004e45d0`. The matching render-side owner is - now bounded too: `shell_load_screen_render_active_page_panel` at `0x004ea060` formats the common - heading and panel frame, then switches on page id `[this+0x78]` and hands control down into the - active page body. That older branch is now demoted to what it actually is: - `shell_load_screen_profile_stock_holdings_page_handle_message`, the page-specific handler beneath - the stock-holdings slice. Inside that same family, - `shell_load_screen_render_profile_stock_holdings_summary_panel` at `0x004e5300` grounds the - selected-profile holdings page: it resolves the current chairman profile from `[this+0x8c]`, - renders the top summary rows `1204` `Stock Value:`, `1205` `Total Assets:`, and - `1206` `Stock Holdings:`, then walks the active company roster and formats one row per positive - holding through `1201` `Click to view details on %1.`, `1207` `%1 Shares`, and `1208` `%1 Value`, - falling back to `1209` `None` when no positive holdings survive. It also appends `3029` - `Click to change player name and portrait.` plus the adjacent `1941` `Change` affordance only - when the rendered profile matches the scenario-selected chairman. The earlier pages are tighter - now too: `0x004e68e0` is the selected-company financial ranking page using the active company - roster plus `1235..1245` for revenue, profit, cash, track mileage, and report affordances; and - `0x004e6ef0` is the active-chairman wealth ranking page using the chairman profile collection - plus `1237`, `1241`, `1246..1250` for cash, stock, total, and purchasing-power style comparisons. - The later sibling renderers are broader than that one holdings page now too: `0x004e7670` is the - selected-company train list page using `1235..1267`, `0x004e8270` is the selected-company - building list page using `1268..1278`, `0x004e8bb0` is the selected-company station list page - using `1279..1288`, and `0x004e9460` is the map-wide cargo list page using `1289..1298` over the - live candidate collection rather than one company roster. The last broad early-page owner is - tighter now too: `0x004e9b20` is the shared multi-year company report-table renderer for page - `4` `Income Statement`, page `5` `Balance Sheet`, and page `6` `Haulage Report`, all driven from - `0x004ea060` with one caller-supplied mode byte and yearly company rows built through - `company_read_year_or_control_transfer_metric_value`. The row families are bounded too: - income-statement rows `1301..1315`, balance-sheet rows `2816` and `1317..1322`, and - haulage-report rows `1323..1335`. The only special rows inside that family are now tighter too: - `0x00425880` and `0x004258c0` provide the negative-cash and positive-cash interest-rate inserts - for the `%1/%2` placeholders in strings `2815` and `2816`, so they are no longer anonymous - private math blobs. The adjacent early siblings are tighter now too: `0x004e5130` is the - selected-company `Stock Data` page wrapper that falls back through `1299` and otherwise reuses - `0x004c0160` to render the `Largest Shareholders`, `Shares`, and `Per Share Data` family; - `0x004e6ef0` is the `Player List` page; `0x004e5300` is the `Player Detail` holdings page; and - `0x004e51ea` is the `Game Status` briefing panel that pulls current scenario briefing text from - the live scenario text store and appends the `1772/1773` `Briefing` affordance. The active-page - renderer at `0x004ea060` is now tighter too because its 13-byte page descriptor table at - `0x006220a0` has been decoded directly as `{ page kind, title string id, `0x3ef8` backlink - page, selected-company-header flag }`. The currently grounded rendered title order is: - `XXX`, `COMPANY OVERVIEW`, `COMPANY LIST`, `INCOME STATEMENT`, `BALANCE SHEET`, - `HAULAGE REPORT`, `STOCK DATA`, `PLAYER LIST`, `PLAYER DETAIL`, `GAME STATUS`, - `TRAIN LIST`, `TRAIN DETAIL`, `STATION LIST`, `STATION DETAIL`, `CARGO LIST`, - and `INDUSTRY LIST`. Its live body bindings are now bounded too: page `0` falls back to - `1203` `Unable to display page`, page `1` is the company overview wrapper, page `2` is the - company list page, pages `3..5` are income statement, balance sheet, and haulage report, page - `6` is stock data, page `7` is player list, page `8` is player detail, page `9` is game status, - page `0x0a` is train list, page `0x0b` currently falls back to `1203`, page `0x0c` is station - list, page `0x0d` currently falls back to `1203`, page `0x0e` is cargo list, and page `0x0f` - is industry list. The row-click path is tighter now too: player-list rows re-enter page `8` - directly, but train, station, and industry rows leave `LoadScreen.win` through the shell - detail-panel manager at `0x004ddbd0` instead of switching to title-table pages `0x0b` or - `0x0d`. Page `0` is tighter now too: its descriptor is kind `0`, title `1200` `XXX`, backlink - `0`, and header flag `0`, and no current post-constructor selector path has been recovered for - it. The descriptor side now also bounds the only known reverse route for the dormant detail - titles: `0x3ef8` is the table-driven backlink affordance, so if page `0x0b` or `0x0d` were ever - selected, the known reverse path would return to train-list page `0x0a` or station-list page - `0x0c` respectively rather than through a separate detail-only owner. - The launcher side is tighter too: current grounded `shell_open_or_focus_load_screen_page` - callers cover pages `1`, `2`, `3`, `4`, `5`, `6`, `7`, `9`, `0x0a`, `0x0c`, `0x0e`, and `0x0f`, - and no current recovered opener or row-click route selects `0x0b` or `0x0d`. So the - `LoadScreen.win` family now has a much cleaner shape: one outer message owner - `0x004e3a80`, one active-page render owner `0x004ea060`, and then the narrower page-specific - handlers and renderers beneath them. The launcher side is tighter now too: `0x004e4ee0` is the - shared open-or-focus ledger-page owner above this family. Outside sandbox it either re-enters - `shell_load_screen_select_page_subject_and_refresh` on the live runtime at `0x006d10a8` or - allocates that transient runtime, seeds it through `0x004e4b10`, and enters the visible modal - loop; inside sandbox it raises localized id `3899` `The ledger is not available in sandbox mode.` - instead. That narrows the remaining `LoadScreen.win` gap again: `TRAIN DETAIL` and - `STATION DETAIL` now read as dormant title-table entries unless some still-unrecovered nonstandard - selector reaches them. The live auto-load boundary is tighter now too: hook-driven - `shell_transition_mode(4, 0)` now completes old-mode teardown, reconstructs and republishes - `LoadScreen.win`, and returns cleanly, but the later post-transition service ticks still keep - `[0x006cec78] = 0`, `[shell_state+0x0c]` on the same `LoadScreen.win` singleton, and - `[LoadScreen.win+0x78] = 0` through at least counts `2..8`. So the next runtime edge is no - longer the old mode-`4` teardown or publish band; it is the `LoadScreen.win` message owner - `0x004e3a80` itself, because later service alone is not promoting the plain load screen into the - separate startup-runtime object path. One later runtime probe did not actually reach that edge: - the `0x004e3a80` hook installed, but the run never produced any ready-count, staging, - transition, post-transition, or load-screen-message lines, only ordinary shell node-vcall - traffic. So that result is now treated as a gate-or-cadence miss rather than as evidence against - the `LoadScreen.win` message path itself. The newer shell-state service trace tightens it again: - on a successful staged run the later service ticks do execute in `mode_id = 4`, but the - `0x004e3a80` message hook still stays silent while the state remains frozen in the plain - `LoadScreen.win` shape. So the next runtime boundary is now the shell-runtime prime call - `0x00538b60` beneath `shell_state_service_active_mode_frame` `0x00482160`, not the message owner - alone. The first direct `0x00538b60` probe run is not trustworthy yet, though: it stopped - immediately after the first shell-state service-entry line, before any ready-count or - runtime-prime entry logs. So that result is currently treated as probe validation work, not as a - real boundary move inside RT3. The static service branch is conditional too: `0x00482160` only - enters `0x00538b60` when `[shell_state+0xa0] == 0`, so silence from the runtime-prime hook does - not yet prove the shell stops before that call unless the service-entry logs also show the `+0xa0` - gate open. The newer run now closes that condition: `[shell_state+0xa0]` is `0`, and the - `0x00538b60` runtime-prime hook enters and returns cleanly. The newer run closes the next owner - too: `0x00520620` `shell_service_frame_cycle` also enters and returns cleanly on the same frozen - mode-`4` path, and the logged fields match its generic branch rather than a startup-promotion - lane (`[+0x1c] = 0`, `[+0x28] = 0`, `flag_56 = 0`, `[+0x58]` pulsed then cleared, and - `0x006cec78` stayed `0`). So the next runtime boundary under the same shell-state service pass is - now one level deeper: the per-object service walker `0x0053fda0` beneath `0x00538b60`. The newer - run closes that owner too: it enters and returns cleanly while servicing the `LoadScreen.win` - object itself, with `field_1d = 1`, `field_5c = 1`, and a stable child list under - `[obj+0x70/+0x74]`, and its first child-service vcall target at slot `+0x18` stays - `0x005595d0`. Since `0x006cec78` still stays `0` through those clean object-service passes, the - next runtime boundary is now the child-service target `0x005595d0`, not the higher object - walker. The newer child-service run narrows that again: the first sixteen `0x005595d0` calls are - stable child lanes under the same `LoadScreen.win` parent, with `[child+0x86]` pointing back to - the load-screen object, `field_b0 = 0`, and a split where earlier children carry - `flag_68 = 0x03` and return `4` while later siblings carry `flag_68 = 0x00` and return `0`. The - static body matches that read too: `0x005595d0` is gated by `0x00558670` and then spends most of - its work in draw or overlay helpers `0x54f710`, `0x54f9f0`, `0x54fdd0`, `0x53de00`, and - `0x552560`, so it now reads as another presentation-side service lane rather than the missing - startup-runtime promotion. The widened allocator-window trace then reconciled the runtime with - the static mode-`4` branch one step further: the first transition-window allocation is `0x7c`, - which matches the static pre-construct `0x48302a -> 0x53b070` alloc exactly, and the later - `0x111/0x84/0x3a/0x25...` allocations all occur before `LoadScreen.win` construct returns, so - they now read as constructor-side child or control setup. That means the allocator probe did not - disprove the still-silent startup-runtime slice; it simply exhausted its log budget inside the - constructor before the post-construct block. The later reset-at-return run is now the decisive - one: after `LoadScreen.win` construct returns there are still no further allocator hits before - publish and transition return, which matches the corrected jump-table decode because mode `4` - does not own the `0x46c40 -> 0x4336d0 -> 0x438890` startup-runtime path. -- Editor breadth: the broader map-editor page owner is now bounded through - `map_editor_panel_select_active_section` `0x004ce070` and - `map_editor_panel_dispatch_active_section_message` `0x004cf700`, which switch among the grounded - setup pages, `Cities/Regions`, `Territories`, the `Players` and `Player Pool` setup slices, the - now-grounded `Building Density` page, the locomotives-available and industry-availability pages, - the economic and special-condition pages, the `Port/Warehouse Cargos` page, and the later report - pages. The mid-editor ownership is materially clearer now too: the chairman-slot editor is the - `Players` page, the available-chairman editor is the `Player Pool` page, and the former unnamed - dual tri-state page now lines up with localized page text `997` `Building Density` plus help text - `1017` and the direct field captions `1642` `Starting Building Density Level:` and `1644` - `Building Density Growth:`. Both controls are now bounded as stored ordinal bytes `0/1/2` rather - than loose labels: the first three-choice control is the map-wide starting-density selector, with - its default middle state `1` matching the documented `100%` baseline from `1643`; the second is - the paired overall growth selector whose effects later appear in the city-growth side of the - simulation. `map_editor_city_region_panel_construct` and - `map_editor_city_region_panel_handle_message` own the city-or-region editing lane with rename and - copy-industry-data flows. That copy side is tighter now too: the handler first enters - `0x00420e00`, which rebuilds the selected region's profile collection `[region+0x37f]`, clones - the source region's live label-weight entries when a source region is present, and otherwise - reseeds a fixed default weight set through repeated `0x004206b0` calls. The no-source companion - `0x00420ed0` now makes that split explicit: it rebuilds the same subcollection and then picks one - of two fixed default label-weight sets based on region class dword `[region+0x23e]`, using one - all-`0.2f` family for nonzero-class regions and one class-`0` family that starts with `0.3f` - before continuing with repeated `0.2f` entries. The lower mutator - `0x004206b0` then linearly scans the selected region subcollection by profile label, creates a - new profile only when the copied weight is positive, removes an existing profile when the copied - weight is non-positive, updates `[entry+0x1e]` otherwise, and refreshes the region's derived - availability-summary bytes `[region+0x2f6/+0x2fa/+0x2fe]` through `0x00420410`; `map_editor_territory_panel_construct` and - the adjacent no-source companion `0x00420ed0` is tighter too: it rebuilds the same collection - root `[region+0x37f]` but then seeds one of two fixed default profile-label sets directly through - repeated `0x004206b0` calls, splitting by region class dword `[region+0x23e]`. Nonzero-class - regions take one all-`0.2f` default set, while class-0 regions take a different set that starts - with one `0.3f` weight before continuing with repeated `0.2f` entries. That makes `0x420ed0` - the true class-split default-profile companion to the source-cloning helper at `0x420e00`, - rather than just more of the same editor copy path. - `map_editor_territory_panel_construct` and - `map_editor_territory_panel_handle_message` own the territory rename and border-remap lane; - `map_editor_locomotive_availability_panel_construct` plus - `map_editor_locomotive_availability_panel_handle_message` now bound the locomotive policy page - over `0x006ada84`; `map_editor_industry_availability_panel_construct` plus - `map_editor_industry_availability_panel_handle_message` do the same for the industry candidate - pool at `0x0062b268`; and `map_editor_port_warehouse_cargo_panel_construct` plus - `map_editor_port_warehouse_cargo_panel_handle_message` now ground the recipe-book page that edits - port or warehouse cargo policies through twelve per-book state blocks at - `[0x006cec78+0x0fe7+index*0x4e1]`. Each book now has a shared maximum annual production float at - `book+0x3ed` and five fixed cargo-line entries starting at `book+0x3f1` with stride `0x30`; each - line is bounded as a mode dword, annual amount, a supplied-cargo token at `+0x08`, and a - demanded-cargo token at `+0x1c`. The constructor and handler now make those fields materially - tighter too: the row pair shown in `Supply Only` and `Production Demand->Supply` is the `+0x08` - supplied-cargo selector, the row pair shown in `Demand Only` and `Production Demand->Supply` is - the `+0x1c` demanded-cargo selector, and the single amount field at `+0x04` is labeled `Annual - Demand:` only in mode `1` but `Annual Supply:` in modes `2/3`. The stronger new runtime-side - result is now a full chain rather than only the importer: - `scenario_state_rebuild_port_warehouse_cargo_recipe_runtime_tables` first imports those same five - lines into one repeated array of identical `0xbc`-byte runtime descriptors with no row-index - special casing, and the candidate-side rebuild pass at - `structure_candidate_collection_rebuild_runtime_records_from_scenario_state` `0x00412d70` then - projects those descriptors into the live structure collection at `0x0062ba8c` before - `structure_candidate_rebuild_cargo_membership_and_scaled_rate_tables` `0x00411ee0` rebuilds the - per-cargo runtime summary tables. The current local file-side result is now tighter too: the - grounded recipe-book root at `0x0fe7` is preserved byte-for-byte across the checked map/save - scenario pairs, so the loader can safely treat the twelve `0x4e1`-byte books as preserved - scenario payload rather than a drifting save-only band. A conservative summary probe now only - reports per-book head signatures, raw cap dwords at `+0x3ed`, and five raw line summaries rooted - at `+0x3f1` so the file-side structure stays aligned with this grounded ownership. The - player-facing line modes remain `Disabled`, `Demand Only`, `Supply Only`, and - `Production Demand->Supply`, and the fourth mode is tighter now too: current wording around - `1674`, `1675`, and `504` plus the downstream scaling path says it is the - production-line mode governed by the shared annual production cap, where the entered annual amount - stays on the supply side while the demanded side becomes the normalized input branch. The - candidate-side accumulator pass reinforces that split by applying the shared production cap only - to the supply-half runtime branch and bypassing that scaling on the normalized demand half. The - lower gameplay side is tighter now too: `structure_candidate_query_cargo_runtime_summary_channels` - `0x00412650` is the first grounded consumer beneath that rebuild chain, because it lazily rebuilds - four per-cargo summary banks and returns one direct-supply channel, one cap-normalized supply - channel, one demand or input channel, and one scaled production-output subrow channel for a - requested cargo id. The internal indexing is tighter now too: the direct-supply lane indexes from - `[desc+0x1c]`, the demand or input lane uses that same resolved cargo id in the no-subrow branch, - and the scaled production-output lane indexes each subordinate row directly from - `[desc+0x44+row*0x1c]`, with no post-resolution failure guard between the importer writes and the - summary-bank updates. So the strongest current read is narrower than a full cargo-id decode: if - the imported low-16 marker rows fail the exact matcher at `0x0041e9f0`, the resulting `0` ids - will still hit the first summary-bank bucket inside `0x00412650`, but the semantic meaning of - cargo id `0` itself remains ungrounded. The sibling helper - `structure_candidate_supports_or_references_cargo_id` - `0x004129d0` then uses those same banks plus the cached cargo-membership arrays to answer whether - a live candidate materially references a cargo at all. One compare step tighter, the raw line - lanes now split cleanly by scenario family while still preserving map->save identity inside each - checked pair. `Alternate USA.gmp` and `Autosave.gms` match at the raw line-content level: books - `0..4` keep mixed line areas, their `line02` slots carry the recurring nonzero mode words - `0x00110000`, `0x000b0000`, `0x000b0000`, `0x00130000`, and `0x00180000`, and the same `line02` - slots also carry one recurring supplied token `0x000040a0`; the neighboring `line00/line01` - slots carry the same recurring demanded token lanes such as `0x00010000`, `0x72470000`, - `0x6f430000`, `0x694c0000`, and `0x694d0000`. `Southern Pacific.gmp` and `p.gms` also match at - the raw line-content level, but the same rooted line slots stay zero in the checked pair. - `Spanish Mainline.gmp` and `g.gms` again match at the raw line-content level yet carry a distinct - nonzero pattern: books `0..4` keep mixed line areas, line-level supplied tokens include - `0x00170000`, `0x00150000`, `0x00004040`, and `0x00004000`, demanded tokens include - `0x00010000`, `0x68430000`, and `0x6c410000`, and the later `line02` mode words stabilize at - `0x00070000` then `0x00010000`. So the loader can now safely treat these raw line lanes as - preserved scenario payload with family-specific signatures, even though the exact cargo-id and - mode-enum semantics still need separate grounding. One inference is tighter now too: when those - demanded-token words are zero in the low 16 bits and printable in the high 16 bits, the byte - order reads as short two-letter stems such as `Gr`, `Co`, `Li`, `Mi`, `Ch`, and `Al`, which fit - the current scenario cargo-name families `Grain`, `Corn`, `Livestock`, `Milk`, `Cheese`, and - `Alcohol` from `RT3.lng`; the runtime probe now exposes those only as probable ASCII stems, not - as fully grounded cargo-id decodes. The supplied-token side is now bounded as a separate layout - family rather than forced into that same stem model: the `Alternate USA` family uses one stable - low-16 marker `0x000040a0` only in `book00..04.line02`, the `Southern Pacific` family leaves the - supplied lanes zero in the checked pair, and the `Spanish Mainline` family splits between two - high-16 numeric tokens `0x00170000` and `0x00150000` in `book00/01.line01` plus the later low-16 - markers `0x00004040`, `0x00004000`, and `0x00004040` in `book02..04.line02`. The probe now - exposes those conservatively as token-layout classes `high16-ascii-stem`, `high16-numeric`, and - `low16-marker`, without claiming that the non-stem numeric or marker families are decoded yet. - One more structural layer is stable enough to name conservatively: the checked nonzero recipe - rows repeatedly fall into four line-signature classes. `Alternate USA` books `0..4` all expose - one `demand-numeric-entry` at `line00` (`0x00010000`), one `demand-stem-entry` at `line01` - (`Gr/Co/Li/Mi` stems), and one `supply-marker-entry` at `line02` (nonzero mode plus - `0x000040a0`). `Spanish Mainline` books `2..4` expose that same three-line pattern with - `Ch/Al` stems and the `0x00004040/0x00004000` marker family, while books `0/1` only expose the - earlier `supply-numeric-entry` form at `line01`. So the loader can now distinguish recurring row - roles such as demand-stem versus supply-marker without pretending the marker payloads themselves - are decoded. The importer-side branch map is tighter now too because local `objdump` over - `0x00435630` shows that only nonzero mode dwords materialize into `0xbc` runtime descriptors: - mode `0` lines are skipped entirely, mode `1` enters the demand-only branch, mode `3` enters the - dual demand-plus-supply branch, and every other nonzero mode falls into the supply-side branch. - In the checked corpus that means the recurring `demand-numeric-entry` and `demand-stem-entry` - rows in `Alternate USA` and `Spanish Mainline` are preserved scenario-side line records but do - not become live runtime descriptors, while the later `supply-marker-entry` rows are the ones that - actually reach the runtime import path. The runtime probe now exposes that directly as - `imports_to_runtime_descriptor` plus one conservative `runtime_import_branch_kind`. - The raw token windows beneath those branch labels are tighter now too. The checked mode-zero - demand rows preserve string-bearing windows at `line+0x1c`, and the current probe shows those - conservatively as prefixed ASCII previews such as `..Grain`, `..Corn`, `..Livestock`, and - `..Milk`; local `objdump` over `0x0041e9f0` then shows the importer feeding the corresponding - token buffer into an exact cargo-name matcher built over the live cargo collection at - `0x0062ba8c`. By contrast, the imported `supply-marker-entry` rows feed nonprintable windows such - as `.@...` from `line+0x08` through that same matcher, and the resolver path currently shows no - special-case decoding for those marker forms. So the strongest static read is now: the stem-like - demand rows preserve cargo-name text but are skipped because their mode is zero, while the - nonzero imported marker rows are the live descriptor inputs yet likely fail exact cargo-name - resolution unless another upstream transform exists. - The wrapper layer above that query no longer looks like a hiding place for special treatment - either. Local `objdump` now shows `0x00412960` simply summing the two supply-side floats returned - by `0x00412650`, while `0x004129a0` returns the single scaled production-output lane directly; - neither wrapper checks for cargo id `0` after the query returns. The broader world-side - accumulator at `0x0041e7be` is tighter in the same way: it calls `0x00412650`, requires all four - returned channels to be positive before continuing, and only then scales those four channel - values by one linked-instance count from `0x00413940` into caller-owned accumulators. So the - current strongest read remains structural rather than semantic: unresolved marker rows can still - propagate through the first bank bucket, but the first place that meaning matters is a normal - positivity-gated cargo-channel consumer, not a dedicated null-cargo branch. - The caller side is narrower than before too. The steady-state site bitset owner - `placed_structure_rebuild_candidate_cargo_service_bitsets` `0x0042c690` starts its inner cargo - loop at id `1` and only walks upward through the current live cargo count, so it never - intentionally queries cargo id `0`. The broader placed-structure sweep around `0x00452e60` - tightens the same boundary from above: when the requested cargo id is nonzero it resolves the - backing candidate and enters `structure_candidate_supports_or_references_cargo_id`, but when the - requested id is exactly `0` it skips that cargo-reference helper entirely and falls through to a - different linked-site or station-or-transit gate. Current local `objdump` now shows that bypass - first requiring one subtype latch through the placed-structure vtable `+0x70`, then resolving the - linked site id at `[site+0x2a8]` through the placed-structure collection `0x006cec20`, and then - forwarding that linked peer into the narrower predicate at `0x0047fd50`. That narrower helper is - tighter than before too: it resolves the linked peer's backing candidate through the peer site id - at `[peer+0x04]`, reads candidate class byte `[candidate+0x8c]`, and returns true only for the - first three class values `0/1/2` while rejecting `3/4` and anything above `4`. So current local - callers treat cargo id `0` as a nonstandard request bound to one linked-site reachability or - classification side path, not one ordinary cargo lane they routinely probe. - The vtable-`+0x70` latch itself is bounded a bit better now too. It still lacks a direct field - decode, but every local callsite we checked around `0x0040d230`, `0x0040dba0`, `0x0040dbf0`, and - `0x0040f670` uses that slot only as the precondition for touching `[site+0x2a8]` and the - neighboring linked-site helpers `0x0047dda0`, `0x0047fd50`, and `0x004138b0`. That makes the - safest current read a linked-site-bearing or linked-site-capable latch, strongly aligned with the - subtype-`1` construction lane that is the only grounded writer of `[site+0x2a8]`, rather than a - broad cargo or route-style predicate. - The neighboring maintenance pair tightens that linked-site read further. Local `objdump` now - shows `0x0040dba0` and `0x0040dbf0` as complementary tiny helpers that each require the same - vtable-`+0x70` latch, resolve optional linked peer id `[site+0x2a8]` through `0x006cec20`, - forward that linked peer (or null) into `0x0047dda0`, and then mirror opposite values into local - byte `[site+0x42]` (`0` for `0x0040dba0`, `1` for `0x0040dbf0`). The route-entry side beneath - them is tighter too: `0x0047dda0` reads route-entry anchor id `[peer+0x08]`, resolves that anchor - through `0x006cfca8`, and only dispatches one of two route-entry vtable calls when - `0x0048a090(1)` reports that all three anchor-slot dwords `[entry+0x206]`, `[entry+0x20a]`, and - `[entry+0x20e]` are still `-1`. So the strongest current read is no longer just "linked-site - capable" in the abstract: this latch consistently fronts the local linked-peer class gate - `0x0047fd50`, the paired `[site+0x42]` route-entry state toggles, and the later linked-peer - collection sweep `0x004138b0`, which keeps the `cargo id 0` bypass path firmly on the - linked-site route-anchor or classification side rather than on an ordinary cargo lane. - One smaller ownership boundary is tighter too: byte `[site+0x42]` is not private scratch owned - only by that pair. Local `objdump` shows tiny direct setters at `0x0040cbc0` and `0x0040cbd0` - plus a raw getter at `0x0040cbf0`, so the `0x0040dba0/0x0040dbf0` pair is writing one shared - placed-structure state byte rather than inventing a route-entry-only scratch lane. One caution - is tighter now too: there are later mode-gated reads at other addresses that also touch a - `+0x42` byte on their own object layouts, but current local evidence does not yet prove those are - the same placed-structure owner family, so the safest current note keeps only the immediate - `0x0040cbc0/0x0040cbd0/0x0040cbf0/0x0040dba0/0x0040dbf0` cluster grounded together. - The vtable side sharpens that split too. A local `.rdata` scan shows `0x0040dba0` and - `0x0040dbf0` each appearing exactly once, together with `0x0040cbf0`, in one method table rooted - at `0x005c8c50`; the constructor chain is tighter now too, because `0x0040c950` installs that - same table as one concrete placed-structure specialization above the common base table - `0x005cb4c0`, while `0x0040c970` tears the same specialization back down to the base before the - temporary object is freed. By contrast the raw set or get trio - `0x0040cbc0/0x0040cbd0/0x0040cbf0` also appears in several sibling tables such as `0x005c9750` - and `0x005dd1f0`. So the strongest current structural read is that byte `[site+0x42]` belongs - to one broader placed-structure virtual interface, while the linked-peer route-entry toggles are - one specialization-specific override pair inside that family rather than generic setters used by - every sibling. - One negative boundary is tighter now too: the - raw token words in this recipe block do not look like the already grounded shell-side - `AnyCargo/AnyFreight/AnyExpress` selector-table ids from `0x00621e04/0x00621e10`, so the current - best read is that these on-disk line tokens are not just copied UI selector ordinals or the same - small express-side id family in another wrapper. One broader collection pass also now ties - the editor rule side back into runtime filtering: - `structure_candidate_collection_refresh_cargo_economy_filter_flags` `0x0041eac0` rebuilds - per-candidate flag `[candidate+0x56]` across the live structure collection, and current grounded - callers show it rerunning directly off the runtime cargo-economy latch at `[0x006cec74+0x25f]`, - which aligns this lane with the editor's `Disable Cargo Economy` special condition rather than - leaving it as a purely editor-owned recipe page. The first common live gate beneath that filter is - now bounded too: `structure_candidate_is_enabled_for_current_year` `0x0041e220` is the shared - year-and-filter check used by the collection refresh and later candidate-selection branches, while - `structure_candidate_rebuild_local_service_metrics` `0x0041e2b0` is a setup-side local service - scorer that already consumes the same enabled candidate records through world-grid sampling. One - steady-state world-side consumer is now grounded as well: - `placed_structure_rebuild_candidate_cargo_service_bitsets` `0x0042c690` walks linked placed - structures, filters live category-`2` candidates through - `structure_candidate_is_enabled_for_current_year`, and compacts the direct and scaled supply-side - channels from `0x00412960` and `0x004129a0` into per-cargo bitsets on the placed-structure record. - The next site-side owner layer is tighter now too: - `placed_structure_refresh_linked_candidate_flag4` `0x0042c8f0` refreshes the sibling state bit at - `[site+0x0e6]`, `placed_structure_refresh_candidate_service_state` `0x0042cdf0` ties that flag - refresh to the cargo-service bitset rebuild, - `placed_structure_rebuild_candidate_local_service_tables` `0x0042ce00` then performs the heavier - per-site candidate score rebuild over the aligned float and word tables at `[site+0x107]`, - `[site+0x02]`, and `[site+0x6c]`, and `placed_structure_refresh_local_service_score_bundle` - `0x0042d580` is now the local wrapper that chains that rebuild into the neighboring post-passes - before the world-grid owner continues. Those post-passes are tighter too: - `placed_structure_apply_route_linked_service_caps` `0x0042cc50` is the first route-backed cap pass - over the rebuilt local tables, - `placed_structure_redistribute_local_service_pressure_from_neighbors` `0x0042c1b0` is the - neighboring-site redistribution pass, and `placed_structure_clamp_candidate_service_age_table` - `0x0042cb30` is the final recent-service clamp over the primary per-candidate word table. Above - that refresh lane, `placed_structure_query_candidate_local_service_metrics` `0x0047e240` is the - first higher-level query, `placed_structure_count_candidates_with_local_service_metrics` - `0x0047e330` counts how many candidates currently produce that query, - `placed_structure_get_nth_candidate_id_with_local_service_metrics` `0x0047e620` is the ordinal - selector over that same visible candidate family, - `placed_structure_query_cached_express_service_class_score` `0x0047e390` caches one parallel class - score for the express family now strongly aligned with `Passengers`, `Mail`, and `Troops`, - `placed_structure_refresh_candidate_local_service_comparison_cache_against_peer_site` - `0x0047eb90` rebuilds one peer-site comparison cache over the same local-service inputs, and - `placed_structure_select_best_candidate_id_by_local_service_score` `0x0047f910` is the best-hit - selector above the direct and directional local-service query pair. Those site-side scores now - have grounded shell read-side consumers too: - `shell_station_detail_format_freight_and_express_summary` `0x00506be0` formats the visible - `Freight: %1` and `Express: %1` lines in `StationDetail.win`, and the same station-detail family - now has a deeper candidate-service lane: - `shell_station_detail_set_active_candidate_service_preview` `0x00504ae0` stores the active - `(station id, candidate id)` pair for the world-side preview scan, - `shell_station_detail_clear_active_candidate_service_preview` `0x00504a90` tears that pair back - down, `shell_station_detail_update_candidate_service_entry` `0x00504ba0` is the shell-side entry - updater above that preview pair, `shell_station_detail_format_candidate_local_service_summary` - `0x00504bea` uses `placed_structure_query_candidate_local_service_metrics` together with localized - ids `681`, `682`, and `2813` to build the visible candidate service text, - `shell_station_detail_build_to_from_haul_summary_widget` `0x00505150` now grounds the paired `To` - and `From` hauled-traffic strip widgets, `shell_station_detail_present_to_from_haul_stats_popup` - `0x00504770` owns their click-through annual and lifetime `hauled TO/FROM this station` popup, - `shell_station_detail_refresh_nearby_structure_jump_rows` `0x00505470` owns the five-row - nearby-structure jump lane, and `shell_station_detail_refresh_candidate_service_rows` `0x00505760` - is now the larger row-list owner that enumerates active candidate-service entries and wires - `shell_station_detail_update_candidate_service_entry` into the per-row click path. - `shell_station_list_format_freight_and_express_availability_summary` `0x00506e50` feeds the - station-list summary `%1 has %2 freight loads and %3 express loads available for hauling...`, and - the paired modifier helper `shell_station_list_handle_center_or_rename_action` `0x00506d50` owns - the visible Shift-center and Ctrl-rename row actions. The report side is clearer as well: - `0x004d3060` is the dedicated `Stats - Trees` constructor over `map_editor_tree_stats_report`, - `0x004d3080` is the actual `General Validation` constructor over - `map_editor_general_validation_report`, and the same page table also now grounds `Stats - Cargo`, - `Stats - City/Region`, `Stats - City Count`, `Event Variable Values`, and the neighboring - event-validation page. The remaining open editor edge is therefore mostly the deeper gameplay - meaning of those site-side service scores and flag bits, not page ownership. - -- Station-detail overlay: the shell-side candidate preview pair now has a grounded world consumer - too. `world_render_station_candidate_service_map_overlay` at `0x0043f640` reads the active - `(station id, candidate id)` pair from `0x005ee4fc` and `0x005ee500`, scans the placed-structure - collection, and then splits the legend by candidate mode. When the active candidate carries a - nonzero route-style byte at `[candidate+0x46]`, the overlay uses the heavier helper - `placed_structure_query_candidate_directional_route_overlay_summary` at `0x0047e690` in both - directions between the preview station and each scanned site and formats the resulting directional - rows as `3874` `Coming To %1` and `3875` `Going From %1`. When that byte is zero, the same overlay - falls back to the direct local-service path through - `placed_structure_query_candidate_local_service_metrics` and formats the two legend rows instead - as `3876` `Current Supply @ < %1` and `3877` `Current Demand @ > %1`. Empty directional lanes - collapse to `3878` `--None--`, and one title lane falls back to literal `All`. Current disassembly - no longer supports treating `3872` `Already Connected by Another Company` or `3873` `Not - Connected` as direct overlay-body emits. -- Station-detail overlay, corrected boundary: the neighboring connection-state note pair now appears - to live in a city connection-bonus label formatter, not in `0x0043f640`. That formatter is now - bounded as `city_site_format_connection_bonus_status_label` at `0x004207d0`: it directly chooses - localized ids `3868` through `3873` after consulting the reusable city-peer scan - `city_connection_bonus_exists_matching_peer_site` at `0x00420030`. Separately, `3879` `Out of - Sync` is grounded under the multiplayer preview dataset path instead: - `multiplayer_preview_dataset_service_launch_state_and_warn_out_of_sync` at `0x0046b780` checks - global `0x006cd91c`, raises the `Out of Sync` shell status through `0x5386e0`, and then continues - through the wider multiplayer preview launch-state service. So the station-detail overlay - currently owns only the `Coming To`, `Going From`, `Current Supply`, `Current Demand`, `--None--`, - and `All` legend lanes. -- Station-detail overlay, ownership side: one reusable site helper is grounded now too. - `placed_structure_query_linked_company_id` at `0x0047efe0` resolves the current placed structure's - linked instance through `0x0062b26c` and returns its company id from `[instance+0x276]`; the - adjacent city bonus formatter at `0x004207d0` compares that id against the active company selector - before choosing whether a scanned site should carry `3871` `Connected By Another Company` or - `3872` `Already Connected by Another Company`. The larger caller boundary is no longer open - either: the first bounded announcement owner above this formatter family is now - `company_evaluate_and_publish_city_connection_bonus_news` at `0x00406050`, which re-enters the - peer-route candidate builder at `0x004046a0` and later publishes one of the localized - city-connection bonus news strings `2888`, `2890`, or `2921` through the shell news path. -- Station-detail overlay, peer-selector side: the city bonus formatter no longer depends only on - boolean peer existence. The companion helper - `city_connection_bonus_select_first_matching_peer_site` at `0x00420280` is now grounded as the - first-match selector paired with `city_connection_bonus_exists_matching_peer_site`: it walks the - same city-peer candidate set, applies the same site-class table plus the narrower - station-or-transit and linked-instance class-byte flags, and returns one representative matching - peer site id instead of a boolean. `city_site_format_connection_bonus_status_label` reuses that - selector after the note checks so it can recover one linked company context from the selected - peer. The remaining open edge here is therefore above this formatter family, not inside the - peer-scan pair itself. -- Station-detail overlay, caller side: the reusable bridge between the status formatter and the - company news lane is now bounded too. `city_connection_bonus_build_peer_route_candidate` at - `0x004046a0` reuses `city_connection_bonus_select_first_matching_peer_site` with both selector - flags forced on, samples the selected peer's derived coordinates through `0x0047df30` and - `0x0047df50`, and then either tries the shared heavy builder - `city_connection_try_build_route_with_optional_direct_site_placement` `0x00402cb0` or falls - back to the smaller wrapper `city_connection_bonus_try_compact_route_builder_from_region_entry` - `0x00404640` before handing the result back to the company-side announcement sweep at - `0x00406050`. The score side of that announcement lane is tighter now as well: - `city_compute_connection_bonus_candidate_weight` at `0x004010f0` provides the per-city opportunity - weight, `company_query_min_linked_site_distance_to_xy` at `0x00405920` provides the nearest - linked-site distance term, `company_count_linked_transit_sites` at `0x00426590` provides one of - the company-side caps, `company_compute_connection_bonus_value_ladder` at `0x00425320` supplies - the bounded company-side value scalar, and - `company_compute_prime_rate_from_issue39_scenario_baseline` at `0x00424580` now bounds the - shared prime-rate-side helper that this lane reuses beside the raw issue-`0x39` total, - `scenario_state_sum_issue_opinion_terms_raw` at `0x00436710` now bounds the raw additive - issue-total helper beneath that term, and `company_connection_bonus_lane_is_unlocked` at - `0x00427590` is the small boolean gate above the ladder. Wider governance and CompanyDetail xrefs - now tighten slot `0x2b` into the rolling net-profits lane reused by annual finance checks and a - per-share/history formatter, while the report-history descriptor table now aligns raw slot `0x09` - with the Income Statement fuel-cost lane surfaced by tooltip `1309`. The wider result now reads - more like recent net profits minus recent fuel burden than a governance-pressure term. That now - also sharpens the annual finance lane at `0x00401c50`: the first bankruptcy branch reads as - sustained cash-and-debt stress over recent profits and fuel burden, the later fallback branch as - a deeper `-300000` cash / three bad years cleanup trigger, and the later stock-issue branch reads - as a price-to-book-versus-coupon approval ladder rather than a generic support vote. The tail is - cleaner now too: it compares total retired versus newly issued principal to choose the `2882..2886` - debt headline family, then publishes `2887` separately from the accumulated repurchased-share - count. The sibling news owner above the same - city-pair route family is bounded now too: - `simulation_try_select_and_publish_company_start_or_city_connection_news` `0x00404ce0` - filters and scores candidate city entries, re-enters the same shared heavy builder through - `city_connection_try_build_route_between_region_entry_pair` `0x00404c60` for the dense pair - sweep and the final retry, and then publishes `2889` `%1 has started a new company - the %2` - or `2890` `%1 has connected %2 to %3.` through the shell news path. The remaining open edge on - this branch is therefore narrower now: it is mostly whether `0x39` should be read as the - narrower city-connection public-opinion lane or as part of a broader management-attitude family, - not the ownership of the connection-bonus formatter, peer-route candidate path, or company news - gate. -- Station-detail overlay, route-list side: the neighboring helper - `placed_structure_append_unique_route_entry` at `0x0047f010` is now grounded as the - append-if-missing builder for the six-byte route-entry list rooted at `[site+0x462]` and - `[site+0x466]`. That matters here because the directional overlay query at `0x0047e690` consumes - the same list, so the remaining uncertainty is no longer list ownership. It is down to the exact - semantics of each entry's `u32` payload. +Detailed section: +[input-save-load-and-simulation.md](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md) ## Next Mapping Passes -- Resolve the owner-side callback roles behind the validated GameSpy packet branches, especially - `[route+0x9c]`, `[route+0xa0]`, `[route+0xa4]`, and `[route+0xd4]`. -- Determine whether any later world-mode branch beneath the frame owner bypasses the shell - controller input path for non-cursor gameplay input, since the current grounded overlay and cursor - helpers still reuse `0x006d4018`. -- Keep detailed pending-template or transport work scoped to the specific atlas edges that remain - unresolved. +Detailed section: +[next-mapping-passes.md](/home/jan/projects/rrt/docs/control-loop-atlas/next-mapping-passes.md) diff --git a/docs/control-loop-atlas/README.md b/docs/control-loop-atlas/README.md new file mode 100644 index 0000000..e318814 --- /dev/null +++ b/docs/control-loop-atlas/README.md @@ -0,0 +1,18 @@ +# Control-Loop Atlas + +This directory holds the canonical atlas narrative split by the original top-level sections from +[docs/control-loop-atlas.md](/home/jan/projects/rrt/docs/control-loop-atlas.md). + +Use the compatibility index when an existing link only knows the old single-file path. Use these +section files when adding or reviewing grounded narrative content. + +## Sections + +- [crt-and-process-startup.md](/home/jan/projects/rrt/docs/control-loop-atlas/crt-and-process-startup.md) +- [bootstrap-and-shell-service-bring-up.md](/home/jan/projects/rrt/docs/control-loop-atlas/bootstrap-and-shell-service-bring-up.md) +- [shell-ui-command-and-deferred-work-flow.md](/home/jan/projects/rrt/docs/control-loop-atlas/shell-ui-command-and-deferred-work-flow.md) +- [presentation-overlay-and-frame-timing.md](/home/jan/projects/rrt/docs/control-loop-atlas/presentation-overlay-and-frame-timing.md) +- [map-and-scenario-content-load.md](/home/jan/projects/rrt/docs/control-loop-atlas/map-and-scenario-content-load.md) +- [multiplayer-session-and-transport-flow.md](/home/jan/projects/rrt/docs/control-loop-atlas/multiplayer-session-and-transport-flow.md) +- [input-save-load-and-simulation.md](/home/jan/projects/rrt/docs/control-loop-atlas/input-save-load-and-simulation.md) +- [next-mapping-passes.md](/home/jan/projects/rrt/docs/control-loop-atlas/next-mapping-passes.md) diff --git a/docs/control-loop-atlas/bootstrap-and-shell-service-bring-up.md b/docs/control-loop-atlas/bootstrap-and-shell-service-bring-up.md new file mode 100644 index 0000000..e1438be --- /dev/null +++ b/docs/control-loop-atlas/bootstrap-and-shell-service-bring-up.md @@ -0,0 +1,24 @@ +## Bootstrap and Shell Service Bring-Up + +- Roots: `app_bootstrap_main` at `0x00484440`, `bootstrap_init_shell_window_services` at + `0x004840e0`, and `shell_install_global_controller` at `0x0051ff90`. +- Trigger/Cadence: one-time bootstrap handoff immediately after CRT completion. +- Key Dispatchers: `app_bootstrap_main`, `bootstrap_init_shell_window_services`, + `shell_install_global_controller`, `shell_service_pump_iteration`, graphics config load or + default-init helpers, runtime capability probes, and early shell service initializers under the + `0x004610..0x0053f0..` branch. +- State Anchors: global shell controller pointer `0x006d4024`, sibling display/runtime globals under + `0x006d402c` and `0x006d4030`, and host capability flags gathered by + `bootstrap_probe_system_profile`. +- Subsystem Handoffs: after the global shell controller has been installed the bootstrap path enters + the repeating `shell_service_pump_iteration` loop, which services shell-state work and hands each + iteration down into the controller frame path; when the shell lifetime ends this same bootstrap + path tears the shell bundle down and returns to `app_bootstrap_main`. +- Evidence: `startup-call-chain.md`, function-map rows for `app_bootstrap_main`, + `bootstrap_init_shell_window_services`, `shell_install_global_controller`, + `shell_service_pump_iteration`, `shell_load_graphics_config_or_init_defaults`, + `shell_reset_display_runtime_defaults`, and related graphics setup helpers. +- Open Questions: whether gameplay or in-engine world stepping later escapes this bootstrap-owned + shell loop entirely, or whether gameplay entry still rendezvous with the same outer coordinator + before the shell bundle is destroyed. + diff --git a/docs/control-loop-atlas/crt-and-process-startup.md b/docs/control-loop-atlas/crt-and-process-startup.md new file mode 100644 index 0000000..84a382d --- /dev/null +++ b/docs/control-loop-atlas/crt-and-process-startup.md @@ -0,0 +1,17 @@ +## CRT and Process Startup + +- Roots: `entry` at `0x005a313b`, CRT helpers in the `0x005a2d..0x005ad4..` range, and + `app_bootstrap_main` at `0x00484440`. +- Trigger/Cadence: single process startup path before shell or engine services exist. +- Key Dispatchers: `startup_init_tls_state`, `startup_init_file_handle_table`, + `startup_run_init_callback_table`, `__setenvp`, `startup_build_argv`, + `___crtGetEnvironmentStringsA`, then `app_bootstrap_main`. +- State Anchors: CRT heap and file-handle tables; process environment and argv storage. +- Subsystem Handoffs: exits the generic CRT path at `app_bootstrap_main`, which becomes the first + RT3-owned coordinator. +- Evidence: `artifacts/exports/rt3-1.06/startup-call-chain.md`, + `artifacts/exports/rt3-1.06/function-map.csv`. +- Open Questions: exact ownership boundary between compiler CRT shims and the first game-owned + bootstrap helper; whether any nontrivial startup callbacks seed game globals before + `app_bootstrap_main`. + diff --git a/docs/control-loop-atlas/input-save-load-and-simulation.md b/docs/control-loop-atlas/input-save-load-and-simulation.md new file mode 100644 index 0000000..7797edd --- /dev/null +++ b/docs/control-loop-atlas/input-save-load-and-simulation.md @@ -0,0 +1,4117 @@ +## Input, Save/Load, and Simulation + +### Runtime Roots and Cadence + +- Roots: the shell controller window-message ingress `shell_controller_window_message_dispatch` at + `0x0054e3a0`, the shell input-state object initialized at `0x006d4018` through + `shell_input_state_init` `0x0054e710`, the saved-world restore path + `world_load_saved_runtime_state_bundle` at `0x00446d40`, the live-world save path + `world_runtime_serialize_smp_bundle` at `0x00446240`, `world_entry_transition_and_runtime_bringup` + at `0x00443a50`, the frame-owned cadence `simulation_frame_accumulate_and_step_world` at + `0x00439140`, the recurring `GameMessage.win` service branch through + `game_message_window_service_if_present` `0x004e0720`, the world-facing `GameUppermost.win` + overlay branch ensured by `shell_ensure_game_uppermost_window` `0x004e0e40` and serviced through + `game_uppermost_window_service_world_hotspot_band` `0x004e0780`, and the lower step family rooted + at `simulation_advance_to_target_calendar_point` `0x0040ab50` with periodic branches through + `simulation_service_periodic_boundary_work` `0x0040a590`. +- Trigger/Cadence: shell-side input is event-driven by controller-window `WM_*` traffic while save + or load work is triggered either directly from shell commands or through the `fileopt.win` branch + flags into the `.smp` runtime-state family; post-bring-up world service becomes recurring once a + world root exists at `0x0062c120`, but the current grounded top-level cadence still remains the + shell-owned `shell_service_pump_iteration` path, which calls + `simulation_frame_accumulate_and_step_world` directly and lets it accumulate elapsed wall-clock + time into one or more simulation-step quanta. A second ingress is now bounded too: + `simulation_run_chunked_fast_forward_burst` at `0x00437b20` repeatedly calls the same lower + stepper `simulation_advance_to_target_calendar_point`, but current grounded callers put that + helper inside the larger post-load generation pipeline `world_run_post_load_generation_pipeline` + at `0x004384d0` under the `Seeding Economy...` phase rather than under the ordinary player-facing + speed buttons. That setup pipeline is now clearer at the progress-banner level too: on the fuller + setup path it first runs one preliminary named-candidate availability prepass through `0x00437743` + before any visible progress banner is posted. One startup-side selector edge is tighter now too: + `shell_active_mode_run_profile_startup_and_load_dispatch` `0x00438890` reaches an early + selector-`2` branch at `0x00438a66..0x00438c00` that refreshes one support-family type-`7` + record from setup path buffer `0x006d1370` through `0x0053d130`, strips the basename extension + into a local label buffer, briefly drops the nested mouse-cursor hold through `0x0053f310`, + builds three progress-text payloads, and re-enters the hold through `0x0053f2f0` before the + common world-root bring-up continues. After that, localized id `318` + `Computing Transportation and Pricing...` stays visible while the pipeline runs + `world_compute_transport_and_pricing_grid` `0x0044fb70`, the early collection-owned staging pass + `world_rebuild_secondary_raster_derived_surface_and_companion_planes_in_rect` `0x0044e940`, + `world_setup_building_collection_phase` `0x0041ea50`, and the conditional region pair + `world_region_collection_seed_default_regions` `0x00421b60` plus + `world_region_collection_refresh_neighbor_and_profile_bands` `0x00420f30`. One save-load-side + status-stack strip is now tighter too: `0x004422d0/0x00442330` push and pop the same four shell + dwords `[0x006cec74+0x140/+0x13c/+0x138/+0x144]` plus startup byte `[0x006cec78+0x4c74]` + through the local stack `0x0062be90` with depth `0x0062bedc`, and the paired wrappers + `0x004423a0/0x004423d0` bracket that same band while also servicing the live TrackLay.win and + StationPlace.win tool objects through `0x0050e070`, `0x00507a50`, `0x0050a530`, and + `0x0050e1e0`. The live `.smp` serializer uses the higher pair, while `world_entry_transition_and_runtime_bringup` + `0x00443a50` and `world_load_saved_runtime_state_bundle` `0x00446d40` also use the raw + push/pop pair directly around their heavier bundle and status spans. + `world_region_border_overlay_rebuild` `0x004882e0`. The transport/pricing side is tighter now + too: `0x0044fb70` first routes one null-build path through the preview ensure wrapper + `0x0044faf0`, whose deeper worker `0x0044f840` allocates a default target through + `0x00534930`, seeds five palette entries through `0x0051de10`, maps each target pixel back into + the live secondary raster through `0x00533970/0x00533980`, uses the low-3-bit class split plus a + local `+/-4` neighborhood and `0x0051db80` to choose the preview color, and only then re-enters + `0x0044e940` on the full rectangle. The later `322` side is tighter now too: the top owner + `0x0044d410` rejects while generation counter `[world+0x2205]` is live or when `0x00449e90` + cannot supply a surviving work rect, then forwards that rect into `0x005374d0`, `0x00533e70`, + and `0x00537010`, notifies the shell owner at `0x0062be68`, and refreshes neighboring region or + manager companions through `0x00421f50`, `0x00461770`, and `0x00415340`. `0x00421f50` itself is + now bounded as the narrow class-0 side of that refresh: it scans the live region collection for + class-0 records whose normalized coordinates fall inside the caller-supplied float rectangle and + republishes each surviving region's current-position triplet through `0x00455a70(0)`. The local + companion-float strip under that same owner is tighter now too: `0x0044d4e0` and `0x0044d6e0` + are sibling five-pass cross-neighbor relaxers over `[world+0x1605]`; both clamp the caller + rectangle, average the four cardinal neighbors, subtract the current sample, scale the delta by + one fixed coefficient and caller gain, and then feed the surviving rectangle back into + `0x0044d410`. The first helper only checks raster bit `0x01` in `[world+0x2135]`, while the + second adds the tighter acceptance gate `0x004499c0` and can skip the final `0x0044d410` tail + when its caller disables that refresh. Their center-biased sibling `0x0044d880` is now bounded + too: it seeds one baseline from the current center sample when its caller gain is positive, + expands one square neighborhood by radius, and raises surrounding cells toward that baseline + through the same `0x0051dc00` falloff model before tailing into `0x0044d410`. The local + peak-oriented sibling `0x0044da70` then raises one clamped square neighborhood by quantized + local maxima and on its optional branch also consults `0x00534f00` before keeping the larger + peak. So the `0x0044d4e0/0x0044d6e0/0x0044d880/0x0044da70` band now reads as the local + companion-float refinement layer immediately beneath the shared `Calculating Heights...` owner + rather than a set of unrelated scalar writes. The default-region side is tighter too: + one earlier class-0-only helper `0x0041fb00` now sits directly under that same family too: + it skips nonzero `[region+0x23e]` records, rounds the region center through + `0x00455800/0x00455810/0x005a10d0`, stamps one orientation-dependent local secondary-overlay + pattern through `0x00534e10` plus `0x004497a0`, and then runs one bounded scored refinement pass + through `0x0051db80`, `0x00534040`, `0x005340a0`, `0x00534100`, and `0x00533fe0`. The finalizer + `0x00421730` then clears the per-cell region word at `[world+0x212d] + cell*4 + 1` across the + full live world raster, seeds each live region's cached bounds fields, and repopulates that same + raster by writing the nearest class-0 region id `[region+0x23a]` into empty or weaker cell slots + from one bounded center-and-radius sweep. The region-profile side is tighter too: `0x0041f940` + counts only the current subcollection entries whose backing + candidates pass `0x0041f998`, and that smaller predicate now has one real content split instead + of staying anonymous. Candidates whose subtype byte is not `2` pass immediately, while subtype-2 + candidates only pass when either availability word `[candidate+0xba]` or runtime recipe latch + `[candidate+0x7ac]` is nonzero; `0x00412af0/0x00412b70` now ground the lookup step beneath both + counters as a casefolded profile-label-to-candidate resolver over the global candidate pool + `0x0062b268`; and the stricter year-filtered counter `0x0041f9b0` then stacks the subtype and + `[candidate+0x26] <= max_year` gates on top of that same availability test. Two adjacent + collection helpers are grounded now too. `0x0041fa30` linearly scans the same region profile + collection `[region+0x37f]`, compares labels through `0x005a57cf`, and returns profile-weight + float `[entry+0x1e]` from the first casefolded match or the shared zero float when none match; + `0x0041fac0` resolves one 1-based ordinal out of that same collection and copies both the + matched profile label and weight `[entry+0x1e]` to caller-owned outputs. Those reads line up with + the editor copy-industry mutator `0x004206b0`, which already treats `[entry+0x1e]` as the live + editable profile-weight lane. That border + pass is now tighter too: the + outer owner refreshes the companion region set `0x006cfc9c` through the reset-and-assign wrapper + `0x00487650` above the heavier record initializer `0x00487540`, then re-enters `0x004881b0` to + refresh the raw per-region cell-count band from the live world raster, and the inner emitter + `0x00487de0` clears prior chunked segment queues through `0x00533cf0`, scans the live region + raster, and appends fresh border-segment records through `0x00536ea0`. The lower presentation + helper strip under the same owner is now explicit too: `0x00533970/0x00533980` query the cached + world-grid X/Y maxima, `0x00533990` stores the secondary-overlay shift field `[world+0x15e1]`, + `0x005339a0` builds one plane equation from three XYZ points, and `0x00533a30` uses the same + three-point patch to solve one sampled height at caller-supplied `(x,z)`, + `0x00533ae0/0x00533af0/0x00533b00` expose the secondary-raster and companion byte-raster roots, + and `0x00533b20/0x00533b30/0x00533b70/0x00533b90` expose the normalized coordinate, strip-offset, + and sample-triplet tables used by shell-side overlay staging. The adjacent queue side is tighter + now too: `0x00533bc0/0x00533bd0/0x00533be0` are the direct append, remove, and root getters for + shell queue `[this+0x166d]`; `0x00533bf0/0x00533c20` are the cell-addressed attach/detach + helpers over nearby-presentation table `[this+0x1671]`; `0x00533c50/0x00533c70/0x00533ca0` do + the same for the region-border overlay chunk table `[this+0x1679]`; and + `0x00533dd0/0x00533e00` are the matching geographic-label cell-table attach/detach wrappers over + `[this+0x1675]`. The geographic-label text side is tighter now too: beneath + `shell_emit_geographic_label_text_span` `0x0053a960`, the support strip `0x0053b090`, + `0x0053b390`, `0x0053b590`, and `0x0053b5c0` now reads as one banked fixed-record loader and + keyed lookup family with a small recent-query cache plus a string-hash helper. The static load + loop at `0x0053ce09` seeds those banks from the pointer table rooted at `0x00624e48`, while the + lookup core partitions rows by `key & 0x1f` into `32` per-bank buckets and keeps a `10`-entry + recent-query cache rooted at `[this+0x4290c]`. The adjacent stream and staging side is bounded + too: `0x0053b630/0x0053b690/0x0053b6f0/0x0053b7c0/0x0053b830` now read as the current-entry + ordinal resolver, current-stream close/open helpers, and the shared byte-read strip, while + `0x0053b850/0x0053b8d0/0x0053b920/0x0053b970` own the local `13`-byte staging-table growth, + type-`7` service passes, and bucket-chain reset. The next owner layer is tighter now too: + `0x0053b9e0` is the broader `Pack System Leak Count : %1` report-and-reset pass, releasing the + four owned report-slot roots at `[this+0x429b0..+0x429bc]` plus sibling global `0x00ccba50`, + formatting staging-row fields through `0x0051b700`, publishing them through callback slot + `0x005c8078`, then tearing the staging slab and all per-bank handles back down. The keyed query + side now extends cleanly beyond raw lookup: `0x0053bd40` seeks the selected-or-current payload + stream and returns the handle, `0x0053be10` resolves or lazily opens one keyed typed auxiliary + object including a descriptor rooted at `data\\Other\\AirplaneTypes.txt`, `0x0053c930` is the + composite-string lookup wrapper, and `0x0053c9c0` is the matching payload-length resolver. The + local row side is now first-class too: `0x0053bf60`, `0x0053c000`, and `0x0053c070` release, + drop references on, and acquire-or-create refcounted staging rows with typed payload roots at + `[row+0x09]`, while `0x0053c900` resets the adjacent stream-plus-recent-query-cache strip. + `0x0053ca20/0x0053ca90` now bound the current-selection push/pop frame stack at `[this+0x20428]`, + and `0x0053cb10` is the small two-`u32` plus optional heap-blob reader sitting directly on top + of the shared byte-read helper. The broader bootstrap owner is tighter too: `0x0053cb60` zeroes + the whole family, allocates the four owned report slots, walks the static root-pointer table + `0x00624e14..0x00624e48`, loads banks through `0x0053b090`, and then routes selected keys such + as `companyLogo`, `portrait`, and `trainSkin` back through the typed-object strip into those + report slots. The nearby wrappers `0x0053d0f0/0x0053d110` are just the string-keyed type-`1` + and type-`6` staging-row acquire helpers above `0x0053c070`. The adjacent `0x0053d130` is + tighter now too: it strips one caller path to the final basename, derives a second stem copy + through `0x0051d8a0`, gates on `support_query_path_is_openable_for_read` `0x0051e430`, and only + then refreshes one type-`7` staging row through `0x0053c710` before resetting owner dword + `[this+0x427b0] = -1`. Immediately after that, the local + utility strip `0x0053d1d0..0x0053d470` now resolves as one scored binary-heap plus scored-node + queue family: `0x0053d1d0/0x0053d240/0x0053d2e0/0x0053d300` are the heap reorder and top-score + helpers, while `0x0053d320/0x0053d390/0x0053d440/0x0053d470` are the queue acquire, pop-highest, + membership, and release-side helpers. The sibling heap-owner body now lands too: + `0x0053d4c0/0x0053d540/0x0053d5d0/0x0053d630` are the pooled scored-heap insert, pop-top, + release, and construct-with-capacity paths over the same score-at-`+0x04` node shape. The + adjacent extended owner is now bounded too: `0x0053d6f0/0x0053d740` are the release and + construct-with-capacity paths for the sibling scored-heap owner that carries one extra sentinel + header at `[this+0x10]` plus best-score lane `[this+0x14]`, and current callers are the hotkey + report iterator `0x0045f250` and the nearby shell/runtime owner around `0x00522c67`. The next + support strip is tighter too: `0x0053d810/0x0053d870` are the CRC32-like NUL-string and fixed + byte-span hash helpers over table `0x00624e48`, while `0x0053d8a0/0x0053d960/0x0053d9e0/ + 0x0053daa0/0x0053dae0/0x0053db20/0x0053dbf0` now resolve as one intrusive `u32 -> ptr` + hash-table family with optional pooled `0x10`-byte nodes: release, insert, remove-and-return, + contains, lookup, callback iteration, and construct-with-bucket-count-and-node-capacity. + That family is already grounded on real world owners too, not just support-side data-structure + shape: connected-component and local bucket maps under `0x00416170/0x00419110`, selected owner + hashes under `0x00531ef0`, and the shell-side cleanup owner around `0x00522e7e` all use the same + pooled hash helpers. Beneath both the scored heaps and that hash family, `0x0053dcb0/ + 0x0053dcf0` are now bounded as the shared fixed-stride pool-descriptor release and reset helpers, + with freelist seeding over caller stride and count rather than one owner-family-specific allocator. + The next typed payload branch in the same banked-record family is tighter now too: row type `6` + is no longer just “some constructor under `0x0053c070`”. `0x0053ee70/0x0053e370` now read as the + construct wrapper and full constructor for one shell image-marker payload that parses a grounded + keyword set from the banked record text (`Image`, `ImageWH`, `ImageWHForceScale`, + `ImageWHWithRef`, `ImageScaled`, `ImageWHScaled`, `MaxPercentOfInterfaceVRAM`, + `MaxPercentOfInterfaceVRAMToUse`, `Scaleable`, `TGATargetScreenHeight`, + `TGATargetScreenWidth`, `TGAHeight`, `TGAWidth`, `TGAName`, + `HorizontalScaleModifier`, `VerticalScaleModifier`), registers one shell helper token through + `[0x006d401c+0xc69]`, and then hands off to `0x0053de60`. That heavier sibling is now bounded as + the payload's screen-metrics and VRAM-policy variant-table refresh owner: it derives current + screen-space scale from shell display state, resolves one selected TGA or DDS resource through + `0x0053c1c0`, and rebuilds the live variant array `[this+0x24]` through `0x005520a0` for later + consumers such as `shell_queue_world_anchor_marker` `0x00552560`. The rebuild and release side + is explicit too: `0x0053e2b0` releases current variants and the loaded image handle before + tail-jumping back into `0x0053de60`, while `0x0053e2e0/0x0053ee60` are the real destructor and + release thunk for the same type-`6` payload family. + The nearby overlay builders are tighter now too. `0x00478200` is no longer just a generic + single-marker wrapper: it validates owner id `[this+0x11b]` against collection `0x0062bae0`, + resolves that live city-database-style owner, samples normalized XY through `0x00455800` and + `0x00455810`, derives one localized label through `0x0053de00([this+0xaf],2)`, measures + projected half-height through `0x00477a10`, and then queues the finished marker through + `0x005521a0/0x00552160/0x00552560`. The broader sibling `0x00478330` now reads as the real + active-mode overlay-list owner: it derives the current world-space view box from + `[this+0xc3/+0xc7/+0xcb/+0xcf]` plus live world dims, runs six category passes `0..5`, pulls one + active-mode collection through `0x005130f0 -> 0x004b2b70` or `0x0050f600`, walks live placed + structures in `0x006cec20` through `0x0047fd50`, `0x0047df30`, and `0x0047df50`, and emits one + repeated label-marked overlay stream through `0x00477a10`, `0x004779c0`, and + `0x00552560`. After those category passes it also walks `0x006cfcbc` and can add one final + focused-region marker from `[this+0x113]` through `0x0048a170` with label id `0x3c`. The local + overlay-state helper strip under those builders is tighter now too. `0x00477af0` is the actual + default reset for the state band `[this+0xa3..+0x11f]`, seeding minimum span floor + `[this+0x11f]`, default cell bounds `[this+0xbb/+0xbf/+0xcb/+0xcf]`, scale lanes + `[this+0xd3/+0xd7/+0xdb]`, and normalized rect `[this+0xef/+0xf3/+0xf7/+0xfb]`. `0x00477a70` + is the paired scaled-max-span helper over the rebuilt cell bounds, while `0x00478dc0` and + `0x00479510` are now bounded as the two heavier owner passes above that strip: the first rebuilds + world-cell bounds and normalized rect from mode flags, raster bit `0x02`, and optional + placed-structure scans, while the second clamps and recenters those bounds and then refreshes the + normalized rect again after drag- or zoom-side updates. One input-side owner is bounded now too: + `0x00477c10` maps one screen-space point into a world-cell pair under the current overlay-state + bounds, and the larger sibling `0x00478cb0` is the drag-side loop above it that repeatedly + applies those deltas through `world_view_apply_screen_delta_to_focus_position` `0x0043d0c0` + before re-entering the same overlay-state rebuild or clamp family. The next query above that is + tighter now too: `0x00479b50` is the nearest-target resolver for this overlay family, first + searching placed structures in `0x006cec20` through `0x0047df30/0x0047df50` and `0x0051db80`, + then optionally falling back to regions in `0x006cfca8` through `0x0048a170` when the shell-side + metric flag bit `0x4` is set. The click-side owner above that is bounded now too: `0x00479d30` + first maps the cursor through `0x00477c10`, resolves the nearest target through `0x00479b50`, + then either publishes restriction notices `0x0c12/0x0c13`, forwards one compact selector-`0x384` + request into the Multiplayer preview owner at `0x006cd8d8`, or dispatches that same local target + through the active-mode handler pair `0x004b3160/0x004b2c10` before easing the shell scalar tail + through `0x0045ea20`. The broader raster owner above this branch is bounded now too: + `0x0047a120` first stages one visible overlay rect through `0x00534930/0x00534c50`, optionally + allocates the target RGBA buffer, and then rasterizes the visible map window through the world + classification helpers `0x00534e50`, `0x00534f00`, `0x00449bd0`, and `0x00448aa0`, mapping the + result through palette table `0x005f2c34` and finally marking city-database owners from + `0x0062bae0`. The small constructor strip under that raster owner is tighter now too: + `0x0047b070` and `0x0047b0d0` are the two concrete constructors for vtable `0x005ce840`, both + reusing `0x00477af0` for default state and then seeding the trailing template byte + `[this+0xa2]`. The release and service strip under the same vtable is tighter now too: + `0x0047b110` drops template handle `[this+0xaf]` and surface root `[this+0xab]` before tailing + into the base release; `0x0047b170` is the main service body that refreshes bounds through + `0x00479510`, draws the current overlay surface, and then queues either the repeated marker list + `0x00478330`, the single city-database marker `0x00478200`, or the fallback quad path + `0x00477d80`; and `0x0047b3d0` is the narrow wrapper that reruns `0x0047a120` into a temporary + raster target and commits the result back into live surface handle `[this+0xab]`. The next local + owner strip is tighter now too: `0x0047b470` ensures surface handle `[this+0xab]` by deriving + zoom-scaled requested dimensions from the current shell zoom table at `[0x006d4024+0x11421e]`, + growing them as powers of two under controller caps, allocating one `0xec`-byte surface owner + through `0x00543980`, and immediately rerasterizing through `0x0047b3d0`; `0x0047b5e0` is the + hover-update sibling that either tracks hovered classification id `[this+0x117]` under overlay + flag `0x00400000` or refreshes nearest target ids `[this+0x10f/+0x113]` through `0x00479b50` + before forwarding the live cursor band into `0x00558760`; and `0x0047b720` is now bounded as the + main message dispatcher for the same family, with current grounded cases for id `6`, refresh pair + `0xba/0xbb`, and scalar-update id `0xbc`, dispatching into the click owner `0x00479d30`, the + drag owner `0x00478cb0`, the ensure-surface path `0x0047b470`, the reraster path `0x0047b3d0`, + and the bounds rebuild owner `0x00478dc0`. The adjacent global marker strip is tighter now too: + `0x0047ba60` clears the ten-entry global pointer-marker slot table at `0x006ceba4`, + `0x0047bb90` is the matching release loop, and `0x0047ba80` rebuilds one indexed slot by + constructing a `0x26e`-byte specialization-root object through `0x0045b680`, seeding it from + literal roots `pointer`, `pointer2`, or `pointer3` through `0x0045b9b0`, publishing the caller + world anchor through `0x004556f0`, applying scalar `0.8f` through `0x00455720`, and clearing bit + `0x20` in the derived state byte. Current grounded callers are the clustered world-side branches + at `0x0051677b`, `0x00516797`, `0x005167df`, and `0x005167fe`, so this now reads as a real + shell-side global pointer-marker slot family rather than loose specialization constructors. + That keeps the label side grounded as a real support-family database strip rather than a loose + collection of anonymous bootstrap helpers. If shell-state gate + `[0x006cec74+0x174]` is set it then posts id `320` `Setting Up Buildings...` for + `world_region_collection_run_building_population_pass` `0x00421c20`; if `[0x006cec74+0x178] > 0` + it then posts id `321` `Seeding Economy...` for `simulation_run_chunked_fast_forward_burst` + `0x00437b20`; only after those setup-side gates does the code post id `319` + `Setting up Players and Companies...`. That `319` lane is no longer just a shell-state placeholder: its + earlier hidden prepass is tighter now too: `0x00437743` is the scenario-side named + candidate-availability seeding pass over the live candidate pool `0x0062b268`, feeding the + override collection at `[state+0x66b2]` through `0x00434f20` before any visible banner is posted. + That grounded write path is narrower than the static file evidence, though: the startup reset + helper `world_runtime_reset_startup_dispatch_state_bands` `0x004336d0` explicitly clears + `[state+0x66b2]` before the dispatch path begins, and the current exported write-side callers + we can name after that reset are still just the live-pool preseed `0x00437743`, the sibling + startup lane `0x00436ad7`, and the editor-side `Industry (Overall)` toggle handler + `0x004cf430` through `0x00434f20`. So while the fixed `0x6a70..0x73c0` candidate-availability + block is now well grounded as bundled map/save source data, a direct bulk-import path from that + block into the live runtime collection `[state+0x66b2]` is still not grounded by the current + disassembly notes. + That candidate-side table now has a grounded fixed record layout too: each entry is a `0x22`-byte + blob with a zero-terminated candidate-name slot at `[entry+0x00..+0x1d]` and one trailing + availability dword at `[entry+0x1e]`, read through `0x00434ea0` and mirrored later into + `[candidate+0x7ac]`. The same scenario state keeps a locomotive-side sibling collection at + `[state+0x66b6]`, read through `0x00435030` and updated through `0x004350b0`, which is now the + shared named locomotive-availability lane beneath the `Locomotives` editor page and the + startup-side locomotive seeding branches. That locomotive-side table is the same pattern at a + larger width: each entry is a `0x41`-byte blob with a zero-terminated locomotive-name slot at + `[entry+0x00..+0x3c]` and one trailing availability dword at `[entry+0x3d]`, later mirrored into + `[loco+0x7b]`. Both override dwords now read most safely as simple availability bits rather than + wider mode enums. That `319` lane is no longer just a shell-state placeholder: its + primary grounded work is still the chairman-profile pair + `world_seed_default_chairman_profile_slots` `0x004377a0` plus + `world_build_chairman_profile_slot_records` `0x00437220`, which seed the 16 selector bytes at + `[0x006cec7c+0x87]`, materialize the per-slot chairman records from the scenario selectors, + campaign override flag `[0x006cec7c+0xc5]`, and the static persona table at `0x005f2d28`, and then + publish the selected chairman-profile and linked company summary pair through `[state+0x25]` and + `[state+0x21]`. The local slot-record shape is tighter too because the shell editor panel around + `0x004cc2d0` now surfaces it directly: `[slot+0x00]` is the staged chairman profile id, + `[slot+0x01]` is the Optional-versus-Mandatory byte with nonzero=`Optional` and zero=`Mandatory`, + `[slot+0x02]` combines with the separate per-slot gate at `[world+0x0bc3+slot*9]` to surface + `Human`, `Computer`, and `Human or Computer`, `[slot+0x03]` is the special occupied-seat byte, and + `[slot+0x04]` is the numeric tuning field. Both the selector seeder and the record materializer + treat either `[slot+0x02]` or `[slot+0x03]` as enough to keep a slot live, but current grounded + writes only seed `[slot+0x03]` on slot zero and later move it solely by whole-record compaction. + That makes `[slot+0x03]` the strongest current anchor for the distinguished primary-human-seat + flag rather than a generic role byte. The summary fields are tighter too: current direct accessors + now show `[state+0x25]` as the selected chairman profile id in `0x006ceb9c`, while `[state+0x21]` + is the linked owning company id copied from `[profile+0x1dd]` through + `scenario_state_set_selected_chairman_profile` `0x00434890`. The raw id strip under those record + helpers is tighter now too: `0x004337a0` reads `[state+0x21]` directly as the selected company + id, `0x004337b0` reads `[state+0x25]` directly as the selected chairman profile id, and + `0x00433790` is the paired raw selected-company setter that the company and chairman reassignment + flows use when the visible ownership summary changes without re-entering the full profile setter. + The underlying profile constructor family is grounded now too. `0x00476140` is the broad + named-profile constructor beneath both chairman seeding passes: it stores the caller id at + `[profile+0x00]`, marks the record live through `[profile+0x04] = 1`, seeds byte and guard lanes + across `[profile+0x291..+0x295]` and `[profile+0x1e1]`, zeroes the large per-company and tail + bands `[profile+0x2ab..]` and `[profile+0xc66..]`, copies the caller byte into `[profile+0x15c]`, + seeds `[profile+0x158]` to `7.763f`, formats localized fallback name `0x0b87` when the caller + name is empty, copies the caller biography into `[profile+0x27]`, and picks one static persona + row through `0x004760f0`. That helper is now bounded as the wrapped-unused-row allocator over the + static persona table at `0x005f2d28`, marking one zero flag byte at stride `0x27` after a + modulo-`0x29` search. The neighboring raw company-slot strip is explicit too: `0x004760a0` + resolves indexed dword slot `[profile + company_index*4 + 0x2ab]` when the caller's generation + stamp differs from `[profile+0xc43]`, and `0x004760c6` is the paired store-side helper for the + same slot plus optional stamp write. The adjacent profile-metric strip used by the player-list + page is tighter now too: `0x00476320` sums the per-company holding band `[profile+0x15d..]` + against either cached company scalar `0x00423eb0` or the broader support-adjusted company scalar + `0x00424fd0`, while `0x004763b0` folds those same per-company contributions through one extra + thresholded transform before accumulating them. The active-profile collection helpers are direct + now too: `0x004778c0` returns the live record id of the Nth active chairman profile, and + `0x00477920` counts how many active chairman profiles precede one caller-selected live record id. + The neighboring transaction and cached-metric strip is tighter now too. `0x00476780` is the + direct-total-plus-cash query (`0x00476320 + [profile+0x154]`), while `0x00476c20` is the + threshold-adjusted-total-plus-cash sibling (`0x004763b0 + [profile+0x154]`). `0x004767a0` + selects between raw cash `[profile+0x154]`, the direct holding total, or their sum, and + `0x00476810` caches selectors `0` and `1` into the local qword band rooted at `[profile+0x1e9]`. + The trade-side helpers now split cleanly too: `0x00476460` is the sell-side mutator that reduces + one company holding slot `[profile + company_id*4 + 0x15d]`, converts the resulting proceeds + through `0x00424fd0(-units,1)`, and adds the scaled result back into `[profile+0x154]`; the buy + companion is `0x00477110`, which first reuses the feasibility gate `0x00476ff0`, then increases + that same holding slot and subtracts the scaled purchase cost from `[profile+0x154]`. Between + them, `0x00476e50` computes the rounded `1000`-sized trade block by mode, and `0x00476ff0` + performs the actual buy-affordability check against current cash plus an optional direct-holdings + fallback; the reduction-side sibling `0x00476c40` uses the same threshold-adjusted-total-plus-cash + lane from `0x00476c20` as its optional fallback when the direct holding slot is too small. One + broader periodic scalar is grounded now too: `0x00476560` walks raw issue `0x39` + through `scenario_state_sum_issue_opinion_terms_raw` plus the scenario baseline at `0x00433740`, + clamps the resulting factor against several `[profile+0x154]` thresholds, and then adds the + final scaled delta back into `[profile+0x154]`; current grounded caller `0x0040a760` applies + that adjustment across every active chairman profile before the later trigger-kind-`2` pass. + The adjacent start-new-company gate is explicit now too: `0x00476d10` first rejects through + localized id `2952` `You're not able to start a new company.` when scenario gate `0x00476a60` + is active; otherwise it treats `0x004763b0(1) + [profile+0x154]` as the relevant purchasing-power + lane, succeeds only when that total reaches threshold `0x005c8830`, and on failure formats the + richer localized warning `271` `You don't have enough money to start a new company!...` using the + selected chairman profile's current purchasing-power figure from `0x004348c0`. + The adjacent persona-row lookup strip is partly explicit now too: `0x00476bb0` returns the + matched static persona row index for current profile stem `[profile+0xc47]`, while `0x00476b30` + returns the same matched row's `+0x20` asset-stem pointer or falls back to `[profile+0x20]`, + and `0x00476ab0` is the structural `+0x40` string-pointer sibling for that same row family. + The adjacent chairman refresh owner is tighter now too: `0x00433850` uses the guard pair + `0x0062be20/0x0062be1c` to walk the active-chairman collection through + `0x00477820/0x00477860 -> 0x004771e0` until no nested mutation asks for another pass. + The editor-side scenario setup surface beside that chairman panel is clearer now too. + `map_editor_scenario_metadata_panel_refresh_controls` `0x004ca790` republishes the scenario + description from `[0x006cec78+0x672e]`, the start-year trio `[+0x66ca]`, `[+0x66d2]`, and + `[+0x66ce]`, the direct campaign-designated bit `[+0x66de]` through control `0x5b6e`, and the + inverse of the paired metadata byte `[+0x66f3]` through control `0x5b74`. The resource-side + anchor is now explicit too: `editorDetail.win` carries localized ids `3160/3161` `Campaign + Scenario` and `If checked, this map will be reserved as a campaign scenario.` inside the control + record rooted at `0x5b6e`, so `[+0x66de]` is now the grounded campaign-scenario flag rather than + an anonymous metadata boolean. `map_editor_scenario_metadata_panel_refresh_briefing_mode` + `0x004ca670` now bounds the single-player versus multiplayer briefing switch by flipping selector + `0x621f50`, publishing localized headings `1491` and `3586`, and refreshing the two briefing texts + from `[state+0x4f30]` and `[+0x5ae9]`. The companion dispatcher + `map_editor_scenario_metadata_panel_handle_message` `0x004cb4a0` makes the year semantics tighter + too: it commits the description and both briefing texts from edit-control payloads, toggles the + same two booleans, and clamps the three year fields to `1829..2100` while maintaining `minimum <= + default <= maximum`, which now lines up directly with the editor strings `Description:` `Minimum + Start Year:` `Default Start Year:` `Maximum Start Year:` `Briefing` and `Multi-Player Briefing`. + The neighboring special-conditions page is clearer as well: + `map_editor_scenario_special_conditions_panel_construct` `0x004cb2b0` now grounds the live owner + for the `Setup_Options_Buttons.imb` list rooted at `0xa7fa`, walks the 49-entry static rule table + at `0x005f3ab0`, counts enabled flags from `[0x006cec78+0x4a7f]`, and publishes the `Special + Conditions In Effect` summary from localized id `1053`. The same page now has a bounded live + dispatcher too: `map_editor_scenario_special_conditions_panel_handle_message` `0x004cb8e0` handles + both bulk selection controls and direct row-state changes, commits them back into + `[0x006cec78+0x4a7f]`, and then re-enters the panel constructor to refresh the summary. That table + is no longer just a raw id run; it now clearly includes the finance and construction restrictions + `2535..2563`, plus later editor toggles such as `Use Bio-Accelerator Cars`, `Disable Cargo + Economy`, `Disable Train Crashes`, `Disable Train Crashes AND Breakdowns`, and `AI Ignore + Territories At Startup`. The neighboring available-chairman page is tighter too. + `map_editor_available_chairman_panel_construct` `0x004ca540` now bounds the shell-side owner for + the 40-entry persona-availability surface under `0x5aa0..0x5b03`: it walks the same persona table + family at `0x005f2d28`, publishes one localized chairman-name row per profile, counts enabled + availability bytes from `[0x006cec78+0x6987..]`, and emits the summary `%1 out of %2 are + selected.` from localized id `1035`. The live state owner beside it is now grounded as well: + `map_editor_available_chairman_panel_handle_message` `0x004cb6f0` handles three bulk-selection + controls `0x5aa1..0x5aa3` by rewriting that same availability-byte array from preset bytes + embedded in the persona table, and it also commits direct per-row toggle changes from + `0x5aaa..0x5b03` back into `[state+0x6987..]` before refreshing the page. So the editor lane now + has three distinct scenario-setup slices rather than one chairman-only blob: chairman slots, + scenario metadata and briefings, plus both a rule-toggle matrix and an available-chairman pool. + There is now one adjacent company-side lane too: current neighboring setup flow conditionally + enters `world_conditionally_seed_named_starting_railroad_companies` `0x0047d440` when the + Multiplayer preview owner `0x006cd8d8` is absent and either sandbox flag `[0x006cec7c+0x82]` is + set or shell-state flag `[0x006cec74+0x14c]` is set while editor-map mode `[0x006cec74+0x68]` is + clear. That helper no longer looks like a generic company refresh. It seeds exactly three fixed + named railroad-company records from `RT3.lng` ids `575..577`: `Missouri Pacific`, `New York + Central`, and `Grand Trunk Railroad`. The first seeded company is tied back to the selected + chairman-profile summary and becomes the selected company id. The second railroad is tighter now + too: it only receives a chairman link when `profile_collection_count_active_chairman_records` + finds at least two live chairman records, and the helper then binds the zero-based second active + chairman through `profile_collection_get_nth_active_chairman_record` with ordinal `1`. The third + railroad currently gets no matching chairman-link branch in the grounded setup flow and therefore + remains an unchaired named company in the live roster. The shell UI above that setup lane is now + tighter as well: `shell_company_list_window_construct` `0x004c7200` builds a live company-list + window over the company collection at `0x0062be10`, `shell_company_list_window_refresh_rows` + `0x004c6c30` formats the active companies with localized strings `267..270`, and only then + conditionally appends one synthetic row id `0x7fff` through + `shell_company_list_format_company_or_start_row` `0x004c6b40` so `<>` appears + as a separate affordance rather than as part of the seeded trio itself. Current shell paging + around that same roster is tighter too because the live company collection now has a grounded + active-only ordinal helper family: `company_collection_count_active_companies` `0x00429a50`, + `company_collection_count_active_companies_before_company_id` `0x004299f0`, and + `company_collection_get_nth_active_company_id` `0x00429990`. Those helpers now anchor the “current + company among active companies” math used by shell-side detail and picker flows rather than + leaving it as anonymous collection glue. `shell_company_list_window_handle_message` `0x004c6f30` + then routes the synthetic row into `start_new_company_dialog_open` `0x0047d080`, whose commit path + now grounds through `start_new_company_dialog_commit_create_company` `0x0047d120`. That lower + helper unlinks any current chairman-owned company, allocates a fresh company id from the live + collection at `0x0062be10`, initializes it through `0x00428420`, and only then publishes the new + selected company. The neighboring compact request helper + `start_new_company_request_create_company` `0x0047d320` does the same fresh-company path from a + request block and is already reached from the startup-company branch at `0x00470e48`. The dialog + side is tighter now too: `0x0047c070` and `0x0047bea0` rebuild the two funding-band globals from + the selected chairman profile through `0x00476c20` and `0x00476950`, publish their range cards + into controls `0x714f` and `0x7150`, `0x0047c190` republishes the current pair `0x006cec14` and + `0x006cec10` into controls `0x7149` and `0x714a`, `0x0047c220` snaps those two current funding + lanes back onto the active band steps, and `0x0047c360` is the small child-control callback gate + over that same funding family. The immediate pre-open helper `0x0047d020` is now bounded too: it + seeds the staged dialog name buffer and then runs the same clustered funding-band rebuild sequence + before `start_new_company_dialog_open` continues into the constructor/callback modal path. The + constructor and message side are bounded enough now too: `0x0047c590` constructs the modal dialog + controls for `0x714f/0x7150/0x7149/0x714a/0x714b/0x714c/0x714d/0x714e`, installs callback + `0x0047c360` on the funding-band pair, and publishes the live dialog root at `0x006cec18`, + while `0x0047c3a0` is the main dialog message owner over shell messages `0xca/0xcb`, the staged + name field `0x714b`, the two funding-step controls `0x714c/0x714d`, the companion summary lane + `0x714e`, and the modal notice branch rooted at `0x03f2/0x03f4`. The + immediate sibling shell branch below that roster is still station-oriented: current grounded + resource names and handlers put one branch on `shell_station_detail_window_construct` + `0x005068c0`, another on `shell_station_list_window_construct` `0x005074c0`, and the subordinate + selector lane on `shell_station_pick_window_open_modal_and_return_selected_station_id` + `0x005078c0` above `shell_station_pick_window_construct` `0x00507620`. But the broader + company-detail ownership question is no longer open. There is now a separately grounded + `CompanyDetail.win` family rooted at `shell_company_detail_window_construct` `0x004c5540`, with + `shell_company_detail_window_handle_message` `0x004c56a0` as its main dispatcher and + `shell_company_detail_window_refresh_controls` `0x004c2ca0` as the shared repopulation pass for + the selected-company presentation and tabbed control bands around `0x9476..0x9490`. A grounded + direct shell-command strip now sits cleanly above those two company panels too: `0x00433a40` is + the shared availability gate for both the company-list and selected-company-detail lanes, + rejecting only when scenario toggle `[0x006cec78+0x4aef]` is set. `0x004405a0` uses that gate to + open detail-panel mode `7` as the direct company-list path, while `0x004405d0` first recovers + the selected-company id through `0x004337a0`, optionally offers `Start New Company` through + `0x0047d080` after warning `368` when no company is selected, and only then opens detail-panel + mode `8` for the selected-company `CompanyDetail.win` lane. A grounded + shell detail-manager caller reaches that constructor at `0x004dde24`, the first finance-action + layer beneath it is now bounded through `shell_company_detail_issue_bond_offer_flow` `0x004c3890`, + `shell_company_detail_issue_stock_offer_flow` `0x004c3f30`, + `shell_company_detail_buyback_stock_flow` `0x004c46d0`, and + `shell_company_detail_change_dividend_rate_flow` `0x004c5360`, and the first non-finance layer is + now bounded too through `shell_company_detail_resign_chairmanship_flow` `0x004c5a0e`, + `shell_company_detail_bankruptcy_flow` `0x004c5b99`, the territory-access family rooted at + `shell_company_detail_refresh_selected_territory_access_summary` `0x004c1b60` plus + `shell_company_detail_buy_territory_access_rights_flow` `0x004c5fc9`, backed by + `company_clear_selected_chairman_if_current_profile` `0x00428a10`, + `company_declare_bankruptcy_and_halve_bond_debt` `0x00425a90`, + `company_has_territory_access_rights` `0x00424010`, `company_set_territory_access_rights_byte` + `0x00424030`, and `company_can_purchase_territory_access_rights` `0x00426be0`, plus the two + control-transfer lanes. `shell_company_detail_attempt_chairmanship_takeover_flow` `0x0050ccc0` now + grounds the special chairman's election path: it checks the caller's current stock ownership in + the target company, rejects insufficient holdings through localized id `623`, rejects recent + failed attempts through id `624`, and then opens the confirmation under id `625` before seeding + the local takeover-election state or packaging the same request through the multiplayer shell + transport. The follow-on resolver `shell_resolve_chairmanship_takeover_vote_and_commit_outcome` + `0x0050c940` now closes the single-player election loop too: it walks the active chairman profile + collection, computes weighted votes for and against the takeover, compares the affirmative total + against half the target-company value, presents the result through + `shell_present_chairmanship_takeover_vote_outcome_dialog` `0x0050c500` in single-player or + localized id `3082` in multiplayer, and then either transfers chairmanship through `0x00428a30` or + stamps the current year into `[company+0x289]` as the grounded takeover-cooldown field. + `shell_company_detail_attempt_merger_flow` `0x004ec640` now grounds the merger side too: it + rejects empty worlds through id `727`, rejects recent failed attempts through id `728`, checks the + proposed premium against company cash through localized id `3889`, and then commits into the + resolver family. That merger resolver is now bounded too: + `shell_resolve_merger_vote_and_commit_outcome` `0x004ebd10` walks the active chairman profile + collection, computes weighted votes for and against the proposed merger, compares the affirmative + total against half the target-company value, presents the result through + `shell_present_merger_vote_outcome_dialog` `0x004eb890` in single-player or localized id `3059` in + multiplayer, and then either commits the merger through `0x00427e20` or stamps the current year + into `[company+0x15f]` as the grounded merger-cooldown field. The vote-bias side beneath that + resolver is tighter now too: `scenario_state_compute_issue_opinion_multiplier` `0x00436590` is no + longer just an abstract issue table lookup because its merger callsite uses issue id `0x3a`, which + lines up directly with localized id `726` saying merger votes depend on public attitude toward the + management of the two companies. By contrast the broader support-adjusted share-price helper + `company_compute_public_support_adjusted_share_price_scalar` `0x00424fd0` uses issue id `0x37`, + and the shared setter under that lane is tighter now too: `0x004339b0` clamps one small + scenario-side issue value into `[state+0x2d]` with range `0..4`, derives one companion scalar in + `[state+0x29]`, and then forces a live-company sweep through `0x00424fd0` so the support-adjusted + share-price family is recomputed immediately after the issue lane changes. The finance-side debt + helpers now bound `0x38` and `0x39` separately as the explicit + credit-rating and prime-rate lanes. That leaves `0x37` as the broader investor-confidence lane + behind equity support, share price, and adjacent governance pressure, with the strongest current + text anchors coming from the investor-attitude strings `1217` and `3048/3049` about company or + chairman performance rather than from the merger-only management-attitude term. One older local lead is now ruled out too: the + `0x460900..0x460cac` / `0x473620` setup block is the camera-view command family over localized ids + `3474..3493` (`Select/Assign Camera View 1..9` and `0`), not issue-opinion infrastructure, so it + should no longer be used as evidence for the player-facing meaning of issue `0x37`. The editor-side + `Stock Prices` label is also no longer being used as direct evidence here: the `0x4ca980` / + `0x4cadf0` panel owns a separate float-tuning block `[state+0x0bde..0x0bf6]`, with + `[state+0x0bde]` merely mirroring `[state+0x0be2]`, so that label belongs to a different + settings family than the issue table behind `0x37`. A direct shell-resource follow-up now narrows + the remaining caption question too: the extracted `CompanyDetail.win` blob from `rt3_2WIN.PK4` + contains no plain-English investor or finance caption for this lane, which matches the owner-side + read that section-0 is a dynamic `0x947f` text widget fed by + `shell_format_company_governance_and_economy_status_panel` `0x004e5cf0` rather than a separate + fixed label row. The supporting stat layer is bounded more cleanly now too: the + surrounding `0x0b` setup in the merger and takeover offer builders is formatter mode rather than a + player-facing issue number, while the company-side stat wrapper + `company_read_year_or_control_transfer_metric_value` `0x0042a5d0` now reads as a generic + stat-family accessor over year-relative series or the bounded slot family in + `company_read_control_transfer_metric_slot` `0x0042a2e0`. Its recurring family token `0x2329` is + no longer treated as an issue id here either; it is the stat-family selector paired with localized + company-stat label id `2329`. That means the paired raw and scaled helpers at `0x004241e0` and + `0x00424200` now read as narrow control-transfer offer policy totals instead of direct + issue-argument consumers, and the same broader support-and-governance metric family now also feeds + the annual shareholder-revolt and creditor-liquidation lane surfaced by localized ids `300..304`. + The editor-side help text cluster around ids `2433..2437` is no longer floating either: current + grounded map-editor code now has a live economic tuning family beside the chairman-slot panel. + `map_editor_economic_cost_slider_panel_construct` `0x004cadf0` binds six slider controls through + `map_editor_economic_cost_slider_dispatch` `0x004ca980` into the scenario-state float block + `[0x006cec78+0x0be2..0x0bf6]`, while the surrounding descriptor table at `0x00611c70..0x00612220` + pairs that wider editor lane with localized fields `Prime Rate`, `Merger Premium`, and `Build + Stations Cost` through `Steam Engine Cost` plus the comparison or help texts `2433..2437`. The + broader shell-state master flag at `[0x006cec74+0x68]` still sits above the remaining post-load + phases, plus two narrower per-phase gates: `[0x006cec74+0x174]` directly fronts id `320` `Setting + Up Buildings...` and the later region-owned structure-demand and placement pass through + `world_region_collection_run_building_population_pass` `0x00421c20` plus the deeper per-region + worker `world_region_balance_structure_demand_and_place_candidates` `0x004235c0`, while + `[0x006cec74+0x178]` directly fronts id `321` `Seeding Economy...` and the chunked burst helper + `simulation_run_chunked_fast_forward_burst`, whose grounded tail now also sweeps the live region + collection through `world_region_refresh_cached_category_totals_and_weight_slots` `0x00423d30`; + id `322` then fronts `Calculating Heights...`. The + master `+0x68` flag is no longer just structural: the shell load/save coordinators now use the + same flag to force the editor-map `.gmp` family, so current evidence treats it as the broader + editor-map mode above those later setup branches rather than an unnamed generic toggle. That + worker is no longer one opaque building bucket: current grounded categories split into `House`, a + weighted region-profile family surfaced through the `Industry Weightings` stats path, and a third + branch whose low-level fallback token is `Commercial` but whose aligned stats label is `City + Support`. The same placement-commit gate beneath it, `world_region_validate_and_commit_candidate_placement` + `0x00422a70`, is also corroborated by the separate world-side randomized batch helper + `world_try_place_random_structure_batch_from_compact_record` `0x00430270`, which retries + placements around one compact center/radius record rather than the ordinary per-region demand + deficits. That batch placer now sits under a wider compact runtime-effect dispatcher, + `world_apply_compact_runtime_effect_record_to_resolved_targets` `0x00431b20`, so the world-side + branch is no longer just “another caller near `0x43051e`” but one real effect family alongside + the ordinary region-demand worker. Above that, the live scenario event collection at `0x0062be18` + now has a tighter runtime-effect lane too: `scenario_runtime_effect_record_service_and_dispatch_linked_compact_effects` + `0x004323a0` services one live runtime-effect record, dispatches its linked compact effects + through `0x00431b20`, and can synthesize follow-on records through + `scenario_runtime_effect_record_build_followon_effect_from_compact_record_and_targets` + `0x00430b50`, which in turn allocates new live records through + `scenario_event_collection_allocate_runtime_effect_record_from_compact_payload` `0x00432ea0`. + Above that, `scenario_event_collection_service_runtime_effect_records_for_trigger_kind` + `0x00432f40` now bounds the collection-wide loop that services those live runtime-effect records + for one trigger kind. That trigger split is tighter now too: recurring simulation maintenance + drives kinds `1`, `0`, `3`, and `2`; the neighboring route-style follow-on drives `5` and `4`; + startup-company and named-railroad creation branches drive `7`; kind `6` is now bounded as a + mixed post-change family spanning the placed-structure post-create tail, one build-version-gated + company-startup or roster-refresh tail, and the route-entry post-change sweep on `0x006cfca8`; + one world-entry-side one-shot gate drives `8` and then clears shell-profile latch + `[0x006cec7c+0x97]`; the briefing-text query lane is kind `9`; and the collection dirty latch + still forces the internal rerun at kind `0x0a`. + That moves this branch out of the “isolated world-side placement oddity” bucket and into a real + scenario-runtime effect pipeline with a mostly bounded trigger-kind family. + The same lower helper also reappears later on a slower + simulation-side cadence with + scale `1/12`, so it no longer looks like one-time setup glue only. The actual game-speed control + family remains separate, rooted at `world_set_game_speed_mode` `0x00434680`, + `world_adjust_game_speed_mode_delta` `0x00434850`, and `world_toggle_pause_or_restore_game_speed` + `0x00437a60`. The direct shell command stub above that family is now explicit too: `0x00440880` + just re-enters the pause-or-resume toggle with flag `1` and then issues one indexed shell + feedback nudge through `0x0045ea20` with selector `0x2c` and scalar `0.5f`. That feedback path + is tighter now too: `0x0045ea20` is the reusable indexed audio-feedback helper over the + table-driven pairs at `0x005f0828/0x005f082c`, and `0x00531e10` is the shell-audio-service sink + that only dispatches those nudges when the live service gates are satisfied. +### Camera View Command Strip + +The adjacent shell-command family at `0x004408f0..0x00440c30` is now + grounded as the ten-slot `Assign/Select Camera View` owner rather than as a generic modal strip. + `shell_assign_camera_view_slot_and_publish_confirmation` `0x004408f0` snapshots one `0x30`-byte + record inside the live world-view owner through `world_view_store_camera_view_slot_snapshot` + `0x0043b2c0`, storing both the live view tuple `[view+0x04..+0x24]` and one saved focus-kind pair + from `[0x006cec78+0x45/+0x49]`; `shell_select_camera_view_slot_or_publish_unassigned_warning` + `0x004409c0` then re-enters `world_view_restore_camera_view_slot_snapshot_if_populated` + `0x0043ca20`, which restores the same fields, optionally replays the saved focus through + `shell_world_focus_selected_subject_kind_and_id` `0x00437a90`, and returns silently on success. + Only empty slots surface the shared shell modal path, using localized ids `371..373` after one + label-format pass through `0x0051b700`. The wrapper strip `0x00440b00..0x00440c30` is now fully + bounded too: `0x00440b00/10/20/30/40/50/60/70/80/90` are `Assign Camera View 1..9/0`, while + `0x00440ba0/b0/c0/d0/e0/f0/c00/c10/c20/c30` are `Select Camera View 1..9/0`, and the + registration block at `0x00460903..0x00460cac` ties those wrappers to localized command ids + `3474..3493`. +### CompanyDetail Addendum + +The shared helper `shell_company_detail_resolve_selected_company` at + `0x004c16f0` now bounds the common current-company accessor beneath the whole pane, and the + read-side owner also has a separate active-company navigation family through + `shell_company_detail_step_selected_active_company_delta` at `0x004c3470` plus the next or + previous wrappers at `0x004c3540` and `0x004c3550`. The section switch in + `shell_company_detail_window_refresh_controls` is now grounded too: section index `0x006cfe60` + selects a chairman/governance slice, a debt-and-capital slice, a per-share slice, or a + territory-access slice, published through the tab band around `0x9472..0x9479`, with adjacent + section-navigation controls around `0x947b..0x947c` and `0x948f..0x9490`. +### Key Dispatchers + +`shell_controller_window_message_dispatch`, + `shell_input_apply_window_key_transition`, `shell_input_snapshot_dispatch_state`, + `shell_input_cursor_inside_active_view`, `world_load_saved_runtime_state_bundle`, + `world_runtime_serialize_smp_bundle`, `simulation_frame_accumulate_and_step_world`, + `game_message_window_service_if_present`, `game_message_window_service_frame`, + `game_uppermost_window_handle_message`, `game_uppermost_window_service_world_hotspot_band`, + `game_uppermost_window_refresh_controls`, + `world_view_service_keyboard_turn_pan_and_zoom_bindings`, `world_view_step_heading_quadrant`, + `world_view_step_zoom_bucket`, `world_seed_default_chairman_profile_slots`, + `world_build_chairman_profile_slot_records`, + `world_conditionally_seed_named_starting_railroad_companies`, + `scenario_state_set_selected_chairman_profile`, + `scenario_state_get_selected_chairman_profile_record`, + `scenario_state_get_selected_chairman_company_record`, `shell_company_list_window_construct`, + `shell_company_list_window_refresh_rows`, `shell_company_list_window_handle_message`, + `start_new_company_dialog_open`, `start_new_company_dialog_commit_create_company`, + `start_new_company_request_create_company`, `shell_station_detail_window_construct`, + `shell_station_list_window_construct`, `shell_station_list_window_handle_message`, + `shell_station_pick_window_construct`, `shell_station_pick_window_populate_station_rows`, + `map_editor_chairman_slot_panel_construct`, `map_editor_chairman_slot_panel_handle_message`, + `map_editor_chairman_slot_panel_refresh_selected_slot`, + `map_editor_chairman_slot_panel_cycle_selected_slot_profile`, + `map_editor_available_chairman_panel_construct`, + `map_editor_available_chairman_panel_handle_message`, + `map_editor_scenario_metadata_panel_refresh_briefing_mode`, + `map_editor_scenario_metadata_panel_refresh_controls`, + `map_editor_scenario_metadata_panel_handle_message`, + `map_editor_scenario_special_conditions_panel_construct`, + `map_editor_scenario_special_conditions_panel_handle_message`, + `map_editor_economic_cost_slider_panel_construct`, `map_editor_economic_cost_slider_dispatch`, + `station_place_world_surface_sync_and_dispatch`, `station_place_window_handle_message`, + `track_lay_window_refresh_controls`, `track_lay_window_service_frame`, + `track_lay_window_handle_message`, `simulation_advance_to_target_calendar_point`, the smaller + single-step helper at `0x00409e80`, `0x0040a9c0`, `0x0040a910`, and + `simulation_service_periodic_boundary_work`. +### State Anchors + +Shell input object `0x006d4018`, per-key state table starting at `[input+0x100]`, + packed shell input flags at `[input+0xa8c]` now grounded as Right Shift `0x1`, Left Shift `0x2`, + Control `0x4`, and Alt `0x20`, nested dispatch counter `[input+0xa90]`, global shell controller + `0x006d4024`, active world root `0x0062c120`, `GameMessage.win` object `0x006d081c`, + `GameUppermost.win` overlay object `0x006d0820`, `StationPlace.win` tool object `0x006d1720`, + `TrackLay.win` tool object `0x006d1a8c`, accumulated leftover simulation time at `[this+0x4c80]`, + shell and mode globals at `0x006cec74`, `0x006cec78`, and `0x006cec7c`, world manager collections + at `0x0062be10`, `0x006ceb9c`, `0x006cfcbc`, `0x006cec20`, `0x0062bae0`, and `0x006acd34`, plus + the packed calendar-like tuple fields around `[this+0x0d]`, `[this+0x0f]`, `[this+0x11]`, and + `[this+0x14]`. +### Subsystem Handoffs + +The controller window dispatcher now looks like the first grounded input + ingress. It translates keyboard and mouse `WM_*` traffic into shell controller state and the + separate input object at `0x006d4018`; read-side cursor and camera helpers later snapshot that + object through `shell_input_snapshot_dispatch_state` and gate world-relative interaction through + `shell_input_cursor_inside_active_view`. Current grounded consumers around `0x00478cb0`, + `0x004e0780`, `0x0053f450`, and `0x0053fe90` still sit on the shell controller path and consult + `0x006d4024` or the world owner at `0x0062be68`, so there is still no evidence for a distinct + gameplay-only input object after world entry. Instead, the first deeper world-mode interaction + branch now looks like a shared world-view coordinator layered on top of the same shell-fed input + state. Shell_transition_mode ensures the `GameUppermost.win` object at `0x006d0820`; its message + dispatcher `game_uppermost_window_handle_message` owns the narrow action band `0x7918` through + `0x7921`; and the recurring service helper `game_uppermost_window_service_world_hotspot_band` + rate-limits those hotspot actions, rechecks `shell_input_cursor_inside_active_view`, and then pans + the live world view through `world_view_pan_relative_offset_in_camera_plane` `0x0043d130`. The + same lower setter family is also reached from the cursor-drag path through + `world_view_apply_screen_delta_to_focus_position` `0x0043d0c0`. Above both of those sits the + larger recurring service `world_view_service_shell_input_pan_and_hover` `0x0043db00`, which now + has one grounded keyboard branch beneath it: + `world_view_service_keyboard_turn_pan_and_zoom_bindings` `0x0043d740`. That helper resolves four + binding-pair families from the shell input table via `0x0054e7d0`, and the localized labels are + now grounded from `Data/Language/RT3.lng`: `Camera Forward` and `Camera Backward` feed the first + signed pan channel, `Camera Left` and `Camera Right` feed the second signed pan channel, `Camera + Zoom In` and `Camera Zoom Out` feed the signed zoom-step channel that `0x0043db00` smooths into + `world_view_step_zoom_bucket` `0x0043cc30`, and `Camera Rotate Left` plus `Camera Rotate Right` + feed the continuous heading-turn branch through `0x0043c810`. The setup side is now better bounded + too: `world_view_seed_keyboard_binding_slot_pairs` at `0x00439e40` seeds the eight slot pairs at + `[this+0x0a6]` through `[this+0x0e2]` from the global action-binding registry through + `shell_input_binding_registry_lookup_primary_code_and_mode_bits_by_action_id` `0x0045f370` using + the distinct registry keys `0x0043d2a0` through `0x0043d310`, and the registration block at + `0x00460769` through `0x004608e7` plus the shared installer + `shell_input_register_action_binding_with_mode_specific_defaults` `0x0045f6d0` show those roots + are defaulted to the expected Up Down Left and Right virtual keys before runtime polling begins. + The adjacent lookup strip is tighter now too: `shell_input_binding_registry_resolve_entry_by_action_stem` + `0x0045ede0` resolves one action stem into the live binding registry, while + `shell_input_binding_registry_format_display_label_by_action_stem` `0x0045f3d0` and + `shell_input_binding_registry_query_primary_code_by_action_stem` `0x0045f400` are the small + display-label and primary-code wrappers above that resolver. The camera-view modal family at + `0x004408f0/0x004409c0` now uses that same strip directly when formatting the optional focus-label + lines inside the assign/select camera-view confirmations. The lower label path is now bounded too: + `shell_input_binding_format_display_label_from_registry_entry` `0x0045ea90` is the actual + registry-entry formatter with the three localized prefix fragments `0xdef/0xdf0/0xdf1` plus the + descriptor-table caption fallback at `0x005f0a34`, and + `shell_input_binding_descriptor_query_bucket_key_for_action_id_when_mode_mask_is_singular` + `0x0045ed90` is the descriptor-side bucket-key helper used by the installer when the target mode + mask is singular. The same local family now reaches one step further into the hotkeys sidecar: + `shell_input_binding_report_iterate_next_entry_in_sorted_priority_order` `0x0045f250` builds a + temporary sorted report queue over the live registry, `shell_input_write_hotkeys_report_file` + `0x0045f550` writes the resulting table to `hotkeys\hotkeys.txt`, and the hotkey reassignment path + uses the smaller helpers `0x0045ec00`, `0x0045ec70`, `0x0045ecd0`, `0x0045ed70`, `0x0045ef00`, + and `0x0045f8a0` to split imported `foo+bar` labels, recover one action id from the descriptor + table, decode a compact modifier code, expand that code back into the live registry mask, and + finally rebucket or replace the live binding entry. The surrounding registry lifecycle is tighter + now too: `shell_input_seed_default_binding_registry_entries_from_static_table` `0x0045f9e0` + seeds the fixed defaults from `0x005ecadc` and then appends the smaller manual shell-command + strip; `shell_input_binding_registry_destroy_all_roots_and_reset_globals` `0x00461070` is the + hard reset that also flushes `hotkeys\hotkeys.txt`; and + `shell_input_binding_registry_initialize_roots_seed_defaults_and_optionally_import_hotkeys_file` + `0x00461120` rebuilds the pool roots, reseeds defaults, and tail-jumps into + `shell_input_import_hotkeys_file_and_rebucket_registry_entries_from_compound_labels` `0x0045f420` + when the caller requests saved-hotkey import. + Beneath that camera stack, the enclosing frame + path now has one grounded non-view sidecar: after `0x0043db00` it reads the active controller-view + object pointer at `[0x006d4024+0x18]+0x366e`, compares it against the latched target at + `[frame_owner+0x66a2]`, fires exit and enter-style vtable callbacks on pointer changes through + slots `+0x64` and `+0x60`, and only latches the new object when the object passes its own slot + `+0x1c` availability test and shell detail control id `0x07d6` on `0x006d0818` has flag bit `0x4`. + That `0x07d6` gate is now more bounded than before: the dedicated `TrackLay.win` tool family + rooted at `0x006d1a8c` special-cases the same control id in both `track_lay_window_service_frame` + and `track_lay_window_handle_message`, uses world hit tests through `0x00448ac0` to arm and + release a drag latch on that surface, and routes the resulting command work through the shared + track-lay mode state at `0x00622b0c`. The surrounding `track_lay_window_refresh_controls` pass now + shows that this is not just one isolated drag handler: the same tool family owns three mutually + exclusive primary mode buttons at `0x985e` `0x985f` and `0x9860`, and current primary evidence now + bounds those values as `Lay single track.` `0x1`, `Lay double track.` `0x4`, and `Bulldoze` `0x40` + from the localized strings 2054 2055 and 1721 plus the matching control-routing branches in + `track_lay_window_handle_message`. The same family also owns the downstream route-entry policy + bridge at `0x004955b0`: current caller evidence says that helper maps the live TrackLay primary + mode into endpoint-synthesis policy `1` or `4` before the tool re-enters `0x00493cf0`, which is + the strongest current bridge from the player-facing single-track versus double-track buttons into + the lower route-builder policy bytes. The same family also owns a bridge-type preference selector + rooted at `0x006cec74+0x138`, two wrapped `Never` through `Common` frequency settings at + `0x006cec74+0x140` and `0x006cec74+0x13c`, two boolean track-lay preference toggles, and the + electrify-all-track action path. Those last two toggles are now tighter than before: current + evidence strongly aligns control `0x986e` and state `0x006cec74+0x144` with `Auto-Hide Trees + During Track Lay` from strings 1838 and 1839, while control `0x986d` and state `0x006cec78+0x4c74` + align with `Auto-Show Grade During Track Lay` from strings 3904 and 3905. That mapping is still + evidence-backed rather than absolutely direct from a recovered resource table, but the state + ownership and control order now make it the strongest current fit. That makes `0x07d6` look like + the shared main-world interaction surface inside a broader TrackLay world-command subsystem, not + an unrelated detail button. The neighboring `StationPlace.win` family is now grounded on that same + surface too: the shell detail-panel constructor family allocates it through + `station_place_window_construct` at `0x00509d80`, publishes it at `0x006d1720`, services it each + frame through `station_place_window_service_frame` at `0x0050a530`, and routes player-facing + commands through `station_place_window_handle_message` at `0x005091b0`. That dispatcher + special-cases the same `0x07d6` control, and the shared helper + `station_place_world_surface_sync_and_dispatch` at `0x00508bb0` either accepts that direct surface + traffic or falls back to the same detail-panel control looked up through `0x006d0818`, rechecks + flag bit `0x4`, hit-tests the world through `0x00448ac0`, stages world coordinates into + `0x006d1738/0x006d173c`, refreshes the remaining preview metric field through + `station_place_refresh_preview_metric_control_0x6983` `0x00508550`, and updates the live + station-placement selection state at `0x00622af0`, `0x00622aec`, and `0x006d1740`. The tool-side + save and restore choreography is tighter now too: `station_place_window_release_cached_selection_handles_and_world_followons` + `0x005079c0` releases cached helper handles `[this+0x7c/+0x80/+0x88/+0x84]` through the matching + global owners after re-entering world and placed-structure follow-ons, and the thin wrapper + `0x00507a50` is the entry used by the broader save-load status-stack helpers. The category side + of that state is now tighter too: the shared helper `0x0044bd10` quantizes the staged world coordinates into the + current cell, resolves the mixed byte-or-word region id from `[world+0x212d]`, looks up the + owning city-or-region entry through `0x0062bae0`, and returns `[entry+0x272]` with fallback + `5`; the StationPlace world-surface branches at `0x00508b80`, `0x00508d59`, and `0x0050a4e6` + use that result directly to refresh the current selection category latch at `0x00622af0`. + Together with + `station_place_select_category_and_refresh` `0x00508880`, + `station_place_refresh_category_controls` `0x00507b90`, and `station_place_format_preview_panel` + `0x00508730`, that makes StationPlace a second grounded consumer of the shared main-world + interaction surface rather than only a sibling constructor plus frame hook. The StationPlace + control semantics are now tighter too: the top category strip at `0x697c` through `0x6981` now + grounds as small station, medium station, large station, service tower, maintenance facility, and + non-station building from `RT3.lng` strings 2197 through 2202. For the three station categories + only, the secondary strip at `0x6988` and `0x6989` plus display field `0x698c` no longer looks + like another placement mode family; it is a building-style scroller. The click handlers on + `0x6988` and `0x6989` cycle the style override in `0x00622aec`, and the display path builds the + active style token from `StationSml`, `StationMed`, or `StationLrg` plus the localized + architecture styles `Victorian`, `Tudor`, `Southwest`, `Persian`, `Kyoto`, and `Clapboard` from + `RT3.lng` ids 2672 through 2667. One layer lower, the remaining opaque controls are now much + tighter: `0x6985` and `0x6986` are no longer a generic assist toggle but the two station-rotation + policy choices from strings 2207 and 2206, switching between auto-orienting the building to track + or obstacles and strictly obeying the rotation specified by the circle above. The dedicated + control at `0x6987` is the station-rotation circle itself, wired through + `station_place_rotation_circle_callback_publish_current_heading_widget` `0x00507a90` and aligned + with `Click to rotate the building. You can also use bracket keys [ and ] to rotate buildings.` + string 2208. The lower rotation strip is now grounded too: + `station_place_set_rotation_and_refresh_live_selected_site_pose` `0x00507cf0` owns the write to + `0x006d172c` and the live selected-site pose refresh, `station_place_window_drag_rotate_selected_site_toward_world_cursor` + `0x00507d80` is the drag-update branch under the dispatcher, and + `station_place_step_rotation_by_integer_notches` `0x005086c0` is the discrete notch helper used by + the neighboring StationPlace rotation-step branches. That matches the lower behavior too: when the + strict-rotation choice is off, both preview and commit paths route staged coordinates through + `station_place_window_try_auto_orient_candidate_to_covering_route_entry_and_validate_placement` + `0x00508040`, which performs the extra orientation search before validation by retrying a small + orientation-mode set around the reusable covering-route-entry helper `0x00417b40`; when strict + rotation is on, that pass is skipped and the current angle in `0x006d172c` is used directly. The + preview strip is tighter now too: `station_place_format_preview_panel` `0x00508730` is the real + owner for controls `0x6982/0x6983/0x6984`, and the middle field `0x6983` is no longer anonymous. + `station_place_refresh_preview_metric_control_0x6983` `0x00508550` resolves the staged world-cell + category through `0x0044ad60`, reads the linked profile scalar at `[profile+0x22]`, chooses issue + slot `0x3b` or `0x3c` from candidate subtype byte `[candidate+0x32]`, folds that scalar through + `scenario_state_compute_issue_opinion_multiplier` `0x00436590`, and then passes it through the + version-gated quantizer `0x005084a0` before formatting the visible text into control `0x6983`. + The singleton-side entry above that strip is explicit now too: + `station_place_format_preview_panel_if_live_singleton_and_valid_selection` `0x00508860` only + forwards non-`-1` selection ids into that refresh path when `0x006d1720` is live. + One layer below preview versus commit, the shared gate is also tighter now: + `station_place_validate_current_selection_at_world_coords_and_optionally_format_status` + `0x00507e80` is the common validation-and-status path beneath the preview and commit branches, + publishing red, yellow, or green feedback through `0x0040cb10` around the same + `placed_structure_validate_projected_candidate_placement` `0x004197e0` core. The + direct shell UI also exposes the same discrete view-step family through + `world_view_step_heading_quadrant` `0x0043cb00` and + `world_view_step_zoom_bucket` `0x0043cc30`. The neighboring gating predicates + `world_view_should_drive_primary_pan_channel` and `world_view_should_drive_secondary_pan_channel` + test packed shell input bits `0x3`, and `shell_input_apply_window_key_transition` now grounds + those bits as the left and right Shift modifiers from scan codes `0x2a` and `0x36`. That means + cursor drag, overlay hotspots, held Shift state, direct keyboard turn/pan/zoom bindings, the + TrackLay and StationPlace world-command surfaces, and at least one frame-owned hover or + focus-target branch all converge under the same shell-fed world-mode input path rather than a + separate gameplay-input stack. +### Evidence + +Function-map rows for `shell_controller_window_message_dispatch`, + `shell_drain_pending_window_messages`, `shell_input_state_init`, + `shell_input_apply_window_key_transition`, `shell_input_snapshot_dispatch_state`, + `shell_input_cursor_inside_active_view`, `world_load_saved_runtime_state_bundle`, + `world_runtime_serialize_smp_bundle`, `world_entry_transition_and_runtime_bringup`, + `simulation_frame_accumulate_and_step_world`, `game_message_window_service_if_present`, + `game_message_window_service_frame`, `shell_ensure_game_uppermost_window`, + `game_uppermost_window_construct`, `game_uppermost_window_handle_message`, + `game_uppermost_window_service_world_hotspot_band`, `world_view_set_focus_position_xyz`, + `world_view_apply_screen_delta_to_focus_position`, + `world_view_pan_relative_offset_in_camera_plane`, `world_view_seed_keyboard_binding_slot_pairs`, + `world_view_service_keyboard_turn_pan_and_zoom_bindings`, `world_view_step_heading_quadrant`, + `world_view_step_zoom_bucket`, `world_view_should_drive_primary_pan_channel`, + `world_view_should_drive_secondary_pan_channel`, `world_view_service_shell_input_pan_and_hover`, + `world_seed_default_chairman_profile_slots`, `world_build_chairman_profile_slot_records`, + `world_conditionally_seed_named_starting_railroad_companies`, + `profile_collection_count_active_chairman_records`, + `profile_collection_get_nth_active_chairman_record`, + `scenario_state_set_selected_chairman_profile`, + `scenario_state_get_selected_chairman_profile_record`, + `scenario_state_get_selected_chairman_company_record`, `start_new_company_dialog_open`, + `start_new_company_dialog_commit_create_company`, `start_new_company_request_create_company`, + `shell_company_list_format_company_or_start_row`, + `shell_company_list_activate_or_shift_center_company`, `shell_company_list_window_refresh_rows`, + `shell_company_list_window_handle_message`, `shell_company_list_window_construct`, + `shell_company_detail_window_refresh_controls`, `shell_company_detail_window_construct`, + `shell_company_detail_window_handle_message`, `shell_station_detail_window_construct`, + `shell_station_list_window_construct`, `shell_station_list_window_handle_message`, + `shell_station_pick_window_construct`, `shell_station_pick_window_populate_station_rows`, + `map_editor_chairman_slot_panel_construct`, `map_editor_chairman_slot_panel_refresh_slot_list`, + `map_editor_chairman_slot_panel_refresh_selected_slot`, + `map_editor_chairman_slot_panel_refresh_slot_counters`, + `map_editor_chairman_slot_panel_cycle_selected_slot_profile`, + `map_editor_chairman_slot_panel_handle_message`, `map_editor_available_chairman_panel_construct`, + `map_editor_available_chairman_panel_handle_message`, + `map_editor_scenario_metadata_panel_refresh_briefing_mode`, + `map_editor_scenario_metadata_panel_refresh_controls`, + `map_editor_scenario_metadata_panel_handle_message`, + `map_editor_scenario_special_conditions_panel_construct`, + `map_editor_scenario_special_conditions_panel_handle_message`, + `map_editor_economic_cost_slider_panel_construct`, `map_editor_economic_cost_slider_dispatch`, + `station_place_refresh_category_controls`, `station_place_format_selected_site_summary`, + `station_place_format_preview_panel`, `station_place_select_category_and_refresh`, + `station_place_world_surface_sync_and_dispatch`, `station_place_window_handle_message`, + `station_place_window_construct`, `station_place_window_service_frame`, + `track_lay_window_refresh_controls`, `track_lay_window_construct`, + `track_lay_window_service_frame`, `track_lay_window_handle_message`, and + `simulation_service_periodic_boundary_work`, plus the shell-input disassembly around `0x0054f290`, + `0x0054e880`, `0x0054e9c0`, `0x0054ea20`, `0x0054eb10`, and `0x0054ee50`, + the world-view setup and service branches around `0x00439e40`, `0x0043d740`, `0x0043db00`, + `0x0043cb00`, and `0x0043cc30`, the `319` setup-side branches around `0x004377a0`, `0x00437220`, + `0x00477820`, `0x00477860`, `0x0047d440`, `0x004c6c30`, `0x004c6f30`, `0x0047d080`, `0x0047d120`, + `0x0047d320`, `0x004c2ca0`, `0x004c5540`, `0x004c56a0`, `0x005068c0`, `0x005071e0`, `0x005074c0`, + and `0x005076c0`, the direct summary-field helpers around `0x00434870` `0x00434890` and + `0x004348c0`, the company-link writers at `0x00427c70` and `0x00427d74`, the company constructor + at `0x00428420`, the startup-company branch around `0x00470e48`, the shell company-list strings + `266` `<>`, `267` `You are the chairman of the %1!`, `268` `The %1 has no + chairman at the moment.`, `269` `%1 is the chairman of the %2.`, `270` `Double-click for + details.`, and `2992` `Shift-Click to center on this company's primary station.`, the + `CompanyDetail.imb` and `CompanyDetail.win` resource strings in `.rdata`, the `StationDetail.imb`, + `StationDetail.win`, `StationList.win`, and `StationPick.win` resource strings in `.rdata`, the + shell editor window branches around `0x004c9da0`, `0x004ca010`, `0x004ca1c0`, `0x004ca540`, + `0x004ca670`, `0x004ca790`, `0x004ca980`, `0x004cb2b0`, `0x004cb4a0`, `0x004cb6f0`, `0x004cb8e0`, + `0x004cc250`, `0x004cc2d0`, `0x004ceb90`, and `0x004cecc0`, the localized chairman-slot strings + `2997` through `3001` `Optional` `Mandatory` `Human or Computer` `Computer` and `Human`, the + localized scenario-editor strings `1483..1492` `Description:` through `Type the briefing for this + map.`, the localized summary strings `1035` `%1 out of %2 are selected.` and `1053` `Special + Conditions In Effect`, the 40-entry persona availability page under `0x5aa0..0x5b03`, the 36-entry + special-condition table at `0x005f3ab0` covering ids `2535..2563`, `2874`, `3722`, `3835`, `3850`, + `3852`, and `3920`, the static persona table at `0x005f2d28`, the selector array at + `0x006cec7c+0x87`, the persona collection at `0x006ceb9c`, the localized persona strings in + `Data/Language/RT3.lng` including `2730` `Unassigned`, the named-chairman range `2731+`, and the + neighboring biography range `2495+`, plus the seeded railroad-name strings `575` `Missouri + Pacific`, `576` `New York Central`, and `577` `Grand Trunk Railroad`, the StationPlace.win + constructor plus category, dispatcher, rotation-circle, shared-world-surface, preview-build, and + recurring service branches around `0x00507a90`, `0x00507b90`, `0x00508550`, `0x00508730`, + `0x00508880`, `0x00508bb0`, `0x005091b0`, `0x00509d80`, and `0x0050a530`, the StationPlace string + cluster `Place a small station` 2197 `Place a medium station` 2198 `Place a large station` 2199 + `Place a service tower` 2200 `Place a maintenance facility` 2201 `Place a non-station building` + 2202 `Scroll through building styles.` 2203 `When placing the building, it will strictly adhere to + the rotation specified by the circle above.` 2206 `When placing the building, it will rotate + itself as needed to orient to track or avoid obstacles.` 2207 `Click to rotate the building. You + can also use bracket keys [ and ] to rotate buildings.` 2208 and the architecture-style labels + `Clapboard` 2667 `Kyoto` 2668 `Persian` 2669 `Southwest` 2670 `Tudor` 2671 and `Victorian` 2672, + the TrackLay.win constructor and dispatcher family around `0x0050d2d0`, `0x0050e400`, + `0x0050e070`, `0x0050e1e0`, and `0x0050e5c0`, the localized `Never` through `Common` strings 615 through 618, + the track-lay strings `Bulldoze` 1721 `Lay single track.` 2054 `Lay double track.` 2055 and 3114, + and the deeper shared bulldoze helper at `0x0044b160`. That helper is no longer just a vague + proximity scan: it validates the active company unless editor mode is active, emits the exact + RT3.lng bulldoze rejection ladder `419..424`, reads company cash through `0x0042a5d0`, + debits approved bulldoze cost through `0x0042a080`, and then scans nearby route entries, + linked structures, city-or-region records, route blockers, and placed structures before + committing the mutation. The nested tool-side entry is tighter now too: `0x0050e070` increments + the TrackLay reentry guard, snapshots several live route-owner fields from `0x006cfca8` into the + tool object, refreshes tool-local state through `0x0050dab0`, and only then tails into the later + restore or service branch `0x0050d1e0`. That tail is now tighter too: `0x0050d1e0` resets the + route-owner search state through `0x0049ad90/0x00495540`, drops invalid cached route ids from the + TrackLay tool or deletes non-admitted live entries when route latch `[route+0x118]` is set, + clears `[tool+0x78]`, and then conditionally refreshes shell presenter slot `[presenter+0x3741]` + through `0x00523e20`. The destructor side is tighter too: `0x0050db10` restores the TrackLay + vtable, re-enters that same cleanup tail, runs the route-owner post-change sweep + `0x004a3db0`, clears singleton `0x006d1a8c`, conditionally replays world follow-ons around + `0x00453510`, and only then tails into the common shell destroy path `0x0053f7d0`. Two smaller + TrackLay-side helpers are tighter now too: `0x0050dc00` refreshes the version-gated action rows + `0x986a..0x986c` plus `0x9872` before re-entering the main control refresh, and `0x0050dc80` + owns the active route-latch branch that either forwards into `0x004a00b0` or clears route latch + `[0x006cfca8+0x118]` plus local byte `[tool+0x82]`. The broader shared route or hit-test owner + under both message and recurring service is now tighter too: `0x0050dce0` first drops any cached + tool route id, then either seeds or updates the current route-owner selection from a world-surface + hit test through `0x00448ac0`, `0x00493600`, `0x0049ace0`, and `0x0049b180`, or refreshes the + active route-owner path through `0x004955b0`, `0x00493cf0`, and `0x004a04c0`, with the cleanup + side posting the fixed shell payload and optionally deleting route ids `[+0x125]` and `[+0x129]`. + The smallest active-route companion is tighter now too: `0x0050dab0` only runs when latch + `[0x006cfca8+0x118]` and route id `[+0x125]` are both live, then resolves that entry, re-enters + `0x0049afe0`, `0x0048b660`, and `0x0049b070`, and returns. + dispatching the selected delete branch through `0x004937f0`, `0x004941a0`, `0x0048abf0`, or the + surrounding placed-structure virtual slot `+0x58`. That makes the TrackLay `Bulldoze` mode + tighter than before: the tool-side mode latch at `0x00622b0c == 0x40` is only the front-end + selector, while the actual world-side bulldoze choice and failure policy sits under `0x0044b160` + and is reused by neighboring world-surface callers beyond TrackLay itself. + the TrackLay preference strings `Auto-Hide Trees During Track Lay` 1838 `If 'Auto-Hide Trees + During Track Lay' is checked, trees will automatically be reduced to small stumps whenever you are + in track laying mode.` 1839 `Auto-Show Grade During Track Lay` 3904 and `If 'Auto-Show Grade + During Track Lay' is checked, you'll see the grade number over the track while laying track - + useful for trying to keep your slopes to a minimum.` 3905, the electrify-all confirmation and + failure strings 3083 3084 3837 and 3900, the binding-registry lookup path at `0x0045f370`, the + registration block at `0x00460769` through `0x004608e7`, and the localized labels in + `Data/Language/RT3.lng` ids `3466` through `3473`. +### Open Questions + +Current evidence grounds the shell-controller-backed input and frame path as the + only coordinator after world entry; no separate outer gameplay loop or gameplay-only input + object is grounded yet. The new setup-pipeline evidence also points the same way: the + currently grounded chunked burst path at `0x00437b20` now looks subordinate to + `world_run_post_load_generation_pipeline` rather than to the ordinary speed controls, and even + there it still reuses the same lower stepper and pumps shell work between chunks instead of + revealing a detached gameplay loop owner. The player-facing speed-control family is now cleaner + too: `world_set_game_speed_mode` owns the bounded `Paused` through `Very Fast` ladder plus the + hidden `Ultra Fast 6..9` extension, `world_toggle_pause_or_restore_game_speed` uses `[this+0x1d]` + as the resume slot, and the multiplayer host restriction now looks attached to that same setter + family rather than to the setup-side burst helper. The frame-owned shell coupling is tighter now + too: inside `simulation_frame_accumulate_and_step_world` itself, one direct branch opens or + focuses `LoadScreen.win` through `shell_open_or_focus_load_screen_page`, and the post-step + shell-window ladder also probes several sibling shell windows by the same presence-plus-dirty + pattern, including the live `LoadScreen` singleton, the shared callback-driven custom modal, the + shared file-options dialog, `SettingsWindow.win`, the now-grounded `Overview.win` and + `BuildingDetail.win` singletons, the adjacent tool-window strip now grounded as + `Bulldoze.win`, `ChangeHeight.win`, `ChangeTrees.win`, `PaintRegion.win`, `PaintSound.win`, + `PaintTerrain.win`, `PaintTerritory.win`, and `StockBuy.win`, and now the shell-side + `Trainbuy.win` singleton too. The `SettingsWindow.win` side is tighter now too: + `shell_settings_window_rebuild_hotkeys_list_control_from_sorted_binding_report` `0x004fec60` + rebuilds the hotkeys list control `0x757a` from the same sorted binding-report iterator + `0x0045f250`, using the temporary `0x88`-stride list model at `0x006d1354` before restoring the + previous selection. The message owner above it is bounded now too: + `shell_settings_window_handle_message` `0x004fede0` is the actual dispatcher for the singleton, + and its currently grounded hotkeys cases are the reset-to-defaults path + `0x00500147 -> 0x00461120(0) -> 0x0045f550 -> 0x004fec60` and the selected-row reassignment path + `0x00500186..0x0050022b`, which resolves one chosen hotkey row from control `0x757a`, validates + the destination bucket through `0x0045ed90`, skips Enter and Escape, expands the compact modifier + code through `0x0045ed70`, commits the rebucket through `0x0045ef00`, and then rewrites the same + report file plus rebuilds the list. The page-refresh side is bounded now too: + `shell_settings_window_refresh_selected_page_controls` `0x00500410` republishes the category + strip `0x7533..0x7540`, uses the local in-refresh guard byte `0x006d135d`, and then dispatches + the current page through the `0x005005e0` table; page `7` is now directly grounded as the + hotkeys page because it dispatches into `0x004fec60`. The category table at `0x00622870` now + grounds the whole page order as `Gameplay`, `Sound`, `Graphics`, `Model Detail`, `Draw Distance`, + `Textures`, `Miscellaneous`, `Hot Keys`, `Scrolling`, `Camera Controls`, `Dialogs`, + `Miscellaneous`, and `Sandbox Options`, with only the second dword in each table row still + unresolved as a small subgroup or style flag. Several page bodies are now grounded too: + `0x004fda20` is the `Gameplay` refresh owner, `0x004fdb90` the `Sound` refresh owner, + `0x004fe770` the top-level `Graphics` refresh owner, `0x004fe960` the `Model Detail` refresh + owner, `0x004feb20` the `Draw Distance` refresh owner, `0x004febd0` the `Textures` refresh + owner, `0x004fdd70` the first `Miscellaneous` refresh owner, `0x004fdf20` the `Scrolling` + refresh owner, `0x004fdfd0` the `Camera Controls` refresh owner, `0x004fd940` the `Dialogs` + refresh owner, `0x004fd730` the later `Miscellaneous` refresh owner, and `0x004fd8d0` the + `Sandbox Options` refresh owner. The neighboring companion helpers are tighter now too: + `0x004fd550` refreshes the `Draw Distance` companion strip under controls + `0x7566/0x7596/0x7560/0x7562/0x7564`, `0x004fd650` does the same for the `Textures` companion + strip under `0x756e/0x756a/0x756c/0x7570`, `0x004fe4c0` rebuilds the graphics custom-resolution + list on `0x7553` from the live display-mode table filtered to `640x480 .. 1600x1200` and + formatted through `%1x%2`, and `0x004fe6f0/0x004fe730` are the small primary-selector mirror + helpers for `Draw Distance` `0x755f` and `Textures` `0x7569`. The `Camera Controls` page is + stronger now too: `0x7587` is the day-night cycling selector rooted at `Normal day/night + cycling` through `Frozen at 11pm`, while `0x7588` is the weather-cycling selector rooted at + `Normal weather cycling` through `Frozen at storms`. The callback strip under the dispatcher is + tighter now as well: `0x004fefb0` is the sound-backend selection-change owner for + `0x7551/0x7550`, `0x004ff070` is the custom-resolution selection owner, `0x004ff0d0` the + top-level graphics selector-change owner, `0x004ff1b0` the main draw-distance selector-change + owner, `0x004ff2e0` the textures selector-change owner, and `0x004ffbc0` the graphics + custom-resolution or range-refresh branch that persists `engine.cfg`, rebuilds the custom list, + and republishes `0x7555/0x7578`. The small wrapper `0x00500620` is the nonreentrant `if live, + refresh page` gate above that body. The tiny helper strip beneath those branches is at least + bounded now too: `0x00531640/0x005316d0` query the active sound-backend index and availability + flag from the shell audio service, `0x0053ef60/0x0053ef70` read the graphics-backend status + slots used by controls `0x757c/0x759a`, and `0x0051fd40/0x0051fd60` are the small graphics-range + custom-mode flag and scalar queries behind `0x7555/0x7578`. The next apply-strip under the same + family is tighter now too: `0x004fe270` applies a changed custom-resolution tuple and persists + it, `0x004fe2d0` applies the top-level graphics selector then republishes `0x757c/0x759a`, + `0x004fe3b0` applies the draw-distance selector then refreshes `0x004fd550`, `0x004fe400` + applies the textures selector then refreshes `0x004fd650`, `0x004fe140` is the small composite + backend-status predicate used by the timer-gated graphics service branch, and `0x004fe160` is + the sound-backend follow-on refresh path. The graphics service tail is tighter now too: + `0x004ffafb` is the timer-gated backend-service-plus-graphics-page repaint branch using + `0x0051d890` against deadline `0x006d136c`, the follow-on calls `0x0053f170/0x0053f2c0`, and a + shortened `60` ms rearm after it repaints `0x004fe770`, while `0x004ffb64` is the sibling + backend-service branch that uses `0x0053f0f0/0x0053f210` and only raises the shell refresh latch + without repainting the page directly. The same `MouseCursor.cpp` owner family is tighter now too: + `0x0053f000` is the live cursor-shape selector that lazily loads native handles, updates the + shell-side presentation payload, and toggles cursor visibility on the `0 <-> nonzero` boundary; + `0x0053f0f0`, `0x0053f170`, and `0x0053f210` are the three local hidden or release-transition + branches that mirror shell latches `[0x006d4024+0x11473a/+0x11473e]`; `0x0053f2f0/0x0053f310` + are the nested hold-counter helpers; `0x0053f330` is the constructor-side reset and latch-sync + owner; `0x0053f400` is the coarse global-latch service; and `0x0053f450` is the inside-view + watcher paired with `shell_input_cursor_inside_active_view` `0x0054f540`. The same pair is now + grounded on the heavier save/load paths too: `world_entry_transition_and_runtime_bringup` + `0x00443a50` pushes the hold at `0x443b04` before the larger startup-dispatch and staged + rehydrate work, then pops it at `0x444c03` after the late world or shell rebuild tail; the live + `.smp` serializer `world_runtime_serialize_smp_bundle` `0x00446240` does the same thing through + `0x446271` and `0x446d09` around its bundle-write and fixed status-publish span. The exact + save/load-side status stack under those spans is tighter now too: `0x004422d0/0x00442330` push + and pop shell dwords `[0x006cec74+0x140/+0x13c/+0x138/+0x144]` plus startup byte + `[0x006cec78+0x4c74]` through `0x0062be90`, while `0x004423a0/0x004423d0` layer the same band + under active TrackLay.win and StationPlace.win service. The per-frame tail is + tighter now too: `0x0054f5b0` queues one 12-dword shell-input event record into the rotating + ring at `[input+0x128]`; `0x0054f6a0` and `0x0054f6b0` are the two neighboring fixed-value + seeders for shared phase scalar `0x00d93850` used by shell-side branches `0x00538b72`, + `0x0052819d`, and `0x0052b9f8`; and `0x0054f6c0`, `0x0054f6d0`, and `0x0054f6e0` are the tiny + primary-motion scalar reset, snapshot, and restore leaves that `0x0053f4e0` uses around the + later cursor-presentation pass. The graphics-range + callback strip beneath that is bounded now too: `0x004ffd10` is the user-facing custom-mode + toggle rooted at control `0x7555`, using + `0x0051fd00`, `0x0051fd40`, `0x00520fd0`, and the localized dialog ids `0x0e16/0x0e17/0x0e93`; + `0x004ffe72` flips the graphics-range scalar through `0x00521030`; and the adjacent + display-runtime toggles `0x004ffea4`, `0x004ffeff`, `0x004fff2d`, `0x004fff59`, `0x004fff85`, + `0x004fffde`, and `0x0050000a` now bound a compact persisted graphics or model-detail option + strip over controller fields `[0x006d4024+0x1146eb]`, `[+0x114697]`, `[+0x1146e9]`, `[+0x1146b8]`, + `[+0x1146af]`, `[+0x1146a8]`, and `[+0x1146e3]` rather than one anonymous tail blob. The lower + setter layer is tighter too: `0x0051fd00` is the current `has live custom payload` predicate for + the graphics-range family, `0x00520fd0` stores the custom-mode flag and re-applies the current + range when possible, `0x00521030` stores the scalar and re-applies it when the graphics mode is + live, and `0x0051d890` is the shared elapsed-tick helper over the bootstrap-seeded tick count. + The same local support strip is broader now too: `0x0051e1d0` is the mode-`0` alternate sibling + of the packed preview-color ramp at `0x0051dfc0`; `0x0051e430/0x0051e480` are the shared + path-openability and file-size probes; `0x0051e4e0/0x0051e560` are the bounded ASCII clipboard + export and import helpers; `0x0051e6e0` is the nonempty digits-only predicate used by nearby + text-entry validation branches; `0x0051e720/0x0051e740` own the active debug-log filename + (`rt3_debug.txt` / `language_debug.txt`) and the one-time `.\\data\\log\\%s` separator write; + and `0x0051e810` is now grounded as the `MouseCursor.cpp` `ShowCursor` refcount and live-position + sync helper that the warning-modal strip also reuses. The immediate shell-controller strip under + that is tighter now too: `0x0051ea80` is the small core-state reset plus default seeding path + rerun by `0x0051ff90`; `0x0051f000` registers the static `World` window class through wndproc + `0x0054e3a0`; `0x0051f070/0x0051f080` and `0x0051f090/0x0051f0a0` are the paired controller + accessors and setters for the live presentation owner and world-basis owner; `0x0051f0c0`, + `0x0051f0d0`, and `0x0051f0e0` are the small indexed input-subobject flag write or query helpers + beneath the shell window-message path; `0x0051f100` materializes the active display-mode tuple + from `[controller+0x34]` and selector `[+0x11421e]`; `0x0051f1a0` is the current + graphics-mode-byte accessor over `[controller+0x114226]`; and the nearby shared shell-presenter + helper `0x00527de0` is now bounded as the common scalar-caption publisher reused by several tool + windows. It scales one caller float through `0x005dd158`, forwards that value into nested + presenter field `[this+0x364d]` through `0x0052ea90`, scales a second caller float through + `0x005c8568`, and stores that auxiliary caption-side weight in `[this+0x3728]`. Grounded callers + now include `Bulldoze.win`, `ChangeTrees.win`, the world-surface brush ordinal setter, + `PaintRegion.win`, `PaintSound.win`, `PaintTerrain.win`, and `PaintTerritory.win`, so this is the + shared shell scalar-caption lane rather than a window-specific text formatter. The neighboring page-owned dispatcher + leaves are tighter now too: `0x004ff58a`, `0x004ff5b6`, + and `0x004ff5e6` are direct persisted toggles for the later `Miscellaneous` input page fields + `[0x006d4024+0x1146d7]`, `[0x006cec74+0x28b]`, and `[0x006cec74+0x283]`, with the last one also + republishing a `Game.win` affordance through `0x004dd8d0`; `0x004ff637`, `0x004ff667`, + `0x004ff697`, `0x004ff6c7`, `0x004ff6f7`, and `0x004ff727` are the page-owned toggle leaves for + the `Dialogs` page fields `[0x006cec74+0xf8]` and `[+0x26b/+0x26f/+0x273/+0x277/+0x27b]`; and + `0x004ff757`, `0x004ff796`, `0x004ff7c6`, and `0x004ff84e` are the remaining compact `Gameplay` + page toggle leaves over `[0x006d4024+0x114742]`, `[0x006cec74+0x0a8]`, `[+0x263]`, and + `[+0x309]`, with the `+0x114742` path also nudging `BuildingDetail.win` and the `+0x263/+0x309` + paths triggering narrow live-tool follow-ons. The next tiny leaves are bounded now too: + `0x00500036` is the direct apply leaf for the graphics-misc option family mirrored through + `0x00484af0(0x0c)` into control `0x7586`; `0x0050006c/0x0050009c/0x005000cc` are the shared + setup-config toggles over `[0x006cec74+0x247/+0x24b/+0x243]` that persist the same three booleans + later mirrored by `Setup.win` controls `0x0e88/0x0e89/0x0e8a`; and `0x005000fc` is the direct + scrolling-page boolean-companion setter for `[0x006cec74+0x120]` and control `0x7585`. + neighboring stock-buy lane is tighter now too: `0x00433aa0` is the shared `StockBuy.win` + availability gate, rejecting when scenario toggle `[0x006cec78+0x4aa7]` is set or when no + selected-company id is present at `[scenario+0x21]`. The direct shell opener `0x00440660` and + the page-side launcher `0x004de50f` both use that gate before entering detail-panel mode `0x0c`, + whose same-mode refresh tail re-enters `0x00493150`. The shell-side control strip under that + window is tighter now too: `0x0050a660` is the raw selected-chairman-row setter for global + `0x006d19f4`, `0x0050a570` is the selected-company stock-data panel callback wired to control + `0x3aa0` and feeding the shared stock formatter `0x004c0160`, `0x0050a6d0` publishes the current + selected company id into `0x00622b00` and restyles control `0x3a9b`, `0x0050a670` is the shared + live-window refresh wrapper hit by the buy/sell chairman mutators after they touch + `[profile+0x154]` and the per-company holding band, `0x0050a5e0` is the constructor-wired + invalidation callback for control `0x3a9a`, and `0x0050a6a0` is the unconditional invalidation + sibling used by the local in-window trade branches after they commit the rounded block. One level + higher, `0x0050a730` is now bounded as the broad row/card refresh owner: it walks the active + chairman profiles through `0x00477820/0x00477860`, lays out the selected and unselected profile + cards through the cached widget roots `0x006d19d8/0x006d19dc/0x006d19e8/0x006d19ec`, resolves + persona/name labels through `0x00476bb0`, and pulls the same currently grounded metric lanes + from `0x00476320`, `0x00476780`, and `0x00476c20`. The selected-company panel under control + `0x3a9a` is separate and broader: `0x0050ae50` is now bounded as the main selected-company + summary renderer, resolving the current company through `0x00518140`, the current chairman row + through `0x00477860`, choosing one of panel roots `0x006d19e8/0x006d19ec`, and then formatting a + mixed text-plus-metric surface through helpers such as `0x00423eb0`, `0x00426b10`, and + `0x00426ef0`. The adjacent publish side is bounded too: `0x0050b910` formats the selected company + ownership line through localized ids + `0x0e10/0x0e11/0x0e12` plus the resolved company and owner labels, and `0x0050ba00` is the + shared selected-company summary refresh tail over controls `0x3a9a/0x3a9b`; `0x0050c130` is the + narrow mode-`0x0b` refresh wrapper that re-enters that tail only when the current detail-panel + object is actually `StockBuy.win`; and `0x0050c470` is the selected-company clamp/setter sibling + that republishes `0x00622b00` before re-entering the same summary tail. The payload-driven trade + commits are explicit now too: `0x0050c150` resolves one chairman record from payload + `[profile_id, company_id]`, derives the rounded buy block through `0x00476e50`, and commits it + through `0x00477110`; `0x0050c1f0` is the same sibling for the rounded sell block and + `0x00476460`. Both also emit the local selected-chairman shell cue before the shared + `StockBuy.win` refresh tail when the payload chairman matches the currently selected chairman in + `0x006cec78`. The message-owner and teardown side are bounded now too: `0x0050bbe0` is the real + `StockBuy.win` dispatcher, with `0xcb` control bands for chairman-row selection + `0x3afc..0x3b5f`, company-row selection `0x3d54..0x3db7`, company wrap/step controls + `0x3aa1..0x3aa3`, and toggle-byte writes `0x3aad..0x3ab2`, while `0xca` owns the local buy row + band `0x3c8c..0x3cef` and sell row band `0x3cf0..0x3d53`. The buy-side confirmation path now has + one extra leaf too: `0x0050a600` is the callback-driven tutorial gate for the localized + `0x0292` confirmation modal, opening the sibling tutorial modal `0x0e8c` only on `0xcb` control + `0x03f4` while tutorial flag `0x006d3b4c` is live. The destructor counterpart `0x0050bac0` + releases the cached roots `0x006d19d8..0x006d19ec`, frees the per-company cached stock-data + handles in `0x006d1748`, invalidates controls `0x3b60` and `0x3e4e`, clears singleton + `0x006d19f0`, and then tails into the common shell-object teardown. The + remaining adjacent detail-panel gates are now at least structurally bounded too even though their + target families are still unnamed: `0x00434db0` layers extra scenario toggle `[0x006cec78+0x4a7f]` + on top of the broader company-list/detail gate before allowing mode `0x0b`, while `0x00434e20` + only hard-blocks mode `0x06` when all three toggles `[+0x4ab3/+0x4ab7/+0x4abf]` are set and + otherwise, outside editor-map mode, still requires a selected-company id before the direct + openers `0x00440530` and `0x00440690` hand those modes to `shell_detail_panel_transition_manager`. + The + train-buy family is no longer just an unnamed probe pair either: the opener path is now grounded + under the same shell-owned cadence through `shell_can_open_trainbuy_window_or_warn` and + `shell_open_or_focus_trainbuy_window`, and its current family semantics already extend beyond a + bare locomotive picker into selected-train upgrade summary and route-edit affordances. The direct + shell opener `0x004406c0` now aligns with the page-side launcher `0x004de7d9`: both use + `shell_can_open_trainbuy_window_or_warn` `0x00433b00` before calling + `shell_open_or_focus_trainbuy_window` `0x00512c50`. The + selected-train side is tighter now too: we have explicit query helpers for the selected train + record, id, validity, and company ownership, plus one explicit ownership-mismatch warning modal. + That same pass also clarified one boundary we should not conflate: the neighboring shell family + rooted at `0x006d3b20` is now grounded separately as `TrainDetail.win`. It reuses the same + selected-train context and some of the same helpers, but it is not the same `Trainbuy.win` + singleton family. The `TrainDetail.win` side now has its own constructor, opener, refresh path, + and message owner above the broader train-command strip. Its inner `0xcb` strip is tighter now + too: one bounded branch is the selected-train engine-replacement or trainbuy handoff lane using + warning ids `593/594`, and another is the selected-train retirement lane using `595/596/597` + with either a local teardown path or multiplayer opcode `0x37`. The remaining train-command + family is narrower too: the shared `0x33`-stride helper trio at `0x004b2f00`, `0x004b3000`, and + `0x004b3160` now looks like a real train route-stop or waypoint list rather than a generic row + buffer, and route-entry flag byte `+0x28` now has one grounded top-level split: sign bit clear + entries are the live placed-structure-backed family, while sign bit set entries use the direct + route-node payload side. The helper `train_route_list_count_live_site_reference_entries` + `0x004b2b80` now counts the first family explicitly. One deeper lower-bit result is grounded too: + both `train_route_list_insert_staged_entry_at_index` and the auxiliary finalize helper + `train_finalize_aux_route_entry_buffer_preserving_subflags` `0x004a94b0` explicitly preserve + bits `0x40`, `0x20`, and `0x10` in the same flag byte during route-entry rewrites. Those bits are + also no longer copy-only: the neighboring shell helper + `shell_building_detail_refresh_flagged_service_capability_rows` `0x004b9a20` now consumes them to + restyle the `BuildingDetail.win` row bands `0x7d07..0x7d1c` and `0x7f58..0x801f`. The exact + player-facing labels for those rows are still open, but the subflags now have one real shell-side + consumer instead of only preservation logic. The broader `BuildingDetail.win` refresh family is + tighter too: `shell_building_detail_refresh_subject_cargo_and_service_rows` `0x004ba3d0` now + clearly owns the selected subject rows around `0x7d06`, `0x7d96..`, and `0x7d0e`, resolving + ordinary ids through the live candidate collection and the special express-side ids through the + embedded `AnyCargo.imb`, `AnyFreight.imb`, and `PassMail.imb` paths. The first fixed triplet is + now table-grounded instead of only inferred: `0x00621df8` seeds the short-label controls + `0x7dc8..0x7dca` with RT3.lng `494..496` `Any Cargo`, `Any Freight`, and `Any Express`, while + `0x00621e10` seeds the adjacent `0x7e90..0x7e92` icon-name triplet with `AnyCargo`, + `AnyFreight`, and `PassMail` before `%1.imb` formatting. RT3.lng also tightens the longer popup + side now: `0x00621e04` feeds the first clickable selector triplet `0x7f58..0x7f5a` with + `494/497/498`, so the help text there is `Any Cargo`, `Any Freight\n(Freight is everything but + Passengers, Mail, and Troops)`, and `Any Express\n(Express is Passengers, Mail, and Troops)`. + The sibling special service rows still align to `Dining Car` and `Caboose`. The extracted + `BuildingDetail.win` blob now sharpens the resource boundary too: its embedded text table is + currently sparse rather than rich, exposing the help line for `0x7d01`, repeated + `BuildingDetail.imb` asset strings, and one standalone caption entry `Cargo`. That makes + `Cargo` the strongest current resource-side anchor for the row header around `0x7d06`. The + ordinary deeper rows are tighter now too: they do not look like hidden caption-table entries, + but like live candidate-derived rows. The current path validates each ordinary id through + `indexed_collection_entry_id_is_live` `0x00517d40`, resolves the concrete candidate record + through `indexed_collection_resolve_live_entry_by_id` `0x00518140`, and then reuses candidate + field `[record+0x04]` as one shared stem for both the row asset `%s.imb` path and the + neighboring display-label lookup through + `localization_lookup_display_label_by_stem_or_fallback` `0x0051c920`. That lookup is now + bounded too: it scans the static stem table at `0x006243c8`, already grounding entries such as + `Alcohol`, `Aluminum Mill`, `Automobiles`, `Bauxite`, and `Big Boy` against RT3.lng + `3202..3220`, and only falls back to localized id `3866` when no table entry matches before the + fixed `0x384..0x386` express-side triplet takes over. One neighboring candidate-side helper is + tighter now too: `structure_candidate_query_route_style_or_local_availability_metric` + `0x0041e650` shares the same route-style byte at `[candidate+0x46]`, returning the cached local + float at `[candidate+0x5a]` for ordinary candidates but switching route-style rows to one + normalized count over the world-side route-link collection `0x006ada90` keyed by candidate class + `[candidate+0x3e]`. That collection is tighter now too: it is constructed during world bring-up + by `placed_structure_route_link_collection_construct` `0x00468110`, and current grounded + creation flow through `placed_structure_route_link_allocate_site_pair_for_candidate_class` + `0x00467f50` seeds class byte `+0x10`, a masked initial state template, and the strongest + current creation-side site-pair fields at `+0x0c` and `+0x0e` before + `placed_structure_route_link_attach_site_owner` `0x00467eb0` links the new route-link record + into the placed-structure-owned chain at `[site+0x272]`. The owner-side split is tighter now + too: route-link field `+0x08` is the separate route-node-style owner anchor used by + `placed_structure_route_link_attach_route_node_owner` `0x00467f20`, while `+0x0a/+0x0c/+0x0e` + now read as the site-reference triple matched by + `placed_structure_route_link_collection_remove_links_touching_site_id` `0x004681f0`. Creation + flow now sharpens that further: `+0x0c` is the strongest current candidate for the stable + first-site field seeded before owner attachment, `+0x0a` is the mutable owner-site anchor + installed by the attach helper, and `+0x0e` is the stable second-site field. One more split is + tighter now too: `placed_structure_route_link_recompute_endpoint_pair_state` `0x00467c30` + currently uses `+0x0a` and `+0x0e` as the active endpoint site pair while recomputing state + byte `+0x12`; `+0x0c` is still not directly read there. The family also has a clearer release + and refresh side now: `placed_structure_route_link_release_and_detach` `0x004680b0` rolls back + the class counters and then tails into `placed_structure_route_link_detach_current_owner_chain` + `0x00467df0`, while + `placed_structure_route_link_collection_recompute_all_endpoint_pair_state` `0x004682c0` + explicitly reruns the per-record endpoint-pair reconciler across the whole live route-link + collection. One layer above that, + `placed_structure_route_link_rebuild_route_style_grid_counters_and_endpoint_state` + `0x00468300` now looks like the full-family refresh owner: it clears three route-style class + lanes in the world-grid tables rooted at `[0x0062c120+0x2129]`, then clears bit `0x2` across + the live route-link records and reruns the endpoint-pair reconciler. That now lines up with the + visible shell split: non-route candidates keep the richer local metric and price lane, while + route-style candidates use one world-side route-link family instead. The emission side is + tighter now too: `placed_structure_try_emit_best_route_style_peer_link_for_candidate_class` + `0x0040fef0` scans the live placed-structure collection for one best peer site by + class-specific weight, distance window, and type gate, then only creates a new route-link + through `placed_structure_route_link_allocate_site_pair_for_candidate_class` `0x00467f50` when + `placed_structure_endpoint_pair_has_shared_route_entry_key` `0x0040fbe0` says the chosen site + pair does not already share a route-entry key. One layer above that, + `placed_structure_rebuild_route_style_candidate_scores_and_peer_links` `0x004101e0` now reads + as the broader per-site owner of this lane: it computes per-class route-style score scalars from + local site state and scenario multipliers, drives the first three route-style emission attempts, + and then continues into a larger descriptor-driven scoring phase. Inside that larger pass, + `placed_structure_accumulate_candidate_metric_or_emit_route_style_peer_link` `0x0042cab0` + now cleanly shows the split between ordinary candidates, which add directly into the local + route-style grid lane at `[site+candidate*4+0x103]`, and remapped route-style candidates, which + re-enter the peer-link emitter. One layer above that, the broader post-create or post-edit site + rebuild `placed_structure_finalize_creation_or_rebuild_local_runtime_state` `0x0040ef10` + conditionally re-enters `0x004101e0` with stack flag `1` when its local latch at `[site+0x29e]` + stays clear, so the route-style lane is no longer floating under an unnamed single-site caller. + The placement side is tighter now too: the direct constructor + `placed_structure_collection_allocate_and_construct_entry` `0x004134d0` is the shared allocator + immediately beneath the current placement-side callers before they hand the new site into + `0x0040ef10`, and the lower constructor + `placed_structure_construct_entry_from_candidate_and_world_args` `0x0040f6d0` now bounds the + actual field-seeding layer beneath that allocator. The old unresolved higher placement chooser is + bounded more cleanly now too: the `0x00403ed5` and `0x0040446b` direct-placement commits sit + inside one larger helper, + `city_connection_try_build_route_with_optional_direct_site_placement` `0x00402cb0`. That shared + heavy builder is now the common target of the compact wrapper `0x00404640`, the peer-route + candidate builder `0x004046a0`, the region-entry pair wrapper + `city_connection_try_build_route_between_region_entry_pair` `0x00404c60`, and the direct retry + paths inside `simulation_try_select_and_publish_company_start_or_city_connection_news` + `0x00404ce0`. Internally it now has three bounded lanes: + an early route-entry search or synthesis attempt through + `route_entry_collection_try_build_path_between_optional_endpoint_entries` `0x004a01a0`, + a single-endpoint direct-placement lane that scans `Maintenance` and `ServiceTower` candidates + and commits through `0x00403ed5 -> 0x004134d0 -> 0x0040ef10`, + and a later paired-endpoint fallback lane that seeds two endpoint candidates from the same stem + family, walks a temporary route-entry list, and commits through + `0x0040446b -> 0x004134d0 -> 0x0040ef10`. + That early lane can now be described more concretely: it can reuse supplied route-entry + endpoints, synthesize a missing leading endpoint from the caller's coordinates, seed the + route-store builder-state block, and then hand off to the deeper path-search core without + placing a new site. The previously vague side family at `0x006cfcb4` is tighter too: current + evidence now bounds it as a small auxiliary route-entry tracker collection with an allocator at + `0x004a42b0`, a refcount or destroy path at `0x004a4340`, a direct route-entry group-id setter + at `0x00489f80`, an endpoint-membership probe at `0x00494ed0`, a boolean-latch refresh or + owner-notify path at `0x00494fb0`, and a two-endpoint merge or bind helper at `0x00494f00`. + One smaller constructor-side ownership split is tighter now too: the cached `u16` chain fields + `[site+0x26e]`, `[site+0x270]`, and `[site+0x383]` are no longer free-floating. Constructor-side + helper `0x0041f7e0` prepends one new peer into that chain by storing the old head from + `[this+0x383]` into `[peer+0x270]` and then replacing `[this+0x383]` with the peer's own + placed-structure id `[peer+0x2a4]`; the direct resolver `0x0041f810` turns the cached head id + back into one live record through `0x0062b26c`; and the removal-side companion `0x0041f850` + removes one peer from the same chain before clearing `[peer+0x26e/+0x270]`. That caller split is + now strong enough to treat this as one cached single-link or predecessor-chain family beneath + placed-structure construction and rebuild rather than as unrelated scratch words. + That bind side is tighter now too: the trackers group route entries only when a route-key-like + value from `0x0048aa70`, the route-entry signature word `+0x22e`, and the boolean latch derived + from byte `+0x44` all agree. The deeper handoff under that lane is no longer anonymous either: + `route_entry_collection_search_path_between_entry_or_coord_endpoints` `0x0049d380` is now + bounded as the internal search core that runs the first candidate sweep, quality gates, and the + later route-extension fallbacks before returning one resolved route-entry id or `-1`. The first + sweep now has a bounded owner at `0x0049bd40`, and the two later fallback helpers are bounded as + the route-entry point-window coverage query `0x00494cb0` and the frontier-extension helper + `0x0049c900`. The math side is bounded more cleanly now too: the family reuses + `math_measure_float_xy_pair_distance` `0x0051db80` for its direct point-to-point scalar, + `math_compute_quadrant_adjusted_heading_angle_from_xy_pair` `0x004952f0` for heading-angle + construction, `math_normalize_subtracted_angle_delta_and_report_wrap` `0x004953c0` for wrapped + angle deltas, and now one tighter visual-side strip too: `0x00539230` applies one local + float-preset layout from state byte `[entry+0x218]`, `0x00539380` loads the matching + table-driven profile bands and optional display latch `[entry+0x44]`, `0x005394b0` exports four + consecutive `3*dword` triplet bands from the entry into caller buffers, and `0x005391b0` + releases one optional world-space attachment before the entry's vtable slot `+0x00` teardown + fires. The adjacent publish side is bounded too: `0x00539580` broadcasts one caller-supplied + three-scalar packet across the optional attached-handle list at `[entry+0x08]`, and + `0x005395d0` ensures that same list, adds one new handle, and immediately republishes one + aggregate scalar derived from local bands `[+0x18/+0x24/+0x30/+0x3c]` together with head lanes + `[+0x0c/+0x10]`. The next owner layer is tighter now too: `0x00539640` is the heavy derived-band + rebuild that turns those four triplets plus profile weights `[entry+0x1f5/+0x1f9/+0x1fd]` into + the larger scalar bands rooted at `[entry+0x63]` through `[entry+0x1d3]`, refreshes center + scalars `[entry+0x0c/+0x10]`, re-enters root query `0x00534490` several times, and conditionally + maintains the optional `0xc0`-byte display buffer at `[entry+0x1e3]` according to display-state + byte `[entry+0x44]`. The surrounding wrappers are coherent with that same ownership split: + `0x0053a740` copies caller triplets into `[entry+0x14/+0x20/+0x2c/+0x38]`, refreshes optional + attachment id `[entry+0x55]` through `0x00533e00/0x00533dd0`, and republishes center lanes + `[entry+0x1ed/+0x1f1]`; `0x0053a890` reprojects the stored triplets through `0x00534490` and + rebuilds; `0x0053a920` fills all four triplets from one uniform scalar before rebuilding; + `0x0053ac40` rebinds the root pointer, clears attachment state, and optionally rebuilds from the + current triplets; `0x0053aca0` is the concrete default constructor for the same route-entry + object family; and `0x0053ae10` is the construction-time root-bind plus state-profile-and-triplet + initializer. The attachment manager beneath that strip is tighter too: `0x0053a5b0` is the tiny + broadcast wrapper over current head lanes, `0x0053a5d0` is the heavier ensure-and-clone path + that seeds one new attached handle from the first live entry when a list already exists, and + `0x0053a6d0` tears that attached-handle list back down. The collection side is tighter too: + `0x00491af0` constructs the indexed + `0x006cfca8` owner beneath the world bundle-load path, and the later post-load `319` lane now + uses `0x00491c20` as a dedicated collection-wide refresh pass that re-enters `0x00539640` on + every live route entry. That keeps the route-entry visual or presentation side grounded as a real + sibling strip to the search and regrouping code, not loose per-caller scratch fields. + angle-delta checks, and `math_abs_double_with_crt_special_case_handling` `0x005a152e` for the + absolute-value side of the quality gates. Current evidence also bounds the threshold shape a + little more tightly: the initial sweep and later extension path both reuse one signed angle-bias + term `+/-0.181000038854627`, and the first sweep switches between a looser `1.4` and stricter + `1.8` quality multiplier depending on route-policy byte `4` or the broader display-runtime + preference `[0x006cec78+0x4c74]`, already grounded elsewhere as `Auto-Show Grade During Track + Lay`. + The small policy-byte semantics are still not fully closed, but current evidence is tighter than + before. Literal byte `1` is now the strongest current match for direct linked-site + endpoint-anchor creation or replacement, because the linked-site constructor and neighboring + repair branches around `0x00480463`, `0x00480a77`, and `0x00480b69` all feed that byte into + `0x00493cf0` before rebinding one chosen route-entry anchor through `0x0048abc0`. Literal byte + `2` now looks broader: the later world-side caller at `0x00480cd0` and the linked-site refresh + helper `placed_structure_refresh_linked_site_display_name_and_route_anchor` `0x00480bb0` both + reach `0x004a01a0` with both optional endpoint-entry ids unset and that byte, so the strongest + current read is a full linked-site route-anchor rebuild between optional endpoint entries rather + than the narrower direct creation lane. The TrackLay side now gives one tighter user-facing + anchor too: the live mode field `0x00622b0c` is already grounded as `Lay single track.` `0x1` + versus `Lay double track.` `0x4`, and the small mapper `0x004955b0` collapses that state into + the endpoint-policy bytes later passed to `0x00493cf0`, so the strongest current read is + `policy 1 = single-track endpoint synthesis` and `policy 4 = double-track endpoint synthesis`. + Bytes `1/2` are still the ones that enable the + auxiliary tracker lane in `0x004a01a0`, while byte `4` now reads more narrowly as the larger + company-side endpoint-synthesis charge inside `0x00493cf0`, because that helper feeds `-1` + versus `-2` into the saturating company counter helper `0x00423ec0` on `[company+0x7680]` + rather than skipping the company branch entirely. That counter is tighter now too: nearby + company initialization seeds it to `50` when scenario byte `0x4aaf` is enabled and to sentinel + `-1` otherwise, while the companion getter `0x004240a0` returns either the live counter or fixed + fallback `29999`. Current language-table correlation also gives `0x4aaf` a stronger + player-facing meaning: it is the live gate behind `Company track laying is limited...` and the + event variable label `Company Track Pieces Buildable`. So the current strongest read is + available track-laying capacity, not an abstract company route-budget. That site-side helper + also closes one adjacent ownership gap: beneath + `placed_structure_finalize_creation_or_rebuild_local_runtime_state` `0x0040ef10`, it rebuilds + one linked site's route-entry anchor and display-name buffer. That path is tighter now than just + “bind anchor then touch `0x006cfcb4`”: after the literal-policy-`2` rebuild succeeds it + re-enters `aux_route_entry_tracker_collection_refresh_route_entry_group_membership` `0x004a45f0`, + which can now be described more concretely. Its early prepass at `0x004a4380` can split one + mismatching adjacent subchain into a fresh tracker group; its later helper at `0x004a4ce0` can + transfer one compatible adjacent chain between neighboring groups; and the repair-side helper at + `0x004a4ff0` can reseed a whole route-entry component into a fresh tracker when the old group id + is missing or invalid. The regrouping pass also still rewrites compatible endpoint slots through + `0x004950f0` and refreshes one nearby cached-match payload band through `0x00495020` before the + helper resumes the name-buffer work. The remaining display-name side still matches the earlier + grounded text family: copy the resolved city name when available, append civic suffixes + `Township`, `New`, `Modern`, or `Renaissance`, append `Service Tower` or `Maintenance Facility` + on the linked-instance class branches, and otherwise fall back through the older + `Junction`..`Center` and `Anytown` text families. + The higher owner-refresh side of that same tracker family is tighter now too. The reusable gate + at `0x004a4c00` no longer looks like a stray predicate: it explicitly requires both route-entry + trackers to keep matching cached fields `+0x18/+0x1c/+0x1d/+0x1e` and both route entries to keep + their special side fields `+0x20e/+0x222` unset before adjacent-chain transfer is allowed. The + collection-wide traversal sweep at `0x004a5fc0` is bounded now as the connected-component refresh + owner over tracker field `+0x0c`, with a temporary queue at `[this+0x94]` and direct fallback + into the reseed helper `0x004a4ff0` whenever one neighboring route entry has lost valid tracker + ownership. Above both of those sits `aux_route_entry_tracker_collection_refresh_owner_adjacent_compatible_group_links` + `0x004a6360`, which now reads as the owner-side latch-change refresher invoked from + `0x00494fb0`: it starts from one owner route-entry id, confirms both bound endpoint entries agree + on the boolean class state implied by route-entry byte `+0x44`, and then probes both endpoint + sides for adjacent route-entry groups that can be absorbed through the `0x004a4c00 -> 0x004a4ce0` + gate-and-transfer pair. The sibling query side is bounded now too: + `aux_route_entry_tracker_collection_query_component_label_by_tracker_id` `0x004a6320` is the + dirty-aware accessor for tracker field `+0x0c`, while + `aux_route_entry_tracker_dispatch_route_entry_pair_metric_query` `0x004a65b0` is the remaining + mode-switched lower metric dispatcher beneath the heavier chooser at `0x004a6630`, forwarding + fixed route-entry-pair candidate sets into either `0x004a5280` or `0x004a5900` depending on the + shared hundredths-scaled build-version query + `runtime_query_hundredths_scaled_build_version` `0x00482e00` over `0x006cec74`. The current + caller thresholds `>= 0x67`, `>= 0x68`, `>= 0x69`, and `>= 0x6a` now line up with executable + build values `1.03`, `1.04`, `1.05`, and `1.06`, and the version source itself can come from + the multiplayer companion path as well as the local executable, so this split is no longer + best-read as a time- or era-side cutover at all. It now reads more cleanly as a pre-`1.03` + versus `1.03+` route-metric compatibility dispatcher. That lower split is tighter now too: + `0x004a5280` is the weighted recursive branch with heuristic ordering, per-tracker best-cost + cache `0x006cfcac`, and prune threshold `0x006cfcb0`, while `0x004a5900` is the alternate + recursive neighbor-walk branch that stays within compatible component labels through + `0x004a62c0` and accumulates step and mismatch penalties over route-entry links + `+0x206/+0x20a/+0x20e`. Above both of them, + `aux_route_entry_tracker_query_best_route_entry_pair_metric_with_endpoint_fallbacks` + `0x004a6630` is now bounded as the real chooser: direct fixed-pair query when both entries pass + `0x0048b870`, otherwise endpoint-pair fallback across the two tracker groups. + The adjacent route-style rebuild side is tighter now too: the same build-version family reaches + `placed_structure_rebuild_route_style_candidate_scores_and_peer_links` `0x004101e0`, where build + `1.04+` keeps one `Recycling Plant` stem-specific compatibility branch alive and build `1.05+` + skips one older descriptor-side attenuation fallback. There is also one neighboring world-side + compatibility lane now bounded below the same family: `placed_structure_collect_connected_component_tile_bounds_with_version_gate` + `0x004160c0` skips one older recursive component-bounds walk through `0x00415f20` on build + `1.03+` when scenario field `[0x006cec78+0x46c38]` is already active. The wrapper above that + path is bounded now too: `placed_structure_map_tile_range_to_connected_component_records_with_optional_bounds_refresh` + `0x00416170` walks the caller rectangle, maps tile keys into the component table rooted at + `0x0062ba7c`, and only re-enters `0x004160c0` when the current owner still has no cached bounds + and the local world or scenario suppressors stay clear. The higher neighboring raster side is + tighter too. `world_grid_refresh_projected_rect_sample_band_and_flag_mask` `0x00418610` is the + shared projected-rectangle helper above `world_grid_refresh_flagged_region_float_extrema_and_mean` + `0x00415020`: it refreshes the temporary sample band at `0x0062b7d0`, publishes the surviving + rectangle through `0x0044d410`, and on the single-sample path re-enters + `world_grid_toggle_flagged_mask_bit0_for_nonsentinel_rect_samples` `0x004185a0` to flip mask bit + `0x01` for the corresponding non-sentinel cells. Current grounded callers for `0x00418610` are + the neighboring placed-structure local-runtime helper `0x00418be0` and the heavier placement + validator `0x004197e0`, so this adjacent family now reads more like projected placement or local + raster prep than an unowned generic world-grid scan. One neighboring caller into the same + height-support band is tighter now too: the world-side branch at `0x00419070..0x004190f0` + walks one admitted local window, dispatches the acceptance-gated relaxer `0x0044d6e0` once per + cell with a one-cell radius and no immediate tail refresh, and only after that outer loop + completes re-enters `0x0044d410` on the full surviving rectangle. The higher owner split is + tighter now too. + `placed_structure_build_local_runtime_record_from_candidate_stem_and_projected_scratch` + `0x00418be0` is the broader construction or rebuild lane: resolve one candidate id from a stem, + build projected scratch through `0x00416ec0`, then publish the projected rectangle and validate + its side windows through `placed_structure_publish_projected_runtime_rect_globals_and_validate_side_windows` + `0x00416620`. That publish pass is bounded now too: it stages `0x0062b308/0x0062b30c/0x0062b310`, + validates the rectangle against route-entry coverage through + `route_entry_collection_query_rect_window_passes_entry_type_gate` `0x00494240`, can branch into + the special projected-slot picker `placed_structure_try_select_projected_rect_profile_slot` + `0x00415570`, and refreshes the compact per-cell side tables through + `world_grid_refresh_projected_rect_surface_and_region_byte_tables` `0x00414e10` before the + finished scratch is copied into one queued runtime record and the new record re-enters + `0x00416170` when its rectangle is valid. The smaller sibling + `0x00419200` is now bounded beneath that same projected-rectangle family too: it is the tiny + getter over the temporary dword cell-value bank at `0x0062b300`, flattening one caller cell + through live world width `[0x0062c120+0x2155]` and returning the corresponding dword when the + bank exists, else `0`. Current grounded caller is the later world-side branch at `0x0048af99`. + The smaller sibling + `placed_structure_clone_template_local_runtime_record_for_subject_and_refresh_component_bounds` + `0x00418a60` now reads as the current-subject clone path above the same connected-component and + mask-refresh helpers, returning the cloned local runtime record later stored into `[site+0x24e]` + by `placed_structure_refresh_cloned_local_runtime_record_from_current_candidate_stem` + `0x0040e450`. The higher wrapper above that clone path is bounded now too: + `placed_structure_collection_refresh_local_runtime_records_and_position_scalars` `0x004133b0` + first drains the temporary site-id queue rooted at `0x0062ba64/0x0062ba6c/0x0062ba70` through + `placed_structure_local_runtime_site_id_queue_count` `0x00414480` and + `placed_structure_local_runtime_site_id_queue_pop_next` `0x00413f50`, rebuilding one cloned + local-runtime record per queued placed structure through `0x0040e450`, and only then sweeps all + live placed structures through the side refresh helper + `placed_structure_refresh_local_runtime_position_triplet_and_linked_anchor_followon` `0x0040ee10`. + The constructor or ownership split beneath that family is tighter now too. The shared allocator + `placed_structure_collection_allocate_and_construct_entry` `0x004134d0` no longer just reaches + an anonymous `0x3e1`-byte scratch object: it first constructs one concrete placed-structure + specialization through `placed_structure_construct_concrete_specialization_vtable_5c8c50` + `0x0040c950`, which calls `0x0045b680` to seed the common base table `0x005cb4c0`, clear the + derived field band `[this+0x23a..+0x26a]`, and re-enter the older base initializer + `0x00455610`, then installs the specialization table `0x005c8c50`. The paired cleanup path at + `0x0040c970` now reads like the matching teardown thunk: it briefly reinstalls `0x005c8c50`, + then immediately demotes the record back to the base table through `0x0045b040 -> + 0x00455650` before the stack object is freed or unwound. The corresponding serializer entry + `0x0040c980` is equally tight now: it simply tails into `0x0045b560`, which first re-enters the + base serializer `0x004559d0` and then emits the derived payload bracketed by tags `0x5dc1` and + `0x5dc2` over `[this+0x23e]`, `[this+0x242]`, `[this+0x246]`, `[this+0x24e]`, and `[this+0x252]`. + One nearby string clue is useful but narrower than it first looked. The specialization table at + `0x005c8c50` is immediately followed by `RadioStation` and `Radio Station`, but the local member + method `0x0040ce60` now shows why: it compares site stem `[this+0x3ae]` against `Radio Station`, + canonicalizes that stem to `RadioStation` on match, and then re-enters `0x0040cd70` plus + `0x0045c150`. So those adjacent strings ground one stem-normalization lane inside the + specialization, not the specialization name by themselves. The small virtual-slot and cached-id + side is tighter now too. The same `0x005c8c50` table carries three literal-false stubs + `0x0040cc10/0x0040cc20/0x0040cc30`, one literal-true stub `0x0040ccc0`, and the narrower + linked-site-id presence predicate `0x0040ccb0`, which simply returns whether `[this+0x2a8]` is + nonzero. Beneath the stem-normalization path, `0x0040cd70` is now bounded as the common cached + source/candidate resolver: it clears `[this+0x3cc]` and `[this+0x3d0]`, scans source collection + `0x0062b2fc` for a stem match against `[this+0x3ae]`, stores the matched source id into + `[this+0x3cc]` plus the linked candidate/profile id from `[source+0x173]` into `[this+0x3d0]`, + and when no match exists formats localized id `0x00ad` through `0x0051e980` with the current + stem buffer. That warning path is tighter now too: `0x0051e980` is the guarded warning-modal + publisher that forces cursor visibility through `MouseCursor.cpp` before showing the shared + warning box. The two tiny followers `0x0040cec0` and `0x0040cee0` then resolve those cached ids + back into concrete source and candidate records through `0x0062b2fc` and `0x0062b268` + respectively. The derived payload and transient family under that same table is tighter now too. + `0x0045c150` is the clear payload-loader + counterpart to `0x0045b560`: it reinitializes the derived field band, opens the `0x5dc1/0x5dc2` + payload bracket, restores the two payload strings into `[this+0x23e]` and `[this+0x242]`, clears + the transient roots `[this+0x24e]`, `[this+0x256]`, `[this+0x25a]`, and `[this+0x25e]`, and then + rebuilds follow-on specialization state through `0x0045b5f0` and `0x0045b6f0`. The neighboring + builder pair is coherent too: `0x0045b210` formats `amb_%1_01.wav`, allocates a `0x141`-byte + transient object, stores it at `[this+0x24a]`, and registers it through `0x0052da00`, while + `0x0045c310` allocates the separate primary transient handle at `[this+0x246]` from payload + strings `[this+0x23e]` and `[this+0x242]`, then publishes it through `0x00530720` and + `0x0052d8a0`. The next rebuild layer is tighter now too. `0x0045b5f0` resolves one current + world-position tuple through `0x0052e720 -> 0x0051f090 -> 0x00534490`, then uses that derived + scalar to refresh the ambient-side transient again through `0x0045b210`. Above that, + `0x0045b6f0` clears the optional handles at `[this+0x25a]` and `[this+0x25e]`, then probes and + materializes a larger named variant family rooted in `[this+0x23e]` through strings such as + `%1_`, `%1_Upgrade1`, `%1_Anim%2.3dp`, `%1_Upgrade1Anim%2.3dp`, and + `%1_Upgrade1Light%2.3dp`, looping across numbered variants and publishing surviving records + through `0x0052d8a0`. One higher timed branch is bounded now too: `0x0045baf0` advances the two + timer-like fields `[this+0x26a]` and `[this+0x266]`, gates on nearby world-distance and + candidate-side checks, and then formats one output around `rnd_%1_%2.wav` plus the same anim or + light string family before dispatching through `0x00531e50` under owner `0x006d402c`. Their + release-side companions `0x0045b160` and `0x0045c3c0` tear down those same transient roots and + payload strings again, and the recurring service slice `0x0045be50` updates the derived scalar + triplet `[this+0x22e]`, `[this+0x232]`, and `[this+0x236]` before republishing it through + `0x00530720`. The string literals `amb_%1_01.wav`, `%1_Anim%2.3dp`, + `%1_Upgrade1Anim%2.3dp`, `%1_Upgrade1Light%2.3dp`, and `rnd_%1_%2.wav` therefore ground the + derived band `[this+0x23e..+0x26a]` as one payload-plus-transient owner family with ambient, + animation, light, and random-sound components, rather than more linked-site or route-entry ids. + One broader specialization-side build pass under that same family is bounded now too. + `0x0045b760` first scans one base-or-upgrade descriptor family rooted in `[this+0x23e]` + through `%1_` or `%1_Upgrade1`, probing each numbered hit through `0x0053c930` and dispatching + every accepted one through vtable slot `+0x7c`. It then builds the matching attached-emitter list + through `0x0045e940`, ensures the shared `%1_Anim.3dp` payload root exists through `0x0045ae80`, + and finally scans the paired animation family through `%1_Anim%2.3dp` or + `%1_Upgrade1Anim%2.3dp`, materializing each accepted hit into a `0x206` record through + `0x00530640`, publishing that record through `0x0052d8a0`, hashing the generated name through + `0x0053d810`, and forwarding the result into `[this+0x256]` through `0x0045a7f0`. So that + specialization side now has one explicit base-or-upgrade descriptor and animation-record build + pass above the later timed anim/light/random-sound service slice, not just the narrower + `%1_Anim` and `%1_Upgrade1Light` helpers. + The shared `%1_Anim.3dp` collection under that build pass is tighter now too. `0x0045ae80` + formats literal `%1_Anim.3dp`, probes the named-bank owner `0x006d4020`, reads the matched + payload bytes, and lazily allocates the intrusive shared list root `0x006acd5c`, so this is the + bootstrap for the specialization-side shared animation payload family rather than just another + bank-read leaf. `0x0045a7f0` then acts as the keyed replace-or-publish helper over that same + family: it rewrites matching keys across the current `0x006acd50/0x006acd4c` row collection, + mirrors the replacement into the per-row four-lane pointer bands, inserts newly active rows into + the intrusive list rooted at `0x006acd5c`, and when selector table `0x006acd44` is live it + allocates one selector-`0` effect slot through `0x00475ed0` before forwarding it into + `0x00475240(-1,0)`. The smaller helper `0x0045a700` is the keyed three-float accumulator beneath + that same path: it scans the live `0x168`-byte rows in `0x006acd50`, filters on one key dword + plus row flag bit `0x400`, and accumulates one output anchor delta from the shared basis bands in + `0x006acd4c+0x04/+0x34` or `+0x40/+0x70`. The service side above the collection is also bounded: + `0x0045af50` clears globals `0x006acd44/48/54`, publishes the current row collection into + `0x006acd50/0x006acd4c`, releases oversize selector roots through `0x00475100`, and prunes every + intrusive active record in `0x006acd5c` whose owner pointer at `[record+0xf0]` matches the + current collection owner. The heavier per-record body is `0x0045a9c0`: it honors the current + controller gates in `0x006acd48/58`, clears and re-arms the selected effect-slot band in + `0x006acd44`, optionally mirrors one caller dword into row field `[row+0x80]`, updates timing and + mode fields across every matching shared row, derives local scalar deltas through `0x0045a280`, + optionally subtracts keyed anchor deltas through `0x0045a700`, and republishes the finished two + owner triplets through `0x0052e8b0` and `0x00530720`. + `0x0045ade0` seeds cursor `0x006acd60` from `[0x006cec78+0x15]`, then services the intrusive + list in `0x0f`-tick windows by dispatching the heavier per-record body at `0x0045a9c0(owner, + cursor, 0)` for every linked record whose owner pointer at `[record+0xf0]` is live. So the + specialization transient family now includes a concrete shared `%1_Anim.3dp` payload root, + keyed record replacement, keyed anchor accumulation, and a bounded 15-tick shared service loop, + not just the base builder at `0x0045b760`. + The low-side leaves under that same family are tighter now too. `0x0045b050` is the explicit + field reset for payload roots `[this+0x23e/+0x242]`, transient handles `[this+0x246/+0x24a/+0x24e]`, + selector slot `[this+0x262] = -1`, timer fields `[this+0x266/+0x26a]`, and the packed flag band + `[this+0x23a..+0x23d]`, with an optional tail into `0x00455610` when the caller requests a + broader base clear. `0x0045b0b0` is the paired integer-triplet publish leaf: it forwards one + caller triplet through `0x0052e680` on the specialization owner and, when present, repeats that + same publish into the primary transient `[this+0x246]`. `0x0045b0f0` is the neighboring packed + RGB-triplet forwarder into vtable slot `+0x58`. The two tiny wrappers around them are now + explicit too: `0x0045b040` demotes the specialization straight back to base vtable `0x005cb4c0` + before tailing into the common cleanup body `0x00455650`, while `0x0045b110` is just the direct + wrapper into the shared world-anchor triplet publisher `0x00455660`. + One intermediate transient build layer is bounded now too. `0x0040cf00` first requires + creation-mode byte `[this+0x3d4] == 1` and live seed handle `[this+0x24e]`, re-enters + `0x0045b370(1)`, derives one scaled float from current local geometry through `[this+0x14]`, + `[this+0x21]`, `[this+0x3a]`, and `0x005c8cf4`, and then allocates a second transient handle + into `[this+0x25a]` through `0x00475ed0`. It follows that with one current world-position + resolve through `0x00414450` and `0x0052e720`, several local offset-triplet writes through + `0x00475010`, and four numbered channel updates through `0x00475030` with selector ids `1..4`. + That is enough to bound it as another specialization-side transient-handle builder beneath the + same payload family as `0x0045c310` and `0x0045b210`, without yet over-naming the user-facing + subtype or effect semantics of the built handle. The adjacent data-loading strip under that same + transient family is tighter now too. `0x00474700` reloads `particles.dat` into global root + `0x006cea5c` and then registers literal `ParticlesTexture` through owner `0x006d4030`; + `0x00474790` reloads `emitters.dat` into global root `0x006cea60`; `0x00474820` hashes one + caller-supplied emitter name and resolves the first matching entry out of that `emitters.dat` + table; `0x00474860` is the adjacent formatted-variant iterator that walks the same table through + `%s%s%i.3dp`, saving the selected row root into `0x006cea90` and the generated variant name into + `0x006cea94`; `0x00474970` is the small handle-array release helper used by the same + emitter-template teardown side; and `0x004749a0` is the tiny exact-compare predicate for literal + `steam`. The lower definition-to-handle materialization body is bounded now too: `0x004749d0` + copies scaled float and packed dword bands from one emitter-definition row into the attached + emitter handle, resolves the named particle row from `particles.dat` through `0x0053d810`, and + mirrors that particle row into `[handle+0x10c..]` before returning the live handle. The + higher creator above that materializer is tighter now too: `0x00474e20` first strips special + high bits for `CargoMoney_DollarSign`, clears incoming flag `0x400` when definition gate + `[def+0xb8]` is zero, and then either hashes the definition name plus owner token and clones one + owner-side template through `0x00556ce0`, or allocates a fresh `0x1fd` runtime emitter through + `0x00556920` before re-entering `0x004749d0`. On success it publishes that emitter through + `0x0052d950`, stores the definition owner pointer into `[emitter+0x60]`, and when final flags + carry `0x02000000` it forces persistent flag dword `[emitter+0xbc] = 1`. One larger owner-stem + branch above that iterator is bounded now too: `0x0045e940` rejects `Stadium`, clears caller flag + bit `0x10` for `ParticleCar`, repeatedly pulls formatted variants through `0x00474860`, + instantiates each accepted variant through `0x00474e20`, sets emitter flag `0x02` for + `Nuclear`, and optionally returns the created emitter list through the caller array. So the + `0x00474e20/0x00475010/0x00475030` emitter builders are now sitting on top of a grounded pair + of particle and emitter data tables plus one concrete owner-stem-driven variant-list builder, + not just anonymous global payload roots. The small shared slot utilities + under those builders are tighter now too: `0x00474fe0` is the shared per-slot flag broadcast + into `[emitter+0xbc]`; `0x00475010` caches one shared anchor + triplet into globals `0x006cea68/0x006cea6c/0x006cea70`, `0x00475030` republishes that cached + triplet into either all emitters in one slot container or one selected emitter index at + `[emitter+0x1b0..+0x1b8]`, `0x00475240` toggles the per-emitter enable byte `[emitter+0x1d8]` + for either all or one selected emitter, and `0x004752b0` is the paired boolean query that + reports true only when that same byte is zero. The update side is explicit too: `0x00474f70` + runs `0x00555e50(0)` across either one supplied slot container or every slot in the global linked + list rooted at `0x006cea74`. The release side is explicit too: `0x00475100` + tears emitter slots down, optionally unlinks them from the global active list + `0x006cea74/0x006cea78/0x006cea7c`, and then either recycles or frees the slot depending on + whether it falls inside the pooled descriptor rooted at `0x006cea58`. Two named bundle builders + are grounded now too: `0x004752d0` builds the three-emitter `BrokenDown_Steam` + + `FlamespoutB` + `Crash_SmokeA` bundle, while `0x00475550` builds the two-emitter + `BrokenDown_Steam` + `BrokenDown_Smoke` bundle. The next owner layer above those helpers is + grounded now too. `0x00474ce0` is the global particle/emitter bootstrap: it reloads + `emitters.dat`, reloads `particles.dat`, publishes the mode-`1` ratio labels through + `0x00474690`, lazily allocates pooled slot root `0x006cea58`, allocates backing slab + `0x006cea54`, seeds that slab into the pooled descriptor through `0x0053dcf0(0x38, 0x2710, 1)`, + clears the global linked-slot heads and shared anchor globals, rebuilds the flagged templates + through `0x00474c60`, and finally publishes enable-state `1` through owner `0x006d4030`. + `0x00474db0` is the teardown-side companion that frees `0x006cea54`, `0x006cea5c`, + `0x006cea60`, and then resets and frees the pooled slot root `0x006cea58`. That makes the + effect-slot builders a real subsystem rooted at `0x006cea54..0x006cea98`, not just a loose + string-and-handle utility strip. The named bundle surface is broader now too: `0x00475420` + selects one `Volcano_BlackSmoke*` + `Volcano_Lava*` pair from the caller float tier + `0.5/0.75/1.0/1.5/2.0` and builds the two-emitter volcano bundle; `0x00475650` builds the + three-emitter `ServiceTower_Water2` + `ServiceTower_Water` + `ServiceTower_Water3` water bundle + from the paired `ServiceTower_Anim2#water.3dp`, `ServiceTower_Anim3#water.3dp`, and + `ServiceTower_Anim4#water.3dp` definitions; `0x004757b0` builds the three-emitter + `Rocket_Flame` + `Rocket_Smoke` + `Rocket_Sparkle` fireworks bundle from the paired + `Fireworks_Anim2/3/4#water.3dp` definitions; `0x00475910` is the adjacent randomized + one-emitter fireworks builder that rotates among `Fireworks1/2/3`, uses + `Fireworks_Anim5#water.3dp`, and writes fixed dword `0x3c` into `[emitter+0xbc]`; + `0x004759f0` and `0x00475b30` build the one-emitter `CargoMoney_DollarSign` and + `SpendMoney_DollarSign` bundles; `0x00475a90` builds the one-emitter `SelectObject` bundle; + `0x00475bd0` builds the five-emitter directional construction bundle from `Construct_Pos`, + `Construct_Left`, `Construct_Right`, `Construct_Back`, and `Construct_Forward`; `0x00475dc0` + selects between one-emitter `Mist` and `MistSmall`; and `0x00475e30` builds the one-emitter + `Vent` bundle. The next local owner above that catalog is grounded too: `0x00475ed0` is the + selector-driven named-bundle dispatcher that chooses one of those builders from the caller + selector, mirrors the first emitter's attachment token into `[slot+0x04]`, stores caller mode + into `[slot+0x34]`, and when that mode equals `1` links the finished slot into the global active + list `0x006cea74/0x006cea78/0x006cea7c`. So that specialization-side transient path now has a + much broader data-backed effect catalog and a concrete selector-driven bundle owner above it, not + just the earlier broken-down bundles. + One adjacent train-side effect strip is bounded now too, and it should stay separate from the + concrete placed-structure specialization family. `0x0045d130` resolves one owner profile + through `0x006ada84`, allocates a `0x141`-byte handle, initializes it through `0x00554830` + using one mode-selected train sound stem from the tiny selector at `0x0045d22e`, applies two + fixed parameter writes through `0x00554340` and `0x00554450`, stores the result at `[this+0x336]`, + and registers it through `0x0052da00`. `0x0045d260` is the paired live-handle updater: it clamps + one caller-scaled rate into `0x1f40..0xac44`, forwards that through `0x005542c0`, pushes the + caller gain through `0x00554450`, and when the current handle mode at `[handle+0x138]` equals + `1` also forwards zero through `0x005543f0`. The broader owner above both helpers is + `0x0045d2e0`: it republishes the current world anchor through `0x0052e720`, updates an existing + live sound handle at `[this+0x346]` when one exists, or otherwise selects one new sound stem from + fixed `Train_Burning.wav`, fixed `Train_Breakdown_loop.wav`, or one dynamic table-driven name + after the `0x0041b8f0 -> 0x004a8840` branch, then creates the fresh sound handle through + `0x00531e50`, stores it at `[this+0x346]`, sets fixed flag bits `0x18`, seeds two scale fields + from the chosen mode factor, and clears the three train-state latches `[this+0x33a/+0x33e/+0x342]` + again. So the neighboring `0x0045d130/0x0045d260/0x0045d2e0` family is now bounded as a + train breakdown-or-burning sound/effect handle strip rather than more placed-structure emitter + state. + The larger owner above that train-side strip is bounded now too. `0x0045d4b0` optionally clears + prior state through `0x00455610`, copies the caller primary and secondary stems into + `[this+0x32e]` and `[this+0x332]`, probes the named-bank owner `0x006d4020` for the secondary + stem, then falls back through the primary stem and the suffixed `_C.tga` form. It resolves one + `ServicePoint.3dp` payload into `[this+0x23e/+0x23a]`, one `Body.3dp` payload into + `[this+0x242/+0x246]`, counts existing `%1_Truck%2.3dp` variants into `[this+0x31a]`, allocates + the larger per-variant table at `[this+0x316]`, and then enters the later subloops that fill the + cargo-icon, bogie, drivewheel, piston, connecting-rod, coupling-bar, body, and track-point + bands. That keeps the `0x0045d130/0x0045d260/0x0045d2e0` sound helpers nested under a broader + train visual/profile preload owner rather than floating as an isolated sound-only strip. + The release and load sides of that same train family are bounded now too. `0x0045e390` drops the + optional sound handle `[this+0x346]` through `0x00531ef0` plus the mode-gated `0x005317b0` path, + clears the live train-effect handle root `[this+0x336]` by re-entering `0x0045cc90(0)` and + `0x0045cf40(0)`, iterates the variant table at `[this+0x316]` to free per-row pointer arrays, + two heap buffers, and any nested owned list rooted at `[row+0x0c]->[+0x75]`, then frees the main + table and the two payload strings `[this+0x32e]` and `[this+0x332]`. `0x0045e530` is the + load-side owner: it opens tags `0x61a9` and `0x61aa`, reads two heap strings, optionally rewrites + the first string by scanning the live collection at `[0x006d4020+0x429b8]`, rebuilds the train + visual family through `0x0045d4b0` with unit scale, republishes the early per-row handles through + `0x005548d0`, and under scenario latch `[0x006cec78+0x46c34] > 0x2585` also enters the optional + child-record branch under tag `0x61b2` before closing `0x61ab`. That makes the train-side strip a + real payload-owned family with explicit preload, service, load, and teardown phases rather than a + one-off visual helper. + Two shared selector-slot toggles under that same family are bounded now too. `0x0045cc90` owns + the three selector-driven effect slots at `[table+0x34]`, `[table+0x38]`, and `[table+0x3c]`: + in build mode it allocates selectors `1`, `2`, and `3` through `0x00475ed0`, reseeds their + shared anchors through `0x00475010/0x00475030`, and then enables every live emitter in the main + row-object list by writing byte `1` into `[emitter+0x1d8]`; in release mode it tears those same + three slots down through `0x00475100`, clears the table fields again, and disables the same + emitter list by writing byte `0`. `0x0045cf40` is the same pattern for selector `5` into + `[table+0x40]`. So the train visual family now has one explicit selector-slot toggle layer above + the named `0x00475ed0` bundle catalog, rather than touching those effect slots only through the + broader load and teardown owners. + One smaller service leaf under that same family is grounded now too. `0x0045e8c0` walks the + fixed 32-entry row-object strip rooted at `[this+0x277]` and dispatches vtable slot `+0x10` on + every live row object. When the caller supplies a valid selected row index instead of `-1`, it + re-enters that selected row through vtable slot `+0x0c`, and when the paired per-row flag byte in + the neighboring strip is nonzero it also pushes `0,0,1.0f,1.0f` through `0x0052eab0` on that + selected row object. The current grounded callers at `0x0041c680` and `0x0041c69a` derive the + selected row from byte `[cargo+0x20]`, so this is best read as the row-object service plus + selected-entry refresh leaf under the train visual family, not a generic object-list sweep. + One adjacent helper block is tighter now too, and it should stay separate from the concrete + `0x005c8c50` vtable rather than being folded into it. The small predicates + `0x0040cc40/0x0040cc60/0x0040cc80` all follow the same `[this+0x173] -> 0x0062b268` chain into + one linked candidate/profile record. `0x0040cc40` returns whether candidate subtype byte + `[candidate+0x32]` equals `1`, `0x0040cc60` returns raw candidate byte `[candidate+0xba]`, and + `0x0040cc80` returns the stricter conjunction `subtype == 1 && class == 3` using class byte + `[candidate+0x8c]`. The current grounded caller for all three is + `world_grid_refresh_projected_rect_sample_band_and_flag_mask` `0x00418610`, where they derive + the two boolean mode inputs for `0x00415020`; that makes them a shared candidate-profile helper + cluster adjacent to the specialization family, not direct overrides in the `0x005c8c50` table. + The neighboring `0x0040ccf0` stays on the same “adjacent but not the same vtable” side of the + boundary: it resolves one linked instance through `0x0047de00`, follows that instance's vtable + `+0x80` owner chain, and returns candidate class byte `[candidate+0x8c]`. Current grounded + callers at `0x00480fb5` and `0x004b03ce` compare that returned class against `3` and `4`, so the + current safest note is simply “linked-instance candidate-class reader.” One gated collection-side + scan in the same neighborhood is bounded now too. `0x0040cd10` first requires shell latch + `[0x006cec74+0x1c3]` and creation-mode byte `[this+0x3d4] == 1`, then resolves the current + subject's center world-grid cell through `0x00455f60`, reads the local site roster count and id + list at `[cell+0xeb]` and `[cell+0xef]`, and resolves each listed placed-structure id through + `0x006cec20`. Its current grounded caller is the broader collection sweep at `0x00413860`, so + the strongest current read is a gated center-cell site-roster scan rather than one more direct + specialization override. + One small neighboring world-grid helper is grounded cleanly enough to keep too. `0x0040ccd0` + takes one live world root, one X-like index, and one Y-like index, multiplies the Y-like term by + world width `[world+0x2145]`, adds the X-like term, scales the resulting slot by fixed cell + stride `0x1d7`, and returns the corresponding cell pointer under base `[world+0x2129]`. Current + grounded callers include the placed-structure cargo-service bitset sweep around `0x0042c386` and + several world-grid overlay passes in the `0x004525bc..0x00452bb2` range, so that helper is now + best read as the shared `(x,y) -> world-cell*` resolver rather than another object-specific + method. + The next sibling table at `0x005c9750` is tighter now too, though still not fully decoded. The + structural anchor is `map_load_city_database` `0x00474610`: that loader stages bundle tags + `0x61a9..0x61ab`, iterates one collection, and dispatches each entry through vtable slot `+0x44`. + In `0x005c9750`, that same slot resolves into the sibling record family beside + `0x0041ab70/0x0041ab80`, which is enough to treat the table as the city-database entry family + rather than a generic unresolved runtime object. The small load-side slot `0x0041ab70` simply + jumps into `0x0045c6f0`, which restores two strings into `[this+0x32e]` and `[this+0x332]`, + stages the same `0x61a9/0x61aa/0x61ab` tag family, and iterates the child runtime band rooted at + `[this+0x316]`. The one real behavioral slot we recovered there is `0x0041ab80`: it refreshes + one named handle through owner `0x006d4020`, writes the resulting handle into `[this+0x1c]`, + queries three base floats through `0x0045c480`, and returns one scaled float derived from the + first queried component. That method is currently called from later world-side branches at + `0x0046e4f7`, `0x004aafee`, and `0x004ab020`. The exact user-facing semantics of the handle and + the many constant-return virtuals in the same table are still open, but the family boundary is no + longer arbitrary: this is now the current city-database entry vtable cluster, not another + placed-structure specialization. One correction matters here too: the lower + `0x00455660/0x00455800/0x00455810/0x00455930` helpers are no longer city-only. Local `.rdata` + now shows the same shared slots under both the city-entry table `0x005c9750` and the sibling + `Infrastructure` table `0x005cfd00`, whose constructors at `0x0048a240/0x0048a2dc/0x00490a3c` + all re-enter `0x00455b20`, install `0x005cfd00`, and seed the same scalar-band family through + `0x00455b70` with the literal stem `Infrastructure`. So the safest current family name for those + low helpers is the broader `0x23a` runtime-object band rather than city-entry-only. `0x00455800` + and `0x00455810` are simply the paired normalized coordinate getters over `[this+0x1e2]` and + `[this+0x1ea]`, which explains why they recur all over the city-side, route-link, and + placed-structure placement code. The narrower helper `0x00455660` sits above those getters: it + scales the caller-supplied normalized coordinate pair, converts it through + `0x006d4024 -> 0x0051f090 -> 0x00534490`, adds a caller-supplied integer height bias, optionally + rounds that height through `0x005a10d0` when the auxiliary-preview gate `0x00434050` is active, + and finally publishes the resulting world-anchor triplet through `0x00530720`. One + serializer-side sibling is bounded too. `0x00455930` queries two triplet-like scalar bands + through `0x0052e720` and `0x0052e880` and writes the resulting six dwords through `0x00531030`; + its load-side stream counterpart `0x00455870` reads the same six four-byte lanes back through + `0x00531150`, republishes the first triplet through `0x00530720`, republishes the second through + `0x0052e8b0`, and returns the summed byte count. The neighboring tagged string-triplet serializer + `0x004559d0` is now no longer reversed either: it writes bracket tags `0x55f1/0x55f2/0x55f3` + through `0x00531340`, emits the three string lanes `[this+0x206/+0x20a/+0x20e]` through + `0x00531410`, dispatches vtable slot `+0x4c`, then re-enters `0x0052ec50` before the closing + tag. + +### Shared Runtime-Object and Support Families + +The low helper strip beneath that shared family is tighter now too: `0x0052ecd0` is the + common local-state reset that clears the list and handle roots, resets the string/scalar side + bands, preserves only selected low bits of `[this+0x20]`, and reseeds the recurring default + `1.0f` lanes; `0x0052ebd0/0x0052ec50` are the load/save companions for the two flag bits stored + in that same byte; `0x0052eb90` releases every entry hanging from list root `[this+0x79]` + through `0x00554d50`; and `0x0052eca0` is the grouped-table cursor over `[this+0x14]`, + `[this+0x21]`, and `[this+0x3a]` that returns the next `0x45`-byte subrecord in the current + group when one exists. The next shared initializer `0x0052edf0` then binds caller + pointer `[this+0x04]`, resolves optional handles into `[this+0x10]` and `[this+0x1c]`, copies + one anchor triplet into `[this+0x1e2/+0x1e6/+0x1ea]`, sets bit `0x08`, and seeds packed color + `[this+0x43] = 0x007f7f7f`; its release-side siblings `0x0052eeb0` and `0x0052ef10` clear the + two owned list roots `[this+0x79]` and `[this+0x7d]` through distinct per-entry destructors + before freeing the list roots themselves. The broader release body `0x0052ef70` sits above that + strip: it clears the active shell preview-owner latch when it still points at `this`, drops the + dependent handle at `[this+0x0c]`, recursively tears down the nested object list `[this+0x75]`, + clears sibling owned list `[this+0x81]`, detaches any world binding rooted at `[this+0x04/+0x08]`, + and finally frees the optional handles at `[this+0x10]` and `[this+0x1c]`. The next shared + dirty-bit helper `0x0052f120` is now bounded too: when byte `[this+0x20]` still carries bit + `0x02`, it rebuilds the cached 16-dword transform-style block at `[this+0x14e]` from scale + `[this+0x36]`, anchor triplet `[this+0x1e2/+0x1e6/+0x1ea]`, and either the live local vector + lanes `[this+0x4b/+0x4f/+0x53]` or the stored fallback block at `[this+0x18e]`, then flips the + dirty bit over to the cached-ready bit `0x04`. The next two adjacent helpers are bounded too: + `0x0052f1e0` is a pure five-vec3 boolean geometry predicate built from signed-volume or + separating-plane style tests, and `0x0052f370` is the quantized selector that rounds world + coordinates, folds them through table `0x006d9098`, samples one grouped metric through owner + `[this+0x04]`, updates byte `[this+0x5c]`, and then chooses the active `0x45`-byte subrecord by + storing index `[this+0x21]` and pointer `[this+0x18]`. The adjacent emission owner `0x0052f500` + is tighter now too: it starts from that selected grouped subrecord, snapshots the global packet + write pointer and remaining count at `0x00cc3b64/0x00cc3b5c`, optionally refreshes the cached + transform block and applies the five-vec3 predicate when state bit `0x01` is active, and then + emits the selected `0x45`-byte records into one run of `0x20`-byte output packets while + advancing the shared packet cursor. The next shared helpers under that emission band are now + bounded too. `0x0052fb70` is the packed-color propagation helper over `[this+0x43/+0x47]`: when + shell gate `[0x006d4024+0x114742]` is live it combines stored high-byte state with either dim + RGB `0x003c3c3c` or full-bright RGB `0x00ffffff`, pushes the same dim-or-bright triplet into the + child list `[this+0x75]` through `0x0052e680`, and optionally recurses that update over the whole + child tree; when the shell gate is absent it instead stores the raw byte into `[this+0x47]` and + only recurses that byte state. `0x0052fd60` then republishes current anchor triplet + `[this+0x1e2/+0x1e6/+0x1ea]` into every attached entry hanging from list root `[this+0x81]` + through `0x005545d0`. The heavier relocation sibling `0x0052fdc0` marks the object dirty, adds a + caller-supplied triplet delta to the same anchor, quantizes old and new X/Z lanes against the + live world grid, rebinds world handle `[this+0x08]` through `0x00533c20/0x00533bf0` when the + quantized cell changes, and on success re-enters `0x0052fd60`; out-of-bounds moves restore the + prior anchor and fail. One more adjacent rotation-side helper is now bounded too: `0x0052ffb0` + converts the current local 4-dword orientation block at `[this+0x1ce..+0x1da]` into a temporary + axis-angle representation, scales the recovered angle by the caller float, and rebuilds the + stored orientation block by re-entering `0x0052e9f0`. The immediate anchor-publish sibling + `0x00530720` is now explicit too: it is the absolute-triplet form of the same relocation family, + storing one caller-supplied anchor directly into `[this+0x1e2/+0x1e6/+0x1ea]`, optionally + rebinding world handle `[this+0x08]` when the quantized X/Z cell changes, and then re-entering + `0x0052fd60`. The adjacent packet-side query `0x00530030` is bounded as well: it starts from the + currently selected grouped `0x45`-byte subrecord, snapshots the same global packet source span as + `0x0052f500`, lazily refreshes cached basis lanes when needed, transforms one caller-supplied + input triplet through that basis, and then walks the remaining packet span until + `0x0052f1e0` reports one overlap or the span is exhausted. One sibling-table strip is now + explicit too. Table `0x005dd1f0` has the tiny wrappers `0x00530640`, `0x00530670`, and + `0x00530680` as its shared seeded-constructor, reset, and release thunks over `0x0052edf0`, + `0x0052ecd0`, and `0x0052ef70`, while `0x005305c0` is the small list-bit propagator that sets or + clears bit `0` in `[entry+0xb0]` across owned list `[this+0x79]`. The first heavier body under + that same table is now bounded too: `0x00530690` copies one pair of 16-dword cached blocks from a + source object into `[this+0x10e]` and `[this+0xce]`, refreshes local cached transform + `[this+0x14e]`, and recurses the same copy into child list `[this+0x75]`. The `Infrastructure` + side is tighter now too. The optional child + The next adjacent field-accessor strip is explicit too: `0x00533100/0x00533120` are the indexed + float set/get helpers for `[this+0x14e4 + index*4]`; `0x00533130/40`, `0x00533150/60`, + `0x00533170/80`, and `0x00533190/a0` are four direct dword set/get pairs over + `[this+0x1534]`, `[this+0x1540]`, `[this+0x153c]`, and `[this+0x1544]`; `0x005331b0/c0` are the + float set/get pair for `[this+0x14e0]`; and `0x005331d0` is the direct getter for `[this+0x1548]`. + The important caller-side grounding is narrow but real: `0x0052f370` samples one indexed float + through `0x00533120` while choosing the active grouped subrecord, and `shell_emit_ranked_overlay_cell_items` + `0x00524780` reads the current threshold pair through `0x00533160` and `0x00533180`. So this + strip is now bounded as a genuine shared field-accessor family under the same runtime-object + owner, even though the exact high-level meanings of those fields remain open. + attach helper `0x0048a1e0` allocates and seeds one fresh `Infrastructure` child and, when the + owner already has more than one child, clones the first child's two triplet bands into that new + child before attaching it. The looped rebuild `0x0048dd50` then rebuilds the owner-visible + `Infrastructure` children one ordinal at a time, tears down the higher extras above ordinal `5`, + refreshes cached primary-child slot `[this+0x248]` when needed, and finishes with the same + world-cell and route-side follow-on family around `0x00448a70`, `0x00493660`, and `0x0048b660`. + The smaller attach helper `0x00490a3c` is now bounded too: it conditionally allocates one + `Infrastructure` child from a caller-supplied payload stem, attaches it to the current owner, and + then seeds three caller-supplied position lanes through `0x00539530` and `0x0053a5b0`. The + direct route-entry side of the same family is no longer anonymous either: `0x0048e140`, + `0x0048e160`, and `0x0048e180` are the three direct resolvers over owner fields + `[this+0x206/+0x20a/+0x20e]` into the live route-entry collection `0x006cfca8`. Another shared + sibling family is tight enough now too: the real + packed-byte-triplet owner is `0x0052e680`, and the two local + wrappers `0x00455820` and `0x00455840` both force its recursion flag on. `0x00455820` forwards + three explicit byte arguments, while `0x00455840` unpacks one packed `u24`-style dword into + three byte lanes first. The downstream setter writes packed byte-triplet lane `[this+0x43]`, + defaults that lane to `0x007f7f7f` when all three bytes are zero, and when recursion is enabled + it walks child list `[this+0x75]` through `0x00556ef0/0x00556f00` and re-applies the same packed + update recursively to every child. The shared formatter thunk `0x00455860` is no longer a blind + jump target either: `0x00530820` now reads as the common group-selection status-label formatter + over the same `0x23a` family. It only answers when shell gate `[0x006d4024+0x1146be]` is live, + state bit `0x10` is clear, vtable slot `+0x14` says the current object should answer, and the + owned-entry bit propagator `0x005305c0` succeeds. Under that gate it formats one caller-owned + text buffer from either a fixed fallback block, a simple mode-`1` `X` or index form, or a + grouped-table form built from the current `0x45`-byte subrecord's float lane plus current index + `[this+0x21]`. The sibling `Infrastructure` table `0x005cfd00` also still carries three tiny + fixed-return slots after that shared formatter path: two return literal `0x46`, and one returns + fixed float `1.25f`, so those slots are now bounded as small table constants rather than as + missing behavior. One nearby global helper family is bounded enough too: `0x005309d0` lazily + clears and arms the indexed table rooted at `0x00ccb880`, `0x00530a00` services or releases one + slot in that table according to its local state dword, `0x00530b70/0x00530b90/0x00530c10` query + one slot's primary handle metric, primary handle, and payload-length lanes, and `0x00530ba0` + performs the release-side cleanup for one slot's owned buffers. Current callers are broad + enough that the table's exact resource type still stays open, but the init/service/query/cleanup + split is now grounded. The broader bundle or stream slot layer under that same table is bounded + now too: `0x00530c80` is the common open-or-reuse entry for named slots, `0x00531030` and + `0x00531150` are the shared write and read byte pumps, `0x00531340` and `0x00531360` are the + four-byte tagged-header wrappers used all over map, setup, world, and runtime bundle code, and + `0x00531380/0x00531410` are the shared variable-length heap-string load/save helpers built on + top of those byte pumps. The immediate neighbors are bounded too: `0x00531490` writes one raw + NUL-terminated string without the length prefix, `0x005314b0` is a callback-driven selector over + global `0x00ccba08`, and `0x00531500` is a small gate that only returns true when `[this+0x04]` + equals `1` and global `0x00ccb9f4` is nonnull. The next adjacent strip is now bounded + structurally too even though the owning subsystem is still open: `0x00531520..0x005317b0` + mostly share the inverse gate `[this+0x04] == 1 && 0x00ccb9f4 == 0`, then forward into one of + three global owners `0x00ccba00`, `0x00ccb9f8`, or `0x00ccb9fc`. The clearest member of that + strip is `0x005315c0`, a plain 3x4 affine point transform over three caller-supplied float + pointers. The rest are still best read as structural wrappers: `0x00531640` resolves the + zero-based index of the first callback-selected string matching the current `0x00ccb9fc` string + source, `0x005316d0` forwards one callback-selected entry pointer into `0x00569730`, and + `0x00531710/0x00531730/0x00531750/0x00531770/0x00531790/0x005317b0` are the small + mode-gated dispatch or query wrappers into the neighboring `0x5695..0x56ac..` family. The next + adjacent owner strip is bounded enough now too: `0x00531800/0x00531840` are the null-`0x00ccb9f4` + guarded call wrappers into `0x0056ae80(0x00ccb9f8)` and `0x00569cf0(0x00ccb9fc)` with scoped + reentrancy counter `0x00ccb9f0`; `0x00531880` releases optional handle `[this+0x4c]` through + two function-pointer calls when global `0x00624d58 == 1`; `0x005318b0` spin-waits for that same + reentrancy counter to drain; `0x005318c0` picks between owners `0x00ccb9f8` and `0x00ccb9fc` + from global selector `0x00ccba04`; and `0x005318f0` is the shared constructor that allocates + and initializes globals `0x00ccb9f8`, `0x00ccb9fc`, and `0x00ccba00`, then arms mode flag + `[this+0x04] = 1` when all three are live. The next owner block is no longer just a loose + cluster either: `0x00531a10` is the full teardown path for that same family, first raising + `0x00ccb9f4`, optionally fading scalar lanes `[0x00ccba00+0x104]` and `[0x00ccb9fc+0x58]` + through `0x00557d90/0x00569ae0/0x00569ca0` plus a `0x10`-tick sleep, then spin-waiting on + `0x005318b0`, releasing optional handle `[this+0x4c]`, shutting the three globals down, and + clearing `[this+0x04]` again. `0x00531c00` is the symmetric rebuild side: it force-calls + `0x00531a10(this,1)`, reconstructs the family through `0x005318f0`, and seeds the default live + state through `0x005696b0`, `0x00569660`, `0x00557d90`, `0x0056a8e0`, and `0x00569ae0` from + shell-owned scalars. The smaller strip between them is bounded structurally too: `0x00531d30` + refreshes the primary scalar and dispatches `0x00557e50`; `0x00531dc0` is the dual-scalar idle + predicate over `[0x00ccb9f8+0x20]` and `[0x00ccb9fc+0x58]`; `0x00531e50` is the string-driven + sibling of `0x00531e10`, tail-jumping into `0x0056a520` when the same family is ready; `0x00531e90` + stages one 16-dword local payload block into `[this+0x08..+0x44]` and forces + `[0x00ccb9fc+0x60] = 2`; `0x00531ed0` and `0x00531ef0` are the small active-mode field and + selected-hash-root queries; `0x00531f40` services `0x00ccb9f8/0x00ccb9fc` and clears staged flag + `[this+0x48]`; `0x00531f90` registers one of the guarded callbacks `0x00531800/0x00531840`; and + `0x00531fd0` is the timed primary-scalar transition service that coordinates `0x00ccba00` with + globals `0x00624d58/0x00624d60` under the same reentrancy counter `0x00ccb9f0`. The local + controller layer above that family is bounded now too: `0x00532150/0x00532200` are the + construct/destruct pair for the controller object itself, `0x00532230` rebuilds from one + callback-selected entry through `0x005314b0 -> 0x00531c00`, and `0x00532260` rebinds primary + handle `[this+0x4c]` while registering transition callback `0x00531fd0` and seeding selector + `[this+0x50]`. One other sibling table is bounded enough now + to keep separate too: local `.rdata` at `0x005c9a60` carries the same shared low `0x23a` slots + plus table-specific overrides `0x0041f680`, `0x0041f720`, `0x0041f7b0`, `0x0041f7e0`, + `0x0041f810`, and `0x0041f850`, with nearby literals `(%1)` and `Marker09`. The exact subtype + name behind that table is still open, but the behavior split is strong enough: `0x0041f680` + first refreshes the current global preview/helper owner through `0x00455de0` and then forwards + mode `1` plus handle `[this+0x23a]` into `0x004cf830`; `0x0041f720` formats `[this+0x356]`, + publishes the resulting shell text, and conditionally dispatches `0x00452fa0` with action + `0x12` when world state `[0x0062c120+0x2175]` is `0` or `0x15`; `0x0041f7b0` publishes one + fixed payload and only then jumps to `0x00453510` when that same world state is `0x12`. The + same table also has a tighter adjacent helper strip now: `0x0041f6a0` is the direct + `[this+0x37f] -> 0x00517cf0` slot-count query, `0x0041f6b0` is the rounded normalized-coordinate + world-scalar query above `0x0044afa0`, and that deeper helper is no longer opaque: it first + computes one distance-like term from the current cell to global preview-anchor fields + `[0x0062be68+0x24/+0x1c]` through the precomputed radial helper `0x0051dc00`, samples the + companion float raster `[world+0x1605]` at the current cell plus two 8-direction rings, keeps + the strongest local rise above the center sample, adds one thresholded preview-scalar bias from + `[0x0062be68+0x20]`, and then adds `0x32` more when the small global gate `0x0041fff0` passes. + That gate itself now reads as a shared shell/preview threshold test: it returns true when + `[0x006cec74+0x2bb] == 2`, or when the same mode dword is merely nonzero and preview scalar + `[0x0062be68+0x20]` exceeds the float threshold at `0x005c9a9c`. `0x0041f6e0` resolves the + current center world-grid cell and checks one packed `u16` token through `0x0042b2d0`, and + `0x0041f6f0` is the raw byte getter over `[this+0x42]`. One nearby mode-gated flag reader is + bounded too: `0x0041f910` returns + literal `1` when shell mode gate `0x004338c0` is inactive or the object class dword + `[this+0x23e]` is nonzero, and only on the class-0 path does it return the same byte + `[this+0x42]`. That gate itself is tighter now too: `0x004338c0` is just the normalized boolean + wrapper over `0x004d4150`, which returns nonzero when the shell-side owner field at `0x006d07b4` + is live. The release side under that same sibling family is bounded too: `0x00420650` + lazily seeds `[this+0x317]` from shell-profile word `[0x006cec78+0x0d]` before re-entering + `0x00420350`, and that body is now bounded as the local scalar refresh over `[this+0x31b]`: + it compares the seeded word against the current shell-profile word, maps the delta through one + bounded piecewise float curve, and applies one extra affine adjustment when `[this+0x23e]` is + nonzero. `0x00420670` then frees the optional dynamic payload at + `[this+0x37f]`, clears the cached `u16` link chain through `0x0041f8d0`, and tails into base + cleanup `0x00455d20`; and the small collection-side wrapper `0x00421700` simply resolves one + entry id, re-enters `0x00420670`, and erases that id from the owning collection. The + city-entry family also now has one tighter + helper-object branch. `0x00474030` + switches over mode enum `0..10`, maps those cases into `0x00475ed0` with selector families + `4/0xd/0xe` and fixed scalar presets `0.5/0.75/1.0/1.5/2.0`, and on success publishes the + caller-supplied world triplet through `[helper+0x4]`. The refresh helper `0x00474260` first + reloads payload through `0x00455fc0`, then samples the current normalized coordinates plus one + world-height scalar from `0x00448bd0`, and rebuilds `[this+0x23a]` through that same + mode-selected helper builder using mode `[this+0x242]`. The surrounding collection-side and + teardown helpers are tight enough now too. `0x004743d0` and `0x00474400` are the two release + siblings over the same helper field `[this+0x23a]`: both destroy that helper through `0x00475100` + when live and clear the field, but `0x004743d0` tails into the smaller base cleanup + `0x00455650`, while `0x00474400` tails into the heavier dynamic-payload cleanup `0x00455d20`. + The small predicate `0x00474430` simply returns `1` unless shell mode gate `0x004338c0` is + active, in which case it returns byte `[this+0x42]`; the exact meaning of that flag byte is still + open, but the mode-gated query itself is bounded now. One level higher, `0x00474450` constructs + the collection rooted at vtable `0x005ce4a8` with fixed parameters `(0,0,0,0x14,0x0a,0,0)`, and + bootstrap caller `0x004487a9` stores that collection into global `0x006cea50`. The collection's + entry path is also bounded now: `0x004744a0` seeds a stack-local temporary entry through + `0x00474110`, allocates one `0x250`-byte live record, resolves it, constructs it through + `0x00474130`, and then tears the temporary entry down through `0x004743d0`; `0x00474510` + resolves one entry id, releases it through `0x00474400`, and removes it from the collection. The + collection-owned load loop at `0x00474540` sits directly beneath `map_load_city_database` + `0x00474610`: it opens the same `0x61a9/0x61aa/0x61ab` bracket on the caller-supplied bundle, + binds the selected path context, iterates the current collection, dispatches each record through + vtable slot `+0x40`, accumulates the returned byte counts, and tears down the temporary entry + after each record. That still leaves broader semantic questions open, but the current static edges + around the city-entry family are now largely exhausted. The adjacent scaffolding is bounded too. + Base helper `0x00455b20` initializes the shared `0x23a`-sized record family by installing base + vtable `0x005cb1c0`, clearing the scalar bands `[+0x206/+0x20a/+0x20e/+0x22e/+0x232]`, zeroing + the seven-dword block `[+0x212..+0x22a]`, and re-entering `0x0052ecd0`; that is why it shows up + not only in the city-entry temporary constructor `0x00474110`, but also in several later object + construction paths outside the city family. The city collection itself now has a bounded teardown + side too: `0x00474480` is the small release-and-free wrapper for the collection rooted at + `0x005ce4a8`, and teardown caller `0x004492c3` uses it before freeing the global collection + pointer at `0x006cea50`. On the load side, `0x00445713`'s broader setup branch re-enters + `map_load_city_database` `0x00474610` on that same global `0x006cea50` collection. Outside the + city-specific branch, the two tiny dispatch wrappers `0x00455a40` and `0x00455a50` are also now + bounded as raw vtable-slot helpers: the first jumps through entry slot `+0x44`, while the second + pushes one caller argument into slot `+0x40` and then clears the global roots + `0x006acd38/0x006acd3c/0x006acd40`. Finally, `0x00455a70` is now bounded as the generic + current-position triplet publisher that queries `0x0052e720`, converts through + `0x006d4024 -> 0x0051f090 -> 0x00534490`, adds a caller-supplied height bias, optionally rounds + under `0x00434050`, and publishes through `0x00530720`. The temporary-entry constructor and live + entry constructor are bounded now too. `0x00474110` is the tiny stack-local initializer: it + re-enters shared base init `0x00455b20`, clears helper fields `[+0x23a]` and `[+0x242]`, + installs vtable `0x005ce428`, and returns. `0x00474130` is the real live-entry constructor: it + stores the entry id into `[+0x23e]`, clears the trailing helper payload block `[+0x246..+0x24e]`, + stores mode `[+0x242]`, derives one world-height scalar from the supplied coordinate pair through + `0x00448bd0`, builds helper field `[+0x23a]` through `0x00474030`, and then seeds the remaining + default scalar or flag tuple through `0x00455b70` using the fixed defaults at + `0x005ce49c/0x005ce4a0/0x005ce4a4`. That broader helper is no longer city-specific either: + `0x00455b70` is now bounded as the shared scalar-band initializer that clears the same + `[+0x206/+0x20a/+0x20e/+0x22e/+0x232]` family, optionally copies up to three caller-supplied + strings into `[+0x206/+0x20a/+0x20e]`, synthesizes one default local token buffer when the middle + string is absent, chooses one effective mode string from the third or first input, derives one + owner handle or transform token through `0x0051f090` unless the caller suppresses that path, and + then seeds the remaining scalar band through `0x0052edf0` and `0x0052e670`. + The same specialization also now has one tighter UI-facing side. The override trio + `0x0040e4e0`, `0x0040e880`, and `0x0040e9d0` all sit in the same `0x005c8c50` table and reuse + the linked-site-capable vtable `+0x70` latch together with creation-mode byte `[this+0x3d4]`. + `0x0040e4e0` is the strongest current owner for contextual status text: it branches across + linked-peer checks, world-mode fields `[0x0062c120+0x2171/+0x2175/+0x2179/+0x2181]`, current + owner state, and candidate or linked-peer display labels, then formats localized ids such as + `0x00af`, `0x00b0`, `0x00b1`, `0x00b2`, `0x00b3`, and `0x0afd` before pushing the result through + shell presenter `0x00538c70`. `0x0040e880` pairs with that publisher on the action side: it + first resets the same presenter through the fixed token at `0x005c87a8`, then dispatches several + world-side follow-ons through `0x00413620`, `0x00453510`, `0x00452db0`, and `0x00452fa0` under + the same linked-peer and world-mode gates. `0x0040e9d0` is the narrower query-style formatter: + when shell branch `[0x006cec74+0x74]` is live it formats one localized label with the fixed + suffix `\nAbsIndex %d`, otherwise it can return one company-side owner label through + `0x00426b10`, and only then falls back to `0x00455860`. So the current best read is that this + concrete specialization owns both the ambient or animation transient family and one linked-peer + status or action UI surface, without yet proving the user-facing subtype name. + One smaller subtype hook cluster is tighter now too. The concrete table also carries + `0x0040d170` and `0x0040d1b0`, both of which resolve the current candidate through cached stem id + `[this+0x3cc]` and then test candidate dword `[candidate+0x4b]`. When that flag is nonzero, + `0x0040d170` tail-calls the primary transient builder `0x0045c310` and `0x0040d1b0` tail-calls + the matching release path `0x0045c3c0`. The same neighborhood now also gives direct cached-record + resolvers instead of more anonymous pointer math: `0x0040d1f0` returns the linked peer from + `[this+0x2a8]` through `0x006cec20`, while `0x0040d210` returns the owner-side record from + `[this+0x276]` through `0x0062be10`. That makes the specialization-side ownership split cleaner: + the `0x005c8c50` family is not only formatting labels and driving side effects, it also has a + direct candidate-flag hook for building or dropping the primary transient handle. + The last lower side reads are tighter now too. `0x0040e450` first seeds the projected-slot cache + through `placed_structure_cache_projected_rect_profile_slot_id` `0x00414470` before it re-enters + `0x00418a60`, and the broader stem-based builder at `0x00418be0` now has one named optional side + renderer instead of an anonymous callsite: + `placed_structure_render_local_runtime_overlay_payload_from_projected_bounds` `0x00418040`. + The side refresh split is bounded now too. `0x0040ee10` publishes one local position or scalar + triplet through the shared setter `0x00530720`, then tails into + `placed_structure_refresh_linked_site_anchor_position_triplet_for_local_runtime` `0x0040e360`; + that smaller follow-on only runs on the current subtype-`1`, class-`3`, linked-site branch, and + recomputes one local-runtime triplet from the linked peer's route-entry anchor when that anchor + is still live. The heavier sibling above that side refresh is bounded now too: + `placed_structure_set_world_coords_and_refresh_local_runtime_side_state` `0x0040eba0` is the + world-coordinate mutation helper that recomputes `[site+0x388]` and `[site+0x38c]`, rewrites the + world-grid owner mapping through `0x0042c9f0` and `0x0042c9a0`, updates the subtype-`4` + proximity-bucket family when needed, rebuilds the same local position or scalar triplet, and + then tails into the linked-site anchor follow-on at `0x0040e360`. One later caller into that + same side-refresh family is bounded now too: `0x00419110` clamps a caller rectangle to the live + world bounds, resolves one per-cell bucket chain through the hashed map at `[arg0+0x88]` and + `0x0053dae0`, and then re-enters `0x0040eba0` for every bucketed site in that rectangle using + the stored per-entry coordinate pair plus two zero flags. Current grounded caller is the edit-side + branch at `0x004bc851`, immediately after the neighboring nibble and companion-float mutations, + so this now looks like a bucket-map-driven local-runtime side-state refresh wrapper rather than + another broad site sweep. + The sibling policy-`1` side is tighter now too. The constructor lane no longer stops at “one + linked site id at `[site+0x2a8]`”: the subtype-`1` branch in + `placed_structure_construct_entry_from_candidate_and_world_args` `0x0040f6d0` now clearly + allocates that linked record through + `placed_structure_collection_allocate_and_construct_linked_site_record` `0x00481390`, whose lower + constructor is `placed_structure_construct_linked_site_record_from_anchor_and_coords` + `0x00480210`. That lower constructor seeds the linked record's own id and anchor-site id, clears + the local route-anchor and display-name fields, projects the anchor footprint into world space, + and then either binds an already-covered route entry through + `route_entry_collection_try_reuse_covering_entry_for_site_coords_and_heading` `0x00417b40` or + falls through into the neighboring policy-`1` route-entry synthesis family around `0x00493cf0` + before rebinding the chosen route entry through `0x0048abc0`. + The cleanup side is tighter now too. Linked-site removal now has a bounded owner at + `placed_structure_collection_remove_linked_site_record` `0x004813d0`: it resolves the linked + record through `0x006cec20`, runs the per-record teardown + `placed_structure_teardown_linked_site_runtime_state_before_removal` `0x00480590`, removes the + live entry from the collection, and only then re-enters the still-bounded company-wide follow-on + at `0x00429c10` when the removed record passed the narrower transit-like latch. That per-record + teardown is no longer just “clear some scratch fields.” It now clearly clears the route-style + scratch lane, clears the five proximity buckets at `[site+0x590..0x5b8]`, detaches or invalidates + the current route-entry anchor, frees the three per-site byte arrays at `[site+0x24..0x2c]`, + clears this site's indexed byte from the corresponding arrays of later placed-structure records, + and then re-enters `0x00436040` with the current site id. + That company-side follow-on is no longer just one opaque callback either. It is now bounded as + `company_collection_refresh_active_company_linked_transit_site_peer_caches` `0x00429c10`, which + walks the active company roster and re-enters + `company_rebuild_linked_transit_site_peer_cache` `0x004093d0` on each company. That per-company + fast pass stamps a refresh tick at `[company+0x0d3e]`, clears and repopulates the + placed-structure-side cache cells addressed through `[site+0x5bd][company_id]`, marks the + eligible linked transit sites for that company, allocates one `0x0d`-stride peer table for each + eligible site, and fills those peer rows from + `aux_route_entry_tracker_query_best_route_entry_pair_metric_with_endpoint_fallbacks` + `0x004a6630`. That helper no longer reads as one anonymous route sweep: it either uses the fixed + pair directly or falls back across tracker endpoint combinations before returning the winning + route-entry id, one route-step count, and one companion mismatch count. The fast cache now reads + more cleanly too: peer-record dword `+0x05` stores that step count, while float `+0x09` stores + the normalized continuity share derived from `(steps - mismatches) / max(steps, 1)`, not a raw + delta-per-step ratio. The + adjacent timed wrapper `company_service_linked_transit_site_caches` `0x00409720` now shows the + cadence too: `0x004093d0` is the shorter-interval refresh, while the older heavier sibling at + `0x00407bd0` was only revisited on the longer interval. + That heavier sibling is now bounded too: + `company_rebuild_linked_transit_autoroute_site_score_cache` `0x00407bd0` no longer looks like a + generic tail refresh. It reuses the fast peer tables, rebuilds candidate-local amount bands plus + normalized issue-opinion scales, and then folds the peer-side route metrics back into three + per-site cache floats with a cleaner split: + `+0x12` is the raw surviving site-score total, + `+0x0e` is the continuity-and-step-weighted companion total, + and `+0x16` is the promoted final site-ranking lane chosen from the strongest grouped candidate + bands. + That also closes most of the cross-version impact question: + the pre-`1.03` versus `1.03+` tracker metric split now looks like it mainly perturbs the weighted + `+0x0e` lane and the promoted `+0x16` lane, not the raw `+0x12` total. + That final lane then feeds the neighboring selectors + `company_select_best_owned_linked_transit_site_by_autoroute_score` `0x00408280` and + `company_build_linked_transit_autoroute_entry` `0x00408380`. That makes the company-side follow-on + read more like a linked-transit autoroute cache family than a generic company maintenance pass. + The neighboring reachability gate is tighter now too: + `company_query_cached_linked_transit_route_anchor_entry_id` `0x00401860` caches one company-side + route-entry anchor, and + `placed_structure_is_linked_transit_site_reachable_from_company_route_anchor` `0x004801a0` + uses that anchor to decide whether a foreign linked transit site can still participate in the + current company's fast peer cache. + The first direct train-side consumer above that cache family is bounded now too: + `train_try_append_linked_transit_autoroute_entry` `0x00409770`. After servicing the owning + company's caches, it asks `0x00408380` for one staged `0x33`-byte route entry using the train's + current anchor site, then either appends that entry through `0x004b3160` and refreshes the new + trailing selection through `0x004b2f00`, or rotates one existing slot in place when the local + two-entry cap has already been reached. So this edge now reaches an actual train-side autoroute + append lane rather than stopping at anonymous company-side cache cells. The weighted cache lanes + still do not escape that route-choice family directly: this train-side append path only inherits + the weighted site and peer choice by calling `0x00408380`, not by reading cache `+0x0e/+0x16` + itself. + The train-side follow-on above that seed path is bounded now too. The owning company can count + its live roster through `company_count_owned_trains` `0x004264c0`, measure one aggregate linked + transit site pressure through `company_compute_owned_linked_transit_site_score_total` + `0x00408f70`, and then rebalance that roster through + `company_balance_linked_transit_train_roster` `0x00409950`. + The aggregate helper no longer reads as a raw sum either: + it starts from the site-cache `+0x12` totals, converts that into one tentative roster target + through year and site-count ladders, and on build `1.03+` adds one special distance-side scaling + branch when exactly two eligible linked transit sites survive. + Because it consumes `+0x12` rather than `+0x0e` or `+0x16`, current evidence now says the tracker + compatibility split is more important for seeded route choice and ranked site choice than for the + final company train-count target itself. The local linked-transit chain is now bounded enough to + say that directly: weighted cache lanes feed `0x00408280 -> 0x00408380 -> 0x00409770/0x00409830`, + while the separate pressure or roster lane feeds `0x00408f70 -> 0x00409950` from raw `+0x12`. + The balancer then applies two age bands to company-owned trains: + very old trains are removed when the roster already exceeds target or upgraded when it still + needs capacity, while the mid-age band can trigger one narrower upgrade pass. + After that it fills any remaining deficit by either packaging multiplayer opcode `0x75` or + locally re-entering + `company_try_add_linked_transit_train_and_publish_news` `0x00409830`. The two visible news + helpers under it are bounded too: `0x00409830` emits RT3.lng `2896` for a newly added train, + while `company_publish_train_upgrade_news` `0x00409300` emits RT3.lng `2897` for the upgrade + branch. + The subtype-`4` sibling side is bounded now too. The nearby-site bucket family now has: + `placed_structure_append_nearby_transit_site_distance_bucket_entry` `0x0047fdb0`, + `placed_structure_remove_site_id_from_proximity_bucket_lists` `0x0047dd10`, and + `placed_structure_clear_proximity_bucket_lists` `0x0047dcd0`, plus the two collection sweeps + `placed_structure_collection_append_site_into_all_proximity_bucket_lists` `0x00481480` and + `placed_structure_collection_remove_site_id_from_all_proximity_bucket_lists` `0x004814c0`. + Current evidence says those five buckets store `(peer site id, distance)` pairs for nearby + station-or-transit peers, grouped through the five-way classifier at `0x0040d350`. The older + stream-backed side is bounded too: `placed_structure_collection_load_dynamic_side_buffers_from_stream` + `0x00481430` walks the live placed-structure collection and re-enters + `placed_structure_load_dynamic_side_buffers_from_stream` `0x0047d8e0`, which repopulates the + route-entry list, the three per-site byte arrays, the five proximity buckets, and the trailing + scratch band from the caller-supplied persistence stream. + The linked-site route-entry list itself is tighter now too. The refresh or teardown branch at + `0x0040e102` re-enters `placed_structure_remove_route_entry_key_and_compact` `0x0047d810`, which + removes one matching `u16` key from the six-byte list rooted at `[site+0x462]/[site+0x466]`, + compacts the surviving entries into a replacement buffer, and decrements the stored route-entry + count. + The broader linked-site mutable runtime strip is tighter now too. + `placed_structure_rebuild_local_service_sampled_cell_list_and_reset_route_link_scratch` + `0x0047f320` is no longer just a teardown-side stub: it resolves an effective comparison mode + from the linked candidate class byte `[candidate+0x8c]` unless the caller overrides it, derives + one radius threshold from current world coordinates `[site+0x4a8/+0x4ac]`, frees the prior + sampled-cell buffer at `[site+0x34]`, always clears the route-link scratch pair + `[site+0x462]/[site+0x466]`, and then scans one bounded world-grid rectangle through + `[0x0062c120+0x2129]` with per-cell distance measured by `0x0051db80`. For accepted cells it + emits temporary twelve-byte `(grid x, grid y, sampled score)` rows through `0x0042b190`, + `0x0042c530`, and `0x0042c580`; when caller arg0 is zero it compacts one representative subset + of those temporary rows into the persistent list at `[site+0x34]/[site+0x38]`, while nonzero + arg0 callers use the same helper as a clear-and-scan companion without the final materialization + step. Current grounded callers are the linked-site refresh and teardown strip + `0x00480542/0x004805c2/0x00480727/0x004807e2`. + The proximity-bucket rebuild side above that list is tighter now too. + `placed_structure_rebuild_nearby_transit_site_distance_buckets_from_neighbor_cells` + `0x0047fef0` first requires the current record to pass the narrower station-or-transit class gate + `0x0047fd50`, quantizes the current site position through `0x00455800/0x00455810`, walks the + surrounding live cell window through `[0x0062c120+0x2129]`, follows each cell's linked + placed-structure chain through word field `[cell+0x0d6]` plus next-id `[peer+0x2a2]`, keeps only + peers whose resolved candidate subtype byte `[candidate+0x32]` equals `4`, and appends the + surviving `(peer site id, distance)` pairs into the same five bucket arrays rooted at + `[site+0x590..+0x5a4]`. So the narrower one-peer append helper `0x0047fdb0` now has a real + broader owner rather than only collection sweeps. + The whole linked-site refresh owner is correspondingly clearer now too. + `placed_structure_refresh_linked_site_runtime_side_buffers_and_route_entry_anchor` `0x00480710` + first clears the current proximity buckets through `0x0047dcd0`, runs `0x0047f320(1,arg1)` + against the pre-update state, republishes the current site position into the world-grid owner map + through `0x0042bbf0/0x0042bbb0`, reruns `0x0047f320(0,-1)` to materialize the current + sampled-cell list, and then rebuilds the nearby-transit buckets through `0x0047fef0`. After that + it either reuses a still-valid route-entry anchor through + `route_entry_collection_try_reuse_covering_entry_for_site_coords_and_heading` `0x00417b40` and + `placed_structure_rebind_route_entry_anchor_to_site_id` `0x0048abc0`, or synthesizes a + replacement through `0x00493cf0` before rebinding it the same way; when an old anchor survives + but now points at a different owner, the helper clears the prior `[entry+0x222]` back to `-1`. + The world-cell owner and route-gather helpers beneath that strip are bounded now too. Word + `[cell+0xd4]` is the head of one placed-structure owner chain: `0x0042bbb0` prepends the current + site id into that chain by writing the previous head into `[site+0x3c]` through the tiny setter + `0x0047d6f0`, while `0x0042bbf0` removes one site id from the same chain by walking the linked + `[site+0x3c]` next pointers until it can splice the requested site out. The sampled-cell rebuild + also now has its lower route-gather leaf: `0x0042c530` walks one world cell's linked-site chain + from word `[cell+0xd6]` through next-id `[site+0x2a2]` and appends each visited site id plus the + caller payload into the six-byte route-entry list helper `0x0042b190`. That same compact list now + has its two local companions bounded too: `0x0042b230` removes one row by leading `u16` key, and + `0x0042b2d0` is the shared contains-key predicate over the same `[...+0xeb]/[...+0xef]` list. + The neighboring `[cell+0xd6]` linked-site chain is bounded now too. `0x0042c9a0` prepends one + site id into that chain by writing the previous head into `[site+0x2a2]` through the tiny setter + `0x0040cb00`, storing the new head back into `[cell+0xd6]`, and then re-entering the paired + rebuild helpers `0x0042c690` and `0x0042c8f0`. `0x0042c9f0` is the remove companion over the + same chain: it walks the linked `[site+0x2a2]` next pointers until it can splice the requested + site id out of the `[cell+0xd6]` head chain, then reruns the same two rebuild helpers. + The two remaining numeric leaves under this strip are bounded now too. `0x0042c580` accumulates + the directional word fan from `[cell+0xf3 + dir*2]` while stepping toward one caller-supplied + grid target through the fixed offset tables at `0x00624b28/0x00624b48`, and that is the floating + sampled-score source later stored by `0x0047f320`. `0x0042c960` is the shared rounded + issue-opinion-scaled word-lane query: it multiplies one local word lane `[this+index*2] << 4` + against the scenario-side scale returned by `0x00437d20(index)` and rounds the result through + `0x005a10d0`. + The broader company-side owner above these pieces is tighter now too. The periodic service pass + `company_service_periodic_city_connection_finance_and_linked_transit_lanes` `0x004019e0` now + reads as the current outer owner for this branch: it sequences the city-connection announcement + lanes, the linked-transit train-roster balancer, the acquisition-side sibling + `company_try_buy_unowned_industry_near_city_and_publish_news` `0x004014b0`, the annual finance-policy helper + `company_evaluate_annual_finance_policy_and_publish_news` `0x00401c50`, and the shorter-versus- + longer linked-transit cache refresh tail through `0x004093d0` and `0x00407bd0`. That outer pass + also has one tighter temporary-state role now: it clears company bytes `0x0d17/0x0d18/0x0d56`, + mirrors `0x0d17` into scenario field `0x006cec78+0x4c74` only while the earlier route-building + side runs, and restores the original scenario value on exit. Current evidence now ties `0x0d17` + to the shared preferred-locomotive chooser `0x004078a0`: the override is only armed when that + helper picks one locomotive whose engine-type dword is `2`. That engine-type lane now best reads + as electric rather than an unnamed class slot, because the linked approval helper around + `0x0041d550` now reads as a real locomotive-era and engine-type policy gate, dispatching the same + `0/1/2` field across three scenario-opinion lanes while the local player-facing engine-type + family is explicitly `Steam / Diesel / Electric`. That same gate also now ties the later scenario + bytes `0x4c97..0x4c99` back to the editor-side `Locomotives` page rather than treating them as + anonymous availability flags: they are the live `All Steam Locos Avail.`, `All Diesel Locos + Avail.`, and `All Electric Locos Avail.` policy bytes behind `0x004cd680` / `0x004cf0d0`. The + current logic is also tighter than a plain override tier: a positive engine-family opinion result + can carry the gate by itself only while none of those three editor bytes is enabled; once any of + them is nonzero, `0x0041d550` instead requires one matching intersection between the record-local + family bytes and the enabled editor family bytes. The `WhaleL` carveout is narrower now too: + current data-file correlation ties that stem to the `Orca NX462` / `WhaleL_NE` locomotive family, + and it explicitly zeros that positive-opinion result before the later family-availability checks, + so it loses the shortcut rather than gaining a special approval path. The same + chooser now also has a bounded fallback below it, `locomotive_collection_select_best_era_matched_non_electric_fallback_id` + `0x00461cd0`, which explicitly skips engine-type `2` and chooses the lowest-penalty remaining + locomotive by era mismatch and approval gates. The route-search side is tighter too: this + electric-only override now clearly feeds the first path-sweep branch in `0x0049bd40`, forcing the + larger `1.8` initial quality multiplier instead of `1.4`, which is the same branch otherwise + chosen by explicit route-policy byte `4`. So the later annual finance helper is reading + same-cycle side-channel state from the earlier city-connection and linked-transit branches, not + unrelated long-lived finance fields. The inner + finance helper is not debt-only either. Current grounded outcomes include bankruptcy news + `2881`, the debt restructure family `2882..2886`, a later share-repurchase headline `2887`, and + the dividend-side adjustment branch. The main commit verbs under that helper are now grounded too: + `company_repay_bond_slot_and_compact_debt_table` `0x00423d70`, + `company_issue_bond_and_record_terms` `0x004275c0`, + `company_repurchase_public_shares_and_reduce_capital` `0x004273c0`, and + `company_issue_public_shares_and_raise_capital` `0x00427450`. The threshold side is tighter now + too. The earliest creditor-pressure lane requires scenario mode `0x0c`, the bankruptcy toggle + `[0x006cec78+0x4a8f]` to be clear, at least `13` years since `[company+0x163]`, and at least + `4` years since founding year `[company+0x157]`; it then scans the last three years of the + derived net-profits and revenue lanes `0x2b` and `0x2c`, chooses one negative pressure ladder + `-600000 / -1100000 / -1600000 / + -2000000` from the current slot-`0x2c` bands around `120000 / 230000 / 340000`, requires the + broader support-adjusted share-price or public-support scalar at least `15` or `20` depending on + whether all three sampled years failed, checks the current fuel-cost lane in slot `0x09` against + `0.08` times that ladder, and requires the + three-year slot-`0x2b` total to clear one final `-60000` gate before it falls into the + bankruptcy commit and RT3.lng `2881` headline. + The middle debt-capital layer is split more clearly now too. With `[+0x4a8b]` clear, one annual + bond lane first simulates full repayment through `company_repay_bond_slot_and_compact_debt_table` + and then uses the post-repayment cash window with fixed `-250000` and `-30000` thresholds plus + the broader linked-transit train-service latch `[company+0x0d56]` to decide whether to append one + or more `500000` principal, `30`-year bonds. The repurchase lane is separate again: when the + city-connection announcement-side latch `[company+0x0d18]` is set, growth setting `2` does not + suppress it, and `[+0x4a87]` is clear, it starts from one `1000`-share batch, can replace its + default `1.0` factor with one linked-chairman personality scalar, scales that by `1.6` when + growth setting `1` is active, and then runs one `800000` stock-value gate plus one + support-adjusted-share-price-times-factor-times-`1000`-times-`1.2` affordability gate before the + repeated `1000`-share buyback commits behind RT3.lng `2887`. The ordering above this helper is + tighter now too: + `company_service_periodic_city_connection_finance_and_linked_transit_lanes` clears those latches + first, runs the city-connection and linked-transit branches, and only then enters the annual + finance helper, so these look like same-cycle reaction gates rather than long-lived balance-sheet + flags. + After the earlier debt or bankruptcy outcomes stay inactive, the later stock-capital lane also + has a tighter bounded shape now too: it only opens on build `1.03+`, only after the earlier + bankruptcy, bond, and repurchase outcomes stay inactive, and with the bond and stock toggles + `[+0x4a8b]` and `[+0x4a87]` clear, at least two bond slots live, and at least one year since + founding. It derives one issue batch from outstanding shares rounded down to `1000`-share lots + with floor `2000`, trims that batch until the broader support-adjusted share-price scalar times + batch no longer exceeds the `55000` gate, recomputes the pressured support-adjusted share-price + scalar and the paired `price/book` ratio, then tests the remaining gates in a fixed order: + share-price floor `22`, proceeds floor `55000`, current cash from `0x2329/0x0d` against the + chosen highest-coupon bond principal plus `5000`, one later stock-issue cooldown gate that + converts the current issue mixed-radix calendar tuple at `[company+0x16b/+0x16f]` through + `calendar_point_pack_tuple_to_absolute_counter` `0x0051d3c0` and compares the result against the + active world absolute calendar counter `[world+0x15]`, and only then the coupon-versus-price-to-book + approval ladder `0.07/1.3 -> 0.14/0.35`. The issue mutator preserves the previous tuple in + `[company+0x173/+0x177]` and refreshes the current tuple from `[world+0x0d/+0x11]` on the + derived-pricing lane. On success it issues two + same-sized tranches through repeated `company_issue_public_shares_and_raise_capital` calls and + publishes a separate equity-offering news family rooted at localized id `4053`, not the earlier + debt or buyback headline family. + The dividend side is bounded too: it requires the dividend toggle `[0x006cec78+0x4a93]` to be + clear, mode `0x0c`, at least `1` year since `[company+0x0d2d]`, and at least `2` years since + founding, then averages the last three years of the net-profits lane `0x2b`, folds in the + unassigned-share pool and the current `0x0d` band, applies the map-editor building-growth + setting `[0x006cec78+0x4c7c]`, treats growth setting `1` as a `0.66` scale-down and setting `2` + as a zeroing pass on the current dividend, quantizes surviving adjustments in tenths, and + finally clamps against + `company_compute_board_approved_dividend_rate_ceiling` `0x00426260`. + The linked-transit route-seeding side has one tighter sibling now too: + `company_reset_linked_transit_caches_and_reseed_empty_train_routes` `0x00401940`. It clears the + two company-side linked-transit cache timestamps, forces one immediate cache rebuild through + `0x00409720`, strips route lists from company-owned trains in modes `0x0a/0x13`, and then + re-enters `train_try_append_linked_transit_autoroute_entry` `0x00409770` only when a train's + route list has become empty. + On the wider chooser question, the current evidence is also tighter than before: every recovered + external owner of `0x00402cb0` is still in the city-connection family, so the two later direct + placement lanes currently read as city-connection fallback behavior rather than a broadly shared + world placement service. + It can still unwind through route-state cleanup without committing new placed structures, so the + exact lower helper semantics are not fully closed, but the broader chooser is no longer + anonymous and its main policy split is now visible. The two lower helpers directly under those + commit lanes are bounded now too: + `placed_structure_project_candidate_grid_extent_offset_by_rotation` `0x00417840` is the shared + projected-footprint offset helper over candidate bytes `[candidate+0xb8]` and `[candidate+0xb9]`, + and `placed_structure_validate_projected_candidate_placement` `0x004197e0` is the shared + go-or-no-go validator that checks company, territory, world-tile, and footprint occupancy state + before either direct-placement commit is allowed to fire. Its strongest current subtype branch is + a station-attachment or upgrade-style lane keyed by `[candidate+0x32] == 1`, which now has the + concrete failure family `2901..2906`: blocked upgrade footprint, ground not flat enough, not + your track, insufficient track-laying capacity, cannot connect to existing track, and ground too + steep. That tightens the chooser materially without yet proving that the validator is + station-only for every caller. + The recurring outer owner is tighter now too: + `placed_structure_collection_refresh_quarter_subset_route_style_state` `0x00413580` walks every + fourth live placed structure from a scenario-time-derived offset and re-enters the per-site + rebuild with stack flag `0`, giving the route-style lane a concrete recurring maintenance sweep + under `simulation_service_periodic_boundary_work` rather than only a floating caller note. One + neighboring helper is now bounded on the message side too: + `shell_building_detail_handle_subject_value_row_band_action` `0x004ba270` switches over the + clicked row family `0x7d07..0x7d14`, treats subject bytes `+0x21/+0x22/+0x23` as one current + selection plus one bounded low/high pair, increments the family dirty latch at `0x006cfe0c` on + change, and republishes the refreshed value through the shared shell control helper on code + `0x66`. One neighboring helper is now bounded on the side-list path too: + `shell_building_detail_propagate_selected_subject_state_into_side_list` `0x004b9ec0` walks the + sibling list owner at `0x006cfe08`, copies the active subject state into each side-list record, + mirrors the current service or capability id at `+0x24`, and preserves the `0x40/0x20/0x10` + subflags from the active subject. That means the value-row actions and later selector rows now + read as propagating one shared building-detail state across the sibling list rather than only + mutating one isolated subject record. One neighboring helper is + now bounded separately too: `shell_building_detail_refresh_subject_pair_value_rows` `0x004bad20` + owns the mutually exclusive value-row pairs `0x7d07/0x7d08`, `0x7d11/0x7d12`, and + `0x7d13/0x7d14`, choosing among them from the same selected-subject flag byte and payload fields + at `+0x22/+0x23`, while the larger cargo-or-service row owner also gates the extra visual lanes + `0x7d6a`, `0x7d6b`, and `0x7d9d` from that same subflag family. The asset-string block is tighter + too: that branch family now explicitly uses `AnyCargo.imb`, `AnyFreight.imb`, `PassMail.imb`, + `Caboose.imb`, and `Dining.imb`, with the bit-`0x20` special lane already aligned to + `Caboose.imb` and the sibling bit-`0x10` special lane now aligned to `Dining.imb`. The larger + `0x7f58..0x801f` band is no longer just a styled row family either: + `shell_building_detail_present_flagged_service_capability_popup` `0x004b9fd0` is now grounded as + its explanatory popup callback. It resolves either one fixed express-side row from `0x00621e04` + or one active candidate or service id from `[subject+0x24]`, then formats one popup through the + shell message-box path. The neighboring refresh helper `shell_building_detail_refresh_flagged_service_capability_rows` + `0x004b9a20` is tighter now too: `0x7d07..0x7d1c` is not one anonymous block, but a real mask + partition over subject bits `0x20` and `0x10`, with one zero-mask pair, one bit-`0x20`-only + pair, one exclusive-or pair, and later one-bit and two-bit indicator rows. RT3.lng now closes + the fixed popup text family too: the single-line branch uses + `3922` `%1\nLoads available at %2: %3`, while the richer ordinary-candidate branch uses + `2981` `%1\nLoads available at %2: %3 Current Price: %4` and can append + `2982` `Price at next station, %1: %2 (%3%4)`. The selector band is narrower too: current + refresh-side evidence shows `0x7f58..0x801f` as one selected-ordinal highlight family over the + three fixed express rows plus the ordinary active-candidate rows, not as a generic unstructured + list. The neighboring `0x8020..0x8051` band is tighter too: it is primarily the matching + remove-entry family for the selected subject's live id list, with two special row indices + re-routing into the `0x7d0f/0x7d10` subflag-clearing path instead of ordinary list compaction + when the current `0x20/0x10` service-bit combination demands it. That means the exact captions + are no longer broadly open across the whole selector family: the fixed express-side rows, the + mask partitions, and the add/remove structure are grounded, and the remaining caption gap is + mostly the ordinary candidate rows further down the same band. The top-level toggles are + tighter now too: the paired + `0x7d02/0x7d03` controls are the real mode switch over subject bit `0x40`, choosing between the + bounded pair-value branch and the current-selection/status branch around `0x7d0d/0x7d0e`, while + the smaller `0x7d0f/0x7d10` controls flip the same special-service subflags later rendered as + `Caboose` and `Dining Car`. One adjacent control is tighter now too: the extracted + `BuildingDetail.win` resource contains the plain-English line `Set the initial cargo amount for + 'Disable Cargo Economy' scenarios.`, and the `0x7d01` plus `0x7d09/0x7d0a` message-side branch + can mirror the current subject or selection through + `shell_building_detail_submit_aux_owner_subject_sync_request` `0x004b9e10` into the auxiliary + owner queue at `[0x006cd8d8+0x8f48]`, with side-owner presence now explicitly grounded through + `shell_has_auxiliary_preview_owner` `0x00434050`. That queued request is tighter too: both + current callsites forward the same side-list mirror latch at `[0x006cfe08+0x0c]`, so the + auxiliary owner now clearly sees not just the staged subject but also whether the local + `BuildingDetail` side-list is in mirrored-subject mode. The same `0x7d01` lane also now has one + clear rejection note: localized id `3587` `This option is only available by following the + tutorial.` now sits behind the active tutorial flag at `0x006d3b4c` and the cached previous + tutorial expected-control id at `0x00622b38`, while the neighboring tutorial helper + `tutorial_advance_step_and_refresh_expected_control_ids` `0x00516be0` now grounds + `0x00622b34/0x00622b38/0x00622b3c` as the current and previous expected-control cache rather + than anonymous globals. The last field is tighter now too: `0x00622b3c` is currently best read + as the active tutorial step's alternate-accepted companion control id, because the generic shell + control path compares clicked control ids against it directly and suppresses the `3587` tutorial + rejection when they match. That does not fully close the player-facing caption bind for every + control, but it does bound the neighboring side-owner sync and tutorial-rejection lane instead + of leaving it as anonymous glue. + The extra pre-insert gate is narrower than it + first looked. It is now grounded as tutorial-only: + `tutorial_validate_train_route_station_indicator_step` `0x00516d00` checks the current tutorial + step from the shell tutorial descriptor table at `0x00622b48` before a live station-or-transit + site id can be committed into the staged route entry, and the currently accepted steps align with + localized prompts `3777` and `3778`, the two train-routing tutorial instructions that tell the + player to click the Milan and Turin station indicators. Outside that tutorial state family, the + route-entry insertion path is not gated there. The adjacent validator is tighter now too: + `train_route_list_validate_reachability_and_station_pair` `0x004b2c10` walks that same route list, + resolves placed-structure-backed entries through the live placed-structure and route-node + collections, uses the direct route-node payload branch for the remaining entry family, and fails + with `3089..3091` when the resulting route cannot be traversed or does not preserve a valid + terminal station pair. The post-validation follow-on is bounded too: + `train_current_route_context_uses_strict_reachability_mode` `0x004a9460` is now the small shared + gate above the stricter branch, keyed off the current linked route object's downstream class type, + and `train_set_route_operating_mode_and_scalar` `0x004ab980` now reads as the shared train mode + setter beneath route editing, with the local and multiplayer insertion paths choosing mode + `0x13` only when that stricter second validation succeeds and mode `0x0a` on the looser fallback + path. The first + deeper world-mode interaction branch is now better + bounded: `GameUppermost.win` hotspots, cursor drag, held Shift state, discrete shell view-step + commands, direct keyboard turn/pan/zoom bindings, the `TrackLay.win` and `StationPlace.win` + world-command surfaces, and a frame-owned hover or focus-target transition branch all feed the + same shell-controller-backed path. The remaining uncertainty has moved farther from basic + ownership: the hover-target branch clearly exists, and `0x07d6` now looks like the shared + main-world interaction surface rather than a generic detail button for one tool family only. One + more shell-side consumer is bounded now too: `0x004bc350` is a world-surface brush handler over + that same `0x07d6` control plus the adjacent mode family `0x0faa..0x0faf` and ordinal strip + `0x0fa0..0x0fa7`. That family is no longer just a generic unlabeled brush owner: the + detail-panel manager now grounds the sibling tool-window strip immediately above it as + `Bulldoze.win`, `ChangeHeight.win`, `ChangeTrees.win`, `PaintTerrain.win`, `PaintRegion.win`, + `PaintSound.win`, and `PaintTerritory.win`, each with its own constructor, refresh pass, and + message owner beneath the same controller rooted at `0x006d0818`. Once its local drag latch is + active it dispatches the current mode dword at `[0x006d0818+0x8c]` into the companion-float + helpers `0x0044d4e0`, `0x0044d880`, and `0x0044da70`, or into the secondary-raster nibble path + `0x00448e20 -> 0x00419110`, so the remaining uncertainty has narrowed from ownership to the + exact one-to-one mode-button mapping inside that grounded tool-window strip. The + `PaintTerrain.win` side is tighter now too: constructor `0x004f7ce0` seeds shell singleton + `0x006d1304`, callback root `0x006d1334`, a constructor-time bulk-update latch at + `0x006d1330/0x006d1331`, and the broader terrain mode or scalar state from `0x00622748..0x00622788` + plus `0x006d1308..0x006d1324`; it then registers the callback strip `0x004f5960`, + `0x004f59f0`, `0x004f6070`, and `0x004f69e0` through `0x00540120`. The direct message owner + under that same family is no longer just a loose branch fan-out either: `0x004f6f50` owns + messages `2/0xca/0xcb`, keeps control `0x07d6` as the live world-surface drag latch, routes + explicit undo control `0x2775` into `0x004f5c30`, maps the selector and mode strips + `0x2711..0x2730`, `0x27d9..0x27df`, `0x283d..0x2843`, `0x28a1..0x28e6`, `0x2915..0x291e`, + `0x2964..0x2967`, and `0x29cd..` into the cached terrain lanes, and then fans the active drag + path into preview helpers `0x004f6930`, `0x004fb5e0`, `0x004fc280`, `0x004fc4d0`, and + `0x004fc630` depending on the current terrain mode. Inside that same family + `0x004f5a80/0x004f5c30` are now the bounded local undo snapshot pair, `0x004f5dd0` is the + tiny active-scalar-group selector, `0x004f6b50` owns the ten-entry mode strip rooted at + `0x28dd`, `0x004f6390` is the broad mode-panel repaint owner, `0x004f6250` is the + mode-dependent world-dispatch bridge, `0x004f6930` samples the current preview raster at + world coordinates, and `0x004fb5e0` is the heavier preview-raster rebuild and shell-surface + publish worker. The next local helpers under that same family are tighter now too: + `0x004f5ea0` and `0x004f5ec0` are just the two tiny special-mode predicates + `(mode 5, variant 2)` and `(mode 4, variant 2)`, `0x004f8770` is the weighted RGB sampler + over the current preview or undo-backed raster neighborhood, `0x004f89b0` is the local + byte-grid connected-component grower over the eight-neighbor tables `0x00624b28/0x00624b48`, + and `0x004f8bb0` is the main drag-path preview compositor that consumes the drag sample strip + `[this+0xf0/+0xf4/+0xf8]`, allocates temporary float or byte grids, and then rasterizes the + surviving preview rectangle through the current terrain descriptor tables at `0x005f3500`, + the weighted color sampler `0x004f8770`, the component grower `0x004f89b0`, and several live + world samplers before writing final RGBA pixels back into the preview surface. The late tail + under that same compositor is tighter too: the mode-`4`, variant-`2` path toggles + secondary-raster byte-2 bit `0x20` by comparing current and previous cells through + `0x00534f40`; the broader mode-`4/5` world-facing branch samples class set `2/4/5` through + `0x00534ec0`, re-enters `0x0044de30` and `0x0044df10`, latches pending world coordinates into + `[0x006d1304+0x78/+0x7c]`, and rewrites the low nibble plus the signed overlay-vector planes + through `0x00448df0`, `0x00448e20`, `0x00448ec0`, `0x00448ee0`, `0x00448e60`, and + `0x00448e90`. After the optional mode-`5` smoothing sweep through `0x004f8370`, the publish + tail either materializes one shell preview surface through `0x0051f090 -> 0x00534730` or, for + the mode-`4/5` world-facing variants, converts the surviving preview rectangle back into + world-space bounds and re-enters `0x0044e940`, `0x00452f20`, and `0x0044d410`. The companion + preview-rebuild owner `0x004fb5e0` is tighter on entry, too: `0x004f726c` is the early + rebuild path that first copies the live preview raster into `[this+0x118]` and snapshots undo + state through `0x004f5a80`, while `0x004f7ada` is the later drag-active path that first + allocates a temporary occupancy mask before rebuilding and then conditionally mirrors that + mask through `0x00450520` on the world-mode-`0x17` side path. So the remaining uncertainty + has narrowed again from family ownership to the exact meaning of a few per-mode scalar and + token lanes, not to whether `PaintTerrain.win` itself is still a mixed shell/world owner. + +### Post-load Generation, PaintTerrain, and Save/Load Restore + +The same brush strip is tighter now too: + `0x004bc210` stores the selected ordinal and refreshes one scalar caption + from table `0x00621e24`, `0x004bc260` exposes the cached world coordinate pair plus the + currently selected scalar, and `0x004bc290` restyles the ordinal strip `0x0fa1..0x0fa7` plus + the mapped mode strip `0x0faa..0x0faf` against the current mode dword `[0x006d0818+0x8c]`. The + next unresolved layer is narrower and more semantic: the setup side now has one grounded + owner, `world_run_post_load_generation_pipeline`, and its building-side branch is no longer just + one opaque block. We now have a region family, a region-border overlay rebuild, a region-owned + structure-demand and placement dispatcher, and a deeper per-region worker that computes category + demand, subtracts existing coverage, and tries candidate placements. The category map is tighter + too: category `0` falls back to `House`, category `2` is the year-gated weighted region-profile + family that also feeds the localized `Industry Weightings` stats panel, and category `3` now + reaches a separate pool-driven picker whose fallback label is `Commercial` but whose aligned + player-facing stats bucket is `City Support`. The normalized region band is tighter too: + `world_region_normalize_cached_structure_balance_scalars` `0x00422320` no longer just writes an + anonymous cached preview band at `[region+0x2e2/+0x2e6/+0x2ea/+0x2ee]`. Current growth-report + evidence now grounds `[region+0x2e2]` as the weighted-profit-margin scalar and `[region+0x2ee]` + as the annual-density-adjust scalar later formatted as a percent in `Stats - City/Region`, with + `[region+0x2e6/+0x2ea]` left as the intermediate normalized-delta and clamped companion slots + beneath that final adjust term. The per-region prepass feeding that normalization is tighter too: + `0x00420d40` clears `[region+0x306/+0x30a/+0x30e]`, walks the linked placed-structure chain from + `[region+0x383]`, accumulates two local placed-structure metrics through `0x0040ca70` and + `0x0040ca80`, and only for class-0 candidates also folds source field `[source+0x141]` through + `0x0040cec0` into the third accumulator before tailing into the later scalar refresh. That tail + helper `0x00420560` is tighter now too: on class-0 regions it revisits the same linked chain and + folds a class-mix contribution into `[region+0x312]`, with one source-derived term for candidate + class `0`, a separate branch keyed by `[candidate+0x78c]` and `[site+0x246]` for class `2`, one + fixed increment for class `3`, and no current contribution from class `1`. One neighboring + collection-side dispatcher is tighter now too: `0x00433b80` only runs when global mutation depth + `0x0062be40` is back at zero and then conditionally fans into the optional refresh hooks + `0x00481430`, `0x00413860`, `0x004b2a90`, and `0x004931e0`. The periodic boundary + side is narrower now too. `0x00422100`, reached only from + `simulation_service_periodic_boundary_work` `0x0040a590`, first requires several live world + state gates to stay clear, derives one year-sensitive random threshold from selected-year fields + plus world width, then scans the region collection for eligible class-0 regions whose transient + dwords `[region+0x276]` and `[region+0x302]` are both clear and which fail the city-connection + peer probe `0x00420030(1,1,0,0)`. When the gate passes it picks one random eligible region, + derives one small severity bucket from `[region+0x25e]`, stores the scaled amount back into + `[region+0x276]`, and appends one queued `0x20`-byte record through `0x004337c0` with literal + kind `7`, the chosen region id, that amount, the fixed payload `0x005c87a8`, and sentinel dwords + `-1/-1`. That append helper is now grounded directly too: `0x004337c0` allocates one zeroed + linked `0x20`-byte node, copies one string or payload seed into `[node+0x04..]`, stores the six + trailing caller dwords at `[node+0x08..+0x1c]`, and appends the finished node to the singly + linked list rooted at `[state+0x66a6]`. The gameplay label for that queued-record family is still + open, but the structural link from periodic region selection into the scenario-state queue is now + direct instead of speculative. One neighboring narrow counter is bounded too: `0x00422850` + counts class-0 regions that pass a second `0x00420030` peer-probe variant with fixed flags + `(1,1,1)` plus one caller-supplied trailing dword, and current callers are the query/script + dispatch at `0x0042f856` and the later region-stats formatter at + `0x004d2088`. The + remaining setup-side uncertainty has therefore narrowed + again: the region seed and border-overlay pair clearly complete before the `Setting up Players and + Companies...` banner is posted; `[0x006cec74+0x174]` now looks like the direct building-population + gate; `[0x006cec74+0x178]` now looks like the direct seeding-burst gate and selected-year-adjust + policy; and `[0x006cec74+0x68]` now aligns with editor-map mode because the same flag forces the + `.gmp` family in the shell file coordinators while suppressing the later building and seeding + branches and diverting the deeper region worker into alternate logic. One write side for that + `[shell+0x178]` policy is now grounded too: inside `shell_dispatch_ui_command` `0x00464410`, + command ids `0x9d26..0x9d28` store `command_id - 0x9d26` directly into `[0x006cec74+0x178]`, + yielding live values `0`, `1`, and `2`. That means the later restore branch is no longer gated + by an abstract hidden shell latch; at least one of its adjustment inputs is an explicit UI + launch policy and current evidence still does not show that value being recovered from saved + state. The `319` lane itself is no longer the + open structural gap; it now clearly owns chairman-profile slot seeding, profile-record + materialization, a shell editor surface over the same local record family, and a separate + live-company presentation path through the company-list window. The later interior order of that + same `319` lane is tighter now too: after the route-entry collection refresh on `0x006cfca8` it + refreshes the auxiliary route-entry tracker collection `0x006cfcb4`, then runs + `placed_structure_collection_refresh_local_runtime_records_and_position_scalars` `0x004133b0`, + then a flagged world-grid cleanup sweep through the compact grid-flag query + `0x00448af0` plus the neighboring local chunk-cell write helper `0x00533fe0`, and only after + that the later route-entry post-pass at `0x00491c20`. The same `319` lane is tighter internally + now too: + before that later world and shell reactivation tail, `world_entry_transition_and_runtime_bringup` + runs one distinct post-bundle status and runtime refresh phase that posts progress ids `0x196` + and `0x197` through `0x005193f0/0x00540120` with paired `0x004834e0` follow-ons, refreshes the + live event collection at `0x0062be18` through + `scenario_event_collection_refresh_runtime_records_from_packed_state` `0x00433130`, rebuilds the + scenario-side port-or-warehouse cargo recipe runtime tables through `0x00435630`, and then runs + the named-candidate availability preseed through `0x00437743`. One later subphase is tighter now + too: before the broad world-reactivation sweep it posts progress ids `0x32dc/0x3714/0x3715`, + reloads one `0x108`-byte packed profile block through `0x00531150`, conditionally copies staged + runtime-profile bytes back into `0x006cec7c` while latch `[profile+0x97]` is set, mirrors the + grounded campaign-scenario bit `[profile+0xc5]` and sandbox bit `[profile+0x82]` into world + bytes `[world+0x66de]` and `[world+0x66f2]`, and restores the selected year/profile lane through + a tighter two-stage calendar path than before. Current local disassembly now shows the raw saved + lane at `[profile+0x77]` first feeding helper `0x0051d3f0` with constant components + `(month=1, day=1, subphase=0, tick=0)`, which writes the resulting Jan-1-style tuple dwords + into `[world+0x05/+0x09]`. Only after that seed does the same lane enter one mode-sensitive + adjustment branch: non-editor startup mode can decrement the lane by `1` or `3` depending on + shell-state editor gate `[0x006cec74+0x68]`, shell-side selected-year-adjust policy + `[0x006cec74+0x178]`, and the saved special-condition slot `[0x006cec78+0x4af7]`, and only that + adjusted lane then feeds + helper `0x0051d390` before `world_set_selected_year_and_refresh_calendar_presentation_state` + `0x00409e80` stores the final absolute counter into `[world+0x15]` and refreshes + `[world+0x0d/+0x11]`. That means the restore no longer reads as a direct + `[profile+0x77] -> [world+0x15]` copy; the raw lane seeds the tuple immediately, but the final + absolute-counter restore still depends on live shell/startup context. That dependency is tighter + now too: current local evidence shows `[shell+0x178] == 1` decrementing the restored lane by + `1`, `[shell+0x178] == 2` subtracting `3`, and otherwise a nonzero + `[0x006cec78+0x4af7]` supplying the fallback `-1` branch. That field is no longer unresolved: + current local disassembly now shows `0x00436d10` bulk-zeroing the dword table rooted at + `[startup+0x4a7f]` through `rep stos`, which includes `+0x4af7`, while the editor-side special + conditions owner at `0x004cb2b0/0x004cb8e0` counts and commits that same 49-entry table from the + static rule descriptors at `0x005f3ab0`. The `.smp` save or restore family now grounds that live + band directly too: `world_runtime_serialize_smp_bundle` `0x00446240` writes `49` dwords from + `[world+0x4a7f..+0x4b3f]` plus one trailing scalar at `[world+0x4b43]`, and + `world_load_saved_runtime_state_bundle` `0x00446d40` restores the same fixed `0xc8`-byte band + symmetrically. Slot `30` in that table is localized pair `3722/3723` + `Disable Cargo Economy`, so `+0x4af7` now reads as the live copy of that saved scenario rule, + not a startup-runtime-only mystery latch. The neighboring fixed reads line up with the same rule + cluster too: `+0x4aef` is slot `28` `Completely Disable Money-Related Things`, `+0x4af3` is slot + `29` `Use Bio-Accelerator Cars`, `+0x4afb` is slot `31` `Use Wartime Cargos`, `+0x4aff` is slot + `32` `Disable Train Crashes`, `+0x4b03` is slot `33` `Disable Train Crashes AND Breakdowns`, and + `+0x4b07` is slot `34` `AI Ignore Territories At Startup`. So the remaining loader gap is + narrower than before: the restore still depends on live shell policy `[shell+0x178]`, but the + `+0x4af7` input itself is save-derived scenario rule data rather than something that requires + runtime tracing to discover. Its read-side family is no longer isolated to the selected-year + restore either: it also shapes the chunk size in + `simulation_run_chunked_fast_forward_burst` `0x00437b20` and appears in candidate/local-service + selection and station-detail-side scoring branches around `0x0047f910`, `0x00410d87`, and + `0x005069c6`, which now makes this whole slot cluster look like broader runtime consumers of + scenario special conditions rather than one startup-only mode enum. One file-side anchor is now + tighter too: the checked classic and 1.05 `gmp/gms/gmx` corpus does expose the same aligned + `0x0d64..0x0e2c` `50`-dword band as the grounded `.smp` runtime save or restore copy into + `[world+0x4a7f..+0x4b43]`, but most checked file families only populate a sparse subset of that + band. The first `36` dwords still behave like the older inferred fixed rule matrix with hidden + slot `35` fixed to sentinel value `1`, while the trailing `13` unlabeled rule lanes plus one + scalar vary much more selectively by file family. Current local corpus scans make that split + concrete: the grounded 1.05 scenario-save family (`p.gms`, `q.gms`) stably lights lanes + `35, 37, 39, 44, 45, 46, 47, 48`; the base 1.05 save family (`Autosave.gms`, `nom.gms`) only + shares lane `35` stably and otherwise varies sparsely through `42`, `45`, and `47`; the checked + grounded 1.05 maps, the lone 1.05 alt save, and the visible sandbox-family `.gmx` files keep + only the sentinel lane `35` nonzero. So the current loader boundary is narrower than before: the + `.smp` path still gives a grounded direct runtime-band restore, and checked `gmp/gms/gmx` files + now show a partially populated projection of that same aligned band rather than a wholly separate + fixed record family. The overlap against the later scalar window is now explicit too: trailing + band indices `36..49` are byte-identical with post-window offsets `0x00..0x34`, so every nonzero + lane in that prefix of the post-sentinel scalar window is also a nonzero lane in the aligned + runtime-rule band. That means the real “other fields” boundary inside the post-sentinel window + starts only at `0x0e2c`: `0x0df4..0x0e2c` is the aligned-band overlap prefix, while + `0x0e2c..0x0f30` is the later tail that still looks like save-side scalar state. Local corpus + scans now make that tail split more specific. The base 1.05 save family + (`Autosave.gms`, `nom.gms`) shares a stable tail subset at relative offsets + `0xb4`, `0xc0`, `0xe0`, `0xfc`, and `0x100`, with additional per-file lanes around them. The + 1.05 scenario-save family (`p.gms`, `q.gms`) has a much denser stable tail covering + `0x08`, `0x0c`, `0x10`, `0x14`, `0x20`, `0x24`, `0x28`, `0x30`, `0x34`, `0x3c`, `0x5c`, + `0x6c`, `0xa0`, `0xa8`, `0xbc`, `0xc0`, `0xc4`, `0xc8`, `0xcc`, `0xdc`, `0xe0`, `0xe4`, + `0xe8`, `0xf4`, `0xf8`, and `0xfc`; those values still differ per save, but the occupancy is + stable. The lone 1.05 alt save (`g.gms`) only lights `0x20`, `0x34`, `0xf0`, and `0xf4`. + Grounded map families and classic saves keep the tail zeroed, while the only current map-side + outlier remains `Tutorial_2.gmp` under the broad unknown map-family bucket. The immediately + following fixed file window at `0x0df4..0x0f30` is now bounded separately as well: checked maps + and classic saves leave that whole post-sentinel band zeroed, + while checked 1.05 saves carry sparse nonzero dwords there, many of which decode cleanly as + normal little-endian `f32` values. That makes the adjacent band look like a 1.05 save-only + runtime band rather than scenario-static payload, even though its semantics are still open. + One numeric alignment inside that band is now exact too: the tail start `0x0e2c` is the same + relative distance from the aligned runtime-rule base `0x0d64` as live object offset `+0x4b47` + is from grounded world-rule base `[world+0x4a7f]`, so the bounded tail window + `0x0e2c..0x0f30` is offset-aligned with live bytes `[world+0x4b47..+0x4c4b]`. The first + grounded live field at that boundary is no longer anonymous. `0x004367c0` sets one outcome mode + in `[world+0x4a73]`, zeros `[world+0x4d]`, snapshots the selected-year lane to `[world+0x4c88]`, + and then copies localized id `2923` `You lose.` or `2924` `You win, cheater...` into + `[world+0x4b47]`; `0x00472dd0` formats localized id `3918` `%1 has won the game!` with one live + profile name and writes that string into the same destination; and one compact runtime-effect + branch inside `world_apply_compact_runtime_effect_record_to_resolved_targets` `0x00431b20` resets + the same destination to the fixed placeholder token at `0x005c87a8`. That gives a grounded live + interpretation for the start of the tail: `[world+0x4b47]` is the start of a victory or outcome + status-text buffer, not a float lane. The same evidence also gives a useful caution: those live + helpers copy up to `0x12c` bytes into `[world+0x4b47..+0x4c73]`, so the current bounded file-tail + window `0x0e2c..0x0f30` cuts through the first `0x104` bytes of a grounded text field rather + than ending on a clean live-field boundary. One small continuation probe now tightens that edge: + the remaining file window `0x0f30..0x0f58` is exactly the last `0x28` bytes needed to reach the + clean live-field boundary at `[world+0x4c73]`, and checked 1.05 saves still carry sparse nonzero + bytes in that continuation window rather than a trailing text-looking suffix. Checked 1.05 save + bytes in the aligned region therefore still do not resemble preserved text; they stay mostly zero + at the beginning and many nonzero lanes decode as ordinary `f32` values. So the safest current + note is: the tail is offset-aligned with the live object beyond `+0x4b43`, but it is not yet a + validated byte-for-byte mirror of the live `[world+0x4b47]` status-text buffer, and the current + nonzero save-side content continues right up to the first clean field edge at `0x0f58`. The next + exact grounded fields after that edge are byte lanes, not restored dwords: `0x0f59` maps to + `[world+0x4c74]` `Auto-Show Grade During Track Lay`, `0x0f5d` maps to `[world+0x4c78]` + `Starting Building Density Level`, `0x0f61` maps to `[world+0x4c7c]` `Building Density Growth`, + `0x0f65` maps to grounded dword `[world+0x4c80]` `leftover simulation time accumulator`, and + `0x0f6d` maps to byte `[world+0x4c88]` `selected-year lane snapshot`. The first later grounded + dword after that is `[world+0x4c8c]` at `0x0f71`. That means the simple 4-byte file-lane model + stops matching grounded live field boundaries immediately after the text-buffer edge: the post- + `0x0f58` file bytes are still offset-correlated to live state, but they are no longer naturally + dword-aligned with the next grounded object fields. The new byte-neighborhood probe makes the + mismatch more concrete. In checked 1.05 scenario saves, the exact grounded byte offsets + themselves do not look like clean selector values: `p.gms` carries `0x33` at `0x0f5d` and `0x8c` + at `0x0f6d`, while `q.gms` carries `0xcc` and `0xba` at those same offsets. The only clean + float-looking starts in that neighborhood instead appear one byte earlier, at `0x0f5c` and + `0x0f6c`: `p.gms` decodes those as roughly `7.6` and `6.0172`, while `q.gms` decodes them as + roughly `23.6` and `44.6824`. That tightens the current read further: the checked save bytes + remain offset-correlated to the live `[world+0x4c74..+0x4c8c]` neighborhood, but they are still + not a validated byte-for-byte mirror of the exact live field layout. Local + A second byte-oriented neighborhood immediately after that now has the same kind of split rather + than a clean restored-field mirror. The earlier grounded anchors in that band all stay zero in + the checked 1.05 saves: exact file offset `0x0f87` maps to selected-year bucket companion scalar + `[world+0x4ca2]`, while `0x0f93` and `0x0f97` map to the two startup-dispatch reset-owned bands + `[world+0x4cae]` and `[world+0x4cb2]`, and the local corpus leaves all three exact dword starts + zeroed. The same is true for the later exact byte-owned policy lanes: file offsets `0x0f78`, + `0x0f7c`, `0x0f7d`, and `0x0f7e` map cleanly to grounded byte fields `[world+0x4c93]` and + `[world+0x4c97..+0x4c99]`: the linked-site removal follow-on gate plus the three editor + locomotives-page policy bytes `All Steam Locos Avail.`, `All Diesel Locos Avail.`, and `All + Electric Locos Avail.`. In the checked 1.05 save corpus those four exact byte lanes all stay + `0`, which is at least structurally clean. The later grounded dword fields in the same + neighborhood are less direct again. Exact file offset `0x0f9f` maps to `[world+0x4cba]` (the + station-list selected-station mirror) and exact offset `0x0fa3` maps to cached + available-locomotive rating `[world+0x4cbe]`, but the checked save bytes at those exact dword + starts do not look like clean preserved ids or floats. The only stable float-looking starts sit + three bytes earlier, at `0x0f9c` and `0x0fa0`: `p.gms` yields roughly `96.8754` and `186.4795`, + `q.gms` yields `329.9467` and the same `0x0fa0`-side candidate shape, `g.gms` yields `7.0` and + `95.8507`, and `Autosave.gms` only shows the later `0x0fa0` candidate at about `68.2629`. So + this later band now has the same conservative read as the post-text one: the save bytes are + still offset-correlated to grounded live fields, but the exact live byte or dword layout is not + yet validated as a direct on-disk mirror. + One more structural cut is now grounded beyond that neighborhood. The aligned scalar plateau + `0x0fa7..0x0fe7` ends exactly at the later recipe-book root `[world+0x0fe7]` already grounded in + the port-or-warehouse cargo editor and runtime rebuild path. We still do not have live semantic + names for the plateau itself, but its aligned dword run now splits cleanly by save family. The + base 1.05 saves (`Autosave.gms`, `nom.gms`) carry one stable signature with + `0x0faf = 0x8000003f`, `0x0fb3 = 0x75c28f3f`, repeated `0x75c28f3c` lanes through `0x0fbf`, a + sign-flipped lane `0x0fc3 = 0xa3d70a3c`, one tiny marker at `0x0fc7 = 0x0000003b`, and + `0x0fcb = 0x00300000`. The scenario-save family (`p.gms`, `q.gms`) carries a different stable + plateau over the same offsets, beginning `0x0faf = 0x4000003f`, `0x0fb3 = 0xe560423f`, then + `0x03126f3b`, `0x1374bc3c`, and paired `0x23d70a3c` lanes at `0x0fbf/0x0fc3`, with + `0x0fc7 = 0x0000003c`. The alt-save family (`g.gms`) follows the base signature through + `0x0fc7`, then diverges sharply into the same `0xcdcdcd..` fill pattern already seen in its + earlier header lanes. So the current best fit for `0x0fa7..0x0fe7` is a family-shaped aligned + scalar plateau that belongs to save-side runtime state and terminates immediately before the + grounded recipe-book block, not one more directly named live-field mirror. One conservative + loader-side summary probe now starts exactly at that recipe root instead of extending the plateau + model further. The fixed recipe-book block spans twelve books from `0x0fe7` with stride `0x4e1`, + and the checked map/save pairs `Alternate USA.gmp -> Autosave.gms`, `Southern Pacific.gmp -> + p.gms`, and `Spanish Mainline.gmp -> g.gms` preserve that rooted block byte-for-byte in the + sampled local corpus. The current probe therefore treats it as preserved scenario payload rather + than save-only runtime drift and only reports per-book signatures: a coarse head kind over the + pre-line region, the raw `book+0x3ed` annual-production dword, and one raw summary for each of + the five fixed `0x30`-byte cargo lines beginning at `book+0x3f1`: coarse line kind, raw mode + dword, raw annual-amount dword, and the raw supplied/demanded cargo-token dwords at `+0x08` and + `+0x1c`. That is enough to separate zero, `0xcd`-filled, and mixed books or lines without + overstating line semantics beyond the grounded editor/runtime ownership already documented below. + Local + corpus clustering now makes the remaining split more specific. The base 1.05 save family + (`Autosave.gms`, `nom.gms`) shares a narrow tail-heavy subset with stable relative offsets + `0xec`, `0xf8`, `0x118`, `0x134`, and `0x138`, while still varying in value across files. The + 1.05 scenario-save family (`p.gms`, `q.gms`) shares a much broader stable set spanning almost the + whole window from `0x04` through `0x134`, again with per-file scalar differences but consistent + occupancy. Pairwise compare runs tighten that read further: `Autosave.gms` vs `nom.gms` does not + preserve one common numeric tail signature even at the shared base-save offsets, and `p.gms` vs + `q.gms` keeps the broad scenario-save occupancy pattern but still changes every shared value, with + `q.gms` additionally lighting two extra lanes at `0x78` and `0x84`. So the current best fit is + “family-shaped live scalar state” rather than family-default constants. The lone 1.05 alt-save + sample (`g.gms`) only lights up four lanes at `0x58`, `0x6c`, + `0x128`, and `0x12c`. The checked 1.05 maps and classic saves stay zero in that same bounded + window, which strengthens the current read that this is runtime-save scalar state rather than + generic map payload. One older unknown map-family outlier in the local corpus does still carry a + populated window: `Tutorial_2.gmp` under the classic install tree. So the safest current note is + “zero for grounded map families and classic save families, nonzero for observed 1.05 save + families, with one older unknown-map exception.” Static consumer grounding is still sparse for + that tail: direct object-offset hits currently only name the trailing scalar `[world+0x4b43]` + through the editor panel and `.smp` save or restore family, while local opcode searches do not + yet surface equally direct reads for the intervening `+0x4b0b..+0x4b3f` tail lanes. So the + save-file family clustering is now strong, but those later tail scalars remain structurally + bounded rather than semantically named. The + same branch is no longer world-entry-only either: current local + disassembly now shows the identical lane-adjust and + `0x51d3f0 -> 0x51d390 -> 0x409e80` sequence in the post-fast-forward selected-year tail at + `0x004370e0`, which lines up with the existing post-fast-forward callers already mapped under + `0x00433bd0`, `0x00435603`, `0x0041e970`, and `0x00436af0`. That restore now + also has some neighboring slot semantics bounded well enough to carry in the loader notes. Slot + `31` `[0x006cec78+0x4afb]` is no longer best read as an unnamed runtime cargo-economy latch: + local disassembly now ties it directly to the saved special-condition table entry `Use Wartime + Cargos`, and the strongest current runtime owner is + `structure_candidate_collection_refresh_cargo_economy_filter_flags` `0x0041eac0`. Inside that + candidate-collection sweep the branch at `0x0041ed37` only activates when slot `31` is set and + then treats the string family `Clothing`, `Cheese`, `Meat`, `Ammunition`, `Weapons`, and + `Diesel` as one special cargo set before writing the live candidate filter byte `[entry+0x56]`. + That makes the old read-side note around `0x00412560` tighter too: the neighboring descriptor + gate is now best understood as using the live copy of the `Use Wartime Cargos` scenario rule, + not an anonymous cargo-economy mode byte. Slot `34` `[0x006cec78+0x4b07]` is similarly bounded + on the runtime side: the wrapper at `0x004013f0`, which sits immediately above the broader + company-start or city-connection chooser `0x00404ce0`, snapshots region dword `[entry+0x2d]` + across all `0x18` live region records in `0x006cfc9c`, zeros that field while the chooser runs, + and then restores the original values on exit. That is a strong current fit for the editor rule + `AI Ignore Territories At Startup`, even though the exact meaning of region field `+0x2d` + remains open. Slot `29` `[0x006cec78+0x4af3]` is less semantically tidy but still worth carrying + as a bounded consumer family: the branch at `0x0041d286` activates one later placed-structure or + building-side scoring path only when that slot is nonzero and the linked candidate or era record + at `[entry+0x41]` equals `5`, while two already-grounded world helpers + `world_scan_secondary_grid_marked_cell_bounds` `0x0044ce60` and + `world_service_secondary_grid_marked_cell_overlay_cache` `0x0044c670` also gate on the same + slot. So the identity of slot `29` as saved rule data is grounded, but the downstream runtime + semantics are still mixed enough that the loader should preserve the raw value without trying to + rename its whole consumer family yet. The neighboring train-safety slots are now bounded enough + to keep as a cautious runtime split too. Slot `33` `[0x006cec78+0x4b03]` + `Disable Train Crashes AND Breakdowns` is the coarse gate in the currently recovered train-side + deterioration family around `0x004af8a0`: the very first branch at `0x004af8ab` jumps straight + to the function tail when the slot is set, bypassing the year-scaled threshold build, the later + random or threshold comparison, and the two follow-on state transitions at `0x004ad7a0` and + `0x004ada00`. Slot `32` `[0x006cec78+0x4aff]` `Disable Train Crashes` is narrower in the same + family: after the threshold path has already run, the branch at `0x004af9c1` uses slot `32` to + suppress only the lower failure-transition path and force the milder follow-on at `0x004ada00`. + That same slot-`33` read also appears in the smaller train-side scalar query at `0x004ac460`, + where setting it returns one fixed float immediately before the ordinary route-object-dependent + calculation runs. So the current best loader-facing read is: slot `33` is the broad train + deterioration bypass, slot `32` is the narrower crash-only branch inside that same family, but + the exact player-facing names of the two unnamed train helpers still need one more naming pass. + That restore now + also has one concrete file-side correlation in the classic `.gms` family: local save inspection + now consistently finds `0x32dc` at `0x76e8`, `0x3714` at `0x76ec`, and `0x3715` at `0x77f8` in + `Autosave.gms`, `kk.gms`, and `hh.gms`, leaving one exact `0x108`-byte span from `0x76f0` to + `0x77f8` between `0x3714` and `0x3715`. That span already carries staged-profile-looking payload + text such as `British Isles.gmp`, so the current static-file evidence now supports the atlas-side + `0x108` packed-profile note for the classic save family even though the exact field layout inside + that block is still unresolved. The same classic corpus is tighter now too: inside that + `0x108` span the map-path C string begins at relative offset `0x13`, the display-name C string + begins at `0x46`, the block is otherwise almost entirely zeroed, and the three local samples are + byte-identical except for the leading dword at `+0x00` (`3` in `Autosave.gms` and `hh.gms`, + `5` in `kk.gms`). The currently atlas-tracked bytes `[profile+0x77]`, `[profile+0x82]`, + `[profile+0x97]`, and `[profile+0xc5]` are all `0` in that classic sample set, so the current + file-side evidence grounds the block boundaries and the embedded strings but does not yet show + live examples of those branch-driving latches being set. One 1.05-era file-side analogue is now + visible too, but only as an inference from repeated save structure rather than a disassembly-side + field map: local `.gms` files in `rt3_105/Saved Games` carry one compact string-bearing block at + `0x73c0` with the same broad shape as the classic profile slab, including a leading dword at + `+0x00`, one map-path string at `+0x10`, one display-name string at `+0x43`, and a small + nonzero tail around `+0x76..+0x88`. In that 1.05 corpus the analogue bytes at relative `+0x77` + and `+0x82` are now nonzero in every checked sample (`Autosave.gms`/`nom.gms` show `0x07` and + `0x4d`; `p.gms`/`q.gms` show `0x07` and `0x90`; `g.gms` shows `0x07` and `0xa3`), while + relative `+0x97` and `+0xc5` remain `0`. The compared 1.05 save set is tighter now too: + `Autosave.gms` and `nom.gms` cluster together on `Alternate USA.gmp` with `+0x82 = 0x4d`, + `g.gms` carries `Spanish Mainline.gmp` with `+0x82 = 0xa3`, and `p.gms`/`q.gms` cluster on + `Southern Pacific.gmp` with `+0x82 = 0x90`; across all five files the same inferred analogue + lane at `+0x77` stays fixed at `0x07`, while the same map- or scenario-sensitive tail word at + `+0x80` tracks those `0x4d/0xa3/0x90` byte lanes (`0x364d0000`, `0x29a30000`, `0x1b900000`). + The leading dword at `+0x00` also splits the same corpus, with `Autosave.gms` alone at `3` and + the other four checked 1.05 saves at `5`. That is enough to say the wider save corpus does + contain nonzero candidates for two of the atlas-tracked profile lanes, and that one of them + varies coherently with the loaded scenario family, but not yet enough to claim that the 1.05 + block reuses the exact same semantic field assignments as the classic one. The loader-side + family split is tighter now too: `p.gms` and `q.gms` no longer live under a generic fallback; + their save headers now classify as one explicit `rt3-105-scenario-save` branch with preamble + words `0x00040001/0x00018000/0x00000746` and the early secondary window + `0x00130000/0x86a00100/0x21000001/0xa0000100`, while `g.gms` now classifies as a second + explicit `rt3-105-alt-save` branch with the different preamble lane + `0x0001c001/.../0x00000754` and early window + `0x00010000/0x49f00100/0x00000002/0xa0000000`. That branch now carries the same bootstrap, + anchor-cycle, named 1.05 trailer, and narrow profile-block extraction path as the other 1.05 + saves. The bridge just below that trailer is now explicit too: the common 1.05 save branch + carries selector/descriptor `0x7110 -> 0x7801` in `Autosave.gms` and `0x7110 -> 0x7401` in + `nom.gms`, and both still reach the same first later candidate at + `span_target + 0x189c`, well before the packed profile at `span_target + 0x3d48`; the + `rt3-105-alt-save` branch instead carries `0x54cd -> 0x5901` and its first later candidate + lands at `packed_profile + 0x104`, essentially on the profile tail; the scenario-save branch + still diverges locally with `0x0001 -> 0x0186` and never enters that later `0x32c8`-spanned + bridge at all. The common-branch bridge payload is narrower now too: both checked base saves + expose the same 0x20-byte primary block at `0x4f14` followed by the same denser secondary block + at `0x671c`, `0x1808` bytes later, and that secondary block now appears to run intact up to the + packed-profile start at `0x73c0` for a total observed span of `0xca4` bytes. The trailing slice + of that secondary block is now typed one level further: a small header at `secondary+0x354` + carries the observed stride `0x22`, capacity `0x44`, and count `0x43`, followed by a fixed-width + 67-entry name table starting at `secondary+0x3b5` and running through names like + `AluminumMill`, `AutoPlant`, `Bakery`, `Port00..11`, and `Warehouse00..11`, with a short footer + (`dc3200001437000000`) after the last entry. The trailing per-entry word is now surfaced too: + most entries carry `0x00000001`, while the currently observed zero-trailer subset is + `Nuclear Power Plant`, `Recycling Plant`, and `Uranium Mine`. That footer is tighter now too: + it parses directly as `0x32dc`, `0x3714`, and one trailing zero byte, so the shared + map/save catalog currently ends on the same two grounded late-rehydrate progress ids that the + classic staged-profile band already exposed. The strongest structural read is therefore that the + entire `0x6a70..0x73c0` catalog region is shared verbatim between `Alternate USA.gmp` and the + derived `Autosave.gms`, not rebuilt independently during save. Combined with the earlier + grounded record-layout work under `0x00437743`, `0x00434ea0`, and `0x00434f20`, the current + safest semantic read is that this shared catalog is the bundled source form of the scenario-side + named candidate-availability table later mirrored into `[state+0x66b2]`, with each entry's + trailing dword now reading as the same availability override bit later copied into + `[candidate+0x7ac]`. The loader-side coverage is tighter now too: the same table parser now + attaches both to the common-save bridge payload and directly to the fixed source range in + `.gmp` files and the non-common `rt3-105-scenario-save` / `rt3-105-alt-save` branches. That + makes the scenario variation explicit instead of anecdotal. `Alternate USA` keeps only three + zero-availability names in this table (`Nuclear Power Plant`, `Recycling Plant`, `Uranium + Mine`), `Southern Pacific` widens the zero set to twelve (`AutoPlant`, `Chemical Plant`, + `Electric Plant`, `Farm Rubber`, `FarmRice`, `FarmSugar`, `Nuclear Power Plant`, `Plastics + Factory`, `Recycling Plant`, `Tire Factory`, `Toy Factory`, `Uranium Mine`), and `Spanish + Mainline` widens it again to forty-two, including `Bauxite Mine`, `Logging Camp`, `Oil Well`, + `Port00`, and the `Warehouse00..11` run while also flipping `Recycling Plant` back to + available. The header lanes just ahead of the table vary coherently with those scenario + branches too: `Alternate USA` carries `header_word_0 = 0x10000000`, `Southern Pacific` + carries `0x00000000`, and `Spanish Mainline` carries `0xcdcdcdcd`, while the structural + fields from `header_word_2` onward remain stable (`0x332e`, `0x1`, `0x22`, `0x44`, `0x43`) + and the 9-byte footer still decodes as `0x32dc`, `0x3714`, `0x00` in all three checked maps. + A wider corpus scan over the visible `.gmp`/`.gms` files makes those two anonymous header + lanes less mysterious too: the parser currently sees only three stable + `(header_word_0, header_word_1)` pairs across 79 files with this table shape, namely + `(0x00000000, 0x00000000)`, `(0x10000000, 0x00009000)`, and + `(0xcdcdcdcd, 0xcdcdcdcd)`. The zero-availability count varies widely underneath the first and + third pairs (`0..56` under the zero pair, `14..67` under the `0xcdcdcdcd` pair), so those two + lanes no longer look like counts or direct availability payload; the safest current read is + that they are coarse scenario-family or source-template markers above the stable + `0x332e/0x22/0x44/0x43` table header, with `0xcdcdcdcd` still plausibly acting as one reused + filler or sentinel lane rather than a meaningful numeric threshold. Current exported + disassembly notes still do not ground one direct loader-side or editor-side consumer of + `header_word_0` or `header_word_1` themselves, so that family-marker read remains an + inference from corpus structure rather than a named field assignment. + The new loader-side compare command makes the save-copy claim sharper too: for the checked + pairs `Alternate USA.gmp -> Autosave.gms`, `Southern Pacific.gmp -> p.gms`, and + `Spanish Mainline.gmp -> g.gms`, the parsed candidate-availability table contents now match + exactly entry-for-entry, with the only reported differences being the outer container family + (`map` vs `save`) and source-kind path (`map-fixed-catalog-range` vs the save-side branch). + has the explicit companion `world_refresh_selected_year_bucket_scalar_band` `0x00433bd0`, which + rebuilds the dependent selected-year bucket floats after the packed year changes; and then + rehydrates the named locomotive availability collection at `[world+0x66b6]` through + `locomotive_collection_refresh_runtime_availability_overrides_and_usage_state` `0x00461e00`. + That locomotive-side restore is tighter now too: its tail explicitly re-enters + `scenario_state_refresh_cached_available_locomotive_rating` `0x00436af0`, which rebuilds one + cached available-locomotive rating at `[state+0x4cbe]` from the current year plus the strongest + surviving available locomotive-side rating scalar `[loco+0x20]`, and the tiny query sibling + `0x00434080` is now bounded as the shell-side clamped read helper over that same cached field, + with the grounded shell-side reader later bucketing that value against `40/50/70/85/100`. The + same rehydrate band also refreshes the live structure-candidate filter and year-visible counts + through `structure_candidate_collection_refresh_filter_and_year_visible_counts` `0x0041e970`, + rebuilding the paired per-slot bands at `[candidates+0x246]` and `[candidates+0x16e]` and the + aggregate counts at `[candidates+0x31a]` and `[candidates+0x242]`; the same late checkpoint also + re-enters `placed_structure_collection_seed_candidate_subtype2_runtime_latch` `0x00434d40`, + which seeds runtime dword `[candidate+0x7b0]` across subtype-`2` candidate records before the + later world-wide reactivation sweep. That checkpoint also now has an explicit shell-facing scalar + publisher: `world_publish_shell_controller_progress_scalar_from_year_thresholds_or_selector_overrides` + `0x004354a0` writes one clamped `0..255` value into the current shell presentation object, + sourcing it either from the shell selector override pairs or from the scenario-side year-threshold + band rooted at `[state+0x3a/+0x51/+0x55/+0x59/+0x5d/+0x61]`; and just ahead of the later + scenario-side recipe rebuild, the same band also re-enters + `scenario_state_ensure_derived_year_threshold_band` `0x00435603`, which only falls into its + heavier rebuild body while `[state+0x3a] < 2` and otherwise leaves the derived year-threshold + companion slots `[state+0x51/+0x55/+0x59/+0x5d/+0x61]` unchanged. The neighboring late status + checkpoints around progress ids `0x196` and `0x197` also share one explicit stage gate now: + `world_query_global_stage_counter_reached_late_reactivation_threshold` `0x00444dc5` compares the + global counter `0x00620e94` against threshold `0x9901`, and the two current callers use a + negative result to clear `[world+0x39]` before the broader world and shell reactivation sweep. + The later reactivation tail is tighter now too: it includes the region-center world-grid flag + reseed pass + `0x0044c4b0`, which clears bit `0x10` across the live grid and then marks one representative + center cell for each class-`0` region through `0x00455f60`; its immediate sibling `0x0044c450` + then reruns `placed_structure_rebuild_candidate_cargo_service_bitsets` `0x0042c690` across every + live grid cell. The small secondary-raster premark helper `0x0044c570` is bounded now too: it + only admits cells whose current raster byte has no bits in mask `0x3e` and whose parallel class + query `0x00534e10` is false, then rewrites that masked class field to `0x02` and widens the same + cached bounds-and-count band `[world+0x21c6..+0x21d6]`. The next helper `0x0044ce60` scans the secondary raster at `[world+0x2135]` + for cells with any bits in mask `0x3e`, caching min/max bounds plus a marked-cell count in + `[world+0x21c6..+0x21d6]`; the larger sibling `0x0044c670` then consumes those cached bounds to + normalize the same raster and rebuild one dependent overlay/cache surface before the later + route-style rebuild, shell-window, and briefing branches. That overlay side is tighter now too: + after `0x0044c670` resolves scaled surface dimensions through `0x00534c50`, it walks one local + `3 x 32` sample lattice through the static offset tables at `0x00624b28/0x00624b48`, keeps only + secondary-raster classes `4..0x0d`, folds several interpolated `0x0051db80` samples into one + strongest local score, writes packed overlay pixels into the staged surface buffer, and only then + publishes that staged overlay through `0x00534af0`. The lower helper layer under that overlay + pass is tighter now too: `0x00534e10` is the reusable secondary-raster class-set + predicate for classes `1/3/4/5`, `0x00534e50` is the smaller neighboring class-subset predicate + for `1/4`, `0x00534ec0` covers `2/4/5`, `0x00534f00` covers `3/5`, `0x00534e90` is the + marked-bit query over the same 3-byte cell family, and the nearby local counter `0x0044bdb0` + is now bounded as the 8-neighbor count companion for that same `2/4/5` subset, walking the + shared `0x00624b28/0x00624b48` offset tables and re-entering `0x00534ec0` on each bounded + neighbor cell. The first caller cluster around `0x0044bf9d..0x0044c37b` therefore reads as a + secondary-raster neighborhood service band rather than a generic map scan. + `0x00533e70` and `0x00534160` are the coarser siblings over the overlay table at `[world+0x1685]`: + the first clears coarse chunk objects across one clamped rectangle, while the second ensures one + chunk object and seeds local marks through its deeper stamp helper. One level up, the neighboring + rect owner `0x005374d0` now reads as the shared secondary-overlay refresh pass: it reruns the + local sample and unsigned-word reducers `0x00536230/0x00536420`, rebuilds the signed vector byte + planes through `0x00536710`, and then rebuilds the multiscale support surfaces through + `0x00533890`, whose inner reducers now explicitly target the packed sample-triplet buffer plus + the float and unsigned-word support planes rooted at the five-entry per-scale families + `[world+0x15f1..+0x1601]`, `[world+0x1605..+0x1615]`, and `[world+0x1619..+0x1629]`. The setup + side of that same family is tighter now too: + `0x005375c0` is the shared ensure-and-seed owner that allocates the sample, sidecar, mask, + raster, vector, and coarse-cell tables together; crucially, it seeds `[world+0x1655]` with byte + `0x02` and `[world+0x1659]` with byte `0x01`, which closes the default-fill split. The local + component-walk owner under the same neighborhood band is tighter now too: `0x0044c200` + allocates a temporary `width*height` visit bitmap at `0x0062c128`, seeds one class-`2/4/5` + starting cell, derives an initial direction index through the remap table `0x005ee5d4`, and then + fans into the deeper recursive walker `0x0044be20`. That deeper walker widens dirty bounds + `[world+0x21ad..+0x21b9]`, stamps one companion-word orientation lane through `0x005ee5cc`, + reuses `0x00534ec0` plus `0x0044bdb0` to filter admissible neighbors, tracks temporary + visitation in `0x0062c128`, and then applies the local byte-1 edge-bit `0x04/0x08` updates + before returning. So the `0x0044bf9d..0x0044c422` cluster now reads as a real connected-component + walk plus edge-flag refresh layer over the secondary raster rather than only a loose group of + local neighbor counters. The adjacent mutation strip is tighter now too: `0x0044dcf0` refreshes + companion-word bit `0x200` in one local rectangle by checking whether any neighbor belongs to + class set `2/4/5`, while `0x0044df10` clears three local sidecar byte planes, demotes class `4` + to `1` and class `5` to `3`, and then reruns that marked-bit refresh over the surrounding + `+/-1` window. One level up, `0x0044e500` is the rect-wide owner that recomputes byte-1 edge + bits `0x04/0x08` for class-`2/4/5` cells, dispatches `0x0044df10` on incompatible local + patterns, and finally consumes the pending global seed pair at `[0x006d1304+0x78/+0x7c]` + through `0x0044c200`. The shell-side owner of that pending pair is tighter now too: + `[0x006d1304]` is the live `PaintTerrain.win` shell singleton while the callback-heavy side also + keeps a second rooted pointer at `0x006d1334`; the tool constructor snapshots the broader + terrain-paint state into both families while the world-side raster owner still only consumes + `[0x006d1304+0x78/+0x7c]` as one pending component-seed pair. Its radial sibling `0x0044e7d0` + is narrower: + after validating world-space + coordinates through `0x00414bd0`, it stamps class-`2` marks into the secondary raster by walking + one clamped bounding box and admitting cells only when the radial falloff helper `0x0051db80` + stays positive before re-entering `0x0044c570`. The two small support predicates under that same + strip are now explicit too: `0x00414bd0` is the float grid-bounds gate, and `0x00449df0` is the + integer rectangle clamp-and-validity helper shared by the local mutation owners. One level up, + the broader rect-scoped owner is tighter now too: + `world_rebuild_secondary_raster_derived_surface_and_companion_planes_in_rect` `0x0044e940` + first reclamps the caller rectangle through `0x00449df0`, reruns the local edge-refresh owner + `0x0044e500`, lazily ensures one presentation target through + `0x0051f090/0x00534910/0x00534920/0x00534930`: the first helper resolves the shared + world-presentation owner, `0x00534910/0x00534920` expose the current staging flag and buffer + root, and `0x00534930` captures one normalized-bounds rect into that staging buffer before the + later publish step `0x00534af0`. The same family then resolves scaled target dimensions through + `0x00534c50` before allocating one temporary `width*height` mask. Its main scan then + walks the live secondary raster `[world+0x165d]` through the same class predicates + `0x00534e10/0x00534e50/0x00534f00/0x00534ec0`: class-`1/3/4/5` cells force `0xff` into the four + sidecar byte planes `[world+0x1631..+0x163d]`, while the broader per-cell pass writes packed + values into the ensured target through `0x00534730` and also updates nibble lanes at byte offsets + `+0x2` and `+0x5` inside the same three-byte secondary-raster cell family. After the publish it + notifies the shell owner at `0x0062be68`, re-enters `0x00449f80` and `0x004881b0`, frees the + temporary mask, expands the caller rectangle by dirty bounds `[world+0x21ad..+0x21b9]` through + `0x00536710`, and finally seeds companion byte `[world+0x162d]` with `0xc4` on cells selected + from mask plane `[world+0x1655]`. So the `0x0044e500 -> 0x0044e940` band is now a real + derived-surface and companion-plane rebuild family rather than only a loose collection of local + raster mutations. The local + evidence now also supports a stronger negative conclusion: unlike `[world+0x1655]`, that second + mask plane is not part of the actively rebuilt runtime overlay path, and in the grounded local + corpus it behaves only as a separately seeded, cleared, and persisted sibling plane. One level + lower, the + base-plane allocator `0x00532c80` now reads more cleanly too: it is the narrower owner that + clears `[world+0x15e1]`, optionally applies the current grid dimensions, allocates the base + float-summary plane `[world+0x1605]`, the four sidecar byte planes `[world+0x1631..+0x163d]`, + both one-byte mask planes `[world+0x1655/+0x1659]`, and the packed secondary raster + `[world+0x165d]`, then seeds those planes with the same `0x02/0x01/0x00` default split. The + load-side owner for those same planes is tighter now too: the constructor thunk `0x0044e910` + immediately feeds the heavier payload body `0x0044cfb0`, which reads the rooted chunk families + `0x2ee2/0x2ee3/0x2ef4/0x2ef5/0x2ef6/0x2ee4/0x2ee5/0x2f43/0x2f44`, allocates the core world-grid + and secondary-raster arrays `[world+0x2129..+0x2141]` plus the route-entry collection + `0x006cfca8`, initializes every grid-cell record through `0x0042ae50`, and only then hands off + into `world_compute_transport_and_pricing_grid` `0x0044fb70`, the neighboring presentation + refresh `0x00449f20`, and the shell-mode pulse `0x00484d70`. So the `0x0044e910 -> 0x0044cfb0` + load side is now bounded as the heavy world-grid and secondary-raster bundle-load body rather + than just another anonymous constructor tail. One + level higher again, the broader world-presentation reinitializer `0x00537e60` now sits above + that base allocator and the larger support-family ensure path `0x005375c0`: it stores the live + grid dimensions, hard-resets the whole overlay runtime family through `0x00532590`, + and that reset strip is no longer opaque either: the immediately preceding local helpers + `0x00532310..0x00532550` now bound one compact overlay-local state family under the same owner. + `0x00532310/0x00532360/0x00532370/0x00532380` own the seven-dword companion block + `[world+0x15b5..+0x15cd]` together with live flag byte `[world+0x15b4]`; `0x005323f0`, + `0x00532460`, and `0x00532490` are the ensure, publish, and query strip for cached surface root + `[world+0x478]` using saved dimensions `[world+0x159c/+0x15a0]`; `0x005324e0/0x00532500` are the + live-flag setters for `[world+0x159b]`; `0x00532510` is the direct setter for mode byte + `[world+0x159a]`; and `0x00532520/0x00532550` own the four-dword saved dimension quad + `[world+0x15a4..+0x15b0]`. So the broader `0x00532590` reset really does sit at the base of a + concrete local cached-surface and companion-block owner family, not just a pile of unrelated + presentation fields. The reinitializer then + reinitializes the secondary-overlay family for those dimensions, and then republishes the + neighboring overlay constants and support owners used by both the world-side reattach branch and + the `.smp` restore-side presentation rebuild path, including several owners that all funnel + through the shared static-template slot allocator `0x00532ad0` over the local `0x100` pointer + band at `[world+0x08]`. Those neighboring owners are tighter now too: `0x00535070` is the small + primary overlay-surface-or-template setup owner; `0x00535100` is the heavier requested-dimension + apply and four-slot overlay-surface rebuild owner used by the setup-side regenerate branch and + the load-side bundle path; while `0x005356e0` and `0x00535890` seed two + larger static-template slot bands rooted at `[world+0x1568/+0x156c/+0x1574/+0x1578]` and + `[world+0x1560/+0x1564]` respectively; the remaining heavier sibling `0x00535430` now reads as a + shared four-slot overlay-surface rebuild owner that resamples one source or fallback descriptor + into a short local slot strip above `[world+0x155c]`. The immediate helper strip under that same + family is tighter now too: `0x00534f60` is the small presentation-owner base init above + `0x00532590`; `0x00534f80` releases one transient surface handle at `[world+0x478]` and clears + byte `[world+0x159b]`; `0x00532760` releases the current overlay slot chosen by selector + `[world+0x1558]`; `0x005327a0` clamps two requested surface dimensions down to supported + power-of-two sizes while also enforcing shell display caps from `[0x006d4024+0x114243/+0x114247]`; + `0x00532860` is the local twelve-slot stitching pass over the parallel bands rooted at + `[world+0x08/+0x0c/+0x18]`, copying terminal rows and edge dwords between those sibling slot + surfaces before finalizing the primary band through `0x00541c10`; + `0x00532960` is the adjacent paired projection helper that maps two caller counters through the + current `16x16` and `4x4` rounded grid quanta and writes the resulting coarse offsets back to two + out-pointers; + `0x005329e0` maps one `(x,y)` pair into a `1`-based coarse `4x4` overlay region id using the + current rounded grid dimensions; `0x00532a30` is the direct getter for local dword `[world+0x1554]`, + which still reads only as the live count or tag for this overlay slot band; + `0x00532a40` and `0x00532aa0` are the time-selected query helpers over the first and second + template-seeded slot bands rooted at `[world+0x1568/+0x156c]` and `[world+0x1560/+0x1564]`; and + `0x00532a90` is the direct getter for trailing fallback slot `[world+0x1578]`. The next adjacent + owner is tighter now too: `0x00532b30` is the shared release/reset path for the local overlay + slot band at `[world+0x08]`, with a split release policy keyed by shell flag + `[0x006d4024+0x11422e]` and a special forced-direct range for slot ids `1..0x10`, after which it + clears band fields `[world+0x1554/+0x1568/+0x1570/+0x155c/+0x1560/+0x1564]`. The tail of that + same reinitializer is tighter one level up too: `0x00527ce0` is the broader ensure owner that + watches current grid extents plus world tag `[world+0x2121]`, re-enters `0x00532860` when those + cached values change, rebuilds or releases local helper `[this+0x65]`, and then clears the two + large global scratch planes rooted at `0x008f2520` and `0x00b33530`. The tail of that same + reinitializer is + tighter now too: after the larger support-family setup it seeds one seven-entry default overlay + companion set through `0x005373b0`, whose inner allocator `0x00535950` populates the local + `0x1b`-entry slot table from the static template rows `0x005dd300..0x005dd378`. The lifecycle + side is tighter in the same way now: `0x00536044` is the shared teardown owner that frees those same + three five-entry support families together with both mask planes, the packed secondary raster, + the vector-byte planes, the local staging buffer, and the neighboring sidecar or coarse-cell + tables. The remaining base-float lane is tighter too: the larger rebuild owner + `0x00538360` now clearly writes one base float-summary field into `[world+0x1605]`, clears both + one-byte mask planes, and then only repopulates the primary mask plane `[world+0x1655]` for the + qualifying class-`1` interior cells before re-entering `0x00532d90` to normalize that base + float-summary plane globally and `0x00532f60` to expand positive cells through one caller radius. + That asymmetry is now enough to close the local semantic edge: `[world+0x1655]` is the actively + rebuilt primary overlay mask, while `[world+0x1659]` is only the separately seeded and persisted + secondary mask sibling with no comparably grounded distinct read-side consumer. The only grounded + getter call to its root accessor `0x00533b60` is the shell staging branch at `0x00525bad`, and + that branch immediately discards the returned pointer. The bundle side is now explicit too: + `.smp` save-load treats the two mask planes as separate payloads with chunk ids `0x2cee` for + `[world+0x1655]` and `0x2d51` for `[world+0x1659]`, while the neighboring `0x2d49/0x2d50` + branches are the separate packed secondary-raster import lanes rather than alternate consumers + of the second mask plane. So, in the mapped local code, `0x1659` is best treated as a persisted + compatibility or seed-state sibling, not as a second actively consumed runtime overlay mask. The + transport/pricing preview side is tighter now too: `0x00538060` sits directly beneath + `0x0044faf0`, first seeds one preview handle through `0x00535430` using the short `C_` + descriptor, temporarily overrides shell globals + `[0x006d4024+0x11423b/+0x11423f/+0x114254/+0x114255]`, and then loads `%1.tga` through + `0x0053c1c0 -> 0x00541970`. It clamps that sampled image into the `0x401 x 0x401` range, + rewrites `[world+0x1605]` plus the mask/raster family `[world+0x1655/+0x1659/+0x165d]` from the + sampled pixels, optionally re-enters `0x00532d90/0x00532f60`, republishes the seeded preview + handle through `0x0053c000`, and then re-enters `0x005375c0(1, 0, 0)`. The small shell-global + owner it also touches is tighter now too: `0x006d401c` is constructed by `0x00538640`, + `0x005386e0` publishes the primary timed text lane, `0x005387a0` publishes the secondary fixed + `10000` ms lane, `0x00538810` finds the first registered shell window containing one child + control id by walking each window through `0x0053f830`, and `0x00538840/0x00538880/0x00538890` + manage the owner's local `1000`-slot active-token table keyed by child control id. The adjacent + list strip is tighter too: `0x00538990` is the registered-window virtual-slot-`0` gate that + stops on the first zero return, `0x005389c0` is the shared unlink helper for the same doubly + linked list rooted at `[owner+0x00/+0x04]`, `0x00538a60` is the zero-counter gate over + `[owner+0xc60]`, `0x00538a70` is the matching full reset-and-release body used during bootstrap + teardown, and `0x00538a10/0x00538a20/0x00538a30/0x00538a40` are the direct getter, setter, + increment, and clamped decrement helpers for the owner's scalar lanes `[+0xc5c]` and `[+0xc60]`. + The next shell-runtime strip is tighter now too: `0x005388d0` is the shared `12`-dword + descriptor dispatcher with the optional override validator at `[owner+0xc75]` and the recursive + `kind 6 -> 0xb7` rewrite; `0x00538c70` is the prioritized cached-text owner over + `[owner+0xbd8/+0xbdc/+0xbe0/+0xbe4]` that emits descriptor kind `0xae` through `0x005388d0`; + `0x00538e00` is the five-scalar descriptor-synthesis wrapper above that same dispatcher; + `0x00538e50` is the sorted registered-window insert owner over node key `[node+0x21]`; + `0x00538ec0` is the refresh sweep over the indexed helper collection rooted at `[owner+0xc69]`; + and `0x00538f10` is the broader optional-window publish plus blocking descriptor loop used by + modal launchers and some shell transition paths. + +### Event Editors and Scenario Action Windows + +The event side is tighter too: + that `0x00433130` pass in turn materializes each live event record through + `scenario_event_refresh_runtime_record_from_packed_state` `0x0042db20`. Current shell-side xrefs + now tighten that event branch too: the first rebuilt linked row family under `0x0042db20` aligns + with the standalone condition list later queried by `EventConditions.win`, while the second + rebuilt family aligns with the four grouped effect lists later deep-copied through + `scenario_event_clone_runtime_record_deep_copy` `0x0042e050` during event duplication and effect + staging. The condition side is tighter now too: the tiny helper cluster + `0x0042df30/0x0042df70/0x0042dfb0/0x0042dff0` is no longer just "some adjacent list scans". + Current evidence bounds it as four predicates over the standalone `0x1e`-row condition list, + testing class bits `0x01`, `0x02`, `0x04`, or any of those bits in the static table + `0x005f3e04 + id*0x81`, with special fallback checks through event fields `[event+0x7f9]`, + `[event+0x7fa]`, and `[event+0x7f0] == 0x63`. The shell side is tighter too: vtable slot + `0x005d0cd8` now binds `shell_event_conditions_window_handle_message` `0x004d59e0`, and vtable + slot `0x005d0cf8` binds `shell_event_effects_window_handle_message` `0x004d7060`. The effects + side is tighter too: the lower helper trio is no longer anonymous. `0x004d5d00` now reads as the + effect-type selector refresh under control family `0x4fb2`, `0x004d5f50` reads as the selected + effect parameter-row repaint, `0x004d6090` is the heavier staged-effect editor refresh over the + `0x4fc7/0x4fce/0x4ff6/0x4ff9/0x4ffc/0x5041/0x5044/0x5046/0x5047` bands, and `0x004d67f0` + commits the current editor state back into the staged effect row at `[this+0x78]`. The verb side + is tighter now too: `shell_open_event_conditions_modal_and_return_result` `0x004d9dc0` and + `shell_open_event_effects_modal_and_return_result` `0x004d9e40` are the shared modal openers + above the two editor windows; `0x004da640`, `0x004da700`, and `0x004d9ed0` now read as the add, + edit, and remove verbs for standalone condition rows; `0x004da7c0`, `0x004da860`, and + `0x004da920` are the matching add, edit, and remove verbs for grouped effect rows; and + `0x004d8120` is now the heavier condition-row list panel refresh those condition-side verbs + re-enter after mutation. The conditions-side refresh split is tighter too: `0x0042d700` + aggregates standalone condition-list class or modifier flags, `0x0042d740` aggregates grouped + effect-row type flags for one selected grouped list, `0x004d9970` owns the condition-class + summary and grouped-row status bands, `0x004d77b0` owns the grouped summary-band affordance gate + for `0x4fed..0x4ff0` when selector `0x5000` lands on `0x5002`, `0x004d9d10` owns the smaller + grouped-effect territory-target affordance on control `0x500b`, `0x004d9f50` owns the selected-event mode + strip and summary text panels, and `0x004d9390` is the mode-dependent detail-row switch beneath + that strip. `0x004da0f0` is tighter too: selector `0x5001` now has the strongest current + RT3.lng fit as the condition-side `Test against...` mode above `0x004d9970`, while selector + `0x5002` has the strongest current fit as the grouped-effect-side `Apply effects...` mode. + That `0x5002` branch now clearly builds control `0x5014` from RT3.lng `1160..1164` as `to the + company/player/player (i.e. chairman)/territory for which the condition is TRUE` before + enabling the adjacent `0x5005`, `0x500a`, and `0x5014..0x501c` family. The strongest current + RT3.lng fit for the remaining visible target-scope strip is now `0x5015 = to the whole game`, + `0x5016..0x5018 = to all/human/AI companies`, `0x5019 + 0x500b = to territories`, and + `0x501a..0x501c = to all/human/AI players`; the grouped effect-row type mask matches that split + directly through bits `0x08`, `0x01`, `0x04`, and `0x02`. The + selected-event strip is tighter now too: `0x004db120` is the broader selected-event repaint and + navigation refresh above those smaller helpers, `0x004db520` and `0x004db5e0` are the previous + and next selected-event stepping verbs, `0x004db8b0` is the add-or-clone event modal helper, + `0x004dba90` is the rename verb, `0x004d9360` is the delete verb, `0x004db6a0` is the live + selected-event id setter behind control `0x4e84`, and `0x004db6f0` is the callback-binding plus + pending-selection bootstrap path that seeds the strip during window bring-up. The larger + dispatcher at `0x004dbb80` now makes the strip explicit: `0x4e85..0x4e8a` are previous, next, + add blank, clone selected, rename, and delete event, while the later grouped band commits current + summary state through `0x004d8d50` before changing grouped selector `[this+0x9c]` via `0x004dbf93`. + The selection bootstrap side is tighter too: `0x004daf40` is now the placeholder reset helper for + the selected-event summary controls `0x4eaf`, `0x4eac`, `0x4ed9`, `0x4edb`, and `0x4fdf..0x4fe2`. + The grouped target-scope side is tighter too: `0x004d8ea0` now reads as the commit helper for current + selected-event text panels before selection or grouped-action changes, `0x004d8d50` now records + the hidden selector family `0x5006..0x500e -> 0..8`, and `0x004dab60` projects that ordinal + one-to-one onto the visible grouped-effect target-scope display strip `0x5014..0x501c`. That + split is firmer now: `0x5006..0x500e` are the canonical hidden selectors that get stored into + `[event + group + 0x7fb]`, while `0x5014..0x501c` are the visible mirror rows republished from + that same ordinal rather than a second independently named selector family. The grouped row and + stored-summary refresh side is tighter too: `0x004d88f0` is now the selected grouped-effect + row-list renderer for `0x4ed5`, formatting the grouped `0x28`-byte rows through RT3.lng + `1154..1159`, and `0x004da9a0` is the current grouped-summary-state republisher that reloads + `0x500a`, `0x500b`, and visible action selection `0x5014..0x501c` from `[event + group + ...]` + before tailing back into `0x004da0f0`, + `0x004dbfca` as the grouped target-scope mode selector that persists the chosen control id into + `0x00622074`, with `0x5001/0x5002` now strongest-fit as `Test against...` and + `Apply effects...`, `0x004dbeeb` as the pending shared summary-text triplet publish helper for + `0x4eac/0x4ed9/0x4edb`, + `0x004d91e0` as the selected-event summary-header and grouped-mode commit helper above + `0x004d8d50`, and `0x004dbe7a` as the narrower `0x4ec6/0x4ec7` choice-event single-player-only + warning modal branch rooted at RT3.lng `3887`. The remaining gaps on + this lane are narrower again because the grouped-band `0x4dc09c` table now closes one earlier + overclaim: controls `0x5001/0x5002` are the only `0x4fed..0x501c` entries that route into + `0x004dbfca` on the `0xcf` side, while visible rows `0x5014..0x501c` only route to the smaller + `0x004d9d10` affordance path and the rest of `0x4ff1..0x5013` are default no-ops. The open + question is therefore no longer whether those visible target-scope rows are direct selector verbs; + current evidence says they are not. + The local slot records are rooted at + `[world+0x69d8]`, + `[slot+0x01]` polarity and the external role gate at `[world+0x0bc3+slot*9]` are now grounded, and + `[slot+0x03]` now looks like the distinguished primary-human-seat marker because current grounded + writes seed it only on slot zero and later logic moves it solely by whole-record compaction. The + open question is no longer whether the seeded trio lands in the visible shell company roster; + current evidence says it does, and ordinary `Start New Company` now looks like a fresh-company + allocator through `start_new_company_dialog_commit_create_company` and + `start_new_company_request_create_company`, not like the path that claims one of the seeded named + railroads. The immediate post-roster station branch is now clearly separate: current grounded + resource names and handlers put mode `8` on `StationDetail.win`, mode `5` on `StationList.win`, + and the subordinate modal selector helper on `StationPick.win` through + `shell_station_pick_window_open_modal_and_return_selected_station_id` above + `shell_station_pick_window_construct`. The company-side ownership question has therefore moved + down a layer rather than staying open. We now have a recovered `CompanyDetail.win` + owner family through `shell_company_detail_window_refresh_controls`, + `shell_company_detail_window_construct`, and `shell_company_detail_window_handle_message`; the + same owner now has one broader bounded read-side lane too, because control `0x9470` uses + `shell_company_detail_render_financial_history_panel` to draw the five-step Revenue or Expenses or + Interest or Profit or Lifetime strip, sibling control `0x9471` reuses + `shell_format_company_financial_summary_card` through + `shell_company_detail_render_company_summary_card`, controls `0x947d` and `0x947e` now ground a + bond maturity and repay panel through `shell_company_detail_render_bond_maturity_and_repay_panel`, + control `0x9488` now grounds the debt or credit or rate summary block through + `shell_company_detail_render_debt_credit_and_rate_summary_panel`, control `0x948a` now grounds the + share-value and dividend-payout block through + `shell_company_detail_render_share_value_and_dividend_summary_panel`, while the broader six-row + per-share stock-data family is now bounded under `shell_format_company_stock_data_panel`, and the + adjacent territory selector lane is bounded through + `shell_company_detail_select_territory_access_row`, + `shell_company_detail_render_territory_access_row`, + `shell_company_detail_sync_selected_territory_from_picker`, and + `shell_company_detail_refresh_selected_territory_access_summary`; the first finance-action layer + beneath it is bounded through the bond, stock-issue, stock-buyback, and dividend-rate helpers; the + territory-access side is bounded too through + `shell_company_detail_refresh_selected_territory_access_summary`, + `shell_company_detail_buy_territory_access_rights_flow`, and the underlying company access-rights + helpers; and the full takeover and merger vote-result lane is now grounded through + `shell_resolve_chairmanship_takeover_vote_and_commit_outcome`, + `shell_present_chairmanship_takeover_vote_outcome_dialog`, + `shell_resolve_merger_vote_and_commit_outcome`, and `shell_present_merger_vote_outcome_dialog`. + The remaining company-side uncertainty is therefore narrower than before: the broader support and + valuation side is now tighter too because + `company_compute_cached_recent_per_share_performance_subscore`, + `company_compute_five_year_weighted_shareholder_return`, and + `company_compute_public_support_adjusted_share_price_scalar` bound the recent per-share + performance and investor-support/share-price blend beneath those vote resolvers; the recent + per-share feeder now has a grounded four-lane tail too, with current partial-year weight + `(5 * [world+0x0f]) - 5`, prior full-year weights `48/36/24/12` on `0x1f/0x1e`, dividend + non-decline pair weights `9/8/7/6` on `0x20`, lane weights `40/10/20/30`, the startup age ramp + `0/0/0/100 -> 25/25/35/100 -> 50/50/65/100 -> 75/75/85/100 -> 100/100/100/100`, a strongest-lane + `*1.25` boost, a weakest-lane `*0.8` reduction, and separate bounded-intermediate versus final + difficulty applications under `0x005f33b8`; the next consumer `0x00424fd0` is also tighter now, + with the young-company interpolation against `[company+0x57]`, caller pressure clamped to + `[-0.2, 0.2]`, one `(shares / 20000)^0.33` share-count growth term, and the later threshold + ladder `0.6 / 0.45 / 0.3 / 1.7 / 2.5 / 4.0 / 6.0` before the issue-`0x37` multiplier, + `scenario_state_compute_issue_opinion_multiplier` now bounds the + next layer of optional company, chairman, and territory-specific opinion overrides on the active + scenario state, and the broader stat-reader family around + `company_read_control_transfer_metric_slot` and + `company_read_year_or_control_transfer_metric_value` is no longer just a merger-premium helper. + Current grounded callers show the same metric family feeding the annual shareholder-revolt and + creditor-liquidation lane surfaced by localized ids `300..304`, while the debt-side shell and + bond lane now separately close `0x38` as `Credit Rating` and `0x39` as `Prime Rate`. That means + the remaining gap is now mostly gone on the UI side too: issue `0x37` is already bounded to the + same investor-confidence family as the equity-support and governance-pressure paths, and current + grounded UI evidence still stops at the investor-attitude sentence family rather than one + standalone caption. The calendar side is tighter now too: + `[world+0x15]` is the absolute counter for the same mixed-radix `12 x 28 x 3 x 60` + year-plus-subfield tuple packed by `0x0051d3c0` and unpacked by `0x0051d460`, not just a vague + “calendar-like” blob. The `TrackLay.win` family now clearly owns `Lay single track.` `Lay double track.` + and `Bulldoze` as its three primary modes, its bridge selector, its wrapped frequency preferences, + and a strongly aligned pair of `Auto-Hide Trees During Track Lay` and `Auto-Show Grade During + Track Lay` toggles; the `StationPlace.win` family now clearly owns its six top-level category + buttons, the station-style scroller, and the station-rotation controls. The older `Building + placement center` string 671 no longer looks like a live StationPlace control label in the current + recovered flow, because the active constructor, preview, refresh, and dispatcher paths all use + neighboring ids such as 669 and 2208 without a direct recovered lookup of 671. On save or load the + broad serialize-versus-restore split is now grounded, the non-Quicksave `.gmp/.gmx/.gmc/.gms` + families are separated, and the auxiliary `.gmt` path is at least bounded to the preview-surface + side owner. The higher-value shell-facing gap has therefore shifted upward to the remaining + semantics of the post-load generation phases, the later recurring structure-population cadence, + the deeper vote-weight formulas inside takeover and merger resolution, and the still-open meaning + of the packed simulation calendar tuple. + +### CompanyDetail and Section Ownership + +The shell detail family now has an explicit + section-selector lane in addition to the read-side panels already mapped. Controls + `0x9472..0x9475` directly select the four visible CompanyDetail sections through `0x006cfe60`, + `0x9476..0x9479` are the companion visual controls for that same tab strip, and section `0` is now + bounded more tightly as the chairman or governance slice around the portrait-backed chairman band + on `0x9480` plus the dynamic overview widget `0x947f`. That widget is no longer just a vague + status line: the section-0 refresh binds it through a dedicated stack-built dynamic text path, + and the strongest current shared formatter candidate is + `shell_format_company_governance_and_economy_status_panel` at `0x004e5cf0`, which first renders a + five-line company-metric preamble through localized ids `1211..1215`: `Revenues` from slot + `0x2c`, `Profits` from slot `0x2b`, `Load miles hauled` from slot `0x17`, `Revenue per load + mile` from the derived `slot 0x2c / slot 0x17` branch, and `Average speed` from slot `0x26` + rendered through `1216` `%1 m.p.h.`. It then splits the governance summary more concretely: no + linked chairman emits `3045`, wholly owned companies emit `3046` for the scenario-selected + chairman or `3047` for another linked chairman, and investor-owned companies emit the + investor-attitude lines `3048/3049` with one adjective from the table at `0x00622170`. That + branch is no longer using unnamed helpers either: `company_get_linked_chairman_profile_record` + `0x00426ef0` resolves the linked chairman profile and `chairman_profile_owns_all_company_shares` + `0x004768c0` is the full-ownership test behind the `3046/3047` split. The salary side is tighter + too: the formatter computes one signed delta from `[company+0x14f]` and `[company+0x0d59]`, then + chooses `3050..3052` for the scenario-selected chairman or `3053..3055` for another linked + chairman depending on whether that delta is negative, positive, or zero. The bonus line is + narrower still: it only appears when the display year matches `[company+0x34f]`, using amount + `[company+0x353]` with `3056` or `3057`. It then appends the + `1218` `Economy status - %1.` tail caption and stages the adjacent selected-company report or + list help-title pairs `1219/1220` `Income Statement`, `1221/1222` `Balance Sheet`, + `1223/1224` `Haulage Report`, `1225/1226` `Stock Report`, `1227/1228` `Train List`, + `1229/1230` `Station List`, `1231/1232` `Industry List`, and `1233/1234` `Cargo List`. + Current evidence still does not recover separate `CompanyDetail.win` action controls for that + strip under `shell_company_detail_window_handle_message`, so it currently reads as staged + overview text or help content rather than as a closed launcher family. The direct `0x947f` + formatter call is still indirect, but the widget boundary is tighter too: the generic shell + helpers `shell_control_refresh_matching_dynamic_text_payload` `0x00540a47` and + `shell_control_release_dynamic_text_payload` `0x005639d2` now show that type `0x6f` controls + free or swap one heap-backed text payload and then short-circuit as a special dynamic-text case, + which strengthens the reading of `0x947f` as a display-only overview widget rather than a normal + callback control. One adjacent boundary is tighter now too: the broader overview wrapper at + `shell_render_company_overview_panel_header_and_optional_change_affordance` `0x004e5a80` owns + the fallback no-company texts `1210`, `3043`, and `3888`, styles controls `0x3f06` and `0x3f07`, + and on the narrower selected-company branch appends `3044` `Click to change company name and + logo.` plus the neighboring `1941` `Change` affordance before falling through into the shared + `0x004e5cf0` text body. That keeps the name/logo affordance outside the ordinary + `CompanyDetail.win` action dispatcher and makes the `0x947f` alignment cleaner. The message-side + action band is tighter too: `0x94b5` grounds + territory-access purchase, `0x94b6` grounds bankruptcy, `0x94cf..0x94d2` ground bond issue, stock + issue, stock buyback, and dividend-rate changes, `0x9493` routes into the destructive + company-clear helper that deactivates the selected company and clears chairman/share links, + `0x94d6` grounds bankruptcy, `0x94d7..0x94da` ground bond issue, stock issue, stock buyback, and + dividend-rate changes, `0x94db` grounds merger, `0x94dc` grounds resignation, and `0x9538` grounds + chairmanship takeover. The finance-side dialog family is tighter too: the bond-issue lane now has + the dedicated modal renderer `shell_company_detail_render_issue_bond_offer_dialog` `0x004c3560` + for underwriter terms `968..972`, the stock-issue lane has + `shell_company_detail_render_issue_stock_offer_dialog` `0x004c3b50` for the staged offer lines + `975..978`, and the buyback lane has + `shell_company_detail_render_stock_buyback_offer_dialog` `0x004c4300` for broker lines + `981..984`. The compact summary card on sibling control `0x9471` is tighter too: + `shell_format_company_financial_summary_card` at `0x004bfb30` now clearly renders `Cash:`, + `Revenue:`, and `Profits:` from company slots `0x0d`, `0x2c`, and `0x2b`, rather than one looser + unnamed finance block. The dividend lane is now split the same way: + `shell_company_detail_setup_dividend_rate_adjust_controls` `0x004c4c70` binds the paired adjust + controls `0x99e8` and `0xc0f9`, + `shell_company_detail_render_change_dividend_rate_dialog` `0x004c4e30` renders localized ids + `988..990`, and + `shell_company_detail_handle_change_dividend_rate_dialog_message` `0x004c5140` clamps the staged + dividend rate against `company_compute_board_approved_dividend_rate_ceiling` `0x00426260` and + raises localized id `991` when the board refuses a higher dividend, all before the existing + company commit path. All four finance verbs now converge through the shared + callback-driven modal opener `shell_open_custom_modal_dialog_with_callbacks` `0x004c98a0`, which + is also reused by the multiplayer staged text-entry lane. The front controls in section `0` are + tighter too: `0x948b` is a + tutorial-guarded escape or back control that shows localized id `3724` `This option is disabled in + the tutorial.` before falling back to the shell detail-manager escape path, `0x9491` and `0x9492` + only restyle the paired visuals `0x948f` and `0x9490`, and `0x9494` opens localized id `3635` + `Enter the amount that your company's cash should be` and writes the accepted value directly into + the selected company cash pair. The neighboring debt section is tighter now too: controls + `0x947d` and `0x947e` no longer read as one-off bond widgets, but as the owners of two repayable + bond-slot row bands, `0x94e8..0x950f` and `0x9510..0x9537`. Those row controls now clearly + converge on the same repayment path in the message dispatcher: they reject unaffordable repayment + through localized id `2990`, open the early-repayment confirmation rooted at `2991`, and then + either commit through `company_repay_bond_slot_and_compact_debt_table` `0x00423d70` or package + the request through the multiplayer shell transport. The render-side owner is tighter too: + `shell_company_detail_render_bond_maturity_and_repay_panel` formats `Due %1` and `Repay this + bond.` for the selected debt slot while the tiny binder + `shell_company_detail_bind_bond_row_band_for_active_panel` switches between the two row bands. + Current `0xcb` dispatch does not treat `0x948f`, `0x9490`, `0x94d4`, or `0x94d5` as standalone + action cases. The message-side jump table now makes that passive/action split explicit too: in the + dispatch byte map rooted at `0x004c6640`, controls `0x94d6..0x94dc` map to cases `0x06..0x0c`, + control `0x9538` maps to case `0x0d`, and the neighboring companion rows `0x94d4` and `0x94d5` + stay on the default path. The refresh-side ownership is tighter too: the helper now explicitly + loops over `0x94d4..0x9537` as the selected-company-owned band and over `0x9538..0x959b` as the + linked-chairman-owned band, and those two loops do not use the same style polarity. + `0x94d4..0x9537` take style `0x65` when the selected company matches the scenario-selected + company and `0x87` when it differs, while `0x9538..0x959b` take style `0x87` when the selected + company's linked chairman matches the scenario-selected chairman and `0x65` otherwise. The + selected-company action side + is tighter now too: scenario toggle `0x006cec78+0x4a8f` re-enables bankruptcy `0x94d6` together + with passive companion row `0x94d4`, `+0x4a8b` re-enables issue bonds `0x94d7` together with + passive companion row `0x94d5`, `+0x4a87` re-enables stock issue and stock buyback + `0x94d8..0x94d9`, `+0x4a93` re-enables dividend `0x94da` together with the same passive + companion row `0x94d5`, `+0x4adb` re-enables merger `0x94db`, `+0x4acb` re-enables resignation + `0x94dc`, and `+0x4acf` re-enables chairmanship takeover `0x9538`. That makes `0x94d4/0x94d5` + read more like passive companion or heading widgets than hidden verbs. The constructor boundary + is tighter too: current `CompanyDetail.win` setup still only binds explicit callbacks for + `0x9470`, `0x9471`, `0x947d`, `0x947e`, and `0x948c..0x948e`, not for the wider section-0 row + bands. That keeps the remaining `0x94d4..0x959b` content looking more like resource-defined + display rows that are gated and restyled by refresh than like individually code-rendered widgets. + That leaves the main remaining CompanyDetail-specific shell edge at the exact `0x947f` formatter + binding plus the still-unsplit render-side governance rows inside `0x94d4..0x959b`. +### Adjacent LoadScreen.win Report Family + +The neighboring shell lane around controls + `0x3ef6..0x4073` is now separated from `CompanyDetail` instead of being treated as one more + extension of the `0x947f` overview path. The real outer owner is + `shell_load_screen_window_construct` `0x004ea620`, which binds `LoadScreen.win`, randomizes the + `LoadScreen%d.imb` background family, stores the singleton at `0x006d10b0`, and seeds the first + visible page-strip controls. Above the older page-specific work, the real message owner is now + `shell_load_screen_window_handle_message` `0x004e3a80`: it owns page id `[this+0x78]`, + page-local substate `[this+0x7c]`, page-kind `[this+0x80]`, current company `[this+0x88]`, + current chairman profile `[this+0x8c]`, display year `[this+0x9c]`, and the page-local report + row latch `[this+0x118]`, then fans back into the shared selector + `shell_load_screen_select_page_subject_and_refresh` `0x004e2c10`, the company-step helper + `0x004e3a00`, and narrower page branches such as `0x004e45d0`. The matching render-side owner is + now bounded too: `shell_load_screen_render_active_page_panel` at `0x004ea060` formats the common + heading and panel frame, then switches on page id `[this+0x78]` and hands control down into the + active page body. That older branch is now demoted to what it actually is: + `shell_load_screen_profile_stock_holdings_page_handle_message`, the page-specific handler beneath + the stock-holdings slice. Inside that same family, + `shell_load_screen_render_profile_stock_holdings_summary_panel` at `0x004e5300` grounds the + selected-profile holdings page: it resolves the current chairman profile from `[this+0x8c]`, + renders the top summary rows `1204` `Stock Value:`, `1205` `Total Assets:`, and + `1206` `Stock Holdings:`, then walks the active company roster and formats one row per positive + holding through `1201` `Click to view details on %1.`, `1207` `%1 Shares`, and `1208` `%1 Value`, + falling back to `1209` `None` when no positive holdings survive. It also appends `3029` + `Click to change player name and portrait.` plus the adjacent `1941` `Change` affordance only + when the rendered profile matches the scenario-selected chairman. The earlier pages are tighter + now too: `0x004e68e0` is the selected-company financial ranking page using the active company + roster plus `1235..1245` for revenue, profit, cash, track mileage, and report affordances; and + `0x004e6ef0` is the active-chairman wealth ranking page using the chairman profile collection + plus `1237`, `1241`, `1246..1250` for cash, stock, total, and purchasing-power style comparisons. + The later sibling renderers are broader than that one holdings page now too: `0x004e7670` is the + selected-company train list page using `1235..1267`, `0x004e8270` is the selected-company + building list page using `1268..1278`, `0x004e8bb0` is the selected-company station list page + using `1279..1288`, and `0x004e9460` is the map-wide cargo list page using `1289..1298` over the + live candidate collection rather than one company roster. The last broad early-page owner is + tighter now too: `0x004e9b20` is the shared multi-year company report-table renderer for page + `4` `Income Statement`, page `5` `Balance Sheet`, and page `6` `Haulage Report`, all driven from + `0x004ea060` with one caller-supplied mode byte and yearly company rows built through + `company_read_year_or_control_transfer_metric_value`. The row families are bounded too: + income-statement rows `1301..1315`, balance-sheet rows `2816` and `1317..1322`, and + haulage-report rows `1323..1335`. The only special rows inside that family are now tighter too: + `0x00425880` and `0x004258c0` provide the negative-cash and positive-cash interest-rate inserts + for the `%1/%2` placeholders in strings `2815` and `2816`, so they are no longer anonymous + private math blobs. The adjacent early siblings are tighter now too: `0x004e5130` is the + selected-company `Stock Data` page wrapper that falls back through `1299` and otherwise reuses + `0x004c0160` to render the `Largest Shareholders`, `Shares`, and `Per Share Data` family; + `0x004e6ef0` is the `Player List` page; `0x004e5300` is the `Player Detail` holdings page; and + `0x004e51ea` is the `Game Status` briefing panel that pulls current scenario briefing text from + the live scenario text store and appends the `1772/1773` `Briefing` affordance. The active-page + renderer at `0x004ea060` is now tighter too because its 13-byte page descriptor table at + `0x006220a0` has been decoded directly as `{ page kind, title string id, `0x3ef8` backlink + page, selected-company-header flag }`. The currently grounded rendered title order is: + `XXX`, `COMPANY OVERVIEW`, `COMPANY LIST`, `INCOME STATEMENT`, `BALANCE SHEET`, + `HAULAGE REPORT`, `STOCK DATA`, `PLAYER LIST`, `PLAYER DETAIL`, `GAME STATUS`, + `TRAIN LIST`, `TRAIN DETAIL`, `STATION LIST`, `STATION DETAIL`, `CARGO LIST`, + and `INDUSTRY LIST`. Its live body bindings are now bounded too: page `0` falls back to + `1203` `Unable to display page`, page `1` is the company overview wrapper, page `2` is the + company list page, pages `3..5` are income statement, balance sheet, and haulage report, page + `6` is stock data, page `7` is player list, page `8` is player detail, page `9` is game status, + page `0x0a` is train list, page `0x0b` currently falls back to `1203`, page `0x0c` is station + list, page `0x0d` currently falls back to `1203`, page `0x0e` is cargo list, and page `0x0f` + is industry list. The row-click path is tighter now too: player-list rows re-enter page `8` + directly, but train, station, and industry rows leave `LoadScreen.win` through the shell + detail-panel manager at `0x004ddbd0` instead of switching to title-table pages `0x0b` or + `0x0d`. Page `0` is tighter now too: its descriptor is kind `0`, title `1200` `XXX`, backlink + `0`, and header flag `0`, and no current post-constructor selector path has been recovered for + it. The descriptor side now also bounds the only known reverse route for the dormant detail + titles: `0x3ef8` is the table-driven backlink affordance, so if page `0x0b` or `0x0d` were ever + selected, the known reverse path would return to train-list page `0x0a` or station-list page + `0x0c` respectively rather than through a separate detail-only owner. + The launcher side is tighter too: current grounded `shell_open_or_focus_load_screen_page` + callers cover pages `1`, `2`, `3`, `4`, `5`, `6`, `7`, `9`, `0x0a`, `0x0c`, `0x0e`, and `0x0f`, + and no current recovered opener or row-click route selects `0x0b` or `0x0d`. So the + `LoadScreen.win` family now has a much cleaner shape: one outer message owner + `0x004e3a80`, one active-page render owner `0x004ea060`, and then the narrower page-specific + handlers and renderers beneath them. The launcher side is tighter now too: `0x004e4ee0` is the + shared open-or-focus ledger-page owner above this family. Outside sandbox it either re-enters + `shell_load_screen_select_page_subject_and_refresh` on the live runtime at `0x006d10a8` or + allocates that transient runtime, seeds it through `0x004e4b10`, and enters the visible modal + loop; inside sandbox it raises localized id `3899` `The ledger is not available in sandbox mode.` + instead. + The direct shell-command strip above that opener is now explicit too: `0x00440700..0x0044086e` + are just tiny `scenario-present -> open page` wrappers for pages `1`, `3`, `4`, `5`, `6`, + `0x0a`, `0x0c`, `0x0f`, `0x0e`, `2`, `7`, and `9` respectively. So the recovered launcher range + is no longer only “callers of `0x004e4ee0`” in the abstract; each of those small shell-command + stubs now just forwards one fixed page id into the shared opener. + instead. That narrows the remaining `LoadScreen.win` gap again: `TRAIN DETAIL` and + `STATION DETAIL` now read as dormant title-table entries unless some still-unrecovered nonstandard + selector reaches them. The live auto-load boundary is tighter now too: hook-driven + `shell_transition_mode(4, 0)` now completes old-mode teardown, reconstructs and republishes + `LoadScreen.win`, and returns cleanly, but the later post-transition service ticks still keep + `[0x006cec78] = 0`, `[shell_state+0x0c]` on the same `LoadScreen.win` singleton, and + `[LoadScreen.win+0x78] = 0` through at least counts `2..8`. So the next runtime edge is no + longer the old mode-`4` teardown or publish band; it is the `LoadScreen.win` message owner + `0x004e3a80` itself, because later service alone is not promoting the plain load screen into the + separate startup-runtime object path. One later runtime probe did not actually reach that edge: + the `0x004e3a80` hook installed, but the run never produced any ready-count, staging, + transition, post-transition, or load-screen-message lines, only ordinary shell node-vcall + traffic. So that result is now treated as a gate-or-cadence miss rather than as evidence against + the `LoadScreen.win` message path itself. The newer shell-state service trace tightens it again: + on a successful staged run the later service ticks do execute in `mode_id = 4`, but the + `0x004e3a80` message hook still stays silent while the state remains frozen in the plain + `LoadScreen.win` shape. So the next runtime boundary is now the shell-runtime prime call + `0x00538b60` beneath `shell_state_service_active_mode_frame` `0x00482160`, not the message owner + alone. The first direct `0x00538b60` probe run is not trustworthy yet, though: it stopped + immediately after the first shell-state service-entry line, before any ready-count or + runtime-prime entry logs. So that result is currently treated as probe validation work, not as a + real boundary move inside RT3. The static service branch is conditional too: `0x00482160` only + enters `0x00538b60` when `[shell_state+0xa0] == 0`, so silence from the runtime-prime hook does + not yet prove the shell stops before that call unless the service-entry logs also show the `+0xa0` + gate open. The newer run now closes that condition: `[shell_state+0xa0]` is `0`, and the + `0x00538b60` runtime-prime hook enters and returns cleanly. The newer run closes the next owner + too: `0x00520620` `shell_service_frame_cycle` also enters and returns cleanly on the same frozen + mode-`4` path, and the logged fields match its generic branch rather than a startup-promotion + lane (`[+0x1c] = 0`, `[+0x28] = 0`, `flag_56 = 0`, `[+0x58]` pulsed then cleared, and + `0x006cec78` stayed `0`). The static body under the same owner is tighter now too: `0x00538b60` + first re-enters `0x0054f6a0`, refreshes the primary timed-text lane from `[owner+0x1c]` through + `0x005386e0` when that deadline has expired, walks the registered shell-window list from tail + `[owner+0x04]` backward through `+0x54` while servicing each node through `0x0053fda0` and + `0x0051f1d0`, and only then conditionally presents the secondary and primary text lanes through + `0x005519f0`. So the next runtime boundary under the same shell-state service pass is now one + level deeper: the per-object service walker `0x0053fda0` beneath `0x00538b60`. The newer run + closes that owner too: it enters and returns cleanly while servicing the `LoadScreen.win` object + itself, with `field_1d = 1`, `field_5c = 1`, and a stable child list under `[obj+0x70/+0x74]`, + and its first child-service vcall target at slot `+0x18` stays `0x005595d0`. Since `0x006cec78` + still stays `0` through those clean object-service passes, the next runtime boundary is now the + child-service target `0x005595d0`, not the higher object walker. The newer child-service run + narrows that again: the first sixteen `0x005595d0` calls are stable child lanes under the same + `LoadScreen.win` parent, with `[child+0x86]` pointing back to the load-screen object, + `field_b0 = 0`, and a split where earlier children carry `flag_68 = 0x03` and return `4` while + later siblings carry `flag_68 = 0x00` and return `0`. The static body matches that read too: + `0x005595d0` is gated by `0x00558670` and then spends most of its work in draw or overlay + helpers `0x54f710`, `0x54f9f0`, `0x54fdd0`, `0x53de00`, and `0x552560`, so it now reads as + another presentation-side service lane rather than the missing startup-runtime promotion. The + widened allocator-window trace then reconciled the runtime with + the static mode-`4` branch one step further: the first transition-window allocation is `0x7c`, + which matches the static pre-construct `0x48302a -> 0x53b070` alloc exactly, and the later + `0x111/0x84/0x3a/0x25...` allocations all occur before `LoadScreen.win` construct returns, so + they now read as constructor-side child or control setup. That means the allocator probe did not + disprove the still-silent startup-runtime slice; it simply exhausted its log budget inside the + constructor before the post-construct block. The later reset-at-return run is now the decisive + one: after `LoadScreen.win` construct returns there are still no further allocator hits before + publish and transition return, which matches the corrected jump-table decode because mode `4` + does not own the `0x46c40 -> 0x4336d0 -> 0x438890` startup-runtime path. +### Editor Breadth + +The broader map-editor page owner is now bounded through + `map_editor_panel_select_active_section` `0x004ce070` and + `map_editor_panel_dispatch_active_section_message` `0x004cf700`, which switch among the grounded + setup pages, `Cities/Regions`, `Territories`, the `Players` and `Player Pool` setup slices, the + now-grounded `Building Density` page, the locomotives-available and industry-availability pages, + the economic and special-condition pages, the `Port/Warehouse Cargos` page, and the later report + pages. The mid-editor ownership is materially clearer now too: the chairman-slot editor is the + `Players` page, the available-chairman editor is the `Player Pool` page, and the former unnamed + dual tri-state page now lines up with localized page text `997` `Building Density` plus help text + `1017` and the direct field captions `1642` `Starting Building Density Level:` and `1644` + `Building Density Growth:`. Both controls are now bounded as stored ordinal bytes `0/1/2` rather + than loose labels: the first three-choice control is the map-wide starting-density selector, with + its default middle state `1` matching the documented `100%` baseline from `1643`; the second is + the paired overall growth selector whose effects later appear in the city-growth side of the + simulation. `map_editor_city_region_panel_construct` and + `map_editor_city_region_panel_handle_message` own the city-or-region editing lane with rename and + copy-industry-data flows. That copy side is tighter now too: the handler first enters + `0x00420e00`, which rebuilds the selected region's profile collection `[region+0x37f]`, clones + the source region's live label-weight entries when a source region is present, and otherwise + reseeds a fixed default weight set through repeated `0x004206b0` calls. The no-source companion + `0x00420ed0` now makes that split explicit: it rebuilds the same subcollection and then picks one + of two fixed default label-weight sets based on region class dword `[region+0x23e]`, using one + all-`0.2f` family for nonzero-class regions and one class-`0` family that starts with `0.3f` + before continuing with repeated `0.2f` entries. The lower mutator + `0x004206b0` then linearly scans the selected region subcollection by profile label, creates a + new profile only when the copied weight is positive, removes an existing profile when the copied + weight is non-positive, updates `[entry+0x1e]` otherwise, and refreshes the region's derived + availability-summary bytes `[region+0x2f6/+0x2fa/+0x2fe]` through `0x00420410`; `map_editor_territory_panel_construct` and + the adjacent no-source companion `0x00420ed0` is tighter too: it rebuilds the same collection + root `[region+0x37f]` but then seeds one of two fixed default profile-label sets directly through + repeated `0x004206b0` calls, splitting by region class dword `[region+0x23e]`. Nonzero-class + regions take one all-`0.2f` default set, while class-0 regions take a different set that starts + with one `0.3f` weight before continuing with repeated `0.2f` entries. That makes `0x420ed0` + the true class-split default-profile companion to the source-cloning helper at `0x420e00`, + rather than just more of the same editor copy path. Two neighboring collection queries are tight + enough now too. `0x00421d20` counts how many live regions have at least one profile row in + `[region+0x37f]` whose label matches the candidate-name string for one caller-supplied candidate + id; `0x00421e30` resolves the Nth such matching region. Both helpers reuse the same + `0x0041fac0` ordinal label-and-weight copy helper we just grounded, only increment once per + region, and skip nonzero-class regions whose companion count `[region+0x242]` is nonpositive. + Those two queries are what the editor summary side at `0x004cdd56/0x004cdeab` uses before it + formats per-region lists for one selected industry or profile name. The adjacent world-facing + query strip is bounded too: `0x00422010` scans the live region collection for class-0 regions + whose normalized coordinates fall inside one caller-supplied float rectangle, keeps the nearest + region id `[region+0x23a]` by squared XY distance through `0x0051db80`, and returns `0` when no + qualifying region is found; `0x004220b0` is the small wrapper above it that returns the matched + region name `[region+0x356]` or the fallback localized scratch string at `0x0062ba90`. + `map_editor_territory_panel_construct` and + `map_editor_territory_panel_handle_message` own the territory rename and border-remap lane; + `map_editor_locomotive_availability_panel_construct` plus + `map_editor_locomotive_availability_panel_handle_message` now bound the locomotive policy page + over `0x006ada84`; `map_editor_industry_availability_panel_construct` plus + `map_editor_industry_availability_panel_handle_message` do the same for the industry candidate + pool at `0x0062b268`; and `map_editor_port_warehouse_cargo_panel_construct` plus + `map_editor_port_warehouse_cargo_panel_handle_message` now ground the recipe-book page that edits + port or warehouse cargo policies through twelve per-book state blocks at + `[0x006cec78+0x0fe7+index*0x4e1]`. Each book now has a shared maximum annual production float at + `book+0x3ed` and five fixed cargo-line entries starting at `book+0x3f1` with stride `0x30`; each + line is bounded as a mode dword, annual amount, a supplied-cargo token at `+0x08`, and a + demanded-cargo token at `+0x1c`. The constructor and handler now make those fields materially + tighter too: the row pair shown in `Supply Only` and `Production Demand->Supply` is the `+0x08` + supplied-cargo selector, the row pair shown in `Demand Only` and `Production Demand->Supply` is + the `+0x1c` demanded-cargo selector, and the single amount field at `+0x04` is labeled `Annual + Demand:` only in mode `1` but `Annual Supply:` in modes `2/3`. The stronger new runtime-side + result is now a full chain rather than only the importer: + `scenario_state_rebuild_port_warehouse_cargo_recipe_runtime_tables` first imports those same five + lines into one repeated array of identical `0xbc`-byte runtime descriptors with no row-index + special casing, and the candidate-side rebuild pass at + `structure_candidate_collection_rebuild_runtime_records_from_scenario_state` `0x00412d70` then + projects those descriptors into the live structure collection at `0x0062ba8c` before + `structure_candidate_rebuild_cargo_membership_and_scaled_rate_tables` `0x00411ee0` rebuilds the + per-cargo runtime summary tables. The current local file-side result is now tighter too: the + grounded recipe-book root at `0x0fe7` is preserved byte-for-byte across the checked map/save + scenario pairs, so the loader can safely treat the twelve `0x4e1`-byte books as preserved + scenario payload rather than a drifting save-only band. A conservative summary probe now only + reports per-book head signatures, raw cap dwords at `+0x3ed`, and five raw line summaries rooted + at `+0x3f1` so the file-side structure stays aligned with this grounded ownership. The + player-facing line modes remain `Disabled`, `Demand Only`, `Supply Only`, and + `Production Demand->Supply`, and the fourth mode is tighter now too: current wording around + `1674`, `1675`, and `504` plus the downstream scaling path says it is the + production-line mode governed by the shared annual production cap, where the entered annual amount + stays on the supply side while the demanded side becomes the normalized input branch. The + candidate-side accumulator pass reinforces that split by applying the shared production cap only + to the supply-half runtime branch and bypassing that scaling on the normalized demand half. The + lower gameplay side is tighter now too: `structure_candidate_query_cargo_runtime_summary_channels` + `0x00412650` is the first grounded consumer beneath that rebuild chain, because it lazily rebuilds + four per-cargo summary banks and returns one direct-supply channel, one cap-normalized supply + channel, one demand or input channel, and one scaled production-output subrow channel for a + requested cargo id. The internal indexing is tighter now too: the direct-supply lane indexes from + `[desc+0x1c]`, the demand or input lane uses that same resolved cargo id in the no-subrow branch, + and the scaled production-output lane indexes each subordinate row directly from + `[desc+0x44+row*0x1c]`, with no post-resolution failure guard between the importer writes and the + summary-bank updates. So the strongest current read is narrower than a full cargo-id decode: if + the imported low-16 marker rows fail the exact matcher at `0x0041e9f0`, the resulting `0` ids + will still hit the first summary-bank bucket inside `0x00412650`, but the semantic meaning of + cargo id `0` itself remains ungrounded. The sibling helper + `structure_candidate_supports_or_references_cargo_id` + `0x004129d0` then uses those same banks plus the cached cargo-membership arrays to answer whether + a live candidate materially references a cargo at all. One compare step tighter, the raw line + lanes now split cleanly by scenario family while still preserving map->save identity inside each + checked pair. `Alternate USA.gmp` and `Autosave.gms` match at the raw line-content level: books + `0..4` keep mixed line areas, their `line02` slots carry the recurring nonzero mode words + `0x00110000`, `0x000b0000`, `0x000b0000`, `0x00130000`, and `0x00180000`, and the same `line02` + slots also carry one recurring supplied token `0x000040a0`; the neighboring `line00/line01` + slots carry the same recurring demanded token lanes such as `0x00010000`, `0x72470000`, + `0x6f430000`, `0x694c0000`, and `0x694d0000`. `Southern Pacific.gmp` and `p.gms` also match at + the raw line-content level, but the same rooted line slots stay zero in the checked pair. + `Spanish Mainline.gmp` and `g.gms` again match at the raw line-content level yet carry a distinct + nonzero pattern: books `0..4` keep mixed line areas, line-level supplied tokens include + `0x00170000`, `0x00150000`, `0x00004040`, and `0x00004000`, demanded tokens include + `0x00010000`, `0x68430000`, and `0x6c410000`, and the later `line02` mode words stabilize at + `0x00070000` then `0x00010000`. So the loader can now safely treat these raw line lanes as + preserved scenario payload with family-specific signatures, even though the exact cargo-id and + mode-enum semantics still need separate grounding. One inference is tighter now too: when those + demanded-token words are zero in the low 16 bits and printable in the high 16 bits, the byte + order reads as short two-letter stems such as `Gr`, `Co`, `Li`, `Mi`, `Ch`, and `Al`, which fit + the current scenario cargo-name families `Grain`, `Corn`, `Livestock`, `Milk`, `Cheese`, and + `Alcohol` from `RT3.lng`; the runtime probe now exposes those only as probable ASCII stems, not + as fully grounded cargo-id decodes. The supplied-token side is now bounded as a separate layout + family rather than forced into that same stem model: the `Alternate USA` family uses one stable + low-16 marker `0x000040a0` only in `book00..04.line02`, the `Southern Pacific` family leaves the + supplied lanes zero in the checked pair, and the `Spanish Mainline` family splits between two + high-16 numeric tokens `0x00170000` and `0x00150000` in `book00/01.line01` plus the later low-16 + markers `0x00004040`, `0x00004000`, and `0x00004040` in `book02..04.line02`. The probe now + exposes those conservatively as token-layout classes `high16-ascii-stem`, `high16-numeric`, and + `low16-marker`, without claiming that the non-stem numeric or marker families are decoded yet. + One more structural layer is stable enough to name conservatively: the checked nonzero recipe + rows repeatedly fall into four line-signature classes. `Alternate USA` books `0..4` all expose + one `demand-numeric-entry` at `line00` (`0x00010000`), one `demand-stem-entry` at `line01` + (`Gr/Co/Li/Mi` stems), and one `supply-marker-entry` at `line02` (nonzero mode plus + `0x000040a0`). `Spanish Mainline` books `2..4` expose that same three-line pattern with + `Ch/Al` stems and the `0x00004040/0x00004000` marker family, while books `0/1` only expose the + earlier `supply-numeric-entry` form at `line01`. So the loader can now distinguish recurring row + roles such as demand-stem versus supply-marker without pretending the marker payloads themselves + are decoded. The importer-side branch map is tighter now too because local `objdump` over + `0x00435630` shows that only nonzero mode dwords materialize into `0xbc` runtime descriptors: + mode `0` lines are skipped entirely, mode `1` enters the demand-only branch, mode `3` enters the + dual demand-plus-supply branch, and every other nonzero mode falls into the supply-side branch. + In the checked corpus that means the recurring `demand-numeric-entry` and `demand-stem-entry` + rows in `Alternate USA` and `Spanish Mainline` are preserved scenario-side line records but do + not become live runtime descriptors, while the later `supply-marker-entry` rows are the ones that + actually reach the runtime import path. The runtime probe now exposes that directly as + `imports_to_runtime_descriptor` plus one conservative `runtime_import_branch_kind`. + The raw token windows beneath those branch labels are tighter now too. The checked mode-zero + demand rows preserve string-bearing windows at `line+0x1c`, and the current probe shows those + conservatively as prefixed ASCII previews such as `..Grain`, `..Corn`, `..Livestock`, and + `..Milk`; local `objdump` over `0x0041e9f0` then shows the importer feeding the corresponding + token buffer into an exact cargo-name matcher built over the live cargo collection at + `0x0062ba8c`. By contrast, the imported `supply-marker-entry` rows feed nonprintable windows such + as `.@...` from `line+0x08` through that same matcher, and the resolver path currently shows no + special-case decoding for those marker forms. So the strongest static read is now: the stem-like + demand rows preserve cargo-name text but are skipped because their mode is zero, while the + nonzero imported marker rows are the live descriptor inputs yet likely fail exact cargo-name + resolution unless another upstream transform exists. + The wrapper layer above that query no longer looks like a hiding place for special treatment + either. Local `objdump` now shows `0x00412960` simply summing the two supply-side floats returned + by `0x00412650`, while `0x004129a0` returns the single scaled production-output lane directly; + neither wrapper checks for cargo id `0` after the query returns. The broader world-side + accumulator at `0x0041e7be` is tighter in the same way: it calls `0x00412650`, requires all four + returned channels to be positive before continuing, and only then scales those four channel + values by one linked-instance count from `0x00413940` into caller-owned accumulators. So the + current strongest read remains structural rather than semantic: unresolved marker rows can still + propagate through the first bank bucket, but the first place that meaning matters is a normal + positivity-gated cargo-channel consumer, not a dedicated null-cargo branch. + The caller side is narrower than before too. The steady-state site bitset owner + `placed_structure_rebuild_candidate_cargo_service_bitsets` `0x0042c690` starts its inner cargo + loop at id `1` and only walks upward through the current live cargo count, so it never + intentionally queries cargo id `0`. The broader placed-structure sweep around `0x00452e60` + tightens the same boundary from above: when the requested cargo id is nonzero it resolves the + backing candidate and enters `structure_candidate_supports_or_references_cargo_id`, but when the + requested id is exactly `0` it skips that cargo-reference helper entirely and falls through to a + different linked-site or station-or-transit gate. Current local `objdump` now shows that bypass + first requiring one subtype latch through the placed-structure vtable `+0x70`, then resolving the + linked site id at `[site+0x2a8]` through the placed-structure collection `0x006cec20`, and then + forwarding that linked peer into the narrower predicate at `0x0047fd50`. That narrower helper is + tighter than before too: it resolves the linked peer's backing candidate through the peer site id + at `[peer+0x04]`, reads candidate class byte `[candidate+0x8c]`, and returns true only for the + first three class values `0/1/2` while rejecting `3/4` and anything above `4`. So current local + callers treat cargo id `0` as a nonstandard request bound to one linked-site reachability or + classification side path, not one ordinary cargo lane they routinely probe. + The vtable-`+0x70` latch itself is bounded a bit better now too. It still lacks a direct field + decode, but every local callsite we checked around `0x0040d230`, `0x0040dba0`, `0x0040dbf0`, and + `0x0040f670` uses that slot only as the precondition for touching `[site+0x2a8]` and the + neighboring linked-site helpers `0x0047dda0`, `0x0047fd50`, and `0x004138b0`. That makes the + safest current read a linked-site-bearing or linked-site-capable latch, strongly aligned with the + subtype-`1` construction lane that is the only grounded writer of `[site+0x2a8]`, rather than a + broad cargo or route-style predicate. + The neighboring maintenance pair tightens that linked-site read further. Local `objdump` now + shows `0x0040dba0` and `0x0040dbf0` as complementary tiny helpers that each require the same + vtable-`+0x70` latch, resolve optional linked peer id `[site+0x2a8]` through `0x006cec20`, + forward that linked peer (or null) into `0x0047dda0`, and then mirror opposite values into local + byte `[site+0x42]` (`0` for `0x0040dba0`, `1` for `0x0040dbf0`). The route-entry side beneath + them is tighter too: `0x0047dda0` reads route-entry anchor id `[peer+0x08]`, resolves that anchor + through `0x006cfca8`, and only dispatches one of two route-entry vtable calls when + `0x0048a090(1)` reports that all three anchor-slot dwords `[entry+0x206]`, `[entry+0x20a]`, and + `[entry+0x20e]` are still `-1`. So the strongest current read is no longer just "linked-site + capable" in the abstract: this latch consistently fronts the local linked-peer class gate + `0x0047fd50`, the paired `[site+0x42]` route-entry state toggles, and the later linked-peer + collection sweep `0x004138b0`, which keeps the `cargo id 0` bypass path firmly on the + linked-site route-anchor or classification side rather than on an ordinary cargo lane. + One smaller ownership boundary is tighter too: byte `[site+0x42]` is not private scratch owned + only by that pair. Local `objdump` shows tiny direct setters at `0x0040cbc0` and `0x0040cbd0` + plus a raw getter at `0x0040cbf0`, so the `0x0040dba0/0x0040dbf0` pair is writing one shared + placed-structure state byte rather than inventing a route-entry-only scratch lane. One caution + is tighter now too: there are later mode-gated reads at other addresses that also touch a + `+0x42` byte on their own object layouts, but current local evidence does not yet prove those are + the same placed-structure owner family, so the safest current note keeps only the immediate + `0x0040cbc0/0x0040cbd0/0x0040cbf0/0x0040dba0/0x0040dbf0` cluster grounded together. + The vtable side sharpens that split too. A local `.rdata` scan shows `0x0040dba0` and + `0x0040dbf0` each appearing exactly once, together with `0x0040cbf0`, in one method table rooted + at `0x005c8c50`; the constructor chain is tighter now too, because `0x0040c950` installs that + same table as one concrete placed-structure specialization above the common base table + `0x005cb4c0`, while `0x0040c970` tears the same specialization back down to the base before the + temporary object is freed. By contrast the raw set or get trio + `0x0040cbc0/0x0040cbd0/0x0040cbf0` also appears in several sibling tables such as `0x005c9750` + and `0x005dd1f0`. So the strongest current structural read is that byte `[site+0x42]` belongs + to one broader placed-structure virtual interface, while the linked-peer route-entry toggles are + one specialization-specific override pair inside that family rather than generic setters used by + every sibling. + One negative boundary is tighter now too: the + raw token words in this recipe block do not look like the already grounded shell-side + `AnyCargo/AnyFreight/AnyExpress` selector-table ids from `0x00621e04/0x00621e10`, so the current + best read is that these on-disk line tokens are not just copied UI selector ordinals or the same + small express-side id family in another wrapper. One broader collection pass also now ties + the editor rule side back into runtime filtering: + `structure_candidate_collection_refresh_cargo_economy_filter_flags` `0x0041eac0` rebuilds + per-candidate flag `[candidate+0x56]` across the live structure collection, and current grounded + callers show it rerunning directly off the runtime cargo-economy latch at `[0x006cec74+0x25f]`, + which aligns this lane with the editor's `Disable Cargo Economy` special condition rather than + leaving it as a purely editor-owned recipe page. The first common live gate beneath that filter is + now bounded too: `structure_candidate_is_enabled_for_current_year` `0x0041e220` is the shared + year-and-filter check used by the collection refresh and later candidate-selection branches, while + `structure_candidate_rebuild_local_service_metrics` `0x0041e2b0` is a setup-side local service + scorer that already consumes the same enabled candidate records through world-grid sampling. One + steady-state world-side consumer is now grounded as well: + `placed_structure_rebuild_candidate_cargo_service_bitsets` `0x0042c690` walks linked placed + structures, filters live category-`2` candidates through + `structure_candidate_is_enabled_for_current_year`, and compacts the direct and scaled supply-side + channels from `0x00412960` and `0x004129a0` into per-cargo bitsets on the placed-structure record. + The next site-side owner layer is tighter now too: + `placed_structure_refresh_linked_candidate_flag4` `0x0042c8f0` refreshes the sibling state bit at + `[site+0x0e6]`, `placed_structure_refresh_candidate_service_state` `0x0042cdf0` ties that flag + refresh to the cargo-service bitset rebuild, + `placed_structure_rebuild_candidate_local_service_tables` `0x0042ce00` then performs the heavier + per-site candidate score rebuild over the aligned float and word tables at `[site+0x107]`, + `[site+0x02]`, and `[site+0x6c]`, and `placed_structure_refresh_local_service_score_bundle` + `0x0042d580` is now the local wrapper that chains that rebuild into the neighboring post-passes + before the world-grid owner continues. Those post-passes are tighter too: + `placed_structure_apply_route_linked_service_caps` `0x0042cc50` is the first route-backed cap pass + over the rebuilt local tables, + `placed_structure_redistribute_local_service_pressure_from_neighbors` `0x0042c1b0` is the + neighboring-site redistribution pass, and `placed_structure_clamp_candidate_service_age_table` + `0x0042cb30` is the final recent-service clamp over the primary per-candidate word table. Above + that refresh lane, `placed_structure_query_candidate_local_service_metrics` `0x0047e240` is the + first higher-level query, `placed_structure_count_candidates_with_local_service_metrics` + `0x0047e330` counts how many candidates currently produce that query, + `placed_structure_get_nth_candidate_id_with_local_service_metrics` `0x0047e620` is the ordinal + selector over that same visible candidate family, + `placed_structure_query_cached_express_service_class_score` `0x0047e390` caches one parallel class + score for the express family now strongly aligned with `Passengers`, `Mail`, and `Troops`, + `placed_structure_refresh_candidate_local_service_comparison_cache_against_peer_site` + `0x0047eb90` rebuilds one peer-site comparison cache over the same local-service inputs, and + `placed_structure_select_best_candidate_id_by_local_service_score` `0x0047f910` is the best-hit + selector above the direct and directional local-service query pair. Those site-side scores now + have grounded shell read-side consumers too: + `shell_station_detail_format_freight_and_express_summary` `0x00506be0` formats the visible + `Freight: %1` and `Express: %1` lines in `StationDetail.win`, and the same station-detail family + now has a deeper candidate-service lane: + `shell_station_detail_set_active_candidate_service_preview` `0x00504ae0` stores the active + `(station id, candidate id)` pair for the world-side preview scan, + `shell_station_detail_clear_active_candidate_service_preview` `0x00504a90` tears that pair back + down, `shell_station_detail_update_candidate_service_entry` `0x00504ba0` is the shell-side entry + updater above that preview pair, `shell_station_detail_format_candidate_local_service_summary` + `0x00504bea` uses `placed_structure_query_candidate_local_service_metrics` together with localized + ids `681`, `682`, and `2813` to build the visible candidate service text, + `shell_station_detail_build_to_from_haul_summary_widget` `0x00505150` now grounds the paired `To` + and `From` hauled-traffic strip widgets, `shell_station_detail_present_to_from_haul_stats_popup` + `0x00504770` owns their click-through annual and lifetime `hauled TO/FROM this station` popup, + `shell_station_detail_refresh_nearby_structure_jump_rows` `0x00505470` owns the five-row + nearby-structure jump lane, and `shell_station_detail_refresh_candidate_service_rows` `0x00505760` + is now the larger row-list owner that enumerates active candidate-service entries and wires + `shell_station_detail_update_candidate_service_entry` into the per-row click path. The broader + owner above those lanes is tighter now too: `shell_station_detail_window_refresh_controls` + `0x00506610` is the real `StationDetail.win` refresh pass, validating the current station from the + detail manager, publishing the upper summary lane, splitting the `0xb3b7/0xb3b8` action strip by + scenario latch `[0x006cec74+0x1db]`, routing that scenario branch through + `shell_station_detail_present_scenario_station_connection_triplet_popup` `0x00504590`, routing + class `3/4` sites into the alternate branch + `shell_station_detail_refresh_class_3_or_4_train_service_matrix` `0x00504ec0`, and otherwise rebuilding the nearby-structure lane, the paired `To/From` widgets, + and the candidate-service rows together. The compact siblings under that pass are tighter now too: + `shell_station_detail_clear_dynamic_rows_and_haul_widgets_if_dirty` `0x005042c0` is the dirty + clear owner over the dynamic row bands and the paired haul widgets, `shell_station_detail_has_valid_selected_station` + `0x00504370` is the bare selected-station validity probe, `shell_station_detail_selected_station_belongs_to_selected_company` + `0x00504390` is the selected-company ownership gate, and + `shell_station_detail_present_selected_station_not_controlled_notice` `0x005043f0` is the + localized not-controlled popup beneath the same action family, + `shell_station_detail_present_scenario_station_connection_triplet_popup` `0x00504590` is the + scenario-latched station-to-station triplet popup that formats three per-destination scalar lanes + with `%5.2f` or `N/C`, and + `shell_station_detail_refresh_class_3_or_4_train_service_matrix` `0x00504ec0` is the alternate + class-`3/4` branch that rebuilds the `Trains Serviced` / `Trains Maintained` matrix before + reusing the shared haul-popup callback wiring, + `shell_station_detail_refresh_class_gated_action_controls_0xb3bb_to_0xb3bf` `0x005044b0` + refreshes the lower class-gated action strip rather than the older guessed `0xb3f8` lane. + `shell_station_list_format_freight_and_express_availability_summary` `0x00506e50` feeds the + station-list summary `%1 has %2 freight loads and %3 express loads available for hauling...`, and + the paired modifier helper `shell_station_list_handle_center_or_rename_action` `0x00506d50` owns + the visible Shift-center and Ctrl-rename row actions. The list owner itself is tighter now too: + `shell_station_list_window_refresh_rows_selection_and_status` `0x00506f30` is the real + `StationList.win` row and status refresh pass, clearing and repopulating controls `0x61a9` and + `0x61aa`, wiring the visible summary and modifier callbacks, mirroring the shared selected-station + latch at `[0x006cec78+0x4cba]` when it still belongs to the current company, and updating the two + status labels `0x61af` and `0x61b0`. The row-side callout lane is tighter too: + `shell_station_list_row_callback_publish_station_callout_card` `0x00506ac0` is the actual + row callback beneath both list controls, resolving the selected station, deriving one category + header through `0x0053de00` and `0x00552560`, and then publishing the station-name plus freight + and express callout card through repeated `shell_publish_text_callout_presentation` calls. The + side-selector branch is tighter too: + `shell_station_list_window_handle_message` no longer just re-enters the raw `StationPick.win` + constructor. It flips the active side bit at `0x006d1710` and then re-enters the modal helper + `shell_station_pick_window_open_modal_and_return_selected_station_id` `0x005078c0`, which + allocates one helper window, runs `shell_station_pick_window_construct` `0x00507620`, brackets the + modal show path, and returns the staged selected station id from `0x00622ae8`. Inside that helper + family, `shell_station_pick_window_rewrite_list_and_scroll_messages_to_primary_select_event` + `0x005075c0` now bounds the small message-normalization strip beneath controls `0x80e8..0x80ea`. + The Shift-center side is tighter now too: + the shared helper `0x00433900` takes one object pointer plus one small mode, derives one + mode-specific `(distance,height)` preset from the target's virtual classification, and then + re-enters `0x0043c9a0` to center the live world view on that object. The report side is clearer + as well: + `0x004d3060` is the dedicated `Stats - Trees` constructor over `map_editor_tree_stats_report`, + `0x004d3080` is the actual `General Validation` constructor over + `map_editor_general_validation_report`, and the same page table also now grounds `Stats - Cargo`, + `Stats - City/Region`, `Stats - City Count`, `Event Variable Values`, and the neighboring + event-validation page. The remaining open editor edge is therefore mostly the deeper gameplay + meaning of those site-side service scores and flag bits, not page ownership. + +### Station-detail overlay + +The shell-side candidate preview pair now has a grounded world consumer + too. `world_render_station_candidate_service_map_overlay` at `0x0043f640` reads the active + `(station id, candidate id)` pair from `0x005ee4fc` and `0x005ee500`, scans the placed-structure + collection, and then splits the legend by candidate mode. When the active candidate carries a + nonzero route-style byte at `[candidate+0x46]`, the overlay uses the heavier helper + `placed_structure_query_candidate_directional_route_overlay_summary` at `0x0047e690` in both + directions between the preview station and each scanned site and formats the resulting directional + rows as `3874` `Coming To %1` and `3875` `Going From %1`. When that byte is zero, the same overlay + falls back to the direct local-service path through + `placed_structure_query_candidate_local_service_metrics` and formats the two legend rows instead + as `3876` `Current Supply @ < %1` and `3877` `Current Demand @ > %1`. Empty directional lanes + collapse to `3878` `--None--`, and one title lane falls back to literal `All`. Current disassembly + no longer supports treating `3872` `Already Connected by Another Company` or `3873` `Not + Connected` as direct overlay-body emits. +#### Corrected boundary + +The neighboring connection-state note pair now appears + to live in a city connection-bonus label formatter, not in `0x0043f640`. That formatter is now + bounded as `city_site_format_connection_bonus_status_label` at `0x004207d0`: it directly chooses + localized ids `3868` through `3873` after consulting the reusable city-peer scan + `city_connection_bonus_exists_matching_peer_site` at `0x00420030`. Separately, `3879` `Out of + Sync` is grounded under the multiplayer preview dataset path instead: + `multiplayer_preview_dataset_service_launch_state_and_warn_out_of_sync` at `0x0046b780` checks + global `0x006cd91c`, raises the `Out of Sync` shell status through `0x5386e0`, and then continues + through the wider multiplayer preview launch-state service. So the station-detail overlay + currently owns only the `Coming To`, `Going From`, `Current Supply`, `Current Demand`, `--None--`, + and `All` legend lanes. +#### Ownership side + +One reusable site helper is grounded now too. + `placed_structure_query_linked_company_id` at `0x0047efe0` resolves the current placed structure's + linked instance through `0x0062b26c` and returns its company id from `[instance+0x276]`; the + adjacent city bonus formatter at `0x004207d0` compares that id against the active company selector + before choosing whether a scanned site should carry `3871` `Connected By Another Company` or + `3872` `Already Connected by Another Company`. The larger caller boundary is no longer open + either: the first bounded announcement owner above this formatter family is now + `company_evaluate_and_publish_city_connection_bonus_news` at `0x00406050`, which re-enters the + peer-route candidate builder at `0x004046a0` and later publishes one of the localized + city-connection bonus news strings `2888`, `2890`, or `2921` through the shell news path. +#### Peer-selector side + +The city bonus formatter no longer depends only on + boolean peer existence. The companion helper + `city_connection_bonus_select_first_matching_peer_site` at `0x00420280` is now grounded as the + first-match selector paired with `city_connection_bonus_exists_matching_peer_site`: it walks the + same city-peer candidate set, applies the same site-class table plus the narrower + station-or-transit and linked-instance class-byte flags, and returns one representative matching + peer site id instead of a boolean. `city_site_format_connection_bonus_status_label` reuses that + selector after the note checks so it can recover one linked company context from the selected + peer. The remaining open edge here is therefore above this formatter family, not inside the + peer-scan pair itself. +#### Caller side + +The reusable bridge between the status formatter and the + company news lane is now bounded too. `city_connection_bonus_build_peer_route_candidate` at + `0x004046a0` reuses `city_connection_bonus_select_first_matching_peer_site` with both selector + flags forced on, samples the selected peer's derived coordinates through `0x0047df30` and + `0x0047df50`, and then either tries the shared heavy builder + `city_connection_try_build_route_with_optional_direct_site_placement` `0x00402cb0` or falls + back to the smaller wrapper `city_connection_bonus_try_compact_route_builder_from_region_entry` + `0x00404640` before handing the result back to the company-side announcement sweep at + `0x00406050`. The score side of that announcement lane is tighter now as well: + `city_compute_connection_bonus_candidate_weight` at `0x004010f0` provides the per-city opportunity + weight, `company_query_min_linked_site_distance_to_xy` at `0x00405920` provides the nearest + linked-site distance term, `company_count_linked_transit_sites` at `0x00426590` provides one of + the company-side caps, `company_compute_connection_bonus_value_ladder` at `0x00425320` supplies + the bounded company-side value scalar, and + `company_compute_prime_rate_from_issue39_scenario_baseline` at `0x00424580` now bounds the + shared prime-rate-side helper that this lane reuses beside the raw issue-`0x39` total, + `scenario_state_sum_issue_opinion_terms_raw` at `0x00436710` now bounds the raw additive + issue-total helper beneath that term, and `company_connection_bonus_lane_is_unlocked` at + `0x00427590` is the small boolean gate above the ladder. Wider governance and CompanyDetail xrefs + now tighten slot `0x2b` into the rolling net-profits lane reused by annual finance checks and a + per-share/history formatter, while the report-history descriptor table now aligns raw slot `0x09` + with the Income Statement fuel-cost lane surfaced by tooltip `1309`. The wider result now reads + more like recent net profits minus recent fuel burden than a governance-pressure term. That now + also sharpens the annual finance lane at `0x00401c50`: the first bankruptcy branch reads as + sustained cash-and-debt stress over recent profits and fuel burden, the later fallback branch as + a deeper `-300000` cash / three bad years cleanup trigger, and the later stock-issue branch reads + as a price-to-book-versus-coupon approval ladder rather than a generic support vote. The tail is + cleaner now too: it compares total retired versus newly issued principal to choose the `2882..2886` + debt headline family, then publishes `2887` separately from the accumulated repurchased-share + count. The sibling news owner above the same + city-pair route family is bounded now too: + `simulation_try_select_and_publish_company_start_or_city_connection_news` `0x00404ce0` + filters and scores candidate city entries, re-enters the same shared heavy builder through + `city_connection_try_build_route_between_region_entry_pair` `0x00404c60` for the dense pair + sweep and the final retry, and then publishes `2889` `%1 has started a new company - the %2` + or `2890` `%1 has connected %2 to %3.` through the shell news path. The remaining open edge on + this branch is therefore narrower now: it is mostly whether `0x39` should be read as the + narrower city-connection public-opinion lane or as part of a broader management-attitude family, + not the ownership of the connection-bonus formatter, peer-route candidate path, or company news + gate. +#### Route-list side + +The neighboring helper + `placed_structure_append_unique_route_entry` at `0x0047f010` is now grounded as the + append-if-missing builder for the six-byte route-entry list rooted at `[site+0x462]` and + `[site+0x466]`. That matters here because the directional overlay query at `0x0047e690` consumes + the same list, so the remaining uncertainty is no longer list ownership. It is down to the exact + semantics of each entry's `u32` payload. +#### Route-entry and Cache Side + +The adjacent helper strip is tighter now too. + `placed_structure_service_candidate_local_service_comparison_cache_decay_and_row_propagation` + `0x0047df70` is the recurring age-and-propagation service pass over the paired comparison-cache + float tables `[site+0x3e]` and `[site+0x112]` with age stamps at `[site+0x1e6]`; it zeroes stale + entries older than `0x1d8800`, decays younger ones by the fixed `0x005ce900/0x005ce8f8` scales, + and then propagates stronger marked row values back through the three five-float row bands rooted + at `[site+0x24/+0x28/+0x2c]`. The wrapper + `placed_structure_query_candidate_route_or_local_service_comparison_score` `0x0047e9a0` is now + bounded too: it delegates to `placed_structure_query_candidate_directional_route_overlay_summary` + `0x0047e690` when the requested candidate carries a grouped routing class, otherwise it uses the + simpler local `[cell+0x103]` lane and the current sample list at `[site+0x34/+0x38]` before + writing back into the same comparison-cache bands. The route-entry strip beneath the linked-peer + family is no longer open either: `placed_structure_resolve_route_entry_anchor_record` + `0x0047f310` is the direct resolver over `[site+0x08]`, and + `placed_structure_route_anchor_matches_or_reaches_route_entry_id` `0x0047f250` is the boolean + gate above it, first checking a direct match against `[site+0x08]` and then re-entering + `0x0048e050(mode 2, fallback -1)` on the resolved route-entry record. The route-link companion + `route_link_route_entry_reaches_peer_site_route_group` `0x0047f2d0` is tighter now too: it reads + the peer site's route-entry anchor from `[peer+0x08]`, resolves the current link's own anchor, + and re-enters `0x0048e3c0` to test whether the two anchors belong to the same reachable + route-side family. One smaller linked-peer-side setter is grounded as well: + `placed_structure_set_overlay_mark_byte_and_refresh_linked_peer_overlay_if_changed` `0x0047f290` + updates byte `[site+0x5bc]` and then re-enters + `placed_structure_refresh_linked_peer_overlay_when_linked_peer_flagged` `0x0040d2d0` when the + byte changes. +#### Terrain-class Side + +The nearby linked-instance raster wrappers are no + longer anonymous. `world_resolve_secondary_raster_class_record_at_float_xy` `0x0044e270` is the + world-side float-XY lookup over `[world+0x2131]` plus class table `0x006cfc9c`; + `placed_structure_query_linked_instance_secondary_raster_class_id` `0x0047f170` is the raw + linked-instance wrapper that returns the shifted class id directly; and the paired + record-returning wrappers `placed_structure_resolve_linked_instance_secondary_raster_class_record` + `0x0047f0e0` and + `placed_structure_resolve_linked_instance_secondary_raster_class_record_via_world_query` + `0x0047f1f0` now bound the two record-returning lanes used by the later world-side and + linked-peer filters. That means the remaining uncertainty in this neighborhood is no longer the + route-entry or terrain-class helper ownership; it is the broader user-facing meaning of the later + callers that consume those gates. diff --git a/docs/control-loop-atlas/map-and-scenario-content-load.md b/docs/control-loop-atlas/map-and-scenario-content-load.md new file mode 100644 index 0000000..fad7fd2 --- /dev/null +++ b/docs/control-loop-atlas/map-and-scenario-content-load.md @@ -0,0 +1,450 @@ +## Map and Scenario Content Load + +- Roots: `shell_map_file_entry_coordinator` at `0x00445ac0`, the larger active-mode profile owner + `shell_active_mode_run_profile_startup_and_load_dispatch` at `0x00438890`, the shell-mode + switcher `shell_transition_mode` at `0x00482ec0`, the first grounded world-entry branch + `world_entry_transition_and_runtime_bringup` at `0x00443a50`, + `shell_map_file_world_bundle_coordinator` at `0x00445de0`, reference-database setup via + `map_bundle_open_reference_databases` at `0x00444dd0`, and narrower loaders such as + `map_load_geographic_label_database` and `map_load_city_database`. +- Trigger/Cadence: shell tutorial launch, editor or detail-panel file actions through `fileopt.win`, + map-scenario open paths, and scenario-text export batch commands. +- Key Dispatchers: `shell_map_file_entry_coordinator`, + `shell_active_mode_run_profile_startup_and_load_dispatch`, `shell_transition_mode`, + `world_entry_transition_and_runtime_bringup`, `world_runtime_release_global_services`, `shell_map_file_world_bundle_coordinator`, + `map_bundle_open_reference_databases`, `map_load_geographic_label_database`, + `map_load_city_database`, `scenario_text_export_build_language_file`, + `scenario_text_export_report_language_file`, `scenario_text_export_batch_process_maps`. +- State Anchors: shell-side file staging buffers at `0x0062bee0` and `0x0062bec4`, shell and mode + globals at `0x006cec74` and `0x006cec78`, world object root `0x0062c120`, map bundle state + allocated through `0x00530c80`, and geography tables rooted at `0x0062b2fc` and `0x0062b268`. +- Subsystem Handoffs: the shared `fileopt.win` dialog rooted at `0x004dc670` now looks like the + shell-side selector above the two broad file coordinators. Its message handler sets `0x006d07f8` + for the load or restore side or `0x006d07ec` for the save or package side before the detail-panel + transition manager routes into `shell_map_file_entry_coordinator` or + `shell_map_file_world_bundle_coordinator`. The former unresolved third flag at `0x006d07f0` is now + accounted for too: it escapes into the standalone `SettingsWindow.win` path through + `shell_open_settings_window` rather than another map or save verb. The broad coordinators now hand + their interactive work through the shared `filerqst.win` helper at `0x004dd010`, and that helper + gives the extension split a firmer shape. The paired editor-map path is now grounded as `.gmp` + through load mode `4` and save mode `3`. The remaining non-editor families are no longer anonymous + either: `.gmc` is the campaign-scenario branch, backed both by the campaign-screen resignation + prompt on `0x006cec7c+0xc5` and by the numbered `%s%02d.gmc` save helper at `0x00517c70`; `.gmx` + is the sandbox branch, backed by the shell-side `The briefing is not available in sandbox games.` + restriction on `0x006cec7c+0x82`; and the default `.gms` branch is therefore the standalone + scenario family. When a live runtime world is already active the same helper bypasses those + non-runtime extensions and forces the `.smp` runtime-state branch instead. The auxiliary save-side + mode `11` is tighter now too: it still maps to `.gmt`, but instead of looking like another + gameplay save family it conditionally diverts into the same `.gmt` preview-surface pipeline owned + by the Multiplayer preview dataset object at `0x006cd8d8`, and only falls back to the normal + reference-bundle path when that dataset object is absent. The shell-side mode owner above those + file coordinators is clearer now too. `shell_transition_mode` no longer reads like a generic mode + switch: its ABI is now grounded as a `thiscall` with two stack arguments because the body reads + the requested mode from `[esp+0x0c]` and returns with `ret 8`. The grounded world-entry + load-screen call shape is `(4, 0)`, not a one-arg mode switch. The second stack argument is now + tighter too: current local evidence reads it as an old-active-mode teardown flag, because the + `0x482fc6..0x482fff` branch only runs when it is nonzero and then releases the prior active-mode + world through `0x434300`, `0x433730`, and the common free path before clearing `0x006cec78`. + The later world-entry reactivation branch correspondingly uses `(1, esi)` rather than `(1, 0)`. + The current live hook probes now push the remaining auto-load gap much later too: on the + hook-driven path `shell_transition_mode(4, 0)` returns cleanly, and the full old-mode teardown + stack under `0x5389c0` now returns too, including `0x5400c0`, the `0x53fe00 -> 0x53f860` + remove-node sweep over `[object+0x74]`, and the nearby mode-`2` teardown helper `0x00502720`. + The same live run now also reaches and returns from `shell_load_screen_window_construct` + `0x004ea620` and the immediate shell publish through `0x00538e50`. + Its constructor jump table is tighter now too: mode `1` is not the direct `Game.win` + constructor, but the startup-dispatch arm rooted at `0x483012`; mode `2` enters `Setup.win`, + mode `3` enters `Video.win`, mode `4` enters the plain `LoadScreen.win` branch at `0x4832e5`, + mode `5` enters `Multiplayer.win`, mode `6` enters `Credits.win`, and mode `7` enters + `Campaign.win`. The important static correction is that the startup-runtime slice + `0x004ea710 -> 0x0053b070(0x46c40) -> 0x004336d0 -> 0x00438890` belongs to mode `1`, not mode + `4`. Mode `4` only constructs and publishes the `LoadScreen.win` object through `0x004ea620` + and `0x00538e50`. The older hook-driven `(4, 0)` path therefore was not mysteriously skipping + the startup-runtime object; it was entering the wrong jump-table arm for that work. The caller + split above that owner is tighter now too: + `world_entry_transition_and_runtime_bringup` reaches the same owner at `0x443b57` with `(0, 0)` + after dismissing the current shell detail panel and servicing `0x4834e0(0, 0)`, while the + saved-runtime path at `0x446d7f` does the same before immediately building the `.smp` bundle + payloads through `0x530c80/0x531150/0x531360`. That makes the `LoadScreen.win` startup lane the + only currently grounded caller that enters `0x438890` with `(1, 0)` instead of `(0, 0)`. The + remaining runtime uncertainty is narrower now too: the plain-run logs still show the plain + `LoadScreen.win` state under `(4, 0)`, and the corrected allocator-window run now reinforces the + same read because the post-construct allocator stream stays empty instead of showing the expected + `0x46c40` startup-runtime allocation. The first lower allocator probe on `0x005a125d` was not + trustworthy because that shared cdecl body sits behind the thunk and the initial hook used the + wrong entry shape, and the first direct thunk hook was also not trustworthy because a copied + relative-`jmp` thunk cannot be replayed through an ordinary trampoline. But the later corrected + thunk run plus the jump-table decode now agree: the next meaningful hook-driven test is mode + `1`, not mode `4`. + `mode_id = 2`, and it never advanced into `ready gate passed`, staging, or transition. So that + run did not actually exercise the `0x0053b070 -> 0x004336d0 -> 0x00438890` subchain at all. + The next runtime pass now lowers the ready-poll defaults to `1` and `0` and adds an explicit + ready-count log so the mode-`4` startup lane either stages immediately or shows exactly how far + the gate gets. That adjustment worked on the next run: the hook now stages and completes the + `shell_transition_mode` path again, with `LoadScreen.win` construction and publish returning + cleanly. But the post-publish startup subchain is still unresolved: there is still no trusted + `0x46c40` allocator hit, no direct `0x004336d0` entry, and no direct `0x00438890` entry. So + the next clean runtime boundary is the tiny `LoadScreen.win` scalar setter at `0x004ea710`, + which sits immediately before the `0x0053b070` allocation in the static mode-`4` branch. The + immediate next runtime check is even more concrete than the helper hook, though: inspect the + state that `0x004ea710` should leave behind. The hook now logs the post-transition + `LoadScreen.win` singleton, its field `[+0x78]`, `0x006cec78`, the shell state's `[+0x0c]` + active-mode object field, and the startup selector. If `0x004ea710` really ran on the mode-`4` + branch, `[LoadScreen.win+0x78]` should no longer be zero after `shell_transition_mode` returns. + The latest run answered that directly: after transition return, `field_active_mode_object` is + still the `LoadScreen.win` singleton, `0x006cec78` is still null, `[LoadScreen.win+0x78]` is + still zero, and the startup selector is still `3`. So the current best read is that RT3 is + still parked in the plain `LoadScreen.win` state at transition return rather than having entered + the separate runtime-object path yet. That shifts the best next runtime boundary from “deeper + inside `shell_transition_mode`” to “what later active-mode service tick, if any, promotes the + load-screen object into the startup-dispatch path.” The next run now logs the first few + shell-state service ticks after auto-load is attempted with that same state tuple + (`0x006cec78`, `[shell_state+0x0c]`, `0x006d10b0`, `[LoadScreen.win+0x78]`, selector), so the + next question is very narrow: does one later service tick finally promote the plain + `LoadScreen.win` state into the startup-runtime object path, or does it stay frozen as-is? The + internal selector split in `0x438890` is tighter now too: `[0x006cec7c+0x01]` is a separate + seven-way startup selector, not the shell mode id. Values `1` and `7` load `Tutorial_2.gmp` and + `Tutorial_1.gmp`, values `3/5/6` collapse into the same profile-seeded file-load lane through + `0x445ac0([0x006cec7c]+0x11, 4, &out_success)`, value `2` is a world-root initialization lane + that allocates `0x0062c120` and then forces selector `3`, and value `4` is the setup-side world + reset or regeneration lane that rebuilds `0x0062c120` from `0x006d14cc/0x006d14d0` before later + world setup continues. The write side is tighter now too: `Campaign.win` writes selector `6`, + `Multiplayer.win` writes selector `3` on one pending-status path, and the larger `Setup.win` + dispatcher writes selectors `2`, `3`, `4`, and `5` on its validated launch branches. That makes + the file-load subfamily read less like one generic save-open branch and more like a shared + profile-file lane reused by setup, multiplayer, and campaign owners. The world-entry owner + boundary is tighter now too: `world_entry_transition_and_runtime_bringup` at `0x00443a50` no + longer stops at the initial shell transition and world allocation head. The same grounded + function continues through the larger post-load generation tail up to `0x00444dc2`, which means + the later `Setting up Players and Companies...` and neighboring post-load passes are not + floating raw callsites after all. That same owner now clearly covers the event-runtime refresh + through `0x433130`, chairman-profile materialization through `0x437220`, neighboring route and + tracker refresh families, and the one-shot kind-`8` runtime-effect service through `0x432f40` + before clearing shell-profile latch `[0x006cec7c+0x97]`. The `Setup.win` dispatcher + is less opaque now too: the early `0x0bc1..0x0c24` family is mostly fixed submode selection above + `0x00502c00`, except for the separate `0x0bc2/0x0bc5/0x0bc6/0x0bc7` shell-open quartet above + `0x00501f20`; `0x0c1f` is the settings-window escape; `0x0c1e/0x0c20/0x0c22` are direct shell + requests into `0x00482150`; the fixed submode buttons now have concrete lower targets such as + `0x0bc1/0x0bc8 -> 15`, `0x0bc3 -> 16`, `0x0bc4 -> 1`, `0x0c80 -> 13`, `0x0c1c -> 17`, + `0x0c1d -> 2`, `0x0c24 -> 14`, `0x0c81 -> 14`, `0x0c82 -> 6`, `0x0c83 -> 10`, and + `0x0c84 -> 12`; the + `0x0ce6/0x0ce7/0x0d49/0x0d4a/0x0e82/0x0e83` branches are bounded list or slider adjustments on + staged setup fields; and the later `0x0dca/0x0dcb/0x0de9/0x0df3/0x0e81/0x0f6f/0x0f70` controls + are the explicit selector-writing launch buttons rather than one anonymous validated-launch blob. + The constructor-side callbacks are tighter too: control `0x0ce8` is a table-driven payload-label + draw callback above `0x00502030`, not another launch root; that callback now clearly sits on top + of the indexed string-table getter `0x0053de00` before handing the selected text span into the + world-anchor marker queue path. Controls `0x0e86` and `0x0e87` do not select more setup roots; + they update the persisted shell-state selector pairs at + `[0x006cec74+0x233/+0x237]` and `[0x006cec74+0x23b/+0x23f]` through `0x00502160` and + `0x005021c0`, then immediately save config through `0x00484910(1)`. The constructor body is + tighter too: it seeds the initial `Setup.win` state by running `0x502910`, `0x502550`, and + `0x502c00(1)` before the user interacts with the window, installs `0x0c80..0x0c86` and + `0x0f6f..0x0f71` as homogeneous button bands, and treats `0x0e88` as one separate special + control with retuned float fields rather than another ordinary launch root. The remaining + optional constructor child `0x0bd0` is tighter now too: it is built from a separate template + block and optional owned heap object before registration, not another hidden setup-root button. + The generic shell helper layer beneath that constructor is tighter now too: `0x53fa50` is the + shared resource-bind and child-list initialization helper, `0x53f830` is the child-control + lookup-by-id helper over the intrusive list at `[this+0x70]`, `0x558130` is the child-control + finalizer that stamps the owner pointer and resolves localized captions before the control goes + live, and `0x53f9c0` is the ordered child-control registration helper used by the optional + `0x0bd0` branch and other shell dialogs. + The submode selector itself is tighter now too because its button-state lane is mostly decoded: + `0xbc5` tracks submode `15`, `0xbc6` tracks `16`, `0xbba` tracks `2`, `0xbbb` tracks `3`, + `0xbc3` tracks `13`, `0xbbc` groups `3/4/5`, `0xbbd` tracks `4`, `0xbbe` tracks `5`, `0xbbf` + groups `6/12/14`, `0xbc0` tracks `7`, `0xbc1` tracks `8`, `0xbc2` tracks `9`, `0xe75` tracks + `10`, and `0xf6e` tracks `17`. RT3.lng and the setup art families now also make several of those + top-level roots read less like anonymous ids and more like real menu panels: submode `1` is the + strongest current landing-panel fit, `2` is the `Single Player` root, `7/8/9` are the + `Editor` / `New Map` / `Load Map` family, `15` is `Extras`, and `17` is `Tutorial`. By + elimination against the separate shell `Credits.win` mode, the remaining top-level `Setup.win` + roots now most safely read as `13 = Multi Player` and `16 = High Scores`. + The file-backed side is tighter too: `0x502c00` now maps submodes exactly as `4 -> dataset 5`, + `9 -> 4`, `6 -> 8`, `10 -> 6`, `12 -> 10`, and `14 -> 9`, so the saved-game-backed family is + no longer one blurred list pane but a small set of stable dataset variants above + `0x4333f0/0x4336a0`. + The file-list builder under that pair is tighter too: `0x4333f0` no longer just emits unsorted + `0x25a`-byte rows with raw names at `+0x0` and normalized labels at `+0x12d`. After the scan it + now clearly re-enters `0x51dc60`, which is a generic adjacent-swap insertion sort over fixed + records; in this setup-side caller it receives `record_size = 0x25a` and `key_offset = 0x12d`, + so the resulting `Setup.win` rows are sorted by display label rather than by the raw filename. + The file-backed header split is tighter too: `0x5027b0` now maps the top header-control ids as + `4 -> 0xd4b`, `9 -> 0xde8`, `6/12/14 -> 0xdf2`, and `10 -> 0xe85`. RT3.lng closes one earlier + mistake here: those values are local setup control or resource ids, not localized text ids. + The setup art bundle now tightens that family split one step further too: under `rt3_2WIN.PK4` + the distinct file-backed setup art families are the shared `Setup_Load` lane and the separate + `Setup_Sandbox` lane, which matches the selector-side evidence that mode `10` is the + sandbox-backed `new` list while mode `12` is its `load` sibling. Combined with the builder at + `0x4333f0`, that shows only submodes `4` and `10` using the alternate localized-stem list-label + path; `6`, `9`, `12`, and `14` keep the direct filename-normalization lane. + The `rt3_2WIN.PK4` extraction path is grounded a bit more cleanly now too: current `pack4` + samples use a shared `0x03eb` header, a fixed `0x4a`-byte directory entry stride, and a payload + base at `8 + entry_count * 0x4a`. In the checked UI bundle the entry table is contiguous and + `Campaign.win` extracts cleanly at directory index `3` with payload length `0x306a`. + The extracted `.win` payload family now has one narrow shared shape too: `Campaign.win`, + `CompanyDetail.win`, and `setup.win` all share the same first `0x50` bytes at offsets + `0x00`, `0x0c`, `0x10`, `0x14`, `0x34`, `0x38`, `0x40`, and `0x48`, while + `CompanyDetail.win` and `setup.win` also carry an inline root `.imb` name immediately at + `0x51`. Current resource scans show `Campaign.win` embedding the `litCamp*/Ribbon*` family, + `CompanyDetail.win` embedding mainly `CompanyDetail.imb`, `GameWindow.imb`, and `Portrait.imb`, + and `setup.win` embedding the broader `Setup_Background/Buttons/New_Game/Load/Sandbox` art + families. The control records between those strings are still undecoded, but the resource-record + shell itself is tighter now: all checked `.win` samples use the same three-word prelude prefix + `0x0bb8, 0x0, 0x0bb9`, and the fourth prelude word matches `resource_name_len + 1`. The next + word after the terminating NUL then behaves like a per-record selector lane. In `setup.win` + the dominant `Setup_Buttons.imb` family alternates between `0x00040000` and the incrementing + `0x00010c1c..0x00010c86` series with dominant inter-record strides `0xb7/0xdb`; in + `Campaign.win` the `litCamp*/Ribbon*` family carries the incrementing `0x0004c372..0x0004c38e` + selector block with dominant `0x158/0x159` and `0xb2/0xb3` strides. That campaign lane is now + directly aligned to the executable-side control ids too: the low 16 bits of + `litCamp1..16` map exactly to `0xc372..0xc381`, and the low 16 bits of `Ribbon1..16` map + exactly to `0xc382..0xc391`, matching the `Campaign.win` progress and selector control bases + already grounded from `RT3.exe`. The fuller selector export now tightens the auxiliary families + too: `litArrows.imb` covers `0xc36c..0xc371` exactly and `litExits.imb` covers + `0xc397..0xc39a` exactly, matching the constructor-side six-control arrow strip and four-control + exit strip. The second post-name dword is tighter now too: its middle 16-bit lane groups those + same `Campaign.win` records under `0xc368`, `0xc369`, `0xc36a`, and `0xc36b`, which matches the + four page-strip controls and cleanly buckets the first five campaign entries, the next five, the + next three, and the final three under the same page families. There are still no `.imb` + selector records for `0xc393..0xc396` or `0xc39b`, which makes those message-side page-write + controls look more like structural buttons than art-backed repeated resource records. + The grouped `3/4/5` family is narrower now too: `0x0ce5` is no longer part of it, because that + control writes selector `3` and then selects submode `9` as the `Load Map` sibling. The nearby + `0x0dcb` branch instead conditionally selects submode `5` or `3`, which keeps `3` as the + strongest current `New Game` / `Options` companion and `5` as the strongest current `Sandbox` + companion. The file-backed single-player side is tighter in the same way now: modes `4` and `10` + are the only siblings using the alternate localized-stem row-label path, so they now read most + safely as the two setup-local template or profile list variants rather than ordinary save lists. + Mode `10` is the stronger one of the pair because neighboring validated launch control `0x0e81` + both routes into selector `5` and sets sandbox byte `[0x006cec7c+0x82] = 1`, which makes it the + strongest current fit for the setup-local `New Sandbox` list. The distinct `Setup_Sandbox` art + family in `rt3_2WIN.PK4` now reinforces that same split one step further, which makes mode `12` + the strongest closed fit for the paired `Load Sandbox` lane; mode `4` is therefore the strongest + remaining non-sandbox peer in that same pair and now most safely reads as the setup-local `New + Scenario`-style chooser. Modes `6`, `12`, and `14` now tighten one step further as the three + selector-`3` direct-filename setup-local `load` siblings because they stay on the direct + filename-normalization lane, share the same `0xdf2` header family, and clear the same + presence-style latch `[0x006cec7c+0x97]`; mode `14` is the strongest current landing panel for + that cluster because `0x0c24` jumps to it directly while `0x0c82` and `0x0c84` only reach the + sibling modes `6` and `12` from inside the same load family. Current control-pairing and + setup-art evidence now make `12 = Load Sandbox` the strongest closed per-submode assignment. The + remaining non-sandbox pair is closed now too: the deeper bundle filter at `0x433260` + distinguishes dataset `9` from dataset `8` by one extra nonzero payload-flag family, and the + editor-side metadata path now grounds `[0x006cec78+0x66de]` as the direct `Campaign Scenario` + checkbox bit because `editorDetail.win` ties control `0x5b6e` to localized ids `3160/3161`. + That makes dataset `9` the campaign-designated load family and dataset `8` the ordinary scenario + load family, so `14 = Load Campaign` and `6 = Load Scenario` now read as grounded rather than + residual. `0x502910` is + tighter in a + corrective way too: it is not a mode-`3`-only helper after all, but the shared non-file-backed + payload panel that formats + `0xcf3/0xcf4/0xcf5/0xd4f`, mirrors option byte `[0x006cec7c+0x7d]` into `0x0ce9..0x0ced`, + rebuilds row host `0x0ce8` from payload bytes `[+0x31b/+0x31c]`, and mirrors live row markers + into `[0x006cec7c+0x87]`. That makes mode `3` just one user of the shared payload-driven panel, + not the sole owner of it. + The payload-helper cluster under that panel is tighter now too: `0x502220` does not just + republish labels and the preview surface. It first re-enters + `shell_setup_load_selected_profile_bundle_into_payload_record` `0x442400`, which clears one full + `0x100f2`-byte setup payload record, builds a rooted path from the staged profile stem, opens the + selected bundle through `0x530c80`, and then reads either the ordinary saved-profile chunk family + or the map-style chunk family through `0x531150/0x531360` depending on the selected extension + shape. Only after that does `0x502220` copy payload fields `+0x14/+0x3b2/+0x3ba/+0x20` into the + staged runtime profile through `0x47be50`, which in turn normalizes the payload category bytes at + `[payload+0x31a + row*9]` and the local marker-slot bytes at `[payload+0x2c9..]` through + `0x47bc80`. The copied-field consumer split is tighter now too: payload `+0x14` becomes staged + profile `[0x006cec7c+0x77]`, which is the visible setup scalar later formatted into controls + `0x0e84` and `0x0d4f` and adjusted by the `0x0d49/0x0d4a` pair; payload `+0x3b2` becomes + `[0x006cec7c+0x79]`, the live-row threshold that the payload-row draw callback uses to choose + style slot `0x18` versus `0x19`; and payload `+0x3ba` becomes `[0x006cec7c+0x7b]`, the current + scroll or row-index lane adjusted by the `0x0ce6/0x0ce7` pair. So the known setup-side payload + consumers still stop well before the later candidate table, but the early copied lanes are no + longer anonymous. The adjacent region-side worker family is tighter in a negative way too: the setup + payload path now gives one useful upper bound on the newer candidate-availability source block + too. The map-style setup loader is definitely pulling chunk families `0x0004/0x2ee0/0x2ee1` + into one large `0x100f2`-byte payload record, and the fixed `0x6a70..0x73c0` candidate table + clearly lives inside the same broad file family; but the grounded setup-side consumers we can + actually name after that load still only touch earlier payload offsets such as `+0x14`, + `+0x20`, `+0x2c9`, `+0x31a`, `+0x3ae`, `+0x3b2`, and `+0x3ba`. So the current evidence is + strong enough to say the candidate table is probably housed inside the setup payload family, but + not yet strong enough to name one setup-side consumer that reads the `0x6a70` header or the + fixed-width entries directly. The newer fixed-offset compare pass tightens that lower setup slice + too: across the checked map/save pairs `Alternate USA.gmp -> Autosave.gms`, + `Southern Pacific.gmp -> p.gms`, and `Spanish Mainline.gmp -> g.gms`, the known setup payload + lanes `+0x14` and `+0x3b2` are preserved map-to-save on the same scenario-family split as the + later candidate-table headers (`0x0771/0x0001`, `0x0746/0x0006`, `0x0754/0x0001`), while + `+0x3ae` stays fixed at `0x0186` and `+0x3ba` stays fixed at `1` across all six files. By + contrast, `+0x20` does not survive as one shared source value (`0xd3 -> 0xb4`, + `0x6f -> 0x65`, `0xe3 -> 0x78` across those same pairs). So the current best read is that the + setup payload mixes preserved scenario metadata and later save-variant state well before the + `0x6a70` candidate table, rather than acting as one uniformly copied prelude. + The adjacent region-side worker family is tighter in a negative way too: the setup + payload loader is now clearly separate from the broader region-building and placement cluster + around `0x422320..0x423d30`, whose current grounded helpers now include `0x422320`, `0x4228b0`, + `0x422900`, `0x422a70`, `0x422be0`, `0x422ee0`, `0x4234e0`, `0x4235c0`, and + `world_region_refresh_cached_category_totals_and_weight_slots` `0x423d30` rather than one hidden + setup-only panel. The leading region helper is no longer unnamed either: `0x422320` is now + bounded as the recurring cached-structure-scalar normalization pass that writes + `[region+0x2e2/+0x2e6/+0x2ea/+0x2ee]`, while `0x422a70` is the shared placement-validation and + commit gate beneath both the per-region worker and one second world-side placement loop. The + neighboring `0x4234e0` accessor is tighter too: it is the shared projected structure-count scalar + query by category that later feeds both the per-region placement family and the map-editor city + count stats report. So the remaining gap is no longer “what are these setup payload helpers + doing,” but only how aggressive we want to be when naming the last top-level setup roots from + mostly RT3.lng and asset-side evidence. + The adjacent summary helper is tighter too: `0x502550` is not another hidden submode owner. It + republishes the staged path tail in `0xe7f`, the scalar summary in `0xe84`, the two persisted + selector lists in `0xe86/0xe87`, and the config toggles in `0xe88/0xe89/0xe8a`. + The remaining top-level gap is cleaner now too: submode `16` still has no distinct downstream + helper or launch branch in the local selector/refresh family, but it is no longer a blank bucket. + Current evidence now bounds it as the `0x0bc3 -> 16` top-level button whose visual-state lane is + surfaced through control `0xbc6`, and the strongest residual fit is `High Scores` because + `Credits` already lives in separate shell mode `6`. + The validated launch lane is tighter now too: it no longer just writes selector `3` or `5` as + one undifferentiated blob, and it no longer includes `0x0ce5` or `0x0dcb`. `0x0ce5` is the + `Load Map` selector because it writes selector `3` and then selects submode `9`, while `0x0dcb` + is the later conditional `5/3` companion-selector sibling rather than a file launch. The actual + validated staged-profile lane is now bounded more narrowly: `0x0cf6` and `0x0e81` are the + selector-`5` siblings, while the neighboring selector-`3` validated lane is at least shared by + `0x0de9` and `0x0df3`; the shared bridge at `0x4425d0` then forces `[0x006cec7c+0xc5] = 1`, + mirrors payload bytes into `[profile+0xc4]`, `[profile+0x7d]`, and `[profile+0xc6..+0xd5]`, and + only then issues shell request `0x0cc`. The file-side staging bytes in that bridge are now + tighter too: across the checked `Alternate USA`, `Southern Pacific`, and `Spanish Mainline` + map/save pairs, payload `+0x33` stays `0`, but payload `+0x22` and token block `+0x23..+0x32` + do not preserve the earlier map-to-save pairing seen at `+0x14/+0x3b2`. Instead they split by + the finer file family, with examples `Alternate USA.gmp = 0x53 / 0131115401...` versus + `Autosave.gms = 0xae / 01439aae01...`, `Southern Pacific.gmp = 0xeb / 00edeeeb...` versus + `p.gms = 0x21 / 0100892101...`, and `Spanish Mainline.gmp = 0x5b / 0044f05b...` versus + `g.gms = 0x7a / 0022907a...`. So the validated launch bridge now looks more like a file-family + staging lane than a simple copy-forward of the earlier setup summary fields. The destination-side + consumers are tighter now too: `[profile+0xc4]` is no longer just an unnamed staged byte, but the + campaign-progress slot later consumed by the numbered `%s%02d.gmc` save helper `0x00517c70`; + `[profile+0x7d]` is the same compact option byte mirrored back into the `Setup.win` option + controls `0x0ce9..0x0ced`; and the campaign-side selector block is no longer only a one-byte + anchor. Direct `RT3.exe` disassembly of the campaign-side dispatcher at `0x004b89c0` now shows + the exact mirror shape: when the local campaign-page selector `[window+0x78] <= 4`, the helper + writes one highlighted progress control `0x0c372 + [profile+0xc4]` and then mirrors the full + sixteen-byte band `[profile+0xc6..+0xd5]` into controls `0x0c382..0x0c391` through repeated + `0x540120` calls. The same body also treats `[profile+0xc4]` as an index into the fixed + sixteen-entry scenario-name table at `0x00621cf0`, whose observed entries include `Go West!`, + `Germantown`, `Central Pacific`, `Texas Tea`, `War Effort`, `State of Germany`, `Britain`, + `Crossing the Alps`, `Third Republic`, `Orient Express`, `Argentina Opens Up`, + `Rhodes Unfinished`, `Japan Trembles`, `Greenland Growing`, `Dutchlantis`, and + `California Island`. On the launch-side branch the same helper writes startup selector `6`, + copies the resolved campaign filename into `[profile+0x11]`, forces `[profile+0xc5] = 1`, and + then issues shell request `0x0cc`. The lower refresh tail at `0x004b8d49..0x004b8d69` also + shows the observed page-band split over the same progress byte: values `< 5` pair with campaign + page `1`, values `5..9` with page `2`, values `10..12` with page `3`, and values `>= 13` with + page `4`. So `[profile+0xc6..+0xd5]` is no longer a generic opaque span at all, but the staged + sixteen-byte per-scenario campaign selector or unlock band consumed directly by `Campaign.win`. + The neighboring profile helpers are tighter now too: `0x0047bbf0` is the broad default reset for + the staged `0x108`-byte runtime-profile record, clearing the whole record and then reseeding the + visible setup and campaign anchors `[profile+0x77]`, `[profile+0x79]`, `[profile+0x7d]`, + `[profile+0x83]`, `[profile+0x87]`, and `[profile+0x97]`; and `0x0047bc50` is the compact scan + helper over `[profile+0xc6..+0xd5]` that returns the first selector byte below `2`, which keeps + that band tied to staged campaign progress or unlock state rather than to the earlier setup-panel + payload fields. + The message-dispatch side is tighter now too. The local classifier at `0x004b91d8` routes the + control range `0x0c352..0x0c39b` through five concrete case classes: `0x0c352..0x0c361` enter + the shared selector or launch branch, `0x0c362..0x0c367` force local page `1`, + `0x0c368..0x0c392` force local page `2`, `0x0c393..0x0c396` force local page `0`, and + `0x0c39b` alone forces local page `3`. That matches the constructor and refresh shape: the + sixteen scenario selector controls live at `0x0c352..0x0c361`, the four page-strip controls + live at `0x0c368..0x0c36b`, the six-arrow auxiliary strip lives at `0x0c36c..0x0c371`, the + progress band lives at `0x0c372..0x0c381`, the ribbon or selector band lives at + `0x0c382..0x0c391`, the string or voice target lane lives at `0x0c392`, the four exit controls + live at `0x0c397..0x0c39a`, and `0x0c39b` remains the one-off special action control that + spawns or dismisses the campaign-side companion object. The `Campaign.win` blob now exposes that + structural split directly too: alongside the art-backed `0x0004c3xx` records it carries + anonymous zero-name records with the same `0x0bb8 / 0 / 0x0bb9` prelude but selector words in + the `0x0010c3xx` family. Current local extraction shows exactly + `0x0010c352..0x0010c361`, `0x0010c362..0x0010c367`, `0x0010c393..0x0010c396`, and one + `0x0010c39b` record, which is the same non-`.imb` band the message dispatcher treats as the + structural selector and page-write family. Their second selector word then buckets those records + under the same page-strip ids as the art-backed records: `0xc368` for + `0xc352..0xc356`, `0xc362`, `0xc393`, and `0xc39b`; `0xc369` for `0xc357..0xc35b`, + `0xc363`, and `0xc394`; `0xc36a` for `0xc35c..0xc35e`, `0xc365..0xc366`, and `0xc395`; and + `0xc36b` for `0xc367`, `0xc35f..0xc361`, and `0xc396`. One final anonymous record at + `0x0002c392` has no page bucket at all, which fits the already-grounded read of `0xc392` as the + one-off string or voice target lane rather than a normal page-cell control. The anonymous body + layout is only partially named, but one file-side distinction is already stable: the ordinary + structural selector/page records all carry footer words `0xd3000000` and `0xd2000007` at + relative `+0x98/+0x9c`, while the lone `0xc392` record carries `0x00000000/0x00000000` there. + So `0xc392` is no longer just “outside the page buckets”; it is also the only current + anonymous-record outlier in that trailing structural footer pair. The structural selector side is + tighter now too: `0xc352..0xc361` partition exactly as `5 + 5 + 3 + 3` across page buckets + `0xc368..0xc36b`, matching the observed campaign page bands for scenario progress values `< 5`, + `5..9`, `10..12`, and `>= 13`. That makes the anonymous selector records the file-side mirror of + the same campaign page split, not a separate unrelated control family. The file-order adjacency + is tighter in the same way: `0xc352..0xc361` each sit immediately after one `RibbonN.imb` + record and before the next `litCamp` record, which makes them the strongest current file-side fit + for the structural selector or click-target siblings of the visible campaign ribbon controls. + The auxiliary anonymous bands line up the same way: `0xc362..0xc367` sit inside the local + `litArrows.imb` clusters, `0xc393..0xc396` sit inside the `litExits.imb` clusters, and + `0xc39b` sits once between the first arrow and first exit group. So the current best read is + that those anonymous records are the structural hitbox or action siblings of the visible arrow, + exit, and selector art families, not an unrelated hidden control layer. The generic record + cadence is tighter now too: in the current `Campaign.win` dump the ordinary anonymous structural + records all span `0x0a7` bytes, while the named art-backed records cluster at `0x0b1`, `0x0b2`, + and `0x0b3`. The only two visible outliers are the leading `0x0080c351` record at `0x0041` + with span `0x0a3`, and the trailing `0x0002c392` record at `0x2fb9` with span `0x0b1`. That + reinforces the current read that `0xc351` and `0xc392` are one-off structural controls flanking + the main selector or page family rather than ordinary repeated art-backed records. + The setup-launch corpus now tightens one corrective caveat there too: when the checked + `Alternate USA`, `Southern Pacific`, and `Spanish Mainline` `.gmp/.gms` files are decoded with + that same campaign-side interpretation, payload byte `+0x22` is always outside the known + campaign progress range `0..15` (`0x53`, `0xeb`, `0x5b`, `0xae`, `0x21`, `0x7a`), so the + ordinary validated setup lane is not simply staging a normal campaign-screen state. The paired + token block `+0x23..+0x32` is still structurally compatible with the campaign selector band, but + in the checked files it only populates a small recurring subset of the sixteen scenario lanes, + chiefly `Go West!`, `Germantown`, `Central Pacific`, `Texas Tea`, and `War Effort`, with + scenario-family-specific byte values rather than a simple `0/1` unlock bitmap. That makes the + setup-side staging bridge look more like one shared destination layout being reused for a broader + launch token family, not a proof that ordinary setup-launched `.gmp/.gms` content is already in + campaign-screen form. + Only `0x0e81` also sets `[0x006cec7c+0x82] = 1`, which is currently the strongest sandbox-side + anchor beneath the later `.gmx` load family. + That launch band is slightly tighter now too: `0x0dca` is the grayscale-map picker branch above + the `TGA Files (*.tga)` / `.\Data\GrayscaleMaps` helper at `0x004eb0b0`, not another ordinary + save-file validator. That launch band is tighter in a second way too: `0x0ddf` is not a lobby + branch after all, but the separate windowed-mode-gated grayscale-heightmap generation path. It + reopens the `TGA Files (*.tga)` / `.\Data\GrayscaleMaps` picker through `0x0042a970`, validates + the chosen image through `0x005411c0`, and only then writes startup selector `2`. The fixed- + button side is tighter too: submode `15` now aligns with the `Extras` family because it sits + above the Readme/Weblinks shell-open quartet and the return-to-extras sibling, while submode + `17` now aligns with the tutorial chooser because it is the only branch that later exposes + startup selectors `1` and `7`, which RT3 uses for `Tutorial_2.gmp` and `Tutorial_1.gmp`. The + map-root family is tighter too: submodes `7/8/9` are the only setup branch that flips the file + root into + `maps\\*.gm*`, with mode `8` specifically the grayscale-heightmap picker and mode `9` the + file-backed map-list sibling. + Submode `13` is slightly tighter now too: current local evidence shows that it stays outside + both the dedicated file-backed pane and the mode-`3` option-heavy pane, so it is best read for + now as one top-level non-file-backed setup branch rather than another saved-game list variant. + The setup-side file roots are tighter now too: the shared file-list builder at `0x4333f0` + formats either `saved games\\*.smp` or `maps\\*.gm*` from the shell-state fields at + `[0x006cec74+0x68/+0x6c]`, with the separate `data\\tutorial` root only appearing on the + tutorial-side `[shell+0x6c] == 2` branch. That means the `Setup.win` submode families are no + longer one generic file pane: the ordinary setup-backed `.smp` family is broader than the + narrower file-list pane, because modes `3/4/5/6/10/12/14` stay on the ordinary saved-game side + while only `4/6/9/10/12/14` re-enter the dedicated file-list panel at `0x5027b0`; the `maps` + branch is the narrower setup or tutorial launch family above the same shared record builder. +- Evidence: function-map map/scenario rows, analysis-context exports for `0x00445ac0`, `0x00445de0`, + `0x00443a50`, `0x00434300`, and `0x00444dd0`, plus objdump string and mode-table evidence for + `.gmp`, `.gmx`, `.gmc`, `.gms`, `.gmt`, `.smp`, `Quicksave`, the `0x004dd010` mode table at + `0x005f3d58`, the auxiliary-owner presence check at `0x00434050`, and the `.gmt` handoff through + `0x00469d30`, together with localized string evidence from ids `3018` and `3898`. +- Direct shell stubs above that coordinator are tighter now too: `0x004408b0` is the pure + zero-flag wrapper into `shell_map_file_world_bundle_coordinator`, while `0x004408d0` is the + sibling wrapper with flag triplet `(0, 1, 0)`. The exact user-facing command names for those two + wrappers are still open, but the dispatcher shape is no longer. +- Open Questions: bit `0x1` on both broad coordinators now grounds the Quicksave name seed and the + former third `fileopt.win` flag has been ruled out as a file-flow question because it just opens + `SettingsWindow.win`. The old broad extension question is mostly resolved: `.gmp` is the + editor-map pair, `.gms` is the standalone scenario family, `.gmc` is the campaign-scenario family, + `.gmx` is the sandbox family, and `.gmt` is at least bounded as an auxiliary preview-surface + branch rather than another gameplay save family. The higher-value global question is no longer + whether `0x00443a50` is world entry. It is where the long-lived simulation cadence takes over + after this bring-up and whether that cadence still rendezvous with the shell-owned frame path or + escapes into a separate gameplay loop. + diff --git a/docs/control-loop-atlas/multiplayer-session-and-transport-flow.md b/docs/control-loop-atlas/multiplayer-session-and-transport-flow.md new file mode 100644 index 0000000..8598208 --- /dev/null +++ b/docs/control-loop-atlas/multiplayer-session-and-transport-flow.md @@ -0,0 +1,607 @@ +## Multiplayer Session and Transport Flow + +- Roots: `multiplayer_window_init_globals` at `0x004efe80`, `multiplayer_window_service_loop` at + `0x004f03f0`, the Multiplayer.win session-event callback table built by + `multiplayer_register_session_event_callbacks` at `0x0046a900`, the active session-event transport + object at `0x006cd970`, the Multiplayer preview dataset object at `0x006cd8d8`, and the lower + pending-template and text-stream helpers around `0x00597880..0x0059caf0`. +- Trigger/Cadence: shell-owned Multiplayer.win frame service plus event-driven session callbacks and + repeated transport pump steps. +- Key Dispatchers: session-event wrappers for actions `1`, `2`, `4`, `7`, `8`; + `multiplayer_register_session_event_callbacks`; `multiplayer_dispatch_requested_action`; + `multiplayer_reset_preview_dataset_and_request_action`; + `multiplayer_preview_dataset_service_frame`; `multiplayer_load_selected_map_preview_surface`; + `multiplayer_flush_session_event_transport`; `multiplayer_transport_service_frame`; + `multiplayer_transport_service_worker_once`; + `multiplayer_transport_service_route_callback_tables`; + `multiplayer_transport_service_status_and_live_routes`; + `multiplayer_transport_text_stream_service_io`; + `multiplayer_transport_dispatch_pending_template_node`; + `multiplayer_transport_service_pending_template_dispatch_store`. +- State Anchors: live session globals at `0x006d40d0`, active session-event transport object at + `0x006cd970`, status latch at `0x006cd974`, session-event mode latch at `0x006cd978`, retry + counter at `0x006cd984`, preview dataset object at `0x006cd8d8`, preview-valid flag at + `0x006ce9bc`, staged preview strings at `0x006ce670` and `[0x006cd8d8+0x8f48]`, Multiplayer.win + backing block at `0x006d1270`, selector-view store root at `[transport+0xab4]`, selector-view + generation counters at `[transport+0xab8]..[transport+0xac0]`, selector-view backing arrays around + `[transport+0xad0]..[transport+0xae4]`, selector-view entry probe-request id at `[entry+0x50]`, + live-state gate at `[entry+0x58]`, third-slot flag word at `[entry+0x64]`, probe-schedule tick at + `[entry+0x68]`, last-success tick at `[entry+0x6c]`, pending-probe latch at `[entry+0x74]`, + success generation at `[entry+0x78]`, consecutive-failure counter at `[entry+0x7c]`, rolling + average at `[entry+0x80]`, recent sample window at `[entry+0x84..]`, bounded sample-count at + `[entry+0x94]`, total-success count at `[entry+0x98]`, pending-template list at + `[transport+0x550]`, dispatch store at `[worker+0x54c]`, and text-stream buffers rooted under + `[worker+0x1c]`. +- Subsystem Handoffs: the Multiplayer.win initializer seeds the backing block at `0x006d1270`, later + reset paths construct the separate preview dataset at `0x006cd8d8`, and the shell-owned + active-mode frame services that dataset every frame through + `multiplayer_preview_dataset_service_frame`. That preview side publishes roster and status + controls through the Multiplayer window control paths, loads `.gmt` preview surfaces through + `multiplayer_load_selected_map_preview_surface`, and is even reused by the map/save coordinator’s + mode-`11` `.gmt` path when the dataset already exists. The preview owner now has a tighter + internal request split too. The fixed selector-descriptor list at `[0x006cd8d8+0x8f28]` is built + through `multiplayer_preview_dataset_append_named_callback_descriptor` `0x00469930`, whose + current grounded owner is the fixed registration block + `multiplayer_preview_dataset_register_fixed_named_callback_descriptors_1_to_10` `0x00473a60`; + the variable-size named UI-request list at `[0x006cd8d8+0x8f2c]` is built through + `multiplayer_preview_dataset_append_named_ui_request_record` `0x00469a50`; and the staged + profile/path strings live at `[0x006cd8d8+0x8e10]` and `[0x006cd8d8+0x8f48]`, with the broader + action-`2` staging path now bounded by + `multiplayer_preview_dataset_stage_profile_text_selected_path_and_sync_session_state` + `0x0046a030`. The companion action-`3` commit path is tighter too: + `multiplayer_preview_dataset_match_named_field_slot_copy_profile_text_and_probe_selection` + `0x0046a110` now sits directly above the lazily initialized `0x80 * 0x11c` field-slot table at + `[0x006cd8d8+0x10]`, whose owner is + `multiplayer_preview_dataset_ensure_field_slot_table_initialized` `0x0046a1a0`. The shared + submitter above those lists is now explicit too: + `multiplayer_preview_dataset_submit_transport_request` `0x00469d30` accepts the caller’s + request-id, selector, payload pointer and length, flag word, and optional auxiliary pointer, + optionally allocates one sidecar object, and then either sends the request directly through the + session-event transport or takes the slower packed branch through `0x00553000/0x00552ff0` into + `0x00521dc0`. The constructor and teardown side are tighter now too. + `multiplayer_preview_dataset_construct_reset_globals_and_seed_callback_owners` `0x0046be80` + is the real reset owner above the action-`2/3` branches in + `multiplayer_dispatch_requested_action`: it re-enters the paired release body + `multiplayer_preview_dataset_release_owned_lists_transients_and_session_side_state` + `0x0046bc40`, clears the surrounding launcher globals, allocates the field-slot table and the + keyed request/descriptor owners, seeds the render target and staging buffers, and then calls + `multiplayer_preview_dataset_reset_global_callback_state_and_register_selector_handlers` + `0x00473280` plus the smaller fixed-name block + `multiplayer_preview_dataset_register_fixed_named_callback_descriptors_1_to_10` `0x00473a60`. + That broader registration pass `0x00473280` now bounds the selector-handler family too: it + zeroes the global scratch bands `0x006ce808..0x006ce994` and `0x006ce290`, seeds default + callback root `[0x006cd8d8+0x08]` with `0x0046f4a0`, and populates the keyed selector table at + `[0x006cd8d8+0x04]` through + `multiplayer_preview_dataset_register_selector_callback_if_absent` `0x00468b10` for selectors + `1..0x83`. The concrete callback bodies under that table are tighter now too. The small split is + real rather than guessed: `0x0046c390` is the direct control-`0x109` publish leaf through + `0x00469d30`; `0x0046c3c0` is the fixed-session-token plus launch-latch arm path; and the large + sibling `0x0046c420` is the real apply-owner for one incoming session payload slab copied into + `0x006cec74` before the shell-refresh follow-ons. A second callback cluster now owns live + session-entry flags instead of just relaying transport payloads: `0x0046c7c0` rewrites the + elapsed-pair dwords `[entry+0x54/+0x58]`, `0x0046c840` sets bit `0x08` in `[entry+0x5c]`, + `0x0046c870` toggles bit `0x01` from payload byte `[msg+0x08]`, `0x0046cf10` sets bit `0x04`, + and `0x0046cf70` is the list-wide clear of that same bit-`0x01` lane across every live session + entry. The broader callback `0x0046c8c0` sits above those single-field leaves and applies either + one or many embedded session-field update records before republishing the list. The pending-state + side is separated now too: `0x0046cce0`, `0x0046cd10`, `0x0046ce90`, and `0x0046d230` are the + current small latch/state owners under `0x006cd91c`, `0x006d1280`, `0x006d1284`, and + `0x006ce9c8`, while `0x0046cd30` and `0x0046ce10` are the paired current-session string/scalar + submit-and-apply handlers over `[entry+0x258c/+0x268c/+0x2690/+0x2694]`. The same callback table + also owns one small fixed transfer-progress family rooted at `0x006ce2e8`: `0x0046cfe0` + allocates the first free `0x5c` slot and optionally formats one label string, `0x0046d090` + appends progress payload into the matched slot while publishing one percent string through + `0x005387a0`, and `0x0046d1d0` clears the finished slot and frees that optional label. On the + release side, `0x0046bc40` now clearly owns the request-list, + descriptor-list, semicolon-name, pooled-span, render-target, and auxiliary-owner teardown, while + `multiplayer_shutdown_preview_dataset_session_object_and_global_helper` `0x0046c230` is the + final wrapper that additionally drops the live session object at `0x006d40d0` and the shared + helper at `0x00d973b4`. The small tuple staging below that family is bounded too: + `multiplayer_preview_dataset_touch_current_session_year_bucket_and_return_staged_tuple` + `0x0046b6d0` now owns the keyed session-bucket touch under `[session+0x2580]` for the staged + tuple at `[0x006cd8d8+0x9048]`, and the companion + `multiplayer_preview_dataset_stage_optional_selected_token_from_source_ptr` `0x0046d610` writes + the optional derived token into `[0x006cd8d8+0x8f38]`. The next service layer under the same + owner is tighter too: `multiplayer_preview_dataset_prune_session_buckets_below_current_year_key` + `0x0046b910` now bounds the older keyed-bucket drain under `[session+0x2580]`, while + `multiplayer_preview_dataset_service_current_session_buckets_and_publish_selector0x67` + `0x0046b9f0` owns the current-bucket walk, the local counters `[+0x987c/+0x9890]`, and the + later selector-`0x67` publish branch back through `0x00469d30`. Its local batch-publish child + `multiplayer_preview_dataset_publish_accumulated_selector0x71_record_batch` `0x00473bf0` is now + bounded too: it packages the fixed-width records at `0x006cd990`, prefixes `(0, count)`, sends + them as selector `0x71`, and then clears the live record count `0x006ce9a0`. The immediate local + helpers under that same band are now explicit too: `0x0046d260` is the fixed-record append + primitive that grows `0x006cd990` up to `0x80` entries, while `0x0046d240` is the paired release + of the optional selector-`0x71` staging blob at `0x006ce994`. The first fixed named-descriptor + block under `multiplayer_preview_dataset_register_fixed_named_callback_descriptors_1_to_10` + `0x00473a60` is tighter in the same way now. Its concrete roots `0x0046db10`, `0x0046db50`, + `0x0046db90`, `0x0046dbd0`, `0x0046dd10`, `0x0046de40`, `0x0046de80`, `0x0046e030`, and + `0x0046e250` all return small static records rooted at `0x006ce9dc..0x006cea3c`; each record + carries a leading tag byte plus the same derived world-year key from `[0x006cec78+0x0d]`, while + the heavier siblings add collection-backed totals from `0x0062be10`, `0x006ceb9c`, `0x0062b26c`, + `0x006cfca8`, or `0x006cfcbc` together with local overlay, geometry, or object-metric sample + paths. The immediate helper strip beneath that same first named block is tighter now too. + `0x0046d980` is the direct `0x006ceb9c` name-to-index lookup over `[entry+0x08]`, while + `0x0046d9e0` is the heavier companion that first resolves the current live session from + `0x006d40d0`, matches that session-side string against the same `0x006ceb9c` table, and returns + the matching entry index or `0xff`. Above those, `0x0046f8f0` resolves and validates one + `0x0062be10` entry, then keeps it only when its profile-index field `[entry+0x3b]` equals the + live-session-backed `0x006ceb9c` index from `0x0046d9e0`; and `0x0046f870` is the paired + rounded-delta leaf that takes one float plus one collection byte index and writes the rounded + positive/negative pair into metric ids `0x0f` and `0x0d` through `0x0042a040`. So this first + descriptor band is no longer just a bag of static record roots: it also owns a real local helper + family for `0x006ceb9c` name matching, live-session profile matching, and one narrow metric-pair + apply path beneath the higher callback bodies. The next selector layer above that helper strip is + tighter now too. Selector `0x12` is the small validate-or-error wrapper above selector `0x13`, + and selector `0x13` body `0x004706b0` resolves the same live-session company match, attempts the + placed-structure apply path through `0x004197e0`, `0x004134d0`, `0x0040eba0`, `0x0052eb90`, and + `0x0040ef10`, and otherwise falls back to a hashed selector-`0x6e` publish over the first + `0x1c` payload bytes. The same pattern appears again one pair later: selector `0x16` is the + thin validate-or-error wrapper above selector `0x17`, and selector `0x17` consumes a count plus + `0x33`-stride adjunct record band, resolves one live train-side entry under `0x006cfcbc`, + re-enters `0x004a77b0`, `0x0052e720`, `0x0040eba0`, `0x0052eb90`, and `0x0040ef10`, and again + falls back to hashed selector `0x6e` publish when the live apply path does not land. The later + status pair is bounded too: selector `0x19` is another thin wrapper, and selector `0x1a` either + derives a status code from `0x0046ed30` and current live-session name matching or treats the + four-byte payload directly as that status code before publishing localized status text + `0x0b7f/0x0b80`. One selector-pair above the metric leaf is now explicit too: + the earlier front edge of the same callback table is tighter now too. Selector `0x02` compares + staged profile text against the shell profile band at `[0x006cec7c+0x11]`, can advance the + requested-action fields `0x006d1280/0x006d1284`, can queue selector `0x53`, and on the success + path syncs the larger shell profile block rooted at `[0x006cec7c+0x44]`. The next small strip is + also grounded: selector `0x0a` clears `[world+0x19]`, seeds `[world+0x66ae]`, mirrors peer byte + `[peer+0x2690]` into named-profile byte `[entry+0x15c]`, refreshes `0x006ce98c`, and optionally + republishes one local status path. Selector `0x0b` is then the small token-staging wrapper above + selector `0x0c`, and selector `0x0c` itself forwards one signed byte pair into `0x00434680` + before adjusting dataset counter `0x006cd8e8`. The other small early leaves are now bounded too: + selector `0x0f` pops one node from the current session queue at `[session+0x64]`, publishes that + node through `0x00469d30`, and releases it; selector `0x10` looks one payload key up in the + session-side store `[session+0x60]` and forwards the result plus dataset string root + `[0x006cd8d8+0x8f48]` into `0x00521790`. One selector-pair above the metric leaf is now explicit too: + selector-`0x15` body `0x00470950` consumes the same compact `(float delta, company-index byte)` + payload shape, resolves the matching live-session company entry through `0x0046f8f0`, submits + selector `0x6b` through `0x00469d30`, and then immediately re-enters `0x0046f870` for the local + apply. The neighboring name-match lane is now explicit too: + selector-`0x61` body `0x00472700` scans `0x0062be10` for a company-name match against the caller + string at `[payload+0x08]` and then either submits selector `0x62` with the original payload or + falls back to the paired error-style `0x21` branch. The next registered band around selectors + `0x1c..0x5d` is tighter now too. Selector-adjacent helpers `0x00470ed0` and `0x00470fa0` + are the paired global preset passes beneath that strip: both walk the guarded named-profile + table `0x006ceb9c`, add opposite signed integer presets into qword field `[profile+0x154]` + through `0x00476050`, then walk `0x0062be10` and write opposite preset + scalars into metric id `0x0d` through `0x0042a040`. Above them, selectors `0x1d`, `0x1f`, + `0x21`, `0x23`, `0x25`, `0x27`, `0x29`, `0x2b`, `0x2d`, `0x2f`, `0x31`, `0x33`, `0x35`, + `0x37`, and `0x39` are now explicit token-staging forwarders into selectors `0x1e`, `0x20`, + `0x22`, `0x24`, `0x26`, `0x28`, `0x2a`, `0x2c`, `0x2e`, `0x30`, `0x32`, `0x34`, `0x36`, + `0x38`, and `0x3a`. The next live-train strip is also grounded: selectors `0x3b`, `0x3d`, + `0x3f`, `0x41`, and `0x43` resolve live train ids from `0x006cfcbc`, stage the current token, + and republish into selectors `0x3c`, `0x3e`, `0x40`, `0x42`, and `0x44`; selectors `0x3c`, + `0x3e`, and `0x40` then dispatch directly into `0x004abd70`, `0x004b2f00`, and `0x004b3000`, + while selector `0x42` is the heavier train-adjunct branch through `0x004b2b70`, + `0x004b3160`, `0x004b2c10`, `0x004a9460`, and `0x004ab980`. The prompt or bitmap cluster is + tighter too: selector `0x48` consumes one 12-byte record, either marks the current-session bit + directly or opens localized prompt `0x0b81` through `0x00469a50` and callback `0x004719c0`, + and then republishes selector `0x49`; selector `0x49` turns that 12-byte result into one keyed + bitset object and republishes selector `0x47`; selector `0x47` consumes the resulting ten-slot + masks and drops straight into `0x004eb230` plus + `shell_resolve_merger_vote_and_commit_outcome` `0x004ebd10`. The same pattern repeats one + size smaller for selectors `0x4c`, `0x4d`, and `0x4b`: selector `0x4c` consumes one 10-byte + record, either marks the current-session bit directly or opens localized prompt `0x0b82` + through `0x00469a50` and callback `0x00471d50`, selector `0x4d` folds that 10-byte result into + the keyed bitset object, and selector `0x4b` turns the resulting masks into one ten-dword cache + setter at `0x0050c4e0` rooted at `0x006d1a08` plus the paired outcome resolver + `0x0050c940`. The direct setter strip after that is explicit too: selector `0x4f` republishes + selector `0x6f` when the live session object exists and dataset + gate `0x006cd91c` is clear, selector `0x50` copies `[dataset+0x9058]` into `[dataset+0x9054]`, + selector `0x51` derives one small session-status code and either republishes selector `0x52` or + shell control `0x109`, selectors `0x55`, `0x56`, and `0x57` directly store dataset field + `0x9860`, a `0x006ceb9c` inline name, and guard field `[entry+0x1e1]`, selector `0x58` flushes + the deferred 16-slot named-profile clear queue `[dataset+0x9864..+0x9873]`, selector `0x59` + derives one roster or capacity status and republishes selector `0x5a`, selector `0x5b` is + another token-staging forwarder into selector `0x5c`, selector `0x5c` gates a + `0x00493960` dispatch plus optional local `0x0046f870` apply, and selector `0x5d` validates + one payload string before republishing selector `0x5e`. The next registered band around selectors + `0x5e..0x7d` is tighter too. Selector `0x5e` updates the named-profile side table + `0x006ceb9c`, mirrors the same string into the resolved live session object, and when the + session-side guard is active hashes that string back into `[session+0x48]` and dataset field + `[0x006cd8d8+0x8f48]`; selector `0x5f` then stages the current year-derived token and republishes + into selector `0x60`, whose body writes one guarded byte field into the same `0x006ceb9c` entry + family. The `0x62..0x64` strip forms the same kind of pair over `0x0062be10`: selector `0x62` + copies one fixed `0x32`-byte band into the matched company entry, selector `0x63` rejects + duplicate field-`0x37` values before forwarding, and selector `0x64` applies that same dword + field directly into the matched entry or one live fallback owner. The receive-side correction is + explicit now too: selector `0x6b` is the tiny local metric-apply wrapper + `0x00472db0 -> 0x0046f870`, selector `0x6c` is the separate train-record wrapper + `0x00472dc0 -> 0x0046d780`, selector `0x6d` formats localized status `0x0f4e` into the grounded + world outcome-text buffer `[world+0x4b47]`, and selector `0x6e` walks the current keyed bucket + under `[session+0x2580]` and marks the first matching companion record by payload hash. The + later wrappers are cleaner too: selectors `0x71`, `0x73`, `0x75`, `0x77`, `0x79`, `0x7b`, and + `0x7d` are all token-staging forwarders into selectors `0x72`, `0x74`, `0x76`, `0x78`, `0x7a`, + `0x7c`, and `0x7e`. Beneath them, selector `0x72` is the heavier counted live-world apply path + over `0x0062b2fc`, `0x0062b26c`, and `0x0062bae0`; selector `0x74` dispatches a resolved + company-entry id into `0x0062b26c` under the small latch `0x006ce9a8`; selectors `0x76`, + `0x7a`, and `0x7c` resolve one company-style entry and then tail into narrower local handlers; + and selector `0x78` is the broader projection-or-notify body over `0x0044b160`, `0x00538e00`, + and the local-session refresh strip. The next adjacent owner `0x0046e5c0` is broader but still + belongs to the same structural neighborhood: in mode `1` it serializes a dual-collection metric + blob from `0x0062be10` and `0x006ceb9c`, writing the two row counts into local header bytes and + then packing one `0x24`-stride band plus one `0x2c`-stride band behind a `0x10`-byte header; the + opposite branch starts validating and applying those packed metrics back into live entries. So + that first named block is no longer just a string-name registry; it already includes a real typed + static-record family beneath the preview dataset, and it now sits directly beside one broader + fixed-record callback-successor strip. Right after the selector-`0x71` batch publisher, the local + `0x005ce418` fixed-record family becomes explicit: `0x00473ce0` constructs one `0x187`-byte + record from two copied strings, shell-profile bytes `[0x006cec78+0x0d/+0x0f/+0x11]`, owner field + `[this+0x04]`, and monotonic sequence dword `[this+0x14]` seeded from `0x006cea48`; + `0x00473dc0`, `0x00473e70`, `0x00473ee0`, and `0x00473f30` are the max-sequence, min-sequence, + previous-sequence, and next-sequence queries over the same live collection; `0x00473e20` is the + boolean scan for any inactive record with a nonzero owner dword; and `0x00473f80` is the real + allocator or constructor owner, trimming the collection down to `0x19` entries, allocating one + live record through `0x00518900`, and then dispatching the heavier constructor. So the callback + registry now leads directly into a concrete preview-side fixed-record collection, not into + another anonymous transport helper band. The broader snapshot/apply owner still sits over the + same multiplayer collection state. In parallel, + `multiplayer_register_session_event_callbacks` allocates and registers the separate session-event + transport object at `0x006cd970`. The shell-side bridge into that deeper transport cadence is now + tighter: `multiplayer_window_service_loop` and neighboring reset or initializer branches call + `multiplayer_flush_session_event_transport`, which forces one status flush and then drops into + `multiplayer_transport_flush_and_maybe_shutdown`. That wrapper in turn runs + `multiplayer_transport_service_frame`, the recurring pump that services one worker step through + `multiplayer_transport_service_worker_once`, sweeps the transport-owned callback tables and field + caches through `multiplayer_transport_service_route_callback_tables`, services both the auxiliary + status route and the current live route through + `multiplayer_transport_service_status_and_live_routes`, and then descends one layer farther into + the shared GameSpy route helper `multiplayer_gamespy_route_service_frame` at `0x58d040`. The + transport also owns a separate selector-view sidecar beneath that route cadence. + `multiplayer_transport_ensure_selector_view_store` allocates the keyed selector-view store at + `[transport+0xab4]`, `multiplayer_transport_find_selector_view_entry_by_name` resolves entries + from that store, `multiplayer_transport_upsert_selector_name_entry` marks per-slot activity and + flags inside each entry, and `multiplayer_transport_mark_selector_slot_views_dirty` plus + `multiplayer_transport_reset_selector_view_entry_runtime_state` manage the dirty or refresh fields + at `+0xa0`, `+0xa4`, and `+0xa8`. That selector-view maintenance path is now split more cleanly + too. The recurring owner is `multiplayer_transport_service_selector_view_refresh_cycle`, which + first runs the fast deferred-probe lane: + `multiplayer_transport_collect_refreshable_selector_view_entries` walks the store through + `multiplayer_transport_filter_insert_refreshable_selector_view_entry`, which now shows that + `[entry+0x64]` is not a generic flag bucket but the third selector-slot flag word, parallel to + `[entry+0x5c]` and `[entry+0x60]`. In that collector, the `g` and `a` mode-letter bits produced by + `multiplayer_transport_parse_selector_mode_letters` become mask `0x0c` in the slot-local flag + words, and any third-slot entry carrying those bits at `[entry+0x64]` is excluded from the + refreshable set. Eligible entries then pass slot-aware retry timing on `[entry+0x68]`, + `[entry+0x6c]`, `[entry+0x78]`, and `[entry+0x7c]`, after which the service loop schedules refresh + probes through `multiplayer_transport_schedule_selector_view_entry_refresh_probe`. That fast lane + is narrower now too: the entry-side match key `[entry+0x50]` is no longer just an opaque request + field. The profile-key callback lanes feed + `multiplayer_transport_parse_selector_view_probe_marker`, which decodes one local `X%sX|%d` marker + into a probe request id plus displayed version/build integer, and + `multiplayer_transport_arm_selector_view_probe_tracking` stores those into `[entry+0x50]` and + `[entry+0x54]` before arming the live probe gate at `[entry+0x58]`. The current-selector callback + root at `0x59f8b0` is now bounded as well: it resolves and upserts the active selector name, + optionally reuses a cached `username` marker to arm probe tracking immediately, then submits the + same profile-key bundle with selector context and forwards that selector through callback slot + `17`, with the status-route side able to force route-mode transitions `2 -> 3 -> 4` afterward. One + layer lower, `multiplayer_transport_handle_profile_key_query_result` at `0x596970` now bounds the + per-key result path itself. It treats `username` as the probe-marker field, `b_flags` as the + selector mode-letter field, and `(END)` as a real sentinel that publishes a zeroed slot-`22` + payload instead of a marker pair. The same helper also hashes the selector-name, key-name, and + resolved value text back into the caller table, so the profile-key bundle now looks like a real + bounded handoff rather than an anonymous callback cloud. The deferred callback shim + `multiplayer_transport_dispatch_selector_view_refresh_probe_result` then walks the keyed store + through `multiplayer_transport_finish_selector_view_refresh_probe_if_matching`, which only + completes entries whose pending latch `[entry+0x74]` is still armed and whose parsed marker + request id `[entry+0x50]` matches the finished request. A failed result `-1` clears the pending + latch and increments the consecutive-failure counter at `[entry+0x7c]`. A nonfailure result clears + the pending latch, increments the success generation at `[entry+0x78]` and total-success count + `[entry+0x98]`, clears `[entry+0x7c]`, stamps the last-success tick at `[entry+0x6c]`, appends the + returned sample into the short rolling history at `[entry+0x84..]`, grows the bounded sample-count + `[entry+0x94]` up to four, computes the current average into `[entry+0x80]`, and then publishes + that averaged `ms` sample through `multiplayer_transport_enqueue_callback_slot24_record`. So the + publication boundary is explicit and the request-id ownership is explicit: `[entry+0x80]` now + reads as the averaged millisecond probe sample and `[entry+0x54]` as the displayed version/build + companion integer. The adjacent route-callback side is tighter too, but it is now kept separate: + the staged route-callback path at `0x5958e0` and the later compatibility gate at + `multiplayer_transport_route_binding_matches_route_callback_descriptor_tuple` `0x595d00` operate + on a compact GameSpy-style server or route descriptor family with a primary endpoint tuple at + `[descriptor+0x00]/[+0x04]`, an optional secondary endpoint tuple at `[descriptor+0x08]/[+0x0c]`, + string-key lookups such as `hostname` and `gamever`, and numeric-key lookups such as + `numplayers`, `numservers`, `numwaiting`, and `gsi_am_rating`. The route-binding side uses that + descriptor family's primary dword and host-order port plus the optional secondary tuple against + route-binding offsets `+0x54/+0x58` and route word `+0x30`. Current evidence still does not prove + that descriptor tuple is the same field family as the selector-view marker companion integer at + `[entry+0x54]`. The higher compact decode owners are tighter now too: `0x5907d0` is the + allocate-and-append lane for one self-consistent compact payload, while `0x590d00` is the keyed + upsert-by-primary-endpoint lane that reuses an existing descriptor when possible and then notifies + the owner callback. The route-callback-table runtime above that decode side is tighter now too: + `multiplayer_transport_route_callback_table_construct` `0x5905e0` seeds one transport-owned + table block, `multiplayer_transport_route_callback_table_release_decoded_schema_dictionary` + `0x5906f0` tears down the decoded schema dictionary rooted at `[this+0x08]`, + `multiplayer_route_callback_runtime_acquire_shared_string_copy` `0x590540` and + `multiplayer_route_callback_runtime_release_shared_string_copy` `0x5905a0` now bound the shared + string pool used by that decoded schema, and the higher bring-up owner `0x596090` now clearly + splits between `[transport+0xba4]` with owner callback `0x595a40`, the local field-cache family + `[transport+0x1724]` seeded through `0x5a08f0/0x595b60`, and `[transport+0x1164]` with owner + callback `0x595bc0`, while + `multiplayer_transport_route_callback_table_service_receive_decode_state_machine` `0x5908c0` + is the current live receive/decode state machine serviced by `0x591290` in table states `2/3`. + The callback-owner mode split above that runtime is now explicit too: append-notify `0x590370` + publishes mode `0`, compact upsert `0x590d00` publishes mode `1`, remove-notify `0x590430` + publishes mode `2`, and the live receive/decode path `0x5908c0` publishes modes `6`, `5`, and + `3`. + The route-handle lifecycle above that decode path is tighter now too: `0x590740` cleanly resets + one table's live route plus decode-side runtime without destroying the outer object; `0x5907a0` + is the broader destroy path that also releases the active descriptor collection; `0x590ed0` + opens the live route handle into `[this+0x4a0]`, stages the initial outbound request, and seeds + state `3` plus the staged receive buffer; `0x5911e0` is the state-`2/3` socket-service wrapper + that reads new bytes, grows the staged buffer, and re-enters `0x5908c0`; `0x5912c0` is the + one-shot send-with-reopen-retry helper; and `0x590ea0` is the shared disconnect publication and + reset tail. The recurring service helper `0x591290` is tighter too: it now first clears the + staged intrusive descriptor list through `0x590490` before entering the state-driven seed-or- + receive branch. The upstream owners are tighter too: `0x5962e0` is now the field-subscription + route-table opener above `[transport+0xba4]`, while `0x596530` is the `gsi_am_rating` reopen + path above `[transport+0x18bc]`. On that latter branch, `0x590dc0` is now bounded as the + state-`0` raw-endpoint seed pass over the live route handle, repeatedly pulling endpoint tuples + through `0x58bc7e` record type `0x1f3` before stamping descriptor flag byte `0x15` with `0x11`. + That makes the remaining source-flag meaning narrower too: current evidence now supports reading + byte-`0x15` bit `0x1` as a primary-endpoint-seed or endpoint-only marker. In the `gsi_am_rating` + dispatcher, clear-bit descriptors can take the richer direct transition lane, while set-bit + descriptors are staged through the queued enrichment path and still suppress that direct + transition even after the ready bit arrives. + The adjacent capacity-descriptor side is tighter too: `0x595bc0` now clearly publishes a + descriptor block from live descriptor properties `hostname`, `numwaiting`, `maxwaiting`, + `numservers`, and `numplayers` plus three carried sidecar scalars. That sidecar at + `[transport+0x1778]` is tighter now too: current evidence says it behaves as one cached pointer + into the transient work-record family at `[transport+0x1780]`, because every meaningful branch + in `0x595bc0` reads the same `+0x0c/+0x10/+0x18` metadata triplet and replay modes later consume + the pointer through `0x5933a0`. The negative result is stronger too: local text-side xrefs still + show no direct store to `[transport+0x1778]`, and a wider local sweep also failed to show any + obvious `lea`-based replay-band writer. The transient-request lifecycle tightens that further: + `0x593330/0x593370/0x593380/0x5934e0/0x5933a0` now fully bound `[transport+0x1780]`, `0x1784`, + and `0x1788` without ever touching `[transport+0x1778]`, and the neighboring active-opcode reset + helper `0x5929a0` is likewise scoped only to `[transport+0x17fc]`. A broader constructor and + teardown pass tightened that further too: `0x596090`, `0x5961b0`, and `0x5962e0` all touch the + neighboring replay-band fields without ever seeding `[transport+0x1778]`. A full-binary + literal-offset sweep tightens it further still: the only direct `0x1778` hit in `RT3.exe` is + the read in `0x595bc0`. One nearby ambiguity is now closed too: the + mode-`5` mirror path in `0x595a40` and `0x595e10` does not target `[transport+0x1778]`; it + writes `[transport+0x54]` and mirrors the same staged route companion dword only into queue-side + slot `[transport+0x1724+0x24]` through `0x005a0940`. So the sidecar writer remains upstream of this + leaf publisher. Mode `0` is now also tied more cleanly to the generic descriptor append-notify lane + at `0x590370`, while mode `2` stays outside this helper as the separate + remove-notify-and-stage path at `0x590430`. The opcode-`2` payload boundary is tighter too: + `0x592ae0` now grounds that payload + as a seven-dword block with an owned string slot at `+0x08`, so live mode supplies a populated + payload while modes `3` and `5` deliberately enqueue an all-zero payload and reuse only + the wrapper-side sidecar metadata. Those two modes are tighter now too: they are the live + receive-state owner callbacks emitted by `0x5911e0 -> 0x5908c0`, not loose generic replay + guesses. So those paths are better read as delayed metadata replays over one cached work record, + not over a separate anonymous cache blob. The neighboring + capacity-owner split is tighter now too: `0x595bc0` only stages descriptor records for modes + `0`, `3`, and `5`; the upstream route-callback-table owner still delivers modes `1`, `2`, and + `6`, but those are explicit no-ops in this capacity leaf. So the owner wiring itself is no + longer the open edge; only the upstream sidecar producer remains unresolved. The neighboring + work queue is tighter too: `0x593330/0x593370/0x593380` now bound `[transport+0x1780]` as the + construct/clear/destroy owner family, while `0x5933a0`, `0x5934e0`, and `0x593570` ground the + remove, allocate, and completion side over that same collection. The small sibling `0x593400` is + tighter too: it is a pure work-record uniqueness predicate over field `+0x0c`. Its caller is + tighter now too: `0x58d720` is an immediate-drain quiescence gate over one transport context id, + using `0x593400` for the queued work family at `[transport+0x1780]` and `0x592970` for the + active opcode-record collection at `[transport+0x17fc]`. The strongest current read is that + `0x5934c0` seeds that shared drain context id first, then the transport copies it into queued + work field `+0x0c` and active opcode-record field `+0x14` before the immediate-drain roots wait + on one shared disappearance test rather than on a vague settle loop. The currently grounded + roots are `0x58df20`, the neighboring formatted selector-text publish path at `0x58dfb0`, and + callback-table registration at `0x58e200`. The active-opcode side is tighter too: `0x5927b0` + now bounds the per-record service-and-retire path, `0x592800` the wider context-or-idle sweep, + `0x5929a0` the remove-by-opcode-type sweep, and `0x5929f0` the narrower opcode-`3` + field-snapshot removal keyed by the subscribed callback-pair payload. That also corrects + `0x595b80`, whose final cleanup is an active field-snapshot purge rather than a queued-work + drain. The adjacent route-callback descriptor-table lifecycle is tighter too: `0x590410` now + grounds `[table+0x5bc]` as the staged intrusive descriptor-list head, `0x590430` is the generic + remove-notify-and-stage lane, `0x590490` releases the staged list, and `0x5904d0` releases the + active descriptor collection before tearing that staged list down. That also makes the earlier + `0x5962e0` “release active descriptors” step explicit. The callback-table attach side now constrains the + same work-record metadata family a little further too: `0x593650` deliberately duplicates its + first caller metadata dword into both fields `+0x0c` and `+0x10`, while carrying the second + caller metadata dword in `+0x18`. The lower opcode wrappers are tighter now too: `0x592a40` + turned out to be the explicit opcode-`1` trigger wrapper whose constructor is a no-op and whose + active-side service is `0x5913c0`, while `0x592c40` is the real `0x08`-byte explicit opcode-`5` + binding leaf. The earlier opcode-`4` read was just the table-indexing mistake in `0x5928a0`: + selector `4` lands on the row at `0x5e2044`, not the row at `0x5e2034`. The producer side is tighter too: + bound-route requests, selector-text route requests, and the type-`9` text fastpath also stage + that same triplet through `0x5934e0`, and the fastpath shim `0x593d00` now gives the cleanest + proof of the callback split by only re-emitting the follow-on lane when `+0x10` is nonnull and + then forwarding `(+0x10, +0x18, +0x0c)` into `0x593170` as callback function, callback + companion, and trailing drain context. So the replay-side triplet is clearly a broader + transport callback-wrapper family, not one fixed route-only tuple. The nearby + field-subscription side is tighter too: `0x592b50` now clearly uses `[transport+0x1774]` as a + cached progress percentage under `[transport+0xba4]`, and `0x5962e0` seeds that percentage to + `1` just before the first immediate mode-`3` snapshot. The nearby route-callback-table + lifecycle is tighter now too: `0x596090` seeds `[transport+0xba0]` as the callback-plumbing + enable latch, clears staged payload slot `[transport+0xb50]`, and constructs the three owner + branches rooted at `[transport+0xba4]`, `[transport+0x1164]`, and `[transport+0x18bc]`; + `0x596210` is the recurring service sweep over those same three tables plus the local field + cache and queued-descriptor family; `0x596060` is the explicit `gsi_am_rating` reset; and + `0x596530` is the reopen-from-stored-label sibling above that same am-rating table. The + matching local cleanup is tighter too: `0x5962c0` is the explicit staged route-callback payload + clear on `[transport+0xb50]`, while `0x595ce0` now clearly resets only the capacity-descriptor + route callback table at `[transport+0x1164]`, not the field-subscription table at + `[transport+0xba4]`. The remaining gap on the capacity side is therefore narrower: the carried + sidecar fields themselves now read more cleanly as the cached callback-wrapper triplet reused + elsewhere (`drain context id +0x0c`, `callback fn +0x10`, `callback companion +0x18`), and the + negative result is stronger too: nearby replay-band fields `[transport+0x176c]`, + `[transport+0x1770]`, `[transport+0x1774]`, `[transport+0x177c]`, `[transport+0x1780]`, and + `[transport+0x1784]` all have direct local owners while `[transport+0x1778]` still appears only + as the single read in `0x595bc0`; even the broader callback-owner lifecycle now skips it while + seeding, servicing, resetting, reopening, or tearing down those neighboring tables and caches. + The constructor now closes that local search further: `0x58dc50` bulk-zeroes the full transport + body and still never writes a nonzero value into `[transport+0x1778]` before later explicit + neighbor initialization. The callback-binding owner stack now tightens that boundary too: + `0x5934e0` stages the shared work-record metadata triplet, `0x593650` binds it into the + callback-table worker path, and `0x593570` later consumes and republishes it, while + `[transport+0x1778]` still appears only as the borrowed sidecar read in `0x595bc0`. So this + edge is now locally closed, and the remaining producer looks like an upstream callback or worker + handoff rather than one missing ordinary field store in the local cluster. The adjacent staged-route + callback side is tighter too: `0x595860` is now bounded as the + submit-result handler beneath `0x5958e0`, and the old `[transport+0xac0]` ambiguity there is now + gone. That branch is using the already-grounded third selector-generation counter at `[0xac0]` + together with target `[0xb48]` to decide whether staged route-callback traffic can push the + multiplayer route-mode ladder from `2` into `3` and later `4`. The selector-view counter beneath + that gate is tighter now too: `0x594e30` counts slot-`2` entries whose flag dword carries bit + `0x20`, optionally filtered by the current transport name buffer. The selector-view mutation + family under that same lane is tighter too: `0x594a30` is now the direct keyed-store remover, + `0x594fb0` clears one selector-slot ownership pointer plus its slot-local flag dword and drops + the whole entry when no slots remain, `0x595010` rekeys one selector-view entry under a new name + while preserving the `0x40..` runtime band, and callback root `0x59f9c0` now reads as the + sibling lane that clears one named selector-view slot, publishes callback slot `18`, and may + still re-enter the route-mode setter from the same slot-`2` status and generation gates. The + neighboring callback roots are tighter now too: `0x5950a0` clears one selector slot from every + selector-view entry in the keyed store, `0x59fab0` is the rename or relabel sibling above + `0x595010`, `0x59faf0` updates one selector slot's fixed sample-text buffer and refreshes the + active selector object when present, and `0x59fb60` replaces one selector slot's name set, + requests the default profile-key bundle for that slot, and publishes callback slot `20`. Slot + `16` is tighter now too: current grounded caller `0x59f440` forwards the staged route-callback + payload handle from `[transport+0xb50]` through `0x592ea0` just before route mode `5`. The + last adjacent callback root in that block is tighter now too: `0x59fbd0` is the built-in + per-slot profile-key query sibling. It resolves the caller selector name into one slot index, + forwards the caller trio into `0x596b90`, and then publishes callback slot `28`; that lower + helper indexes one slot-specific built-in string pair from `[transport+0x189c]` and + `[transport+0x18ac]`, reuses the generic per-key handler `0x596970`, and only republishes slot + `28` when that lower query path succeeds. + The compact-header side is tighter now too: `0x58fe20` and `0x58ff20` now show that compact + payloads always carry the primary IPv4 dword and that header bit `0x10` only gates whether the + primary port word is inline or inherited from the owner default port. `0x58fe90` now validates + the `0x40` inline keyed-property vector against the owner schema, and `0x58fe50` validates the + signed-`0x80` trailing string-pair tail before decode. `0x58ff60` then grounds bit `0x02` as + the inline secondary IPv4 dword branch, bit `0x20` as the paired secondary-port word branch with + owner-port fallback, bit `0x08` as one still-unresolved auxiliary dword stored at + `[descriptor+0x10]`, bit `0x40` as one inline keyed-property vector decoded through the + property-store writers, and signed bit `0x80` as one trailing string-pair tail. The + descriptor-state side is tighter now too: the shared queue helper at + `0x005a09a0` stamps pending state `0x4` for the local field-cache family `[transport+0x1724]` + and pending state `0x8` for the `gsi_am_rating` queued-descriptor family `[transport+0x1e7c]`, + while later service through `0x005a0c80` promotes those pending tags into ready bits `0x1` and + `0x2` in descriptor byte `[entry+0x14]`. That makes the current transport-side tests cleaner: + `0x58d1c0` is the field-cache ready gate, `0x58d1d0` is the `gsi_am_rating` queued-descriptor + ready gate, and `0x58d230` is the remaining flag-byte split between direct primary-endpoint + handling at `[transport+0x18bc]` and the queued path at `[transport+0x1e7c]`. That byte-`0x14` + story is no longer queue-only either: `0x58ff60` can also OR in bit `0x1` after the inline + keyed-property vector and bit `0x2` after the signed string-pair tail. The flag-byte split is no + longer purely behavioral either: current evidence now says byte `[descriptor+0x15]` bit `0x1` is + a source-side descriptor header bit, explicitly seeded during the primary-endpoint table refresh + around `0x590dc0` and preserved by the compact descriptor decode path at `0x58ff60`, rather than + a queue-generated runtime state. The `gsi_am_rating` dispatcher side is tighter too: that same + bit no longer just looks like a direct-versus-queued routing split, because `0x595e10` also uses + it to suppress the direct `0x595dc0` transition even after queued ready bit `0x2` is present. + The descriptor body is tighter too: `[descriptor+0x20]` is now the intrusive next-link used by + the transport-owned primary-endpoint list headed at `[table+0x5bc]`, and `[descriptor+0x1c]` is + now the special numeric scalar behind the current `queryid`/`ping` fallback pair. The compact-only + auxiliary dword at `[descriptor+0x10]` is tighter in a negative way too: local xref scans now + only show it being preserved by later generic helpers like + `generic_record_0x1c_deep_copy_with_owned_string_at_0x08` `0x591410` and the adjacent + callback-marshaling wrappers `0x591480` and `0x591510`, not read through any dedicated semantic + accessor yet. The route-event dispatcher side is tighter too: the mode-`5` tails in both + callback families do not copy a descriptor-local field but instead mirror the transport-staged + companion dword at `[this+0x490]` into `[this+0x54]` and queue-side slot `[this+0x1724+0x24]`. The + `gsi_am_rating` maintenance lane is tighter now too: after pruning failed descriptors it sorts + the surviving primary-endpoint table through `0x590310` in mode `1` with key `gsi_am_rating`, + then selects the new head through `0x590480` before re-entering the route-transition path. The + same service loop also owns a slower sidecar lane keyed off `[entry+0xa4]`: + `multiplayer_transport_select_stale_selector_view_progress_entry` walks the store through + `multiplayer_transport_pick_stale_selector_view_progress_entry`, picks one stale entry whose + progress latch `[entry+0x9c]` is clear and whose last progress tick `[entry+0x70]` is old enough, + and then hands it to `multiplayer_transport_stage_selector_view_progress_snapshot`. That helper + now looks more bounded too: it rebuilds the core `X%sX` marker text from `[entry+0x50]` through + `multiplayer_transport_format_selector_view_probe_marker_core`, formats one `PNG %s %d` line + around that marker and the entry-local averaged millisecond sample at `[entry+0x80]`, appends bounded + selector-slot `PNG` fragments for live overlapping slots, marks progress-snapshot state in flight + at `[entry+0x9c]`, and stamps both `[entry+0x70]` and the transport-wide throttle tick + `[transport+0xaec]`. So the selector-view sidecar no longer looks like one undifferentiated + refresh bucket: it has a faster deferred-probe lane plus a slower progress-snapshot lane, both + still under the shell-owned multiplayer transport cadence. The two descriptor lanes installed by + `multiplayer_transport_attach_callback_table_descriptor` are now tighter too. The first lane + rooted at `0x59f5c0` can arm deferred-close state on the owner transport and then forward through + callback slot `23`. The second lane is no longer just a loose selector-view bucket: + `multiplayer_transport_callback_dispatch_selector_name_payload_lane` at `0x59f650` classifies + selector payloads through `multiplayer_transport_is_selector_control_line`, routes `@@@NFO` + control lines into `multiplayer_transport_sync_selector_view_nfo_r_flag`, and otherwise publishes + either callback slot `13` or the split token-plus-tail callback slot `14` through + `multiplayer_transport_split_selector_payload_token_and_tail`. That local `@@@NFO` helper is now + bounded more tightly too: it only accepts lines ending in the literal `X\` tail, searches for the + field marker `\$flags$\`, and then sets or clears bit `0x2` in the third selector-slot flag word + at `[entry+0x64]` depending on whether that field contains the letter `r` before the next + backslash. The sibling `multiplayer_transport_callback_dispatch_current_selector_payload_lane` at + `0x59f720` first resolves the active selector through `0x5951a0`, then handles the + current-selector variants of the same control vocabulary: `@@@NFO` continues into the same local + `r`-flag sync helper, `@@@GML` plus mode-`3/4` payloads feed the shared control-token helper + `multiplayer_transport_handle_gml_or_png_selector_control`, and the remaining non-control payloads + publish callback slot `9`. That shared helper now narrows the `GML` and `PNG` split materially: + when the token is `GML` and the tail is `Disconnected`, it requires the active selector-view entry + to pass `multiplayer_transport_selector_view_entry_has_gml_disconnect_gate`, which currently means + the entry participates in the third selector slot and has bit `0x20` set in `[entry+0x64]`, before + it forces one status-pump pass, emits callback slot `16`, and re-enters route mode `5`. Its + sibling `PNG` branch resolves a named selector-view entry from the tail text and, when that entry + overlaps the active selector-slot ownership, refreshes selector-view runtime state through + `0x5948f0` and republishes callback slot `25`. Alongside those dispatchers, one grounded branch at + `0x59f560` still updates selector-view runtime state through `0x5948f0` and forwards the same + selector-name pair through callback slot `25`, while `0x59f850` resets selector text state through + `0x5954b0`, forwards through callback slot `19`, and when selector `2` is active in a nonterminal + route mode re-enters `multiplayer_transport_set_route_mode` with mode `1`. The low-level route + helper still looks like a two-part cycle: + `multiplayer_gamespy_route_service_retry_and_keepalive_timers` handles challenge or retry pressure + and periodic outbound control traffic around the `master.gamespy.com`, `PING`, `natneg`, + `localport`, `localip%d`, and `statechanged` strings, while + `multiplayer_gamespy_route_drain_inbound_packets` drains inbound datagrams and dispatches + semicolon lines, backslash-delimited key bundles, and `0xfe 0xfd` GameSpy control packets. The + transport-owned callback story is now narrower too. The shared route constructor + `multiplayer_gamespy_route_construct_and_seed_callback_vector` seeds `[route+0x88]` through + `[route+0x9c]` from the caller-supplied transport callback table, records the owner transport at + `[route+0x104]`, and explicitly zeroes `[route+0xa0]`, `[route+0xa4]`, and `[route+0xd4]` before + any later patch-up. For the transport-owned status route, + `multiplayer_transport_try_connect_status_route` then patches `[route+0xa0]` through + `multiplayer_gamespy_route_set_extended_payload_callback` to point at + `multiplayer_transport_forward_validated_extended_route_payload` `0x00597330`, which simply + forwards the validated payload wrapper into the owner callback at `[transport+0x17f4]` with + context `[transport+0x17f8]`. The grounded live-route connect path at + `multiplayer_transport_try_connect_live_route` does not currently perform any matching + post-construction patch for `[route+0xa0]`, `[route+0xa4]`, or `[route+0xd4]`, and the higher + route-mode state machine now looks consistent with that: `multiplayer_transport_set_route_mode` + latches the requested small mode at `[this+0x18b8]`, then uses mode `0` for the direct-versus + queued `gsi_am_rating` split, mode `1` for the ready-bit plus queued fallback, mode `2` for + pending-descriptor cleanup, mode `3` for the empty-table fallback, mode `4` for deferred + route-status recovery, and mode `5` for copying the staged route companion dword into `[this+0x54]` + and queue-side slot `[this+0x1724+0x24]`. The current grounded mode transitions still switch by releasing route + objects through `multiplayer_gamespy_route_release_and_free` and rebuilding them through + `multiplayer_transport_try_connect_live_route`, not by mutating callback slots in place. The + parser behavior is now tighter as well: semicolon lines only dispatch when + `[route+0xd4]` is non-null, and the subtype-`6` raw fallback only dispatches when `[route+0xa4]` + is non-null. For the currently grounded transport-owned status and live routes, those two branches + therefore remain optional and can cleanly no-op instead of implying a hidden mandatory callback + path. Inside the packet parser, subtype `4` is no longer an unknown callback hop: after cookie + validation it dispatches through `[route+0x9c]`, which the transport-owned status and live routes + seed to `multiplayer_transport_handle_validated_route_cookie_event` `0x005972c0`. That helper + either marks route progress and re-enters `multiplayer_transport_set_route_mode`, or forwards the + event id plus payload into the owner callback at `[transport+0x17f0]` with context + `[transport+0x17f8]`. The surrounding status-route callback vector is tighter now too: + `0x005970e0` publishes either the active selector text or the averaged probe sample at + `[entry+0x80]` and otherwise falls back to owner callback `[transport+0x17e0]`; + `0x00597180` is a straight owner-forwarding lane through `[transport+0x17e4]`; + `0x005971b0` seeds the local status-control id list and can then notify owner callback + `[transport+0x17e8]`; and `0x00597270` returns the third selector-slot generation counter + `[transport+0xac0]` on its bounded local branch before falling back to owner callback + `[transport+0x17ec]`. Subtype `6` still validates the same cookie, dedupes one 32-bit cookie or + packet id, and then dispatches the trailing payload through the natneg-or-raw callback layer + rooted at `[route+0xa0]` and `[route+0xa4]`. This separates the shell-frame preview refresh at + `0x006cd8d8` from the actual transport cadence at `0x006cd970`, and also separates that transport + cadence from the lower GameSpy route-service and packet-parser layer beneath it. +- Evidence: `function-map.csv`, `pending-template-store-management.md`, + `pending-template-store-functions.csv`, plus objdump caller traces showing + `multiplayer_window_service_loop` reaching `multiplayer_flush_session_event_transport` and the + transport pump chain `multiplayer_flush_session_event_transport -> + multiplayer_transport_flush_and_maybe_shutdown -> multiplayer_transport_service_frame -> + multiplayer_transport_service_worker_once -> multiplayer_transport_drain_request_text_queue`. +- Open Questions: unresolved request-id semantics for `1`, `2`, `4`, and `7`; whether any + non-mode-path helper outside the currently grounded release-and-rebuild flow ever patches + `[route+0xa4]` and `[route+0xd4]` for the transport-owned status/live routes, or whether those + packet families are simply unused in this stack; and how far the Multiplayer preview-dataset + machinery is reused outside `Multiplayer.win` beyond the currently grounded `.gmt` save-mode hook. + diff --git a/docs/control-loop-atlas/next-mapping-passes.md b/docs/control-loop-atlas/next-mapping-passes.md new file mode 100644 index 0000000..d6fe4ab --- /dev/null +++ b/docs/control-loop-atlas/next-mapping-passes.md @@ -0,0 +1,9 @@ +## Next Mapping Passes + +- Resolve the owner-side callback roles behind the validated GameSpy packet branches, especially + `[route+0x9c]`, `[route+0xa0]`, `[route+0xa4]`, and `[route+0xd4]`. +- Determine whether any later world-mode branch beneath the frame owner bypasses the shell + controller input path for non-cursor gameplay input, since the current grounded overlay and cursor + helpers still reuse `0x006d4018`. +- Keep detailed pending-template or transport work scoped to the specific atlas edges that remain + unresolved. diff --git a/docs/control-loop-atlas/presentation-overlay-and-frame-timing.md b/docs/control-loop-atlas/presentation-overlay-and-frame-timing.md new file mode 100644 index 0000000..6dd4199 --- /dev/null +++ b/docs/control-loop-atlas/presentation-overlay-and-frame-timing.md @@ -0,0 +1,32 @@ +## Presentation, Overlay, and Frame Timing + +- Roots: the bootstrap-owned `shell_service_pump_iteration` at `0x00483f70`, the shell-state service + pass `shell_state_service_active_mode_frame` at `0x00482160`, the installed global shell + controller at `0x006d4024`, the pending frame-cycle owner `shell_service_frame_cycle` at + `0x00520620`, and the frame-time history path under `shell_update_frame_time_history` at + `0x0051fd70`. +- Trigger/Cadence: recurring bootstrap-owned shell service work once the active mode, controller + window, and display runtime are live; special modal or content-building paths can also force + immediate frame servicing inside that broader cadence. +- Key Dispatchers: `shell_service_pump_iteration`, `shell_state_service_active_mode_frame`, + `shell_service_frame_cycle`, `shell_refresh_presentation_frame`, + `shell_update_frame_time_history`, `shell_get_smoothed_frame_scalar`, + `shell_set_gamma_ramp_scalar`, and overlay builders such as + `shell_queue_single_world_anchor_overlay`, `shell_queue_world_anchor_overlay_list`, and + `shell_queue_indexed_world_anchor_marker`. +- State Anchors: shell state at `0x006cec74`, active mode pointer `0x006cec78`, shell frame history + ring at `0x006d403c`, display/runtime state inside the controller block near `[this+0x114282]` and + `[this+0x11428a]`, presentation service pointer at `[this+0x0c]`, and the native controller window + handle at `[this+0x00]`. +- Subsystem Handoffs: the bootstrap-owned pump runs shell-bundle polling and shell-state maintenance + before the shell-state pass synchronizes active-mode helpers and modal-status work and dispatches + the controller frame cycle, which then consumes world/object state for overlays and presentation + refresh, uses the controller window handle for one-time `ShowWindow` and related UI interaction, + and drains the deferred work queues at the end of the cycle. +- Evidence: function-map rows for `shell_service_pump_iteration`, + `shell_state_service_active_mode_frame`, `shell_service_frame_cycle`, + `shell_flush_deferred_work_queues`, frame history, gamma ramp, world-anchor overlay builders, and + graphics runtime helpers. +- Open Questions: how simulation cadence rendezvous with the shell presentation cadence once + gameplay takes over and whether gameplay stepping exits this shell-owned controller path entirely. + diff --git a/docs/control-loop-atlas/shell-ui-command-and-deferred-work-flow.md b/docs/control-loop-atlas/shell-ui-command-and-deferred-work-flow.md new file mode 100644 index 0000000..fe40afa --- /dev/null +++ b/docs/control-loop-atlas/shell-ui-command-and-deferred-work-flow.md @@ -0,0 +1,20 @@ +## Shell UI Command and Deferred Work Flow + +- Roots: shell callback paths that converge on `shell_dispatch_ui_command` at `0x00464410`. +- Trigger/Cadence: event-driven UI command dispatch plus deferred-message queue flushing during + shell activity. +- Key Dispatchers: `shell_dispatch_ui_command`, `shell_enqueue_deferred_work_message`, + `shell_post_deferred_message_type5`, `shell_post_deferred_message_type6`, + `shell_enqueue_deferred_message_type4`, `shell_enqueue_deferred_message_type1`. +- State Anchors: shell object at `0x0062be68`, queue roots around `[this+0x11369d]`, + `[this+0x1136a1]`, and `[this+0x1136a5]`, global routing gates at `0x006d4034`, and the separate + detail-panel controller rooted at `0x006d0818`. +- Subsystem Handoffs: routes into graphics config, scenario-text export, overlay generation, + multiplayer UI, shell detail windows such as `EditorPanel.win` and `TrainDetail.win`, and + presentation-facing deferred work later drained by `shell_service_frame_cycle`. +- Evidence: function-map shell rows around `0x00464410`, `0x004d4500`, `0x004ddbd0`, and + `0x0051f1d0..0x0051f460`. +- Open Questions: whether the shell command dispatcher is also used by hotkeys or only by UI + callback tables; the current `0x006d0818` detail-panel path looks shell-only and does not yet + explain gameplay world entry. + diff --git a/docs/function-map.md b/docs/function-map.md index ffd185c..634686d 100644 --- a/docs/function-map.md +++ b/docs/function-map.md @@ -6,7 +6,9 @@ confidence. The handbook index in `docs/README.md` should stay high-level. Per-pass function additions and renames belong here and in the derived export artifacts, not in the README. High-level control-loop -and subsystem flow belongs in `docs/control-loop-atlas.md`, with this file staying function-centric. +and subsystem flow belongs in the split atlas under `docs/control-loop-atlas/`, with +`docs/control-loop-atlas.md` serving as the compatibility index and this file staying +function-centric. ## Canonical Schema diff --git a/docs/re-workflow.md b/docs/re-workflow.md index 89be959..389f89d 100644 --- a/docs/re-workflow.md +++ b/docs/re-workflow.md @@ -9,8 +9,9 @@ handoffs, then feeds the function-by-function Rust rewrite and later DLL-based r 1. Confirm the target binary and record its hash. 2. Refresh the exported baseline artifacts. -3. Update `docs/control-loop-atlas.md` with newly grounded loop roots, dispatchers, cadence points, - state anchors, or subsystem handoffs. +3. Update the relevant file under `docs/control-loop-atlas/` with newly grounded loop roots, + dispatchers, cadence points, state anchors, or subsystem handoffs, and touch + `docs/control-loop-atlas.md` only if the top-level section layout changes. 4. Analyze in Ghidra. 5. Cross-check suspicious findings in Rizin or with CLI tools. 6. Update the function map with names, prototypes, ownership, confidence, and loop-relevant notes.