Tales of the Rampant Coyote

Adventures in Indie Gaming!

My Worst Bug Ever

Posted by Rampant Coyote on February 7, 2012

Since I’m in crunch mode in le day job, I’m going for “easy” here with postings on the blog (mostly). So here’s a slightly modified reprint of a story from almost six years ago on the old blog. And yes, I have a tough time believing I’ve been doing this for that long. But since this year is the 30th anniversary of the Commodore 64 (GAH!!! I have a tough time believing I’ve been doing THAT for so long…), it seemed an appropriate time to dust this one off.

My Worst Bug Ever
I’m gonna tell you about a bug that destroyed a game.

Not destroyed as in, “ruined the player’s experience so that the game was no fun.” I mean as in “put a gun to its head and blew its codey bits so that it was never seen or heard from by mortals again.”

The Setting: The Commodore 64
To explain how this worked, I’m first gonna have to talk a little bit about the memory architecture of the Commodore 64, the scene of this particular crime. I’ll try not to be too technical here.

Everything that happens on your computer happens in memory (AKA “RAM”). You may store stuff out to your hard drive, but in order for the computer to actually do anything with it, it has to be read off of the hard drive (or CD-ROM, or USB memory stick, or whatever) and put into memory.

The C-64’s memory was laid out so that information that was on the screen occured in an area from memory location 1024 to memory location 2024. Think of it as a big block on street. Technical note: This was actually where the character data was stored… the screen was 40 characters wide by 25 lines. 25 x 40 = 1000 characters. So area 1024 to 2024. The color data was stored elsewhere, and there were lots of other fiddley bits in other memory locations you could squirrel with. Like creating custom character sets so that the letter “A” actually looked like a sword. And so forth.

The program memory was the next block down. Starting at location 2048. The program memory was where the actual code for running the game resided. Where I was programming in BASIC. In-between the screen-character memory and the program memory was this little chunk of memory that the system used for other things, and I don’t recall what it was used for. But it’s not important to the story.

The important thing to remember is that the character memory and the program memory were next-door neighbors, with the program memory just “below” the graphics memory.

The Set-Up
Back in those days, we stored everything on 5 1/4″ floppy disks. The Commodore 64’s 1541 disk drive was notorious for being both slow and flaky. It was crapping out on us, so my Dad had to take it in to get it repaired. This was on a Thursday, I think. He was supposed to be bringing it on Friday. So all day Thursday, and then all afternoon Friday, I was without a disk drive.

Bored Thursday night, unable to play any games without my drive, I decided to work on a game. A cool fake-3D game slightly reminiscent of the maze arcade game (“Space Paranoids“) in the movie TRON. I got some stuff hacked together, and left the computer on, since I couldn’t save my work until the disk drive was back.

Friday came, and I worked on the game some more. I was starting to get a little antsy about having a power outage or something, because by this point I’d put several hours into developing this game. I’d hate to lose it. Finally, 6:00 rolled by, and my dad came home.

Without the Disk Drive. Turns out the shop wasn’t able to fix it yet, and they weren’t open on the weekend, so he’d have to pick it up on Monday.

That meant I was going to be the entire weekend without a disk drive. No saving my game… no loading anything else up. The computer was pretty much useless for the entire weekend. EXCEPT, I reminded myself, for continued development on my game.

The Final Stretch
So I got back to work on the game, and worked on it off-and-on through Saturday and Sunday. I got it so you could drive around the maze (in sort of a stepwise fashion as seen in the old Wizardry and Bard’s Tale games). And I got the enemy ships (which vaguely resembled Recognizers from Tron) to appear. They didn’t really move yet – they were static targets. When I got home from school on Monday, I was almost afraid to TOUCH the computer, for fear that I’d accidentally type “new” or something and delete this game on which I now had over 10 hours of development invested.

Still, after the homework was done, I found myself a little bored. It was around 4:00 in the afternoon, my dad wasn’t going to be home for a couple of hours, and where our house was located we had lousy TV reception. So I shuffled off down to the computer. I’d put a couple more hours into the game, then my dad would come home with the repaired disk drive, I’d save the game, and then life would be back to normal again. I could waste time that night playing Ultima III.

The Gun Shot
It happened with a gunshot. A laser-gun actually.

I had a gun at the bottom of the screen that would fire up, towards a targeting cursor. The algorithm to have the laser (or “bullet”) fly to the target was mostly simple. You find the X,Y position of the target on the screen. You find the X,Y position of the bullet (which starts just above the launcher). You subtract the target’s position from the bullet’s position. That’s called the offset, and from that you can figure the direction of the bullet. Move the bullet in that direction every frame.

Now, I was using integer math, so I had to do some funky stuff to get it to fly in something resembling a straight line. One trick I did was recalculate the offset every frame, so the bullet might fly in a slightly crooked path, but would always eventually get to the target.

And then I’d just repeat every frame until the bullet’s position was the same as the targeting cursor’s position. Then I’d see if the targeting cursor (or laser) was over a valid target, and if so… boom.

Okay, it’s pretty primitive stuff. I was something like 13 or 14 years old when I did this, so cut me some slack! 🙂

So I tested the game again with the gunshot, about an hour before my Dad was supposed to get home.

I saw the laser appear briefly over the top of the gun, and then that was it. Something was wrong. I waited to see if anything else would happen to help me understand the bug. After a few seconds, I hit the “break” key.

