← All articles

Why Galaga's Bees Stop Shooting

Anyone who spent time around a Galaga cabinet has heard of the trick. On the first stage, shoot everything except the bees in the bottom left corner. Then dodge them. Keep dodging while they swoop down, fire, and loop back up, for something like fifteen minutes. Eventually they stop firing. Shoot them, and for the rest of the game no enemy fires a single shot. You can play on for as long as you can stay out of their way.

It sounds like a cheat code, the kind of thing a programmer would hide on purpose. It is not. It is what happens when one bullet out of every few hundred lands on the one position the game treats as "not there", and the game has room for only eight bullets.

This article follows an enemy bullet through the original 1981 program, the code that ran on the arcade boards, and shows where it gets lost. It also looks at a later revision of the program that Namco shipped, which quietly closes the hole with four extra bytes.

Three processors sharing a desk

Galaga's circuit board has three Z80 processors, the same chip that ran Pac-Man, all reading and writing the same block of memory. Think of three clerks at one desk with a shared notepad. The main processor runs the game: your ship, your shots, the score. A second processor flies the enemies along their swooping paths and decides when they shoot. The third plays the sound.

An enemy bullet passes between two of those clerks. The second processor creates it. The main processor moves it down the screen every frame and throws it away when it leaves the screen.

The life of an enemy shot The enemy processor finds a free slot among eight in shared memory, marks it taken and copies the enemy's position into it. Every frame the main processor moves each shot, skipping any at position 0, and frees the slot when the shot leaves the screen. A shot at position 0 is never moved and never freed, unless the rev B fix frees it. ENEMY PROCESSOR An enemy fires: take a free slot, copy its position MAIN PROCESSOR Every frame: move each shot, free it off screen SHARED MEMORY: EIGHT ENEMY SHOT SLOTS shot shot free shot free free at 0 free A shot made at position 0: the mover skips it (0 = not shown), the off-screen check never sees it leave.
The life of an enemy shot: the enemy processor writes it into one of eight slots in shared memory; the main processor moves it and frees the slot when it leaves the screen. A shot at position 0 is neither moved nor freed.

Eight slots

The game keeps exactly eight places for enemy bullets, eight slots in that shared memory. Each slot is either free or holds a bullet in flight. When an enemy decides to fire, the enemy processor looks through the slots for a free one:

ld   hl,$8868    ; the first of the eight enemy bullet slots
ld   b,8         ; eight to check
ld   a,(hl)      ; look at this slot
cp   $80         ; $80 means free

If it finds one, it marks it taken and copies the enemy's position into it, so the bullet starts where the enemy is. If all eight are taken, the enemy simply does not fire. There is no error and no waiting. That shot just never happens.

This is normal. On a busy stage all eight slots fill up for a moment and some enemies miss their turn. A slot comes free again as soon as its bullet falls off the bottom of the screen.

The number zero

Each bullet's position across the screen is a single byte, a number from 0 to 255, growing from left to right. Your ship is kept between 17 and 225.

The game uses one of those numbers as a signal: position 0 means "this object is not on the screen". The hardware draws anything at 0 outside the visible picture, and the code that handles objects can use 0 as a quick test for "not in use".

The routine that moves enemy bullets does exactly that. Every frame it goes through the eight slots and nudges each bullet along. When a bullet's position is 0, it skips it. The bullet is not shown, so why move it?

The routine that throws bullets away has a different test. It frees a slot when the bullet has left the screen: off the top or the bottom, or at position 244 or more, off the right-hand side. A bullet at position 0 is inside the top and bottom and not past 244. As far as this check is concerned, it is still on the screen.

So a bullet at exactly 0 is never moved, because the mover thinks it is not on screen. And it is never freed, because the cleaner thinks it is. Since it never moves, nothing about it ever changes. It sits in its slot, invisible, for the rest of the game.

What happens to a shot, by its starting position A strip from 0 to 255. Position 0 is marked as never moved and never freed. Positions 1 to 243 are moved and cleared when they leave the screen. Positions 244 to 255 are cleared straight away as off screen. The fighter moves between 17 and 225. A bee leaving the left edge counts 2, 1, 0 and then wraps to 255, 254. A SHOT'S POSITION ACROSS THE SCREEN bee leaving the left edge: 2, 1, 0, 255, 254 ... wraps 0 17 225 244 255 where the fighter can go 0: never moved, never freed (old program) 1-243: moved, freed when it leaves the screen 244-255: freed at once as off screen
Where a bullet can start, by its position byte. From 1 to 243 it falls and is cleared at the bottom; from 244 to 255 it is cleared straight away; at 0 it is skipped by the mover and missed by the cleaner.

How a bee gets to zero

A bullet starts at the position of the enemy that fires it. So for this to happen, a bee has to fire at the exact moment it is at position 0.

The bees at the bottom left of the formation dive out to the left. Their loops take them right off the edge of the screen, and as they go their position counts down: 3, 2, 1, 0. The next step is not -1, because a byte has no negative numbers. It wraps around to 255, then 254, and so on. A bee swinging out past the left edge looks, to the game, like it jumped to the far right.

That wraparound is why only 0 is dangerous. A bee that fires a frame later, at 255, makes a bullet the cleaner sees as past the right-hand edge, so it is thrown away right away. A bee that fires a frame earlier, at 1, makes a bullet that the mover handles like any other. Only a bullet made in the one or two frames the bee spends at exactly 0 slips through both checks.

