• Open Noon-Late Daily
  • All Ages Admitted Until 4:30PM
  • 21+ & I.D. Required After 5PM
Categories: Behind the Barrels

Behind the Barrels: Hacking Donkey Kong – Part 2

In Part 1 of “Behind the Barrels”, Clay began disassembling Donkey Kong’s original arcade version to apply Mike Mika’s “Pauline Edition” hack. Clay began with the graphics, ensuring the characters of Mario and Pauline looked like, well, themselves! 

With a basically working arcade version of Donkey Kong: Pauline Edition, Clay now saw fit to make the game a complete package! 

In Mike’s original version of Donkey Kong: Pauline Edition, the ‘gifts’ that Pauline collected (parasol, purse, hat) remained the same … But if those are now to be gifts for Mario, shouldn’t they be something a plumber could use? The ‘gift’ graphics were easily changed to new shapes: a pipe wrench, crescent wrench, and toilet plunger.

The colors of the gifts were still set to the whites and pinks of Pauline’s presents. Luigi would probably make fun of Mario for using a pink wrench, so more time with the debugger and disassembler unearthed a table at 0x3E54 which was copied to sprite memory through DMA (Direct Memory Access) that included the gift shapes and colors. Three more changes were made to set Mario’s new gifts to more appropriate color schemes.

Further play testing revealed that the colors would revert to their pink/white combinations on the ‘springs’ stage of the game. So more debugging dug up another table at 0x3E48 which was similarly patched to the earlier on making the colors more “suitable” for our plumber-in-peril!

New prizes

One last, itty bitty problem remained. The ‘hostage’ at the top of the screen was built such that the bottom of the two sprites would be Pauline’s kicking legs when she yells for “Help!”. In order to accommodate that same effect with the shorter Mario sprite the sprite graphics were positioned so that the ‘hat’ of Mario was the top sprite and the rest of Mario’s body was the bottom one. For things to look good we show Mario on profile (handsome, as he is) facing right with a new sprite different from the NES version. The problem, however, is that at the end of the ‘rivets/girders’ levels it’s possible for Pauline to have completed the level on the left side of the screen. With the original ‘hostage’ graphics for Pauline this was not a problem as the top sprite was Pauline’s head and torso and the game would ‘flip’ the top sprite right for left to face the rescuer.

With our modified version however, Mario’s head and body are on the bottom sprite and only his hat is on the top one. If Pauline finished the level on the left side of the screen, this resulted in Mario’s hat turning around backwards while he faced away from Pauline. Amusing, but wrong.

This problem couldn’t be changed with a single byte or two here and there– a code patch would be required. Finding where the decision to turn the hostage to face the rescuer was tricky. Since the same memory locations are re-written 60 times a second watchpoints and breakpoints are almost useless. Thankfully, MAME’s debugger also include a trace function where the flow of execution of the program can be written to disk in text form for examination. By using this logging capability just as the last rivet was removed, a full capture of all the program behavior was made. With a combination of text searches and experimental memory modifications in the debugger a small routine was found at 0x180f that handled the “flip” of the bottom sprite in the hostage.

Thankfully there was a small chunk of unused memory available in the ROM at address 0x3F30. In order to take control of the program at that point a ‘jump’ instruction was placed in memory at 0x180F directing the program to continue excution at 0x3F30 instead. The following routine was then created:

ld hl,$6901 ; which direction is the top half sprite facing?
ld a,(hl)   ; got the 'top' sprite value including horizontal flip bit (top bit)
inc a       ; our "end of level" sprite is three sprites farther in memory than the
inc a       ; shape of the 'top' sprite, so we add three to the value we find in
inc a       ; the top sprite and then...
ld hl,$6905 ; ...point back to the 'bottom' sprite
ld (hl),a   ; write it back out with proper orientation
jp $1814    ; Jump back to the original routine

In the arcade game hardware, the top most bit of the sprite shape says if the sprite is drawn facing right or facing left. Since the program already ‘turns’ the top of the hostage to face the player, our little shim simply takes that value (located at 0x6901) and changes the bottom sprite (located at 0x6905) to the correct shape while also maintaining the “direction” that the entire shape needs to be facing.

At this point, we could call the hack done – but since this was way more interesting than finishing our taxes, I decided to mess about some more!

There’s a lot of unused space in the Donkey Kong graphics ROMs.  That got me thinking– why not have some more prizes for Pauline to pick up?  (What guy doesn’ t need more tools?)

A little more time in Photoshop and I had a few more sprites I like:

