re: the reactive-chatter rule table behind ORDOR_SQUADRON_EXTENDED

864 records = 144 rule tables per language pack x 6.  One schema for all
9216 event records; MessageCount*2 == positional count with zero mismatches.
Named 136/144 by two independent routes that agree as sets.  2388/2405
message ids join the settled sound-cue table.

Corrects squadron-orders.md: the executable misspells all four SQUADRON
entries of the 0x820AEEB0 enum as ORDOR_, and the disc data matches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Claude (auto)
2026-08-27 16:07:17 +00:00
parent d1368c12db
commit 2c2af7ad78
6 changed files with 783 additions and 5 deletions

View File

@@ -4029,3 +4029,67 @@ cinematic — before crashing at the same `0x82307128`. The crash is intermitten
in **where** it fires, not whether, so there is no menu route around it. See
[`title-crash-stl-tree.md`](title-crash-stl-tree.md) for the end-to-end
measurement and for what has been ruled out (`--mem_watch=false`, twice).
---
## ✅ 2026-08-27 — `ORDOR_SQUADRON_EXTENDED` opened: the reactive-chatter rule table
The biggest unopened record name in the 3 496-name census (**864 records**) is a
record in the **chatter rule table**: 144 objects per language pack × 6 packs.
Write-up: [`structures/preset-message-rules.md`](structures/preset-message-rules.md);
artefact `data/preset-messages.txt`; regenerator
`tools/re-capture/preset_messages.py`.
**Docs checked before claiming anything**`squadron-orders.md`,
`sound-cue-table.md`, `cutscene-message-table.md`, `ixud-localised-text.md`,
`isl-message-dialogue-link.md`, `movie-subtitles.md`, `mission-phase-deployment.md`,
`mission-phase-membership.md`. Two of them own parts of this:
* `ixud-localised-text.md` owns "`PresetMessage_*` is reactive combat chatter
keyed by speaker class", and `mission-phase-deployment.md` owns the route in
(`UnitMessageSet_S<NN>.tbl``PresetMessage_Phase1/2/3`). **What neither says**
is what is inside the table.
* `cutscene-message-table.md` owns the `Generic`+`Message_NNN` layout for the 32
cutscene objects per pack. **What it does not say** is that the same layout
carries **137 more** objects per pack for in-mission chatter. Control: of 273
`PresetMessage_*` names that hit an IDXD entry, 136 are rule tables and 137 are
message tables — the prefix names two different shapes.
**One schema, no variants.** All 9 216 event records (144 × 64) carry the same
seven named fields — `EffectiveTime, Interval, Priority, Probability,
MessageCount, IntervalFluctuation, Pattern` — then positional `(message id,
Yes/No)` pairs. **`MessageCount · 2 == positional count` in 9 216/9 216, zero
mismatches**, which is what pins the pairing.
**Named twice, independently, with the same answer.** Harvested
`PresetMessage_*` strings hashed under `message\` → 136/144; the
`PresetMessage_Phase1/2/3` declarations of the 22 `UnitMessageSet_S<NN>.tbl`
tables → 136/144; **the two routes name the same set** (set identity, not a
matching count).
**Joins to the settled cue table**: 2 388 of 2 405 distinct message ids
resolve (99.3 %) through `sound-cue-table.md`'s index.
⚠️ **A trap that doc had already paid for, and I walked into it anyway.**
Rewriting `MSG_``VOICE_` unconditionally scores 2 353/2 405, and the 52 misses
looked like a finding ("lines with no recording"). 44 of them were a naming
artefact: `sound-cue-table.md` states that a name already carrying `VOICE_` keeps
the one it has. Applying the documented exception gives 2 388/2 405. Reading the
owning doc caught this *after* the first write-up was drafted — the earlier grep
found the ownership, but the rule inside it still had to be read.
**Correction to `squadron-orders.md`** — it rendered the `0x820AEEB0` enum as
twelve `ORDER_*` names. The executable's own strings misspell all four SQUADRON
entries as **`ORDOR_*`**, and the disc data carries the identical misspelling,
which is how the two sides join. That doc's 🔴 "this is a UI/comms axis, not the
order classes" now has its explanation: the twelve are bark *events*.
**Not settled.** What the seven numeric fields mean (schema only, not
measured against the running game); the `Yes`/`No` element of each pair; which of
the 49 `Sperkers` speakers is a wingman (the "13 tables voice every player-facing
event" partition is a count, not a verified roster). 🟡 **8 of the 144 rule
tables are named by neither route** — nothing on the disc declares them.
`UnitMessageSet_S<NN>.tbl` exists for 22 of the 28 stages and the six missing are
exactly **S18S23, the tutorials** (same set as the missing `AIParams_SNN.tbl`),
so tutorial chatter is the plausible reading — but there is no tutorial
`UnitMessageSet` to confirm it, so it stays a reading.

View File

@@ -98,6 +98,7 @@ files, which is how the same ground got covered twice.
| [`structures/sound-pak-contents.md`](structures/sound-pak-contents.md) | Census of `sound.pak`, and the limit of the leading-region rule | ✅ CONFIRMED, 5 135/5 135 names hash into the TOC, **9 519/9 519** entries accounted for, and a full 4 114-bank manifest (408.3 min of audio) computed from PsuedoBytesPerSec without decoding; ⚠️ leading-region rule holds for 1 571/4 382 eng and 0/5 100 jpn |
| [`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/preset-message-rules.md`](structures/preset-message-rules.md) | The reactive-chatter rule table — 64 events, the (message, Yes/No) pair payload, the `Sperkers` roster | ✅ CONFIRMED, MessageCount·2 == positional count in 9 216/9 216; two independent naming routes agree on the same 136/144; 2 388/2 405 message ids bind to a cue |
| [`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/archive-naming.md`](structures/archive-naming.md) | Which archives the disc can name — 100% for menu paks, **0.0%** for the six 2D paks and `GP_READY_ROOM` | ✅ CONFIRMED — 6027 names × 16 prefixes, bimodal |
| [`structures/hud-config.md`](structures/hud-config.md) | The in-game HUD configuration — 16 records, 419 asset paths, and a per-stage `ResourceTable` | ✅ CONFIRMED — 0 of 419 config paths resolve as pak entries |

View File

@@ -0,0 +1,309 @@
# Reactive combat-chatter rule tables (regenerated by preset_messages.py)
rule tables in GP_MAIN_GAME_E.pak : 144 of 1004 IDXD entries
per language pack : {'GP_MAIN_GAME_D.pak': 144, 'GP_MAIN_GAME_E.pak': 144, 'GP_MAIN_GAME_F.pak': 144, 'GP_MAIN_GAME_I.pak': 144, 'GP_MAIN_GAME_J.pak': 144, 'GP_MAIN_GAME_S.pak': 144}
total across the disc : 864
distinct record-name tuples : 1
records per table : 65 (64 events + Sperkers)
distinct named-field schemas : 1
x9216 EffectiveTime, Interval, Priority, Probability, MessageCount, IntervalFluctuation, Pattern
MessageCount*2 == positional count: 9216/9216 (mismatches 0)
second-of-pair values : {'No': 8940, 'Yes': 388}
the 64 event records, and how many of the 144 tables give each one lines:
ATTACK_IS_AVOIDED 114
ATTACK_SUCCEEDED 114
AVOIDED_BY_PLAYER 50
AVOIDED_PLAYER_ATTACK 15
AVOID_ATTACK 118
COUNTER 114
COUNTER_TO_PLAYER 45
DAMAGED 124
DAMAGED_BY_PLAYER_50_30 0
DAMAGED_BY_PLAYER_GREATER_50 128
DAMAGED_BY_PLAYER_LESS_30 127
DAMAGED_TO_PLAYER 50
EXTENDED 95
EXTENDED_BY_PLAYER 86
FOUND 111
FOUND_PLAYER 45
HP_LESS_10 121
HP_LESS_30 0
HP_LESS_50 121
KILLED 82
KILLED_BY_PLAYER 96
KILL_PLAYER 2
KILL_UNIT 114
LOCKON_1 13
LOCKON_10 13
LOCKON_11 13
LOCKON_12 13
LOCKON_2 13
LOCKON_3 13
LOCKON_4 13
LOCKON_5 13
LOCKON_6 13
LOCKON_7 13
LOCKON_8 13
LOCKON_9 13
LOCKON_DOWN 13
LOCKON_UP 13
LOST_BRIDGE_BY_PLAYER 18
LOST_SHIELD_BY_PLAYER 18
LOST_THRUSTER_BY_PLAYER 18
LOST_TURRET_BY_PLAYER 18
ORDER_SQUAD_ATTACK 7
ORDER_SQUAD_COVER 7
ORDER_SQUAD_EXTENDED 7
ORDER_SQUAD_FORMATION 7
ORDER_WINGMAN_ATTACK 13
ORDER_WINGMAN_COVER 13
ORDER_WINGMAN_EXTENDED 13
ORDER_WINGMAN_FORMATION 13
ORDOR_SQUADRON_ATTACK 7
ORDOR_SQUADRON_COVER 7
ORDOR_SQUADRON_EXTENDED 7
ORDOR_SQUADRON_FORMATION 7
PLAYER_AMMO_LESS_00 13
PLAYER_AMMO_LESS_10 13
PLAYER_AMMO_LESS_40 13
PLAYER_HP_LESS_10 13
PLAYER_HP_LESS_30 13
PLAYER_HP_LESS_50 13
RETURNED 0
SHIELD_DOWNED 61
SHIELD_DOWNED_BY_PLAYER 46
TALK 0
TM_TO_PLAYER 0
Sperkers roster: 49 distinct speakers; sizes {0: 3, 1: 84, 2: 37, 3: 4, 4: 6, 5: 1, 6: 1, 7: 2, 8: 1, 9: 2, 10: 2, 11: 1}
CharacterELLEN 19
CharacterCARL 15
CharacterGENE 15
CharacterSANDRA 13
CharacterKATANA 13
CharacterBILLY 13
CharacterANTONIUS 13
CharacterRAYMOND 12
CharacterNATALIE 10
CharacterYOJI 10
CharacterTCAFOPA 9
CharacterTCAFOPB 8
CharacterCRICHTON 8
CharacterTCAFA 8
CharacterTCAFB 8
CharacterADANPLA 6
CharacterADANPLB 6
CharacterADANPLC 6
CharacterTCAFC 6
CharacterADANOPB 5
CharacterADANOPA 5
CharacterMARGRAS 5
CharacterADANPLD 4
CharacterADANPLE 4
CharacterADANPLF 4
CharacterADANA 4
CharacterADANB 4
CharacterADANC 4
CharacterSHIPSQUIRE1 4
CharacterWAYNE 3
CharacterHOWARD 3
CharacterSHIPLADY1 3
CharacterIAN 3
CharacterRUSSELL 3
CharacterVIOLETA 3
CharacterTCAFPLA 2
CharacterTCAFPLB 2
CharacterTASKENT 2
CharacterHIGGINS 1
CharacterADANCOMMANDER 1
CharacterTCAFSUPPLY 1
CharacterVIEIRA 1
CharacterTCAFMIRANDA 1
CharacterADANETERNAL 1
CharacterADANMASSIVE 1
CharacterTCAFOLYMPUS 1
CharacterMARGRAS2 1
CharacterADANCAMAEL 1
CharacterADANMETATRON 1
distinct message ids : 2405
resolved in tables.pak SOUNDS : 2388 (99.3%)
unresolved : 17
by family: {'ADAN': 4, 'ADPL': 3, 'RHIN': 1, 'VOICE': 9}
MSG_ADAN_569
MSG_ADAN_668
MSG_ADAN_788
MSG_ADAN_789
MSG_ADPL_045
MSG_ADPL_046
MSG_ADPL_047
MSG_RHIN_341
MSG_VOICE_C_286
MSG_VOICE_D_400
MSG_VOICE_D_419
MSG_VOICE_D_443
MSG_VOICE_D_444
MSG_VOICE_D_445
MSG_VOICE_D_446
MSG_VOICE_D_447
MSG_VOICE_D_449
naming route 1 (any harvested PresetMessage_ string): 136/144
naming route 2 (UnitMessageSet_S* declarations) : 136/144
the two routes agree on the same set : True
UnitMessageSet_S* tables present: 22 of 28 (S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 S16 S24 S25 S26 S27 S28 S29)
missing: S18 S19 S20 S21 S22 S23
distinct declared PresetMessage tables: 137
CONTROL — PresetMessage_* names that hit an IDXD entry but are NOT rule tables: 137
their record-name families: {('Generic', 'Message_'): 134, ('Generic',): 3}
rule tables, by name:
0xde14f001 message\PresetMessage_ADAN_Camael.tbl
0x31092781 message\PresetMessage_ADAN_Commander.tbl
0x660be19b message\PresetMessage_ADAN_Eternal.tbl
0x4de6f4ce message\PresetMessage_ADAN_FleetAA.tbl
0x4eed1dce message\PresetMessage_ADAN_FleetAB.tbl
0x4e101fed message\PresetMessage_ADAN_FleetBA.tbl
0x4f1648ed message\PresetMessage_ADAN_FleetBB.tbl
0x4f3944e3 message\PresetMessage_ADAN_FleetCA.tbl
0x503f6de3 message\PresetMessage_ADAN_FleetCB.tbl
0x7d898a7a message\PresetMessage_ADAN_Glance_S07-2.tbl
0x733ffa0f message\PresetMessage_ADAN_Massive.tbl
0xe5b45769 message\PresetMessage_ADAN_Metatron.tbl
0x50a3be19 message\PresetMessage_ADAN_ShipA_01.tbl
0xe41a87df message\PresetMessage_ADAN_ShipA_02_S12-1.tbl
0x5197392f message\PresetMessage_ADAN_ShipB_01.tbl
0xe5767fd1 message\PresetMessage_ADAN_ShipB_01_S03-2.tbl
0x528ab445 message\PresetMessage_ADAN_ShipC_01.tbl
0xe991cee2 message\PresetMessage_ADAN_ShipC_02_S15-1.tbl
0xabb657f0 message\PresetMessage_ADAN_plAB_S01-1.tbl
0xac95b821 message\PresetMessage_ADAN_plAC_S01-1.tbl
0x494882e2 message\PresetMessage_ADAN_plA_S01-1.tbl
0xadf51dd8 message\PresetMessage_ADAN_plBC_S01-1.tbl
0x4a27e313 message\PresetMessage_ADAN_plB_S01-1.tbl
0x4b074344 message\PresetMessage_ADAN_plC_S01-1.tbl
0x1ced0fc8 message\PresetMessage_ADAN_plDEF_S15-1.tbl
0xb5cae6f3 message\PresetMessage_ADAN_plDE_S03-3.tbl
0xb6aa4724 message\PresetMessage_ADAN_plDF_S03-3.tbl
0x503eda97 message\PresetMessage_ADAN_plD_S03-3.tbl
0xb709b304 message\PresetMessage_ADAN_plEF_S03-3.tbl
0x511e3ac8 message\PresetMessage_ADAN_plE_S03-3.tbl
0x52fd94d0 message\PresetMessage_ADAN_plF_S03-3.tbl
0xa6e5b0b5 message\PresetMessage_Acropolis_01_S02-1.tbl
0xac82d3e4 message\PresetMessage_Acropolis_02_S07-1.tbl
0xa871f99c message\PresetMessage_Acropolis_03_S11-1.tbl
0x4bf26dc4 message\PresetMessage_Antonius_01_S01-2.tbl
0x4cf19786 message\PresetMessage_Antonius_02_S02-1.tbl
0x50034271 message\PresetMessage_Antonius_03_S03-3.tbl
0x536e1ae6 message\PresetMessage_Antonius_04_S07-1.tbl
0x4f5d409e message\PresetMessage_Antonius_05_S11-1.tbl
0xfad127f0 message\PresetMessage_Antonius_06_S28.tbl
0xf66565a9 message\PresetMessage_Billy_01_S01-2.tbl
0xf7648f6b message\PresetMessage_Billy_02_S02-1.tbl
0xfb76342d message\PresetMessage_Billy_03_S03-3.tbl
0xfee10ca2 message\PresetMessage_Billy_04_S07-1.tbl
0xfad0325a message\PresetMessage_Billy_05_S11-1.tbl
0xa51488ed message\PresetMessage_Billy_06_S28.tbl
0x7ce33a27 message\PresetMessage_Carl_01_S01-2.tbl
0x7de263e9 message\PresetMessage_Carl_02_S02-1.tbl
0x81f408ab message\PresetMessage_Carl_03_S03-3.tbl
0x845ee749 message\PresetMessage_Carl_04_S07-1.tbl
0x804e0d01 message\PresetMessage_Carl_05_S11-1.tbl
0x2be8d24f message\PresetMessage_Carl_06_S28.tbl
0xe9b7a641 message\PresetMessage_Ellen_01_S01-1.tbl
0xebbcf903 message\PresetMessage_Ellen_02_S02-1.tbl
0xefce9dc5 message\PresetMessage_Ellen_03_S03-3.tbl
0xf2397c63 message\PresetMessage_Ellen_04_S07-1.tbl
0xf77113b6 message\PresetMessage_Ellen_05_S09-3.tbl
0x99745ef7 message\PresetMessage_Ellen_06_S28.tbl
0x79eb166f message\PresetMessage_Gene_01_S02-1.tbl
0x7dfcbb31 message\PresetMessage_Gene_02_S03-3.tbl
0x806799cf message\PresetMessage_Gene_03_S07-1.tbl
0x859f3122 message\PresetMessage_Gene_04_S09-3.tbl
0x82d412fc message\PresetMessage_Gene_05_S15-2.tbl
0x6300daef message\PresetMessage_Howard_01_S05-2.tbl
0x640004b1 message\PresetMessage_Howard_02_S06-1.tbl
0x6361021c message\PresetMessage_Howard_03_S13-1.tbl
0x49ced33f message\PresetMessage_Katana_01_S01-1.tbl
0x4bb45c70 message\PresetMessage_Katana_02_S01-2.tbl
0x4cb38632 message\PresetMessage_Katana_03_S02-1.tbl
0x4e990f63 message\PresetMessage_Katana_04_S02-2.tbl
0x51a48b25 message\PresetMessage_Katana_05_S03-3.tbl
0x540f69c3 message\PresetMessage_Katana_06_S07-1.tbl
0x5840d816 message\PresetMessage_Katana_07_S09-2.tbl
0x5a266147 message\PresetMessage_Katana_08_S09-3.tbl
0x51975723 message\PresetMessage_Katana_09_S10-1.tbl
0x4a425a04 message\PresetMessage_Katana_10_S11-1.tbl
0x4c47acc6 message\PresetMessage_Katana_11_S12-1.tbl
0x4e4cff88 message\PresetMessage_Katana_12_S13-1.tbl
0x517844db message\PresetMessage_Katana_13_S15-1.tbl
0xf93b44ee message\PresetMessage_Katana_15_S28.tbl
0x632e5d87 message\PresetMessage_Lady1.tbl
0x64348687 message\PresetMessage_Lady2.tbl
0x653aaf87 message\PresetMessage_Lady3.tbl
0xca38072d message\PresetMessage_Margras_01_S03-3.tbl
0xcb3730ef message\PresetMessage_Margras_02_S04-2.tbl
0xc86c12c9 message\PresetMessage_Margras_03_S10-1.tbl
0xcfc8c66f message\PresetMessage_Margras_05_S14-2.tbl
0xd0c7f031 message\PresetMessage_Margras_06_S15-1.tbl
0xd532e9aa message\PresetMessage_Raymond_02_S02-1.tbl
0xd9448e6c message\PresetMessage_Raymond_03_S03-3.tbl
0x81791b91 message\PresetMessage_Raymond_04_S28.tbl
0x131f8802 message\PresetMessage_Raymond_S01-1.tbl
0x53b2e415 message\PresetMessage_Sandra_01_S01-2.tbl
0x54b20dd7 message\PresetMessage_Sandra_02_S02-1.tbl
0x58c3b299 message\PresetMessage_Sandra_03_S03-3.tbl
0x5b2e9137 message\PresetMessage_Sandra_04_S07-1.tbl
0x571db6ef message\PresetMessage_Sandra_05_S11-1.tbl
0x02351472 message\PresetMessage_Sandra_06_S28.tbl
0x52223719 message\PresetMessage_Squire1.tbl
0x53286019 message\PresetMessage_Squire2.tbl
0x542e8919 message\PresetMessage_Squire3.tbl
0x5534b219 message\PresetMessage_Squire4.tbl
0x9bfa033e message\PresetMessage_TCAF_17thFleetAA.tbl
0x9c003267 message\PresetMessage_TCAF_17thFleetAB.tbl
0x9c232e5d message\PresetMessage_TCAF_17thFleetBA.tbl
0xf021197c message\PresetMessage_TCAF_17thFleetShipC.tbl
0x64ecd655 message\PresetMessage_TCAF_AcropolisGuard.tbl
0x4f33ea2e message\PresetMessage_TCAF_Caliban.tbl
0x57a53d3b message\PresetMessage_TCAF_FleetAA.tbl
0x58ab663b message\PresetMessage_TCAF_FleetAB.tbl
0x58ce6231 message\PresetMessage_TCAF_FleetBA.tbl
0x59f78727 message\PresetMessage_TCAF_FleetCA.tbl
0x5afdb027 message\PresetMessage_TCAF_FleetCB.tbl
0xa6b0cfde message\PresetMessage_TCAF_Janus.tbl
0x616c4182 message\PresetMessage_TCAF_Miranda.tbl
0x9ec12cb7 message\PresetMessage_TCAF_Olympus.tbl
0x6a18ba6a message\PresetMessage_TCAF_Pandora.tbl
0x9aafd76a message\PresetMessage_TCAF_ShipA.tbl
0x9bb6006a message\PresetMessage_TCAF_ShipB.tbl
0x9cbc296a message\PresetMessage_TCAF_ShipC.tbl
0x326328f2 message\PresetMessage_TCAF_Supply.tbl
0x22beec7a message\PresetMessage_TCAF_Vinson.tbl
0xb704e242 message\PresetMessage_TCAF_plAB_S02-2.tbl
0x554cc1d2 message\PresetMessage_TCAF_plA_S02-2.tbl
0x562c2203 message\PresetMessage_TCAF_plB_S02-2.tbl
0xd74c69b3 message\PresetMessage_Taskent_01_S03-3.tbl
0xd84b9375 message\PresetMessage_Taskent_02_S04-2.tbl
0xd4edb4dc message\PresetMessage_Violeta_01_S08-1.tbl
0xd7f9309e message\PresetMessage_Violeta_02_S09-2.tbl
0xd0964834 message\PresetMessage_Violeta_03_S11-1.tbl
0x027f9fba message\PresetMessage_Wayne_01_S05-2.tbl
0x037ec97c message\PresetMessage_Wayne_02_S06-1.tbl
0x02dfc6e7 message\PresetMessage_Wayne_03_S13-1.tbl
0x9a44099c message\PresetMessage_Yoji_01_S06-2.tbl
0x9b43335e message\PresetMessage_Yoji_02_S07-1.tbl
0xa07acab1 message\PresetMessage_Yoji_03_S09-3.tbl
0x5483c09d <unnamed>
0x59d48b31 <unnamed>
0x9d29575d <unnamed>
0x9d4c5353 <unnamed>
0x9e527c53 <unnamed>
0xcde33d3e <unnamed>
0xee14c77c <unnamed>
0xef1af07c <unnamed>
unnamed rule tables: 8

View File

@@ -0,0 +1,167 @@
# The reactive-chatter rule table
**✅ Settled 2026-08-27** (static; regenerator
`tools/re-capture/preset_messages.py`, artefact
[`data/preset-messages.txt`](../data/preset-messages.txt)).
The corpus already knew *that* `PresetMessage_*` is reactive combat chatter —
[`ixud-localised-text.md`](ixud-localised-text.md) names the IXUD family
("the bulk: reactive combat chatter keyed by speaker class") and
[`mission-phase-deployment.md`](../mission-phase-deployment.md) found the link
that reaches it (`message\UnitMessageSet_S<NN>.tbl` gives every crew a
`PresetMessage_Phase1/2/3`). What neither says is **what is inside the table**
which events exist, what governs when a line fires, and how a line reaches a
recording. That is this document.
## Two files per set
A chatter set is a **pair** of IDXD objects in each `dat/GP_MAIN_GAME_<lang>.pak`:
| name | role |
|---|---|
| `message\PresetMessage_<who>.tbl` | the **rule** table — this document |
| `message\PresetMessage_<who>_msg.tbl` | the **message** table |
The `_msg` half is *not* new: it is exactly the record layout
[`cutscene-message-table.md`](cutscene-message-table.md) settled for
`MSG_DEMO_*` — a `Generic` count record plus `Message_NNN` records with `ID` /
`PageCount` and 9 positional fields per page. What that document does not say is
that the same layout carries **137 more objects per language pack** for
in-mission chatter, against the 32 cutscene ones it counted. The control run
confirms the split cleanly: of the 273 `PresetMessage_*` names that hit an IDXD
entry, **136 are rule tables and 137 are `Generic`+`Message_NNN` message
tables** (3 of those are `Generic`-only, i.e. empty).
## The rule table
**144 per language pack, 864 across the six `GP_MAIN_GAME_<lang>.pak`** — one
identical count in each, and `ORDOR_SQUADRON_EXTENDED` (the misspelling is the
game's, see below) is the largest single record name on the disc for exactly
that reason.
Every one of the 144 has the **same 65 records**: 64 event records plus a
`Sperkers` (sic) roster. One record-name tuple, no variants.
### Event records
All 9 216 event records (144 × 64) share **one** named-field schema, with no
exceptions:
```
EffectiveTime Interval Priority Probability MessageCount
IntervalFluctuation Pattern
```
After the seven named fields come the record's positional payload —
[a record's unnamed positional fields are its payload] — in **pairs**:
(message id, Yes/No) e.g. ('MSG_BIRD_020', 'No')
`MessageCount` is the number of pairs, and that identity is **exact**:
`MessageCount · 2 == positional-field count` in **9 216 of 9 216** records, zero
mismatches. That is what pins the pairing. The second element of each pair is
`No` 8 940 times and `Yes` 388 times; its meaning is not settled.
### The 64 events
The full census with per-event table counts is in the artefact. The shape of
that census is itself informative:
* **Player-facing events are voiced only by the wingman tables.** Every
`LOCKON_1..12`, `LOCKON_UP`, `LOCKON_DOWN`, `PLAYER_HP_LESS_10/30/50` and
`PLAYER_AMMO_LESS_00/10/40` record carries lines in **exactly 13** of the 144
tables — the same 13 as `ORDER_WINGMAN_{FORMATION,ATTACK,COVER,EXTENDED}`.
* The squad/squadron order events carry lines in **7** tables each.
* Generic combat events are near-universal: `DAMAGED_BY_PLAYER_GREATER_50` 128,
`DAMAGED` 124, `HP_LESS_10` and `HP_LESS_50` 121 each.
* **Five events are declared everywhere and populated nowhere** —
`DAMAGED_BY_PLAYER_50_30`, `HP_LESS_30`, `RETURNED`, `TALK`, `TM_TO_PLAYER`
have `MessageCount 0` in all 144 tables. They are slots the shipped data never
uses.
Note the near-miss pairs that are *not* redundant: `HP_LESS_*` (the speaker's
own hull) versus `PLAYER_HP_LESS_*`, and `AVOIDED_BY_PLAYER` versus
`AVOIDED_PLAYER_ATTACK`. The `_PLAYER` half of each pair is the smaller
population.
### `Sperkers`
The last record is a roster of speaker names as **field names** with empty
values — `CharacterELLEN`, `CharacterADANCAMAEL`, … **49 distinct speakers**
across the 144 tables. Most tables name one speaker (84 of 144); the rest name
211, and three name none.
## The join to audio is the settled cue table
The pair's first element is a message id, and it resolves through the cue index
[`sound-cue-table.md`](sound-cue-table.md) already documents — `MSG_` becomes
`VOICE_`, then `SOUNDS` in `dat/tables.pak` gives the numeric id and `FILES` the
`.slb` bank.
**2 388 of 2 405 distinct message ids resolve (99.3 %).** The 17 that do not
are characterised, not swept up: 8 are ordinary four-letter-family ids
(`MSG_ADAN_569/668/788/789`, `MSG_ADPL_045/046/047`, `MSG_RHIN_341`) and 9 are
`MSG_VOICE_*`, seven of them the consecutive run `MSG_VOICE_D_443``_449`. A
consecutive run with no recording reads as content cut late. All 17 are listed
in the artefact.
⚠️ **The wrinkle in that doc is real and I walked into it.** Rewriting `MSG_` to
`VOICE_` unconditionally gives `VOICE_VOICE_D_443`, which resolved only 2 353 of
2 405 and would have been written up as "52 lines with no recording", with 44 of
them a naming artefact. `sound-cue-table.md` states the exception explicitly —
a name that already carries `VOICE_` keeps the one it has — and applying it
moves the count to 2 388. Recorded here because the same trap is one line of
code away in any port.
## Naming, by two independent routes that agree
The rule tables are pak entries keyed by `name_hash`, so they had to be named
before any of this could be read.
1. **Harvested strings** — every `PresetMessage_*` string appearing anywhere in
any IDXD object on the disc, hashed under the `message\` prefix: **136/144**.
2. **Declarations** — the `PresetMessage_Phase1/2/3` values of the 22
`message\UnitMessageSet_S<NN>.tbl` tables: **136/144**.
The two routes name **the same set** (verified as a set identity, not a matching
count). Names are of the form
`PresetMessage_<who>[_<NN>]_S<stage>-<phase>.tbl`, e.g.
`PresetMessage_Ellen_03_S03-3.tbl`, `PresetMessage_ADAN_Camael.tbl` — so a set is
scoped to a character *and* a stage-phase, which is what makes 144 of them.
### Residual, characterised
* **8 rule tables stay unnamed** and — this is the point — they are unnamed by
*both* routes: nothing on the disc declares them. Their hashes are in the
artefact.
* `UnitMessageSet_S<NN>.tbl` exists for **22 of the 28 shipped stages**. The six
missing are exactly **S18S23, the tutorials**, which is the same set that has
no `AIParams_SNN.tbl` ([`challenge-mission-gate.md`](challenge-mission-gate.md)).
So the 8 undeclared tables are plausibly tutorial chatter, but that is a
reading — no tutorial `UnitMessageSet` exists to confirm it.
* The 22 stage tables declare **137** distinct `PresetMessage` sets against 136
rule tables resolved, so one declared set has no rule table under the
`message\` prefix.
## ✅ Correction to `squadron-orders.md`
That document renders the voice-line enum at `0x820AEEB0` as
`ORDER_{WINGMAN,SQUAD,SQUADRON}_{FORMATION,ATTACK,COVER,EXTENDED}`. The
executable's own strings are **not** uniform: the WINGMAN and SQUAD names are
`ORDER_`, and all four SQUADRON names are misspelled **`ORDOR_`**. The disc data
carries the identical misspelling, which is how the two sides were joined.
That document's 🔴 warning — that this enum is a UI/comms axis and is **not** the
order-class enum — is **confirmed and now explained**: all twelve names are
record names in this chatter rule table, i.e. they are the twelve *events*
"a squadron order was issued", each with its own lines, priority and interval.
They are triggers for barks, not order types.
## 🟡 Not settled
* What `EffectiveTime`, `Interval`, `IntervalFluctuation`, `Priority`,
`Probability` and `Pattern` mean numerically — they are read here as a schema,
not measured against the running game.
* The `Yes`/`No` second element of each pair.
* Which of the 49 speakers is a wingman — the "13 tables" partition above is a
count, not a verified roster.

View File

@@ -57,11 +57,21 @@ as 🟡 rather than levelled up to match the other three.
## 🔴 A different enum that is NOT this
`sub_82320B48` selects a voice line from
`ORDER_{WINGMAN,SQUAD,SQUADRON}_{FORMATION,ATTACK,COVER,EXTENDED}`
(`0x820AEEB0`…). The names are tempting — ATTACK and COVER look like they should
map onto the order classes — but there is **no evidence** they index the order
types, and it is a UI/comms axis. Not connected; do not conflate them.
`sub_82320B48` selects a voice line from twelve strings at `0x820AEEB0`…. Note
the spelling, which is the game's own and matters because it is the join key:
the WINGMAN and SQUAD names are `ORDER_`, and **all four SQUADRON names are
misspelled `ORDOR_`** — `ORDOR_SQUADRON_{FORMATION,ATTACK,COVER,EXTENDED}`. (An
earlier revision of this document rendered all twelve as `ORDER_`.)
The names are tempting — ATTACK and COVER look like they should map onto the
order classes — but there is **no evidence** they index the order types, and it
is a UI/comms axis. Not connected; do not conflate them.
**✅ Settled 2026-08-27, and the warning above holds.** All twelve are record
names in the reactive-chatter rule table, carrying the same misspelling on the
data side — see [`preset-message-rules.md`](preset-message-rules.md). They are
the twelve *events* "a squadron order was issued", each with its own lines,
priority and interval. Triggers for barks, not order types.
## 🟡 Not settled