This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/structures/hangar-loadout-system.md
Sylpheed RE agent 2b2d984f0c 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.
2026-08-27 12:58:53 +00:00

90 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ✅ 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.