From dde827cb3c34509efcacde9c6804b030957c6411 Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Wed, 26 Aug 2026 01:18:30 +0000 Subject: [PATCH] =?UTF-8?q?re:=20built-in=2015=20IS=20set=5Fgroup=5Fspeed?= =?UTF-8?q?=20=E2=80=94=20and=20the=20turret=20anomaly=20was=20my=20own=20?= =?UTF-8?q?artefact?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The member object sub_82348830 returns is the per-member unit DEFINITION, and that identification is not a guess: the same spawn loop builds two aggregates and each lands on a semantically apt field with the apt reducer. group +192 min, seeded FLT_MAX member +164 = CruisingVelocity group +472 sum member +84 = HP A wrong struct would have to make both offsets land on apt fields AND pair each with the apt reducer. Minimum of a speed, sum of hit points: a formation's cruise limit and its total health. The quantitative test over all 1360 sites, joining each to its craft's definition: value <= the craft's MaximumVelocity 1355 / 1360 = 99.6% (5 fail) value <= the craft's CruisingVelocity 1042 / 1360 = 76.6% (318 fail) The test discriminates -- the cruise bound breaks 318 times, the hull maximum 5 -- so the script sets a COMMANDED SPEED, free to exceed the cruise default and bounded by what the hull can do. The turret anomaly that stopped me naming this two iterations ago was my own artefact. UN_e007_ADAN_Turret's definition carries MaximumVelocity 500 and CruisingVelocity 280: the data models turrets as if mobile, so a script value of 400 is legal and simply never manifests. I had assumed turrets have no velocity fields and treated 13% of the traffic as a refutation. Recorded as unsettled: the five overshoots are UN_e106_ADAN_Destroyer 200 vs a 150 maximum (x2) and UN_e011_ADAN_Attacker_B_HF/_Wayne 500 vs 450 (x3). Designer overrides or an engine clamp; not established. Named set_group_speed. Default = the slowest member's CruisingVelocity; mode 1 restores it, mode 3 sets it, mode 2 hands it a global constant. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE --- docs/re/data/isl-stage02.txt | 1 + docs/re/structures/isl-builtins.md | 49 ++++++++++++++++++++++++++++-- tools/re-capture/isl.py | 1 + 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/docs/re/data/isl-stage02.txt b/docs/re/data/isl-stage02.txt index e05498dc..f31566c2 100644 --- a/docs/re/data/isl-stage02.txt +++ b/docs/re/data/isl-stage02.txt @@ -91,6 +91,7 @@ Generated by `tools/re-capture/isl_report.py calls`. 30 objective_marker 179 20 hp_pct_test 167 47 squadron_attack 137 + 15 set_group_speed 127 18 dist_lt 92 5 kill_coroutine 83 70 unit_alive 71 diff --git a/docs/re/structures/isl-builtins.md b/docs/re/structures/isl-builtins.md index fb4c0639..a3073e49 100644 --- a/docs/re/structures/isl-builtins.md +++ b/docs/re/structures/isl-builtins.md @@ -140,7 +140,7 @@ and spread checks but its maximum *exceeds* the table — flag indices run 0..31 against symbol tables as small as 40 — so it is excluded, and the disassembler now declines to resolve it rather than printing an invented name. -### 🟡 Built-in 15 takes a craft-class scalar — but "speed" does not survive intact +### ✅ Built-in 15 is `set_group_speed` — the group's commanded speed `15` is the biggest unnamed built-in: **1360 sites across 27 of 28 stages**. Its operand shape is invariant — `(unit, double)` — and joining every call site's @@ -173,8 +173,51 @@ The asteroid is the control that makes this sharp: a genuinely immobile object gets **0 every time**, so "immobile things get a meaningless value" does not explain the turrets either. -So: ✅ a craft-class-dependent scalar in speed's range and with speed's ordering; -❌ not `set_speed` as a plain reading. **Left unnamed.** +#### ✅ What the members contribute — and why the turrets stop being a problem + +`sub_82348830` is a `std::map::find`, and the object it returns is the per-member +**unit definition**. That identification is not a guess: the same spawn loop +builds *two* aggregates, and each lands on a semantically apt field with the apt +reducer — + +| group field | reducer | member field (`unit_definition_layout.txt`) | +|---|---|---| +| `+192` | **min**, seeded `FLT_MAX` | `+164` = **`CruisingVelocity`** | +| `+472` | **sum** | `+84` = **`HP`** | + +A wrong struct would have to make both offsets land on apt fields *and* pair each +with the apt reducer. Minimum of a speed, sum of hit points: that is a formation's +cruise limit and its total health. + +#### ✅ The quantitative test, over all 1360 sites + +If the script is commanding a speed, its value should respect the craft's own +limits. Joining every call site to its craft's definition: + +| bound | holds | fails | +|---|---|---| +| value ≤ the craft's **`MaximumVelocity`** | **1355 / 1360 = 99.6 %** | 5 | +| value ≤ the craft's `CruisingVelocity` | 1042 / 1360 = 76.6 % | **318** | + +The test discriminates: the cruise bound is broken 318 times, the hull maximum +just 5. So the script sets a **commanded speed**, free to exceed the cruise +default and bounded by what the hull can do. + +🟡 The five exceptions are small overshoots on three craft — +`UN_e106_ADAN_Destroyer` 200 against a 150 maximum (×2) and +`UN_e011_ADAN_Attacker_B_HF`/`_Wayne` 500 against 450 (×3). Designer overrides, +or the engine clamps; not established. + +#### ✅ The turret anomaly dissolves + +`UN_e007_ADAN_Turret`'s definition carries `MaximumVelocity` **500** and +`CruisingVelocity` 280 — the data models turrets as if mobile. So a script value +of 400 is perfectly legal in the data model; it simply never manifests, because a +turret does not translate. The 13 % of sites that looked like a refutation were +an artefact of assuming turrets have no velocity fields. + +**Named `set_group_speed`.** Default = the slowest member's `CruisingVelocity`; +mode 1 restores it, mode 3 sets it, mode 2 hands it a global constant. #### ✅ The write side, read directly diff --git a/tools/re-capture/isl.py b/tools/re-capture/isl.py index ea1b4ece..4a177f0d 100755 --- a/tools/re-capture/isl.py +++ b/tools/re-capture/isl.py @@ -80,6 +80,7 @@ BUILTIN = { 1: 'start_coroutine', 2: 'deploy_squadron', 3: 'move_order', 4: 'wait_s', 5: 'kill_coroutine', 6: 'END_PHASE', 8: 'set_flag', 9: 'read_freg', 10: 'random', 11: 'end_coroutine', 13: 'play_se', 14: 'play_bgm', + 15: 'set_group_speed', 17: 'wait_frames', 18: 'dist_lt', 20: 'hp_pct_test', 24: 'squad_survival_pct', 26: 'damage_unit', 30: 'objective_marker', 31: 'objective_marker_at_route', 33: 'global_counter0', 34: 'global_counter1', 36: 'screen_fade',