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.
This commit is contained in:
Sylpheed RE agent
2026-08-27 12:49:22 +00:00
parent 9281aa7456
commit 2519427bab
7 changed files with 306 additions and 6 deletions

View File

@@ -827,6 +827,42 @@ unknown, what evidence exists, and what the first step would be. Move an item in
field; the stat keys in records not opened here (`MegaTons`, `BulletLimit`, field; the stat keys in records not opened here (`MegaTons`, `BulletLimit`,
`CrewCount`, `HP_CLASS`); why the roster lists 59 of 131. `CrewCount`, `HP_CLASS`); why the roster lists 59 of 131.
* ✅✅ **(2026-08-27) THE 59-OF-131 ARSENAL QUESTION IS CLOSED — an Arsenal item
names a HARDPOINT SLOT, not a weapon.**
[structures/arsenal-item-weapon-chain](structures/arsenal-item-weapon-chain.md),
artefact `data/arsenal-chain.txt`, regenerator
`tools/re-capture/arsenal_chain.py`.
Open since the weapon datasheet was decoded, and one wrong answer was
refuted yesterday. The link is **three hops**:
`Arbalest_155KG.PlayerWeapon`**`Turret_050`** (a slot on
`UN_f001_TCAF_DeltaSaber_T_Player`) → `.WeaponID`
`Weapon_DSaber_P_wep_50_Cannon`.
🧪 The controls, both run 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 (`No_Equipment`, `NullWeapon_Arm1/2/3`).
🔑 **Wingmen fly a cheaper gun.** Following the same 59 slots across craft
variants: the `_Player` tables give each item **59 distinct** weapon records
(`Weapon_DSaber_P_wep_NN_*`); the AI tables (`…DeltaSaber_T`, `_W`, `_EX5`)
collapse all 59 onto **10** generic classes (`Weapon_TCAF_DeltaSaber_Beam`,
`…_Gun`, …). That is most of the 131: 59 player + 10 AI-Saber + ship/ADAN
turret guns.
**Upgrades yesterday's 🟡** — the "hardpoint catalogue" reading of the
player craft's 63 `Turret_NNN` slots is now ADOPTED, proved from an
independent file. ⚠️ And it corrects a number in that entry: the "10 distinct
`WeaponID`s" was measured on the **AI** variant; `_Player` has 59.
An item record also carries `Model`/`Package`/`SilhouetteModel` (the meshes
the corpus decodes), `Points` + `Stage` (the develop economy
`arsenal-develop-economy.md` recovered from the screen side), the Hangar stat
bars `Power`/`Range`/`Size`/`Speed`/`Weight`, and `Type` = a slot class.
🟡 Not settled: `Type` and the per-slot allow-lists (`STANDARD_ARM1/2/3`,
`PlayerSET_*`, `ExSET_*`, `SNNSET_*` — records whose only field is `Type`);
the **wingman loadout** records (`Bird1-Sandra`, `Rhino1-Katana`, … with
`Arm1`/`Arm2`/`Arm3`/`Nose`/`UnitID`) — named here, not opened; empty
`Dependency`/`MissionObjective`; which weapons the 26 never-on-a-turret ones
are.
***(2026-08-27) THE DESTRUCTIBLE-SUBSYSTEM MODEL — a unit's sub-records, ***(2026-08-27) THE DESTRUCTIBLE-SUBSYSTEM MODEL — a unit's sub-records,
opened at last. 835 turrets, and every turret's weapon resolves.** opened at last. 835 turrets, and every turret's weapon resolves.**
[structures/unit-substructure-records](structures/unit-substructure-records.md), [structures/unit-substructure-records](structures/unit-substructure-records.md),

View File

