1984 · Activision

Ghostbusters

This minisite was contributed by air, unorig. It’s currently claimed by unorig who is editing it to reach a Gold tier standard.

The whole game in the browser, from the sing-along to the portal on Zuul. It was ported from the game's 6502 code routine by routine, and checked against the original at every pass of its main loop.

Loading the game's bytes…
  • ← → ↑ ↓ the joystick
  • Alt, right Ctrl or Numpad 0 fire
  • F1 F3 on the title (or the buttons)
  • Space the status report, on the map
  • B bait, on the map; 1-3, E in the shop
  • Esc RUN/STOP: pause, on the map
  • Letters, digits, , Enter Backspace: the interview
Start at
Cheats

The game's own screen, drawn from the port's memory each frame the way the video chip would, with every register write the interrupts make on the line where they make it. Start at plays the start of the game for you, faster than real time, and hands over on the city map.

01 · Start anywhere

A level select made of the game's own start

Ghostbusters has no levels, only a clock: the city's PK energy, which climbs until the Keymaster and the Gatekeeper meet. The start buttons take you to the points along it that are worth playing.

No saved snapshot is involved. The page starts the game from its first instruction and plays its start for you without drawing it: F1 on the title, VENKMAN,PETER at the interview, no account, the station wagon on the car page. In the shop it puts the equipment in the car as the shop would have left it, then presses E. That takes the game about 2,200 frames, around 45 seconds of C64 time, which the page runs in a fraction of a second.

StartWhat the page changesWhat happens next
The city, equippedthe kit byte $6D = $6F (every item), 9 traps owned and empty ($6A, $6B), 20 dollops of bait ($69)the normal game, with $4,000 left after the car
PK 4,990PK energy $5B/$5A = $49/$90at 5,000 the game picks the Marshmallow Man's building, and every thousand after that, a new one
PK 9,490PK energy 9,490, the balance $57-$59 $20,000 and the balance at the start $51-$53 $10,000at 9,500 both head for Zuul; when they meet, the car goes to Zuul's street

02 · Cheats

Four cheats, each one variable or one routine

Each cheat can be switched on and off at any moment. Off, the game is the original again.

CheatHow
Free spendingThe known POKE 38454,96 writes an RTS over the first byte of money_subtract ($9636), so nothing the game charges is taken: the car, the equipment, the Marshmallow Man's damage. The port does not run the game's bytes, so the page makes its own money_subtract return at once, which is what the POKE does.
Full backpacksThe proton packs' power, $3E, is put back to 99 every frame. A bust uses one percent every 16 frames with the streams on, and crossing the streams empties it.
Traps stay emptyThe count of empty traps, $6B, is set to the count owned, $6A, every frame, so there is no need to go back to GHQ.
PK rises only by escapesThe meter's timed climb (frame_pk_rise, $73F3) does nothing. A Slimer left alone still escapes and adds 300, and a Roamer reaching Zuul still adds 100.

03 · The port

Every routine of the game, checked against the original at every pass

Nothing on this page emulates a 6502. The game's routines are written out in JavaScript, one function each, named by the listing's labels, and run on the game's own 64 KB of memory.

The page loads that memory from the listing, the same bytes the Source code tab shows. From then on the port reads and writes the game's variables where the game keeps them, with the game's own decimal arithmetic, its self-modified operands and its bugs: the two bytes each drive leaves on the stack, and the empty branch at $7200.

How it was checked

The original code runs in a 6502 simulator beside the port, from the same saved moment and with the same keys and joystick. At the start of every pass all 64 KB are compared, with colour RAM. Only the stack page is left out.

RoutinesTested aloneLockstep sessionsResult
The frame, the input, the text engine, money, the interview and the car page68 routines, 204,000 cases17 sessions, about 21,000 passes: every interview answer, both F3 cases, every car, the map and the drive with their keysidentical at every pass but two, both the random-number race below
The shop and the city map35 routines, 70,000 cases23 sessions, 57,252 passes: every shop page, full cars, walks, bait, every refusal of fire, PK 5,000 and PK 9,500identical at every pass but 17, all the race
The drive, the bust and GHQ44 routines, 132,000 cases18 sessions, 10,639 passes: steering, the vacuum, catches, misses, crossed streams, the laser system, bait, GHQidentical at every pass but the race
The Marshmallow Man, Zuul and the endings33 routines, 165,000 cases10 sessions, about 13,700 passes: bait in time and too late, the win, GOOD TRY, a catch, foreclosure, the wait for F1identical at every pass but one: on the pass after F1 restarts the game from the end pages, the sprites' X registers differ, because the check replays the interrupt that sets them after init_game_vars clears them, where the game ran it before
The interrupt, the music, the effects, the speech, the start-up and the title20 routines, 3,000 cases each; 35 phrasesthe cold start, the title with SPACE, F1 and F3, RUN/STOP + RESTORE, and all 57 sessions above again with this group in: 88,550 passesidentical at every pass but the two races below

Where the original depends on its interrupts

The title's tune during speech. While a phrase plays on the title, the game steps the tune, the lyrics and the ball from a loop that compares the raster line with the last one it read. It reads the line's two parts one after the other, and the speech interrupt can fall between them, so the game sometimes steps twice in a frame: 98 steps in 88.7 frames for one phrase. The port steps once a frame, so on this page the sing-along can end a fraction of a second later.

The random number. The raster interrupt steps the random number $06 once a frame, at line 184. When a pass starts late, after a slow one, the main program reads $06 after the interrupt has stepped it. The port runs the interrupt between passes, so its read gets the value before. Three places read it this way: the Roamer's spot on the road at the start of a drive ($8113), the Keymaster's and the Gatekeeper's turns ($7DFF) and the new haunting ($740C). On this page a Slimer or a Roamer can therefore turn up somewhere the original, at that moment, would not have put it. Either is a place the original can choose.

The character set is built at start-up from the machine's character ROM: the code at $608A copies 1,016 bytes of the upper-case letters from $D008-$D3FF of the 901225-01 character ROM. The page carries those bytes, and nothing else of the ROM.

04 · Speed

It runs at the C64's speed, pass for pass

The game does one pass of its main loop a frame, and some passes take several: drawing the map, a building, Zuul's tower. A port that ran each pass in a frame would be too fast there.

So the page keeps a PAL machine's clock: 312 lines of 63 cycles, 50.12 frames a second, with the raster interrupts on their lines. The port does not execute instructions, so it cannot count their cycles. Each pass costs the median time the original's pass took in the same game state, measured on the simulator over 78,000 passes of the lockstep sessions, and the interrupts, the speech and the raster waits take their own time.

SessionPassesFrames, originalFrames, this page
Walking the map4,0354,0354,035
The shop, then the map2,8752,8802,880
A drive, the building drawn, a bust set up700709709
GHQ: the restock and the men walking out1,4001,4091,400
Zuul's street353356358

Both run from the same saved moment with the same input at every pass. A session in which the random-number race (section 03) sends the two games different ways cannot be compared like this, since from then on they are playing different games.

05 · Differences

What differs from a C64