# Original shell screens and mission flow

The [shell browser](../analysis/shell/index.html) joins the original GO screen
dispatcher to layouts, text, artwork, handlers and screenshots. It includes 42
states: 39 supplied DLG files and three states implemented without a DLG. GO's
`0x3c7d8` dispatch table has 41 keys; MENU888.DLG is retained outside that direct
table. Controls/calibration (1320), career introduction (1490), and the commander
briefing (1499) are code-managed. The empty MENU1499.BIN does not mean its spoken
briefing is empty: the mission ENG and portrait resources supply that content.

`build_shell_catalogue.py` extracts all branches and screen-local event tables.
It also executes original region resolver `0x40afa` for each state with all seven
previous regions: 294 resolutions. A region owns the background/presentation;
it is distinct from the currently open dialog. Main menus use region 1000,
service-bay screens 4000, debriefing 5000, briefing maps 6000, and the general's
career introduction 7000. Some destinations preserve their previous region.
The generated catalogue retains the complete mapping rather than assuming
one fixed background per screen.

## Dialog records and actions

GO `0x3a1f7` reads a short count and 13-byte records: four signed short rectangle
coordinates, byte type, byte style, byte key scan, and unsigned short action/view
ID. Child bounds are relative to the root window. Types distinguish text,
buttons, lists, value selectors, color selectors and specialized views.

The final short is screen-local. Some numbers coincide with screen IDs, while
others select a weapon, change an allocation, validate a name, or open a modal
control. Common 99/100 events mean cancel/accept, but do not bypass the owning
handler. The browser therefore shows both the ID and handler; links are lookup
aids. A button can run a script or change state without directly opening that screen.

A shortcut scan of 1 means Escape, 0x39 Space and 0x48/0x50 the arrow keys.
Dialogs without such a button need not react to Escape. In the original
captures, Escape does not leave the armament screen or repair-policy popup.
Armament's Done button returns to the briefing map. Choosing a repair policy
returns to Repairs; clicking outside or pressing Escape did not dismiss it.

## Main paths

| Path | Original screens and behavior |
|---|---|
| Single mission | Main 1000 → mission list 1100 → optional parameters 1110 → commander 1499 → map 1501 → armament 1800/1820 → map → launch 9999 |
| New career | Main → career list 1200 → registration 1210 → general's introduction 1490 → service bay 1700 |
| Campaign launch | Bay → crew 1610 / armament / briefing → commander 1499 → map 1500 → launch 9999 |
| Ordinary return | GO restores the launch context and imports simulator results, presents debrief 1520, then enters the post-mission bay 1710 |
| Service | Bay → repairs 1900 → component allocation 1920 or policies 1910; scrap warning 4444; construction 2000 (2010 is a separate registered SALVAGE layout) |
| Options | 1300 → preferences 1310, nested controls/calibration 1320, battle-set selector 1330, demo or credits |

Screens depend on campaign/single-mission context and validation. The table is
not a promise that every destination is available in every state. The supplied
launch script coordinates GO and DBSIM using DATA/EXIT.CFG. Launch writes 2;
normal simulator return writes 3, while alternate return 4 takes the same GO
return branch. Attract playback has a separate code 6 and returns to the main
menu. A loading image remaining on screen after GO exits is not a running
simulator: the batch launcher must start DBSIM next.

The retained interactive career follows real registration, crew assignment,
briefing, simulator launch, an incomplete patrol abort, debrief, repair screens,
and construction. The original incomplete-mission dialog explicitly says the
player has not visited all waypoints. The subsequent debrief says the patrol
failed and lists salvage, kills, squad losses, recovered weapons and technology.
Construction immediately spends its required salvage and marks the new HERC
under construction; the captured Roadrunner cost 50 of the available 60 tons.

## Presentation ownership and terminal paths

