DARKER Research archive

Mission scripts and scenario setup: first structural pass

Open the scenario inspector to select any stored record, view its base map and stored object positions, inspect cell-state lists, read English text runs and browse decoded operations. The scenario JSON preserves the entire shared block of every record, including undecoded bytes. The opcode directory records all 77 entries of the main dispatcher.

See also the scenario object identities and visual key for bank-specific models, enemy names and confidence levels.

Launch and destination points

The scenario map's Launch / destination sites checkbox shows green L markers for departure/entry and magenta D markers for return destinations. An L/D marker combines both at the same cell. Click a marker or use the site dropdown for coordinates, model type, script offset where applicable and an approximate nearest printed-map location. Shift-click retains access to stored objects beneath a marker.

tools/mission_hangars.py derives these from the normal initial return site 7162h (49,113), inherited surface destinations, 29 return-site instructions, and 28 explicit entry instructions. Packed site columns are doubled and are divided by two for display. Underground entry/return coordinates are shown on the underground map; the surface destination is retained separately so the following surface mission starts at the correct tunnel entrance. For example, mission 16 departs (49,113) for (50,48); mission 17 uses its underground portal; mission 18 emerges at (50,48) and returns to (49,113).

This is a static normal-campaign interpretation, not a loaded-save simulation. An edited save may change the departure site. Scripted destinations become active when their instructions execute; marker visibility does not mean the hangar is currently open. No ordinary Caero record currently has multiple return-site assignments. The viewer can list multiple assignments without claiming simultaneous landing permission.

Halon uses supply pads, not fixed destination hangars. Its explicit initial Skimma entry is shown, but later save-dependent pad starts are left unspecified. The special late Delphi entry is labelled an entry position, not a hangar. Presentation records have no inferred world points.

Coverage

Item Exported
Stored records across all 16 archive-04 resources 124
Records containing world setup 107
Presentation-only records 17
Explicit object templates 1,857
Embedded native-code setup blocks 7, in four records
Compact special-object route streams 172 object references
Statically decoded main-script instructions 5,204
Unclassified main-script decode limits 0
Guarded boundary exits (exceptional fall-through unresolved) 1

These counts are not counts of distinct playable missions: some records are scenes or supplementary programs. World setup includes reserve/free-list templates, not just objects active at the start. The instruction inventory is not a runtime trace or a full control-flow reconstruction.

Record and shared-header layout

Record traversal follows next = record + 2 + length. Three language offsets are relative to record + 2; the shared block starts at record + 8 and ends at the English-section boundary. Language text remains indexed as printable runs, with exact resource offsets and possible embedded formatting bytes.

The first four shared bytes are:

Offset Type Interpretation
+0 u16 Relative entry offset into the shared block; independent of the player object's ongoing mission-script entry
+2 u8 Script timing multiplier used by delay/message handlers
+3 u8 Packed configuration, or FF for presentation-only records

BAFA–BB0D splits non-FF configuration into a low-nibble craft configuration and high-nibble variant. Craft setup selects executable definition slot 24 + configuration. That definition's byte +0D selects bank mode; the geometry bank is 30 + mode.

BCCC–BCD1 selects map 68 + mode + map_addition. For craft configurations below 4, the addition is zero; a nonzero high nibble instead selects supplementary script material from resource 04_015 (BB39–BB4D). For configuration 4 and above, BB52 uses the high nibble as the map addition. Thus an arbitrary high nibble must not simply be added to the city-map ID.

BB12–BB28 converts an internal one-based stage byte into resource index (stage-1)>>3 and stored record (stage-1)&7. This documents the selector arithmetic, not an asserted one-to-one mapping to player-visible mission numbers.

Cell lists and objectives

World setup begins after the four-byte header:

  1. An FF-terminated byte sequence feeds the sequential energy-beacon change mechanism. Its exact bytes are preserved; this pass does not simulate its progression.
  2. Three packed coordinate lists follow, each containing (column,row) byte pairs and a one-byte terminator.
  3. C85A/C87E ORs state 20h into the first list's cells and 40h into the second list's cells. The third list is traversed without that initial write.
  4. The second list's terminator determines the objective-list pointer: FE selects the second list, while FF selects the third. All observed records use these forms.

The selected list is exported as objective_cell_list. The native C82F check advances over cells whose relevant state bits are set; its mask is patched by bank setup. C84E combines cell-list completion with the outstanding object counter, and script opcode 1E waits on that result. This is more informative than treating all three lists as interchangeable building placements.

