WORLDS/GRAFIX0N.DAT is a big-endian (Mac-origin) tileset: an 8-byte header
(file size at 0x08, entry count at 0x0c), 16-byte entry records (BE offset +
id), and per-graphic blocks with a BE width/height/frames/id header followed by
w*h*frames 8-bit palette indices. Confirmed against the in-game loader at
0x444db0 (16-byte record stride, BE->LE dword swap).
GRAFIX00.DAT decodes to 29 graphics: explosion (id 901, 8 frames), smoke
(id 911, 8 frames), and 27 single-frame 64x64 structure/wall textures
(ids 8001-8028). tools/grafix_extract.py renders them to PNG with any
768-byte RGB palette (the XPAL palettes from INTRFACE.FF work).
- tools/grafix_extract.py: parser + PNG renderer
- docs/FORMATS.md: GRAFIX0N.DAT spec
- README: status update
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TN4Ytn3gdWRonNmHpisWQv
Diagnosed and fixed the crash that killed HAVOC_NOCD.EXE ~1s after launch
(dgVoodoo window appears black, then the process exits). It was not a clean
exit: an ACCESS_VIOLATION (null-pointer read at VA 0x444E6A) during init.
Root cause is a copy-protection check in the WORLDS\ data-file loader
(0x42a480). It opens each file (GRAFIX/LAND/MAP/STUF) from both a local
"WORLDS\<name>" path and a CD-drive path (HAVOC.INI [SETUP] DRIVE=D:\), and
returns a valid stream only when the local open fails and the CD-drive open
succeeds. With files present locally and no D: drive it returned NULL, and the
GRAFIX loader (0x444db0) dereferenced that NULL without checking.
Fix: 14-byte patch at FO 0x29a2b rewrites the return decision to hand back the
successfully-opened local object. The game now boots to the title screen
("HAVOC(tm) by Reality Bytes"), responsive, main loop running.
- docs/PATCHES.md: full patch table (28 patches) + crash write-up
- tools/: RE + patching scripts (r2pipe disasm, minidump parser, ctypes
debugger, PE/IAT/import analysis)
- run_probe.bat / run_and_log.bat: reliable native launch for repro
- .gitignore: exclude CD images, Ghidra install/project, dgVoodoo, *.ini
Diagnosed via WER minidumps (%LOCALAPPDATA%\CrashDumps) parsed in pure Python
(no cdb/windbg available).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TN4Ytn3gdWRonNmHpisWQv
BitB/BitR/XPAL/STR# system fully reverse-engineered:
- BitB<id>.dat: big-endian uint16 width/height header
- BitR<id>.dat: raw 8-bit palette-indexed pixels (no header)
- XPAL<id>.dat: 256 RGB triplets, 8-bit per channel
- STR#<id>.dat: length-prefixed UI string tables
- Runtime patch: index 2 must be forced to black (0,0,0) --
the game engine overwrites this at runtime but stored values vary
Discovery: XPAL7A12 (correct render) vs XPAL7A1C (salmon background)
differ in only 3 palette entries (0,1,2); index 2 is the canvas black.
All 32 full-screen menu backgrounds, 57 vehicle HUD icons, cockpit
windshield frames, vehicle selection screens, and button strips now
render correctly. Documented in docs/FORMATS.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ff_extract.py: .FF (FlashFile) archive extractor with music song
assembly (WAVE+PLST), ogg/mp3 conversion, and FL Studio pack export
(samples + per-song MIDI + mapping).
- docs/FORMATS.md: reverse-engineered file formats (.FF, WAVE/PLST music,
world data + binary notes).
- Original game data is gitignored (copyright Reality Bytes, 1995).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>