"""Gitea #46 -- verify the ammo bay fire detonates and applies real damage.
Before this fix, three stacked defects made an armed bay fire permanently inert:
the clock stub (`0 < 0` never fired), the InjectHeat no-op (nothing applied),
and the never-stamped Damage record (0 damage of type 0 even if it had).
Rig: BT_BAYTEST= sends message 1 (the crit-induced "begin cook-off
countdown", @004bdb94) to the first AmmoBin. The authentic fuse is a FIXED
10.0 seconds (raw disasm @004bd450: 10.0 x ticksPerSecond + 0.5, __ftol --
the old "RandomDelay" was a Ghidra artifact).
PASS =
[ammo] ... BAY FIRE (message): cook-off armed, N rounds, detonation in 10s
...~10 wall seconds later...
[ammo] ... BAY FIRE DETONATION: N rounds x D = total (type T)
ammo explosion damaging (the binary's exact @0050df61 print)
...and the mech takes real zone damage (BT_MP_NET handler line / DAMAGE state).
Kills only the PID it spawns.
"""
import os
import re
import subprocess
import sys
import time
REPO = r"C:\git\bt411"
LOG = os.path.join(REPO, "scratchpad_lampflash.log")
if os.path.exists(LOG):
os.remove(LOG)
env = dict(os.environ)
env.update({
"BT_START_INSIDE": "1",
"BT_DEV_GAUGES": "1",
"BT_BAYTEST": "400", # arm at sim frame 400
"BT_AMMO_LOG": "1",
"BT_MP_NET": "1",
"BT_LAMP_LOG": "1", # [techstat]/[galarm]/[lamp] -- the #47 flash chain # [mp-hdlr] TakeDamageHandler lines (zone + amount)
"BT_DEATH_LOG": "1", # crit cascade / zone destruction
"BT_LOG": LOG,
})
proc = subprocess.Popen(
[os.path.join(REPO, "build", "Release", "btl4.exe"), "-egg", "LAST.EGG"],
cwd=os.path.join(REPO, "content"), env=env,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print("pid", proc.pid)
try:
deadline = time.time() + 240
armed = False
while time.time() < deadline:
if os.path.exists(LOG):
t = open(LOG, errors="replace").read()
if "BAY FIRE (message)" in t:
armed = True
break
time.sleep(2)
if not armed:
print("FAIL: never armed")
# wait through the 10s fuse + margin for the fan-out and damage
time.sleep(25)
finally:
proc.terminate()
time.sleep(1)
t = open(LOG, errors="replace").read() if os.path.exists(LOG) else ""
arm = re.findall(r"^\[ammo\].*BAY FIRE.*armed.*$", t, re.M)
boom = re.findall(r"^\[ammo\].*DETONATION.*$", t, re.M)
zones = re.findall(r"^ammo explosion damaging.*$", t, re.M)
hdlr = re.findall(r"^\[mp-hdlr\] TakeDamageHandler.*$", t, re.M)
dfx = re.findall(r"^\[deathfx\].*$", t, re.M)
ext = re.findall(r"^\[ammo\].*EXTINGUISHED.*$", t, re.M)
print("\n=============== RESULT ===============")
print("armed:", len(arm))
for l in arm[:2]:
print(" ", l[:120])
print("\ndetonation:", len(boom))
for l in boom[:2]:
print(" ", l[:130])
print("\n'ammo explosion damaging' zone prints:", len(zones))
for l in zones[:6]:
print(" ", l[:100])
print("\nTakeDamage handler runs:", len(hdlr))
for l in hdlr[:4]:
print(" ", l[:150])
print("\n[deathfx] zone/crit lines:", len(dfx))
for l in dfx[:8]:
print(" ", l[:120])
if ext:
print("\nextinguished (unexpected in this rig):", ext[:2])
ok = arm and boom and zones and hdlr
print("\nVERDICT:", "PASS -- bay fire armed, detonated on the 10s fuse, and applied real zone damage"
if ok else "FAIL -- see which stage is missing above")
sys.exit(0 if ok else 2)