The inspector's outlined cells are selectable on the map and through a cell dropdown. Its building key groups cells by building type and combined setup flags, with thumbnails of the resulting model. Select a cell to compare its base model with the model after the list writes, and follow either link into the 3D atlas. A list selector and clickable key entries highlight matching placements; Shift-click selects an overlapping mobile object instead.

These previews apply the lists' OR masks to state 00h, combining writes when a cell belongs to multiple lists. They are not a reconstructed runtime snapshot: alternate-state bits, native setup and later mission scripts may change the result. The recovered model traversal uses bit 20h for Delphi damage and bits 20h/40h for Halon and underground damage stages. Consequently a red 40h outline in Delphi does not itself select damaged geometry. The third list performs no initial write. Unchanged geometry and models without polygon faces are explicitly labelled.

Open hypothesis (gameplay observation): the additional Halon/underground damage bits may distinguish permanent damage that is not repaired between missions. Only their model-selection effect is established here. Confirm by tracing state preservation/reset during mission transitions, any repair routines, and save/load handling; the number of linked damage models alone cannot establish persistence.

tools/render_city_thumbnails.js generates analysis/models/city-identities.json and 338 distinct state thumbnails from the model atlas renderer, covering 391 bank/type entries at states 00h, 20h, 40h and 60h. Run it after tools/model_viewer.py, then rebuild with tools/mission_browser.py.

Object templates and reinforcement queues

BE07 consumes three FF-terminated object groups. The setup orchestration at BDA9–BDC9 gives them distinct roles:

All groups are available for inspection, with different marker colours. Each object retains its exact source record and zero-based executable definition slot. Runtime object indices begin at 1 after the player object at SS:D986.

Three record forms are present:

Form Size Main fields
Moving 13 bytes Header, attribute byte, heading byte, cell X/Y, six bytes copied to runtime +50..+55, final script/target word
Compact special 6 bytes Header, heading byte, cell X/Y, route/target word
Absolute static 6 bytes Header, heading byte, full X/Y position words

The header's low six bits choose the definition slot. Bit 6 selects the absolute-position form; otherwise slots above 28 use the compact form. Bit 7 includes the object in the mission's counted-object mechanism. Native constructor checks verify the returned count for each decoded group. Scripts can also manipulate counters, so this flag is not a complete description of every success condition.

For the cell-based forms, stored coordinates expand to cell*256 + 128. A heading byte expands to byte << 8. The final word can be a forward relative pointer, or a special object-reference/no-script encoding. Moving records feed the main script interpreter; compact specials feed a separate route interpreter.

These are source placements, not guaranteed final positions. The geometry-dependent initializer adjusts altitude; underground initialization at BEE7 snaps/adjusts positions using route geometry. Embedded native code can also patch following template bytes. The inspector labels this limitation rather than presenting those inputs as measured runtime positions.

Two different bytecode systems

Main object/presentation scripts

BFA9–BFB5 dispatches through 77 words at C475–C50E. Values with bit 7 set instead select a parameter offset used by animation/presentation operations. The export records fixed operands, list operands, handler addresses and descriptive names.

Recovered operation families include:

Delay 22 uses its argument multiplied by shared-header byte +2 in native clock units. A common multiplier is 50, approximately one tenth of a second per argument unit at the recovered PIT rate. Other wait instructions use different scales; do not treat all script operands as seconds.

The decoder follows known roots and relative jumps and stops at script termination/context transfers, while queuing opcode 26’s saved continuation as a separate path for a later context entry. It recognises 08 as a repeat-or-stop operation, rather than falling through into adjacent data. Payload references such as presentation pointers are retained without assuming the payload is another main-script program.

The former two limits are now characterised; see native setup and boundary analysis. Opcode 38 consumes a height word only when enabling altitude mode, recovering 65 additional instructions. Decoding propagates the reset-state assumption along each path. The presentation ending at 04_015 / 2 / 0619 is guarded by 1F FF: counter 0–254 retries, but counter 255 falls into language bytes. That exceptional path remains unresolved and is exported explicitly as a guarded boundary exit, not silently treated as a stop.

Even where instruction boundaries decode cleanly, handler names are descriptive working names. This is not a claim that every handler's gameplay semantics have been fully reconstructed.

Compact special-object routes

8F3B reads the separate streams referenced by compact special objects. Ordinary bytes contain an action in the low nibble and a repeat/control quantity in the high nibble. FF introduces a signed relative branch, using the interpreter's specific pointer convention. Ten action handlers are listed at 9171.

