From 122a05735d2cbf676afd4a2af4e7d033d5dda87a Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Fri, 28 Aug 2026 09:28:39 +0000 Subject: [PATCH] re: _e/_f on an effect name is the binding unit's FACTION (94 of 94) Chasing the 17 unlocated eff_l### turned up their shape first: they come in _e/_f PAIRS - eff_l101_e + eff_l101_f, and the same for l102, l104, l105, l106, l201, plus _e-only l010/l011/l107/l108 and _f-only l002. Partitioning every eff__ binding by the ID letter of the OWNING unit (one GP_MAIN_GAME_* pak = one user): effect _e effect _f UN_e### 33 0 UN_f### 0 61 94 of 94 agree and both off-diagonal cells are empty. The control reads the factions straight off the IDs: UN_e### -> ADAN (42 objects), UN_f### -> TCAF (26), UN_n### -> TTRL (2, tutorial, binding neither). So an effect ending _e belongs to an ADAN ship and one ending _f to a TCAF ship - the same visual is authored twice, once per faction, which is exactly why eff_l### arrives in pairs. What the 34 unlocated ARE is now also clear, even though where they live is not. They are one job, not a scatter: Generic binds 32 of the 34, Explosion 19, Shell 9, Level_0 and Weapon 2 each. The binder fields rank LowerHPFxModel 252, HitFxModel 144, then JetFxModel_00N and AfterBurnerFxModel_00N. They sit in the six GP_MAIN_GAME_* paks at 130 bindings each plus 32 in DefTables.pak. Since LowerHPFxModel is the damaged-ship effect, the residual is largely the per-faction battle-damage and hit visuals. None of the 34 is a record name and only one is a field name, so they are asset references. Stated plainly: they remain unlocated AS ASSETS. Knowing the family and its naming law does not say where the geometry lives - the .xpr route is exhausted for them and the parsed pak payloads hold references, not meshes. Also fixes a defect in the artefact shipped last commit. effect-homes.txt came back with two equal-count lines swapped: Counter.most_common() breaks ties by insertion order, so the package listing was not deterministic. Now sorted by (-count, name) and verified to regenerate byte-identical twice running. This is the corpus's own rule - any map built by iterating a set or Counter needs sorted() - and the new tool had violated it. The other sixteen artefacts are byte-identical; effect-homes.txt changes only in the tie-break ordering of the five 1-count rows, with every line pairing. --- docs/re/BACKLOG.md | 28 +++++++++++++ docs/re/data/effect-homes.txt | 6 +-- .../structures/unit-substructure-records.md | 41 +++++++++++++++++++ tools/re-capture/effect_homes.py | 2 +- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index d77bf2d7..4c1fdb74 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -6735,3 +6735,31 @@ population a residual is measured against.** New artefact: `tools/re-capture/effect_homes.py` → `docs/re/data/effect-homes.txt` (lists all 34 by name). + +--- + +## ✅ 2026-08-28 — `_e`/`_f` on an effect name is the binding unit's FACTION + +Item (a). Chasing the 17 unlocated `eff_l###` showed they come in **`_e`/`_f` +pairs**. Partitioning every `eff__` binding by the ID letter +of the owning unit (one `GP_MAIN_GAME_*` pak = one user): + +| | effect `_e` | effect `_f` | +|---|---|---| +| **`UN_e###`** | **33** | 0 | +| **`UN_f###`** | 0 | **61** | + +**94 of 94, both off-diagonal cells empty.** The control reads the factions off +the IDs: `UN_e### → ADAN` (42 objects), `UN_f### → TCAF` (26), `UN_n### → TTRL` +(2, binding neither). 🔑 **The same effect is authored twice, once per faction** — +which is exactly why `eff_l###` arrives in pairs. + +🟡 **What the 34 are**: `Generic` binds 32 of them, `Explosion` 19, `Shell` 9, +`Level_0`/`Weapon` 2 each; binder fields rank **`LowerHPFxModel` 252**, +`HitFxModel` 144, then `JetFxModel_00N`/`AfterBurnerFxModel_00N`. So the residual +is largely **per-faction battle-damage and hit visuals**. None is a record name; +one is a field name. + +⚠️ **Still unlocated as assets** — knowing the family and its naming law does not +say where the geometry lives. The `.xpr` route is exhausted and the parsed pak +payloads hold references, not meshes. ❔ Open: which package (if any) ships them. diff --git a/docs/re/data/effect-homes.txt b/docs/re/data/effect-homes.txt index 06c5c98c..35b8fd86 100644 --- a/docs/re/data/effect-homes.txt +++ b/docs/re/data/effect-homes.txt @@ -6,11 +6,11 @@ resolved, by package: Base.xpr 53 ptc_pack.xpr 46 Stage_S28.xpr 2 - rou_f001_wep_28.xpr 1 - rou_f001_wep_27.xpr 1 rou_f001_wep_12.xpr 1 - rou_f001_wep_82.xpr 1 + rou_f001_wep_27.xpr 1 + rou_f001_wep_28.xpr 1 rou_f001_wep_59.xpr 1 + rou_f001_wep_82.xpr 1 by digit-width: 3-digit: 80 resolved of 110 diff --git a/docs/re/structures/unit-substructure-records.md b/docs/re/structures/unit-substructure-records.md index 170aea64..c11d99e4 100644 --- a/docs/re/structures/unit-substructure-records.md +++ b/docs/re/structures/unit-substructure-records.md @@ -361,3 +361,44 @@ is measured against. Regenerate with `tools/re-capture/effect_homes.py` → [`docs/re/data/effect-homes.txt`](../data/effect-homes.txt), which lists all 34 by name. + +### ✅ `_e` / `_f` on an effect name is the FACTION of the unit that binds it + +Chasing the 17 unlocated `eff_l###` turned up their shape: they come in +**`_e`/`_f` pairs** — `eff_l101_e` + `eff_l101_f`, and the same for `l102`, +`l104`, `l105`, `l106`, `l201`, plus `_e`-only `l010`, `l011`, `l107`, `l108` +and `_f`-only `l002`. + +Partitioning every `eff__` binding by the **ID letter of the +owning unit** (one `GP_MAIN_GAME_*` pak = one user): + +| | effect `_e` | effect `_f` | +|---|---|---| +| **`UN_e###`** | **33** | 0 | +| **`UN_f###`** | 0 | **61** | + +**94 of 94 agree; both off-diagonal cells are empty.** And the unit IDs name the +factions themselves — the control reads `UN_e### → ADAN` (42 objects), +`UN_f### → TCAF` (26), `UN_n### → TTRL` (2, tutorial, binding neither). + +🔑 So an effect ending `_e` belongs to an **ADAN** ship and one ending `_f` to a +**TCAF** ship: the same visual effect is authored twice, once per faction. That +is why the `eff_l###` family arrives in pairs. + +### 🟡 What binds the 34 unlocated, and what they are + +The 34 are not scattered — they are one job. `Generic` binds 32 of the 34, +`Explosion` 19, `Shell` 9, and two apiece for `Level_0` and `Weapon`. The +binder fields rank **`LowerHPFxModel` 252**, `HitFxModel` 144, then +`JetFxModel_00N` and `AfterBurnerFxModel_00N` at 48/30 each. They sit in the six +`GP_MAIN_GAME_*` paks (130 bindings each — one user) plus 32 in `DefTables.pak`. + +`LowerHPFxModel` is the damaged-ship effect, so **the unlocated set is largely +the per-faction battle-damage and hit visuals**. None of the 34 resolves as a +record name and only one as a field name, so they are asset references, not +records. + +⚠️ **Still unlocated as assets.** Knowing what they are for does not say where +their geometry lives; the `.xpr` route is exhausted for them and the parsed pak +payloads hold references, not meshes. Worth stating plainly: this iteration +identified the family and its naming law, not the missing package. diff --git a/tools/re-capture/effect_homes.py b/tools/re-capture/effect_homes.py index 5ad95bf2..5c1aa528 100644 --- a/tools/re-capture/effect_homes.py +++ b/tools/re-capture/effect_homes.py @@ -55,7 +55,7 @@ def main(): for f in home[n]: per[f] += 1 print('resolved, by package:') - for f, k in per.most_common(): + for f, k in sorted(per.items(), key=lambda kv: (-kv[1], kv[0])): print(' %-26s %d' % (f, k)) print() print('by digit-width:')