GO `0x3ba47` owns startup and return selection. `check_shell_presentation.py`
executes that entire decision routine for 56 combinations of exit code, career
mode, pilot condition, campaign continuation and cinematic flags. Its sinks
record programs, songs, region changes and save ordering. Rendering, file
transactions and health/campaign queries are explicit fixture boundaries;
this probe does not claim to play every ending or independently verify those
other routines. Whole return/save transactions and their limits are in
[CAMPAIGN.md](CAMPAIGN.md); ordinary live DOSBox navigation is separate evidence.

| Condition | Original selected presentation |
|---|---|
| Normal startup, cinematics enabled | INTRO1 (12): DYNAMIX.TTM and LEAD_IN.TTM; INTRO2 (13): IINTRO.TTM and EARTH_W.TTM |
| Startup skip already requested | LEAD_IN is omitted; later startup programs are still requested |
| `-a` startup | No normal startup programs; this does not suppress the new-career general's briefing |
| Attract return 6 | Main menu, without normal startup programs |
| Single-mission survivor | Presentation mode 3, debrief region 5000 |
| Single-mission pilot death | Single-mission selector 1100, without career-death movie |
| Career pilot death | DEATH (7), ENDFA.TTM when cinematics enabled, then career termination |
| Career continuation 99 | INTRO2 (13), END_WIN1/2/3.TTM, then INTRO/EARTH.TTM and termination |
| Career continuation -1 | LOSING (19), FAILED.TTM, then INTRO/EARTH.TTM and termination |
| Continuing career | Presentation mode 7, condition-dependent mechanic response and service-bay region 4000 |

Victory/failure programs are selected even with `-a`; its death/startup gates
are narrower than a universal "skip all cinematics" option. The return dispatcher
then invokes automatic repair, career-history update and save, in that order.
WIN2 is not selected by the victory branch; its retained-resource endpoint is
recorded in [MUSIC.md](MUSIC.md).

Blocking program player `0x3b8df` allocates a TTM slot through `0x4680a`, updates it
through `0x465da`, checks completion at `0x466cc`, polls skip input, presents pages,
and frees the slot with `0x469da`. The service bay instead runs multiple resident
programs: elevator doors, lighting, ambient workers, portraits and chassis-specific
repair/welding animations. The live trace confirms the original filenames,
including ELEV_L/R, SOUNDS, CHRIS3 and the chassis welding scripts. Thus the bay
is a composition of separately controlled programs rather than one movie.
Mission brief/debrief text is expanded from ENG bytecode and counters; portrait
speech also drives SNC mouth frames. See [FORMATS.md](FORMATS.md) and the
[presentation browser](../analysis/presentations/index.html).

## Persistence and capture boundaries

The private-session screenshots show MUSIC OFF surviving restart, a tentative
ON change reverting on Cancel, and accepted ON surviving a second restart.
PREFS.CFG is 17 bytes; only byte 0 changed in that sequence. The 800 isolated
original preference transactions additionally cover callbacks, partial saves,
rollback and byte arithmetic; see [INPUT.md](INPUT.md). Repair policy is separate
career/shell state, not that music preference byte.

All navigation used ordinary mouse/keyboard input on a private X server and a
copied install. The user's comparison install and saves were untouched. Named
screenshots preserve the DOSBox window, including its 320×240 aspect correction
and nested modal dialogs. A few initial direct VGA images are native 320×200.
Interaction logs retain original 320×200 input coordinates. Their sampled
main-loop ID can lag a transitional image or remain the parent during a nested
dialog; it is not an exact scene classification for every instantaneous image.

`original-navigation` used the first shell observer: its 0x4680a `name_bytes`
field selected the wrong argument and must not be used as a TTM filename.
Its unprefixed periodic raw frame/snapshot names also overlap the simulator's
names during the one GO→DBSIM→GO run. Named window screenshots and separately
copied launch/return DATA manifests remain unambiguous. `original-persistence`
uses the corrected fourth argument and `shell-` prefixes; its observed program
names are the live filename evidence. Both runs retain their original logs with
these limitations rather than silently rewriting historical events.