@@ -99,6 +99,7 @@ files, which is how the same ground got covered twice.
| [`structures/sound-cue-table.md`](structures/sound-cue-table.md) | The cue index in `tables.pak` — message id -> cue -> sound id -> `.slb` bank | ✅ CONFIRMED, 1 326/1 338 script message ids bind to a bank; SOUNDS and FILES agree on the same 12 absentees, 0 orphan files | | [`structures/sound-cue-table.md`](structures/sound-cue-table.md) | The cue index in `tables.pak` — message id -> cue -> sound id -> `.slb` bank | ✅ CONFIRMED, 1 326/1 338 script message ids bind to a bank; SOUNDS and FILES agree on the same 12 absentees, 0 orphan files |
| [`structures/cutscene-message-table.md`](structures/cutscene-message-table.md) | Cutscene dialogue — speaker, portrait, on-screen seconds, audio cue per page | ✅ CONFIRMED, field count = 9·PageCount+2 for all 7 PageCounts, 1 252/1 252 caption keys match, 138 ids close both ways | | [`structures/cutscene-message-table.md`](structures/cutscene-message-table.md) | Cutscene dialogue — speaker, portrait, on-screen seconds, audio cue per page | ✅ CONFIRMED, field count = 9·PageCount+2 for all 7 PageCounts, 1 252/1 252 caption keys match, 138 ids close both ways |
| [`structures/isl-mission-timer.md`](structures/isl-mission-timer.md) | The mission timer — two sequential countdowns, not a limit and a warning | ✅ CONFIRMED — read from `sub_822639B8`; the threshold reading is | | [`structures/isl-mission-timer.md`](structures/isl-mission-timer.md) | The mission timer — two sequential countdowns, not a limit and a warning | ✅ CONFIRMED — read from `sub_822639B8`; the threshold reading is |
| [`structures/arsenal-item-weapon-chain.md`](structures/arsenal-item-weapon-chain.md) | The 59-of-131 arsenal question — an item names a hardpoint slot, not a weapon | ✅✅ CONFIRMED — 0/59 `PlayerWeapon` are a `Weapon.ID`, 59/59 are a `Turret_NNN` slot |
| [`structures/unit-substructure-records.md`](structures/unit-substructure-records.md) | The destructible-subsystem model — a unit's `Turret`/`Bridge`/`Hatch`/`ShieldGenerator`/`Thruster` sub-records | ✅ CONFIRMED — 835 turrets, 835/835 `WeaponID` resolve, `StructureCount` control 667/684 | | [`structures/unit-substructure-records.md`](structures/unit-substructure-records.md) | The destructible-subsystem model — a unit's `Turret`/`Bridge`/`Hatch`/`ShieldGenerator`/`Thruster` sub-records | ✅ CONFIRMED — 835 turrets, 835/835 `WeaponID` resolve, `StructureCount` control 667/684 |
| [`structures/unit-datasheet-static.md`](structures/unit-datasheet-static.md) | The static unit datasheet and AI flight model — `Generic`, `Maneuver`, `Effect` | ✅ CONFIRMED — 394 Generic + 114 Maneuver + 114 Effect records read | | [`structures/unit-datasheet-static.md`](structures/unit-datasheet-static.md) | The static unit datasheet and AI flight model — `Generic`, `Maneuver`, `Effect` | ✅ CONFIRMED — 394 Generic + 114 Maneuver + 114 Effect records read |
| [`structures/weapon-datasheet-static.md`](structures/weapon-datasheet-static.md) | The static weapon datasheet — `Weapon`, `Shell`, `AssortMissileParam` | ✅ CONFIRMED — 131 Weapon + 131 Shell + 9 AssortMissileParam records read | | [`structures/weapon-datasheet-static.md`](structures/weapon-datasheet-static.md) | The static weapon datasheet — `Weapon`, `Shell`, `AssortMissileParam` | ✅ CONFIRMED — 131 Weapon + 131 Shell + 9 AssortMissileParam records read |

View File

