import struct data = open(r'C:/git/bt411/content/BTL4.RES','rb').read() n = len(data) def cstr(off, maxlen=32): s = data[off:off+maxlen].split(b'\0')[0] try: return s.decode('ascii') except: return None def f32(off): return struct.unpack_from('= len(pad) - 2: recs.append((i, name, cid, sz)) i += 0x28 continue i += 1 print(f'total subsystem records: {len(recs)}') # group into chains (consecutive: next record at p+sz) chains = [] cur = [] for k,(p,name,cid,sz) in enumerate(recs): if cur and cur[-1][0] + cur[-1][3] == p: cur.append(recs[k]) else: if cur: chains.append(cur) cur = [recs[k]] if cur: chains.append(cur) # mech-name strings for labeling mechnames = [b'madcat', b'bhk', b'vulture', b'thor', b'blackhawk', b'blh', b'owens', b'strider', b'sunder', b'cauldron', b'avatar', b'mdc'] low = data.lower() namepos = [] for m in mechnames: j = 0 while True: j = low.find(m, j) if j < 0: break namepos.append((j, m.decode())) j += 1 namepos.sort() def nearest_label(p): best = None for pos, name in namepos: if pos < p: best = (pos, name) else: break return best WEAP = {0xBC8:'Emitter', 0xBD4:'PPC', 0xBCD:'MechWeapon/Projectile', 0xBCE:'GaussRifle?', 0xBD0:'MissileLauncher'} for ci, ch in enumerate(chains): lbl = nearest_label(ch[0][0]) has_weap = any(c[2] in WEAP for c in ch) print(f'--- chain {ci} @0x{ch[0][0]:x} n={len(ch)} nearest-name={lbl} roster={[c[1] for c in ch]}') for (p,name,cid,sz) in ch: if cid not in WEAP: continue rr, wr = f32(p+0x190), f32(p+0x194) dmg = f32(p+0x19C); dt = i32(p+0x1A0); heat = f32(p+0x1A4) pip = i32(p+0x1A8); pc = (f32(p+0x1AC), f32(p+0x1B0), f32(p+0x1B4)); per = i32(p+0x1B8) line = (f' {name:24s} cid=0x{cid:X}({WEAP[cid]}) sz=0x{sz:X} Recharge={rr:g} Range={wr:g} ' f'Damage={dmg:g} Type={dt}({DMGTYPE.get(dt,"?")}) Heat={heat:g} Pip={pip} PipColor={pc} PipExt={per}') if cid in (0xBC8, 0xBD4) and sz >= 0x1DC: gl, dtm = f32(p+0x1BC), f32(p+0x1C0) sv = [f32(p+0x1C4+4*k) for k in range(5)] ri = i32(p+0x1D8) line += f' | GraphicLen={gl:g} DischargeTime={dtm:g} SeekV={["%g"%v for v in sv]} RecIdx={ri}' if cid in (0xBCD, 0xBD0) and sz >= 0x1D0: ti, abi = i32(p+0x1BC), i32(p+0x1C0) mtof, mvp, mjc = f32(p+0x1C4), f32(p+0x1C8), f32(p+0x1CC) line += f' | TracerInt={ti} AmmoBin={abi} MinTOF={mtof:g} MinVolt%={mvp:g} MinJam={mjc:g}' if cid == 0xBD0 and sz >= 0x1E0: mc = i32(p+0x1D0); mv = (f32(p+0x1D4), f32(p+0x1D8), f32(p+0x1DC)) line += f' | MissileCount={mc} MuzzleVel={mv}' print(line)