Files
BT412/scratchpad/scan_434b.py
T
arcattackandClaude Fable 5 fd055281a8 Combat: THE AUTHENTIC DAMAGE ECONOMY -- authored per-weapon amounts through the real fire chain (task #8)
Three root causes, all fixed:
1. kDamageScale was 1.0 -- _DAT_004bafbc is an x87 float80 = 1e-7, cancelling
   the ctor's x1e7: damagePortion = authored DamageAmount x (charge/seekV)^2
   (closed form at fire time; madcat AC=25/LRM=50/ERLL=6, bhk1 PPC=12/SRM=35).
   The observed "0.25" was the degenerate EC=1 fallback, never authored data.
2. CheckFireEdge NaN latch: TriggerState carries ControlsButton INTS; the
   release value (-65) is a negative NaN.  The binary's x87 unordered compare
   read it as "released"; IEEE-correct float compares latched the edge
   detector shut after the first release -- the reason the emitter discharge
   chain NEVER fired in-game.  Fixed with bit-pattern sign compares.
3. The weapon-side submission LIVE: Emitter::FireWeapon fills damageData
   (amount + damageForce=target-muzzle [the gyro directional-bounce feed] +
   impact) -> MechWeapon::SendDamageMessage (@004b9728 real body) ->
   messmgr consolidation with per-weapon records + explosion bundling.
   The mech4 bring-up damage block + flat kShotDamage retired to diag hooks.
Bonus: LODReuseHysteresis 0.82 -> 0.33 (double misread).  Zone model
verified byte-exact (no change).  Solo end-to-end: 5-record volleys (2 PPC
+ 3 ERML with authored amounts), per-weapon zone granularity, explosions,
kill.  Heat stays bring-up scale pending the heat-calibration audit [T3].

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 15:32:24 -05:00

32 lines
1.2 KiB
Python

import capstone, struct, sys
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
data = open(r"C:/git/bt411/content/BTL4OPT.EXE","rb").read()
CODE_VA=0x401000; CODE_RA=0xE00
pe = struct.unpack_from("<I", data, 0x3c)[0]
nsec = struct.unpack_from("<H", data, pe+6)[0]
opt=pe+24; szopt=struct.unpack_from("<H",data,pe+20)[0]; sec0=opt+szopt
for i in range(nsec):
off=sec0+i*40
name=data[off:off+8].rstrip(b"\0").decode()
vsz,va,rsz,ra=struct.unpack_from("<IIII",data,off+8)
if name=="CODE": code_rsz=rsz
pat=b"\x34\x04\x00\x00"
md=capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32)
start=0; matched={0x4a1d2d,0x4a22ad,0x4b984b,0x4bacc7,0x4baeb4}
while True:
idx=data.find(pat,start)
if idx<0: break
start=idx+1
if not (CODE_RA<=idx<CODE_RA+code_rsz): continue
va=CODE_VA+(idx-CODE_RA)
ok=False
for back in range(2,9):
for ins in md.disasm(data[idx-back:idx-back+16], va-back):
if "0x434" in ins.op_str and va+4 <= ins.address+ins.size <= va+8:
ok=True; break
if ok: break
if not ok:
# show raw bytes context for manual inspection
print(f"UNMATCHED at va {va:08x}: {data[idx-8:idx+8].hex()}")
print("done")