diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 7fdc8f6a..3e192a34 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -827,6 +827,35 @@ unknown, what evidence exists, and what the first step would be. Move an item in field; the stat keys in records not opened here (`MegaTons`, `BulletLimit`, `CrewCount`, `HP_CLASS`); why the roster lists 59 of 131. +* 🟡 **(2026-08-27) WHERE `.prt` SCREEN PARTS LIVE — and the five mission + banners are a real exception.** + [structures/mission-script-manifest](structures/mission-script-manifest.md), + artefact `data/prt-parts.txt`, regenerator `tools/re-capture/prt_parts.py`. + Read first, as the rule now requires: `ui-prm-primitives.md`, + `ui-rat-layout.md`, `ui-screen-runtime.md` — they own the `.prt`/RATC/T8aD + stack but describe element names INSIDE bundles, not where parts live. + ✅ **A `.prt` IS a pak entry, under a LANGUAGE directory.** Of **376** distinct + `.prt` names referenced on the disc, **241 resolve** as archive entries — 220 + under `eng\` and `jpn\`, 38 under each of the other four. `prbase.prt` + resolves under all six; `palogo1.prt` under two. + ❌ **All five `pgmsg_*.prt` resolve under NOTHING**, across 15 prefixes that + include every language dir — so this is not the missing-prefix mistake again. + 🟡 **A lead, refuted by its own control.** Four of the five have a same-stem + **`_sub.rat` sub-bundle** inside every per-language 2D pak + (`pgmsg_{start,end,failed,restart}_sub.rat`, 6 archives each); **`pgmsg_update` + has none.** Tempting as "the parts live as RATC sub-bundles" — but **only 4 of + 376 `.prt` stems have a `_sub.rat`** (the other 7 belong to `GP_BUNK`, + `GP_SYSTEM`, `GP_MISSION_LOG`), and `prbase.prt`, which does ship as an entry, + has none. Not the container convention. **Not adopted.** + 🟡 Still open: where the five actually are. What is settled is that they are + not pak entries while 241 siblings are, and that `pgmsg_update` is the odd one + out even among the five. + ⚠️ Method note: an intermediate pass of this iteration nearly reported "the + five appear only in the manifest" — wrong, because the token census was + truncated by a `[:20]` slice and the RATC hits were `pgmsg_start_sub.rat`, a + LONGER token. **A truncated listing is not a distribution**, and a prefix match + is not an exact match. + * ❌ **(2026-08-27) CORRECTION — the mission dialogue table was ALREADY IN THE CORPUS, and my headline negative was a FALSE NEGATIVE.** [structures/mission-script-manifest](structures/mission-script-manifest.md), diff --git a/docs/re/data/prt-parts.txt b/docs/re/data/prt-parts.txt new file mode 100644 index 00000000..8f9fe3f0 --- /dev/null +++ b/docs/re/data/prt-parts.txt @@ -0,0 +1,39 @@ +# Where `.prt` screen parts live +# Regenerate: python3 tools/re-capture/prt_parts.py +# See docs/re/structures/mission-script-manifest.md + +## `.prt` IS a pak entry name -- under a LANGUAGE directory + distinct .prt names referenced anywhere : 376 + resolving as a pak entry : 241 + prefix 'eng\\' 220 + prefix 'jpn\\' 220 + prefix 'fra\\' 38 + prefix 'deu\\' 38 + prefix 'ita\\' 38 + prefix 'esp\\' 38 + prefix '' 21 + +## the five mission-banner parts + pgmsg_start.prt resolves under: NOTHING + pgmsg_end.prt resolves under: NOTHING + pgmsg_update.prt resolves under: NOTHING + pgmsg_failed.prt resolves under: NOTHING + pgmsg_restart.prt resolves under: NOTHING + prbase.prt resolves under: ['eng\\', 'jpn\\', 'fra\\', 'deu\\', 'ita\\', 'esp\\'] + palogo1.prt resolves under: ['eng\\', 'jpn\\'] + +## `_sub.rat` sub-bundles inside RATC + distinct _sub.rat names: 11 + pgmsg_end_sub.rat in 6 archives ['GP_MAIN_GAME_D2D.pak', 'GP_MAIN_GAME_E2D.pak'] + pgmsg_failed_sub.rat in 6 archives ['GP_MAIN_GAME_D2D.pak', 'GP_MAIN_GAME_E2D.pak'] + pgmsg_restart_sub.rat in 6 archives ['GP_MAIN_GAME_D2D.pak', 'GP_MAIN_GAME_E2D.pak'] + pgmsg_start_sub.rat in 6 archives ['GP_MAIN_GAME_D2D.pak', 'GP_MAIN_GAME_E2D.pak'] + piface_sub.rat in 1 archives ['GP_MISSION_LOG.pak'] + pjeff03_sub.rat in 2 archives ['GP_BUNK.pak', 'GP_DEBRIEFING_PILOTLOG.pak'] + pjex_eff07_sub.rat in 4 archives ['GP_BUNK.pak', 'GP_DEBRIEFING_PILOTLOG.pak'] + pjex_eff08_sub.rat in 4 archives ['GP_BUNK.pak', 'GP_DEBRIEFING_PILOTLOG.pak'] + pqeff20_sub.rat in 1 archives ['GP_SYSTEM.pak'] + pqeff21_sub.rat in 1 archives ['GP_SYSTEM.pak'] + pqeff22_sub.rat in 1 archives ['GP_SYSTEM.pak'] + CONTROL .prt stems that have a _sub.rat: 4 / 376 -- so this is NOT the general + container convention; `prbase` has a .prt entry and no _sub.rat. diff --git a/docs/re/structures/mission-script-manifest.md b/docs/re/structures/mission-script-manifest.md index 69161446..36a293fe 100644 --- a/docs/re/structures/mission-script-manifest.md +++ b/docs/re/structures/mission-script-manifest.md @@ -97,8 +97,42 @@ read, and closes them the same way. in [sound-pak-contents](sound-pak-contents.md); worth repeating because it doubles the apparent hit count of any prefix sweep. +## 🔎 Where `.prt` parts live — and why these five are the exception + +Followed up the next iteration. Read first: `ui-prm-primitives.md`, +`ui-rat-layout.md`, `ui-screen-runtime.md` — they own the `.prt`/RATC/T8aD UI +stack and describe element names *inside* bundles, not where the parts live. +Artefact `../data/prt-parts.txt`, regenerator `tools/re-capture/prt_parts.py`. + +**A `.prt` IS a pak entry — under a LANGUAGE directory.** Of the **376** distinct +`.prt` names referenced anywhere on the disc, **241 resolve** as an archive +entry: 220 under `eng\` and `jpn\`, 38 under each of the other four. My earlier +sweep had `eng\`…`esp\` in the list, so this is not the missing-prefix mistake +again — the five simply are not there. + +| name | resolves under | +|---|---| +| `prbase.prt` | all six language dirs | +| `palogo1.prt` | `eng\`, `jpn\` | +| **all five `pgmsg_*.prt`** | **nothing, under any of 15 prefixes** | + +🟡 **A partial lead, and its own refutation.** Four of the five have a +same-stem **`_sub.rat` sub-bundle** inside every per-language *2D* pak +(`pgmsg_start_sub.rat`, `_end_`, `_failed_`, `_restart_` — 6 archives each); +**`pgmsg_update` has none**. Tempting as "the parts live as RATC sub-bundles", +but the control kills the generalisation: **only 4 of 376 `.prt` stems have a +`_sub.rat` at all** (the other 7 belong to `GP_BUNK`, `GP_SYSTEM`, +`GP_MISSION_LOG`), and `prbase.prt` — which *does* ship as an entry — has no +`_sub.rat`. So `_sub.rat` is not the container convention; it is something these +four happen to have. + +**Still not settled**: where the five mission-banner parts actually are. What is +now settled is that they are **not** pak entries while 241 of their siblings are, +and that `pgmsg_update` is the odd one out even among them. + ## 🟡 Not settled -* Where the five `pgmsg_*.prt` screen parts live. +* Where the five `pgmsg_*.prt` screen parts live — see the section above for + how far that got. * `dat\GP_TEST\` is named by the manifest and is not on the disc — a debug path left in, not a missing asset. Not chased. diff --git a/tools/re-capture/prt_parts.py b/tools/re-capture/prt_parts.py new file mode 100644 index 00000000..882f3c27 --- /dev/null +++ b/tools/re-capture/prt_parts.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +"""Where `.prt` screen parts live, and why the five mission banners do not. + +Regenerates docs/re/data/prt-parts.txt. +""" +import sys, os, glob, re, collections + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +import unitgroup as U +from unit_substructures import pak_entries + +FIVE = ['pgmsg_start.prt', 'pgmsg_end.prt', 'pgmsg_update.prt', + 'pgmsg_failed.prt', 'pgmsg_restart.prt'] +PRE = ['', 'Stage\\', 'stage\\', 'message\\', 'language\\', '2d\\', 'ui\\', 'prt\\', + 'view\\'] + [l + '\\' for l in ('eng', 'jpn', 'fra', 'deu', 'ita', 'esp')] + +def main(): + H = collections.defaultdict(set) + names = set() + rat = collections.defaultdict(set) + for pk in sorted(glob.glob('/work/sylph_extract/**/*.pak', recursive=True)): + base = os.path.basename(pk) + for h, b in pak_entries(pk): + H[h].add(base) + for m in re.finditer(rb'[A-Za-z0-9_]{3,40}\.prt', b): + names.add(m.group(0).decode()) + if b[:4] == b'RATC': + for m in re.finditer(rb'[A-Za-z0-9_]{3,40}_sub\.rat', b): + rat[m.group(0).decode()].add(base) + + print("# Where `.prt` screen parts live") + print("# Regenerate: python3 tools/re-capture/prt_parts.py") + print("# See docs/re/structures/mission-script-manifest.md") + + byp = collections.Counter() + hit = set() + for n in names: + for p in PRE: + if U.name_hash(p + n) in H: + byp[p] += 1; hit.add(n) + print("\n## `.prt` IS a pak entry name -- under a LANGUAGE directory") + print(" distinct .prt names referenced anywhere : %d" % len(names)) + print(" resolving as a pak entry : %d" % len(hit)) + for p, c in byp.most_common(): + print(" prefix %-8s %3d" % (repr(p), c)) + + print("\n## the five mission-banner parts") + for n in FIVE + ['prbase.prt', 'palogo1.prt']: + ok = [p or '' for p in PRE if U.name_hash(p + n) in H] + print(" %-20s resolves under: %s" % (n, ok if ok else 'NOTHING')) + + print("\n## `_sub.rat` sub-bundles inside RATC") + print(" distinct _sub.rat names: %d" % len(rat)) + for k in sorted(rat): + print(" %-26s in %d archives %s" % (k, len(rat[k]), sorted(rat[k])[:2])) + stems_prt = {n[:-4] for n in names} + stems_rat = {k[:-8] for k in rat} + print(" CONTROL .prt stems that have a _sub.rat: %d / %d -- so this is NOT the general" + % (len(stems_prt & stems_rat), len(stems_prt))) + print(" container convention; `prbase` has a .prt entry and no _sub.rat.") + +if __name__ == "__main__": + main()