#!/usr/bin/env python3 """Parse/write the MAP chunk of level WADs (Lama/Croc 2 engine, PC). Reimplemented from groove.exe FUN_0042ac50 (MAP loader). Depends on WFPC flags (u32 in the WFPC chunk, bits 0x10000, 0x10000000, 0x200000, 0x4000000, 0x10) TRAK model vertex counts (vertex colour block). See notes/objects.md. """ import struct class R: def __init__(s, d, o=0): s.d, s.o = d, o def u32(s): v = struct.unpack_from(' DAT_006da350 m['grid'] = r.f('%dI' % (W * H)) m['tiles2'] = [r.f('6I') for _ in range(nt)] m['tilemodel'] = list(r.f('%dI' % nt)) alts = [] if wfpc & 0x10000: n = r.u32(); alts = [r.f('5I') for _ in range(n)] m['alts'] = alts # vertex colours: nv u32 per tile (byte 3 = frames), more frames if any; then alt model altidx = [i for i, t in enumerate(m['tiles']) if t[5]] altmap = dict(zip(altidx, alts)) start = r.o split = [] # vertex colour bytes per tile (incl. alt model) for i in range(nt): t0 = r.o for mdl in [m['tilemodel'][i]] + ([altmap[i][4]] if i in altmap else []): nv = vcounts[mdl] cols = r.f('%dI' % nv) fr = max([c >> 24 for c in cols] + [0]) if fr > 1: r.o += 4 * nv * (fr - 1) split.append(d[t0:r.o]) m['vcol'] = d[start:r.o] m['vcol_split'] = split ns, x = r.f('2I') m['strat_x'] = x m['strats'] = [r.f(STRAT) for _ in range(ns)] paths = [] if wfpc & 0x200000: np_ = r.u32() for _ in range(np_): nsub = r.u32(); subs = [] for _ in range(nsub): cnt, fl = r.f('2H'); pts = [] for _ in range(cnt): a = r.f('2I') c = r.f('I') if wfpc & 0x4000000 else () pts.append(a + c + r.f('2H')) subs.append((fl, pts)) paths.append(subs) m['paths'] = paths m['x200'] = r.u32() if wfpc & 0x10 else None m['last'] = r.u16() m['rest'] = d[r.o:] return m def build(m, wfpc): """Counterpart of parse(); m['vcol'] must match tilemodel/alts (raw bytes).""" P = struct.pack o = [P('<3I', len(m['tiles']), m['W'], m['H'])] o += [P('<3f3I', *t) for t in m['tiles']] o.append(P('