The exporter preserves 172 object references to these decoded routes. They are not incorrectly fed into the main 77-opcode dispatcher. The vehicle route analysis now executes these streams, plots their movement and links map-damage actions to mission waits. It covers all 172 route references; combat, player interference and the complete mission scheduler remain outside the route preview.

Native machine code inside mission data

FE in an object group invokes executable code at the following stream address (BE12–BE19). Seven such blocks occur in:

Resource / stored record Native block offsets and lengths
04_012 / 2 1AAC: 30 bytes
04_012 / 4 1D51: 40; 1D80: 7; 1D95: 27
04_014 / 2 0F91: 35
04_015 / 0 0028: 28; 0060: 9

Each observed block starts by advancing SI over its own bytes. Examples modify player speed, heading/position, altitude or the coordinates of following object records. Some transfer through the helper-pointer structure at BEDD, rather than ending in a conventional RET. This is an explicit escape from the data format into the original machine code.

The export retains those blocks exactly and marks affected scenarios. A modern engine adaptation will need named equivalents for their effects; copying only the object table would lose behaviour. All seven now execute in the scenario verification and have explicit translated effects, disassembly and separate differential checks; see the detailed analysis.

Verification and reproduction

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

Verification results:

The probe applies the original mode-specific call patch at BEA7. Without that setup, the untouched image contains a misleading CALL-to-next-instruction placeholder. The geometry placement helper C7BF is observed and executes against synthetic zero-height geometry; underground route initialization BEE7 is substituted so source-coordinate decoding can be checked independently of route snapping. Native coordinate patches are included in expected placements. This is not a simulation of mission completion, spawning during flight, collision or rendering.

Further analysis: name compact route actions and timing; associate messages with exact script events; trace a selected mission's complete state transitions and scheduler; investigate reachability of the exceptional terminal-counter value. Future engine work follows the separately planned two-stage reconstruction direction.

Text sections and display conditions

The viewer now separates formatted pages from counted scripted messages, with conservative associations to preceding waits and delays. See message sections and native scheduling details, including the first mission's return-to-base message. Branching and shared-cursor ambiguities are marked rather than assigned speculative triggers.

Native per-object scheduling

Scheduler analysis and controlled first-mission trace now establish deadline catch-up, checkpoint retries, coarse-time waits and stop behaviour with 74 native cases. Full cross-object mission execution remains separate.

Reserve activation and context exchange

Native reserve and context analysis documents category queues, reverse setup order, objective-counter changes, owner registration and paired script/message cursor exchange. The viewer exposes initial reserve queues and decoded operations without treating them as a runtime spawn schedule.

Multi-object update ordering

Native list-walker traces establish which activations can receive callbacks in the same update and distinguish immediate opcode context swaps from the deferred late-frame context gate. These controlled traces preserve the original walker; they are not full mission playthroughs.

Callback inventory and geometry context entry

Callback census exports all 1,857 native setup callback assignments and documents 12 checked geometry-entry cases. It distinguishes the main script scheduler from the compact vehicle-route interpreter.

Supplementary records

Supply and blackout script paths now link all 13 callers to their supplementary record and distinguish explicit context returns from the permanent blackout delay loop.

Supply pad motion

Approach, centring and departure now have bounded native checks, including the docked output target and the script/input gates for return to ordinary Skimma flight.

Combined supply cycle

Controlled motion/script/message trace now runs both supply records through departure and checks all 21 upgraded-supply messages in order. Weapon/shield effects now execute natively; attitude integration remains explicitly substituted.

Blackouts and object completion

Blackout replay and mission inventory correct the header-queue lifecycle and distinguish partial failures, shared grid failure and final-mission choreography. Object completion checks connect native list expiry/counters to the player objective wait in the same update.

Reconstruction evidence index

Evidence and remaining integration work consolidates the asset/logic coverage, native fixtures, corrected assumptions and open questions across subsystems. Persistent cell-state checks establish ordinary 20h/40h packing without assuming a repair policy.

Real persistence and exit handling

Real-map persistence checks verify eligibility and complete restoration/variant rebuilding on all ten maps. Exit-state tests connect beacon queue application to successful city-state commits and distinguish runtime changes from saved progression.

Selection and city retries

Real selection/reload checks establish failure rollback to committed city damage, the stage-1 restoration bypass, and the special Nightmare entry at 04_015/0. The record lookup is arithmetic selection, not save validation.