Gobbling Up Memory
9 years ago
General
I mentioned the type-in game "Viper" for the Commodore 64 and how it was a basic program with an assembly core. That led to some weird occurrences when the normal flow of the game was circumvented...
The way it worked was the BASIC portion of the program would run the menus, take the selections, set up the play field (drawing a border around the screen and the mazes if necessary), put the first star (the mouse/food) on the board and load relevant information (such as the selected speed) into memory locations. It would pick the starting location of the snake and load that location into memory and then flash the diamond character different colors at that starting location. Once the joystick was not centered, the BASIC programming invoked the assembly code.
The assembly would take joystick input, move the snake, update the tail, make the movement sound effect and delay for the proper amount of time based on the speed selection. If the location the snake was moving into was not an empty space, it would load the character code for what was occupying that location into a memory location and drop back to BASIC.
BASIC would then pick things up, checking the memory location to see what the snake had hit. If it was a solid block or the snake's own body, it jumped to the snake's death (head becomes a yellow star, simple sound effects, proceed to game over and score screens). If it was a star, it would do the appropriate sound effect, update the score, put a new star on the screen and jump back into the assembly routine. And if it was another character that it didn't understand, it would fall back into the assembly code.
Normally everything stayed contained, because there was always a solid-block border around the edges of the screen. The snake could not exit the screen without being killed. But there was a time I was fiddling with the program, looking at it and I started the BASIC code in the game loop. I ended up playing the game on a screen full of the BASIC program listing, instead of the standard arena.
Moving off the left or right side of the screen only caused the snake to wrap around to the other side, because they were all contiguous memory locations. But trying to exit the top or bottom of the screen... well... you might recall that the C64 had no memory protection and would let you gleefully alter any memory you'd like. And then you have to realize that screen memory sat right above "zero page" (containing all kinds of critical vectors and indexes and settings) and right below BASIC memory.
Moving the snake off the top of the screen was a recipe for crashing or at least scrambling the brain of the computer. It was just a matter of running into that critical register and the assembly code overwriting it with the snake character. Sometimes it would freeze, sometimes it would do an interrupt reset (the RUN/STOP-RESTORE combination, for those familiar) and half the time even after the reset it would be scrambled enough that you had to power off and back on. While researching this journal, I accidentally moved the snake off the top of the screen. I maneuvered blindly but after a few seconds the emulator barfed up a rainbow of graphic characters across the screen and froze solid.
Moving the snake off the bottom of the screen would send it tearing through BASIC memory. And it would corrupt BASIC memory as it went. The thing was, the main loop of the BASIC program was only two or three lines as long as the snake didn't collide with a character that mattered. You could run roughshod over the program and it would keep going as long as those three lines didn't get corrupted. Once they did, it would stop with a SYNTAX ERROR and if you listed the program you could see the damage and corruption that had been done.
Kinda funny... it gives a whole new perspective on a worm (or a snake, in this case) in your computer, damaging your data.
Viper had two unintended things that could happen.
The snake "moved" on the screen by updating the position of the head, drawing in a body character where the head used to be and then writing an empty space into the last piece of the tail (and a space or two beyond, to be safe). Because the body character made a nice repeating pattern and the snake moved a character space at a time, it was a convincing animation of movement.
But there was an edge case with the placement of the star. There was a subroutine to pick a random spot on the screen that was empty and this was used to pick the location of the new star once the current one was gobbled up. Every once in a rare while, the location picked for the star was directly at the tail of the snake. The star would be placed by the BASIC code, it would jump back to the assembly, which would animate the snake and write spaces into the locations at the end of the tail... erasing the star! You were then pretty much boned: there was no way to advance because there was no longer a star to gobble.
The other oddity had to do with the length of the snake. The number of stars eaten was kept in a BASIC variable and then poked into memory for the assembly code to reference. That number was doubled to come up with the length of the snake's body, i.e. every star eaten lengthened the snake by two spaces. The assembly code probably kept a table somewhere of the spaces the snake body occupied, adding to the front of it while erasing the end of it.
When the BASIC counter got to 128, the assembly code that handled the table look up would wrap around... an 8-bit memory location can hold a value from 0 to 255. So suddenly the assembly code would go from erasing the snake body 250+ characters down the line... back to two characters down the line. In effect, the snake would "shed" its long body and go back to being short, leaving the old long body in place on the screen as an additional obstacle. While this was a cool difficulty increase, it was also easy to get screwed: a star that ended up inside the coils of the shed skin could not be eaten.
I also discovered while researching that bug that if you were good enough to shed the skin and get the snake back to the point it was about to shed again, that the BASIC variable holding the number of stars eaten would reach 256. When it attempted to poke that value into memory for the assembly code, the program would crash with an ILLEGAL QUANTITY error because memory locations can only hold a value up to 255. But I assure you: if you could survive that long, then crashing the game is a testament to the sheer magnitude of your skill and luck.
The way it worked was the BASIC portion of the program would run the menus, take the selections, set up the play field (drawing a border around the screen and the mazes if necessary), put the first star (the mouse/food) on the board and load relevant information (such as the selected speed) into memory locations. It would pick the starting location of the snake and load that location into memory and then flash the diamond character different colors at that starting location. Once the joystick was not centered, the BASIC programming invoked the assembly code.
The assembly would take joystick input, move the snake, update the tail, make the movement sound effect and delay for the proper amount of time based on the speed selection. If the location the snake was moving into was not an empty space, it would load the character code for what was occupying that location into a memory location and drop back to BASIC.
BASIC would then pick things up, checking the memory location to see what the snake had hit. If it was a solid block or the snake's own body, it jumped to the snake's death (head becomes a yellow star, simple sound effects, proceed to game over and score screens). If it was a star, it would do the appropriate sound effect, update the score, put a new star on the screen and jump back into the assembly routine. And if it was another character that it didn't understand, it would fall back into the assembly code.
Normally everything stayed contained, because there was always a solid-block border around the edges of the screen. The snake could not exit the screen without being killed. But there was a time I was fiddling with the program, looking at it and I started the BASIC code in the game loop. I ended up playing the game on a screen full of the BASIC program listing, instead of the standard arena.
Moving off the left or right side of the screen only caused the snake to wrap around to the other side, because they were all contiguous memory locations. But trying to exit the top or bottom of the screen... well... you might recall that the C64 had no memory protection and would let you gleefully alter any memory you'd like. And then you have to realize that screen memory sat right above "zero page" (containing all kinds of critical vectors and indexes and settings) and right below BASIC memory.
Moving the snake off the top of the screen was a recipe for crashing or at least scrambling the brain of the computer. It was just a matter of running into that critical register and the assembly code overwriting it with the snake character. Sometimes it would freeze, sometimes it would do an interrupt reset (the RUN/STOP-RESTORE combination, for those familiar) and half the time even after the reset it would be scrambled enough that you had to power off and back on. While researching this journal, I accidentally moved the snake off the top of the screen. I maneuvered blindly but after a few seconds the emulator barfed up a rainbow of graphic characters across the screen and froze solid.
Moving the snake off the bottom of the screen would send it tearing through BASIC memory. And it would corrupt BASIC memory as it went. The thing was, the main loop of the BASIC program was only two or three lines as long as the snake didn't collide with a character that mattered. You could run roughshod over the program and it would keep going as long as those three lines didn't get corrupted. Once they did, it would stop with a SYNTAX ERROR and if you listed the program you could see the damage and corruption that had been done.
Kinda funny... it gives a whole new perspective on a worm (or a snake, in this case) in your computer, damaging your data.
Viper had two unintended things that could happen.
The snake "moved" on the screen by updating the position of the head, drawing in a body character where the head used to be and then writing an empty space into the last piece of the tail (and a space or two beyond, to be safe). Because the body character made a nice repeating pattern and the snake moved a character space at a time, it was a convincing animation of movement.
But there was an edge case with the placement of the star. There was a subroutine to pick a random spot on the screen that was empty and this was used to pick the location of the new star once the current one was gobbled up. Every once in a rare while, the location picked for the star was directly at the tail of the snake. The star would be placed by the BASIC code, it would jump back to the assembly, which would animate the snake and write spaces into the locations at the end of the tail... erasing the star! You were then pretty much boned: there was no way to advance because there was no longer a star to gobble.
The other oddity had to do with the length of the snake. The number of stars eaten was kept in a BASIC variable and then poked into memory for the assembly code to reference. That number was doubled to come up with the length of the snake's body, i.e. every star eaten lengthened the snake by two spaces. The assembly code probably kept a table somewhere of the spaces the snake body occupied, adding to the front of it while erasing the end of it.
When the BASIC counter got to 128, the assembly code that handled the table look up would wrap around... an 8-bit memory location can hold a value from 0 to 255. So suddenly the assembly code would go from erasing the snake body 250+ characters down the line... back to two characters down the line. In effect, the snake would "shed" its long body and go back to being short, leaving the old long body in place on the screen as an additional obstacle. While this was a cool difficulty increase, it was also easy to get screwed: a star that ended up inside the coils of the shed skin could not be eaten.
I also discovered while researching that bug that if you were good enough to shed the skin and get the snake back to the point it was about to shed again, that the BASIC variable holding the number of stars eaten would reach 256. When it attempted to poke that value into memory for the assembly code, the program would crash with an ILLEGAL QUANTITY error because memory locations can only hold a value up to 255. But I assure you: if you could survive that long, then crashing the game is a testament to the sheer magnitude of your skill and luck.
FA+

