The project hasn't been a WormKit DLL for a long time — it requires a
custom launcher. Rename the crate to openwa-dll with output openwa.dll
to match the rest of the naming convention (openwa-core, openwa-launcher).
Updates all references across Cargo.toml, Rust sources, PowerShell scripts,
CLAUDE.md, skill files, and docs. Replaces stale "wormkit hook/shim"
comments with accurate descriptions. Three remaining "WormKit" references
are legitimate (refer to the actual WA modding framework).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6-task plan for porting WA's .spr sprite loading to Rust with
ParsedSprite parser in openwa-core and hook replacements in openwa-wormkit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Launcher passes /silentcrash to WA.exe in headless mode, preventing
the crash handler from relaunching with /handlecrash and showing the
"Fatal error" dialog that blocks test execution
- Hook ERRORLOG.TXT creation via OPENWA_ERRORLOG_PATH env var to
redirect crash logs to per-test paths in the run directory
- Detect crashes by NTSTATUS exit codes or ERRORLOG.TXT presence,
show CRASH status with exception details and first 20 lines of
the error log (using lossy UTF-8 for binary memory dumps)
- Strip ANSI color codes when stdout is not a terminal
- Add RE notes for Frontend__MainNavigationLoop (crash handler mechanism)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The only creation site for this task type is FireWeapon__Girder (0x51E350).
The "FireBall" name was a legacy RE guess; it's actually a short-lived
terrain placement task for girder/bridge objects.
Rename in ClassType enum (26 = Girder), weapon.rs comments, task-hierarchy
docs, and Ghidra labels.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat: add #[vtable(...)] attribute macro for typed vtable definitions
Expands the document from "partial fix, investigation continues" to the
complete seven-bug resolution story. Adds phases 2-4 covering RNG tracing,
sub-object hashing breakthrough, hook binary search, and all root causes.
New lessons on Ghidra element indexing, buffer layout verification, and
the value of multiple test replays.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Constructor correctness (match original WA behavior):
- Load debris.spr and back.spr unconditionally, not gfx_mode-gated
- Initialize PaletteContext for masks.img (word=1, word=0xFE, Init)
- Document PCLandscape param_5 as game_info+0xDAAC
Debug tooling improvements:
- Hardware watchpoints: EBP-based stack trace on every hit
- Watchpoint base selection: OPENWA_WATCH_WRAPPER, OPENWA_WATCH_DISPLAY
- Display watchpoint arming during constructor for field tracing
- Snapshot: walk parent chain to CTaskTurnGame (true entity root)
Add docs/re-notes/desync-investigation.md — writeup of the longbow
desync investigation methodology and findings.
NOTE: Longbow desync (4 checksum mismatches) is NOT yet resolved.
These changes are correctness fixes and tooling for continued work.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
docs: update weapon-system.md with SubtractAmmo investigation results
Verified all 5 call sites for SubtractAmmo (0x522680):
- CTaskWorm: Teleport (0x28)
- CTaskTeam: selected weapon (dynamic)
- FUN_0055F8C0: DamageX2 (0x43), CrateSpy (0x44)
Hook is correct — never triggered because test replay doesn't use
those weapons. No rename needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: correct WeaponTable layout — no header, add entry fields
InitWeaponTable analysis revealed the weapon table is a flat array of
71 × 0x1D0 = 0x80B0 bytes with NO 16-byte header. The previous struct
had a phantom _header that made address math accidentally correct but
mislabeled the field being checked.
WeaponEntry now has proper fields:
- panel_state (+0x08, init 0xFFFFFFFF)
- defined (+0x10, checked by CheckWeaponAvail)
- availability (+0x24, init 0xFFFFFFFF, then 0/1 per weapon)
- enabled (+0x28, init 1)
check_weapon_avail now reads `entry.defined` instead of misnamed
`entry.name1`. Updated weapon-system.md to match.
Verified: headless PASS (byte-identical), headful 133+3 PASS / 0 FAIL.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Incremental strategy: 7 usercall functions ported to pure Rust (Groups A-C),
10 stdcall constructors hooked individually (Groups D-G), with headful+headless
replay tests after each group.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Incremental approach: decompile and map fields, create DDGame::new()
with bridges for sub-calls, then eliminate bridges one at a time.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
docs: document replay system architecture and spacebar advance mechanism
Fully traced the spacebar-to-advance-replay chain through Ghidra:
keyboard -> TurnGame+0x1F4 -> HurryHandler -> DDGame+0x7E41 -> GameFrameEndProcessor -> local Hurry message (0x17).
Adds 11 replay/turn function addresses and 6 DDGame replay offsets to address.rs.
Creates docs/re-notes/replay-system.md with full findings including
the Option A direct control strategy (set DDGame+0x7E41 from DLL).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: replay fast-forward via PostMessage + WndProc subclass
Automatically fast-forward through entire replays during testing by
posting WM_KEYDOWN/WM_KEYUP spacebar messages with 50ms gaps. Subclasses
the game's WndProc to intercept WM_ACTIVATE/WM_ACTIVATEAPP, making WA
think it always has focus so input works even when the window is in the
background.
- Add input.rs with PostMessage loop + WndProc subclass
- Update validation auto-capture: dump at 8s, 120s safety timeout
- Update replay-test.ps1 with 150s timeout
- Add DDKeyboard::PollKeyboardState address
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
refactor: add RQ_ prefix to render queue addresses, label pipeline in Ghidra
Rename all RenderQueue enqueue function constants with RQ_ prefix for
consistency (e.g., DRAW_PIXEL -> RQ_DRAW_PIXEL). Add 20 new address
constants for helpers, pipeline functions, and the type 0xE enqueue.
Label 25 functions in Ghidra including 7 RQ helpers and 7 render
pipeline functions. Document complete render queue system in
docs/re-notes/render-queue.md.
Research findings:
- All 11 standalone enqueue functions identified (types 0-14 switch,
but types 3/7/10/12 have no standalone enqueue — inlined or unused)
- DDDisplay vtable drawing method map (12 slots at 0x2C-0x58)
- Render pipeline: RenderFrame -> GameRender -> RQ_RenderDrawingQueue
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: reverse engineer sprite system — docs, types, and Ghidra labels
Design for launching WA.exe with replay files for automated
validation and RE discovery. Validator DLL detects automated mode
via OPENWA_REPLAY_TEST env var and self-terminates after capture.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
docs: add configuration system design and implementation plan
Design doc and implementation plan for porting WA's configuration
subsystem (Theme I/O, Registry, GameInfo, CrashReportURL) to Rust.
These were used to guide the config.rs implementation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: add typed scheme payload structs + field accessors
Add SchemeOptions (36B), WeaponSettings (4B), and ExtendedOptions (110B)
structs with from_bytes/to_bytes for safe typed access to .wsc payload
fields. Include V3 ROM defaults, scheme weapon order table, and 8 new
tests covering typed field access, roundtrips, and version boundaries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the complete frontend navigation state machine:
- Main navigation loop at 0x4E6440 (CWinApp::Run, 19KB)
- g_CurrentScreen (0x6B3504) drives screen dispatch
- 20 dialog constructors mapped to screen IDs
- Bitmap font system: 4 font sizes, glyph renderer, textbox API
- Display wrapper at 0x79D6D4 with 6 backend variants
47 new Ghidra labels applied (functions, globals, dialog ctors).
38 new address.rs constants: dialog ctors, font system, display globals.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: add offline test harness that loads WA.exe and calls its functions
Loads WA.exe into a 32-bit test process via LoadLibraryExA with
DONT_RESOLVE_DLL_REFERENCES, patches the IAT (445 imports), initializes
the statically-linked MSVC CRT heap, and successfully calls WA.exe
functions including malloc and CTask::Constructor.
9 tests: PE loading, vtable validation, prologue checks, IAT patching,
malloc wrapper call, and CTask constructor call with SEH support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ASLR rebasing (GetModuleHandleA) — WA.exe loads at 0x90000, not 0x400000
- Replace retour constructor hooks with global pointer polling (10s delay)
Hooks crashed due to retour trampoline splitting SEH prologues
- Fix DDGameWrapper constructor: __stdcall with 7 params, not __thiscall
Confirmed via RET 0x1c and stack parameter access patterns
- Fix CTask constructor: __stdcall with 3 params, not __thiscall
Confirmed via RET 0xc
- Add G_GAME_SESSION (0x7A0884) global for polling DDGameWrapper at runtime
- Fix DDGameWrapper struct: +0x4C0 is not GfxHandler, +0x4D4 is sound ptr
- Remove retour dependency (no longer needed, builds on stable Rust)
- Add missing prologue bytes: 0x64 (FS: SEH), 0x85 (test), 0x8D (lea)
Results: 78/78 static + 6/6 deferred = 84/84 all passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add frontend screen system: ScreenId enum and 21 named functions
Map the MFC CDialog-based menu system from 65 decompiled call sites.
Add ScreenId enum with 18 screen IDs (main menu through lobby).
Name 21 frontend/lobby functions and 4 global variables in Ghidra.
Add 25 new addresses to address.rs (14 frontend + 7 lobby + 4 globals).
Document screen transition architecture in frontend-screens.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add DDGame engine architecture structs and subsystem types
Define DDGame (0x98B8), DDGameWrapper, PCLandscape, DSSound, and
OpenGLState repr(C) structs with compile-time size assertions.
Add 9 subsystem vtable addresses to address.rs. Document the
engine initialization chain and update memory map with DDGame layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Initial openwa-types crate: enums, structs, and RE addresses
Bootstrap the Rust type foundation for WA 3.8.1 reverse engineering:
- Cargo workspace with openwa-types crate
- Enums translated from wkJellyWorm: ClassType (34), TaskMessage (83+),
Weapon (71), SoundId (126), SpriteId (696)
- Fixed-point math newtype (16.16 format, 0x10000 = 1.0)
- CTask and CGameTask struct stubs with compile-time size assertions
- 80+ known addresses: vtables, constructors, gameplay, rendering, sound
- RE documentation: task hierarchy, vtable layouts, memory map
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>