Files
Sylpheed/tools/re-capture/hud_config.py
Sylpheed RE agent 6ea3d60c6f re: the objective/tutorial marker records; S24-S29 are CHALLENGE, not story
Correction first.  stage-numbering-and-player-craft.md called S24-S29
'story' and reported 22 story stages.  challenge-mission-gate.md OWNS
that split and already had it: S01-S16 story, S18-S23 tutorials,
S24-S29 challenge.  A third confirmation fell out of this iteration:
AUTO_SETTINGS names stage01..16_settings.tbl, tutorial01..06 and
challenge01..06, and its field tags are 1-16, 18-23, 24-29 -- the
shipped stage numbers exactly.  The campaign is 16 story missions, not
22.  AUTO_SETTINGS and IGNORE are likewise already owned by
isl-condition-builtins.md, so nothing there was new either.

What is new: the 11 marker records hud-config.md listed as unread.  12
named fields each, portable HUD data.  Colour is ARGB, three per marker
-- objectives red 0xFFFF0000, guard/waypoint green 0xFF20FF20,
Acropolis/tanker cyan 0xFF00FFFF, sub-objective yellow 0xFFFFFF00, and
every TutorialMarker_* amber 0xFFFFA010.  Each carries a Normal sprite
and an Emphasis part with optional Sub companions; HPGauge 0/1/2;
RadarCursorType Circle/Rectangle/blank; BlinkCycle 0x800 on all eleven.
TutorialTarget is Yes on exactly the five TutorialMarker_* and No on the
six ObjectiveMarker_*.

Parameters binds the roles: TargetMarker -> ObjectiveMarker_Target,
HelpMarker -> ObjectiveMarker_SubObjective, TutoTargetMarker ->
TutorialMarker_Target, plus ReloadDispTime 0.1.
Enumerate_ObjectiveMarkers is the 11-name roster.

Artefact +13 lines / 0 deletions; the other nine regenerate
byte-identical.
2026-08-27 15:46:31 +00:00

90 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""The in-game HUD configuration in the `GP_MAIN_GAME_*2D.pak` IDXD entries.
Regenerates docs/re/data/hud-config.txt.
"""
import sys, os, glob, collections
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import unitgroup as U
from unit_substructures import pak_entries
PRE = ['', '2d\\', 'ui\\', 'hud\\'] + [l + '\\' for l in ('eng', 'jpn', 'fra', 'deu', 'ita', 'esp')]
DEFAULT = ('HudResource.tbl', 'HudMarkerResource.tbl')
def main():
p2 = glob.glob('/work/sylph_extract/**/GP_MAIN_GAME_E2D.pak', recursive=True)[0]
E = dict(pak_entries(p2))
H = set()
for pk in sorted(glob.glob('/work/sylph_extract/**/*.pak', recursive=True)):
for h, b in pak_entries(pk):
H.add(h)
print("# The in-game HUD configuration (GP_MAIN_GAME_*2D.pak, IDXD entries)")
print("# Regenerate: python3 tools/re-capture/hud_config.py")
print("# See docs/re/structures/hud-config.md")
print("\n## the six IDXD entries of GP_MAIN_GAME_E2D.pak")
for h, b in sorted(pak_entries(p2)):
if b[:4] != b'IDXD': continue
recs = U.parse(b)
print(" %08x %2d records: %s" % (h, len(recs), ", ".join(r['squadron'] for r in recs)))
print("\n## every config record, field by field")
seen = set()
for h, b in sorted(pak_entries(p2)):
if b[:4] != b'IDXD': continue
for r in U.parse(b):
if r['squadron'] in seen: continue
seen.add(r['squadron'])
n = U.named(r)
pos = [v for t, nm, v in r['fields'] if nm is None]
print("\n== %s : %d fields (%d named, %d positional)"
% (r['squadron'], len(r['fields']), len(n), len(pos)))
for k, v in sorted(n.items()):
print(" %-28s %s" % (k, v))
for i, v in enumerate(pos):
print(" [%2d] %s" % (i, v))
vals = set()
for h, b in pak_entries(p2):
if b[:4] != b'IDXD': continue
for r in U.parse(b):
for t, nm, v in r['fields']:
if v.endswith('.prt') or v.endswith('.t32') or v.endswith('.tbl'):
vals.add(v)
ok = [v for v in vals if any(U.name_hash(q + v) in H for q in PRE)]
print("\n## CONTROL do the config's own path values resolve as pak entries?")
print(" distinct .prt/.t32/.tbl values: %d ; resolving under %d prefixes: %d"
% (len(vals), len(PRE), len(ok)))
print(" the config FILENAMES themselves:")
for n in list(DEFAULT) + ['HudResource_S26.tbl', 'HudMarkerResource_S26.tbl']:
print(" %-30s %s" % (n, 'resolves' if any(U.name_hash(q + n) in H for q in PRE) else 'no hit'))
print("\n## the objective / tutorial MARKER records")
seen = set()
for h, b in pak_entries(p2):
if b[:4] != b'IDXD': continue
for r in U.parse(b):
sq = r['squadron']
if not (sq.startswith('ObjectiveMarker_') or sq.startswith('TutorialMarker_')): continue
if sq in seen: continue
seen.add(sq)
n = U.named(r)
print(" %-30s %s" % (sq, " ".join("%s=%s" % (k, v) for k, v in sorted(n.items()))))
print("\n## ResourceTable -- 29 pairs, one per stage, with a single override")
for pk in sorted(glob.glob('/work/sylph_extract/**/GP_MAIN_GAME_*2D.pak', recursive=True)):
for h, b in pak_entries(pk):
if b[:4] != b'IDXD': continue
for r in U.parse(b):
if r['squadron'] != 'ResourceTable': continue
vv = [v for t, nm, v in r['fields']]
odd = [(i, v) for i, v in enumerate(vv) if v not in DEFAULT]
print(" %-26s %2d fields = %d pairs ; non-default at %s"
% (os.path.basename(pk), len(vv), len(vv) // 2, odd))
if __name__ == "__main__":
main()