Model components, landing structures and pointer sharing
Update: animated geometry and linked model states now implements gate/fountain transforms, exports 27 additional linked definitions, and adds state/animation controls. Earlier references below to those models being unresolved describe the previous extraction pass.
2026-09-18. Reproduce with python3 tools/inspect_model_components.py.
The machine-readable inventory is components.json.
Addresses below refer to the unrelocated executable image or explicitly to a bank's geometry pool.
Screen-space discs
The command is 22 colour:u8 radius_numerator:u16le. In the ordinary projection
path, FC22 dispatches to 314D: it subtracts four from the projected-vertex
cursor, takes that vertex's screen coordinates, resolves the colour via 3383,
and calls A5C0 with the numerator in AX and projected depth in CX.
Thus it consumes the last vertex slot, which subsequent vertices may reuse.
The native A,B,C coordinates below use the model export's convention (A,-C,B)
for Y-up coordinates.
At A5C0, unsigned integer division gives radius_numerator / projected_depth.
The result is capped at 256 screen units; zero takes the single-pixel path.
The following routine constructs clipped horizontal circle spans. There is no
bitmap, UV map or spherical polygon mesh in this command. The near/clipped
handler 3161 rejects depths below 32 before projection. Colours go through the
same distance/runtime shade machinery as flat faces, then the display lookup.
These are internal units, not established metres or an independent world radius.
| Bank / entry | Centre A,B,C | Colour byte | Numerator |
|---|---|---|---|
| 30 / city 1, energy beacon | (0,0,-2400) | 0D |
30720 (7800) |
| 30 / city 11 | (0,0,-720) | 1C |
6144 (1800) |
| 30 / city 101 | (198,-198,-160), (198,-198,-608) | 93, 1B |
19712 each (4D00) |
| 30 / city 102 | (198,198,-160), (198,198,-608) | 93, 1B |
19712 each |
| 30 / city 103 | (-198,198,-160), (-198,198,-608) | 93, 1B |
19712 each |
| 30 / city 104 | (-198,-198,-160), (-198,-198,-608) | 93, 1B |
19712 each |
| 30 and 32 / special 0 | (64,0,0) | 1C |
2176 (0880) |
The tower disc therefore sits at Y=2400 in the exported coordinate system.
For illustration, projected depths 1024 and 2048 yield integer screen radii 30
and 15. 1C is a dynamic shade token, not simply a fixed palette index 28.
The two discs of types 101–104 are real separate drawing commands.
This inventory covers the statically traversed base definitions, not every alternate/damage model or unresolved animation branch. No discs were encountered in bank 31's traversed definitions. Discs are now shown as camera-facing circles in the model preview (and city viewer), but remain omitted from OBJ surfaces. Their exact definitions and pool offsets are retained in the JSON; see preview scaling.
Other non-polygon components encountered are opcode 1E coloured lines:
city types 65 and 67 in bank 30, type 41 in bank 31, and 111 and 112 in bank 32.
There are also model-header distant-point representations and conditional
visibility branches; these are not additional mesh faces. The static inventory
is deliberately not a claim to have exhausted runtime effects or particles.
Fountain reflections: authored geometry, not transparent water
Open the assembled animated fountain. Its twelve components are placed from map 68: two instances each of types 101–104 and one each of 120–123. The authored face/disc order reproduces the tinted reflection over the opaque water; switching off Authored drawing order shows why ordinary polygon depth sorting breaks this effect. Animation starts automatically and the clock can be paused/scrubbed. The view remains orthographic, with approximate between-component sorting and disc sizing.
The facing-test sign was checked against 256 controlled executions of native
2F65: it skips when the screen-space cross product is negative, as used by
the viewer. The earlier reflection failure was caused by inspection depth
sorting, not an inverted conditional branch. This check covers the sign for
supplied projected vertices, not equivalence of every perspective camera pose.
Visual inspection identified the lower discs and pedestal shapes as reflections.
The bank-30 type-101 data confirms reflection about the water plane at exported
Y=384: the upper light is at Y=608, the lower copy at Y=160, exactly 224 units
on either side. Types 102–104 repeat the arrangement in the other quadrants.
Both discs use radius numerator 19712, but the upper colour is 1B and the
reflected colour is 93, giving the reflection its authored tint.
The lower pedestal includes exact mirrored polygon counterparts: replacing
native C with -768-C maps upper faces to lower ones, with different face
colours (for example 47 becomes 86, and 70 becomes 8F). These are stored
vertices and palette choices, not a runtime reflection transform.
There is no transparent-water material in this model. The ordinary opaque
water faces (colour 8B, Y=384) are issued first, followed by the reflected
disc and tinted pedestal geometry, then the remaining fountain structure.
For type 101, water commands start at pool 9D19, the reflection disc is at
9D45, and reflected pedestal faces follow at 9D49 onward. Stored command
order matters more than increasing byte offsets because the model calls shared
subroutines. The software renderer has no depth buffer to reject those later
reflection pixels for lying below the water plane.
Thus the appearance of seeing through water is an authored reflection illusion: opaque colours and drawing order, not alpha blending. No semitransparent model material has been identified in the decoded retail model command set. Collision overlay translucency belongs solely to the inspection UI. This does not claim that every other screen effect or sprite in the game uses the same mechanism.
Landing gates and animated geometry
HQ gates were proposed for 17,19,21,23 and approach stripes for 18,20,22,24. The executable strongly supports the landing gate/approach identification:
C598–C5A5fetches the cell beneath the Caero. During the automated landing state,C5F9subtracts 17, requires a result below 8, then shifts right. The odd/even branch therefore distinguishes the gate/stripe pairs explicitly.C656–C668advances an animation value byCS:[7A2B] << 6, capped atE800.C631stores that value atSS:7935. Another branch computes it from approach distance; landing/takeoff state also affects it (C5A7–C5BD).- Each of gate types 17,19,21,23 contains
32 00, at pool offsets1408,168E,1731,1D11, respectively. Handler319Ereads the low five cell-state bits, adds the command's parameter byte and indexes words atSS:7935. The32/35/38handlers then alter projected geometry using that parameter. C670–C6EFchecks the landing approach, installs the automated movement callback and toggles state bit80on the selected cell and its two neighbours. That bit also selects alternate model definitions, as documented previously.
This is stronger evidence than spatial proximity alone. It does not establish that every occurrence belongs to one of the four specifically named HQs on the paper map. The main-city resource contains nine type-17 and eight type-21 cells, with the corresponding stripe immediately in front of each. Types 19/20 and 23/24 do not occur in that resource. Other mission state may alter the map.
Types 14 and 16 are empty base drawing definitions, not currently undisplayed
HQ meshes: both point at pool 0FC9, whose body 5A 52 61 0D emits an origin
vertex and returns without polygons. Types 78 and 125 share it. Neither 14 nor
16 occurs in the supplied main-city map. An additional role elsewhere is not excluded.
Types 120–123 use another dynamic transform, 3B 09, at pool offsets
BDBB, C037, C197, C2F7. Handler 334A reads the same parameter table and
scales projection coefficients. DB1A–DB69 updates six parameters beginning at
SS:7947 (index 9), driven by the clock and a sine lookup. This identifies a
procedural animation dependency. Subsequent visual inspection identified these as
probable fountain effects: their four map cells form the central 2×2 of the
fountain, surrounded by pool types 101–104. See the
assembled scene and coordinates.
The eight animated definitions still need correct transform emulation before
claiming complete exports.
Shared pointers versus copies
Within a bank, the repeated entries overwhelmingly are aliases to the exact same drawing stream, not duplicated meshes. The 33 special records use only 23 distinct pointers in bank 30, 9 in bank 31, and 19 in bank 32.
| Bank | Special slots | Shared pool offset |
|---|---|---|
| 30 | 19,24,26,27 — Skimma geometry | D25F |
| 30 | 25,28,29 — Caero geometry | C9E0 |
| 30 | 11,13,16 | C819 |
| 30 | 12,17 | C8C0 |
| 31 | 19,24,25,26,27,28,29,30,31,32 — Skimma geometry | 4E53 |
| 31 | 0–10,15 | 4C37 |
| 31 | 11,13,16,18 | 4C8C |
| 32 | 19,22,23,24,26,27 | C1AF |
| 32 | 25,28 — Caero geometry | B930 |
| 32 | 29,30,31,32 | C5A4 |
Every group, including the remaining pairs and singletons, is in components.json.
The early special objects were identified as ammunition through gameplay; individual weapon names
have not yet been assigned from their behaviour records. The apparent repeated
tanks can be checked by their numeric slots in this table/inventory without
assuming a tank name from silhouette alone.
The executable retains separate 24-byte object definitions at 1926+24*i;
the bank loader fills their model pointers. Equal geometry therefore does not
imply equal behaviour, weapons, damage or player controls.
Across banks, data lives in separate resource pools: there is no cross-bank pointer sharing in this directory format. Shape comparison, ignoring colour and shade attributes, finds bank-30/31 Skimma geometry identical, bank-30/32 Caero geometry identical, and specials 20 and 21 geometrically identical across all three banks. Their complete colour-bearing exports are not all identical. The underground Skimma has 97 polygon commands versus 99 in banks 30/31. Drawing streams also use relative subroutine calls; their actual targets are listed, rather than treating each directory slot as a self-contained mesh blob.
Follow-up audit: empty Delphi types 14, 16, 78 and 125
These four IDs have identical eight-byte directory records, c9 0f 80 80 00 00 00 00, not merely similar-looking previews. All select pool offset 0FC9 (resource offset 1457). None occurs in the supplied Delphi map, resource 00/68.
The 11-byte header is 00 00 00 00 f0 86 ff 00 00 00 00: both damage and alternate links are zero. The complete drawing body is 5A 52 61 0D, which produces one origin vertex and returns. There are no polygon faces, lines, light discs, transforms or subroutine calls. All 256 possible state-byte values retain that same empty result.
An audit of all 154 unique city headers reachable through the bank's type directory and state links found no incoming damage/alternate links to this definition. None of the 33 special-object pointers aliases it. Decoding city/state and special drawing streams found no calls into it; a broader raw scan also found no relative call/jump candidates into its 15-byte header/body range.
The evidence therefore supports unused empty directory slots in the shipped Delphi base assets, plausibly placeholders left by content development. Their position next to particular building IDs does not establish a hangar, collision trigger or other identity. There is no concealed model or non-polygon visual component to recover from these bytes.
This is not proof that the IDs can never be introduced dynamically: the audit does not yet cover every executable path and mission-script operation. No specific gameplay purpose has been established for them. Likewise, this finding applies to bank 30; the same numeric IDs in other banks are different definitions.
Reproduce with python3 tools/inspect_empty_models.py; results are in empty-model-audit.json.