re: the Hangar loadout system -- loadout, allow-list, arsenal item
15 loadout records, one per flight position x pilot (Bird1-Sandra .. Rhino4-Yoji), each with Arm1/Arm2/Arm3/Nose + UnitID. The same trap as PlayerWeapon, one level up: Arm1/Arm2/Arm3/Nose do NOT name items. They name a per-slot ALLOW-LIST record -- one of 24 whose only named field is Type (the slot kind) -- and the candidate items are that record's positional, unnamed fields, in order. Four hops: Rhino4-Yoji.Arm1 -> STANDARD_ARM1 -> [Falcon_9AM, Condor_105AM, ...] -> item.PlayerWeapon = Turret_NNN -> slot.WeaponID -> Weapon.ID Controls: Arm1/2/3/Nose -> allow-list record 60/60; allow-list positional entries -> arsenal item 70/88, and every one of the 18 misses is the single sentinel No_Equipment -- one of the four WEAPONS-roster values with no item record, i.e. the empty-slot marker. UnitID is two ID spaces at once: 5 rows name a unit Generic.ID (the three -Katana rows are the player -- a _Player craft plus an extra, empty PlayerUnit field), 8 name a character, resolving as Character + the value into the 64-record character table. Two values resolve to nothing, both single rows against 13 that do: Rhino2-Ellen.UnitID = UN_f001_TCAF_DeltaSaber_W exists nowhere (checked as a Generic.ID across every pak and as a record name, 0 hits) while UN_f002_TCAF_DeltaSaber_W does -- consistent with a shipped typo, reported not diagnosed -- and Rhino4-Brandon.UnitID = BRANDON has no CharacterBRANDON among the 64. New structure doc, artefact and regenerator; the other four artefacts regenerate byte-identical.
This commit is contained in:
89
docs/re/structures/hangar-loadout-system.md
Normal file
89
docs/re/structures/hangar-loadout-system.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# ✅ The Hangar loadout system — loadout → per-slot allow-list → arsenal item
|
||||
|
||||
Finishes the Hangar. [The item chain](arsenal-item-weapon-chain.md) resolved an
|
||||
Arsenal item down to a `Weapon` record; this is the layer above it — **who flies
|
||||
with what**, and **what the Hangar is allowed to offer for each slot**.
|
||||
|
||||
Artefact `../data/hangar-loadouts.txt`, regenerator
|
||||
`tools/re-capture/hangar_loadouts.py`.
|
||||
|
||||
`GP_HANGAR_ARSENAL.pak` carries **15 loadout records** — `Bird1-Sandra`,
|
||||
`Bird2-Billy`, `Bird3-Antonius`, `Bird4-Carl`, `Rhino1-Katana`,
|
||||
`Rhino1-Raymond`, `Rhino2-Ellen`, `Rhino2-Gene`, `Rhino2-Katana`,
|
||||
`Rhino3-Ellen`, `Rhino3-Gene`, `Rhino3-Katana`, `Rhino4-Brandon`,
|
||||
`Rhino4-Ellen`, `Rhino4-Yoji` — one per **flight position × pilot**, each with
|
||||
`Arm1`, `Arm2`, `Arm3`, `Nose` and `UnitID`.
|
||||
|
||||
🔑 **Same trap as `PlayerWeapon`, one level up: `Arm1`/`Arm2`/`Arm3`/`Nose` do
|
||||
not name items.** They name a **per-slot ALLOW-LIST record** — one of the 24
|
||||
whose only *named* field is `Type` (the slot kind: `Arm1`/`Arm2`/`Arm3`/`Nose`).
|
||||
The candidate items live in that record's **positional, unnamed fields**, in
|
||||
order. So the full path is four hops:
|
||||
|
||||
```
|
||||
Rhino4-Yoji.Arm1 ──▶ STANDARD_ARM1 (an allow-list, Type=Arm1)
|
||||
──▶ [Falcon_9AM, Condor_105AM, …] (arsenal item names, in order)
|
||||
──▶ item.PlayerWeapon = Turret_NNN (a hardpoint slot)
|
||||
──▶ slot.WeaponID = Weapon.ID
|
||||
```
|
||||
|
||||
## 🧪 The controls
|
||||
|
||||
| | |
|
||||
|---|---:|
|
||||
| `loadout.Arm1/2/3/Nose` names an allow-list record | **60 / 60** |
|
||||
| allow-list positional entries name an arsenal item | **70 / 88** |
|
||||
| — every one of the 18 misses | the single sentinel `No_Equipment` |
|
||||
| `loadout.UnitID` resolves | 5 a unit `Generic.ID`, 8 a character (as `Character`+value), **2 neither** |
|
||||
|
||||
`No_Equipment` is one of the four `WEAPONS`-roster values that have no item
|
||||
record ([the item chain](arsenal-item-weapon-chain.md)), so the residual is the
|
||||
empty-slot sentinel appearing once per list — not a decode failure.
|
||||
|
||||
## The six allow-list sets
|
||||
|
||||
| set | Arm1 | Arm2 | Arm3 | Nose | used by |
|
||||
|---|---:|---:|---:|---:|---|
|
||||
| `STANDARD_*` | 11 | 9 | 9 | 8 | Rhino 2/3/4 wingmen |
|
||||
| `ExSET_*` | 10 | 8 | 4 | 7 | — (not referenced by any loadout here) |
|
||||
| `S01SET_*` | 2 | 1 | 1 | 1 | Bird flight, `Rhino1-Raymond`, `Rhino3-Ellen` |
|
||||
| `S02SET_*` | 3 | 2 | 2 | 1 | — |
|
||||
| `PlayerSET_*` | 2 | 1 | 1 | 1 | the three `…-Katana` rows |
|
||||
| `NULL_*` | 1 | 1 | 1 | 1 | — (`No_Equipment`, `No_Equipment`, `No_Equipment`, `Stiletto_BG1`) |
|
||||
|
||||
So a wingman's weapon choice is drawn from a small, ordered, *per-slot* list,
|
||||
and the `SNNSET_` sets are stage-scoped variants of it — `S01SET_ARM1` offers
|
||||
two Arm1 items, `STANDARD_ARM1` offers eleven.
|
||||
|
||||
## `UnitID` is two ID spaces at once
|
||||
|
||||
* **5 rows name a unit** — `UN_f001_TCAF_DeltaSaber_T`,
|
||||
`…_T_Player`, `…_f002_W_Player`. The three `-Katana` rows are the **player**:
|
||||
they carry an extra (empty) `PlayerUnit` field and point at a `_Player` craft.
|
||||
* **8 rows name a character** — `SANDRA`, `BILLY`, `ANTONIUS`, `CARL`,
|
||||
`RAYMOND`, `GENE` ×2, `YOJI`. None is a `Generic.ID` on its own; all resolve
|
||||
as **`Character` + the value** into the 64-record character table
|
||||
([the `Generic` partition](unit-datasheet-static.md)).
|
||||
|
||||
## 🟡 Two values that resolve to nothing
|
||||
|
||||
* **`Rhino2-Ellen.UnitID = UN_f001_TCAF_DeltaSaber_W`.** No such unit exists —
|
||||
checked as a `Generic.ID` across *every* pak, and as a record name: 0 hits.
|
||||
`UN_f002_TCAF_DeltaSaber_W` does exist, and `Rhino1-Katana` uses
|
||||
`UN_f002_TCAF_DeltaSaber_W_Player`. **Consistent with a shipped `f001`/`f002`
|
||||
typo** — but what the game does when the lookup fails is not shown here, so
|
||||
this is reported, not diagnosed.
|
||||
* **`Rhino4-Brandon.UnitID = BRANDON`** — no `CharacterBRANDON` among the 64.
|
||||
`CharacterKATANA` does exist, and Katana is the player.
|
||||
|
||||
Both are single rows against 13 that resolve, so they are exceptions in the
|
||||
data, not a wrong reading of the field.
|
||||
|
||||
## 🟡 Not settled
|
||||
|
||||
* Who *selects* a loadout record. The names encode flight position and pilot,
|
||||
and [the stage definition table](stage-definition-table.md) has
|
||||
`AI_TCAF_RhinoFlight` / `AI_TCAF_BirdFlight` — the join is not shown here.
|
||||
* `ExSET_*`, `S02SET_*` and `NULL_*` are referenced by no loadout in this pak.
|
||||
* The `PlayerUnit` field is present but empty on all three `-Katana` rows.
|
||||
* `IGNORE` (13 item names) — a blocklist for something unread.
|
||||
Reference in New Issue
Block a user