`build_dosbox_reference.py` rebuilds the private read-only emulator observer.
It never patches guest instructions or substitutes game input. The hardware
boundary is DOSBox; fixed cycle settings and host observation overhead remain
part of the reference configuration. `compact_shell_capture.py` losslessly
compresses completed logs/snapshots and converts PPM pixels to PNG, preserving
hashes and checking decoded bytes/pixels before removing the larger copies.

Equipment, mount selection and original bay-artwork findings are in
[ARMAMENT.md](ARMAMENT.md).

Detailed original repair, policy, construction and salvage transactions:
[HANGAR_SERVICE.md](HANGAR_SERVICE.md).

## Launch validation and occupied bays

The service-bay handler at GO 0x2d327 and map handler at 0x2c057 both check Begin
Mission for an unassigned selected pilot (3333), followed by an unarmed squad
(3000, Cancel/Proceed). The post-mission bay checks Next Mission first for a
disabled selected HERC (7770, must repair), then a disabled squad member (7771,
Cancel/Proceed). These are separate stages; the latter is not a second
preflight test. Both legs and engine must have at least 50% internal condition.
The unarmed test checks weapon ID 17 in every mount, not ammunition or condition.

The squad queries 0x1620d/0x16294 start at the retained crew cursor, test it before
advancing, and run as many iterations as there are active assigned pilots. They
retain cursor/selected-HERC side effects. An initially inactive cursor is thus
tested too and can cause the last active pilot to be skipped. The C++ owner
preserves that original ordering while bounding invalid memory access.

Build (2000) is replaced by warning 7772 when eight bays are occupied, subtracting
the construction slot if it holds a HERC so an existing build remains accessible.
The native test does not ask whether construction_remaining is nonzero.

tools/capture_launch_checks.py executes 512 mixed rosters through both original
handlers: 2,048 dispatches, capturing final event ID, crew cursor and selected
HERC. Mission preparation/export, saving and presentation ownership are explicit
sinks. The capture includes exact 49/50/51 boundaries, missing assignments,
inactive pilots, unarmed loadouts and full bays. Its report is
work/research/shell/launch-checks-verification.json.

Warning dialogs share panel artwork by their root control ID (999), not their
requested screen number. GO 0x36874 also selects the root's static text font:
NM_GREEN for 999/1240/4444, CSTATS_2 for 1610/1800, ACTIVE for 1920, otherwise
GRAY. Type-1 labels are drawn at their authored position, baseline height minus
three; their rectangles are not per-label clipping windows. The caption plaque
has 20 pixels of padding in region 4000 and 40 elsewhere, with a four-pixel top
offset in regions 2000/4000 and five elsewhere.

## GO animation interpreter and exact brush rendering

GO 0x46f2c is not the DBSIM cockpit scheduler: it executes a newly selected page
even with a positive countdown, has distinct ENDLABEL/repeat rules, and consumes
the shared additive RNG. RANDOM_WAIT includes both limits. CALL_LABEL replaces
the retained drawing offset instead of accumulating/restoring it; paired HOTSPOT
instructions implement cumulative-weight label selection. Primary JUMP_LABEL
takes precedence over that pending weighted branch.

capture_shell_animations.py verifies 84 programs / 12,064 sequential updates /
19,820 drawing requests, including all 56 RNG words and both indices.
capture_shell_animation_rasters.py additionally executes the original brush
rasterizers and FIX_RECT page copies for 4,662 visible/background frame pairs.
The C++ compositor matches all these indexed pixels. Display dispatch is taken
from the initialized private DOSBox capture; the harness supplies VGA ports,
memory-only files/allocation, frame restore and a dirty-rectangle bookkeeping sink.

These checks cover the brush/label/wait subset, not the remaining palette,
screen, font or sound families or live screen ownership. R4000A08 references
ROSEY5.BMP (mapped to ROSEY5.DBA), which is absent from the supplied data.
The missing-resource list is retained in animation-verification.json.

