Oracle: "crouch wasn't resetting on respawn ... mechs always spawn standing".
Correct -- Mech::Reset (@0049fb74) stands the mech up and the port cleared
none of it:
*(this+0x398) = 0 duckState
Set_Alarm_Level(this+0x39c,0) legStateAlarm -> standing
Set_Alarm_Level(this+0x714,0) bodyStateAlarm -> standing
*(this+0x650/0x654/0x658) = 0 death + leg/body reset latches
*(this+0x5ac) = 1.0f idleStrideScale
A pilot who died CROUCHED came back crouched -- leg parked in 'sqd' -- and now
that the cockpit strip works, showing the up-arrow "press to rise" frame on a
standing mech.
Benched (crouchrespawn.sh): A squats, dies while down, respawns -> legLvl 0
(standing) after Mech::Reset. Weak but the failure mode (stuck legLvl=1) is
absent. NB the first attempt was void: force-damage kept A dying before it
could crouch (legLvl 22/24 = death clips), so the run tested a STANDING death.
Switched to self-damage so the mech is stopped long enough to crouch.
Also carries the #142 gauge work: the crouch strip is a BUTTON-STATE indicator
(grey unavailable / orange down-arrow ready / orange up-arrow crouched),
decoded by rendering BDUCK.PCC rather than inferring it; and the gauge
factory's missing-image path no longer uses the no-op DebugStream.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NCJQkvq6G2JNrpVbA75tVZ
50 lines
2.2 KiB
Python
50 lines
2.2 KiB
Python
"""Audit Mech::Reset (@0049fb74) -- every field the binary clears vs ours.
|
|
|
|
Motivated by finding EIGHT dropped posture clears (duckState, both state alarms,
|
|
the death/reset latches, idleStrideScale) in the port's Reset, and by #137
|
|
"respawn came back with MYOMERS heat MAXED" + Sauron's overheating generator D:
|
|
if the reconstruction dropped the posture clears it may have dropped others.
|
|
"""
|
|
import io, re
|
|
|
|
DECOMP = r"C:\git\bt411\reference\decomp\all\part_012.c"
|
|
HPP = r"C:\git\bt411\game\reconstructed\mech.hpp"
|
|
CPP = r"C:\git\bt411\game\reconstructed\mech4.cpp"
|
|
|
|
# --- 1. every offset the BINARY's Reset touches ---------------------------
|
|
lines = io.open(DECOMP, encoding="latin-1", errors="replace").readlines()
|
|
body = "".join(lines[14191:14400]) # FUN_0049fb74
|
|
bin_off = sorted({int(m, 16) for m in re.findall(r"param_1 \+ (0x[0-9a-f]+)", body)})
|
|
|
|
# --- 2. offset -> our field name, from mech.hpp's offset comments ---------
|
|
name_of = {}
|
|
for ln in io.open(HPP, encoding="latin-1", errors="replace"):
|
|
m = re.search(r"^\s*(?:[A-Za-z_][\w:<>* ]*?)\s+(\w+)\s*(?:\[\d+\])?\s*;.*?(?:@|//\s*)0x([0-9a-fA-F]+)", ln)
|
|
if m:
|
|
name_of.setdefault(int(m.group(2), 16), m.group(1))
|
|
|
|
# --- 3. what OUR Reset assigns -------------------------------------------
|
|
cpp = io.open(CPP, encoding="latin-1", errors="replace").read()
|
|
i = cpp.find("Mech::Reset(const Origin &origin, int mode)")
|
|
ours_body = cpp[i:i + 9000] if i != -1 else ""
|
|
ours = set(re.findall(r"^\s*(\w+)\s*(?:\.\w+\([^)]*\)|=)", ours_body, re.M))
|
|
|
|
print("Mech::Reset @0049fb74 -- %d distinct fields touched by the binary\n" % len(bin_off))
|
|
missing, covered, unknown = [], [], []
|
|
for off in bin_off:
|
|
nm = name_of.get(off)
|
|
if nm is None:
|
|
unknown.append(off)
|
|
elif nm in ours:
|
|
covered.append((off, nm))
|
|
else:
|
|
missing.append((off, nm))
|
|
|
|
print("COVERED by our Reset (%d):" % len(covered))
|
|
print(" " + ", ".join("%s@0x%x" % (n, o) for o, n in covered) + "\n")
|
|
print("*** NOT CLEARED by our Reset (%d) -- named fields the binary resets ***" % len(missing))
|
|
for o, n in missing:
|
|
print(" 0x%-5x %s" % (o, n))
|
|
print("\nUNMAPPED offsets (%d) -- no named field at that offset in mech.hpp:" % len(unknown))
|
|
print(" " + " ".join("0x%x" % o for o in unknown))
|