@@ -0,0 +1,72 @@
# The Arsenal item -> hardpoint slot -> Weapon record chain
# Regenerate: python3 tools/re-capture/arsenal_chain.py
# See docs/re/structures/arsenal-item-weapon-chain.md
## the roster and the item records
WEAPONS roster values 59
arsenal ITEM records 59
item names that are roster values 55
roster values with no item record: ['No_Equipment', 'NullWeapon_Arm1', 'NullWeapon_Arm2', 'NullWeapon_Arm3']
Weapon.ID values in the datasheet 131
## CONTROL item.PlayerWeapon is NOT a Weapon.ID
distinct PlayerWeapon values 59 ; how many are a Weapon.ID: 0
## CONTROL item.PlayerWeapon IS a Turret_NNN slot id
UN_f001_TCAF_DeltaSaber_T slots 63 Player 59/59 Wingman 59/59
UN_f001_TCAF_DeltaSaber_T_EX5 slots 63 Player 59/59 Wingman 59/59
UN_f001_TCAF_DeltaSaber_T_EX5_el slots 63 Player 59/59 Wingman 59/59
UN_f001_TCAF_DeltaSaber_T_Player slots 63 Player 59/59 Wingman 59/59
UN_f001_TCAF_DeltaSaber_T_Player_Ttrl1 slots 5 Player 3/59 Wingman 3/59
UN_f001_TCAF_DeltaSaber_T_Player_Ttrl2 slots 5 Player 1/59 Wingman 1/59
UN_f001_TCAF_DeltaSaber_T_Ttrl slots 4 Player 4/59 Wingman 4/59
UN_f002_TCAF_DeltaSaber_W slots 63 Player 59/59 Wingman 59/59
UN_f002_TCAF_DeltaSaber_W_Player slots 63 Player 59/59 Wingman 59/59
UN_f004_TCAF_DeltaSaber_A_Player slots 63 Player 59/59 Wingman 59/59
## THE CHAIN, per craft variant: item -> slot -> WeaponID -> Weapon.ID
UN_f001_TCAF_DeltaSaber_T 59/ 59 land on a Weapon.ID, 10 distinct
slot WeaponIDs: 59 non-NULL, 10 distinct, e.g. ['Weapon_TCAF_DeltaSaber_ASMissile', 'Weapon_TCAF_DeltaSaber_Beam']
UN_f001_TCAF_DeltaSaber_T_EX5 59/ 59 land on a Weapon.ID, 10 distinct
slot WeaponIDs: 59 non-NULL, 10 distinct, e.g. ['Weapon_TCAF_DeltaSaber_ASMissile', 'Weapon_TCAF_DeltaSaber_Beam']
UN_f001_TCAF_DeltaSaber_T_EX5_el 59/ 59 land on a Weapon.ID, 10 distinct
slot WeaponIDs: 59 non-NULL, 10 distinct, e.g. ['Weapon_TCAF_DeltaSaber_ASMissile', 'Weapon_TCAF_DeltaSaber_Beam']
UN_f001_TCAF_DeltaSaber_T_Player 59/ 59 land on a Weapon.ID, 59 distinct
slot WeaponIDs: 59 non-NULL, 59 distinct, e.g. ['Weapon_DSaber_P_wep_01_Beam', 'Weapon_DSaber_P_wep_02_Missile']
UN_f001_TCAF_DeltaSaber_T_Player_Ttrl1 3/ 59 land on a Weapon.ID, 3 distinct
slot WeaponIDs: 3 non-NULL, 3 distinct, e.g. ['Weapon_DSaber_P_wep_01_Beam', 'Weapon_DSaber_P_wep_02_Missile']
UN_f001_TCAF_DeltaSaber_T_Player_Ttrl2 1/ 59 land on a Weapon.ID, 1 distinct
slot WeaponIDs: 1 non-NULL, 1 distinct, e.g. ['Weapon_DSaber_P_wep_01_Beam']
UN_f001_TCAF_DeltaSaber_T_Ttrl 4/ 59 land on a Weapon.ID, 4 distinct
slot WeaponIDs: 4 non-NULL, 4 distinct, e.g. ['Weapon_TCAF_DeltaSaber_ASMissile', 'Weapon_TCAF_DeltaSaber_Beam']
UN_f002_TCAF_DeltaSaber_W 59/ 59 land on a Weapon.ID, 10 distinct
slot WeaponIDs: 59 non-NULL, 10 distinct, e.g. ['Weapon_TCAF_DeltaSaber_ASMissile', 'Weapon_TCAF_DeltaSaber_Beam']
UN_f002_TCAF_DeltaSaber_W_Player 59/ 59 land on a Weapon.ID, 59 distinct
slot WeaponIDs: 59 non-NULL, 59 distinct, e.g. ['Weapon_DSaber_P_wep_01_Beam', 'Weapon_DSaber_P_wep_02_Missile']
UN_f004_TCAF_DeltaSaber_A_Player 59/ 59 land on a Weapon.ID, 59 distinct
slot WeaponIDs: 59 non-NULL, 59 distinct, e.g. ['Weapon_DSaber_P_wep_01_Beam', 'Weapon_DSaber_P_wep_02_Missile']
player craft slots not referenced by any item: ['Turret_000', 'Turret_097', 'Turret_098', 'Turret_099']
## a full item record -- Arbalest_155KG
Dependency
MissionObjective
Model rou_f001_wep_50_hangar
Package rou_f001_wep_50_hangar.xpr
PlayerLOD Equip_EnumLODSet_wep_50.tbl
PlayerMotion Equip_EnumGameModel_wep_50.tbl
PlayerPackage rou_f001_wep_50.xpr
PlayerWeapon Turret_050
Points 25000
Power B
Range B
SilhouetteModel rou_f001_wep_50_NA
Size L
Speed -
Stage 6
Type g04b
Weight 1.5
WingmanLOD Equip_EnumLODSet_wep_50.tbl
WingmanMotion Equip_EnumGameModel_wep_50.tbl
WingmanPackage rou_f001_wep_50.xpr
WingmanWeapon Turret_050