The ambient SOUNDS.TTM path has a separate 2,048-update comparison. GO 0x4a0e0
ignores VOLUME_SX; successful HDS_PLAY chooses volume 10..34 with the shared RNG,
then latches the page to avoid retriggering. Disabled sound or failed loading
does not consume that volume draw. Replacing a loaded sample releases its
previous sound object. The capture models SoundManager availability explicitly
and compares 573 load attempts / 328 plays; it does not claim full PCM output.


## Resident service-bay assembly and timing

CFG/TM_FILES.DAT assigns 25 programs to region 4000. GO 0x122e0 claims global
programs 0..3, assigns RNUAMB1 to the selected pilot's bay and one worker program
per other occupied bay. Claiming only succeeds for the unowned sentinel -99.
The optional RLITR6 program depends on mission kind 4 and campaign-current state;
it is not selected by nighttime. Construction refresh 0x120f9 unclaims the bay
before selecting DAVSB or CHRIS3 and the chassis-specific welding program.
Elevator positions also consume shared RNG, affecting later shell randomness.

capture_bay_animation_plan.py compares 128 initializations / 512 changes.
capture_bay_scene.py runs original 0x294d8/0x241f9 assembly and 0x4652e animation
updates: 1,984 full visible/background page pairs, eight complete chassis and
17 partial-construction stages, all interpreter states and shared RNG words.
0x25090 must initialize the static artwork positions before this comparison.
The harness supplies frame restoration and sinks dirty-region bookkeeping;
dialogs and audio are excluded from this pixel fixture.

GO 0x45d24 constructs the shared timer with PIT divisor 0x26d3 (about 120 Hz).
0x4670e registers TTM callback 0x46681 with period two, about 60 Hz. In original
shell-flat-00002, pointers 0x82758, 0x829d8, 0xab784 and 0x8728c all name the
object at 0xb8570, whose divisor is 0x26d3. The fallback clock created by a
standalone TTM initializer uses 0x4da6; it is not the ordinary game startup path.
Individual animation WAIT values divide this clock further; there is no single
10-fps animation rule.


## Shell music and armament previews

The region song IDs are 1, 1, 3, 4, 3, 3, 1 for regions 1000 through 7000.
GO 0x20a70 replaces the prior song through 0x20a18/0x209e0: it writes volume
100 down to 1, waiting one period-two clock step after each, stops/releases the
old object, loads the new registered song, sets loop count 65535, and starts
only when music is enabled. capture_shell_music.py checks 16 cases and 848
ordered load/stop/play/gain/loop events. SoundManager calls and waits are explicit
recording boundaries. The native shell now routes this through the existing
HMI/FM/PCM pipeline; its asynchronous menu fade still leaves the original
blocking input boundary for presentation integration.

GO 0x37996 loads fourteen W1800W programs and four W1800R programs for control
1803. Selection 0x1f359 restarts page one; the authored WAIT 2 turn ends with a
FIX_RECT and ENDLABEL, leaving its final view stationary. Weapon ID 17 hides the
preview; missile subtype selection uses index 14 plus subtype (0x2e47f).
G00/G01 remain retained resources outside this normal eighteen-program list.
The live native menus now animate this control and play the six bay RAW sounds.


## Briefing map, tour and callouts

GO constructs its separate map at 0x94d9, paints at 0x9ca7 and advances the
guided tour at 0x9cfb. It uses shell0/DGS terrain and TEX1, REGN6000's palette,
ICONS and MAP.DFN. Shell terrain selector order is TEMPER, ICE, DESERT, URBAN;
it must not be replaced by the simulator's DESERT, TEMPER, ICE, URBAN order.

Full/squad camera fitting, player formations, grid reveal, waypoint travel,
objective holds, zoom/pan and latched hover labels now have independent native
C++ consumers. The opening waits ten timer ticks each for background and terrain,
then one per grid line (including the initial offscreen line); the first tour
pause follows. Nominal ticks are the shared 120 Hz shell clock. The host keeps
input responsive during the reveal; matching the original blocking owner remains
part of the broader presentation/input work.

