(Or, how cheating at Arkanoid gave me a broken heart)
Published May 3, 2010. Last updated February 3, 2023
There are 33 rounds in the arcade game Arkanoid, when played normally: 32 “regular” rounds, where you knock out bricks Breakout-style, and the “boss” round, where you battle an Easter Island-looking creature named “Doh” by bouncing balls against his head.
Once you defeat Doh, the game is over.
Unless you cheat.
One of the handy cheat codes you can use with MAME enables the “warp door” at the bottom right of the playfield. This warp door lets you skip to the next round, and is activated normally by picking up the pinkish-purple “B” capsule seen below.
If you turn on this cheat when Doh is on the screen, you can bypass the game-ending logic that occurs when you defeat Doh: simply enter the warp and proceed on to the nonexistent Round 34.
Since the programmers did not anticipate a player using the warp on the “final” level, the data that points to the playfield structure for Round 34 is not properly initialized, and instead points to a part of memory that wasn’t intended for playfield data.
This results in differently-colored bricks scattered all over the screen, making it look a little like Pac-Man’s famous kill screen.
However, that doesn’t mean Round 34 is unplayable; in fact, you can rack up an amazing number of points on this screen since many of the bricks that appear on the screen aren’t normal bricks (worth a hundred or so points), but instead have wildly different point values, up to tens of thousands of points per brick!
If you keep the warp cheat enabled, you can bypass Round 34, and keep on plowing through subsequent levels, most of which have similarly scattered playfields, although a few have areas that resemble earlier, intentionally-designed playfields.
When you get to Round 129, though, the screen is identical to the very first playfield; the next screen is identical to the second, and so on.
But while the 32 screens starting at Round 129 are identical to their earlier counterparts, the 33rd screen is not: rather than re-playing the Round 33 battle against Doh, an entirely new screen appears:
It’s a broken heart. (Or maybe a heart with a zipper.) Note that the Round shows as “ROUNDD 1”; it’s actually Round 161.
This appears to be the only intentionally-designed level that never actually appears in the game as playable in an arcade (i.e. without using cheat codes.)
Why is it in there? Was one of the developers suffering from a broken relationship, or perhaps some unrequited love?
Interestingly, the sequel to Arkanoid features a similar, but different, heart level:
Is this also a broken heart, or is this more of a “two-hearts-intertwined” thing? Hard to say. Maybe the developers found true love in between the original game and the sequel. (Or, there were different, happier developers on the sequel.)
After you defeat (or warp past) the broken-heart level, Arkanoid returns to scattered-brick mode until the 256th round (“Round 0”), whereupon the game loops back around to Round 1.
Like many arcade games of that era, Arkanoid appears to store the current round number in a single byte of memory, and converts this byte to decimal digits when it needs to display the round number.
However, once you warp past Round 99, the byte-to-decimal-digits routine fails, and instead of displaying “ROUND100”, it instead displays “ROUNDGA0”.
Although “A0” is a reasonable substitute for “100” (since “A” in hexadecimal is “10” in decimal), it’s not immediately clear why there’s a “G” in there. As you continue to warp to higher levels, the “GA” is replaced with other characters, while the rightmost character cycles from zero to nine.
|34 – 99||ROUND 34 – ROUND 99|
|100 – 109||ROUNDGA0 – ROUNDGA9|
|110 – 119||ROUNDME0 – ROUNDME9|
|120 – 129||ROUNDOV0 – ROUNDOV9|
|130 – 139||ROUNDER0 – ROUNDER9|
|140 – 149||ROUNDRO0 – ROUNDRO9|
|150 – 159||ROUNDUN0 – ROUNDUN9|
|160 – 169||ROUNDD 0 – ROUNDD 9|
|170 – 179||ROUNDPL0 – ROUNDPL9|
|180 – 189||ROUNDAY0 – ROUNDAY9|
|190 – 199||ROUNDER0 – ROUNDER9|
|200 – 209||ROUNDRE0 – ROUNDRE9|
|210 – 219||ROUNDAD0 – ROUNDAD9|
|220 – 229||ROUNDY 0 – ROUNDY 9|
|230 – 239||ROUND##0 – ROUND##9|
|240 – 249||ROUND##0 – ROUND##9|
|250 – 255||ROUND##0 – ROUND##5|
Starting with Round 230, the letters are replaced with colored squares (represented by “#” in the table above.)
The fact that the playfields repeat after 128 screens is likely due to the way the playfield pointers are stored: since they’re probably 16-bit pointers, only 128 of them will fit in a (256-byte) page of memory. Therefore attempting to access the 129th playfield pointer will cause the logic to roll over to the 1st playfield pointer.
If this is true, the different Round 33 screens (Doh for the first one, the broken heart for the second one) suggests that special logic is being called for the first Round 33, although I’ve not taken a peek at the code at verify this.
An interesting feature about the scattered-bricks screens is that the silver bricks can take hundreds of hits before being destroyed. These are the bricks which occasionally offer tens of thousands of points, likely due to the fact that the brick score data points not to valid locations, but to memory locations that weren’t intended to be used as score data.
Update, and even more technical stuff
On the AtariAge forums, A.J. Franzman points out a pattern: starting with the “GA”, each pair of letters in that position spells out “GAME OVERROUND PLAYER READY”.
This suggests that the program is reading from a string like “ 1 2 3 4 5 6 7 8 9” in memory when deciding what to display on the screen in the hundreds and tens digit spot, and it moves two places to the right every time the ones digit flips from 9 to 0.
It further suggests that the “ 1 2 3 4 5 6 7 8 9” string sits in memory right next to the other words displayed, so when the round switches from 99 to 100, the program looks for the next two digits to display, and those happen to be the “G” and “A” from the “GAME OVER” string.
To fix this bug (if it can legitimately be called a bug, since the game was not designed with levels higher than 33 in mind) one could move the “GAME OVERROUND PLAYER READY” string elsewhere in memory and replace it with “10111213141516171819202122232425” (so it would display “ROUND100” instead of “ROUNDGA0”, “ROUND110” instead of “ROUNDME0”, etc.) This would allow the display of all rounds from zero to 255.
In other words, one could fix the problem without changing any program code, just by moving some string data around! (You’d also need to adjust the pointers to the “GAME OVER” and similar text to point to the text’s new location in memory, however.)
Of course, the display still wouldn’t be right exactly, since there’d be no space between the “ROUND” and the round number. Not to mention the fact that you’d still need to either design new levels or reuse existing ones for these “extended” rounds if you didn’t want the scattered-brick levels.
Leave a Reply