re: built-in 15 IS set_group_speed — and the turret anomaly was my own artefact

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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Sylpheed RE agent
2026-08-26 01:18:30 +00:00
parent 161ee4df3a
commit dde827cb3c
3 changed files with 48 additions and 3 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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',