rrt/docs/control-loop-atlas/event-editors-companydetail-and-loadscreen.md

423 lines
36 KiB
Markdown
Raw Normal View History

# Input, Save/Load, and Simulation: Event Editors, CompanyDetail, and LoadScreen
### 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.