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 2b9709eaa0 re: who selects a loadout -- the pak entry does; the Arsenal pak is stage-scoped
Settled by elimination with two controls.  The 15 loadout names appear
as a field VALUE nowhere on the disc -- 0 occurrences across every pak
-- while the control Arbalest_155KG, which is referenced, appears 150
times as a value in the same pak.  They occur only as the field names of
the UNITS record.  They are not in the executable either; control:
WEAPONS (a section key) is, Arbalest_155KG is not.

So nothing references a loadout by name.  The selection is which pak
entry the Hangar loads.  GP_HANGAR_ARSENAL.pak has 180 IDXD entries in
10 shapes; 168 carry a UNITS roster = 28 stages x 6 languages, and the
other 12 = 2 x 6.  Each entry is one stage's whole Hangar config, and
its UNITS roster is the flight for that stage -- 5 distinct rosters over
15 / 5 / 5 / 2 / 1 stages, including one where Rhino2-Katana flies
alone.  Every count is a multiple of 6 and they sum to 28, the disc's
stage count by a fourth independent route.

Corrects the previous commit: it read the pak with setdefault, so
'15 loadouts / 24 allow-lists / STANDARD_ARM1 has 11 entries' is the
union of first-seen records, not one table.  Contents vary per entry --
PlayerSET_ARM1 has 5 distinct contents, STANDARD_ARM1 3, ExSET_NOSE 4.
The chain and both controls (60/60, 70/88) are per-record and
unaffected; only the per-list sizes were over-generalised.

Not settled: the entry filenames.  name_hash probing over 8 templates x
40 indices x 6 languages resolved 0, while the same probe's controls
<lang>\weapon.tbl and <lang>\strings.tbl resolved 12/12.

Artefact +40 lines / 1 changed heading; the other four regenerate
byte-identical.
2026-08-27 13:09:07 +00:00

7.2 KiB
Raw Permalink 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.

⚠️ CORRECTION (2026-08-27, same day) — the pak is STAGE-SCOPED, and the

counts below are a UNION, not one table

GP_HANGAR_ARSENAL.pak has 180 IDXD entries in 10 distinct shapes, and 168 of them = 28 stages × 6 languages carry a UNITS roster. Each entry is one stage's Hangar configuration: its own UNITS roster, its own loadout records, its own allow-lists. The first pass read the pak with setdefault, keeping only the first-seen copy of each record name — so "15 loadouts / 24 allow-lists / STANDARD_ARM1 has 11 entries" is the union of first-seen, not a single table. The allow-list contents genuinely vary: PlayerSET_ARM1 has 5 distinct contents across entries, STANDARD_ARM1 3, ExSET_NOSE 4; the SNNSET_* and NULL_* sets have exactly 1 each.

The structure of the chain below is unaffected — the 60/60 and 70/88 controls are per-record and still hold on the first-seen slice — but treat the per-list sizes as "one stage's", not "the game's".

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.

Who selects a loadout — the pak ENTRY does

Settled the same day, by elimination with two controls:

  • The 15 loadout names appear as a field value nowhere on the disc — 0 occurrences across every pak. Positive control in the same loop: the item name Arbalest_155KG, which is referenced, appears 150 times as a value in the same pak. They appear only as the field names of the UNITS record, i.e. UNITS is the index over them.
  • They are not in the executable either. Control: WEAPONS (a section key) is in the executable; Arbalest_155KG is not — so the executable holds table keys, not row names.

So nothing references a loadout by name. The selection is which pak entry the Hangar loads, and there is one per stage per language (168 = 28 × 6). The entry's UNITS roster is the flight for that stage, and it changes across the campaign exactly as the story does:

stages pilots in UNITS
15 Bird 14 (Sandra, Billy, Antonius, Carl) + Rhino1-Katana, Rhino2-Ellen, Rhino3-Gene, Rhino4-Yoji
5 Bird 14 + Rhino1-Raymond, Rhino2-Gene, Rhino3-Katana, Rhino4-Ellen
5 Rhino2-Katana alone
2 Bird 14 + Rhino1-Raymond, Rhino2-Katana, Rhino3-Ellen
1 Rhino1-Katana, Rhino2-Ellen, Rhino3-Gene, Rhino4-Brandon

Every count is a multiple of 6 and they sum to 28 — the disc's stage count, reached here by a fourth independent route.

🟡 The entry FILENAMES are not recovered. Probing name_hash over 8 templates × 40 indices × 6 languages resolved 0; the same probe's controls <lang>\weapon.tbl and <lang>\strings.tbl resolved 12/12, so the method works and the naming convention is simply not one of the eight guessed.

🟡 Not settled

  • Which entry is which stage — see the filename note above. 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.