The 'can't kill the enemy / no visible damage' cluster, root-caused and fixed faithfully: - STEP-6 unaimed path was INERT: the cylinder table was 'cached' at Wword(0x111) -- the recon ABSORBER bank (stores nothing, reads 0) -- so every unaimed hit silently no-op'd. Promoted to the named member Mech::damageLookupTable (binary this[0x111], was mislabeled ammoExpended). New gotcha class recorded (reconstruction-gotchas §2) + sweep; 2 dead multiplayer branches logged. - Fire path migrated off the stale vital-zone aim onto the completed STEP-6 unaimed dispatch (zone=-1 + beam entry point -> cylinder resolves the exterior zone). No more invisible 1-shot kills; death via the authentic cascade (~14 center-mass hits). Wreck stays TARGETED on kill (beams stop on it); scoring latches off. - SendSubsystemDamage AV fixed: unbound critical-subsystem plug guard (43 unbound plugs/mech logged as an open question -- the binding itself is a gap). - RemakeEntity (render damage swap): the 1996 render state machine's missing Remake state, reconstructed as an in-place SetDrawObj mesh swap keyed by each segment's damage-zone graphic state (tree dtor doesn't cascade -> never rebuild). Destroyed arms/guns visibly wreck (the only variants the RES registers). - BT .PFX particle layer (L4VIDEO.cpp): the 1995 explosion/damage effect layer, unported since 2007 (DPLIndependantEffect/ReadPSFX/ExplosionScripts all stubs). Parses the authentic VIDEO/*.PFX definitions via the [pfx_day] psfxN mapping; premultiplied blending renders BOTH families from the same data (additive-style fire + occluding smoke -- DDAM2 is 30% grey, DDTHSMK ramps negative: impossible additively); depth-sorted billboards with a radial-masked grit sprite; impact-frame orientation (.PFX offsets are authored mech-local, -Z = out of the struck armor toward the shooter) for weapon hits AND damage bands (via lastInflictingID, now maintained -- was declared but never written). Both effect-number encodings route (raw dpl <100 + WinTesla 1000+slot carried by the band resources). Death fires the authentic dnboom (7) + ddthsmk smoke plume (1). - Effects anchor at the impact point / damaged zone's segment, not the mech origin (no more fire at the feet). - Dev force-input gates BT_AUTOFIRE / BT_AUTODRIVE for headless fire-chain verification; BT_PFX_ADD=1 flips the particle blend for A/B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
28 lines
996 B
Python
28 lines
996 B
Python
import struct
|
|
data = open(r'C:\git\bt411\content\BTL4OPT.EXE', 'rb').read()
|
|
e = struct.unpack_from('<I', data, 0x3C)[0]; coff = e+4
|
|
num = struct.unpack_from('<H', data, coff+2)[0]; osz = struct.unpack_from('<H', data, coff+16)[0]
|
|
opt = coff+20; base = struct.unpack_from('<I', data, opt+28)[0]; sect = opt+osz
|
|
secs = []
|
|
for i in range(num):
|
|
o = sect+i*40
|
|
vs, va, rs, rp = struct.unpack_from('<IIII', data, o+8)
|
|
secs.append((va, vs, rp, rs))
|
|
|
|
def off2va(off):
|
|
for va, vs, rp, rs in secs:
|
|
if rp <= off < rp+rs:
|
|
return base+va+(off-rp)
|
|
return None
|
|
|
|
targets = {0x49ed0c: 'FUN_0049ed0c (glue: table->zone) == the handler',
|
|
0x49de14: 'FUN_0049de14 (cell->zone roll)'}
|
|
cva, cvs, crp, crs = secs[0]
|
|
for i in range(crp, crp+crs-5):
|
|
if data[i] == 0xE8:
|
|
rel = struct.unpack_from('<i', data, i+1)[0]
|
|
site = off2va(i)
|
|
tgt = site+5+rel
|
|
if tgt in targets:
|
|
print('call site VA %08x -> %s' % (site, targets[tgt]))
|