GO retains its older signed-byte bearing correction table at 0x8708c and cosine
table at 0x8b648. Its cosine samples differ from DBSIM's in 554 entries, each by
one, and its angle indexing truncates rather than rounds. All 5,129 authored
ZONE placements are yaw-only; using the shell table for these placements fixes
a one-pixel edge discrepancy in the chapter-six map. Its odd-height viewport
also includes the bottom grid row. Return-to-map rebuild 0x9c64 restores the
full fitted camera but retains pan.

The GO bitmap scaler (0x74b18) is endpoint-aligned, unlike DBSIM's later scaler.
It also retains horizontal clipping's fractional remainder between rows.
capture_shell_bitmaps.py checks 500 clipped/transparent cases independently.

The retained comparisons are:
- capture_briefing_map.py: 90 complete VGA frames and geometry/navigation states,
  seven single-mission categories and the opening mission in all eight campaign
  chapters, including return-to-map restoration.
- capture_briefing_tour.py: 3,069 original tour updates and 62 sampled full frames.
- capture_briefing_opening.py: 39 reveal frames and original wait deadlines.
- capture_briefing_labels.py: 79 selected-object callout frames at several zooms.
- Native launch validation also constructs/draws maps for all 674 coherent
  captured mission launches.

Two original undefined accesses have explicit limits. Group-positioned bases
can have point index -1; the original map drawing/label constructor reads before
the points allocation. Fixtures suppress those invalid base markers after
construction; C++ omits them. No allocator bytes are treated as mission positions.
B0_C6_7A additionally has player formation -1. GO 0xcab1 reads no formation data
in that case, and its local-vector constructor 0xce6f does not initialize the
offset buffer. check_briefing_formation_bounds.py runs unchanged placement with
three supplied prior stack patterns, demonstrating different follower positions
while preserving the leader. The probe explicitly uses a valid B0_C6_0A map
with formation overridden to -1; it is not a whole B0_C6_7A startup capture.
C++ marks these follower positions undefined and excludes them from map fitting,
labels and icons, consistently with the simulator's existing undefined-position
policy. No pixel-equivalence claim covers these undefined coordinates.


### Shell dialogue and synchronized portraits

Commander briefings, the general's chapter introductions, launch remarks and
single-mission debriefs now run as modal presentations with original voices,
caption wrapping and synchronized mouth frames. Text-only, voice-only and both
preferences remain independent of music and ambient effects. Skipping consumes
the input; departure releases launch only after speech finishes or is skipped.

Independent original-code comparisons cover all 209 speech-list entries and
45,319 mouth states; 164 captions and 621 complete frames; 629 speech selections
with full RNG state; and 159 complete portrait/caption compositions including
resident commander animation and both retained pages. The live shell test covers
natural completion, multi-clip introductions, skipping, voice output with music
and effects disabled, and mission launch/return. Three native screens were saved
for inspection. The shell SNC format differs from the simulator's radio format.

Reference capture supplies clock ticks, page restoration and sound-device sinks;
it executes original selection, mouth, caption and TTM code. The live owners, chapter travel, mechanic response chains and workshop
animation during speech are integrated and covered in the later sections below.
Sound-card timing has the separate limits documented in MUSIC.md.


## Shell dialogue

- `shell_speech.bin` (ESSPSNC1): GO's original list/SNC readers, timer and mouth
  cursor, 209 entries / 45,319 states. TTM and audio calls are recorded boundaries.
- `shell_captions.bin` (ESCAPTN1): original text allocation, wrap and drawing;
  164 texts / 621 complete VGA frames across speech preferences and page changes.
- `shell_speech_selection.bin` (ESSPSEL1): 629 original mode/chapter/grade/seed
  selections, paths, indices, music and complete additive RNG states.
- `shell_speech_scenes.bin` (ESSPSCN1): 16 original portrait scenes / 159 full
  frames with retained backgrounds and RNG; original resident and mouth TTMs run.

