The obvious follow-up to last commit's wep_85 finding: the weapon packages number
00 to 84 with 26 holes, so are those holes cut weapons too? Partitioning every
number 00-85 by package-present x named-anywhere-in-the-parsed-pak-data:
named in data not named
package present 59 0
package absent 1 26
59 + 0 + 1 + 26 = 86, the numbers 00 through 85.
The 26 gaps are simply unused numbers, not unshipped weapons - nothing in the
data names them at all. The one occupied cell is the one already known: wep_85,
named 16 times, with no package. It is an isolated cut, not a pattern, which
refutes the natural expectation that finding one cut weapon means finding a
family of them.
The other zero is worth as much: 0 shipped packages are never named. Every
rou_f001_wep_NN.xpr on the disc is referenced by the data, so the package set and
the weapon vocabulary agree in both directions but for that single entry.
Running the identical test on the craft family gives a clean negative. Every
rou_f### number appearing inside an .xpr against every number named in the parsed
data: 16 in both, 0 named-but-unshipped, 0 shipped-but-unnamed. The 16 are
f001-f004, f101, f102, f104-f106, f201, f202, f301-f303, f401, f402 - the
hundreds digit groups them into five families with holes inside each (no f103, no
f203). No craft was cut.
So across both families the disc ships exactly what it declares, with the single
exception of that one weapon.
All seventeen artefacts byte-identical.
135 lines
6.0 KiB
Markdown
135 lines
6.0 KiB
Markdown
# ✅✅ The 59-of-131 arsenal question — an item names a HARDPOINT, not a weapon
|
||
|
||
Open since the weapon datasheet was decoded: the Hangar's arsenal lists **59**
|
||
weapons, the disc's `Weapon` table has **131**, and
|
||
[the previous pass](unit-substructure-records.md) showed the two name sets
|
||
overlap in **0** values. This closes it.
|
||
|
||
**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:
|
||
|
||
```
|
||
GP_HANGAR_ARSENAL.pak Arbalest_155KG
|
||
.PlayerWeapon ───▶ Turret_050 (a slot on UN_f001_TCAF_DeltaSaber_T_Player)
|
||
.WeaponID ───▶ Weapon_DSaber_P_wep_50_Cannon (a Weapon record)
|
||
```
|
||
|
||
Artefact `../data/arsenal-chain.txt`, regenerator
|
||
`tools/re-capture/arsenal_chain.py`.
|
||
|
||
## 🧪 The controls
|
||
|
||
| | |
|
||
|---|---:|
|
||
| `WEAPONS` roster values | 59 |
|
||
| arsenal ITEM records (field set `Model`/`Package`/`PlayerWeapon`/`Points`/`Power`/`Range`/…) | **59** |
|
||
| item names that are roster values | 55 |
|
||
| roster values with no item record | 4 — `No_Equipment`, `NullWeapon_Arm1/2/3` |
|
||
| **distinct `PlayerWeapon` values that are a `Weapon.ID`** | **0 / 59** |
|
||
| **distinct `PlayerWeapon` values that are a `Turret_NNN` slot id** | **59 / 59** |
|
||
| the full chain lands on a `Weapon.ID` | **59 / 59** |
|
||
|
||
`WingmanWeapon` resolves identically, 59/59. The 4 roster entries with no item
|
||
record are the empty-slot sentinels, so the roster is 55 real weapons + 4 nulls
|
||
against 59 item records — the item table is the superset.
|
||
|
||
## 🔑 Wingmen fly a cheaper gun
|
||
|
||
Following the same 59 slots on different craft variants splits them cleanly:
|
||
|
||
| craft variant | slots | distinct `Weapon.ID` reached |
|
||
|---|---:|---:|
|
||
| `…DeltaSaber_T_Player`, `_W_Player`, `_A_Player` | 63 | **59** (`Weapon_DSaber_P_wep_NN_*`) |
|
||
| `…DeltaSaber_T`, `_W`, `_T_EX5`, `_T_EX5_el` | 63 | **10** (`Weapon_TCAF_DeltaSaber_Beam`, `…_Gun`, …) |
|
||
|
||
Same slot ids, same 59 arsenal items, but the **`_Player` tables give each item
|
||
its own weapon record while the AI tables collapse all 59 onto 10 generic
|
||
behaviour classes**. A wingman carrying an `Arbalest_155KG` does not fire the
|
||
player's `wep_50` ballistics.
|
||
|
||
That also explains the 131: 59 player weapons + 10 AI-Saber classes + the ship
|
||
guns and ADAN weapons the turrets use.
|
||
|
||
Four of the player craft's 63 slots are referenced by no item: `Turret_000`
|
||
(the `Weapon_NULL` slot) and `Turret_097` / `_098` / `_099`.
|
||
|
||
## ✅ Upgrades a 🟡 from the previous pass
|
||
|
||
[unit-substructure-records](unit-substructure-records.md) read the player
|
||
craft's 63 `Turret_NNN` records as "a hardpoint catalogue, `TurretCount 4` =
|
||
how many mount at once", marked 🟡 because nothing showed the selection. The
|
||
arsenal table **is** the selection, from an independent file, 59/59. Adopted.
|
||
|
||
## The item record
|
||
|
||
```
|
||
Model / Package rou_f001_wep_50_hangar (+ .xpr) the Hangar display mesh
|
||
PlayerPackage / _LOD / _Motion rou_f001_wep_50.xpr, Equip_EnumLODSet_wep_50.tbl,
|
||
WingmanPackage / _LOD / _Motion Equip_EnumGameModel_wep_50.tbl
|
||
SilhouetteModel rou_f001_wep_50_NA
|
||
PlayerWeapon / WingmanWeapon Turret_050
|
||
Points 25000 Stage 6 develop cost, and the stage that unlocks it
|
||
Power B Range B Size L Speed - Weight 1.5 the Hangar's stat bars
|
||
Type g04b the slot-compatibility class
|
||
Dependency MissionObjective (empty on this item)
|
||
```
|
||
|
||
`Model` ties an arsenal entry to the meshes the corpus already decodes; `Points`
|
||
and `Stage` are the develop economy that
|
||
[arsenal-develop-economy](../arsenal-develop-economy.md) recovered from the
|
||
screen side.
|
||
|
||
## 🟡 Not settled
|
||
|
||
* `Type` (`g04b`) is a slot-compatibility class. `STANDARD_ARM1/2/3`,
|
||
`STANDARD_NOSE`, `PlayerSET_*`, `ExSET_*`, `S01SET_*`, `S02SET_*` are records
|
||
whose only field is `Type` — the per-slot allow-lists — and the loadout
|
||
records (`Bird1-Sandra`, `Rhino1-Katana`, … with `Arm1`/`Arm2`/`Arm3`/`Nose`/
|
||
`UnitID`) are the **wingman loadouts**. Named here, not opened.
|
||
* `Dependency` and `MissionObjective` are empty on the sampled item; what fills
|
||
them elsewhere is unread.
|
||
* Which `Weapon` records the 26 never-on-a-turret weapons are.
|
||
|
||
## ✅ `wep_85` is the only declared-but-unshipped asset — the gaps are unused numbers
|
||
|
||
The previous iteration found `wep_85` declared in the datasheets with no
|
||
`rou_f001_wep_85.xpr`. The obvious next question is whether it is the tip of a
|
||
family: the shipped packages number **00–84 with 26 holes**, so are those holes
|
||
cut weapons too?
|
||
|
||
Partitioning every number 00–85 by *package present* × *named anywhere in the
|
||
parsed pak data*:
|
||
|
||
| | named in data | not named |
|
||
|---|---|---|
|
||
| **package present** | **59** | **0** |
|
||
| **package absent** | **1** | 26 |
|
||
|
||
`59 + 0 + 1 + 26 = 86` — the numbers 00 through 85.
|
||
|
||
🔑 **The 26 gaps are simply unused numbers, not unshipped weapons.** Nothing in
|
||
the data names them at all. And the one occupied cell is the one already known:
|
||
**`wep_85`, named 16×, with no package**. It is an isolated cut, not a pattern.
|
||
|
||
⚠️ The other zero is worth as much: **0 shipped packages are never named** — every
|
||
`rou_f001_wep_NN.xpr` on the disc is referenced by the data. So the weapon
|
||
package set and the weapon vocabulary agree in both directions but one entry.
|
||
|
||
### ✅ Craft models: 16 of 16, both residuals empty
|
||
|
||
Running the identical test on the `rou_f###` craft family — every number that
|
||
appears inside an `.xpr` against every number named in the parsed data:
|
||
|
||
* in an `.xpr` **and** named: **16**
|
||
* named but not in any `.xpr`: **0**
|
||
* in an `.xpr` but never named: **0**
|
||
|
||
The 16 are `f001–f004`, `f101`, `f102`, `f104`–`f106`, `f201`, `f202`,
|
||
`f301`–`f303`, `f401`, `f402` — the hundreds digit groups them into five
|
||
families, with holes inside each (no `f103`, no `f203`).
|
||
|
||
So **no craft was cut**, and the method that found `wep_85` returns a clean
|
||
negative here. Across both families the disc ships exactly what it declares,
|
||
with the single exception of that one weapon.
|