How I Hacked My First Game

It wasn't that hard, really, and I didn't actually change any of the data.  That Lode Runner lets you edit levels helped immensely, so Lode Runner is probably the easiest to look into.  What I did first was to create a simple C application("Wiff", short for WinDiff.)  It read two files and compared them byte by byte.  When two bytes were not equal it reported the miscompare up to a maximum number of miscompares.

I figured they wouldn't have anything too complex;  although popular graphics formats like GIF and JPG are mind-numbingly complex, that is because they save space when transmitted, and security codings are not used unless the information needs to be secure.  This is just a game, and besides, when Lode Runner was written, they didn't even have LZW compression--if you don't know, don't ask!  (Okay, it's how ZIP files are compressed.)  By the way, bitmaps(*.bmp) may look confusing but they are really orderly.  Wotsit.org is one place that tells how bitmaps are created.  Once you get past the terminology, you'll realize there is only so much to see.  File format specifications are created to make things simpler, at least in the long term.

From there I used the level editor.  I had one file lrdata.dsk which I used in my Apple Emulator.  I copied it to lrdata2.dsk and changed the top left square in level one in lrdata2.dsk.  Then I ran my Wiff and noticed which byte changed.  If it was only one, that would make things a lot less complicated.  I changed the top left square back and shifted to the second.  What I noticed was that each "block" was a value of 0 to 9(which corresponded to the values in the editor) stored in a "nibble"(four bits, decimal value 0 to 15).  There were 28x16 total squares in a level, making for 28*16/2=224 bytes in a level.  But where did the next level start?

For that answer I changed the top left square in level two.  I noted that the top left square in level 1 was determined by byte 12288(0x3000 in hexadecimal) and the top left square in level 2 was stored in 12544(0x3100 in hexadecimal).  The difference was 256 and 256-224(bytes in a level) gave spacing of 32 bytes.

The algorithm seemed pretty clear, then.  You started at offset 0x3000(it turned out that this worked for Lode Runner data disks, the boot disk, and Championship Lode Runner!  Even if it hadn't there are hexadecimal editors where I can search for a certain pattern, since I know what the map must look like, and I can find the offset!)  You read in a byte, with the "low nibble" corresponding to the square on the left.  After you got up to byte 224, you skipped 32 bytes and then started again.  I figured this was the pattern for the whole disk;  otherwise, it'd be a nightmare to figure out.  Thankfully, I was right.

File stream output is a hassle to learn but easy once you know it.  I generated text files, one per level, based on the nibbles.  For those of you who know C, it is below(I left out declarations and fopen/fclose calls.  The precise code is elsewhere on the site!):

fputs("d28x16\n");  for (count=0;  count < 224;  count++)
{x=(long)fgetc(F1);  lobyte=(char)(x&0x0f);  hibyte=(char)(x>>4);  fputc(lobyte + '0', F2);  fputc(hibyte + '0', F2);}
for (count=0;  count<32;  count++) fgetc(F1);

The casting is necessary because otherwise a byte like 88 will be read as negative and 88>4(shift bits over 4) will become xf8, and what should be 8 is ).  This gave me a nasty shock at first.  But there always seem to be details to clean up.

I had the text files, and I already had a program that converted the text files to bitmaps, if you had icon files.  Creating the icon files was not too hard;  I took a screen shot and determined the widths and pixels.  The icons were an odd 10x11 shape, but they look great, as we know.  I then ran another C program(PERL is more effective, but that's another story!) to create a huge batch file that would convert the text files for each level to bitmaps and then gifs and remove the bitmaps.

I had a bunch of graphics but no good way to display them.  So with another few lines I created something that would, given a number and a template file, write the appropriate links in.  The code's simple once you get used to it.  I had a few disasters at first, but the good thing is, once it's in place, it works fine.  I'm sure there will be quirks, but I am pretty sure I can iron them out.  Meanwhile, enjoy the pictures!

On a related note I tried to find out how to change the high scores.  I saved lrdata.dsk, copied it to lr2data.dsk, and played a game on lr2data.dsk.  I pretty much self-destructed on level 1, scoring 1250, and signed myself "XXX."  My Wiff program noticed that on lrdata.dsk bytes 52992-52994 were -40, 52995 was 1, and 52998 was 18, and 52999 was 80.  I ran the program again, scored 1000, and noticed bytes 53000-53002 were -40, 53003 was 1, 53006 was 16.  All miscompares were 0 on lr2data.dsk.  I figured "X" was 40 and value=-64+letter of alphabet.  The level was the next byte.  What confused me were the hexadecimal values, until I wrote them out.  18 decimal = 12 hex.  80 decimal = 50 hex.  Put them side-by-side and get 1250 hex.  1250 was my score.  Note 16 hex and 0 hex give 1000, my score the second game.  So we have a block of 80 bytes, 8 bytes per high score.  Bytes 8x+4 through 8x+7 are, when shown as hexadecimal, the high score.  So it'd be easy to change the high scores in a hex editor;  I in fact have given myself a score of 12345678 on level 240.  But what happens if you get to level 256 and above and score over 99999995 points?  Does the level counter reset?  Does the score?  I don't have the time but if we could make a very easy level and automate it(for instance, no gold chests, and you start at the top--that'd solve the question of levels!) we could find out. 1