Hardware watchpoint on game_object+0x18 (runtime addr 0x2361064) fired during
active gameplay via MCP debug agent. Write at 0x4360A7 (MOV [ECX+18h], 0xB0)
inside on_deactivate_force_pause_state. Confirms existing static analysis:
- eax=0x47 (old gameplay state read just before write)
- esi=0x1c (WM_ACTIVATEAPP -- exact match to documented WM message)
- DAT_0047E578=0x47 (prev-state global saved correctly)
- game_object+0x20=0x47 (target state still 0x47, round-trip intact)
State 0xB0 (pause/deactivate) was already documented; this adds live confirmation.
The still-open symptom-2 (reset to menu on re-focus during gameplay) is not in
this state write -- it lies further along in ddraw_full_display_reinit.
Also records Item 3 watchpoint result: watchpoint on DAT_0047c488 fired at
0x40E998 (MOV [DAT_0047c488], EAX in player_cooldown_timers_tick -- the store
is in the caller, not inside compute_frame_delta_ticks_60hz_min1_clamp).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TN4Ytn3gdWRonNmHpisWQv
Ghidra decompilation environment stood up on Linux (headless, no sudo): JDK 21 +
Ghidra 12.1.2 in ~/tools, reusing the existing analyzed project at
tools/ghidra_project/ from the prior Windows session instead of starting fresh.
FPS-coupling investigation: traced the main game loop's per-frame path and found
the real root cause - compute_frame_delta_ticks_60hz_min1_clamp (0x4092D0) computes
correct delta-time from timeGetTime(), but clamps the minimum return value to 1 tick
even when zero ticks truly elapsed, causing simulation speed to scale with framerate
above 60fps. First patch attempt (NOP the clamp) crashed on level load because the
shared delta value has 203 read sites across 40+ functions and only 2 were checked
for zero-safety; reverted and archived as a documented lesson. The corrected fix
(busy-wait instead of lying) is designed but not yet built.
Pause-loop hang fixed: the pause command handler blocks the Windows message queue
in a tight GetAsyncKeyState polling loop (found while locating the cheat code
handler), which trips modern Windows' "Not Responding" hang detection if left
paused too long, permanently disconnecting input. Patched (HAVOC_NOCD_PAUSEFIX_v1.EXE)
to pump one message per loop iteration via the game's own existing message-drain
function; confirmed fixed by play-testing, including the related "alt-tab while
paused resets to menu" symptom. A separate "alt-tab while not paused" reset symptom
remains open.
New tracking docs: docs/FUNCTIONS.md (function-by-function RE progress),
docs/PATCH_VERSIONS.md (binary patch version log), docs/LEVEL_NOTES.md (level/AI
design quirks for the Remaster variant). Extended docs/PATCHES.md and
docs/METHODOLOGY.md with full discovery narratives including dead ends.