Files
Sylpheed/docs/re/structures/unit-substructure-records.md
Sylpheed RE agent 2519427bab re: the 59-of-131 arsenal question is closed -- an item names a hardpoint
An Arsenal item does not reference a Weapon record.  It references a
Turret_NNN HARDPOINT SLOT on the player craft's own unit table, and the
slot is what carries the WeaponID.  Three hops:

  Arbalest_155KG.PlayerWeapon -> Turret_050  (a slot on
  UN_f001_TCAF_DeltaSaber_T_Player) -> .WeaponID ->
  Weapon_DSaber_P_wep_50_Cannon

Controls, both in the same loop: 0/59 distinct PlayerWeapon values are a
Weapon.ID; 59/59 are a Turret_NNN slot id; the full chain lands on a
Weapon.ID 59/59.  WingmanWeapon resolves identically.  The WEAPONS
roster's 59 = 55 item names + 4 empty-slot sentinels.

Wingmen fly a cheaper gun: following the same 59 slots across craft
variants, the _Player tables give each item its own weapon record (59
distinct) while the AI tables collapse all 59 onto 10 generic classes.
That is most of the 131.

Upgrades yesterday's 'hardpoint catalogue' reading from 21 to adopted,
proved from an independent file, and corrects its '10 distinct WeaponID'
figure -- that was the AI variant, not the player's.

Also adds an __main__ guard to unit_substructures.py so importing
pak_entries from it does not run its report; its artefact is unchanged
and still byte-identical.
2026-08-27 12:49:22 +00:00

6.4 KiB
Raw Blame History

The destructible-subsystem model — a unit's sub-records

The corpus has named the sub-records of a unit .tbl since unit-struct-runtime ("Generic, Maneuver, Shield, Explosion, Mass, Effect, SE, Turret_00N … all flattened into that single object") but has never opened them. This does.

One unit = one IDXD pak entry. 114 of them (the Generic partition). Artefact ../data/unit-substructures.txt, regenerator tools/re-capture/unit_substructures.py.

family records max/unit non-indexed fields
Turret_NNN 835 63 38
Generic / Maneuver / Effect / Shield / Mass / SE / Explosion / StructureCount 114 each 1
NS_Body 68 1 12
ShieldGenerator_NNN 46 4 21
Thruster_NNN 38 4 21
Hatch_NNN 26 4 23
Bridge_NNN 25 2 20

Seven singletons named with a literal ??? (Turret_???, Versatile_???, …) are the schema's own template rows.

The shared destructible-part base

Turret, ShieldGenerator, Thruster, Hatch and Bridge are the same record shape with per-kind extras. Every one of the 970 part records carries:

ID  Name  ParentStructureID  Frame  NomalModel  CollisionModel  Radius
HP  IsDestructible  IsShielded  IsInvolved  IsRadarVisible  SpreadDamage
DamagedMotionName  DestroyMotionName  DestroyMotionTime
Effect_Explosion  Effect_Flare  Effect_Paralyze

