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.
This commit is contained in:
131
docs/re/structures/unit-substructure-records.md
Normal file
131
docs/re/structures/unit-substructure-records.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# ✅ 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.
|
||||
Reference in New Issue
Block a user