#!/usr/bin/env python3 """`Stage\\script.tbl` -- the mission-script manifest, and what its values point at. Regenerates docs/re/data/script-manifest.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 def main(): mg = glob.glob('/work/sylph_extract/**/GP_MAIN_GAME_E.pak', recursive=True)[0] E = dict(pak_entries(mg)) recs = U.parse(E[U.name_hash('Stage\\script.tbl')]) print("# Stage\\script.tbl -- the mission-script manifest") print("# Regenerate: python3 tools/re-capture/script_manifest.py") print("# See docs/re/structures/mission-script-manifest.md") print("\n## the three records") for r in recs: n = U.named(r) print(" %-10s %2d fields" % (r['squadron'], len(r['fields']))) if r['squadron'] == 'SCRIPTS': continue for k, v in sorted(n.items()): print(" %-22s %r" % (k, v)) sc = [r for r in recs if r['squadron'] == 'SCRIPTS'][0] print("\n## SCRIPTS -- the 11 non-MISSION fields, read for the first time") for t, n, v in sorted(sc['fields'], key=lambda x: (x[1] or '')): if n and n.startswith('MISSION') and v.endswith('.ssb'): continue print(" %-22s %r" % (n, v)) idx = {} for pk in sorted(glob.glob('/work/sylph_extract/**/*.pak', recursive=True)): idx[os.path.basename(pk)] = {h for h, b in pak_entries(pk)} targets = ['MissionDialogMessage.tbl', 'MissionDialog_local_string.tbl', 'pgmsg_start.prt', 'pgmsg_end.prt', 'pgmsg_update.prt', 'pgmsg_failed.prt', 'pgmsg_restart.prt'] pre = ['', 'Stage\\', 'stage\\', 'message\\', 'language\\', 'msg\\', 'dialog\\', 'script\\', 'SCRIPTS\\', 'GP_SCRIPT\\', '2d\\', 'ui\\', 'prt\\', 'view\\', 'dat\\', 'hidden\\'] for l in ['eng', 'jpn', 'fra', 'deu', 'ita', 'esp']: pre += [l + '\\', 'Stage\\' + l + '\\', 'message\\' + l + '\\'] print("\n## do those values resolve as pak entries? (%d prefixes x %d archives)" % (len(pre), len(idx))) for t in targets: hits = sorted({p + t for p in pre if any(U.name_hash(p + t) in s for s in idx.values())}) if hits: for hname in hits[:1]: where = sorted(pk for pk, s in idx.items() if U.name_hash(hname) in s) print(" %-32s FOUND as %-40s in %d archives" % (t, hname, len(where))) else: print(" %-32s not found" % t) c = U.name_hash('Stage\\script.tbl') print(" CONTROL Stage\\script.tbl resolves in %d archives" % sum(1 for s in idx.values() if c in s)) print(" NOTE name_hash is CASE-INSENSITIVE (message\\ == Message\\); tag_hash is not.") b = E[U.name_hash('message\\MissionDialogMessage.tbl')] dr = U.parse(b) pat = re.compile(r'^S(\d+)_P(\d+)_(.+)$') fam = collections.Counter(); st = collections.defaultdict(set); nf = collections.Counter() for r in dr: m = pat.match(r['squadron']) if m: fam[m.group(3)] += 1 st[int(m.group(1))].add(int(m.group(2))) nf[len(r['fields'])] += 1 print("\n## message\\MissionDialogMessage.tbl -- %d records, %d bytes" % (len(dr), len(b))) print(" name families S_P_: %s" % dict(fam)) shape = collections.defaultdict(collections.Counter) for r in dr: m = pat.match(r['squadron']) if m: shape[m.group(3)][(len(r['fields']), sum(1 for t, n, v in r['fields'] if n is not None))] += 1 print(" per kind (total fields, NAMED fields) -> count:") for k in sorted(shape): print(" %-12s %s" % (k, dict(shape[k]))) print(" stages present (%d): %s" % (len(st), sorted(st))) print(" phases per stage: %s" % {k: len(v) for k, v in sorted(st.items())}) H = {h for h, _ in pak_entries(mg)} ship = {i for i in range(0, 40) if U.name_hash('stage\\UnitGroup_S%02d.tbl' % i) in H} print(" CONTROL subset of the %d shipped stages: %s ; shipped with NO hints: %s" % (len(ship), set(st) <= ship, sorted(ship - set(st)))) r0 = [r for r in dr if r['squadron'].endswith('_HINT_PAUSE')][0] print("\n sample %s:" % r0['squadron']) for t, n, v in r0['fields']: print(" tag %-3s %-8s %r" % (t, n or '', v)) if __name__ == "__main__": main()