DARKER Research archive

Embedded mission setup: translated effects and checks

The seven FE-prefixed x86 blocks in four archive-04 records now have explicit effect descriptions in scenarios.json, readable reference operations in mission_native.py, and byte-addressed disassembly plus differential results in native-verification.json. The scenario browser displays the descriptions beside the stored setup.

All offsets below are offsets in the decompressed resource. Object offsets refer to the original 112-byte runtime object, accessed through SS:BP. Object 0 is the player; other indices follow setup allocation order across all three groups. BP is the most recently allocated object, not invariably the player.

Native calling convention

BE12–BE19 saves AX, sets BX to the helper-pointer table at BEDD, and calls SI. Every observed block advances SI by its own length. Some return directly; others tail-call a helper through BX. The parser restores AX, preserving its counted-object total.

Pointer Handler Effect
BEDD C79D Initialise boost/weapon energy, active boost, pitch, and placement
BEDF 8E24 Set motion parameters, two clock-relative fields and callback 8DDD
BEE1 5E59 Write AL to weapon-1 counters 5E14 and 5E11

C79D stores DX to boost reserve 8540 and weapon energy 7FA6. Its incoming carry flag selects active boost high byte 7F0E: clear gives 0; set gives 28h. AX sets pitch. It then enters C7C8, which subtracts the current model's header word at +7 from CX to produce the object's height, stores DI as heading, and refreshes cell and position caches. This model-dependent adjustment must survive a faithful reconstruction.

The seven blocks

Resource / record / block Current object Effects
04_012 / 2 / 1AAC Player Speed magnitude 200, forward velocity 400; clear flag bit 4; pitch FF00, heading EC00, nominal height 2560; empty boost and weapon energy
04_012 / 4 / 1D51 Player Sub-cell X=C8, Y=BB; rewrite following objects 1 and 2 to the player's cell; pitch 0, heading 0F20, nominal height 264; empty boost and weapon energy
04_012 / 4 / 1D80 Object 1 Increment height high byte, equivalent to adding 256 with 16-bit wrap
04_012 / 4 / 1D95 Object 2 Sub-cell X=4B, Y=46; subtract 2400 from height; speed magnitude 200, pitch 0C00; install callback 8DDD
04_014 / 2 / 0F91 Player Speed magnitude 300, forward velocity 600; clear flag bit 4 and weapon-1 counters; pitch FE00, preserve heading, nominal height 4096; empty boost and weapon energy
04_015 / 0 / 0028 Player Patch later native instruction with player's model pointer; clear flag bit 4; pitch F500, preserve heading, nominal height 2432; boost/weapon energy 9FFF and active boost high byte 28
04_015 / 0 / 0060 Object 2 Assign the model pointer embedded by the earlier block

All pitch/heading values in the table are raw hexadecimal words; other quantities are decimal unless indicated. The descriptions intentionally avoid assigning scene identities from motion alone.

Two dependencies are particularly important:

For 1D95, helper 8E24 stores clock+256 at object +68, clock+1024 at +5E, and 8DDD at +66, all with 16-bit wrap. Callback 8DDD calls movement helpers and compares the live clock against +5E using a signed difference; on expiry it changes the callback to 8823 and clears flag bit 4. Its complete subsequent movement is outside this setup check.

Script boundary findings

Opcode 38: conditional altitude operand. Handler C194 toggles bit 7 of 7ED2. When the bit becomes set, it consumes a little-endian height word into 80AC; when clear, it consumes no operand. Initial reset 3C43 clears the flag. The ordinary A-key handler changes bit 0, not bit 7.

In 04_015 / 0, resource offset 039B enables height 0200h and continues at 039E. Offset 03CC disables the mode; 03CD is already the next opcode (12, beacon-row change). Propagating this state recovers 65 additional instructions across the record's reached paths. The decoder tracks state through relative jumps and reports conflicting boundaries if encountered. Entry roots assume the reset high bit; this is not proof of all interleavings of concurrently running scripts or arbitrary entry into a supplementary record.

Terminal counter wait. 04_015 / 2 ends its shared block with 1F FF at 0617, immediately before the English section at 0619. Handler C219 compares the operand with the counter held in the immediate byte at C21B. For counter 0–254 it branches to C1E1, which reloads the checkpoint and yields. For counter 255 it returns and falls into the following language bytes. The exporter records this as a guarded boundary exit, not an unconditional stop or a text continuation. Whether this scene can actually reach counter 255 has not been established. The exceptional path remains unanalysed and explicitly visible in both scenario and presentation exports.

Verification scope

The full parser check uses synthetic zero-height geometry and a known synthetic player position. Underground route initialisation remains substituted. These checks establish setup effects and byte consumption, not complete mission behaviour, real-world placement height, rendering, or mission completion.

Reproduce with:

python3 tools/inspect_missions.py
PYTHONPATH=/tmp/darker-python python3 tools/verify_missions.py
PYTHONPATH=/tmp/darker-python python3 tools/verify_mission_native.py
python3 tools/mission_browser.py
python3 tools/extract_presentations.py