Drove the retail game headless (Canary + lavapipe, vgamepad) to the Ready Room Arsenal and read the Gallery-Mode DATA SHEET for every weapon the 5%-progress save reveals. Two UI->field mappings are CONFIRMED against weapons whose values ARE on disc: Ammo Capacity == LoadingCount (9/9 exact matches) Max. Lock Ons == TriggerShotCount (FALCON 9AM 12 == wep_02; BUZZARD 22 == wep_04) That makes the panel an oracle for fields the disc leaves defaulted, and it is shown for undeveloped weapons too, so no points need spending. Recovered TriggerShotCount for wep_05 and wep_60 (both 4, on-disc absent), and bracketed the defaulted Power / MaximumRange via the Range/Damage letter classes. Ruled out first: the defaults are not in hidden/DefTables.pak (no WEAPON-schema objects there) nor in the localized GP_MAIN_GAME_* duplicates. Also adds the two analysis examples that produce the shopping list of defaulted fields, the screenshot harness used to drive the menus, and the evidence PNGs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
151 lines
9.5 KiB
Markdown
151 lines
9.5 KiB
Markdown
# Weapon DATA SHEET — runtime capture (Route B)
|
||
|
||
**Status:** 🟡 first dynamic capture, 2026-07-28. The Arsenal's *Gallery Mode* panel is a
|
||
direct runtime readout of the IDXD weapon record, which makes it an oracle for the fields
|
||
the disc leaves **defaulted**. Two field mappings are ✅ `CONFIRMED`; two defaulted values
|
||
are recovered at 🟡 `PROBABLE`. Captured from the retail game under Xenia Canary
|
||
(software Vulkan, headless) — see [the container recipe](#how-this-was-captured).
|
||
|
||
## Problem
|
||
|
||
`sylpheed-formats::game_data` reads the combat tables out of `dat/GP_MAIN_GAME_E.pak`, but
|
||
**a field left at its default value carries no value on disc** — the key is present in the
|
||
IDXD string pool with no value token in front of it. Those defaults live in title code, so
|
||
a static read can only ever say "not set", never *what* the game uses. That is a real hole
|
||
for the reimplementation: e.g. `Weapon_DSaber_P_wep_01_Beam` — the Delta Saber's starting
|
||
beam gun — has no `TriggerShotCount` and no `Power` on disc.
|
||
|
||
Ruled out first: the defaults are **not** hiding in another pak. `hidden/DefTables.pak`
|
||
contains no `WEAPON`-schema (`0x6ab4825a`) objects at all, and the other `GP_MAIN_GAME_*`
|
||
paks are localized duplicates of the English one.
|
||
|
||
The two scratch analyses that produced the shopping list live next to the crate:
|
||
`crates/sylpheed-formats/examples/defaulted_fields.rs` (per-schema: which keys are declared
|
||
but defaulted, and by whom) and `examples/default_owners.rs` (per-key: every owner, valued
|
||
or `<DEFAULT>`).
|
||
|
||
> Caveat on those tools: they classify a token as a *value* only if it is numeric or
|
||
> non-identifier-shaped. **Boolean/enum-valued fields therefore read as `<DEFAULT>`
|
||
> spuriously** (`Yes`, `Homing`, `Single`, `Burst` are identifier-shaped). Every finding
|
||
> below concerns numeric fields, where the classification is sound.
|
||
|
||
## Finding — the DATA SHEET reads the record
|
||
|
||
In **ARSENAL → (weapon type) → Y (Gallery Mode)** each entry shows a `DATA SHEET`, and it
|
||
is shown for weapons that have **not** been developed yet — only fully hidden (dashed)
|
||
entries are withheld. The same panel appears in **HANGAR → (hard point)**, with an extra
|
||
`Weapon Type` row.
|
||
|
||
| DATA SHEET row | IDXD field | Confidence | Evidence |
|
||
|---|---|---|---|
|
||
| `Ammo Capacity` | `LoadingCount` | ✅ CONFIRMED | 9/9 exact matches across 4 weapon types — 3000, 6000, 4000, 600, 300, 600, 45, 18, 75 |
|
||
| `Max. Lock Ons` | `TriggerShotCount` | ✅ CONFIRMED | FALCON 9AM = 12 vs `wep_02`'s 12; BUZZARD 10AM = 22 vs `wep_04`'s 22 (two distinctive values, two independent records) |
|
||
| `Hard Point` | mount slot | ✅ CONFIRMED | matches the HANGAR slot the weapon is mountable/equipped on (`STILETTO BG I` → NOSE, `FALCON 9AM` → MAIN WEAPON1) |
|
||
| `Range Class` | bucket of `MaximumRange` | 🟡 PROBABLE | monotone in the on-disc metres, see the bracket table below |
|
||
| `Damage Class` | bucket of `Power` | 🟡 PROBABLE | monotone in the on-disc power, see below |
|
||
| `Weight Class` | bucket of the hangar-table `Weight` | ❔ HYPOTHESIS | only one clean pair so far (`wep_33`, Weight 0.3 → "Light") |
|
||
| `Speed Class` | ❔ | ❔ | present only on missiles (MPM = A, ASM = B); no on-disc pairing established |
|
||
| `Sight Homing`, `Lock on Overlap` | ❔ (`Available` / `–`) | ❔ | the plausible on-disc partners (`Homing`, `OverlapLockon`) are identifier-valued and not yet decoded; **NEEDS-HUMAN** |
|
||
|
||
## Finding — recovered defaults
|
||
|
||
| Weapon | UI name | Field | On disc | **Runtime** | Conf. |
|
||
|---|---|---|---|---|---|
|
||
| `Weapon_DSaber_P_wep_05_ASMissile` | TERRIER SMH | `TriggerShotCount` | *(defaulted)* | **4** | 🟡 |
|
||
| `Weapon_DSaber_P_wep_60_ASMissile` | HOUND SMH | `TriggerShotCount` | *(defaulted)* | **4** | 🟡 |
|
||
|
||
Both defaulted weapons read **4**, which is consistent with a single title-code default of
|
||
`TriggerShotCount = 4` rather than two per-weapon constants — but two samples cannot tell
|
||
those apart. ❔ HYPOTHESIS: *the title-code default for `TriggerShotCount` is 4.* It would
|
||
be confirmed by a third weapon that defaults the field and also reads 4 (candidates that
|
||
were still locked in this save: `wep_27`, `wep_30`, and the seven Beams), or refuted by one
|
||
that reads anything else.
|
||
|
||
`Power` and `MaximumRange` defaults are **not** exactly recoverable from this panel — it
|
||
shows only the letter bucket. They are bracketed instead (below).
|
||
|
||
## Captured rows
|
||
|
||
All values are from one session on save slot 01 (Stage 02, "At Standby", 5 % clear, 4101 P);
|
||
`✓` marks a value that matches the on-disc record exactly.
|
||
|
||
| UI name | Record | Rng | Dmg | Spd | Weight | Ammo | Lock | Homing | Overlap | Hard point |
|
||
|---|---|---|---|---|---|---|---|---|---|---|
|
||
| LIGHT MACHINE GUN MG I | `wep_33_Gun` | D | E | – | Light | 3000 ✓ | – | – | – | NOSE WEAPON (Nose) |
|
||
| BROAD SWORD SG I | *see below* | E | D | – | Light | 200 | – | – | – | NOSE WEAPON (Nose) |
|
||
| STILETTO BG I | `wep_01_Beam` | E | E | – | Light | 6000 ✓ | – | – | – | NOSE WEAPON (Nose) |
|
||
| DAGGER BG2 | `wep_37_Beam` | D | E | – | Light | 4000 ✓ | – | – | – | NOSE WEAPON (Nose) |
|
||
| PILUM BP | `wep_24_Beam` | B | D | – | Light | 600 ✓ | – | – | – | MAIN WEAPON1 (Fore) |
|
||
| FALCON 9AM | `wep_02_Missile` | D | D | A | Heavy | 300 ✓ | 12 ✓ | Available | – | MAIN WEAPON1 (Fore) |
|
||
| BUZZARD 10AM | `wep_04_Missile` | C | D | A | Heavy | 600 ✓ | 22 ✓ | – | Available | MAIN WEAPON1 (Fore) |
|
||
| DART 23 ROCKET | `wep_55_Rocket` | C | D | – | Heavy | 600 ✓ | – | – | – | MAIN WEAPON1 (Fore) |
|
||
| TERRIER SMH | `wep_05_ASMissile` | D | C | B | Heavy | 45 ✓ | **4** | Available | Available | MAIN WEAPON2 (Rear) |
|
||
| HOUND SMH | `wep_60_ASMissile` | B | C | B | Medium | 18 ✓ | **4** | Available | Available | MAIN WEAPON2 (Rear) |
|
||
| TOMAHAWK ALPHA RAIL GUN | `wep_03_Cannon` | C | C | – | Medium | 75 ✓ | – | – | – | MAIN WEAPON3 (Lower) |
|
||
|
||
**BROAD SWORD SG I is unidentified — NEEDS-HUMAN.** `Ammo Capacity 200` narrows it to
|
||
`wep_38` / `wep_41` / `wep_42_Shotgun` (all `LoadingCount = 200`); "SG" and the GUN tab fit
|
||
a shotgun. `wep_42` is excluded by range (2500 m would not share class E with `wep_38`/
|
||
`wep_41`'s 3000 m *if* the class is a pure range bucket), leaving `wep_38` vs `wep_41`,
|
||
which the panel cannot separate. Its `Damage Class D` also does not fit the `Power` bracket
|
||
below (all three shotguns are `Power ≤ 16`, i.e. bucket E), so either the identification or
|
||
the "Damage Class = bucket of `Power`" model is wrong for shotguns.
|
||
|
||
### Letter-class brackets
|
||
|
||
Sorting the identified rows by their on-disc numbers gives monotone, non-overlapping bands:
|
||
|
||
```
|
||
Range Class E: 3000 (wep_01)
|
||
D: 3500 · 4000 · 4000 · 4000 (wep_33, wep_37, wep_02, wep_05)
|
||
C: 4500 · 5000 · 5000 (wep_55, wep_04, wep_03)
|
||
B: 6500 · 6500 (wep_24, wep_60)
|
||
|
||
Damage Class E: 10 · 14 · 16 (wep_33, wep_01, wep_37)
|
||
D: 70 · 75 · 100 (wep_24, wep_04, wep_55)
|
||
C: 200 · 400 (wep_03, wep_05)
|
||
```
|
||
|
||
Two consequences for the reimplementation:
|
||
|
||
- The **thresholds are not pinned** — only bracketed (e.g. the D/C range boundary lies in
|
||
(4000, 4500]). More weapons, or a static read of the title-code table, would pin them.
|
||
- They **bracket the defaulted numbers**: `wep_02_Missile`'s defaulted `Power` sits in the
|
||
D band (≈ 17…150 by the observed edges) and `wep_60_ASMissile`'s in the C band
|
||
(≈ 150…500). 🟡 PROBABLE, and only as good as the bucket model.
|
||
|
||
## How this was captured
|
||
|
||
Container recipe (`sylph-container/mission.md`), with two corrections worth keeping:
|
||
|
||
- **Skip the intro movie with A.** The brief warns it crashes; it does not. Skipping cuts
|
||
boot-to-main-menu from ~13 min to **~1 min** under lavapipe. (Thanks: user tip.)
|
||
- **The title screen falls back to the attract loop within a few seconds**, so a
|
||
screenshot→look→tap cycle always misses it. Poll the framebuffer and tap in the same
|
||
process. Both are automated in `scratchpad/skip_intro.sh` (movie detected by frame-to-
|
||
frame RMSE; title by the green Ⓐ glyph at pixel 625,618).
|
||
- Under lavapipe the game polls input at its own low frame rate: **a 60 ms d-pad tap is
|
||
dropped roughly half the time**; 200 ms is reliable and 300 ms starts to auto-repeat.
|
||
- The Hangar hard-point weapon carousel is cycled with d-pad **down**, not left/right.
|
||
|
||
Path: title → A → LOAD GAME → slot 01 → *Load game?* **YES** → READY ROOM → ARSENAL →
|
||
type tab (LB/RB) → **Y** for the DATA SHEET → d-pad down through the list.
|
||
|
||
## Open / next
|
||
|
||
- Only **9 weapons of ~61** are revealed at 5 % completion, and none of the four whose
|
||
`LoadingCount` is defaulted (`wep_11`, `wep_28`, `wep_36`, `wep_70`) is among them.
|
||
Progressing the save (or a later save) is what unlocks the rest — the panel itself
|
||
already shows undeveloped weapons, so no points need to be spent.
|
||
- **Craft (`UNIT`-schema) defaults are not reachable this way.** The Hangar exposes exactly
|
||
one craft-level runtime number, `Gross Weight` (a class, "Light"). The defaulted craft
|
||
fields (`ShieldRatio`, `BarrelRoll_Count*`, `HoldPosition_*Ratio`, `Slalom_TurnCount_Max`,
|
||
`UsingChaffRatio`, …) are AI/flight-model constants with no UI surface; they would need
|
||
in-flight behavioural measurement or a guest-memory read, not a menu screenshot.
|
||
- The `Sight Homing` / `Lock on Overlap` on-disc partners are still unidentified.
|
||
|
||
Screenshots for every row above: `/sylph-home/re/caps/` in the container.
|
||
|
||
Evidence PNGs are committed under [`captures/weapon-datasheet/`](captures/weapon-datasheet/)
|
||
(64-colour quantized for size; the numbers stay legible).
|