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

4.4 KiB
Raw Blame History

The Hangar loadout system — loadout → per-slot allow-list → arsenal item

Finishes the Hangar. The item chain 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 recordsBird1-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), 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 unitUN_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 characterSANDRA, 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).

🟡 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 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.