Generated by `tools/capture_shell_speech*.py` and `capture_shell_captions.py` in
Earthsiege analysis. Device audio, explicit 60 Hz updates and page restoration
are capture boundaries. The memory-stream transport recognizes already-detached
objects during destruction; original speech instructions remain unchanged.


### Cinematic fade-in scratch-state defect

GO 0x4933b (TTM FADE_IN) fills the rectangle at frame-local -0x3a4 but
does not construct or set the preceding kind word (-0x3a8) before calling
0x51c40. That dispatch accepts kind 0 or 2. Isolated A_CAMNI calls with
scratch stacks filled with 0, 0x11111111 and 0x22222222 pass exactly those
values to the copy dispatch. The normal capture setup left 4 there, suppressing
the intermediate page copy. Thus the visible image during the fade can depend
on earlier stack contents; palette interpolation and completed TTM pages do not.

The cinematic fixture explicitly zeroes scratch stack before each TTM update,
so its intermediate image comparison has a defined rectangular-copy boundary.
The native compositor initializes that rectangle normally. This does not claim
equivalence to every possible original uninitialized-stack history. The
original instructions are not patched.


### Cinematic interpreter and palette transitions

The original screen loads, retained-page copies, drawing colours, vector lines,
palette selection and fade arithmetic are now implemented. GO ignores the
retained font-load/select tokens; it does not invoke the generic font path.
All 820 original updates across 18 opening, ending, chapter-travel and monitor
scripts match interpreter/RNG state, both complete drawing pages and 2,096
intermediate palette submissions. Cinematic lines share the verified original
rasterizer rather than the generic framebuffer line helper.

The fade range uses byte arguments and an inclusive end: an authored count of
256 changes only the first colour. More significantly, GO's FADE_IN path at
0x4933b does not initialize its temporary copy-region kind. Three independent
scratch patterns (0, 0x11111111, 0x22222222) appear unchanged at the copy dispatch.
The fixture supplies a zeroed scratch stack for this undefined field, and C++
uses an initialized rectangle. Intermediate image parity is bounded to that
explicit setup; palette computation and completed pages remain independently
compared. Live cinematic owners and hardware-dependent retrace pacing follow.


### Live cinematic and campaign-return owners

Opening logos/story, chapter travel, pilot death, victory and defeat now run in
the native shell with their original scripts and music choices. Input skips a
segment; skipping Dynamix also suppresses LEAD_IN, while IINTRO and EARTH_W still
run. --skip-intro matches the original -a boundary: opening and pilot death only.
The terminal Earth loop waits for input. Next Mission uses commander briefing
within a chapter, or mechanic/general/travel at the next chapter boundary.

Campaign return selects the mechanic's chain before automatic repairs, using
HERC condition, new technology, recovery and crew deaths. All 648 original
selections match the complete RNG state, including the one-choice technology
random draw. Zero-condition primary entry -1 is safely omitted. The new live
flow check covers natural opening completion, skip boundaries, ordinary return,
death, both campaign endings and a chapter transition. Original-format saves
remain isolated in the test's temporary directory.

The current host presents intermediate palette submissions at nominal 60 Hz.
Original VGA routine 0x70130 only waits until already inside retrace, allowing
multiple submissions per refresh depending on CPU speed. No wall-clock fade
parity is claimed yet. Bay residents during speech, general monitor transitions, main-menu ANM
playback and owner scheduling are integrated and documented below.

Full rebuild: all 209 CTest checks pass (20.06 seconds). Opening, chapter-travel
and damaged-HERC mechanic-return screenshots were inspected.


### Workshop animation during mechanic dialogue

Mechanic portraits now share the bay's actual visible and retained pages. Only
resident programs 3 and 6 pause, as in GO; other workers, elevators and welding
continue with the same RNG stream. Portrait cleanup returns both drawing pages
to the bay before its two programs resume. No guessed overlay masks are used.

