1984 · Brøderbund Software · Apple II

Karateka

This minisite was contributed by air. It’s agent-generated and needs a human editor. Clone https://github.com/gamesexplained/gamesexplained and follow kit/START.md to curate games/apple2/karateka with me to Gold.

A guard in Karateka chooses each move by holding one random byte against four small tables that every stage keeps just before its own entry point. The last of the four runs into that entry point, so whether a guard who holds back steps in at a given distance is decided by the bytes of a jump instruction.

01 · The game

The game

The player is a karateka, a karate fighter, sent to rescue Princess Mariko from the warlord Akuma's fortress. The way in runs along a cliff path, through the palace hall, down into the dungeon and into Akuma's chamber. Guards come one at a time, each in new headgear and with more strength than the last, and Akuma sends his hawk at the hero in the palace and the dungeon.

A fight is fought from a fighting stance: three keys punch high, middle and low, three more kick, and two step forward and back. The orange arrows at the bottom left are the hero's strength and the blue ones at the right his opponent's. Each blow that lands takes an arrow, and the last one kills. A hero who walks or runs into a fight dies of the first blow, and so does one who comes to Mariko in the stance.

The title screen: the word Karateka in orange letters The hero and the first guard in the stance on the cliff, Mount Fuji behind them, a gate on the right

The title, and the first guard on the cliff. Apple2TS 3.7.0 as an enhanced Apple IIe, from Brøderbund's original disk (reference/).

02 · One frame, rebuilt from memory

The title and the demonstration fight, run from the listing

With no key pressed, the title shows the credits, the logo and the scrolling prologue, plays out a scene in Akuma's chamber and then a fight on the cliff that plays itself. Here the title's own code from the Source tab does all of that in the browser.

loading the listings
flip 1

The title stage's code runs from its entry, $BFFA, on the kit's 6502 over the engine's listing with the title's laid over it, and stops each time the game flips the page shown; the page then shown is drawn by the site's Apple II library (reference/demo.js). The Monitor's delay routine, which the sounds call, is the one piece of the machine stood in for. The round, 571 flips from the credits to the credits again, is worked out once, and the slider moves through it. Play shows each flip at the machine's speed, with the speaker's clicks played through the site's model of the speaker. At 18 flips from the credits to the demonstration fight and the prologue again, both hi-res pages hold the same 16,384 bytes as in Apple2TS, and the round's 16,141 clicks come at the same spacings between its flips, run from the stage's entry (test_demo.js). The run here is an Apple II older than the IIe, which does not wait for the vertical blank before a flip, so the round takes 155.1 seconds here and 157.8 on a IIe. In the game the next round's fight differs, because the random numbers carry on; Play goes round the same one again.

Every frame is drawn on the hi-res page the player is not looking at, and then the two are swapped. The page being drawn is kept in $07 ($20 for page 1, $40 for page 2), and flip ($7609) shows it. On a IIe or IIc the flip first waits for the vertical blank, after a look at the machine's ID byte ($779A); on an older Apple II it flips at once. There is no timer. A frame takes as long as its drawing takes, and a tune or a sound holds the frame up while it plays.

On the cliff, in Apple2TSFramesVideo framesFrames a second
The hero standing still433008.6
The hero running, the scene scrolling111205.5

A fighter is drawn from three pictures: his legs, in 42 poses, his torso, in 38, and his head or headgear. Tables of columns and rows for each pose place them ($6000-$62FF), and draw_figure ($6811) draws them. A fighter facing left is the same pictures drawn mirrored, each byte turned round through a table of 256 reversed bytes ($0980). The guards are told apart by their headgear: types 0 and 6 are pictures the engine keeps, and types 1 to 5 are each stage's own, at $BE00. Akuma is drawn by a routine of the last stage's own ($BC00).

03 · The guards' brain

How a guard chooses his next move

Once both fighters are in the stance and 11 columns apart or closer, a guard's move in each frame comes from the distance between them and the next number of the game's random sequence. Choose the opponent and the distance: each square is one of the 256 values the random number can hold as the guard thinks, coloured by what he does.

