80 lines
2.6 KiB
Python
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}')
|