The original capture runs eight chassis/speaker/clip combinations and compares
104 complete frames, including post-dialogue cleanup, both page CRCs and every
RNG word. All match. Existing bay, portrait, live speech and cinematic-flow
checks also pass. Original sound-device timing remains an explicit boundary.


### LPF menu doors

The two ANM resources are the closing (ESIEGE2) and opening (ESIEGE3) menu-door
transitions, not a looping main-menu background. GO 0x13aa8/0x13d9e/0x13c46
loads, locates and decodes their LPF pages. Its native counterpart now matches
all 60 captured complete frames, over both resources, two background patterns
and opaque/saved-screen modes. The final ring delta is excluded. Written zero
pixels restore the saved screen in transition mode; skip spans retain the prior
frame. ESIEGE3's page directory is not in frame order.

Normal standalone playback uses the header's 15 fps. Menu calls at 0x3c2a4 and
0x3c734 instead select background restoration and omit that clock wait; their
speed depends on decoding and VGA writes. Exact transition scheduling is separate
from the verified decoder. The two call sites request digital sounds 10/11.

G0_ON/OFF/STAT are retained monitor assets, but no caller has yet been found:
they are absent from GO's literal TTM names, the resident TM_FILES table and the
general's G0_FILES speech list. Do not assume the original plays these assets
merely because they exist. G0_SYNC is the verified general portrait program.


### Live menu doors and credits

The shell now plays the original closing/opening ANMs at menu-region changes,
including their digital sounds and saved-screen zero-pixel restoration. Input
is consumed during the transition; speech waits until the doors open. Skipping
the introductory movies still retains the closing doors. Warning dialogs retain
their parent's region and cannot accidentally start a blocked transition.

Options / Credits now runs CREDIT_A and CREDIT_B and returns through the doors.
Both original scripts match 12 captured updates and 310 palette writes. Their
unused GETTEXTSTART producer metadata is ignored as in GO. A single-mission
pilot death returns directly to mission selection, without a career death movie
or spoken debrief.

The host presents each door frame at nominal 60 Hz. The original menu calls use
saved-screen mode and omit the ANM header's 15 fps wait, so their wall-clock speed
depends on CPU/VGA throughput. No original wall-clock pacing is claimed.

All 213 CTest checks pass. Closing, opening and credit screens were inspected.


## Career and debrief statistics

GO paints these specialized controls rather than storing their text in the dialog:
career control 1231 at `0x1705e`, and return control 1522 at `0x175d7`.
They use CSTATS_1 (values) and CSTATS_2 (labels), with WATEXT entries 167–183.
The career panel reads the selected history block, including its selected pilot,
mission step plus one, completed missions, salvage budget and lifetime kills.
Its MISC field is a literal zero. A backup's statistics are viewed without
restoring that backup into the current career.

The return panel displays recovered salvage, personal and squad kills, crew
losses, the number of salvaged weapon records, and the last newly unlocked
technology (or NONE). Kill rows are HERCs, flyers, structures; their storage order
is HERCs, structures, flyers. Squad totals are accumulated before replacement of
dead wingmates. The technology label is updated before unlocking each new item;
when several become available together the last eligible entry wins.

Single missions also execute the result reader and count casualties. Only the
player's chassis conditions update a bay HERC: single-mission wingmate slots refer
to temporary launch records. Wingmate health, current/lifetime kills and rank are
still updated. Single missions do not receive campaign restocking, salvage
inventory, replacements or technology progression. GO consumes mission counters
separately from its saved crew block.

[Panel captures](../analysis/shell/statistics/index.html) show original executable
output. `tools/capture_shell_statistics.py` retains 96 complete pixel comparisons
across both return layouts, career/history selection, live/dead pilots, signed
statistics and technology labels. `tools/capture_shell_single_return.py` executes
24 whole original single-mission returns through private in-memory launch files.
The native implementation agrees with the captured crew, roster, counters,
casualties, squad totals and panel pixels. Hardware/file transport are explicit
harness boundaries; the drawing and return routines run unchanged.
