import struct, collections

RES = r"C:\git\bt411\content\BTL4.RES"
data = open(RES, "rb").read()

ver = data[0:4]
labOnly, maxID = struct.unpack_from("<ii", data, 4)
offsets = struct.unpack_from("<%dI" % maxID, data, 12)

Res = collections.namedtuple("Res", "rid rtype name prio flags off length")
resources = {}
for o in offsets:
    if o == 0: continue
    rid, rtype = struct.unpack_from("<ii", data, o)
    name = data[o+8:o+40].split(b"\0")[0].decode("ascii","replace")
    prio, flags, roff, rlen = struct.unpack_from("<iIII", data, o+40)
    resources[rid] = Res(rid, rtype, name, prio, flags, roff, rlen)

t29 = sorted([r for r in resources.values() if r.rtype == 29], key=lambda x: x.name)
t20 = {r.name: r for r in resources.values() if r.rtype == 20}
print("version", list(ver), "type29 (DamageLookupTableStream) count =", len(t29))
print("type20 (DamageZoneStream) count =", len(t20))
print("name-match: every t29 name also a t20 name?",
      all(r.name in t20 for r in t29), "\n")

def hexdump(b, base=0, n=64):
    out=[]
    for i in range(0, min(n,len(b)), 16):
        chunk=b[i:i+16]
        hexs=" ".join("%02x"%c for c in chunk)
        out.append("  %04x  %-47s" % (base+i, hexs))
    return "\n".join(out)

def parse_table(b, name):
    print("="*70)
    print("TABLE '%s'  (%d bytes)" % (name, len(b)))
    print(hexdump(b, 0, 48))
    p = 0
    rowCount = struct.unpack_from("<i", b, p)[0]; p += 4
    print("  rowCount =", rowCount)
    for r in range(rowCount):
        rotate = struct.unpack_from("<i", b, p)[0]; p += 4
        cellCount = struct.unpack_from("<i", b, p)[0]; p += 4
        print("  row[%d] rotateWithTorso=%d cellCount=%d" % (r, rotate, cellCount))
        for c in range(cellCount):
            # cell: [int slen][slen chars]["\0"][int cnt][cnt*(float threshold, int zone)]
            slen = struct.unpack_from("<i", b, p)[0]; p += 4
            if slen < 0 or slen > 64 or p+slen > len(b):
                print("     cell[%d] *** slen sanity fail slen=%d @%d ***" % (c, slen, p-4)); return
            s = b[p:p+slen].decode("ascii","replace"); p += slen + 1   # +1 = trailing null
            cnt = struct.unpack_from("<i", b, p)[0]; p += 4
            entries=[]
            for _ in range(cnt):
                thr = struct.unpack_from("<f", b, p)[0]
                zone = struct.unpack_from("<i", b, p+4)[0]; p += 8
                entries.append((round(thr,4), zone))
            if r == 0:
                print("     cell[%d] str='%s' cnt=%d entries=%s" % (c, s, cnt, entries))
    status = "EXACT" if p == len(b) else "MISMATCH (off by %d)" % (len(b)-p)
    print("  consumed %d / %d bytes  -> %s" % (p, len(b), status))

# ground on the first 2 tables
for r in t29[:2]:
    b = data[r.off:r.off+r.length]
    parse_table(b, r.name)
