Add scratchpad/cursoraudit.py: static audit for the #42 stale-cursor draw family
Scans the gauge TUs for cursor-relative draws with no MoveToAbsolute in scope. Found 6 of 29, three of them STATE-CHANGE-ONLY draws -- notably L4GraphicLamp::NotifyOfStateChange (L4LAMP.cpp:376/380), which blits a lamp using whatever cursor the view happens to hold. That is the '#48 misplaced lamp' class: lamp-shaped, on the panels that have lamps, only on damage/jam/heat state changes, and persistent. Explains why the 5-pilot rig capture was clean (no combat = no lamp state change). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0166KTsC7ADm7VXEi1HF1jNg
This commit is contained in:
co-authored by
Claude Opus 5
parent
5174c638ce
commit
81fbfc7eaa
@@ -0,0 +1,75 @@
|
||||
"""#48 audit: find gauge draws that are NOT preceded by a cursor set.
|
||||
|
||||
The #42 family: a draw that relies on the CURRENT cursor works by accident the
|
||||
first time (the cursor happens to be right) and lands in the wrong place on a
|
||||
later redraw. Draws that only fire on a STATE CHANGE -- damage, heat, jam,
|
||||
alarm -- are the dangerous ones: they are rare, so the bug hides until gameplay
|
||||
triggers them, and nothing erases the stray pixels afterwards.
|
||||
|
||||
Relative/cursor-relative draws (the risky ones) vs absolute draws (safe):
|
||||
RISKY : DrawFilledRectangleToRelative, DrawBitMap*, DrawLineToRelative,
|
||||
DrawPointToRelative, DrawFilledRectangleToAbsolute (uses cursor as one corner)
|
||||
SAFE : anything taking explicit x,y (DrawPortBackground, NumericDisplay::Draw
|
||||
which carries its own coords)
|
||||
|
||||
Reports each risky draw with the distance back to the nearest MoveToAbsolute /
|
||||
MoveToRelative in the same function, and flags any that has none.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
|
||||
FILES = [
|
||||
"game/reconstructed/btl4gau2.cpp", # weapon panels + eng pages (artifacts seen here)
|
||||
"game/reconstructed/btl4gau3.cpp", # pilotList, PlayerStatus, MessageBoard
|
||||
"game/reconstructed/btl4gau1.cpp",
|
||||
"game/reconstructed/btl4grnd.cpp",
|
||||
"engine/MUNGA_L4/L4GAUGE.cpp",
|
||||
"engine/MUNGA_L4/L4LAMP.cpp",
|
||||
]
|
||||
|
||||
RISKY = re.compile(r"\.(DrawFilledRectangleToRelative|DrawBitMapOpaque|DrawBitMap|"
|
||||
r"DrawLineToRelative|DrawPointToRelative|"
|
||||
r"DrawFilledRectangleToAbsolute)\s*\(")
|
||||
CURSOR = re.compile(r"\.(MoveToAbsolute|MoveToRelative)\s*\(")
|
||||
FUNCHEAD = re.compile(r"^(?:\t|)([A-Za-z_][A-Za-z0-9_]*::[A-Za-z_][A-Za-z0-9_]*)\s*\(")
|
||||
|
||||
root = r"C:\git\bt411"
|
||||
findings = []
|
||||
for rel in FILES:
|
||||
path = os.path.join(root, rel.replace("/", os.sep))
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
lines = open(path, encoding="utf-8", errors="replace").read().splitlines()
|
||||
func = "?"
|
||||
func_start = 0
|
||||
last_cursor = -1
|
||||
for i, ln in enumerate(lines):
|
||||
m = FUNCHEAD.match(ln)
|
||||
if m:
|
||||
func = m.group(1)
|
||||
func_start = i
|
||||
last_cursor = -1 # cursor state does not carry across functions
|
||||
if CURSOR.search(ln):
|
||||
last_cursor = i
|
||||
mm = RISKY.search(ln)
|
||||
if mm:
|
||||
gap = (i - last_cursor) if last_cursor >= func_start else None
|
||||
findings.append((rel, i + 1, func, mm.group(1), gap, ln.strip()[:78]))
|
||||
|
||||
print("=" * 100)
|
||||
print("RISKY DRAWS WITH **NO** CURSOR SET IN THE ENCLOSING FUNCTION (top suspects)")
|
||||
print("=" * 100)
|
||||
none = [f for f in findings if f[4] is None]
|
||||
for rel, line, func, call, gap, src in none:
|
||||
print(" %-32s :%-5d %-42s %s" % (rel.split("/")[-1], line, func, call))
|
||||
print(" %s" % src)
|
||||
print("\n -> %d of %d risky draws have NO cursor set in scope\n" % (len(none), len(findings)))
|
||||
|
||||
print("=" * 100)
|
||||
print("RISKY DRAWS WHOSE CURSOR SET IS FAR AWAY (>12 lines -- may be on another branch)")
|
||||
print("=" * 100)
|
||||
far = [f for f in findings if f[4] is not None and f[4] > 12]
|
||||
for rel, line, func, call, gap, src in far:
|
||||
print(" %-32s :%-5d gap=%-4d %-38s %s" % (rel.split("/")[-1], line, gap, func, call))
|
||||
print("\n -> %d far-cursor draws" % len(far))
|
||||
print("\ntotal risky draws scanned: %d" % len(findings))
|
||||
Reference in New Issue
Block a user