re: the object is PlayerParams, and sub_822F9498 is ITS loader -- not the unit loader
Resolving every string sub_822F9498 references, in code order, gives 90, and they are exactly the 890e1be4 object's schema in its record order: Misc (5 effect names), SpecialAttack (+17), TacticalManeuver (+7), SpecialWeapon (+8), Booster (+50). It never names Generic, Maneuver, Explosion, Shield or StructureCount, and the string Maneuver has 0 xrefs. One call site, from sub_821A6CF0, which is itself called once and references the literal PlayerParams. CORRECTION to unit-datasheet-static.md, which calls sub_822F9498 the unit-definition loader. It loads one object: the player parameter table. Its AA_/AV_ interleave still stands as a struct layout, but the struct is PlayerParams's Booster record, not each unit's Maneuver. What loads the 114 unit Maneuver records is now an open question -- it uses none of these strings. Ranking all 114 units by how many of Booster's 50 values they reproduce: the top five are exactly the five _Player units, all at 39/50; the sixth drops to 13/50; none matches 50/50. The five players agree with each other on all 50 -- the three player ships share one flight model. Booster stands alone on 10 fields; the eleventh, AA_Yaw_Max, is 65.0 vs 65, formatting not a value (last iteration's "11 differ" over-counted). Still open, and sharper: nothing selects Booster. PlayerParams is loaded once, unconditionally, no branch -- yet the measured flight tracks the unit Maneuver (1.25/1.20/1.28) and misses Booster badly. Both cannot govern the same craft; the next test is a runtime watch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
@@ -76,16 +76,64 @@ The object's other records stand as described: `TacticalManeuver`
|
||||
`RollToHorizonTime 2.0`), `SpecialAttack` + `SpecialAttackGauge_1/2/3`
|
||||
(`ChargeMaximum` 33 / 66 / 100), `SpecialWeapon`, `Misc`.
|
||||
|
||||
## ✅ The consumer: `sub_822F9498`, the unit-definition loader
|
||||
## ✅✅ The object is `PlayerParams`, and `sub_822F9498` is ITS loader — not the unit loader
|
||||
|
||||
The string-xref join settles it. The field-name block at **`0x8209F300–0x8209F600`**
|
||||
— `BulletTimeVolumePC`, `FireBirdPower`, `ChargeMaximum`, `Turn180RequiredTime`,
|
||||
`RollToHorizonTime`, `ShieldDoubler_Time`, `HPRegenerator_RegenSpeed`,
|
||||
`ExtraCartridge_Quantity`, … — is **36/36 referenced**, and every reference lands
|
||||
inside **`sub_822F9498`**, the loader [[live-unit-definitions]] already documents
|
||||
(← `sub_821A6CF0`, global `[0x828F358C]`). So the special-attack / tactical
|
||||
records are read by the same code that reads unit definitions, which is exactly
|
||||
what a `Maneuver`-schema `Booster` predicts.
|
||||
Resolving **every** string `sub_822F9498` references, in code order, gives **90**
|
||||
of them, and they are **exactly this object's schema, in this object's record
|
||||
order**:
|
||||
|
||||
```
|
||||
CollisionEffectName … EffectPlacementFrameName (Misc, 5)
|
||||
SpecialAttack + 17 fields
|
||||
TacticalManeuver + 7
|
||||
SpecialWeapon + 8
|
||||
Booster + 50
|
||||
```
|
||||
|
||||
It never names `Generic`, `Maneuver`, `Explosion`, `Shield` or `StructureCount`;
|
||||
the string `Maneuver` exists once in the image and has **0 xrefs**. The function
|
||||
is called **exactly once**, from `sub_821A6CF0` — which is itself called once and
|
||||
whose four strings include the literal **`PlayerParams`**.
|
||||
|
||||
⇒ 🔴 **Correction to [[unit-datasheet-static]], which calls `sub_822F9498` "the
|
||||
unit-definition loader".** It reads one object, the player parameter table. Its
|
||||
`AA_`/`AV_` interleave finding (`AV_` at `X`, `AA_` at `X+8`, five axes) still
|
||||
stands as a **struct layout** — but the struct is **`PlayerParams`'s `Booster`
|
||||
record**, not each unit's `Maneuver`. Whatever loads the 114 unit `Maneuver`
|
||||
records does not use these name strings at all, and has not been found.
|
||||
|
||||
🟡 `name_hash`/`tag_hash` of `PlayerParams` under 7 prefixes × 6 spellings
|
||||
(84 combinations) hits the object's key `0x890E1BE4` **0 times** — the string
|
||||
names the table to the code, not the pak entry.
|
||||
|
||||
⚠️ The loader names **8** `SpecialWeapon` fields; the disc values **7**.
|
||||
`HPRegenerator_Quantity` is named and never valued — the usual pattern.
|
||||
|
||||
## ✅ All five player craft fly identically; `Booster` differs on ten fields
|
||||
|
||||
Ranking all 114 units by how many of the 50 `Booster` values they reproduce:
|
||||
the top five are **exactly the five `_Player` units** — `f001_T`, two
|
||||
`f001_T_Tt`, `f002_W`, `f004_A` — all at **39/50**, and the sixth-best unit drops
|
||||
to **13/50**. **No unit matches 50/50.**
|
||||
|
||||
✅ And the five players **agree with each other on all 50 fields**: the three
|
||||
player ships share one flight model. `Booster` stands alone on **10** of them
|
||||
(the eleventh, `AA_Yaw_Max`, is `65.0` vs `65` — a formatting difference, not a
|
||||
value; my earlier "11 differ" over-counted).
|
||||
|
||||
## 🟡 So what selects `Booster`? Nothing does, and that is the problem
|
||||
|
||||
`PlayerParams` is loaded **once, unconditionally**, at startup: one call site,
|
||||
one caller, no branch. So `Booster` is not a profile the game *chooses* — it is
|
||||
the only flight table this path loads.
|
||||
|
||||
🟡 **That is in tension with the measurements and I have not resolved it.**
|
||||
[[flight-speed-law]] clocked the player at ~125 / ~420 / ~1 530, which tracks the
|
||||
unit `Maneuver` 100 / 350 / 1 200 at a flat ~1.25 and misses `Booster`'s
|
||||
100 / 612 / 2 100 badly — and the `RT`-held run reached ~1 530, not anything near
|
||||
2 100. Both tables cannot govern the same craft. **Cheapest next test is a
|
||||
runtime one:** watch which of the two constant sets reaches the live flight
|
||||
struct, and re-measure with the afterburner held.
|
||||
|
||||
## 🔴 BLOCKED: the analog-curve block is referenced by nothing
|
||||
|
||||
|
||||
@@ -114,6 +114,16 @@ adopted**. See below for what the executable does say.
|
||||
|
||||
### ✅ The two families are one interleaved block (2026-08-27)
|
||||
|
||||
> 🔴 **Corrected 2026-08-27 — `sub_822F9498` is not the unit-definition
|
||||
> loader.** Every one of the 90 strings it references is a field or record name
|
||||
> of the **`PlayerParams`** object (`Misc` / `SpecialAttack` / `TacticalManeuver`
|
||||
> / `SpecialWeapon` / `Booster`); it never names `Generic`, `Maneuver` or
|
||||
> `StructureCount`, and `Maneuver` has 0 xrefs. It is called once, from
|
||||
> `sub_821A6CF0`, which references the literal `PlayerParams`. **The interleave
|
||||
> below is real — but it is the layout of `PlayerParams`'s `Booster` record, not
|
||||
> of each unit's `Maneuver`.** See [`player-tuning-tables.md`](player-tuning-tables.md).
|
||||
> What loads the 114 unit `Maneuver` records is now an open question.
|
||||
|
||||
Exactly **one** function in the image references the `AA_`/`AV_` name strings:
|
||||
`sub_822F9498`, the unit-definition loader, itself called only from
|
||||
`sub_821A6CF0`. Mapping each `addi rN, r29, -offset` (the name) to the `stfs`
|
||||
|
||||
Reference in New Issue
Block a user