Each square runs a port of the brain, opp_brain ($6B00), from that random number, with the guard ready in the stance (legs and torso in pose 6, his legs' step at its third position) and the hero in the stance (reference/brain.js). The thresholds and the chances are read from each stage's listing. The port gives the same move, height, stick and next random number as the game's own routine run on the kit's 6502 in 673,440 cases: every random number at every distance from 0 to 13 in every stage, and 100,000 random states of every cell of zero page the routine reads (test_brain.js).

The random numbers come from random ($6C95), which multiplies the last one by 17 and adds $A1, keeping the low byte. That sequence runs through all 256 values before it repeats, so over a fight the squares above are equally likely. The first number is held against three thresholds for the distance, read from three small tables in the stage: at or above the first, the guard throws no blow; between the first and the second, he tries a kick; between the second and the third, a punch; below the third, a step forward.

A move tried is not yet made. It must pass the guard's chance for it, set by his headgear ($D7 a kick, $D8 a punch, $D9 a step), against the next random number, and a blow's height comes from the number after that: high, middle or low a third of the time each. Akuma never aims low ($6C71). A move that fails its chance falls through to the case of no blow, in which the guard steps in or holds his place, by a fourth table.

For distances 7 to 11 the fourth table is read at $BFF9-$BFFD, and four of those five bytes are not chances at all. They are the stage's entry, JMP $B700 (4C 00 B7), and the stage's number, the first of its check bytes. So at distance 9 a guard who holds back never steps in, because the chance is the low byte of $B700, and at 10 he steps in 183 times in 256, because it is the high byte (Discoveries).

The other cases are simpler. A guard in the stance kicks a standing hero within 8 columns, if his kick chance allows, and steps towards one further off, and towards a hero in the stance 12 columns away or more. A guard standing takes the stance when the hero does or comes within 13 columns, and bows back when the hero bows.

04 · Music

Music: two voices beating on one speaker

The Apple II's speaker clicks each time the program touches $C030. Karateka's tune player, play_tune ($0D00), clicks it for two voices at the same pitch, the second voice's count one shorter, so that the two drift against each other and the note shimmers. These are the sixteen tunes the game stores.

Loading the listings…

Each button runs the stage's own entry for that tune from the listing (a JMP among those at $1000) through the player on the kit's 6502, and plays its clicks through the site's model of the speaker (site/lib/apple2-speaker.js); the drawing shows each note's pitch and, along the foot, every click. Below it are the tune's bytes in memory, with the note playing lit. Run from each stage's snapshot in Apple2TS, all sixteen tunes click at the same cycles, click for click (test_tunes.js). Several stages carry the same tune; each copy plays alike, within three cycles a click.

A tune is two header bytes and then notes of three. The first header byte is the tempo, which the player writes into its own code ($0D5E); the second is the page the second voice reads, where $C0 clicks the speaker and any other page is silent. Each note is a length and a pitch, given as a coarse and a fine count, and a coarse count with its top bit set is a rest. Three bytes are commands:

ByteWhat the player does
$FEtwo NOPs at $0D79: the second voice runs free, and the two voices drift apart and back
$FD nLDY #n at $0D79: each click of the first voice sets the second's count to n, so the two stay a fixed distance apart
$FFthe end of the tune

Every tune starts with $FE or $FD, so each one sets the two voices afresh.

Each stage keeps its own tunes behind JMPs at $1000, at the same place in every stage, so that the engine and the stage can ask for the tune for a guard beaten ($1006) or the hero's death ($1003) whichever stage is loaded; the engine itself keeps two of the last stage's ($0FB0, $0FE4). The closing tune has a tempo of $40, against 4 to 8 for every other, which stretches 64 short notes over 19 seconds.

Before each note the player reads the keyboard. A special key such as CONTROL-S is obeyed at once, and any other key is thrown away, so a key pressed during a tune never reaches the fight.

05 · Fighting

A blow on a standing hero kills him outright

Arrows count the blows a fighter can take, but only in the stance. A hero caught standing, running or bowing dies of the first blow, whatever his arrows ($712A); a guard caught the same way only reels.

Whether a blow lands is decided by hit_test ($7366) from the distance between the fighters and the class of the target's pose (pose_class, $70C6, 26 classes for the 42 poses of the legs). A kick always lands within the target's reach plus one column, and the reach is 6 or 7 columns ($7300). Punches land by tables, at the reach ($7348, $7352) and at the reach plus two ($7334, $733E, $735C). A quick punch, thrown while stepping, lands only at exactly its own reach ($745B). Closer than the reach the two collide, and a hero who is moving is pushed back two columns.

Each blow that lands takes an arrow ($0BC1, $0BD2), and arrows come back one at a time while a fighter is not hit ($0BE3). The stages share out the strength. The hero's most arrows and each opponent's always add up to 28, and each guard beaten moves one more from the hero's side to the next guard's, until the hero is down to a floor that each stage sets.

StageThe hero's most arrows at the startEach opponent'sThe hero gives one up per guard while he hasGuards' headgear
The cliff ($B700)141410 or more0 to 5
The palace ($B700)12169 or more1 to 5
The dungeon ($B700)1018any number3 to 6, then the hawk
Akuma's chamber ($B700)820Akuma

The dungeon's hawk is its last opponent, with 5 arrows that never come back, and the hero has 23 for that fight: 28 again.

06 · Controls

Controls: the low kick is on X

The manual gives Z for the low kick. The game reads X, and Z is the low punch.

KeyStandingIn the stanceCode
SPACEtake the stancestand up$6E78
RIGHT arrowrun, and keep runningone step forward$6E69
LEFT arrowstop runningone step back$6E69
Q, A, Zpunch high, middle, low$6EB9
W, S, Xkick high, middle, low$6EE0
Bbow$6F04

A blow pressed while another is under way waits, and is sent again each frame until the fighter can take it ($46, $47). With the joystick, chosen with J (K goes back to the keys), holding the stick up keeps the hero standing, and letting it go puts him in the stance, where the buttons kick and punch at the height the stick points to (player_input, $6E00). Up stands him up again only when no guard or Akuma is within 15 columns and the hawk is not close.

The special keys work at any time, even in the middle of a tune (special_keys, $7697). ESC freezes the game until a key is pressed. CONTROL-S turns the music off, then the sound, then both back on. CONTROL-B swaps the joystick's buttons, CONTROL-E its axes, CONTROL-X reverses left and right and CONTROL-Y up and down, and CONTROL-N puts all four back. CONTROL-R goes back to the title. Each answers with a beep.

07 · Sound

Sound: one recording, played at seven speeds

Seven short effects are clicks spaced by the Monitor ROM's delay routine. The eighth sound is a recording of 2,048 one-bit samples ($0E00), played back slower or faster for a guard falling dead, a doorway kicked open, the hero falling to Akuma, Mariko's kick, Akuma's cry and the hawk.

Loading the listings…

Each button runs the engine's own code for the sound from the listing on the kit's 6502 and plays its clicks through the site's model of the speaker. The Monitor's delay routine, WAIT, which the ROM holds and the listing does not, is stood in for by its timing, (26 + 27A + 5A²) / 2 cycles. In Apple2TS the same calls click at the same cycles, click for click, for all ten (test_sound.js).

SoundCodePlayed when
The hero struck$0C40a blow lands on the hero: 38 clicks, falling
The opponent struck$0C43a blow lands on the opponent, or a doorway is kicked: 28 clicks
A quick punch lands$0C4617 clicks
A blow thrown$0C49the swing, 10 clicks
A control key$0C4Cthe beep after a special key
Steps$0C4F, $0C52footsteps in a scene, and the hero's run
The recording$0DC0at speed 30 for a guard falling dead or a doorway kicked open ($729F, $740C), 40 for the hero falling to Akuma ($724D), 18 for Mariko's kick ($BB3D), 7 for Akuma's cry before he sends the hawk, and 6, 5 and 4 for the hawk struck, flying off and pecking ($B5DA)

play_sample ($0DC0) waits $BA turns of a loop between samples and clicks the speaker only where the sample changes, so the speed sets the pitch and the length together: the recording lasts 0.35 seconds at speed 30 and 0.45 at 40.

All the sounds are made at the end of the frame that asked for them (end_frame, $7628), and CONTROL-S silences them. The last stage turns the music and the sound back on whatever the player chose, so the ending is always heard ($B700).

08 · The stages and the disk

Five stages take turns in the same 12 KB

The engine stays in memory from the boot to the end. The title and the four stages each load over the one before, into $1000-$1FFF and $A000-$BFFF.

The disk has no DOS and no files. After the boot sector, everything is read by the game's own loader (load, $0338), twelve 256-byte sectors to a track, with four marks of its own on each track (track_marks, $5610). Stage n starts on track 4n + 7, the castle picture shown before the cliff on track 4. The loader's later parts live in the strips of hi-res page 2 that the screen never shows, and are read from the disk again before every load.

Stage$D0First trackLoaded when
The title and demo07at the boot, after THE END, and on CONTROL-R
The cliff111a key at the title, after the castle picture
The palace215the hero walks off the cliff's second screen
The dungeon319the hero passes under the palace's portcullis
Akuma's chamber423the dungeon's hawk is beaten

A stage ends with three check bytes: its number, the number EOR $3B and the number EOR $49. The engine reads the stage again until they check, then enters it by the JMP just before them, at $BFFA (load_stage, $020C).

What passes from one stage to the next is only what is in the engine's memory: zero page, with the control chosen, the sound switches and the hero's record.

Pressing RESET does not get out of the game. The game keeps a copy of the ROM in the language card with its reset vector pointed at the game's own handler, which clears memory and boots the disk again (reset_handler, $0309). Every stage, with its rooms, is drawn by its own code on the Maps / levels tab.