This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/structures/preset-message-rules.md
Claude (auto) 2c2af7ad78 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
2026-08-27 16:07:17 +00:00

168 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
2–11, 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 **S18–S23, 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.