CORNCOB Research archive

Saved campaigns, pilots, demos and generated training

All extraction is read-only. Original files remain in their installations. The resource browser exposes saved theatre maps, decoded named pilots and scrub/play controls for recorded flight paths.

How the save files fit together

A .THT file saves one ongoing theatre. It is a single structured file: a header containing theatre information and an embedded pilot/statistics record, followed by the complete saved world. It is not an archive of named files. One pilot can own several saved theatres, each in a separate numbered .THT.

File Role
PILOT.SCR Pilot roster, career information and references to each pilot's saved theatres. It does not contain the world maps.
THT/<number>.THT Persistent save for one theatre, including its world and associated statistics.
3UNIV.DAT Shared working copy of the current world, passed between the separate DOS programs. It contains the world stream without the .THT campaign header.

During ordinary saved-campaign play:

  1. The menu loads the selected .THT's world into 3UNIV.DAT.
  2. The flight engine reads that working world, runs the sortie and writes its changed world back to 3UNIV.DAT.
  3. The menu incorporates the updated world into the selected .THT and updates the appropriate pilot statistics.

The single 3UNIV.DAT is reused when another saved theatre is selected or a fresh scenario is opened. Changes to it can survive in the corresponding saved campaign; they do not alter the original DEF/CCT scenario for every pilot. Persistence rules describe which changes are saved and the direct-engine-launch qualifications.

Saved theatres

All 22 distinct supplied .THT files have a 671-byte header, followed by a complete 64-tile world stream. Both plain and XOR-encoded type words are accepted only after the whole world validates. Every byte boundary and object type is checked. The stored world is the live saved campaign, so its objects can differ from a pristine DEF/CCT.

Header offset Bytes Interpretation
0 28 NUL-terminated theatre title
28 12 Original definition basename
40 8 Four campaign words, retained without speculative labels
48 623 Embedded pilot/statistics record
671 remainder World stream, including its twelve-byte trailer

The embedded record uses the same 623-byte structure found in PILOT.SCR: a 22-byte name field, flags at offset 22, then statistics and other state. It is plaintext in the theatre file. Source definition basenames reconnect saved maps to their TWR briefings and mission starts. The compact-record expansion now verifies 898 objects across the normal reference's original and saved worlds against 3.EXE.

Named pilots

The supplied PILOT.SCR files are not corrupt or compressed. They use a random-byte mask:

  1. Plain little-endian uint16 format version: 24.
  2. Plain uint16 seed.
  3. Remaining bytes XORed with the original library PRNG output.

The 32-bit PRNG is state = state * 0x015a4e35 + 1, wrapping at 32 bits. Each mask byte is ((state >> 16) & 0x7fff) / 128, using integer division. The native reader's masking wrapper is at MOAG file offset 0x17ca5; srand/rand are at 0x3c71/0x3c82 in the normal 3.42 front end. These are Borland runtime routines, separate from the flight engine's random generator.

Most decoded streams contain a 24-byte header with the pilot count at +22, then 623-byte pilot records. The played 2.00 floppy instead has a 23-byte header with the count at +21, despite also declaring format version 24. Both layouts have one extra check byte after the first pilot, or after the header if there are no pilots. Their on-disk sizes are 29 + 623 * count and 28 + 623 * count respectively. The decoder selects a layout only when the count matches the complete file length exactly; it does not silently discard a byte.

Pilot names occupy the first 22 bytes of each record. Flags follow; bit 0x8000 identifies the selected record in the front end. The rest of the record and all header/check bytes are exported intact. The precise labels of every statistics word and the check-byte calculation are not inferred from sample values.

The normal reference currently has no named pilots; the expansion has two, your original installation has one, and the played 2.00 floppy has eleven. All four unique pilot files are in the browser. Their decoded masks have been checked against the original executable for every supplied byte; unlabelled statistics remain intact in JSON.

Rainmaker: surviving historical date

The old installation's PILOT.SCR contains a last-use/clock-check dword at pilot-record offset 594 (0x252). Rainmaker stores 0x3d1ca82f (1025288239), whose Unix interpretation is 2002-06-28 18:17:19 UTC. Running this copy's original MOAG.EXE time conversion in isolated emulation reproduces that exact value from a DOS system clock of 2002-06-28 14:17:19; the unmodified runtime applies a four-hour summer offset. The stored value does not establish the machine's actual geographical timezone or clock accuracy.

