What is on the disks
Three MS-DOS releases were examined, all from the Internet Archive: EGA builds from November 1987 and January 1988, and a VGA build from February 1988. A fourth copy, the VGA release on 5.25" disks, has a second build of the executable.
Their files hold the caves, two picture formats and the executable. This page also covers when the cartoons play and a debug keyboard the game never mentions.
The disks
| Release | Built | Media | Graphics files | Worlds on the menu |
|---|---|---|---|---|
| EGA r871109 | 9 Nov 1987 | 2 x 5.25" 360K | .FIL, .CAR | hunter, scuba, cook, player, cowboy |
| EGA r880129 | 29 Jan 1988 | 2 x 5.25" 360K | .FIL, .CAR | hunter, cook, cowboy, space, body |
| VGA r880225 | 25 Feb 1988 | 1 x 3.5" 720K | .SCM, .CCM | hunter, cook, cowboy, space, body |
| VGA on 5.25" | no release number | 2 x 5.25" 360K | .SCM, .CCM | as r880225 |
The release number is the build date in the darkstar/tdc-database
listing, which gives every file's size and CRC32 for every release; each copy here
was matched against it. The images are plain FAT12, so a directory walk gets the
files off.
The 1987 release is the odd one out. Its CELLMAPS.BIN is 17,600 bytes:
twenty caves, byte for byte the first twenty of the 1988 file. It asks you to type a
world number where 1988 has pictures to choose from. The two 1988 releases appended
twenty more caves and share the cave file and a near-identical executable. The
hidden worlds page has the detail.
A second VGA executable
A copy of the VGA release on two 5.25" disks, from goodolddays.net and labelled
"1988, Unverified", has identical data files but a different
ROCKFORD.EXE: 31,805 bytes and CRC32 6558ca05, against
31,789 and 4503fd98. Unpacked, the data segment is identical. The code
differs by three small edits (two bytes inserted at 0xEA18, one at
0xFB0C, three deleted at 0x13C4D) and four identical
video-register constants changed from 5 to 1, with every later call and jump shifted
to match. All of it is display code: no table or rule changes, and no new world, cave
or art. It has no release number because tdc-database does not list it.
CELLMAPS.BIN, the caves
In the 1988 releases this one file is the whole level set, as plain as a format gets.
35,200 bytes = 40 caves x 880 cells
880 cells = 40 wide x 22 high, row-major
1 byte = 1 cell
No header, no compression, no per-cave metadata. Four things together prove the layout rather than merely fit it:
- 35,200 divides exactly by 880, leaving no room for a header.
- Read at 40 by 22, every cave has an unbroken steel border on all four sides.
0x74occurs exactly once in every one of the 40 caves.0x20occurs exactly once in every one of the 40 caves.
A wrong stride would not produce all four. The last two are the exit and the player start, one of each per cave; the first reading of this file had them the wrong way round (see the engine).
The cell values
Only 25 distinct byte values appear across all 40 caves.
| Value | What it is | Count |
|---|---|---|
0x00 | Space | 6,544 |
0x01 | Dirt | 13,508 |
0x02 | Steel wall | 7,263 |
0x03 | Brick wall | 2,738 |
0x04 | Magic wall, the timed converter | 96 |
0x08 | Expanding wall | 163 |
0x0C | Quicksand | 64 |
0x10 | Amoeba | 28 |
0x20 | Player start | 40 |
0x28 | Boulder | 2,126 |
0x2C-0x30 | Enemy, the family that yields treasure | 125 |
0x34-0x37 | Enemy, the family that does not | 412 |
0x38 | Fire tap | 7 |
0x70 | Evil worm | 3 |
0x74 | Exit | 40 |
0x78 | Treasure bonus | 2 |
0x7C | Time bonus | 9 |
0x84 | Good worm | 8 |
0x88 | Treasure | 2,017 |
0xC4 | Acid tap | 7 |
The low two bits of a moving entity are its facing, so 0x34 to
0x37 are one entity in four rotations, not four entities.
How this table was wrong
An earlier version was built by census: counting each cave's contents and reasoning about which values must produce a collectable for the cave to be finishable. The reasoning was sound and several conclusions were wrong, because a census only constrains the answer if you already know what the bytes mean.
This one comes from the loader, the code that turns an authored byte into a runtime cell, read instruction by instruction, and every correction cites the instruction behind it.
EGA: .FIL and .CAR
Every file is exactly 32,000 bytes.
32,000 bytes = 320 x 200 at 4 bits per pixel
= 4 sequential bitplanes of 8,000 bytes
Each plane is one bit per pixel, most significant bit leftmost: a straight dump of
EGA video memory, not a packed format, in the order blue, green, red, intensity.
.FIL holds a world's tile and sprite sheet, a 20 by 12 grid of 16 by 16
tiles. .CAR holds its cartoons, a 6 by 4 grid of 48 by 48 frames, of
which the game plays three rows (see when the cartoons
play).
The palettes are in the executable, sixteen registers and an overscan byte at a time. Matching them to worlds took an outside clue and then a check. That story is on the hidden worlds page, because the answer is about the world ordering.
VGA: .SCM and .CCM
320 by 200, one byte per pixel, and the palette travels in the file, which is the useful part.
[RLE image data, 64,000 pixels]
[01 1A] in most files, one more pixel past the end of the screen
[80] the terminator: exactly 0x80, with no value byte after it
[192 bytes] 32 RGB triples, 16-bit little-endian words, each 0-15
The run-length encoding is byte-oriented and four rules long:
0x80 -> end of the stream
0x00 -> nothing (allowed, unused)
n & 0x80 -> run of (n & 0x7F) copies of the next byte
otherwise -> n literal bytes follow
Every file fills the 64,000-pixel screen with values 0 to 31. The game does not
count pixels: it decodes until the terminator, so most files write one byte past the
screen, harmlessly, inside the same 64 KiB segment. The trailing
palettes fit the pictures: the title screen's ends in a grey ramp for the rock, the
jungle world's carries greens, the space world's blues. A .CCM has the
terminator but no palette; it reuses its world's.
So the VGA colours come from the game's own data, with no guesswork. That makes VGA the colour reference and EGA the curiosity, the reverse of how the work started.
When the cartoons play
Each world's cartoon sheet holds four six-frame animations, one to a row, which the
Amiga disk labels NEW, WIN, LOSE and
TIME: a level starting, a level won, a life lost, and time running out.
The PC loads every world's sheet into off-screen video memory and plays it over the
cave from the main game loop, using rows 2 to 4. Row 1, NEW, is never
read: Aleksi Sahala said the PC never shows the cartoons, and for this row he is
right.
Which row plays depends on how the cave ended. This was read from the January 1988 EGA executable on 11 October 2026 and has not been run.
| Cartoon | Row | Chosen when | Plays |
|---|---|---|---|
WIN | 2 | Rockford walked into the open exit with the quota met, and no key ended the cave | before the time bonus counts down |
LOSE | 3 | Rockford died with time still on the clock | when the death countdown reaches zero |
TIME | 4 | Rockford died with the clock at zero or below | at the same point |
Every death, from a hazard or from giving up with R, starts the same
countdown of eight. The clock loses a second every 60 timer ticks and below zero
kills Rockford the same way, which is how running out of time reaches the
TIME row. After a LOSE or TIME cartoon the
game takes a life.
How long one lasts
The six frames loop, each shown for 9 ticks of the 60 Hz timer (150 ms). A cartoon always runs at least 60 ticks, one second; after that any key or a joystick fire ends it, and otherwise it stops at 360 ticks, six seconds.
The VGA executable sets the same flags in the same places, but its own cartoon routine has not been read, so its timings are assumed to be the EGA's and are not confirmed.
In the two builds here
The faithful build plays the three cartoons by these rules, centred on Rockford;
the original's formula for the vertical position was not worked out, so the centring
is approximate. The port credits the time bonus as soon as the cave is complete, so
its WIN cartoon comes after the bonus, where the original's comes
before. VIP plays the same three redrawn at eight to
one. Neither build plays a cartoon in the five hidden worlds.
ROCKFORD.EXE
16-bit real mode, EXEPACK-compressed, and unpackable.
| Release | Packed | Unpacked | Real entry |
|---|---|---|---|
| VGA | 31,277 | 84,800 | 0E9F:02F7 |
| EGA | 29,451 | 142,880 | 1CFB:02F5 |
The unpack checks itself: on both files the compressed stream is consumed to exactly offset -1 just as the output fills exactly the declared length. A wrong decoder would not hit both bounds at once, twice.
The rules, in the game's own words
Strings survive compression and give up the entire rule set:
Collect enough treasures to open exit door.
Flying and falling objects will kill you.
Drop things on flying enemies to kill them.
Use fire button (space bar) to pick up treasures, push
things over, and blow up dirt.
The last describes a ranged action: fire acts on the adjacent cell in the facing direction without moving Rockford. In Boulder Dash the only way to clear a cell is to walk into it, and that difference makes this an arcade game rather than a puzzle game.
Four tables, read straight out of the executable
Per-cave quota, a treasure's score before the quota is met and after it, and the
time limit: forty words each, indexed by raw world * 4 + stage. A
faithful port needs all four. The Rockford Remake
Project transcribed them independently from the EGA executable twenty years ago,
and 160 of 160 values match.
The debug keyboard
Both 1988 releases carry a developer keyboard behind the pause screen, each a different one, and the game never mentions it: no prompt, no message, no menu entry.
To reach it, pause, then hold Up and Down together with Shift: 8 and 2 on the numeric keypad the game steers with. The VGA build accepts either Shift key, the EGA build only the left. Nobody holds opposite directions together by accident.
| Key | What it does |
|---|---|
| C | Collects one treasure, with its sound, and opens the exit if that meets the quota |
| L | One more life |
| M | Ends the cave and makes the next one the world's last |
| N | Ends the cave as completed, with no cartoon |
| P | A thousand points |
| S | One more second on the clock |
| T | Sets the clock to 2 and leaves the pause, so time runs out at once |
| U | Cheat off |
| Z | Cheat on |
Any other key returns to the ordinary pause. The EGA build has only L, N and P, and no cheat flag, so the keyboard grew between releases. With the cheat on, Rockford walks through anything, but he is not invulnerable: the game reads the flag in six places, none on a death path. The port reaches all six.
R, and a toggle that is really a patch
R is an ordinary key, not a debug key: it gives up on the cave, which counts as a death, and the manual calls it restart. The Rockford Remake page says it makes coins appear; it does not. s, next to it, toggles the sound.
The same page lists offset 0x0B98 of the packed EGA executable as a
toggle for dying; it is the byte the Rockford Patcher rewrites for its god mode.
Unpacked, the edit changes one byte, at 0x4300, which nothing reads as a
variable. It is the middle entry of a table of offsets for a 3 by 3 neighbourhood,
and the edit knocks it out of line with the other eight, so an explosion writes
where it was never meant to. That is a patch; the game shipped no such cheat.
It is hand-written assembly
Four independent checks agree, and each one on its own would be awkward to explain away.
There is not one compiler stack frame in either executable
A scan of both unpacked images for 55 8B EC - push bp
then mov bp,sp - returns zero hits across 84,800
and 142,880 bytes. Every DOS C and Pascal compiler of the period opened a
non-trivial function that way. An optimised build would still have some; zero means
a different kind of program.
There is no BP-relative addressing at all
No stack locals or stack parameters anywhere in the image. Variables are
absolute ds: globals throughout.
Arguments are passed in registers
The entry point sets up calls as mov al,0Fh / mov bl,07h
/ call, and the callee reads them straight out of the registers.
No DOS C compiler did this in 1987: cdecl put every argument on the
stack, and Borland's __fastcall did not exist until 1990.
Subroutines save whatever they happen to use, by hand
11327: push bx / push cx / push dx / push di / push si
...
1138F: pop si / pop di / pop dx / pop cx / pop bx / ret
bx, cx and dx are caller-saved scratch
under every DOS C convention, so a compiler would not preserve them. The pattern
occurs 21 times in each image.
Two details support this. The stack segment holds 64 repeats of the literal
STACK , exactly what DB 64 DUP('STACK ')
in a MASM stack segment produces. And the strings contain no runtime library of any
kind: no __acrtused, no DGROUP, no divide-by-zero handler
text, no vendor banner. The only English in the binary is the game's own.
The lineage has layers. The strings say Adapted from
Amiga version and credit the MS-DOS version to Synergistic Software,
programmed by John Conley, so this MASM code is a port. So was the Amiga version:
Rockford began in 1987 as an arcade game for Arcadia Systems, on a board built
around the Amiga, and Icon Design converted it for the Amiga home computer. Its
programmer, Laurence Vanhelsuwé, has said he wrote it all in 68000 assembly.
The arcade code has never been dumped. Behind them all is the 1984 Boulder Dash,
6502 code on the Atari 800. See the other
versions.