View File

@@ -0,0 +1,92 @@
# ✅✅ 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.

View File

@@ -94,11 +94,16 @@ declared=1 records=2 x1 UN_e001_ADAN_Elan_EX4
declared=8 records=9 x1 UN_e107_ADAN_AAFrigate_EX4 declared=8 records=9 x1 UN_e107_ADAN_AAFrigate_EX4
``` ```
🟡 The reading — **not adopted**: on the player craft the `Turret_NNN` list is **ADOPTED the next day** on the player craft the `Turret_NNN` list is a
a *hardpoint catalogue* and `TurretCount 4` is how many mount at once. It fits *hardpoint catalogue* and `TurretCount 4` is how many mount at once. The
(63 slots, all `Frame=GN_mnt`, all `IsAuto=No`, 10 distinct `WeaponID`s across Arsenal table proves it from an independent file: **59/59 of its items name a
them, and the tutorial variants carry a cut-down 5) but nothing here shows the `Turret_NNN` slot in `PlayerWeapon`**, see
selection. The two `+1` warship/craft cases are unexplained. [arsenal-item-weapon-chain](arsenal-item-weapon-chain.md). The two `+1`
warship/craft cases are still unexplained.
⚠️ The "10 distinct `WeaponID`s" 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 ## 🧪 Control 2 — turret weapons resolve into the weapon datasheet

View File