And got a garbled message.

I tried to list my program, and saw nothing but a bunch of garbage. It was impossible to execute, or to even fix, as the computer was not responding correctly.


Solving the Crime
It took me only a minute to figure out what had happened.

I had made two mistakes:

#1 – I’d calculated the offset between the target and the bullet improperly. Instead of subtracting the bullet’s position from the target’s, I’d done it the other way around. So the bullet actually tried to fly in the OPPOSITE direction of where it was supposed to go.

#2 – I hadn’t written any defensive code to make sure that the bullet was restricted to the screen’s position. This isn’t something you wanted in final code (as it would slow the game’s processing down), but it would have been nice during development.

So my gun had actually fired BACKWARDS. Instead of flying up towards the targeting cursor, it had flown…. down. And since I was directly modifying memory to display the blast, it had fired down out of screen memory, into program memory. It had ripped through program memory, cutting a bloody (well, as bloody as bytes of code can get) swath through the entire thing. In fact, it might have been a double-barreled hit, as I was also directly writing to color memory at the same time, and that one had gone out-of-bounds.

Eventually, either the image or the color had ripped through the area of RAM that held the actual operating system code that normally got loaded on boot. Thus the garbled error message.

There was nothing left worth saving. Four days of work. I knew the risks, I took the chance, and I still blew it.

An hour later, my dad came home with the newly fixed (or was it simply replaced?) disk drive.

It’s so nice to have learned these lessons at an early age. But even though the game was crap, I was probably close to “done” on it anyway, and it would have been long gone by now, the memory still gives me pain.

Filed Under: Game Development, Retro - Comments: 12 Comments to Read

  • Califer said,

    Hahaha, guess I’ve been reading these a while. My first thought on seeing the title was “What, worse than the time you shot your own code?”

  • Rampant Coyote said,

    That, or I told you about it at some point. 🙂 Figured that’s a “best of” and could be reprinted.

  • Greg Squire said,

    Looks like you discovered the dangers of self modifying code at an early age. Written any other “viruses” lately? 😉 I did some similar things on my Atari 800XL, but I was always a bit leery about messing with registers and memory directly (so I didn’t do a lot of it). Fortunately now days we don’t have to write our programs that poke things directly into memory locations and are very “architecture specific”. We also now have processors that help protect (mostly) against this kind of thing, so that one program doesn’t clobber another one (386 architecture and beyond)

  • Wavinator said,

    Nice one. It reminds me of years ago trying to add mouse support to a game via inline assembly and managing to crash Windows… 3.1. I took it as a badge of honor (“I managed to crash WINDOWS!”), but then I had backups. 😉

  • Charles said,

    This reminds me… That I’m not a programmer 🙂

  • Eldiran said,

    I cringed while reading this — I feel your pain. Although it is somehow hilariously awesome that you could actually fire digital weapons that could inadvertantly destroy code. Perhaps your game ended up being a bit too Tron-like in that way :p

  • Xian said,

    I dabbled in programming, but that was years ago with GFA Basic on the Atari ST primarily. I work on routers and switches, and the configuration files on those are almost like programming, a scripting language at least.

    The worst mistake I made while working on a router was locking myself out of it, and it was 200 miles away. I was working on an access list for remote access to the router and I was remote myself – on the other side of the state. I had the list of IPs that were permitted to access it and started pasting them in and it just froze after the first line. My telnet session was dropped and I could no longer reconnect to a router a couple hundred miles away. The mistake I had made was that there is an unwritten “deny all” at the end of every access list in Cisco IOS. Since the first IP I had permitted was NOT the IP that I was connected from, the hidden deny all blocked me after that line was entered. I knew exactly what I had done, but there was no undo at that point. At least it was an easy fix. Since I had been locked out the configuration had not been saved, so I had to get someone local to reboot the router and it came back up to the last saved configuration.

  • hexagonstar said,

    Good story! It reminds me of the good old days of C64. Fun times, although I barely could code back then. I remember once when my C64 was broken. Strange, white bars appeared flickering over the screen so it had to go to the repair shop for TWO WEEKS! Imagine that! Two weeks without a C64 back then! The horror!

    Once I wrote a program in Basic when a friend came over. We wanted to go somewhere but I was still finishing my code. He was impatient and switched off the power switch near the tap where the C64 was connected to. I hadn’t saved yet and lost all of the code. I was mad all day at him.

  • Once said,

    Excellent story. The “virtual” laser gun killed your program for real 😉

  • Karja said,

    That’s another example of why coding assembly on the C64 was preferable to BASIC! If I recall correctly, I had a C128 and I used the built-in assembler to write the code. Whenever I wanted to test the game I soft rebooted into C64 mode. A soft reboot reloaded the OS parts, reset the interrupt pointers, rebooted the screen area and cleared the BASIC program area…but it didn’t mess up the rest of the RAM.

    So, as long as I had code around e.g address $2000 or $c000, it would survive.

    The downside to using the C128’s built in assembler was of course that it had no labels… When you did a jump somewhere, you had to calculate the offset manually. In retrospect I understand why most normal people used a proper assembler program…

  • Flatlander said,

    If it’s any comfort, you weren’t the only one: http://blog.danielwellman.com/2008/10/real-life-tron-on-an-apple-iigs.html

  • delve said,

    Worlds first example of cyber-warfare?