Files
Sylpheed/docs/re/structures/unit-substructure-records.md
Sylpheed RE agent 9281aa7456 re: the destructible-subsystem model -- a unit's sub-records
The corpus has named these since unit-struct-runtime.md but never
opened them.  Per unit table: Turret_NNN 835 records (max 63 on one
unit), ShieldGenerator_NNN 46, Thruster_NNN 38, Hatch_NNN 26,
Bridge_NNN 25, plus one each of Shield/Mass/SE/Explosion/
StructureCount and NS_Body on 68 of 114.

Turret/ShieldGenerator/Thruster/Hatch/Bridge are ONE record shape: a
shared 19-field destructible-part base (ID, Name, ParentStructureID,
Frame = a mesh NODE name, NomalModel, CollisionModel, Radius, HP, the
four Is* flags, SpreadDamage, damaged/destroy motion + time, and the
three Effect_*), with per-kind extras.  Turrets add WeaponID,
AngularVelocity, YawLimit, PitchLimit_Elevation/_Depression, CoverArea,
IsAuto, HasBarrel and up to 80 CannonModel_NNN/CannonFrame_NNN.  Shield
generators, thrusters and bridges add PowerRatio.  Hatches add
SquadronID, LoadedCount, MaxAvailableCount, TakeoffInterval -- a
carrier's launch bay.

Control 1: StructureCount.<Kind>Count == #<Kind>_NNN records, over 684
comparisons -- 612 equal, 55 "0 declared, one blank placeholder"
(55/55 blank in Name AND NomalModel AND Frame), 11 differ, 6 kind
absent.  All 11 exceptions are Turret and all are declared < records.

Control 2: 835/835 Turret_NNN.WeaponID resolve to an ID in the
131-record Weapon datasheet, zero unresolved; 26 weapons are never
mounted on a turret.

Refuted in the same pass: "the DeltaSaber's 59 non-NULL hardpoints are
the 59-name WEAPONS arsenal roster".  The counts match exactly and the
sets overlap in 0 values -- two namespaces, one coincidence.

New structure doc, artefact and regenerator; other artefacts unchanged.
2026-08-27 12:39:50 +00:00

132 lines
6.2 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 destructible-subsystem model — a unit's sub-records
The corpus has named the sub-records of a unit `.tbl` since
[unit-struct-runtime](unit-struct-runtime.md) ("`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](unit-datasheet-static.md)). 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 name** —
`GN_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`, `TakeoffInterval` — **a 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
```
🟡 The reading — **not adopted**: on the player craft the `Turret_NNN` list is
a *hardpoint catalogue* and `TurretCount 4` is how many mount at once. It fits
(63 slots, all `Frame=GN_mnt`, all `IsAuto=No`, 10 distinct `WeaponID`s across
them, and the tutorial variants carry a cut-down 5) but nothing here shows the
selection. The two `+1` warship/craft cases are unexplained.
## 🧪 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](weapon-datasheet-static.md) 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** `WeaponID`s. 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.