More tools!

I located them in memory at tile numbers 0x6B-6D and modified the appropriate color palette values discovered earlier.  Playtesting up to the girders/rivets level revealed an unexpected problem– I couldn’t pick up the new prizes!

Back once more in to the debugger, I watched what happened when the player picks up a prize ‘normally’.  The game appears to just change the horizontal position of the object to zero (moving it off screen) when it’s picked up.  That made for a handy way to trigger a watchpoint to see when that actually happened– “wp 6a10,1,w,wpdata==0” only halts execution when a ‘zero’ it written to the horizontal position of the first prize.  Using that result in conjunction with a ‘trace’ right before and during a prize ‘pickup’ lead me to code at 0x19DA:

19DA: 3A 03 62 ld a,($6203) ; player X location
19DD: 06 03    ld b,$03     ; number of prizes (second stage anyway?)
19DF: 21 0C 6A ld hl,$6A0C  ; start of prize sprite attributes (x position)
19E2: BE       cp (hl)      ; compare prize position with player
19E3: CA ED 19 jp z,$19ED   ; they're equal-- hit!
19E6: 2C       inc l        ; increment to next prize in sprite attribute memory
19E7: 2C       inc l
19E8: 2C       inc l
19E9: 2C       inc l
19EA: 10 F6    djnz $19E2   ; loop for 'b' prizes
19EC: C9       ret

This is basically the first part of checking if a prize has been picked up.  What the code is doing is looking at the player’s horizontal position and comparing it to the prize’s position.  What’s interesting here is that it’s only looking for an exact match– basically your player has to cross the left edge of the prize to pick it up.  That’s why it’s possible to overlap most of a prize without picking it up sometimes.  Huh.

Looking a little farther we find:

19ED: 3A 05 62 ld a,($6205)  ; player is over a prize
19F0: 2C       inc l         ; increment up to 'y' position
19F1: 2C       inc l
19F2: 2C       inc l
19F3: BE       cp (hl)       ; if that's not equal, no hit?
19F4: C0       ret nz        ; return if no hit...
19F5: 2D       dec l         ; but it *is* a hit here, so back up to sprite shape index
19F6: 2D       dec l
19F7: CB       5E bit 3,(hl) ; Ah-hah! Only sprites with bit three cleared can be picked up!
19F9: C0       ret nz

This is the second part of a prize pick-up check.  If the code is executing here it’s already decided that the player’s horizontal position indicates it’s the same as a prize.  The next check is to look at the vertical positions and compare them– if they don’t match the code exits the test (ret nz), but if they’re the same it does one final check– bit 3,(hl).

The interesting part about the last test is that had I simply located the new graphics in a slightly different position it could have worked with no more effort.  Essentially, in order for an item to be a ‘prize’ and be picked up, the 4th bit (“bit 3” counting up from “bit 0”) has to be a zero.  By chance I had put my prize graphics at locations 0x6B-6D.  All those locations have the third bit set, so the code would exit without picking it up!

The fix then was trivial– simply place the new sprite tiles at 0x62-0x64 instead.  With that, problem solved and the prize variety goes up!

Now Pauline has to rescue Mario _and_ pick up his stuff?

Now Pauline has to rescue Mario _and_ pick up his stuff?

Now I can’t help but think that there’s still something… missing.  The title screen!  Nothing really sets it apart from a regular DK machine now, so time to start poking around again.

The MAME driver for Donkey Kong says that the screen memory for the game is at 0x7400.  Sticking value into the that area with the debugger’s memory window reveals that it indeed does change the background graphics, so using that we can visually determine through a bit of trial and error where various things that appear on screen go in memory.

