Executable gameplay definitions
Open the gameplay definition browser for all 33 object records, their values, meanings, code references and model bindings. Machine-readable exports are JSON, CSV, and the exact 792 table bytes.
This is a systematic export of the identified object/weapon table, with a catalogue of related exports. It is not a claim that every executable constant, AI rule or mission script has been decoded. Unknown fields and partial meanings are explicitly labelled.
Addresses and table boundaries
The canonical unpacked image contains 33 records × 24 bytes at 1926–1C3D. All addresses here are image offsets, excluding the original MZ header. Each exported record includes its offset, slot, raw bytes and role-specific field interpretation. The exporter requires the verified image SHA-256.
BF1A–BF23 calculates 1926 + slot * 24. The constructor allocates/clears a 112-byte runtime object and expands its definition. Do not confuse that mutable object with the 24-byte static definition: runtime BP-relative accesses use SS; the definition is read through DS. A partial runtime layout records established offsets and references.
The first word is zero in every original record. The geometry-bank loader overwrites it with the selected bank's special-model pointer plus 0400. Exports retain the original zero and separately provide all 99 bank/model bindings. They do not bake one city's pointer into the original definition.
Common fields and overloaded roles
| Offset | Size | Interpretation and consumers |
|---|---|---|
| +00 | word | Bank-patched geometry pointer, copied to runtime +22 (BF46) |
| +02 | word | Initial update callback, copied to runtime +66 (BF4A) |
| +04 | byte | Angular response seed; runtime +30 = byte × 8 (BF55–BF5E) |
| +05 | byte | Runtime +32 = byte × 256; full physical meaning pending |
| +06 | byte | Runtime +34 = byte × 64; full physical meaning pending |
| +07 | byte | Runtime +36 = byte × 128; full physical meaning pending |
| +08 | byte | Impact strength/comparison parameter (CE23, CE3B), not a universal hit-point count |
| +09 | byte | Projectile base speed term × 16 (CC87–CC92); also initial mission-object speed (BE83–BE8E) |
| +0A..+11 | 8 bytes | Role-dependent data; see below |
| +12 | word | Object sound callback (3573) |
| +14 | byte | Native FM patch (356B) |
| +15 | byte | Sound level high byte; low byte starts at FF (3566–3569) |
| +16 | word | Native sound pitch (356E), not Hz or a MIDI note |
Slots 0–18 form the projectile definition group. Slots 19–28 hold craft configurations; slots 29–32 are retained as other special objects. These group labels do not assign unproven in-game names to individual models. In particular, model identity varies with the loaded bank.
Projectile-specific fields:
| Offset | Interpretation | Evidence |
|---|---|---|
| +0A | Energy comparison high byte; low byte is FF | C9DA–C9F3 |
| +0B | Ordinary launch deadline delta in multiples of 256 timer units | CAC4–CAC6, CAF0–CB0F |
| +0C | Impact/collision callback | 6EB6–6EBA |
| +0E | Firing callback | C9FB |
| +10 | Guidance right-shift count | CCAC–CCAF |
| +11 | Target/impact flags; bit 1 participates in ground-target and building-hit handling | D022–D029, CDDA, CDFB |
The energy comparison is not a universal energy cost, and the deadline is not a firing rate. Individual firing callbacks can charge energy differently, accumulate it, require particular targets, or substitute state. Projectile update callbacks can also add guidance-dependent motion. The exported values are native parameters, not a ready-made balance sheet in physical units.
For craft, +0C..+0F cannot be read as two weapon function pointers. In player setup, +0E is a speed seed multiplied by eight; +0F patches a byte in the vertical-target calculation (BD16–BD22). The export retains the other role-specific bytes without speculative names.
Weapon-selection mapping
Caero's selection path calculates 190E + selection_id * 24 (C9D1–C9D8), equivalent to object slot selection_id − 1. The export records IDs 1–10, mapping to slots 0–9. These are arithmetic mappings: availability masks, primary/secondary selection and handler rules still determine what can be fired.
The other-craft firing path calculates 1A16 + selection_index * 24 (C99C–C9A3), selecting slots 10, 11, 12 for indices 0, 1, 2. The three definitions have different speed seeds and angular response values; they are not aliases of the same weapon definition.
Slots 13–18 retain projectile movement/impact/sound data but have zero firing-handler words. They are outside those player selection ranges. Follow-up: weapon identities and behaviour now links all ten Caero slots to names through mission introductions and native availability instructions. The export includes those names.
Identical Skimma meshes, different parameters
Player setup chooses slot 24 + byte[F003] (BD0E–BD13). The known configurations are:
| Slot | Configuration | Update callback | Angular response +30 | Motion +32 | Motion +34 | Motion +36 | Initial speed target |
|---|---|---|---|---|---|---|---|
| 25 | Caero | 7E7F | 416 | 40960 | 1280 | 5120 | 1656 |
| 26 | Skimma | 8108 | 352 | 40960 | 4480 | 13440 | 256 |
| 27 | Upgraded Skimma | 7E49 | 384 | 40960 | 5120 | 13440 | 256 |
| 28 | Underground configuration | D510 | 176 | 0 | 0 | 0 | 96 |
These are constructor/setup values, not measured top speeds. The upgraded Skimma's callback can transition to normal Skimma flight; its identical model pointer does not make its full configuration identical. The signed vertical-target bytes are respectively −90, −106, −110, −90, but these are not established gravitational accelerations.
The selected flight constants separately retain PIT reload 2386; Skimma speed targets 248, 500 and upgraded turbo 640; and Caero boost high-byte cost/activation values 32 and 56. These are instruction immediates, not members of the 24-byte table.
Runtime mutation matters
- Bank loading patches model words.
- Runtime object callbacks can change state; the initial callback is not always the steady-state function.
- Projectile code at
CC5Cwrites a new pitch into19CC(slot 6 +16), so even definition-table sound values can change during play. - Mission setup, availability masks, and self-modifying immediates supplement the static definitions.
- Original fixed-point scales, integer rounding and overflow behaviour must be preserved by a faithful adaptation. Exporting a seed does not replace its consumer logic.
Related data and reproducibility
The catalogue links existing exports of sine values, startup parser keys, flight bindings, native sound definitions, ambient source tables and hidden commands. These remain in their established locations rather than becoming duplicated data sets.
python3 tools/export_gameplay_data.py
PYTHONPATH=/tmp/darker-python python3 tools/verify_gameplay_data.py
Verification reconstructs all 33 records from decoded fields, compares the binary export against the image, runs the original constructor for all 33 slots, and runs the original indexing arithmetic for all 13 player weapon mappings. Consumer disassembly provides the relevant instructions. These checks do not execute full AI, firing, flight or audio behaviour.
Remaining work: identify Skimma/enemy weapon names; decode the remaining craft bytes, target flags and movement parameters; trace firing/impact handlers into equations and state machines; recover further AI and mission data structures as their boundaries become established.
For a player-facing interpretation of the strength/resistance fields, see enemy resistance, recovery and weapon strength and the minimum-hits chart. Definition byte +8 is not a universal hit-point amount: its role depends on whether the definition belongs to the projectile or the victim.