Player collisions, streetlight destruction and shields
Why a crashed-into streetlight changes model
The observation is supported by the original response path and real bank collision data: Delphi type 11 is the only base-state type in banks 30–32 with a collision primitive that qualifies for building damage from the player handler. Other player building impacts still crash the player, but do not advance the building state through this handler.
The player list header is 6FD0. Collision dispatch at 6E56 selects a word at
list header +28, with result-category bits added to the header address:
| Outcome | Player handler |
|---|---|
| Terrain/surface | 6F84 |
| Map building | 6EEC |
| Other object | 6ED4 |
6EEC first skips a player already carrying expiry flag 20. Otherwise it calls
CDB9, then enters the player crash sequence at 6F4F. CDB9 resolves the
current model through 2DE1, including state-selected alternate/damage links.
For a player definition, category 2 and a nonzero current model damage link
admit mutation at 67C1. Category 1 is excluded; other categories reach weapon
checks which player definition pointers do not pass.
The category is not the building type ID or the descriptor's collision marker.
It comes from a collision primitive's opcode shifted right by three
(606C–6073). Type 11's base collision stream begins at 8080 with opcode 10,
giving category 2. The native model selection and admitted-hit response were
checked for states 00, 20, 40, 80, across the four player definitions
25–28. The resulting 5,088 cases all passed. At base state, the eligible
set is {11} for Delphi and empty for Halon and the underground bank.
These tests use actual model headers and collision streams but supply the hit
category from those streams. They do not execute geometric intersection or
prove a collision from every approach. Types marked non-colliding (FF in the
bank descriptor) are excluded. Visual effect spawning is intercepted after
native state mutation; the player crash state changes execute normally.
Crash transition
6F4F installs motion callback 6EF7, marks flags 08 and 20, and schedules
expiry 1,536 clock ticks after BF8 (approximately 3.07 seconds at 500 Hz).
It clears speed +3E, engine/shield flag 4552, and other control/camera state.
The crash motion callback changes heading and steers pitch toward EC00.
This is a separate lethal path from ordinary damage accumulation.
The terrain handler 6F84 additionally ignores contact while object flag 10
is set; this is consistent with a special landing/docking state, but not yet a
complete explanation of all terrain contacts. The object-collision handler
6ED4 damages the other object with strength 5C, then applies randomized
player damage with its high bit set. Neither path is included in the building
census fixture.
Reproduction
PYTHONPATH=/tmp/darker-python python3 tools/verify_player_collisions.py
Native results and collision-category census.
Geometric confirmation
A second fixture now runs 6DF1, 6D35, 6527 and the native collision
primitive tests, rather than supplying an admitted hit. It sweeps the player
through isolated real Delphi models along both horizontal axes and directions,
at six heights, in base and first-damage states. 384 sweeps produced 256
building hits and 20 building-state changes. The tested types are 1, 11, 12,
30, 75, 76, 77 and 86; every state change was a streetlight.
For a concrete comparison, a horizontal centre crossing at height 100 collides with both type 11 and type 30. The streetlight advances from state 0 to 32; the house stays at state 0; both crash the player. The same streetlight crossing at height 1000 clears the geometry. Impact coordinates are recorded too.
This closes the geometry-to-response link for controlled trajectories. The old and new positions are supplied, not produced by a flight callback; other objects and effects are excluded. It is not a captured gameplay run.
PYTHONPATH=/tmp/darker-python python3 tools/verify_player_collision_geometry.py
Player damage and the invulnerability cheat
A further 20,480 native cases execute 84D0 (including its randomized angular
kick) and the health/crash gate 6F45. They cover every incoming damage byte,
Caero and both Skimmas, shields enabled/disabled, several reserve levels and
initial Caero damage levels, with and without “Who gives true life?”. Visual
effect spawning alone is intercepted.
The Caero damage word at 8509 has a peripheral amount in its low byte and a
major-damage count in its high byte. Every 68 peripheral units become one major
unit. An incoming byte with bit 7 set contributes two major units plus its lower
seven bits. A high-byte count of at least four causes the crash gate to fire.
This agrees with the manual's outer/inner Damage Report System display, rather
than treating its two indicators as unrelated quantities.
For Skimmas, an enabled shield subtracts the incoming byte from reserve 810A.
Depleting it exactly is lethal, as is exceeding it: status high byte becomes
4, which the subsequent gate turns into a crash. With shields disabled, any call
through this damage path sets that lethal status. This includes a zero incoming
value; whether such an event occurs naturally depends on the caller.
The cheat zeroes incoming AL after the angular kick. It prevents new Caero damage here and preserves a positive enabled Skimma shield reserve. It does not prevent the unshielded Skimma branch or the zero-reserve branch from marking lethal damage, remove pre-existing lethal Caero damage, or bypass the separate building-crash handler. Nor does it suppress the preceding impact kick. Thus it is not universal invulnerability.
PYTHONPATH=/tmp/darker-python python3 tools/verify_player_damage.py
Flight callback integration
The interactive native trace viewer
replays 48 controlled runs. Each step executes the entire normal Caero 7EB6
or Skimma 8108 callback, then native collision pass 6F0F. Craft definition
motion parameters and the vertical displacement patch come from the original
records; the sine-table startup extension is included. Both engine/shield
states and cheat states are covered. Twenty-eight runs enter the crash callback;
the rest reach the 512-tick limit, which does not imply they are indefinitely safe.
The cheat leaves each paired scenery trace identical. All building-state changes
are streetlights. These runs use fixed 8-tick steps, zero processed input, an
isolated building and a supplied airborne initial state; no claim is made of
complete game-loop or independent C++/Python flight-model equivalence. Full
flight instructions execute, but input production, other actors, drawing and
effect spawning are excluded. Upgraded Skimma starts after its initial docking
transition. Reproduce with tools/trace_flight_collision.py.