One of my favorite examples was the Wing Commander games. When Wing Commander I (and soon to follow II) came out, we were still using 1.44MB floppies to hold game media. Also, the PC of the day was the pentium 386 (but if you had the big money you could afford a pentium 486). I clearly remember time when playing the game that the amount of stuff happening on the screen had a direct impact on how fast the game ran. And again, this was a space shooter, so being able to "lead" or "follow" your target was a big deal. Cut to many years later before DOS was effectively obscured from us mere mortals using Windows, when the game was run on a beefier system, the ships moved so fast and the game processed so fast it was literally unplayable!
Skip ahead a big to Wing Commander III, and now the media is on CDs, and holy crap (!) there were full motion video segments in it! Of course, by today's standards they were barely watchable with video quality so poor you wonder how the hell they ever managed to green screen it into the game. But again, the game ran mostly on the processor of the day which was around the pentium II/III days. I remember the difference as I went back and tried to play it several years later when I got around to upgrading to a pentium IV. See, in the set up of the game it used to run a video test in which it would render a ship model and spin it in 3 axis to test if your system could "handle" it. On a pentium III, the ship would make a full rotation in about 3-4 seconds and this was good enough that you could actually run the game. But wow, when I played it on an upgraded system, the ship would *rotate* 3-4 times a second. What a difference! With the faster system, space battle was smooth and did not have the hiccups and jitters from the previous runs.
Your post also makes me think of a group of college kids huddled around someones PC in the dorms watching in awe as the intro for Command and Conquer ran. That was probably the first game I remember that used full motion video as a part of the game. Granted it was mostly cut scenes, but it wasn't just a gimmick that had been thrown into the game because they could.
Later that same group was huddled around probably the same PC in the same room, watching one guy play Wing Commander III and lending moral support and cheering him on.
I had forgotten about Falcon, which was another favorite of mine (although I played it on the Atari). Such a good simulator!