Files
BT412/scratchpad/bgfparse.py
T
arcattackandClaude Fable 5 8ed6184d65 Combat: AUTHENTIC weapon groups -- streamed per-mech button bindings + the real fire chain (task #5)
The recovered system: fire channels = LBE4ControlsManager buttonGroups
(0x40/0x45/0x46/0x47); default groups = the per-mech type-6 controls-map
resource in BTL4.RES, installed by the T0 CreateStreamedMappings the port
already called -- it needed only the TriggerState attribute (id 0x13 PINNED
to the binary value; fireImpulse@0x31C is the binary's TriggerState) and an
input feed.  Keyboard/harness now push press/release edges into the button
groups; the gBT*Trigger bypasses, per-type keyboard split and 1,0 pulse
hack are retired -- weapons sharing a button fire TOGETHER (madcat Trigger
= 4 weapons).  Myomers @4b9550/@4b95b8 misattribution corrected (they are
MechWeapon ConfigureMappables/ChooseButton).  Verified 2-node: kill through
the authentic chain (12 hits vs ~36 pre-groups).  Config-mode session
(regrouping UI) = the remaining stage, KB-scoped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 13:06:29 -05:00

52 lines
2.0 KiB
Python

import struct,sys
def rdU16(b,p): return struct.unpack_from('<H',b,p)[0]
def rdU32(b,p): return struct.unpack_from('<I',b,p)[0]
def rdF32(b,p): return struct.unpack_from('<f',b,p)[0]
TAGNAME={0x0003:'HEADER',0x0005:'BIZ_DONE',0x0040:'OBJECT',0x0041:'LOD',0x0042:'PATCH',
0x0046:'PMESH',0x0047:'CONN_LIST',0x0048:'SPHERE_LIST',0x004d:'PCONN_LIST',0x0070:'BOUND',
0x0080:'VTX_XYZ',0x0081:'VTX_XYZ_N',0x0082:'VTX_XYZ_RGBA',0x0088:'VTX_XYZ_UV',
0x0089:'VTX_XYZ_N_UV',0x008A:'VTX_XYZ_RGBA_UV',0x2030:'SV_F_MATERIAL',0x2037:'SV_SPECIAL',
0x0010:'TEXTURE',0x0011:'TEXTURE_MAP',0x0018:'BITSLICE',0x0020:'MATERIAL',
0x0021:'MAT_TEXTURE',0x0023:'AMBIENT',0x0024:'DIFFUSE',0x0026:'EMISSIVE',
0x0028:'RAMP_REF',0x0030:'RAMP',0x0031:'RAMP_DATA',0x2008:'NAME',
0x0043:'FACE',0x0044:'FACE?',0x0045:'FACE?'}
CONTAINERS={0x0003,0x0070,0x0040,0x0041,0x0042,0x0046,0x0048,0x0010,0x0020,0x0030}
def parse(b,p,end,depth,out):
while p+3<=end:
tw=rdU16(b,p); p+=2
idv=tw & 0x2fff
lw=4 if (tw&0x8000) else (2 if (tw&0x4000) else 1)
if p+lw>end: break
ln = b[p] if lw==1 else (rdU16(b,p) if lw==2 else rdU32(b,p))
p+=lw
if p+ln>end: break
out.append((depth,idv,p,ln))
if idv in CONTAINERS:
parse(b,p,p+ln,depth+1,out)
p+=ln
if idv==0x0005: break
return
fn=sys.argv[1]
b=open(fn,'rb').read()
assert b[:8]==b'DIV-BIZ2', b[:8]
out=[]
parse(b,8,len(b),0,out)
for depth,idv,p,ln in out:
nm=TAGNAME.get(idv,'?%04x'%idv)
extra=''
if idv==0x2008 or idv==0x0011 or idv==0x0028:
s=b[p:p+ln].split(b'\0')[0].decode('latin1',errors='replace')
extra=' "%s"'%s
if idv==0x2037: # SV_SPECIAL
s=b[p:p+ln].split(b'\0')[0].decode('latin1',errors='replace')
extra=' SPECIAL="%s"'%s
if idv==0x2030: # SV_F_MATERIAL
s=b[p:p+ln].split(b'\0')[0].decode('latin1',errors='replace')
extra=' MAT="%s" (len %d)'%(s,ln)
if idv==0x0018 and ln>=1: extra=' slice=%d'%b[p]
print(' '*depth + '%-14s off=0x%04x len=%d%s'%(nm,p,ln,extra))