In this old install's MOAG, the last-use field is refreshed by time() at file ranges 0x115f4–0x11600 (before launching the flight executable) and 0x18ddb–0x18de7 (configuration writing). The name-display helper compares it with the current time at 0x19c44–0x19c68 and 0x19cbf–0x19cdd, detecting a clock set earlier than the stored value. This establishes historical use/update evidence, rather than a pilot-creation or mission-completion date. The runtime time() implementation is at file range 0x470d–0x475a; this MOAG has a 0x3200-byte MZ header and initial data segment 0x187f.

All three Rainmaker theatre saves (Dusk, Atkinsville and Wasteland) have zero in the corresponding embedded-pilot field. They cannot individually be dated from it. The old install's current filesystem modification times are all from its copy here on 15 October 2026, including both pilot files and the three THTs; these do not preserve their historical modification dates.

Recorded demonstrations

The three unique recordings are shared by shareware 1.20 and the later expansion package. Their accompanying DEMO.NDX gives the titles Basic Mission, Junky Corridor and Vertical Mission, along with readable descriptions.

File Motion records
DEMO1.DMO 2,456
DEMO5.DMO 1,111
DEMO6.DMO 1,013

A tag starts every record. Bit 0x08 must be set. With bit 0x80 clear, the record is 37 bytes: tag, three signed 32-bit positions, three 16-bit angles, three 32-bit velocity fields and three signed 16-bit acceleration fields. With bit 0x80 set, it is eight bytes: tag, three signed acceleration bytes, three angle high bytes and one packed byte containing the next two bits of each angle.

The compact reader updates the low velocity word, then sign-extends it to advance each 32-bit position. It preserves the stored high velocity word. The packed angle byte assigns bits 4–5 to pitch, 2–3 to yaw and 0–1 to roll. Full records with bit 0x20 set do not replace the stored aircraft state; the browser preserves this distinction. Other low tag bits are retained rather than given invented names.

A 0xff tag terminates playback. The writer also emits a final 36-byte payload, which the reader does not consume. It is preserved as unused terminal state. Files validate exactly to that final record.

All 4,580 decoded position/angle states match execution of the original 1.20 reader at 0x1d15. The viewer plots the route and allows scrubbing and playback. It does not resimulate aircraft physics or supply an invented world; the recordings do not embed their training scenery. Preview frame rate is selectable because elapsed wall-clock timing is not encoded in these motion records.

Built-in training world

The flight executable constructs training scenery procedurally at 0x904f–0x960a. extract_training.py runs that original routine in Unicorn. The harness supplies isolated object allocation; native code constructs the records, applies quality flags and chooses positions. No DOS filesystem or existing save is used.

Three examples are in the map browser:

Example Objects Defence counts: KLA / vehicle sites / AAA
Default 67 8 / 8 / 6
No defences 45 0 / 0 / 0
One of each 48 1 / 1 / 1

“No defences” still contains the airfield, fuel targets, forcefields and other training scenery. Inputs are the native count words at DS:0e6c, 0e6e, 0e70. The extracted examples use the original initial PRNG state; they are not an exhaustive catalogue of random training layouts.

Reproduction

python3 tools/extract_training.py
python3 tools/extract_resources.py
python3 tools/validate_extended.py

Native execution requires Unicorn. Verification results record demo and pilot checks; the generated world JSON retains every full 74-byte object record and generator input.

High-score tables

Four distinct PILOT.HSC files are now decoded. Each is 5,040 bytes and contains:

List File offset Entries Bytes per entry
Best missions 0 10 180
Top careers 1,800 10 162
Fastest careers 3,420 10 162

All entries begin with a 22-byte pilot name. Mission entries then have a 22-byte theatre name and 130 statistics bytes. Career entries instead have 16-bit mission/resurrection counts followed by the same 130-byte statistics block. A signed 32-bit score and 16-bit retired/deleted flag finish each entry. Names, score, objectives, primary/other kills, mission and resurrection counts are exposed. The fastest-career list displays integer points per mission. Empty slots and the complete original record bytes remain in JSON.

Retail MOAG's display routines at file offsets 0xe9bd–0xef6a establish the three table offsets, record sizes and display fields. Its two kill-summing helpers at 0xf897–0xf8fc verify all 240 decoded primary/other totals across the four files. The manual's high-score help confirms the meaning of the lists, kill categories, retirement marker and three-mission fastest-career eligibility. See remaining-verification.json.