Galaga's Playable Demo Analyzed and Fixed
by Don Hodges
Also: Read all about the Galaga No-Fire Cheat by Christopher Cantrell
It is fairly well-known that the 1981 arcade game Galaga has a bug in its program that allows the player to control the demo mode of the game.
Initially, the player seems to be able to control the ship's firing using the fire button. The demo also controls the ship's firing, so the two inputs seem to be mixed together.
If the player does not touch any controls, the game's demo always runs exactly the same way each time. During the demo, one of the ships gets captured and then rescued. After the rescue, the double ship is then destroyed by two separate collisions with the enemy bees.
We observe that not only can the player control the ship's firing, but the ship can also be partially controlled after the captured ship has been rescued and is a double ship.
Also, when the enemy boss deploys a tractor beam to capture the ship in the demo, if the player shoots at it and destroys it, he will gain full control of the demo and can then play for a short time, after which the game's watchdog usually kicks in and resets the game completely, or the script ends and the scoring demo resumes. Below are 3 examples of things that can happen in a controlled demo:
The main problem here is that the game is checking for and handling if the fire button is pressed during the demo, when obviously it should not be. The auxiliary problem is that the game is checking for and handling the left-right buttons when there is a double ship during the demo, when it should not be doing this either.
After lots of digging around in the assembly language code, we discover what appears to be the source of the problem.
Some useful material can be gleaned from Chris Cantrell's excellent page discussing the no-fire cheat. We see from a jump table that left-right movement is controlled in a subroutine at #1F8B, and the the player fire is controlled at code segment #1F0A. [These addresses differ slightly from the ones I use here because I am working from a newer ROM set than Chris.]
So, why is the fire button being checked in the demo and how can it be disabled?
It turns out that the jump table on Chris's page is controlled by an array of 32 memory locations from #9000 through #901F. The subroutine for the fire button being checked is controlled by changing memory #9015. If it is set to 0, there is no checking of the fire button. If it is set to 1, the fire button is checked and handled.
Using a MAME debugger, we discover the apparent source of this bug. When the demo starts, we see the following line executed. The register A is set to 1 when this line is called:
1860: 32 15 90 LD ($9015),A ; set task for checking the fire button from the player (!)
This seems to be a pretty glaring bug in the code, and one that should be easily fixed...
The Fix for Firing, First Attempt
When the demo starts, memory #9015 is already set to 0 - the player fire button is already ignored. So, we can attempt a fix by simply changing the code at #1860 to NOP commands (NOP is NO Operation - the command to do nothing).
1860: 00 NOP 1861: 00 NOP 1862: 00 NOP
When we test this fix, we see that it does indeed prevent the fire button from being checked. However, the demo no longer runs the way it used to - in fact it does some very weird things. This fix does not work in an ideal way. Why?
It turns out that another section of code checks memory location #9015 to do several things, like control the timing of when bees break formation to attack. If the player cannot fire, this attack is halted for a short time. The reason for this is to slow or stop the attack when a player ship is captured and when a captured ship is released.
The Fix for Firing, Second Attempt
There is another way to fix the bug, but it is more complex. We will insert a new patch into the check fire subroutine which checks whether the demo is playing, and if so, to return from the subroutine immediately. Again, from Chris Cantrell's page we can easily discover the line where the check fire subroutine begins and change it to a patch call. We also need to find which memory address is used to indicate when the demo is playing - it turns out to be #9201. Finally we need to find some unused memory space to put the patch - I am confident that #1FE7 through #1FFE is unused memory and can be used safely.
Patched code: 1F0E: C3 E7 1F JP $1FE7 ; jump out to patch to check for demo mode ... 1FE7: 3A 01 92 LD A,($9201) ; load A with game state indicator 1FEA: 3D DEC A ; are we in the demo? 1FEB: C8 RET Z ; yes, return without reading fire button input 1FEC: 3A 15 92 LD A,($9215) ; this is original code line, wiped by the patch 1FEF: C3 11 1F JP $1F11 ; return to program
This patch has been tested by using a MAME cheat code and it does work. When applied, the fire button no longer responds during the demo, and the demo appears to run otherwise normally.
The Fix for Ship Control, First Attempt
As stated above, even with the fire button fix, the player can still take left-right (not fire) control of the ship in the demo, after the double ship has been created. We see from Chris Cantrell's page that task #14 controls the left-right movement. This is set in memory location #9014. After some time and experimentation, we find the section of code where this is enabled, which is called right after the double ship is ready to play:
Original code: 20B1: 3E 01 LD A,$01 ; A := 1 20B3: 32 14 90 LD ($9014),A ; enable left-right movement task
Attempting to write a subroutine which is similar to the one above, while indeed fixing the demo so that the ship cannot be controlled, also breaks the way the demo behaves, causing some strange behavior. It turns out that the way the demo is scripted, it relies on the left-right control subroutine to be called when the ship is double. We need to patch it another way...
The Fix for Ship Control, Second Attempt
Similar to the working fix for the firing bug above, we insert a patch into the subroutine which checks for and controls left-right movement. The fix for this subroutine is more complicated because we can't just ditch out of the subroutine if we detect that the game is in demo mode. [This was tried as well and does not work] Let's have a close look at the original code of the left-right check subroutine, with my comments:
Original code: 1F93: 3A 15 92 LD A,($9215) ; A := 1 if player2 input, else A := 0 1F96: C6 B6 ADD A,$B6 ; add constant to create lower part of address #B6 or #B7 1F98: 6F LD L,A ; copy to L 1F99: 26 99 LD H,$99 ; HL now has input port address #99B6 or #99B7 1F9B: 7E LD A,(HL) ; load A with input from port 1F9C: ...
We observe that when no player controls are touched, the input port (#99B6) reads a value of #3F. So, this routine is called during the demo when there is a double ship, but if the controls are not touched the input is always #3F. Therefore we choose the overwrite the two instructions starting at #1F99 with the patch call, and we can use the unused memory from #1FF2-#1FFE for the patch:
Fixed code: 1F99: CD F2 1F CALL $1FF2 ; call patch to fix input during demo ... 1FF2: 3A 01 92 LD A,($9201) ; load A with game state indicator 1FF5: 3D DEC A ; are we in the demo? 1FF6: 3E 3F LD A,$3F ; simulate no input if this is the case 1FF8: C8 RET Z ; if demo, return with fake input of nothing 1FF9: 26 99 LD H,$99 ; original code wiped from patch line 1/2 - set address 1FFB: 7E LD A,(HL) ; original code wiped from patch line 2/2 - load input 1FFC: C9 RET ; return 1FFD: 65 ; checksum fix
This patch has been tested by using a MAME cheat code and it does work. When applied, the left-right controls no longer respond during the demo when there is a double ship, and the demo appears to run otherwise normally.
With these two patches in place, the demo is no longer controllable at all and runs exactly as it does when the controls are not touched.
The fix can be implemented in MAME using a cheat code: [NOTE: this only works in MAME version .126 and lower]
:galaga:20700000:1FFA:997EC965:FFFFFFFF:Fix Demo :galaga:20710000:1FF6:3E3FC826:FFFFFFFF:Fix Demo (2/8) :galaga:20710000:1FF2:3A01923D:FFFFFFFF:Fix Demo (3/8) :galaga:20610000:1F99:00CDF21F:00FFFFFF:Fix Demo (4/8) :galaga:20610000:1FEF:00C3111F:00FFFFFF:Fix Demo (5/8) :galaga:20710000:1FEB:C83A1592:FFFFFFFF:Fix Demo (6/8) :galaga:20710000:1FE7:3A01923D:FFFFFFFF:Fix Demo (7/8) :galaga:20610000:1F0E:00C3E71F:00FFFFFF:Fix Demo (8/8)
Learn all about MAME cheats at http://cheat.retrogames.com
Comments and Conclusions
It is amazing that this bug could go undetected by the people who created the game. I seem to remember discovering this bug when I played this game during my youth. The bug was never fixed, even though the game creators did release updates that fixed the no-fire bug.
Recently (December 2008) on a trip to Las Vegas, I found myself in the arcade inside the Excalibur Hotel/Casino. I came across a machine that had the Galaga / Ms. Pacman 20th anniversary edition. I didn't have any quarters and I suppose the arcade was about to close, because all of the change machines had been turned off. I remembered that the demo in Galaga was playable, and proceeded to play on the demo a few times for free.
|In accordance with Title 17 U.S.C. Section 107, some of the material on this site is distributed without profit to those who have expressed a prior interest in receiving the included information for research and educational purposes. For more information go to: http://www.law.cornell.edu/uscode/17/107.shtml. If you wish to use copyrighted material from this site for purposes of your own that go beyond 'fair use', you must obtain permission from the copyright owner.|