One of the first games I ever played on my family’s Apple IIe was the Jordan Mechner master work, Karateka. Fight the bad guys, save the princess – it’s a simple but classic formula. My brother and I would take turns making our way through Akuma’s fortress. Even then, we wanted a two player version.
Fast forward more than 30 years, and I’ve taught myself 6502 assembly after getting back into the Apple II, through the thriving community online. The idea of a two player version of Karateka came back to me while at KansasFest a couple of years ago. I noodled a little on it back then, getting distracted by finding the code that created the unique music in the game.
Long story short: I finally found the places in the game code that needed patching to allow a second player to control the enemies in the game, and create a functioning two player version of Karateka. The resulting patch is only 42 bytes long. A DSK image is downloadable and playable online at the Internet Archive.
Player 1 controls:
- Q,A,Z to punch
- W,S,X to kick
- C,V to move/run
- SPACE to go from standing to fighting stance and back.
Player 2 controls:
- N to kick
- M to punch
- < to move left
Thanks to Chris Torrence, for helping spelunk the game’s memory layout; to Antoine Vignau for his clean DSK crack and a patch to skip the intro and get right into fighting; 4AM for inspiration and helping test.
Addresses are locations in memory after the game finishes loading.
Before the enemy fighter punches, code loads the Accumulator with D7 then jumps to $6540. A kick is similar, but loads A with C5. I patched those pieces at $6C11 (punch) and $6C20 (kick) instead to read the keyboard buffer and load the appropriate byte into the Accumulator. Otherwise, it goes along to $6540 with 00, which does nothing.
- $6C11: D0 1C C5 21 D0 18 A9 00 85 29 A9 D7 -> AD 00 C0 C9 CD D0 02 A9 D7 8D 10 C0 (M to punch, clears strobe)
- $6C20: 20 95 6C C5 D7 B0 08 20 71 6C A9 C5 -> AD 00 C0 C9 CE D0 02 A9 C5 8D 10 C0 (N to kick, clears strobe)
Code at $6B9B seems to check if the distance between fighters ($33) is too far, trigger the enemy to move closer. This happens with a JMP to 6C52. I read the keyboard ($C000) and check for the comma/less-than.
- $6B9B: A6 33 E0 0C 90 03 4C 52 6C E0 07 B0 02 -> AD 00 C0 EA EA EA C9 AC D0 03 4C 52 6C (< to move player 2)
To be able to check the keyboard while the game is usually busy animating the enemy fighter, I had to find where the keyboard strobe ($C010) was cleared, and NOP it. This happens several places in the main loop, but patching at $6EA9 kept the keyboard buffer long enough for me to check it.
- $6EA9: 8D 10 C0 -> EA EA EA (keep from clearing keyboard strobe)
Once the second player controls were working, I modified the first player controls so both players could huddle around the keyboard and not cross over each other:
- $6e8e: 88 -> C3 (C to move left instead of ctrl-H/left arrow)
- $6e98: 95 -> D6 (V to move right instead of ctrl-U/right arrow)
Bonus: Now defaults to keyboard controls without having to hit K at the beginning.
- $b9a8: A5 C4 D0 00 -> A9 01 85 C4 (default to keyboard control, ignores joystick)