Stuntman is an arcade-style motorcycle jump game in which the player accelerates a bike and attempts to clear a row of double-decker buses. The program uses several blocks of machine code POKEd into memory starting at address 52000, handling screen scrolling and sprite animation routines called via RANDOMIZE USR. User-defined graphics (UDGs) are loaded through READ/DATA statements to render the bike, ramps, buses, and other game elements across characters A through L. Speed is simulated by having the player hold a key to build MPH, with a random braking component determining the jump arc calculated at line 170 using the formula J=9+INT(M/7.5+.5). The game tracks score and lives, awards a bonus for clearing all buses, and includes a scrolling title sequence and instruction screen driven by machine code scroll routines.
Program Structure
The program is organized into several distinct sections:
- Lines 10–50: Initialization — set up UDGs, machine code, and call the scene-drawing subroutine.
- Lines 60–140: Speed-building loop — the player holds a key to accelerate, releasing to commit to a speed.
- Lines 150–310: Jump sequence — calculate arc, animate bike up the ramp and across the screen.
- Lines 310–420: Success branch — animate bus crossing, print result, award score and life, loop.
- Lines 440–590: Scene setup subroutine — draws road, buses, ramps, score/lives display.
- Lines 600–740: Crash/game-over handling — crash animation, life decrement, end-of-game sequence.
- Lines 750–860: Loader section — POKEs UDG data and machine code into memory.
- Lines 860–1030: Title/intro sequence — animated logo, credits, instructions screen.
- Lines 1040–1080: Utility lines — SAVE, system POKEs, and a simple border/paper/CLS subroutine at 1080.
Machine Code Usage
Four machine code routines are POKEd into RAM starting at address 52000, loaded via READ/DATA statements at lines 810–850. They are called throughout the game using RANDOMIZE USR (to discard the return value) or LET L=USR (also discarding the value, but syntactically requiring an assignment).
| Address | Approximate Function | Called At |
|---|---|---|
| 52000 | Scroll or screen wipe routine | Lines 330, 700, 710, 720, 1020 |
| 52022 | Screen clear/reset helper | Lines 340, 410, 610, 630, 950, 1020 |
| 52044 | Parameterized effect (value in POKE 52046) | Lines 600, 630, 680, 690, 710, 720, 890 |
| 52069 | Animated sprite/scroll driver (POKE 52071 sets parameter) | Lines 50, 320 |
The parameter byte at address 52046 is set immediately before calling USR 52044, acting as a simple argument-passing mechanism. Similarly, address 52071 controls behavior of the USR 52069 routine, set to 1 before bus-clearing animation and reset to 5 afterward at line 320.
UDG Loading
Lines 750–800 load custom characters into UDG slots A through L. A loop from USR "A" to USR "I"+7 (covering nine 8-byte characters) reads from DATA at lines 760–770. Notably, the DATA at line 760 uses the variable X as a literal token inside the DATA statement — this is a known quirk where the BASIC tokenizer stores a numeric variable reference instead of a number, which resolves to 0 at runtime (since X has not yet been assigned). UDG “J” (lines 780) is filled with random bytes each run, likely to generate a randomized explosion or debris graphic. UDG “L” is loaded with a fixed wheel/tire pattern (line 800, DATA 124,130,170,130,84,68,56,254).
Jump Arc Calculation
The landing column J is computed at line 170 as J=9+INT(M/7.5+.5), where M is the effective speed after subtracting a random braking factor (Z-5, range −5 to +5) and a fixed deceleration of 40. This means a higher release speed produces a larger J, moving the landing point further along the screen. Success requires J=BUS+7 (line 310), where BUS is a random value from 2 to 18 (line 30), making the number of buses variable each round and requiring different speeds to clear different stacks.
Speed Building Loop
Lines 80–130 implement the throttle mechanic: line 80 waits for any key press, line 90 increments speed by 2+INT(RND*4) each iteration (giving 2–5 MPH per loop), and line 130 exits when the key is released. Speed is capped at 170 MPH (line 110). The sound at line 100 uses two BEEP calls at low pitches to simulate engine noise during acceleration.
Scrolling Title and Instruction Sequences
The intro at lines 860–1030 draws a geometric pattern using PLOT/DRAW and then animates the game title scrolling in from the right using a FOR Z=3 TO 23 loop at line 890. Each iteration prints a substring of a repeating UDG pattern, using the (Z+1) subscript on a string literal to truncate it — a compact horizontal scroll idiom in Sinclair BASIC. The instructions screen (lines 960–1030) uses UDG characters \\k and \\j to draw a decorative border around the “STUNTMAN” title.
Score and Lives Management
Score (SC) starts at 0 and increments by 100 per successful jump (line 390). Lives (LI) start at 3 (line 20) and gain one per successful jump (line 400), while a crash deducts one (line 640). When LI<=0 the game-over sequence fires at line 670. The scene subroutine at line 440 redraws the score and lives on each new round via line 580.
Notable Techniques and Idioms
NOT PIevaluates to 0 (since PI is non-zero, NOT returns 0), used throughout as a compact literal zero forATrow/column and INK color arguments.INT PIevaluates to 3, used at line 200 as the loop limit and at line 240 as a column argument.VAL "number"is not used here;GO TOtargets are all explicit line numbers.- Line 1080 is a minimal utility subroutine:
BORDER 7:PAPER 7:INK NOT PI:CLS :RETURN, called from multiple points to reset the display cleanly. - Line 630 uses
LET L=USR 52022— assigning the machine code return value to an otherwise unused variableLpurely to satisfy BASIC syntax, sinceUSRcannot appear as a statement alone. - Lines 720 and 730 check
S$for “N” and “Y” respectively after an INPUT, with a fallbackGO TO 700at line 740 for invalid input — a standard validation loop.
Anomalies and Notes
- Line 760 DATA contains the token
Xas a numeric value in the DATA stream. At the time the loop at line 750 runs,Xis uninitialized and will be 0, so all occurrences ofXin the DATA effectively supply 0 bytes to the UDG patterns. - Line 1000 contains a typo in the PRINT statement:
"\\f\\f\\g\\f\\g\\g"includes a stray extra character mid-sequence (\\f\\f\\g), likely a mistype of the repeating\\f\\gbus graphic pair. This would display a slightly malformed graphic on that row but is not a program-breaking bug. - Line 1050 contains a
REM IS (35)NORM.comment referencing a system variable, suggesting the developer experimented with thePOKE 23561,12setting (probably RAMTOP or a related pointer) during development. - Lines 1040 and 2000 are SAVE lines used for tape storage and are not part of normal program flow.
Source Code
10 POKE 23658,8:BEEP .1,10:GO SUB 750
20 LET SC=0:LET LI=3
30 RANDOMIZE :LET BUS= INT (RND*17)+2
40 GO SUB 440
50 RANDOMIZE USR 52069
60 LET M=0
70 PRINT AT 1,11;"0 M.P.H."
80 IF INKEY$="" THEN GO TO 80
90 LET M=M+2+ INT (RND*4)
100 BEEP .17,-50:BEEP .1,-55
110 IF M>170 THEN LET M=170
120 PRINT AT 1,11;M;" M.P.H."
130 IF INKEY$ <>"" THEN GO TO 90
140 LET MP=M
150 LET Z= INT (RND*11)
160 LET M=M+(Z-5)-40
170 LET J=9+ INT (M/7.5+.5)
180 FOR O=1 TO 120:NEXT O
190 IF M<-5 THEN LET J=6
200 FOR N=1 TO INT PI
210 PRINT PAPER 6; AT 10,N-1;""; AT 10,N-1;" \f\g"
220 BEEP .1,-50
230 NEXT N
240 FOR O=10 TO 15:BEEP .01,O:NEXT O:PRINT AT 10, PI;" "; AT 9,5;"IH"; AT 9,5;" "; AT 8,6;"\i\h":POKE 52046,10:RANDOMIZE USR 52044
250 IF J=6 THEN GO TO 300
260 FOR N=6 TO J
270 PRINT AT 8,N-1;" "; AT 8,N;" \i\h"
280 BEEP .1,-40:BEEP .1,-50:BEEP .1,-59
290 NEXT N
300 FOR O=1 TO 5:BEEP .01,J:NEXT O:PRINT AT 8,J;" "; AT 9,J+1;"\i\h"; AT 9,J+1;" "; AT 10,J+2;"\i\h"
310 IF J <>BUS+7 THEN GO TO 600
320 POKE 52071,1:RANDOMIZE USR 52069:FOR N=J+3 TO 29:PRINT AT 10,N-1;" "; AT 10,N;" \f\g":BEEP .1,-50:BEEP .01,45:BEEP .01,55:BEEP .1,-59:NEXT N:POKE 52071,5
330 PRINT AT 10,29;"\f\g ":RANDOMIZE USR 52000
340 RANDOMIZE USR 52022:GO SUB 1080
350 PRINT AT 8,11;"GREAT JUMP"
360 PRINT AT 10,2;"YOU CLEARED ALL ";BUS;" BUSSES AT"
370 PRINT AT 12,6;"A SPEED OF ";MP;" M.P.H."
380 FOR X=1 TO 600:NEXT X
390 LET SC=SC+100
400 LET LI=LI+1
410 RANDOMIZE USR 52022:CLS
420 GO TO 30
430 STOP
440 BORDER 5:PAPER 6:INK NOT PI:CLS
450 PRINT AT 11, NOT PI; INK 3;" \::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\:: "
460 PRINT AT 10,5;"\a\b"
470 FOR N=7 TO BUS+6
480 PRINT AT 10,N;"\e":NEXT N
490 PRINT AT 10,BUS+7;"\d\c"
500 PRINT AT 2, NOT PI;"\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''"
510 PRINT "\l\l\l\{16}\{1}\l\l\l\{16}\{2}\l\l\l\l\l\l\{16}\{0}\l\l\l\l\l\l\l\l\l\l\{16}\{2}\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\{16}\{1}\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\{16}\{4}\{16}\{2}\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\l\{16}\{9}"
520 PRINT INK 4; OVER 1;"\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::"
530 FOR J=12 TO 21:PRINT AT J, NOT PI; OVER 1; INK 4;"\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::":NEXT J
540 PLOT 0,152:DRAW 255,0
550 DRAW 0,-32:DRAW -255,0:DRAW 0,32
560 PLOT 0,128:DRAW 255,0:PLOT 0,120:DRAW 255,0
570 PRINT AT 6,0; PAPER 7;"\{20}\{1} \{19}\{1}S T U N T M A N\{19}\{0} \{20}\{0}"
580 PRINT AT 14,10; PAPER PI; INK 7;"SCORE:";SC;" "; AT 16,10; PAPER PI; INK 7;"LIVES:";LI;" "
590 RETURN
600 FOR N=1 TO 10:POKE 52046, INT (RND*10)+1:LET l= USR 52044:BEEP .1,-50:BEEP .1,-50:PRINT AT 10,j+2; OVER 1; BRIGHT 1; FLASH 1;"\j\k"; AT 10,j+2; OVER 1;"\k\j":NEXT N
610 RANDOMIZE USR 52022:GO SUB 1080
620 PRINT AT 10,6;"YOU HAVE CRASHED"
630 FOR J=1 TO 200:NEXT J:LET L= USR 52022
640 LET LI=LI-1
650 IF LI <=0 THEN GO TO 670
660 GO TO 40
670 BORDER 0:PAPER 0:INK 6:CLS
680 FOR Z=0 TO 8:POKE 52046,12:LET L= USR 52044:BEEP .1,-50:BEEP .1,-45:PRINT INK 6; AT 14,Z;" YOU SCORED ";SC:PRINT AT 14,Z+19;" \i\h":NEXT Z
690 FOR Z=0 TO 29:POKE 52046, INT (RND*5)+1:LET L= USR 52044:BEEP .1,-50:BEEP .1,-45:PRINT INK 7; AT 12,Z;"END OF GAME. NO LIVES LEFT "(Z+1);"\i\h":NEXT Z
700 RANDOMIZE USR 52000:INPUT "ANOTHER GAME(Y/N)? :";S$
710 FOR J=30 TO 0 STEP -1:POKE 52046,2:LET L= USR 52044:PRINT AT 12,J;"\f\g "; AT 14,J;"\f\g ":NEXT J
720 IF S$="N" THEN FOR Z=0 TO 8:POKE 52046,12:LET L= USR 52044:BEEP .1,-50:BEEP .1,-45:PRINT INK 6; AT 14,Z;" GOOD BYE ":PRINT AT 14,Z+13;" \i\h":NEXT Z:PAUSE 300:NEW
730 IF S$="Y" THEN LET S=0:GO TO 20
740 GO TO 700
750 FOR I= USR "A" TO USR "I"+7:READ X:POKE I,X:NEXT I
760 DATA 0,X,3,12,48,64,255,0,31,97,129,1,X,X,255,0,X,X,128,96,24,6,255,0,248,134,129,128,X,X,255,0
770 DATA 62,85,127,X,85,127,X,34,3,X,1,X,27,38,37,26,128,136,249,40,88,228,X,24,136,220,178,210,204,128,0,X,X,1,13,18,45,19,18,12
780 FOR I=0 TO 15:POKE USR "J"+I, INT (RND*254)+1:NEXT I
790 FOR I=0 TO 7:READ A:POKE USR "L"+I,A:NEXT I
800 DATA 124,130,170,130,84,68,56,254
810 FOR X=52000 TO 52101:READ A:POKE X,A:NEXT X
820 DATA 33,0,60,58,120,92,71,62,24,211,254,62,0,211,254,16,254,43,188,32,238,201
830 DATA 22,0,33,0,64,126,203,63,119,35,62,88,188,32,246,20,62,9,186,32,237,201
840 DATA 33,200,21,6,40,0,17,0,0,197,229,205,181,3,225,193,43,43,43,43,43,43,16,238,201
850 DATA 33,4,5,6,128,17,1,0,197,229,205,181,3,225,193,35,35,35,35,35,35,16,238,37,37,37,37,62,255,188,32,227,201
860 BORDER 0:PAPER 5:INK NOT PI:CLS :FOR F=100 TO 1 STEP -1:PLOT 132-F/2,105+F/2:DRAW F,0:NEXT F:FOR F=0 TO 40:PLOT 132-F,165-F:DRAW F*2,0:NEXT F
870 PRINT AT PI,14; PAPER 0; INK 6;"\{19}\{1}DAVID"; AT 5,13; INK 7;"RITCHIE" ; AT 7,16; INK 7;"\*\{19}\{0}"
880 PRINT AT 10,11;"JAN 1985 \*"
890 FOR Z=3 TO 23:POKE 52046, INT (RND*5)+1:LET L= USR 52044: BEEP .1,-50:BEEP .1,-45:PRINT INK 1; AT 18,Z;" \i\g\i\g\i\g\i\g\i\g\i\g\i\g\i\g\i\g\i\g\i\g"(Z+1);"\i\h"; AT 19,Z;" \i\g S T U N T M A N \i\g"(Z+1);"\i\h"; AT 20,Z;" \i\g\i\g\i\g\i\g\i\g\i\g\i\g\i\g\i\g\i\g\i\g"(Z+1);"\i\h":NEXT Z
900 FOR J=24 TO 29:BEEP .1,-50:BEEP .1,-55:BEEP .1,-45:PRINT AT 18,J," \i\h"; AT 19,J;" \i\h"; AT 20,J;" \i\h":NEXT J
910 PRINT AT 12,8;"SINCLAIR PROGRAMS":PLOT 64,72:DRAW 136,0
920 PRINT AT 14,7;"INSTRUCTIONS? (Y/N)"
930 INPUT A$:IF A$="y" OR a$="Y" THEN GO TO 950
940 IF a$="n" OR a$="N" THEN LET L= USR 52022:GO TO 1080
950 FOR J=29 TO 1 STEP -1:PRINT AT 18,J;"\i\g "; AT 19,J;"\i\g "; AT 20,J;"\i\g ":BEEP .1,-50:BEEP .1,-55:BEEP .1,-59:BEEP .1,-45:NEXT J:RANDOMIZE USR 52022:GO SUB 1080
960 BORDER NOT PI:PAPER NOT PI:INK 7:CLS :PRINT TAB 10;"\k\k\k\k\k\k\k\k\k\k"; TAB 10;"\kSTUNTMAN\k"; TAB 10;"\j\j\j\j\j\j\j\j\j\j"
970 PRINT AT 5, NOT PI;"IN THIS GAME,IT'S ON WITH YOUR CRASH HELMET AND AWAY YOU GO. YOU MUST JUMP OVER A LINE OF BIGDOUBLE DECKER BUSES. TO DO THIS HOLD DOWN ANY KEY, WATCH YOUR"
980 PRINT "SPEED INCREASE, LET GO OF THE BRAKES (REMOVE FINGER), AND WATCH YOUR STUNTMAN FLY OVER THE RAMPS......"
990 PRINT AT 19, NOT PI;"\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g P R E S S A K E Y \f\g\f\g"
1000 PRINT AT 21, NOT PI;"\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\g\f\f\g\f\g\g\f\g\f\g\f\g\f\g\f\g"
1010 PAUSE NOT PI
1020 RANDOMIZE USR 52022:GO SUB 1080
1030 RETURN
1040 SAVE "BIKE/STUNT":VERIFY "":BEEP .1,7:BEEP .1,7:STOP
1050 POKE 23609,7:POKE 23658,8:POKE 23561,12:REM IS (35)NORM.
1060 STOP
1070 RETURN
1080 BORDER 7:PAPER 7:INK NOT PI:CLS :RETURN
2000 SAVE "BIKE/STUNT" LINE 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.


