"""#48 solo reproduction: drive the COMMS panel's target-designation path. The one comms action never exercised in any rig. Target designation (typed t/y/u/i/o, and the Comm bank buttons 0x30-0x37) performs three RAW writes at `pilotArray[0] + 0x284` (mechmppr.cpp:1344/:1364/:1420) intending the binary's `objectiveMech`. Our compiled layout differs from the binary's, so that write lands on whatever member really sits at byte 0x284 -- the ctor now prints the real offsets, and this run hammers the designation keys while capturing frames. Also toggles the pilot list's SELECT-TARGET highlight, which is the branch that makes PilotList::DrawMechIcon repaint (filled box / inverted blit). Kills only the PID it spawns. """ import ctypes import os import re import shutil import subprocess import sys import time KEYUP = 0x0002 user32 = ctypes.windll.user32 REPO = r"C:\git\bt411" CONTENT = os.path.join(REPO, "content") EXE = os.path.join(REPO, "build", "Release", "btl4.exe") SHOT = os.path.join(REPO, "scratchpad_comms.png") LOG = os.path.join(REPO, "scratchpad_comms.log") OUT = os.path.join(REPO, "scratchpad", "comms") os.makedirs(OUT, exist_ok=True) for f in (SHOT, LOG): if os.path.exists(f): os.remove(f) env = dict(os.environ) env.update({ "BT_START_INSIDE": "1", "BT_KEY_NOFOCUS": "1", "BT_DEV_GAUGES": "1", # cockpit surround -> BT_SHOT captures all panels "BT_SPAWN_ENEMY": "1", # something to designate "BT_SCORE_LOG": "1", # pilot roster + score diagnostics "BT_SHOT": SHOT, "BT_LOG": LOG, }) proc = subprocess.Popen([EXE, "-egg", "LAST.EGG"], cwd=CONTENT, env=env) print("pid", proc.pid) def tap(ch, hold=0.10): vk = ord(ch.upper()) user32.keybd_event(vk, 0, 0, 0) time.sleep(hold) user32.keybd_event(vk, 0, KEYUP, 0) time.sleep(0.12) saved = [] try: deadline = time.time() + 220 while time.time() < deadline: if os.path.exists(SHOT) and os.path.getsize(SHOT) > 20000: break time.sleep(2) else: print("FAIL: never rendered"); sys.exit(2) time.sleep(6) shutil.copy(SHOT, os.path.join(OUT, "00_baseline.png")); saved.append("00_baseline") # hammer the designation keys -- each press runs the raw +0x284 write path for rnd in range(6): for ch in "tyuio": tap(ch) time.sleep(4) n = "%02d_after_%d_designations" % (rnd + 1, (rnd + 1) * 5) try: shutil.copy(SHOT, os.path.join(OUT, n + ".png")); saved.append(n) except Exception as e: print(" copy failed:", e) print(" round %d: 5 designations sent" % (rnd + 1)) finally: proc.terminate() time.sleep(1) print("\nsaved %d frames to %s" % (len(saved), OUT)) txt = open(LOG, errors="replace").read() if os.path.exists(LOG) else "" for pat, label in ((r"^\[layout\].*$", "LAYOUT"), (r"^\[score\] pilot roster built.*$", "roster"), (r"^\[target\].*$", "target")): hits = re.findall(pat, txt, re.M) print("--- %s (%d):" % (label, len(hits))) for h in hits[:3]: print(" ", h[:150])