(NomalModel is the game's own spelling.) Frame is a mesh node nameGN_mnt on the player craft — so a part is bolted to a named bone of the Generic.Model mesh the corpus already decodes.

Per-kind, on top of that base:

kind extra fields
Turret WeaponID, AngularVelocity, YawLimit, PitchLimit_Elevation, PitchLimit_Depression, CoverArea, IsAuto, HasBarrel, CommonCannonModel/Frame, CannonModel_NNN/CannonFrame_NNN (up to 80), SequencingCount, SequencingInterval, and on a few: CurveAngle, FCSAngle, FollowView, ShellModel, CoverModel
ShieldGenerator / Thruster / Bridge PowerRatio — losing the part degrades the parent
Thruster NozzleCount
Hatch SquadronID, LoadedCount, MaxAvailableCount, TakeoffIntervala carrier's launch bay

🔑 That is a complete component model: named bone, own mesh and collision mesh, own HP and destruction motion + effects, and a PowerRatio saying what the parent loses when it dies.

The one-record blocks

record fields
Shield MaxValue, ChargeSpeed, ChargeDelay, ChargeDelay_Break
Mass DryMass, GrossMass
SE ExplosionSE, Thruster, SideThruster, JumpIn, JumpOut, ShipEnvironmentSE, LowerHPSE, LowerHPThresholdRatio
Explosion Delay, DelayAdjustment, ExplosionFxModel, ExplosionMotionName, LowerHPFxModel, DestroyMotionName, DestroyMotionTime
StructureCount TurretCount, BridgeCount, HatchCount, ShieldGeneratorCount, ThrusterCount, VersatileCount
NS_Body Model, NodeCount, Interval, StartingVelocity, Deceleration, Volume, Color_R/G/B, AttenuationVolume, AttenuationAlpha, DeleteFadeSpeed — an engine-trail ribbon, on 68 of 114

Every field the runtime doc reached for Shield (MaxValue +0x238, ChargeSpeed +0x244) and Mass (DryMass +0x274, GrossMass +0x278) is here, at the same names.

🧪 Control 1 — StructureCount counts the part records

declared == #<Kind>_NNN records, over 114 units × 6 kinds = 684:

equal 612
declared 0, one blank placeholder record 55
differs 11
kind absent from StructureCount 6

The 55 are a real sub-rule, not slack: a kind with a count of 0 still emits exactly one record, and all 55 have empty Name, NomalModel and Frame. So the file always carries at least one slot per kind.

Every one of the 11 exceptions is a Turret, and every one has declared < records — never the other way round. Nine are the player's DeltaSaber family:

declared=4  records=63   x7   f001_T, f001_T_EX5, f001_T_EX5_el, f001_T_Player,
                              f002_W, f002_W_Player, f004_A_Player
declared=4  records=5    x2   f001_T_Player_Ttrl1 / _Ttrl2
declared=1  records=2    x1   UN_e001_ADAN_Elan_EX4
declared=8  records=9    x1   UN_e107_ADAN_AAFrigate_EX4

ADOPTED the next day — on the player craft the Turret_NNN list is a hardpoint catalogue and TurretCount 4 is how many mount at once. The Arsenal table proves it from an independent file: 59/59 of its items name a Turret_NNN slot in PlayerWeapon, see arsenal-item-weapon-chain. The two +1 warship/craft cases are still unexplained.

⚠️ The "10 distinct WeaponIDs" measured here is the AI variant UN_f001_TCAF_DeltaSaber_T. The _Player variants give the same 59 slots 59 distinct weapon records — wingmen fly a collapsed 10-class set.

🧪 Control 2 — turret weapons resolve into the weapon datasheet

835 / 835 Turret_NNN.WeaponID values are an ID in the 131-record Weapon table. Zero unresolved. 105 distinct values are used; 26 of the 131 weapons are never mounted on a turret — the player-only arsenal.

That is a hard cross-table link: the weapon datasheet is what arms every gun on every ship.

Refuted in the same pass — "the 59 hardpoints are the 59-name arsenal roster"

The DeltaSaber's 63 turret slots hold 59 non-Weapon_NULL entries, and the WEAPONS roster in GP_HANGAR_ARSENAL.pak has exactly 59 names. Tempting, and wrong: the two sets overlap in 0 values, and the 59 slots carry only 10 distinct WeaponIDs. The roster is display names (Machiene_Cannon_MG1 — the game's spelling); the hardpoints reference Weapon.ID (Weapon_TCAF_DeltaSaber_Gun). Two namespaces, one coincidence of count.

🟡 Not settled

  • What links a roster entry to a Weapon.ID — the 59-of-131 question is still open, and this pass shows the answer is not the hardpoint list.
  • Versatile_NNN has 0 populated records in this pak; only the ??? template row exists, so its schema is known and its instances are not.
  • CoverArea reads as a hex word (0x00000000 / 0x00000001) — a bit mask, bits unknown.
  • The 6 no field comparisons are one unit whose StructureCount omits every count.