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.
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.
WHAT HAD I DONE?
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