@@ -0,0 +1,93 @@
#!/usr/bin/env python3
"""Resolve the arsenal item -> hardpoint slot -> weapon record chain.
An Arsenal item in GP_HANGAR_ARSENAL.pak names a HARDPOINT SLOT on the player
craft (`PlayerWeapon = Turret_050`), not a weapon. The slot's `WeaponID` is
what points into the 131-record `Weapon` datasheet. Regenerates
docs/re/data/arsenal-chain.txt.
"""
import sys, os, glob, re, collections
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import unitgroup as U
from unit_substructures import pak_entries
ITEMF = {'Dependency', 'MissionObjective', 'Model', 'Package',
'PlayerWeapon', 'Points', 'Power', 'Range'}
def main():
ars = glob.glob('/work/sylph_extract/**/GP_HANGAR_ARSENAL.pak', recursive=True)[0]
mg = glob.glob('/work/sylph_extract/**/GP_MAIN_GAME_E.pak', recursive=True)[0]
slots = collections.defaultdict(dict); wids = set()
for h, b in pak_entries(mg):
if b[:4] != b'IDXD': continue
try: recs = U.parse(b)
except Exception: continue
for r in recs:
if r['squadron'] == 'Weapon':
i = U.named(r).get('ID')
if i: wids.add(i)
g = [r for r in recs if r['squadron'] == 'Generic']
if not (g and 'HP' in U.named(g[0])): continue
uid = U.named(g[0]).get('ID')
for r in recs:
if re.fullmatch(r'Turret_\d{3}', r['squadron']):
slots[uid][r['squadron']] = U.named(r).get('WeaponID')
items = {}; roster = None
for h, b in pak_entries(ars):
if b[:4] != b'IDXD': continue
try: recs = U.parse(b)
except Exception: continue
for r in recs:
if r['squadron'] == 'WEAPONS' and roster is None: roster = r
if ITEMF <= set(U.named(r)): items.setdefault(r['squadron'], r)
print("# The Arsenal item -> hardpoint slot -> Weapon record chain")
print("# Regenerate: python3 tools/re-capture/arsenal_chain.py")
print("# See docs/re/structures/arsenal-item-weapon-chain.md")
rset = {v for _, _, v in roster['fields']}
print("\n## the roster and the item records")
print(" WEAPONS roster values %3d" % len(rset))
print(" arsenal ITEM records %3d" % len(items))
print(" item names that are roster values %3d" % len(set(items) & rset))
print(" roster values with no item record: %s" % sorted(rset - set(items)))
print(" Weapon.ID values in the datasheet %3d" % len(wids))
print("\n## CONTROL item.PlayerWeapon is NOT a Weapon.ID")
pw = {U.named(r).get('PlayerWeapon', '').strip() for r in items.values()}
print(" distinct PlayerWeapon values %3d ; how many are a Weapon.ID: %d" % (len(pw), len(pw & wids)))
print("\n## CONTROL item.PlayerWeapon IS a Turret_NNN slot id")
for craft in sorted(slots):
if 'Saber' not in craft: continue
s = slots[craft]
hit = sum(1 for r in items.values() if U.named(r).get('PlayerWeapon', '').strip() in s)
wing = sum(1 for r in items.values() if U.named(r).get('WingmanWeapon', '').strip() in s)
print(" %-40s slots %2d Player %2d/%d Wingman %2d/%d" %
(craft, len(s), hit, len(items), wing, len(items)))
print("\n## THE CHAIN, per craft variant: item -> slot -> WeaponID -> Weapon.ID")
for craft in sorted(slots):
if 'Saber' not in craft: continue
s = slots[craft]
reach = [s.get(U.named(r).get('PlayerWeapon', '').strip()) for r in items.values()]
land = [w for w in reach if w in wids]
print(" %-40s %3d/%3d land on a Weapon.ID, %2d distinct" %
(craft, len(land), len(items), len(set(land))))
vs = [v for v in s.values() if v and v != 'Weapon_NULL']
print(" slot WeaponIDs: %d non-NULL, %d distinct, e.g. %s" %
(len(vs), len(set(vs)), sorted(set(vs))[:2]))
s = slots['UN_f001_TCAF_DeltaSaber_T_Player']
used = {U.named(r).get('PlayerWeapon', '').strip() for r in items.values()}
print("\n player craft slots not referenced by any item: %s" % sorted(set(s) - used))
k = sorted(items)[0]
print("\n## a full item record -- %s" % k)
for kk, vv in sorted(U.named(items[k]).items()):
print(" %-22s %s" % (kk, vv))
main()

View File

@@ -118,4 +118,5 @@ def main():
print(" resolve: %d do NOT resolve: %d" % (hit, sum(wids.values()) - hit)) print(" resolve: %d do NOT resolve: %d" % (hit, sum(wids.values()) - hit))
print(" weapons never mounted on a turret: %d" % len(wnames - set(wids))) print(" weapons never mounted on a turret: %d" % len(wnames - set(wids)))
main() if __name__ == "__main__":
main()