Prince of Persia
Jordan Mechner's 1989 Apple II platformer, read in the 6502 source he released.
The atlas reads Prince of Persia in the 6502 source Jordan Mechner released, version 1.0 of 9/7/891.
#Jumping
Every move is an animation sequence: each cycle steps the kid one frame, and the sequence’s own bytes move him, a set number of units forward and pixels up or down, with no speed2. A block is 14 units3 wide. A standing jump moves him 2 blocks without a floor check, 39 units in all4, and a running jump 43 units (3 blocks) without a floor check, 67 in all5; on the frames between, the game doesn’t test for floor under him. That puts Prince of Persia beside Castlevania on the table end of the jump spectrum.
A running jump doesn’t start where the press comes. The code looks ahead for the floor’s end and moves the kid so the jump starts one block short of it, and when the end is still far off, it doesn’t jump yet6.
The kid has no air control. The control routine reads no input on any frame of either jump7.
#Falling
A fall’s speed grows 3 px/cycle per cycle, from 15 up to 338. With the button held, the kid catches a ledge he falls past, if he isn’t falling too fast9. Landing speed sets the cost10, and in floors that works out as 1 floor safe, 2 cost a hit point, 3 kill11.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Jump | Table | two fixed sequences of per-frame steps, 2 blocks (standing) and 3 (running) without a floor check, with the running take-off moved to a block before the edge |
| Air control | Fixed | the control routine reads no input during a jump's frames |
| Gravity | One gravity | a fall adds 3 px per cycle to the speed, up to 33, or 1 up to 4 while weightless |
| Ledge grab | Button held | the button held, while falling slower than 32 px per cycle and within 25 px of the floor plane below the ledge |
| Fall damage | Stepped by speed | one floor is safe, two cost a hit point, and three kill |
| Gravity | None | the jump sequences move the kid with no gravity |
Every claim about this game, by concept (11)
References
- ^Jordan Mechner's released Apple II source names its build in
VERSION.S, "Prince of Persia 1.0 9/7/89", and itsMASTER.Sis headed as the 3.5-inch disk version; the game code the other claims here read is shared with the 5.25-inch build.Codejmechner/Prince-of-Persia-Apple-IIHow we know
9TextLine asc "Prince of Persia 1.0 9/7/89"01 POP Source/Source/VERSION.S line 9 at 2524355 · upstream ↗ 9* M A S T E R ⋮ 11* (3.5" version)
01 POP Source/Source/MASTER.S lines 9–11 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^Both of the kid's jumps are fixed sequences in
SEQTABLE.S, with no speed or gravity: each cycleANIMCHARreads the sequence up to the next frame number, adding eachchxbyte toCharXin the direction he faces and eachchybyte to his height. The frames of both jumps add no horizontal offset of their own (Fdx0 inFRAMEDEF.S).Codejmechner/Prince-of-Persia-Apple-IIrevisedHow we know
996:next jsr getseq ;get next byte from seqtab ⋮ 999 cmp #chx ;"change x" instruction? 1000 bne :no1 ⋮ 1002 jsr getseq ;next byte is delta-x ⋮ 1004 jsr addcharx 1005 sta CharX ⋮ 1010:no1 cmp #chy ⋮ 1013 jsr getseq ⋮ 1016 adc CharY
01 POP Source/Source/COLL.S lines 996–1016 at 2524355 · upstream ↗ 346* In: A = # pixels to add (+ = fwd, - = bkwd) ⋮ 353ADDCHARX 354 bit CharFace ;-1 = left (normal)
01 POP Source/Source/CTRLSUBS.S lines 346–363 at 2524355 · upstream ↗ 21* Fimage, Fsword, Fdx, Fdy, Fcheck01 POP Source/Source/FRAMEDEF.S line 21 at 2524355 · upstream ↗ 38:16 db $10,0,0,0,$c0+3 ;standjump-9 ⋮ 66:44 db $2c,0,0,0,$c0+4 ;runjump-11
01 POP Source/Source/FRAMEDEF.S lines 38–66 at 2524355 · upstream ↗ 1654 ldy #0 1655 lda (framepoint),y 1656 sta Fimage ⋮ 1659 lda (framepoint),y ⋮ 1663 lda (framepoint),y 1664 sta Fdx
01 POP Source/Source/CTRLSUBS.S lines 1654–1664 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-25.
- ^The kid's horizontal position,
CharX, counts in units of 14 to a block: the left edges of the blocks (BlockEdge) step by 14, and the screen is 140 units wide, so it holds 10 blocks (computed). A floor is 63 px tall (BlockHeight).Codejmechner/Prince-of-Persia-Apple-IIHow we know
143* BlockEdge ⋮ 146* Yields: Screen X-coord of left edge of block ⋮ 150]byte = -12 151 lup 20 152 db ]byte 153]byte = ]byte+14
01 POP Source/Source/TABLES.S lines 143–154 at 2524355 · upstream ↗ 476ScrnWidth = 14001 POP Source/Source/EQ.S line 476 at 2524355 · upstream ↗ 36BlockHeight = 6301 POP Source/Source/TABLES.S line 36 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^The standing jump (
standjump) runs frames 16 to 33. Itschxsteps are 2, 2, 2, 2, 2, 7, 9, 5, 1, 4, −3, 5, and 1 units, 39 in all (computed); its onlychysteps lift the kid 6 px and set him back down on the next frame. Frames 20 to 25 lack the floor-check bit, soongrounddoesn't test the floor under him there, and the steps between frame 19 and frame 26 move him 28 units, 2 blocks (computed).Codejmechner/Prince-of-Persia-Apple-IIHow we know
442standjump 443 db act,1 444 db 16 445 db 17,chx,2 446 db 18,chx,2 447 db 19,chx,2 448 db 20,chx,2 449 db 21,chx,2 450 db 22,chx,7 451 db 23,chx,9 452 db 24,chx,5,chy,-6 ;chx 6? 453sjland db 25,chx,1,chy,6 ⋮
01 POP Source/Source/SEQTABLE.S lines 442–464 at 2524355 · upstream ↗ 41:19 db $13,0,0,0,$40+8 ;standjump-12 42:20 db $14,0,0,0,$80+9 ;standjump-13 43:21 db $15,0,0,0,$00+11 ;standjump-14 44:22 db $16,0,0,0,$80+11 ;standjump-15 45:23 db $17,0,0,0,$00+17 ;standjump-16 46:24 db $18,0,0,0,$00+7 ;standjump-17 47:25 db $19,0,0,0,$00+5 ;standjump-18 48:26 db $1a,0,0,0,$c0+1 ;standjump-19
01 POP Source/Source/FRAMEDEF.S lines 41–48 at 2524355 · upstream ↗ 653Fcheckmark = %0100000001 POP Source/Source/GAMEEQ.S line 653 at 2524355 · upstream ↗ 311* Is there floor underfoot? If not, start to fall ⋮ 313onground 314 lda Fcheck 315 and #fcheckmark 316 beq ]rts ;0--no need to check
01 POP Source/Source/CTRL.S lines 311–316 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^The running jump (
runjump) runs frames 34 to 44. Itschxsteps are 5, 6, 3, 5, 7, 12, 8, 8, 4, 4, and 5 units, 67 in all (computed), and itschysteps raise the kid 14 px over three frames and lower him 14 px over the next two. Frames 39 to 43 lack the floor-check bit, and the steps between frame 38 and frame 44 move him 43 units, 3 blocks and 1 unit (computed).Codejmechner/Prince-of-Persia-Apple-IIHow we know
469runjump 470 db act,1 471 db tap,1,34,chx,5 472 db 35,chx,6 473 db 36,chx,3 474 db 37,chx,5 475 db tap,1,38,chx,7 476 db 39,chx,12,chy,-3 477 db 40,chx,8,chy,-9 478 db 41,chx,8,chy,-2 479 db 42,chx,4,chy,11 480 db 43,chx,4,chy,3 ⋮
01 POP Source/Source/SEQTABLE.S lines 469–485 at 2524355 · upstream ↗ 60:38 db $26,0,0,0,$40+5 ;runjump-5 61:39 db $27,0,0,0,$80+14 ;runjump-6 62:40 db $28,0,0,0,$00+11 ;runjump-7 63:41 db $29,0,0,0,$80+11 ;runjump-8 64:42 db $2a,0,0,0,$80+10 ;runjump-9 65:43 db $2b,0,0,0,$00+1 ;runjump-10 66:44 db $2c,0,0,0,$c0+4 ;runjump-11
01 POP Source/Source/FRAMEDEF.S lines 60–66 at 2524355 · upstream ↗ 313onground 314 lda Fcheck 315 and #fcheckmark 316 beq ]rts ;0--no need to check
01 POP Source/Source/CTRL.S lines 311–316 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^In a run (frames 4 to 14),
arunningreaches the running jump only while the joystick is held forward (centered stops the run, back turns it), and then only on a fresh press of up (clrUnegative), with forward and up the names Mechner's comments give the joystick signs; in a full run (frame 7 or later) that callsDoRunjump, which Mechner's comment describes as "Calibrate jump so that foot will push off at edge". It looks for a gap or spikes in the next two blocks and measures from the kid's position 4 units on to that floor's end. When the end is 6 to 15 units off, it moves him so the jump starts withCharX14 units (one block) short of the end (computed). Farther off, it returns without jumping (comment: "still too far away--wait till next frame"); nearer, it moves him 1 unit (computed) and jumps (comment: "He jumped too late; he'll miss edge"). With no gap in sight, he jumps where he is.Codejmechner/Prince-of-Persia-Apple-IIrevisedHow we know
1743* Calibrate jump so that foot will push off at edge. ⋮ 1746RJChange = 4 ;projected change in CharX 1747RJLookahead = 1 ;# blocks you can look ahead 1748RJLeadDist = 14 ;required leading distance in pixels 1749RJMaxFujBak = 8 ;# pixels we're willing to fudge back 1750RJMaxFujFwd = 2 ;and forward
01 POP Source/Source/CTRL.S lines 1742–1750 at 2524355 · upstream ↗ 1752DoRunjump 1753 lda CharPosn 1754 cmp #7 1755 bcc ]rts ;must be in full run ⋮ 1763 lda #RJChange 1764 jsr addcharx 1765 sta ztemp ;projected CharX ⋮ 1782 cmp #spikes 1783 beq :done ⋮ 1785 jsr cmpspace 1786 beq :done ⋮ 1788 inc bufindex ⋮
01 POP Source/Source/CTRL.S lines 1752–1792 at 2524355 · upstream ↗ 1793 bcs :noedge ;no edge in sight--jump anyway ⋮ 1799 jsr getdist1 ;# pixels to end of block ⋮ 1802 clc 1803 adc Mult7,x 1804 clc 1805 adc Mult7,x ;# of pixels to end of floor ⋮ 1808 sbc #RJLeadDist ⋮ 1811 cmp #-RJMaxFujBak 1812 bcs :ok ;move back a little & jump ⋮ 1814 cmp #RJMaxFujFwd 1815 bcc :ok ;move fwd a little & jump ⋮ 1817 cmp #$80 ⋮
01 POP Source/Source/CTRL.S lines 1793–1836 at 2524355 · upstream ↗ 1348arunning 1349 lda JSTKX 1350 beq :runstop ;jstk centered...stop running 1351 bpl :runturn ;jstk back...turn around ⋮ 1356 lda JSTKY 1357 bmi :runjump ;jstk up... take a running jump ⋮ 1374:runjump 1375 lda clrU 1376 bpl ]rts ⋮ 1378 jmp DoRunjump
01 POP Source/Source/CTRL.S lines 1348–1378 at 2524355 · upstream ↗ 638* In: Raw input 639* JSTKX (- fwd, + back, 0 center) 640* JSTKY (- up, + down, 0 center) ⋮ 643* clrF-B-U-D-btn (- = fresh press)
01 POP Source/Source/CTRL.S lines 638–643 at 2524355 · upstream ↗ 702 cpx #4 703 bcc :starting ;run4-5-6 ⋮ 710:4 cpx #15 711 bcs :2 712 jmp :running ;run8-17
01 POP Source/Source/CTRL.S lines 702–712 at 2524355 · upstream ↗ 917:2 lda clrU 918 bmi :3 ⋮ 920 ldx JSTKY 921 bmi :yesU ⋮ 923 lda #0 924 beq :staU ⋮ 926:yesU cmp #0 927 bne :3 ⋮ 929 lda #-1 930:staU sta clrU
01 POP Source/Source/SPECIALK.S lines 917–930 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Revised after a check by a second AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-25.
- ^
GENCTRL, which turns the player's input into moves, picks its branch by the frame the kid shows (standing, starting a run, running, starting a jump up, hanging, turning, or crouching). The frames of the standing and running jumps, 16 to 44, match none of them, and it returns without reading the joystick, so a jump can't be steered once it starts.Codejmechner/Prince-of-Persia-Apple-IIHow we know
689:cont ldx CharPosn ;previous frame # ⋮ 691 cpx #15 692 beq :standing ⋮ 694 cpx #48 695 beq :turning ⋮ 697 cpx #50 698 bcc :0 699 cpx #53 700 bcc :standing ;turn7-8-9/crouch ⋮ 702 cpx #4 703 bcc :starting ;run4-5-6 ⋮ 705 cpx #67 ⋮
01 POP Source/Source/CTRL.S lines 689–718 at 2524355 · upstream ↗ 720:1 cpx #109 ;crouching? 721 beq :crouching ⋮ 723]rts rts
01 POP Source/Source/CTRL.S lines 720–723 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^With the
weightlessflag clear, a fall (action 4) adds 3 px per cycle to the kid's downward speed, up to 33 px per cycle (AccelGravity,TermVelocity); with it set, gravity is 1 and the cap 4 (WtlessGravity,WtlessTermVel). The fall sequences that start it set the speed to 15 (setfall). In any other action, including the jumps' (action 1) and a fall's first frames (action 3), gravity does nothing.Codejmechner/Prince-of-Persia-Apple-IIrevisedHow we know
1613TermVelocity = 33 1614AccelGravity = 3 1615WtlessTermVel = 4 1616WtlessGravity = 1 ⋮ 1618GRAVITY 1619 lda CharAction 1620 cmp #4 1621 bne ]rts ⋮ 1626 lda CharYVel 1627 clc 1628 adc #AccelGravity ⋮ 1630 cmp #TermVelocity ⋮
01 POP Source/Source/SUBS.S lines 1613–1644 at 2524355 · upstream ↗ 640stepfall ;from #8 (run-11) 641 db act,3 642 db chx,1,chy,3 ⋮ 646fall1 647 db 102,chx,2,chy,6 648 db 103,chx,-1,chy,9 649 db 104,chy,12 650 db 105,chx,-2 ⋮ 652 db setfall,1,15 653 db goto 654 dw freefall
01 POP Source/Source/SEQTABLE.S lines 640–654 at 2524355 · upstream ↗ 882freefall 883 db act,4 884:loop db 106
01 POP Source/Source/SEQTABLE.S lines 882–884 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^A falling kid grabs a ledge while the button is down (either Apple II button, unless manual control splits them) and he is alive, his downward speed is under 32 px per cycle, and his feet are within 25 px above the floor plane he is falling toward.
fallonthen tests for a ledge 8 units behind him (grabreach), requiring clear space above it and a floor piece in front, and on a catch it aligns him to the block, stops his fall, and starts the hang. It runs on the first frames of a fall (102 to 105) and through the free fall.Codejmechner/Prince-of-Persia-Apple-IIHow we know
45grabreach = -8 46grabspeed = 32 ;max Y-vel to grab ledge 47grablead = 25 ;increase to grab ledge earlier
01 POP Source/Source/CTRL.S lines 45–47 at 2524355 · upstream ↗ 248fallon 249 lda btn ;is button down? 250 and CharLife ;& is he alive? 251 bpl ]rts ⋮ 253 lda CharYVel 254 cmp #grabspeed 255 bcs ]rts ;no--falling too fast ⋮ 257 lda CharY 258 clc 259 adc #grablead ⋮ 262 cmp FloorY,x 263 bcc ]rts ;not within grabbing range yet ⋮
01 POP Source/Source/CTRL.S lines 248–298 at 2524355 · upstream ↗ 76falling 77 lda CharY ⋮ 81 cmp FloorY,x 82 bcs :1 ⋮ 84 jmp fallon ;Hasn't reached floor yet
01 POP Source/Source/CTRL.S lines 76–84 at 2524355 · upstream ↗ 120:2 cmp #4 ;freefall 121 beq falling 122 cmp #3 123 bne :1 124 lda CharPosn 125 cmp #102 126 bcc ]rts 127 cmp #106 128 bcs ]rts 129 jmp fallon
01 POP Source/Source/CTRL.S lines 120–129 at 2524355 · upstream ↗ 1814CHECKLEDGE ⋮ 1820 lda blockid ;must be clear ⋮ 1834* Clear above -- is there a ledge in front? ⋮ 1836 lda ztemp ;must be a solid floorpiece 1837;with exposed ledge
01 POP Source/Source/CTRLSUBS.S lines 1814–1858 at 2524355 · upstream ↗ 1045 lda BTN1 1046 ldx ManCtrl ;When manual ctrl is on, btn 0 belongs 1047 bmi :1 ;to kbd and btn 1 to jstk. With manual ctrl 1048 ora BTN0 ;off, btns can be used interchangeably. 1049:1 sta btn
01 POP Source/Source/GRAFIX.S lines 1045–1049 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^A landing's cost goes by the kid's downward speed when he reaches a floor: under 22 (
OofVelocity) he lands softly; from 22 up to 33 (DeathVelocity) he loses 1 hit point and dies if it was his last; at 33 he loses 100, and dies. A guard who lands at 22 or more dies, and the shadow lands softly at any speed under 33.Codejmechner/Prince-of-Persia-Apple-IIHow we know
42DeathVelocity = 33 43OofVelocity = 22
01 POP Source/Source/CTRL.S lines 42–43 at 2524355 · upstream ↗ 184:notspikes 185 lda CharYVel 186 cmp #OofVelocity 187 bcc :softland ⋮ 189 cmp #DeathVelocity 190 bcc :medland ⋮ 192:hardland 193 lda #100 194 jsr decstr 195:hdland1 ⋮ 202:medland 203 lda CharID ⋮
01 POP Source/Source/CTRL.S lines 184–211 at 2524355 · upstream ↗ 691DECSTR 692 ldx CharID 693 bne :enemy ⋮ 695 cmp KidStrength 696 bcs killkid
01 POP Source/Source/MISC.S lines 691–696 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^Computed from the fall sequence and gravity: a kid who steps off a ledge has fallen 30 px when the free fall starts at speed 15, and reaches the floor below at speed 21 after one floor (63 px), 30 after two, and 33 after three or more. One floor costs nothing, two cost a hit point, and three or more kill him. The count assumes
weightlessis clear and that a fall crossing to the screen below keeps its speed and its distance to the next floor, which the atlas hasn't read in the screen-change code.Codejmechner/Prince-of-Persia-Apple-IIrevisedHow we know
640stepfall ;from #8 (run-11) 641 db act,3 642 db chx,1,chy,3 ⋮ 647 db 102,chx,2,chy,6 648 db 103,chx,-1,chy,9 649 db 104,chy,12 ⋮ 652 db setfall,1,15
01 POP Source/Source/SEQTABLE.S lines 640–654 at 2524355 · upstream ↗ 661 jsr animchar ;Get next frame from sequence table ⋮ 663 jsr gravity ;Adjust Y-velocity 664 jsr addfall ;Add falling velocity
01 POP Source/Source/TOPCTRL.S lines 661–664 at 2524355 · upstream ↗ 1651ADDFALL 1652 lda CharYVel 1653 clc 1654 adc CharY 1655 sta CharY
01 POP Source/Source/SUBS.S lines 1651–1655 at 2524355 · upstream ↗ 1613TermVelocity = 33 1614AccelGravity = 3
01 POP Source/Source/SUBS.S lines 1613–1614 at 2524355 · upstream ↗ 36BlockHeight = 6301 POP Source/Source/TABLES.S line 36 at 2524355 · upstream ↗ 42DeathVelocity = 33 43OofVelocity = 22
01 POP Source/Source/CTRL.S lines 42–43 at 2524355 · upstream ↗ 76falling ⋮ 84 jmp fallon ;Hasn't reached floor yet ⋮ 95 bne hitflr ⋮ 97 inc CharBlockY ;Fall thru floor plane
01 POP Source/Source/CTRL.S lines 76–97 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
Sources
Code
- Mechner, Jordan. 2024. “Prince of Persia Apple II source code (jmechner/Prince-of-Persia-Apple-II).” Commit 2524355. jmechner/Prince-of-Persia-Apple-II @ 2524355 · licence, all uses