That takes luck. Two bees left alone on the first stage passed through position 0 forty-one times in three minutes, and only four of those visits lined up with a shot. But the bees have all the time in the world, and the player only has to survive.

Each stuck bullet takes one slot. After eight of them there are no free slots at all. Every bee that wants to fire is turned away, and nothing ever frees a slot again, not even a new stage. That is the trick.

Four bytes

The Galaga set that MAME treats as the main version is a later Namco revision, labelled rev B. Its chips carry a "b" in their names. In that program, the mover's "skip this bullet" path does one more thing before moving on:

ld   h,$88       ; point at this bullet's slot
ld   (hl),$80    ; and mark it free
inc  l           ; then on to the next bullet, as before

A bullet at position 0 still is not moved, but its slot is handed back straight away. The bullet that would have been lost is simply cancelled.

Chris Cantrell's annotated listing of the earlier program, published on his Computer Archeology site, has the same routine without the first two lines: it skips the bullet and moves on, nothing more. The rev B version is four bytes longer, and everything after it in that chip sits four bytes further along. Cantrell found the bug by reading that earlier code, and proposed his own fix in a different place, by nudging a bullet made at 0 to 1 when it is created.

Waiting for the bees

Reading code is one thing; watching it run is better. The rev B program was run under a test script that made the player's ship indestructible by turning off the check that destroys it. When the ship is hit, the game also stops enemies firing for a while; with no hits that never happened, and firing otherwise worked as normal. The script shot every enemy except the two bees at the far left of the bottom two rows, then parked the ship at the right edge and logged every bullet created, every bullet made at position 0, and every slot freed.

The same scenario ran twice: once with the rev B program as it is, and once with its four new bytes replaced by instructions that do nothing, which makes the routine behave like the older listing.

Rev B as shippedFour bytes disabled
First bullet made at position 0after 22 secondsafter 22 seconds
What happened to itfreed in the same framefreed anyway, by a fluke (see below)
Second one, after 54 secondsfreed in the same framestuck
All eight slots stuckneverafter 11 minutes
Bullets fired after that point, still on stage 1bees kept firingnone
The next 8 minutes, after shooting the two bees378 bullets, stages 2 to 13none at all, stages 2 to 6

With the fix in place, the two bees fired 1,114 bullets over half an hour of game time. Thirty-one of them were made at position 0, and every one was freed in the same frame it was made. Not once was a slot left stuck.

With the fix disabled, the bullets made at position 0 came at the same moments, because the bees fly the same way either way, at least until the slots began to run out. Eight of the ten that came before the end stayed stuck. Two were cleared by the throw-away check after all, apparently because that check reads a copy of the positions that can still hold the previous bullet's last position for a moment. That detail was not traced further. Either way, the eighth slot filled eleven minutes in, and the game went quiet for good.

Stuck enemy shot slots over time A step chart of slots holding a stuck shot, against minutes since only the two bees were left. With the rev B fix disabled the count climbs to 1 at 0.9 minutes, 2 at 1.0, 3 at 1.6, 4 at 3.2, 5 at 5.5, 6 at 6.5, 7 at 7.6 and 8 at 11.1, after which no enemy fires. Two shots made at position 0, at 0.4 and 4.9 minutes, were cleared anyway. With the fix in place the count stays at 0. SLOTS HOLDING A STUCK SHOT 8 4 0 0 4 8 12 minutes with only two bees left all 8 taken: no enemy fires fix disabled rev B made at 0, cleared anyway
Slots holding a stuck bullet over time, with the fix disabled. Eight steps over eleven minutes, then no enemy fires again. With the fix in place the line stays at zero.

Eleven minutes is shorter than the fifteen or so players talk about. In the test the ship sat still at the far right and could not be hit, which is not how a person plays, and how quickly the bees line up with zero depends on their loops. The order of events, though, is exactly the story players tell.

Which machines have it

The program studied here, rev B, has the fix. In half an hour of play, its bees never stopped firing. According to Cantrell, the trick works on the earlier program he studied. According to Muse, who brought a Galaga recreation to the MEGA65 computer, the earlier Namco and Midway "set 1" programs have the bug, and Namco's rev B and Midway's "set 2" fixed it after the trick became widespread in arcades. Muse adds that they rarely found a rev B or set 2 machine where the trick no longer worked, which this article cannot explain. Neither the older Namco sets nor the Midway ones were run here.

So the trick that made Galaga famous among players is not a secret door. It is a single number that means "nothing here" to one part of the program and "something here" to another, eight places to keep bullets, and enough patience to fill them all.

Credits and further reading

  • Chris Cantrell, Galaga No-Fire Cheat on his Computer Archeology site, with annotated listings of the three processors' programs. The first explanation of this bug from the code, and the source for the older program's version of the routine. The same work appeared in print as "Debugging Commercial Code: A Quick Fix for Galaga Code", Circuit Cellar issue 184, November 2005, not consulted here.
  • Muse (sho3string), GalagaMEGA65, whose notes say which program revisions have the bug and how common the fixed boards were.
  • The MAME team, galaga.cpp and galaga_v.cpp, for the ROM list, the memory map and how sprite positions are drawn.
  • The full research notes, with addresses and measurements, are on the enemy shots page of the Galaga case study.