Files
llamamod/tools/strats.py
T

80 lines
2.6 KiB
Python

#!/usr/bin/env python3
"""Strat-Typen (Objekttypen) eines Level-WADs: Namen aus STPC-Strat-Code, MAP-Instanzen.
Strat-Code liegt am Ende von STPC (nach Modellen/Animsets). Bytecode = u32-Wörter
(low16 = Opcode, high16 = Kurzoperand). Ein Strat beginnt (fast immer) mit
... 0xd4, 0xea, <s32 rel> -> Name = C-String bei (Adresse nach rel) + rel
strats.py level.wad [--all]
"""
import os
import struct
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import map_dump # noqa: E402
import stpcwalk # noqa: E402
def cstr(d, o):
e = d.index(b'\0', o)
return d[o:e].decode('latin1')
def strat_name(st, entry, lo):
"""Name eines MAP-Einstiegs: Spawn-Stub (b2 <abs> e0 ...) -> Ziel; sonst erstes d4/ea ab entry."""
w = struct.unpack_from('<8I', st, entry)
for k in range(5):
if w[k] == 0xb2 and w[k + 2] == 0xe0 and lo <= w[k + 1] < len(st):
n = strat_name(st, w[k + 1], lo)
return n + '(spawn)' if n else None
for k in range(0, 1024, 4):
o = entry + k
if o + 12 > len(st):
break
a, b = struct.unpack_from('<II', st, o)
if a == 0xd4 and b == 0xea:
rel = struct.unpack_from('<i', st, o + 8)[0]
n = o + 12 + rel
if lo <= n < len(st):
return cstr(st, n)
return None
def all_named(st, lo):
"""Alle d4/ea-Namensstellen im Code-Bereich (Wort-Raster ab lo)."""
out = []
for o in range(lo, len(st) - 12, 4):
a, b = struct.unpack_from('<II', st, o)
if a == 0xd4 and b == 0xea:
rel = struct.unpack_from('<i', st, o + 8)[0]
n = o + 12 + rel
if lo <= n < o:
out.append((o, cstr(st, n)))
return out
def level_types(path):
ch, wf, m = map_dump.load(path)
st = ch['STPC']
lo = stpcwalk.walk(st, wf)['code']
types = {}
for s in m['strats']:
code = s[6]
nm = strat_name(st, code, lo) or f'?@{code:#x}'
types.setdefault(nm, []).append(s)
return ch, wf, m, lo, types
if __name__ == '__main__':
ch, wf, m, lo, types = level_types(sys.argv[1])
print(f'code region {lo:#x}..{len(ch["STPC"]):#x}')
for nm, ss in sorted(types.items()):
s = ss[0]
print(f'{len(ss):3d} x {nm:32s} code@{s[6]:#x} nparams={s[7]} nvars={s[9]} f30={s[10]} '
f'flags={s[11]:#x} extra={s[12]:#x}')
if '--all' in sys.argv:
used = {s[6] for v in types.values() for s in v}
print('-- alle benannten Strats im Code (Namens-Op-Adresse):')
for o, n in all_named(ch['STPC'], lo):
print(f' {o:#x} {n}')