Yesterday's page said "Generic (394 per pak) is the unit datasheet".
Only 114 of the 394 are. Every IDXD file carries exactly one Generic
record and its schema is set by what kind of file it is. Partitioned
by field set, identically in all six GP_MAIN_GAME_*.pak:
114 has HP -- a unit datasheet
204 {Count} only -- a dialogue file
64 {ID, Name, SideID, Unique} -- a character (36 TCAF + 28 ADAN)
10 {EnumAsteroidGroup} -- an asteroid group
2 degenerate
204+114+64+10+2 = 394, and 178 distinct Generic.ID = 114 unit + 64
character, the only two shapes carrying an ID. That settles the
"178 IDs vs 394 records" question the previous entry left open.
Positive control in the same loop: for the 204 dialogue headers Count
equals the number of Message_NNN siblings, 204/204, zero mismatches.
Cross-check from the other side: Maneuver = 114, Effect = 114, the
carrying-entry sets are identical, every unit Generic has a Maneuver
sibling, and Generic.Type splits 43 Craft + 71 Vessel -- the same
43/71/114 unit-struct-runtime.md reached from live guest memory.
New tool generic_partition.py + artefact; ISL artefacts byte-identical.
133 lines
6.2 KiB
Markdown
133 lines
6.2 KiB
Markdown
# ✅ The STATIC unit datasheet and AI flight model — `Generic`, `Maneuver`, `Effect`
|
||
|
||
Found the same way as the weapon tables: **IDXD field names are literal strings in
|
||
the pool**, so a field-shape search over all 190 782 records finds the carriers
|
||
without guessing a filename. This is the static source for what the corpus had
|
||
only measured at runtime — [flight-speed-law](../flight-speed-law.md),
|
||
[flight-controls-runtime](../flight-controls-runtime.md),
|
||
[unit-struct-runtime](unit-struct-runtime.md).
|
||
|
||
> ## ❌ CORRECTION (2026-08-27) — `Generic` is a per-FILE header, not a table
|
||
>
|
||
> This page first read "`Generic` (394 per pak) is the unit datasheet". Wrong:
|
||
> **only 114 of the 394 are.** `Generic` is the record name every IDXD *file*
|
||
> gives its own header record — exactly one per pak entry — and its schema is
|
||
> set by what kind of file it is. Partitioned by field set, in each of the six
|
||
> `GP_MAIN_GAME_*.pak` identically:
|
||
>
|
||
> | `Generic` shape | per pak | what the file is |
|
||
> |---|---:|---|
|
||
> | has `HP` | **114** | **a unit datasheet** (`Maneuver`, `Effect`, `Shield`, `Mass`, `SE`, `Explosion`, `Turret_00N` siblings) |
|
||
> | `{Count}` only | 204 | a **dialogue file** — `Count` is the number of `Message_NNN` siblings |
|
||
> | `{ID, Name, SideID, Unique}` | 64 | a **character** (`Faces` sibling) — 36 `TCAF` + 28 `ADAN` |
|
||
> | `{EnumAsteroidGroup}` | 10 | an asteroid-group file |
|
||
> | 0 and 1 field | 2 | one empty, one naming `eff_n0071` |
|
||
>
|
||
> 204 + 114 + 64 + 10 + 2 = 394, and **178 distinct `Generic.ID` = 114 unit +
|
||
> 64 character** — the only two shapes that carry an `ID`. Positive control in
|
||
> the same loop: for the 204 dialogue headers, `Count` equals the number of
|
||
> `Message_NNN` siblings **204 / 204**, no mismatches.
|
||
>
|
||
> 🔑 The 114 is not a coincidence: `Maneuver` = 114, `Effect` = 114, the entry
|
||
> sets are **identical**, every unit `Generic` has a `Maneuver` sibling, and
|
||
> `Generic.Type` splits **43 `Craft` + 71 `Vessel`** — reproducing the count
|
||
> [unit-struct-runtime](unit-struct-runtime.md) reached from the other side.
|
||
> Artefact `../data/generic-record-partition.txt`, tool
|
||
> `tools/re-capture/generic_partition.py`.
|
||
|
||
| record | per pak | field names | distinct `ID`s |
|
||
|---|---|---|---|
|
||
| `Generic` (unit shape) | **114** | 67 max on one record | 114 |
|
||
| `Generic` (all shapes) | 394 | 110 pooled | 178 |
|
||
| `Maneuver` | **114** | 101 | — |
|
||
| `Effect` | **114** | 9 | — |
|
||
|
||
Repeated identically in every per-language `GP_MAIN_GAME_*.pak`. A unit's
|
||
`Generic`, `Maneuver` and `Effect` share a pak entry — one entry is one unit's
|
||
`.tbl`, which is why the runtime flattens all of them into a single object.
|
||
|
||
⚠️ `Generic` is the game's own record name, not a placeholder — it is also one of
|
||
the 65 section names in `data/config-keys.txt`.
|
||
|
||
## `Generic` — the unit datasheet
|
||
|
||
Sample `UN_e006_ADAN_Vindicator_MargrasF`:
|
||
|
||
```
|
||
ID / Name / Type Craft / UncertainName Craft
|
||
HP 6400.0 ShieldRatio 1.0 DefencePoint 0.0004
|
||
AttackCraftPoint 1.0 AttackVesselPoint 0.001
|
||
ResistanceToShell 0.1 ResistanceToExplosion 0.5 ResistanceToOptics 0.8
|
||
ResistanceToPlayer 1.0 ResistanceParalyze 0.99
|
||
Size_X/Y/Z 12.0 / 5.0 / 30.0 Size_Radius 15.0
|
||
RadarRange 10000.0 FCSRange 8500.0
|
||
MountedFCS No MountedShieldGenerator Yes
|
||
ScorePoint 4000 DamageScore 640 MassScore 30
|
||
HQRatio 1.0 ThrusterRatio 1.0 IsDestructible Yes
|
||
Model rou_e006 CollisionModel Color_R/G/B 1.0 / 0.5 / 0.1
|
||
NozzleCount 3 + per-nozzle Jet / AfterBurner / ReverseThruster / Contrail
|
||
Fx model & frame names, NozzleSpec_00N
|
||
```
|
||
|
||
🔑 **`Model rou_e006` ties the datasheet straight to the mesh names the corpus
|
||
already decodes**, and `Size_*` / `RadarRange` / `FCSRange` are in the corpus's
|
||
**1 metre** world unit — a 10 km radar, an 8.5 km fire-control range, a 12 × 5 ×
|
||
30 m craft.
|
||
|
||
## `Maneuver` — the AI flight model
|
||
|
||
The single richest find for the port. Sample, same unit:
|
||
|
||
```
|
||
MaximumVelocity 1200 MinimumVelocity 100.0 CruisingVelocity 700
|
||
Acceleration 600 Deceleration 400
|
||
SideThrustAcceleration 1000.0 SideThrustVelocity_Max 1000.0
|
||
Turn_AngularVelocity 180.0 MaximumBank_Normal 60.0
|
||
YawDragFactor / RollDragFactor / PitchDragFactor 3.0
|
||
DragFactorThreshold 0.5
|
||
ArterBurner_Vc 2.5 ArterBurner_Acc 2.0 (the game's own spelling)
|
||
ReverseThrust_Vc -0.5 ReverseThrust_Acc 2.0
|
||
UsingChaffRatio 0.5 HomingResistAdjustment 0.8
|
||
```
|
||
|
||
and a set of **named manoeuvres**, each a Yes/No switch plus its own timing,
|
||
ratio and length bounds:
|
||
|
||
```
|
||
TurnAttack + _CutoffRatio _DoubleRatio _DoubleTimeMin/Max
|
||
TurnAway + _Time_Minimum/Maximum
|
||
BarrelRoll + _CountMinimum/Maximum _Radius _Time
|
||
SideRoll + _Time _Length
|
||
Slalom + _CutoffRatio _TurnCount_Min/Max
|
||
Through + _Angle/Length Minimum/Maximum _Time1/2 Min/Max _CutoffRatio
|
||
HoldPosition + _MinimumTime _MaximumTime _CancelTime _CutoffRatio
|
||
_BackRatio _SideRatio _LengthMin/Max
|
||
SolidCutoff + _LengthMin/Max _Ratio
|
||
BoostAway + _Time_Minimum/Maximum
|
||
CutoffTimeMin/Max
|
||
AA_* and AV_* Pitch/Yaw/Roll Min/Max pairs
|
||
```
|
||
|
||
🟡 The `AA_` / `AV_` prefixes pair with `AttackCraftPoint` / `AttackVesselPoint`,
|
||
so *anti-air* vs *anti-vessel* rate limits is the obvious reading — **not
|
||
adopted**, nothing here shows the selection.
|
||
|
||
## `Effect`
|
||
|
||
`ShieldHitEffectName`, `ShieldRecoverEffectName`, `Effect_Paralyze`, plus
|
||
`JumpIn` / `JumpOut` / `FadeIn` / `FadeOut` slots.
|
||
|
||
## 🟡 Not settled
|
||
|
||
* No cross-check against the runtime captures — this locates and reads the
|
||
tables; it does not reconcile them field by field.
|
||
* `HP_CLASS` / `HP_ID` turned out **not** to be ship stats: they sit on records
|
||
named for wingmen and ship classes (`CARL`, `ELLEN`, `SANDRA`, `ACROPOLIS`,
|
||
`Carrier_TCAF1`, `NP_Facility`, …), 120–144 instances each, alongside
|
||
`HPGauge` / `HPGaugeSub` / `RadarCursorType` on the `ObjectiveMarker_*` and
|
||
`TutorialMarker_*` records — a **HUD gauge binding table**, not a datasheet.
|
||
* ~~178 distinct `Generic` IDs against 394 records per pak — the surplus is
|
||
unexplained here.~~ **Settled 2026-08-27 — see the correction at the top.**
|
||
* The `Generic` field-name count of 110 is a POOL across all four shapes; no
|
||
single record carries more than 67.
|