From 6334f36dde5d43a90522b38df9c389799b7b94df Mon Sep 17 00:00:00 2001 From: "Claude (auto)" Date: Thu, 27 Aug 2026 20:48:56 +0000 Subject: [PATCH] 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) Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE --- docs/re/BACKLOG.md | 46 ++++++++++++++ docs/re/INDEX.md | 2 +- docs/re/structures/player-tuning-tables.md | 66 ++++++++++++++++++--- docs/re/structures/unit-datasheet-static.md | 10 ++++ 4 files changed, 114 insertions(+), 10 deletions(-) diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 66e8560..cee275d 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -4951,3 +4951,49 @@ taken for ours. 🟡 Not settled: what selects the `Booster` profile; what `adv_yaw`'s non-monotone curve indexes (unchanged — it needs the reader); why the `0x820A1xxx` block has no xref at all when its neighbour has 36. + +--- + +## ✅✅🔴 2026-08-27 — the object is `PlayerParams`, and `sub_822F9498` is ITS loader, not the unit loader + +Item (a), "what selects the `Booster` profile". It answered a different, bigger +question and **corrected a corpus doc**. Static only; no artefact changed. + +✅✅ **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`; the string `Maneuver` exists once and has **0 +xrefs**. One call site, from `sub_821A6CF0` — itself called once, and referencing +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 (`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`. Note added in place. ⇒ ❔ **What loads the 114 unit `Maneuver` +records is now an open question** — it uses none of these name strings. + +🟡 `PlayerParams` hashed under 7 prefixes × 6 spellings × both hash families (84 +combinations) hits the 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. + +✅ **Ranking all 114 units by how many of `Booster`'s 50 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**; the sixth drops to **13/50**; **none +matches 50/50**. And the five players **agree with each other on all 50** — the +three player ships share one flight model. `Booster` stands alone on **10** +fields. ⚠️ Correcting myself: the eleventh, `AA_Yaw_Max`, is `65.0` vs `65` — +formatting, not a value. Last iteration's "11 differ" over-counted. + +🟡 **NOT SETTLED, and it is now sharper: nothing selects `Booster`.** +`PlayerParams` is loaded **once, unconditionally** — one call site, one caller, no +branch. Yet `flight-speed-law.md` 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; the `RT`-held run reached ~1 530, nowhere near +2 100. **Both tables cannot govern the same craft.** Cheapest next test is a +runtime one (NEEDS-HUMAN): watch which constant set reaches the live flight +struct, and re-measure with the afterburner held. diff --git a/docs/re/INDEX.md b/docs/re/INDEX.md index b9d4677..fa8fee9 100644 --- a/docs/re/INDEX.md +++ b/docs/re/INDEX.md @@ -103,7 +103,7 @@ files, which is how the same ground got covered twice. | [`structures/stage-settings-table.md`](structures/stage-settings-table.md) | The per-stage settings object — Camera rigs, Player limits, Difficulty_* damage record | ✅ CONFIRMED, 24 settings objects vs 29 resource objects both using Phase_1/2/3; Camera is 13/14 fields constant; GravityFactor non-zero in 4 stages; IsBoss16Enable identifies one object; the Phase block is 94 fields of which 68 never vary between phases; all 24 objects named StageParameter_S | | [`structures/isl-mission-timer.md`](structures/isl-mission-timer.md) | The mission timer — two sequential countdowns, not a limit and a warning | ✅ CONFIRMED — read from `sub_822639B8`; the threshold reading is | | [`structures/archive-naming.md`](structures/archive-naming.md) | Which archives the disc can name — 100% for menu paks, **0.0%** for the six 2D paks and `GP_READY_ROOM` | ✅ CONFIRMED — 6027 names × 16 prefixes, bimodal; unnamed entries split by content — three UI paks have ZERO unnamed IDXD (artwork only), DefTables is the only real data gap (1295 LOD/motion tables); **route 2 = the `Enumerate` declaration tables** closes DefTables to 1413/1425 IDXD (99.2 %), 12 left; XPR2 manifests refuted as a naming source | -| [`structures/player-tuning-tables.md`](structures/player-tuning-tables.md) | Player tuning: 8 analog response curves, a second (×1.75 velocity) flight profile, special attacks, the S16 boss | ✅/🔴 — special-attack records read by `sub_822F9498`; `Booster` CORRECTED (it is the unit `Maneuver` schema, and NOT the profile the player flies); the analog block is referenced by nothing | +| [`structures/player-tuning-tables.md`](structures/player-tuning-tables.md) | **`PlayerParams`** — the player parameter table: `Booster` flight model, special attacks, 8 analog curves, the S16 boss | ✅✅ `sub_822F9498` is `PlayerParams`'s loader, NOT the unit loader (90/90 strings); all 5 player craft fly identically and `Booster` differs on 10 fields; 🟡 nothing selects it and the measured flight tracks the unit `Maneuver` instead | | [`structures/hud-config.md`](structures/hud-config.md) | The in-game HUD configuration — 16 records, 419 asset paths, and a per-stage `ResourceTable` | ✅ CONFIRMED — 0 of 419 config paths resolve as pak entries | | [`structures/mission-script-manifest.md`](structures/mission-script-manifest.md) | `Stage\script.tbl`'s 11 non-`MISSION` fields, and the mission dialogue table they name | ✅ CONFIRMED — 1 of 7 values resolves (`message\MissionDialogMessage.tbl`, 200 records), controls in the same sweep | | [`structures/stage-numbering-and-player-craft.md`](structures/stage-numbering-and-player-craft.md) | The disc's stage numbering (S01–S16, S18–S29) and the player's craft per stage | ✅✅ CONFIRMED — two independent files close on 6 + 15 + 1 + 6 = 28 | diff --git a/docs/re/structures/player-tuning-tables.md b/docs/re/structures/player-tuning-tables.md index 406f0fb..60eaddc 100644 --- a/docs/re/structures/player-tuning-tables.md +++ b/docs/re/structures/player-tuning-tables.md @@ -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 diff --git a/docs/re/structures/unit-datasheet-static.md b/docs/re/structures/unit-datasheet-static.md index 975969f..27ee014 100644 --- a/docs/re/structures/unit-datasheet-static.md +++ b/docs/re/structures/unit-datasheet-static.md @@ -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`