# Airfield survey and remaining campaign interface reconstruction

Reference: normal 3.42 `installs/deluxe_dnk/MOAG.EXE`, SHA-256
`6d8c922d59a873073796b367a2a40993fcaa5e763ed2ca907a945981f0c5bc32`.
Its MZ header is 0x3200 bytes; module DS is 0x1886, giving a file DS base of
0x1ba60. Addresses below are file offsets unless stated otherwise.

## INT survey

The survey belongs to MOAG's INT code, independently of TOWER.EXE's briefing
reader. It builds TOWERS.INF from live world records. One-airfield worlds include
all 64 tiles; a nine-airfield expansion instead uses the per-airfield tile table
at DS:52d0. The four base worlds all use the central RDU airfield.

Temporary entries are 17 bytes: three signed dword positions, word type, word
flags and a grouping byte. The low five bits identify the group; bit 0x40 marks
an objective anchor. The 61 three-byte descriptors at 0x20dac contain a name
pointer and inclusion/enemy attribute bits.

- 0x1725f formats descriptions, objective text, ranges, bearings and altitudes.
- 0x16f31 assigns groups; 0x16e32 compares six sorting keys.
- Borland's qsort at 0x7ef2 determines the order of equal-key entries. A stable
  sort, or a different quicksort, changes the visible order of range lines.

The first tower groups friendly objects within a strict 400,000 cm square.
Orbs, objective saucers and qualifying portals claim ungrouped neighbors in the
same square. Remaining objects share a final group. Sorting compares group,
enemy attribute, objective marker, completion flag for objective pairs, type and
quality. Destroyed or completed objects retain their original description rules.

Range calculation truncates each axis into tenths of a mile (16,090 cm) before
an integer Newton square root. Zero displays as `.0`. Positive X is north and
positive Y west. Bearings use integer dominance ratios with boundaries 150 and
503. Altitude uses signed wrapping `z * 10 / 305`, rather than an exact modern
feet conversion. Typed labels and mission text retain original backslash markup.

`tools/moag_survey_native.py` executes the unchanged routines in Unicorn.
Only fprintf output and near allocation are supplied. The C++ generator records
1,952 descriptions (61 types × eight qualities × four flag combinations) and
96 complete randomized grouping/sort runs. The committed Morning text also
matches a real DOSBox-produced TOWERS.INF byte for byte. The scrolling document
has 15 visible lines; its headings scroll with the body.

## Airfield census and storage

INT counts unwrecked aircraft whose X/Y displacement from the airfield start,
and Z displacement from 720 cm, are each below 524,288 cm. This is an integer
start box, not a modern Euclidean range. A one-tower world's incomplete objective
counts are merged into the central airfield. Objective types match the career
scan, including spies and qualifying portals.

MOAG's empty-field warning (0x12819 onward) offers P only when reserve stock is
positive. Enter continues on foot, Escape aborts, and another key returns to
selection. A completed theater first warns that no objectives remain. Deleting
a completed theater requires Y because removing its record can prevent Combat
Master credit; Enter is not confirmation.

Storage selection sets DS:b1bd and appends `h` to the flight command.
CMDLINE.ASM's `hopt` enables `chainflag`. READUNIV then starts the pilot aboard
an aircraft at the stored start, disables normal arrival boarding and sets flag
0x1000. This is the lower-powered **Dumpy**, not the standard Corsair.
The existing flight model already interprets that variant (3.ASM around 8790).

MOAG decrements reserve stock on a credited return (0x12ff5 / 0x1323d), not at
selection. Aborted and invulnerable branches bypass consumption. The native
cache's reserve word +0x1c corresponds to saved THT word 38. The C++ handoff keeps
the pending choice with the sortie; returning updates that word. Trainee worlds
and reserves remain transient. Checks cover exhaustion, on-foot continuation,
uncounted returns, restart persistence and the Dumpy spawn position/variant.

## Records and conditional dialogs

Killed/captured activation can resurrect and activate in one operation. Manual
resurrection separately asks whether to activate the pilot. Stockade confinement
has a scheduled release and cannot be removed with resurrection. Reports distinguish
K.I.A., captivity, confinement, active duty and waiting. An unavailable named pilot
reverts to the trainee after the return/report sequence.

ISCORE's preliminary report temporarily marks home/landed, accumulates speculative
statistics, and displays its own flight-report scoring factors without saving.
Training uses the global record, even with a combat world open. MOAG's final
mission report uses campaign scoring and the pre-promotion rank. Promotion and
medal notices follow, then the post-mission career overview. Decorations are
abbreviated and drawn as repeated MEDAL.FNC glyph pairs, fourteen per line.
Populated high-score rows retain fixed native columns, highlighted retirement
stars, separate kill totals and signed integer points per mission.

`analysis/native-campaign/` preserves original 640×400 DOSBox screenshots.
Eleven are hashed by `corncob-cpp/tools/generate_campaign_menu_reference.py` and
compared against complete C++ frames. They cover preliminary/start/survey/reserve,
three populated score tables, final mission report, promotion, decoration and
post-mission medals. Conditional dialogs also have state-transition tests; their
entire pixel/state combination space has not been established.

Capture preparation:

- Start/survey: acknowledge the absent-return notice, create/activate `Gap Pilot`,
  open Morning and select Fly. I opens the live survey.
- Reserve: a disposable `Reserve Pilot` Morning save has both aircraft's wreck
  flag 0x100 set. Fly and Enter produce the storage warning. No original install
  or user save is modified.
- Populated tables: the committed 5,040-byte `populated_scores.bin` is supplied as
  PILOT.HSC in that disposable install. Rows include a retired 20-character name.
- Preliminary: unchanged ISCORE with the original trainee MOAG.CFG and synthetic
  3.RES statistics: three fuel dumps, one objective, 125 seconds.
- Return: `tools/capture_native_return.py` recreates the full chain from preserved
  original-format `return-before.cfg` and `return.res`. The latter has synthetic
  home/landed statistics (400 resources, 20 objectives, damage 150) plus the
  original-format negative registration hash and zero error trailer. This is a
  controlled UI test, not a claim that an actual flight achieved those totals.
  It also captures the intermediate Purple Heart, Gold Star, DSC and TCM notices.

All drawing in these captures comes from unmodified DOS binaries. Unicorn fixture
execution and DOSBox pixel capture are separate checks. Longer campaign play,
all record combinations and whole-session painter/PRNG fidelity remain broader
verification work, rather than additional missing menu features.
