havoc-remaster/docs/FORMATS.md
pyr0ball 2287f3be12 Initial commit: Havoc preservation toolkit + format docs
- 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>
2026-06-28 23:33:30 -07:00

3.3 KiB
Raw Blame History

Havoc file formats (reverse-engineered)

All offsets/sizes verified against the retail data set (Reality Bytes, Inc., 1995).

Binaries

File Type Notes
HAVOC.EXE PE32 i386, GUI Imports DDRAW, DSOUND, WINMM, WSOCK32, GDI32, USER32, KERNEL32. No Direct3D — 3D is a software rasterizer drawing into a DirectDraw surface. Contains a CD-presence check ("...Extra Player CD...").
LAUNCHER.EXE PE32 i386, GUI Front-end menu (see havoc_9 screenshot).
SETUP.EXE PE32 i386, GUI Config/setup.
DIRECTX/ DX5-era Ships 16-bit DSETUP16.DLL/DDRAW16.DLL — the 16-bit installer path is what breaks on 64-bit Windows, not the game itself.

.FF — "FlashFile" archive implemented in tools/ff_extract.py

Used by MUSIC.FF, SOUND.FF, OBJECTS.FF, INTRFACE.FF. Built by the bundled DOS tool FFCREATE.EXE (found inside MUSIC.FF/SOUND.FF).

uint32  file_count                      (little-endian)
repeat file_count:
    uint32  absolute_offset             (little-endian, from start of .FF)
    char[]  name                        (NUL-terminated, variable length)
<concatenated payloads>                 entry size = next_offset - this_offset

Notes:

  • The table may contain a trailing empty-name entry — skip it.
  • Entry payloads are raw and self-describing (e.g. RIFF/WAVE, MZ, bitmaps).

Archive contents

Archive Count Entry kinds
MUSIC.FF 116 WAVE<id>.DAT PCM segments, PLST<id>.DAT playlists, FFCREATE.EXE
SOUND.FF 65 WAVE<id>.DAT sound effects, FFCREATE.EXE
OBJECTS.FF 526 ASND<id>.DAT … (enemy/pickup models + object sounds — format TBD)
INTRFACE.FF 547 BitB<id>.dat cockpit/HUD/menu bitmaps — format TBD

Music: WAVE segments + PLST playlists

  • WAVE<id>.DAT — standard RIFF/WAVE, PCM mono, 22050 Hz, 8-bit.
  • PLST<id>.DAT — a song = an ordered sequence of WAVE segments. Payload is big-endian (note: the .FF table around it is little-endian — mixed by design):
uint16  segment_count        (big-endian; how many WAVE segments belong to this group)
uint16  step_count           (big-endian)
uint16[step_count]  sequence  (big-endian; 1-based segment index)

Segment resolution: a playlist named PLST<id> has base id = int(id, 16); step value N maps to wave id base + N - 1 (e.g. PLST07D1 step 2 → WAVE07D2). Concatenating the referenced segments' PCM reproduces the song exactly (verified by ear).

World data (WORLDS/) — TODO (3D terrain)

Per-level sets <NN> = 01..06 plus N/N2 variants (biomes: desert, snow/ice, lava, ocean).

Pattern Guess Status
MAP<lvl>.MAP tile/heightmap grid, 1 byte per cell layout confirmed (byte grid); dims TBD
LAND<lvl>.DAT terrain geometry/tile defs TBD
GRAFIX0N.DAT terrain/texture tilesets TBD
STUF<lvl>.DAT entity placement (contains Item records) TBD

Other top-level data — TODO

File Notes
BIGFILE.DAT (64 MB) starts Copyright 1995, Reality Bytes, Inc. then embedded RIFF data — bulk audio/stream pool
STRDATA.DAT length-prefixed UI string table (Out of memory., Not enough disk space., …)
HAVOC.ICO 32×32 4-bit icon