From 7a88d24e669811dbc8b76fd4e16862d0a86dc0be Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Tue, 25 Aug 2026 20:23:34 +0000 Subject: [PATCH] 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. --- docs/re/mission-objective-vocabulary.md | 54 ++++++++++++++++++++----- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/docs/re/mission-objective-vocabulary.md b/docs/re/mission-objective-vocabulary.md index af497080..71a20cc5 100644 --- a/docs/re/mission-objective-vocabulary.md +++ b/docs/re/mission-objective-vocabulary.md @@ -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**