re: correct 'no mission counts kills' -- attribution IS used, globals are not

I wrote that no mission counts kills. Too strong. What holds is narrower: no
mission reads the two GLOBAL counters (33/34, verified 0 sites). The game does
track kills and missions test them through attribution:

  built-in 105 killed_by_player(unit) -- reads [squadron+600], which the
  unit-death handler sets from the damage message's _BY_PLAYER flag -- 117 sites
  across 14 stages (S02: 38, S01: 32), the 17th-most-used built-in in Stage 02.

  built-in 72 -- numerator is a per-(killer, victim) squadron KILL COUNTER,
  incremented in the unit-death handler; 13 sites, S01 only.

So 'did the player get that kill' is a common predicate; the game just never asks
'how many kills in total'. Evidence for 105 is the game's own strings: the death
handler branches into KILLED_BY_PLAYER vs KILLED, beside LOST_TURRET_BY_PLAYER,
SHIELD_DOWNED_BY_PLAYER and the rest.

Also withdraws the 'current / initial members' gloss on built-in 72: it is
100 x (units of B killed by A) / (declared members of B), attributed kills rather
than survivors, and reads 0 unless the script registered the (A,B) pair.

Built-in 55 resolved and shown to be effectively dead (0 sites corpus-wide);
built-in 75 confirmed as five HUD text lines via a [phase+376] dictionary.
This commit is contained in:
Sylpheed RE agent
2026-08-25 20:23:34 +00:00
parent ac4f53b8a1
commit 7a88d24e66

View File

@@ -15,10 +15,28 @@ all 28 stages**. Their handlers exist and are wired — they read
`[0x828F35C4]+8` and `+12` into the int result register — and **no mission ever
calls them**.
That settles the "does a wave start after N kills?" question far beyond Stage 02:
**no mission in the game counts kills.** 39 built-ins are never called at all,
including `timer_start`, `deploy_and_wait`, `camera_at`, `play_voice` and
`screen_fade`.
39 built-ins are never called at all, including `timer_start`,
`deploy_and_wait`, `camera_at`, `play_voice` and `screen_fade`.
### 🔴 CORRECTION: "no mission counts kills" was too strong
I wrote that here, and it is wrong as stated. What is true is narrower: **no
mission reads the two GLOBAL counters.** The game does track kills, and missions
do test them — through *attribution*, per unit and per squadron pair:
| built-in | what it is | sites |
|---|---|---|
| **105 `killed_by_player(unit)`** | reads `[squadron+600]`, which the unit-death handler sets from the damage message's `_BY_PLAYER` flag — "was the most recent death in this squadron the player's doing" | **117 across 14 stages** (S02: 38, S01: 32) |
| **72** | numerator is a per-`(killer, victim)` **squadron kill counter** incremented in the unit-death handler | 13, **S01 only** |
`killed_by_player` is the 17th-most-used built-in in Stage 02. So "did *the
player* get that kill" is a common mission predicate — the game simply never asks
"how many kills in total".
The evidence for 105 is the game's own strings: the death handler branches on
that flag into `"KILLED_BY_PLAYER"` versus `"KILLED"`, alongside
`LOST_TURRET_BY_PLAYER`, `SHIELD_DOWNED_BY_PLAYER`,
`DAMAGED_BY_PLAYER_GREATER_50` and the rest of the family.
## ✅ `hp_pct_test(unit, 0.0)` *is* a destruction test
@@ -68,11 +86,29 @@ entries, and its conditions are a descending player-gauge ladder
## 🟡 Not settled
* **`group_ratio_pct` (72)** takes **two** unit indices — blob+4 and blob+12 —
and its numerator comes from a pair-keyed lookup through `[phase+328]` that
was not read to the bottom. The natural reading (a per-squadron ratio credited
to the player's flight) fits S01's usage, but is **not** established, so it is
not being called "percent killed by the player".
* **`group_ratio_pct` (72) — read to the bottom, and the old label was wrong
in the numerator.** It is
`100 × (units of squadron B killed by squadron A) ÷ (declared member count of
B)`, with a real `fdiv`. The numerator is `e[+12]` of a 16-byte entry in the
table at `0x828F363C`, created by an interpreter command (max 32 entries) and
incremented inside the unit-death handler as
`(killer squadron id, victim squadron id)`. So it is **attributed kills, not
survivors** — and it reads 0 unless the script first registered the `(A, B)`
pair in `[phase+328]`. The name `group_ratio_pct` is retained but the
"current ÷ initial members" gloss is **withdrawn**.
***Built-in 55 is effectively dead**: **0 call sites corpus-wide**. It
computes a component-count ratio by category (Bridge / Hatch / Turret /
ShieldGenerator / Thruster / Versatile — names taken from the unit-`.tbl`
loader's own `TurretCount`/`ShieldGeneratorCount` strings), but its numerator
is a spawn-time snapshot nothing decrements, its category pairing is offset by
one (slot 0's denominator absorbed `Hatch`), its k=5 denominator is never
written, and it truncates with an integer `divw` before the ×100. Whether the
misalignment is a shipped bug is **unknown**.
***Built-in 75 is text** — five symbol-table-1 names resolved through a
dictionary at `[phase+376]` into five 1024-wchar slots, which
`sub_821AA1B0` copies into five 256-wchar HUD fields when `[phase+336] == 2`.
Mechanism confirmed; **which** text (objectives, briefing, subtitles) is not.
39 sites, 3 in Stage 02.
* `isl.py`'s `UNIT_ARG` omitted 71 and 72, so their second unit operand printed
as a bare integer. Noted in the tool; 56 may be the same shape, unverified.
* The timer names in `isl.BUILTIN` look mismatched: 73 `timer_start` has **zero**