New doc docs/re/structures/asteroid-fields.md, indexed.
Half the chain was already in the corpus: stage-definition-table and
stage-mission-tables record the per-phase AsteroidDefinition naming a .tbl,
and unit-datasheet-static partitions Generic and finds 10 per pack whose only
field is {EnumAsteroidGroup}, "an asteroid-group file". Neither says what is
inside them.
The table: 10 objects per pack x 6 packs = 60, 384 AsteroidGroup_* records,
4 or 7 groups per object. Every record carries exactly three fields, all 384,
no partials - AsteroidModelName (28 distinct; mob_n050..n056 x24 each,
mob_n040..n043 x18), AsteroidFrameName (64 distinct, Frame_S<NN>[_pN]_
Asteroid_NN, the same names regn-map-grid reports the Route tables showing),
and EnumAsteroid (37 distinct, 1..588, 6633 per pack summed).
Enum<Thing> is a COUNT; Enumerate<Thing> names a TABLE. EnumAsteroidGroup
equals its object's group count in 54 of 60 and EnumAsteroid is a plain
integer - the opposite of the Enumerate* join rule. The -erate is the
difference. Count-style fields still are not safe: the 6 failures are ONE
object repeated per language pack, declaring 4 while holding 7.
The tenth object is unreferenced and it is the one that miscounts. Joining by
frame prefix, nine objects match the nine AsteroidDefinition values one to
one; the tenth carries Frame_Alpha_S01_Asteroid, Frame_Alpha_S01_Haze and
Frame_TAlpha_S01_Asteroid and is named by nothing.
S28 has an asteroid VOLUME but no asteroid DEFINITION: mcol-collision lists
nine _AsteroidVolume_wp meshes (…, S28_p1); the nine AsteroidDefinition values
are those eight plus test_s8p1. Eight shared, one different each way.
Not settled: what EnumAsteroid counts of; why S28_p1 has a volume and no
definition. The name->object join did not reproduce by hash under name_hash,
mod 0x00FFF9D7, or a 24-bit mask - the join used is by frame prefix.
All fifteen artefacts byte-identical.
87 lines
4.4 KiB
Markdown
87 lines
4.4 KiB
Markdown
# The asteroid-field tables (`AsteroidGroup_00N`)
|
||
|
||
**Status: ✅ decoded statically, 2026-08-28.** Every number below is an exact
|
||
disc census over all 41 `.pak` archives using the corpus reader.
|
||
|
||
## Where it sits in the chain
|
||
|
||
[[stage-definition-table]] and [[stage-mission-tables]] already record that a
|
||
stage's `Phase_N` block carries an **`AsteroidDefinition`** field naming a `.tbl`
|
||
(`test_s8p1_asteroid.tbl` in the `_Test` template, `""` in most phases), and
|
||
[[unit-datasheet-static]] already partitions the `Generic` records and finds
|
||
**10 per pack whose only field is `{EnumAsteroidGroup}` — "an asteroid-group
|
||
file"**. What neither says is what is *inside* those ten files.
|
||
|
||
```
|
||
Stage_SNN . Phase_N . AsteroidDefinition = "S04_asteroid.tbl"
|
||
└── that object: Generic . EnumAsteroidGroup = "7"
|
||
AsteroidGroup_000 … AsteroidGroup_006
|
||
AsteroidModelName = mob_n050
|
||
AsteroidFrameName = Frame_S04_Asteroid_01
|
||
EnumAsteroid = 39
|
||
```
|
||
|
||
## ✅ The table
|
||
|
||
**10 objects per pack × 6 `GP_MAIN_GAME_<lang>` packs = 60**, holding **384
|
||
`AsteroidGroup_*` records** in total. Each object has **4 or 7** groups (12
|
||
objects with 4, 48 with 7). Every group record carries exactly **three** fields,
|
||
present on all 384 with no partials:
|
||
|
||
| field | distinct values | what it is |
|
||
|---|---:|---|
|
||
| `AsteroidModelName` | 28 | the mesh — `mob_n050`…`mob_n056` (24 uses each) and `mob_n040`…`mob_n043` (18 each) |
|
||
| `AsteroidFrameName` | 64 | `Frame_S<NN>[_pN]_Asteroid_NN` — the placement frame |
|
||
| `EnumAsteroid` | 37 | a **count**, 1 … 588; 6 633 asteroids per pack summed |
|
||
|
||
`Frame_S<NN>_Asteroid` is the same name [[regn-map-grid]] reports the mission
|
||
`Route` tables showing independently — the frame is the join to the map data.
|
||
|
||
## ✅ `Enum<Thing>` is a count; `Enumerate<Thing>` names a table
|
||
|
||
`EnumAsteroidGroup` equals the number of `AsteroidGroup_*` records in its own
|
||
object in **54 of 60** objects, and `EnumAsteroid` is a plain integer. That is
|
||
the opposite of the `Enumerate*` convention, where the value is a child table's
|
||
file name. **The `-erate` is the difference**, and it is worth checking the
|
||
spelling before assuming which kind a field is.
|
||
|
||
⚠️ `Count`-style fields still are not safe: the **6 failures are one object,
|
||
repeated once per language pack** — it declares `4` and contains `7`.
|
||
|
||
## 🔑 The tenth object is unreferenced, and it is the one that miscounts
|
||
|
||
Joining the ten objects to the nine `AsteroidDefinition` values by frame prefix:
|
||
|
||
| object's frame prefix | groups | declared | named by |
|
||
|---|---:|---:|---|
|
||
| `Frame_S01_Asteroid` | 4 | 4 | `S01_asteroid.tbl` |
|
||
| `Frame_S04/S05/S13/S14_p1/S14_p2/S08_p1/S08_p2_Asteroid` | 7 | 7 | the matching `SNN[_pN]_asteroid.tbl` |
|
||
| `Frame_Test_Asteroid` | 4 | 4 | `test_s8p1_asteroid.tbl` |
|
||
| **`Frame_Alpha_S01_Asteroid` + `Frame_Alpha_S01_Haze` + `Frame_TAlpha_S01_Asteroid`** | **7** | **4** | **nothing** |
|
||
|
||
Nine `AsteroidDefinition` names, nine matching objects, and a **tenth that no
|
||
phase names** — an `Alpha` Stage-01 variant with its own `Haze` frames and a
|
||
`TAlpha` set. It is also the only object whose declared count is wrong, which is
|
||
what an abandoned table looks like.
|
||
|
||
## 🔑 S28 has an asteroid *volume* but no asteroid *definition*
|
||
|
||
[[mcol-collision]] lists **nine** `_AsteroidVolume_wp` collision meshes: S01,
|
||
S04, S05, S08_p1, S08_p2, S13, S14_p1, S14_p2 and **S28_p1**. The nine
|
||
`AsteroidDefinition` values are the same eight stages plus **`test_s8p1`**. So
|
||
the two sets share eight and differ by one each: **`S28_p1` has the collision
|
||
volume for an asteroid field but no table saying which rocks to scatter in it**,
|
||
while `test_s8p1` has a table with no volume of its own.
|
||
|
||
## 🟡 Not settled
|
||
|
||
* What `EnumAsteroid` counts *of* — instances per frame is the obvious reading
|
||
and the 1…588 range fits, but it is untested.
|
||
* Why `S28_p1` has a volume and no definition (S28 is the challenge mission that
|
||
alone flies `rou_f004`, see [[stage-numbering-and-player-craft]]).
|
||
* 🔴 **The name→object join did not reproduce by hash.** `AsteroidDefinition`
|
||
values do not map to their objects' pak entry keys under `name_hash`, nor under
|
||
that key reduced `mod 0x00FFF9D7` or masked to 24 bits — the join above is by
|
||
frame prefix, which is direct. Either these keys are not name hashes or
|
||
[[archive-naming]]'s resolver differs from `unitgroup.name_hash`; not chased.
|