Using a watchpoint to break on the ‘(c)’ character on the title screen leads us to some code at 0x05E9 which appears to be handling printing strings of characters to the screen.  (Breakpoints set there result in one line of text being printed for each break.  The routine ends up being pretty simple– a ‘string number’ is passed in with the ‘A’ register which ends up essentially being a handle to a final address that stores what should be printed and where it should go.  In particular, the “(c) 1980” message is located at 0x3F00 and printed to the screen at address 0x765C.

To make things simple we can just ‘borrow’ that string ID number (0x1E) and use it for our own tagline.  “Pauline Edition” seems to be the most common reference (and it’s nice and symmetrical), so we’ll use that.

The system doesn’t use ASCII for characters, instead the character table simple starts with 0=0x00, 1=0x01, A=0x10, B=0x11, etc. so to make our string we construct the following:

F5 76 20 11 25 1C 19 1E 15 10 10 15 14 19 24 19 1F 1E 3F 2E CD A6 3F

Or, in plain english– place “PAULINE  EDITION” at address 0x76F5 in memory and terminate the string with 0x3F.  We patch up the string pointer table to our new (longer) string stashed off in some unused memory at the end of the ROM and we’re in business.

We probably shouldn’t flat-out remove Nintendo’s copyright message though, so instead we’ll combine it on the bottom line (which normally says “NINTENDO OF AMERICA INC.”).

This time we’ll just overwrite the existing data and use the same address for the string, so the hack is even simpler– just change the text values.  Another couple minutes in HexWorkshop and the deed is done– a quick playtest reveals… The game crashes!

Immediately this sets off the “copy protection” alarms in my brain.  To test this theory I put the ROM back to the original data and then started modifying one byte at a time and looking for the game to crash (it would hang a few seconds in to the first level).  Changing the “N” in Nintendo to a space didn’t cause any problem, but as soon as I change the “I” the game would crash.  This would have been a bit dicey to figure out in the 1980’s, but MAME makes it trivial.  Since the hang would occur during the game attract mode as well as during game play, I simply used the MAME debugger’s trace capability to log to disk every instruction executed on a “good” ROM then changed the ROM by wiping out the “I” in Nintendo and made another trace with that version.

WinMerge was then used to compare the two text files:

No Piracy Intendo!

No Piracy Intendo!

Well there’s your problem, right there.  Notice that both files are identical until “something happens”, then they’re very different.  Looking at the disassembly we notice this routine at 0x2441:

2441: 21 0C 3F    ld hl,$3F0C ; address of the "I" in "NINTENDO" string
2444: 3E 5E       ld a,$5E    ; start with this value
2446: 06 06       ld b,$06    ; sum the next six bytes
2448: 86          add a,(hl)  ; together in to 'A'
2449: 23          inc hl
244A: 10 FC       djnz $2448  ; (loop until six bytes are done)
244C: FD 21 10 63 ld iy,$6310 ; load a 'magic' value in IY
2450: A7          and a       ; set Z80 flags
2451: CA 56 24    jp z,$2456  ; unless the checksum is equal to zero...
2454: FD 23       inc iy      ; cry havoc and let slip the dogs of war!

In plain English, the game is taking the values of the letters “INTEND” and adding them to the value 0x5E.  If the final sum isn’t 0x00, it adds one to the value in IY, which apparently causes things to go pear-shaped later on…

This is pretty clever back in the day because although the check is performed at the beginning of the level, the game doesn’t actually crash until several seconds later.  Since “really good” logic analyzers back in the 1980’s were only able to capture maybe a few milliseconds of program execution (unlike MAME which is limited only by the size of your hard drive) this would have probably been pretty annoying to find and fix because by the time the game crashes, the actual check that would end up making it crash had happened long ago.  (It’s worth noting though, that Donkey Kong was still widely cloned/pirated/copied even back in the 80’s!)

We could just ‘neuter’ this copy protection check by placing ‘nop’ (do nothing) instructions at address 0x2454-55, but that would result in a slight change to the program timing which would be better to avoid if possible.  Instead, it’s easier to just change the value at 0x2445 (the 0x5E) to something that when summed with our string equals 0x00.  That value happens to be 0x4B, so with that one byte changed we test again– success!  No more crash and a title screen to boot!

New title screen!

Did you know that the arcade Donkey Kong has the pies/conveyor level?  Well, I didn’t.  I thought it was added in the NES cart version. *sigh* That just goes to show you how good of a DK player I am…

Thankfully, the tables used are the same as the earlier levels.  By examining sprite memory at the beginning of the level and searching for that data in the ROM files with HexWorkshop we find the values at 0x3E3C (0x0E3c in ROM “c_5at_g.bin”, to be exact).  A few more bytes patched up and we’re done.  ‘Conveyor’ level all spruced up!

Now we're moving!

Now we’re moving!

Done! For now at least…

Thanks to Mike Mika for the original Donkey Kong: Pauline Edition NES hack and everyone that’s come down to Ground Kontrol to try our custom version!

  1. Fantastic work! I love the motivation behind it. My daughter is just learning to code at CodeAcademy, so I’ll show this to her. We’d love to have the files for MAME. DK is what led me to MAME in the first place, being arcade-aged in the 1980s. My son and I plan to build a cabinet system.

    Thanks for the post.

  2. Is this version currently available to play? (Nov. 2014)