This is a space docking arcade game in which the player manoeuvres a ship (displayed using inverse-video characters) upward toward a randomly positioned fuel satellite, using Z/M keys to move left and right and A to ascend. The program opens with a RAND USR 16514 call to execute a machine-code routine before entering the main game loop. Scoring increments by 210 points per successful docking, and the game tracks how many ships the player has saved across rounds. A subroutine at line 650 draws star-field dots using PRINT AT with RND coordinates and resets a system variable via POKE 16418. Line 702 provides a brief flashing “SAVED” animation implemented with nested delay loops rather than PAUSE.
Program Analysis
Program Structure
The program is organised into a main game loop with several supporting subroutines and an instructions page branched to by a non-existent GOTO 9000 hint on screen. The overall flow is:
- Lines 1–4: Machine-code initialisation (
RAND USR 16514) withFAST/SLOWframing. - Lines 5–82: Variable setup, initial screen draw, star-field and HUD setup via
GOSUB 650. - Lines 90–230: Core game loop — place satellite, move ship, handle keys, detect collision.
- Lines 300–310: Successful docking — advance satellite row, redraw.
- Lines 350–361: Ship lost — increment round counter, award points, flash “SAVED” message, continue.
- Lines 500–645: Game-over screen, pause loop, restart.
- Lines 650–701: Star-field / HUD draw subroutine.
- Lines 702–730: “SAVED” flash animation subroutine with software delay.
- Lines 9000–9020: In-game instructions page (reached only by the player typing
GOTO 9000). - Lines 9998–9999:
SAVE/RUNloader stub.
Machine Code Usage
Line 3 executes RAND USR 16514. Address 16514 (0x4082) sits in the ZX81 system variable / display file area. This is a common technique to invoke a short machine-code patch that has been pre-loaded elsewhere in RAM — here presumably to patch display behaviour or set up the character set, since the game makes heavy use of inverse-video text.
Key Variables
| Variable | Role |
|---|---|
A | Constant 1 (PI/PI), used everywhere in place of the literal 1 to save memory |
B | Constant 0 (PI-PI), used as a zero sentinel throughout |
V | Fuel / move counter (counts down from 600) |
S | Ship row position |
T | Ship column position |
X | Satellite column (random) |
Y | Satellite row (starts at 15, advances up by 5 on each dock) |
R | Ships saved counter |
G | Score (total points) |
P | Loop counter used in both the game-over pause and the flash animation |
Notable BASIC Idioms
- PI arithmetic for constants:
LET A=PI/PI(=1) andLET B=PI-PI(=0) are classic ZX81 memory-saving idioms. Using these named variables avoids storing floating-point literals in every subsequent expression. - Boundary clamping: Lines 170–180 clamp
TbetweenB(0) and 25, preventing the ship from leaving the screen horizontally. - Collision detection: Line 210 checks
T=X AND S=Y-A(ship column matches satellite column and ship row is one above the satellite row) for a successful dock. Line 220 handles the “wrong column, same row” case by resetting the ship downward. - POKE 16418,0: In the star-field subroutine (line 654) this zeroes the ZX81 system variable
FRAMES(low byte), commonly done to reset the frame counter or suppress cursor flicker side-effects.
Graphics and Display
All sprites are rendered using PRINT AT with inverse-video characters encoded as %X escapes. The player’s ship at line 110 shows as % %<\..%>% — a stylised craft. The satellite at line 100 is % %<%O%>% . The docking bay frame (lines 21–22) uses block-graphic characters (▘, ▖, ▌, ▟, etc.) to draw a bay outline at the bottom of the play area. Stars are scattered randomly by printing inverse full-stop characters (%.) at random positions in the subroutine at lines 650–654.
Animation and Timing
The “SAVED” flash at lines 702–720 alternates between printing %S%A%V%E%D and blank spaces three times, with a short software delay loop (lines 724–730, counting to 3) between each frame. This is a purely software-timed approach with no PAUSE statement. The game-over pause (lines 550–575) similarly uses a FOR loop counting to 100 as a delay before restarting.
Scoring
On a successful docking (line 355), the score G is incremented by 210 (110+100). The initial value of G at line 6 is set to a random number in the range 0–349 (INT(RND*350)), effectively randomising the starting score — this appears intentional as a quirky design choice rather than a bug, though it makes score comparison between games inconsistent.
Bugs and Anomalies
- Line 6 sets
G=INT(RND*350)immediately before the game loop, giving a random initial score. This is likely unintentional and means the displayed final score is not purely merit-based. - The
IF INKEY$="A" THEN LET S=S-Aat line 160 only moves the ship upward; there is no downward key defined. The ship can only ascend or hold position, which makes boundary clamping onS(visible at line 200 checkingS=B) the only lower-bound check. - Line 190 checks
V=B(fuel=0) butVis decremented by 1 each iteration (line 130). SinceVstarts at 600 and decrements by the constantA(which is exactly 1.0), this will reach exactly 0 and the check will fire correctly. - The instructions at lines 9000–9020 are only accessible if the player manually types
GOTO 9000; the status bar at line 655 advertises “INST.GOTO 9000” for this purpose.STOPat line 9020 halts the program after displaying instructions rather than returning to the game.
Content
Source Code
1 REM Y% \.'\. :%KNOT $TAB \@@RND\: TAB \'.RNDTAN
2 FAST
3 RAND USR 16514
4 SLOW
5 LET G=0
6 LET G=INT (RND*350)
7 GOSUB 650
10 LET A=PI/PI
20 LET B=PI-PI
21 PRINT AT 20,15;"\':\.:% \:.\:'"
22 PRINT AT 21,14;"\.:% % % % % \:."
30 LET R=B
40 LET V=600
50 LET S=18
60 LET T=15
65 LET Y=15
80 PRINT AT 0,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
81 PRINT AT 1,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
82 GOSUB 650
90 LET X=INT (RND*25)
100 PRINT AT Y,X;"% %<%O%>% "
110 PRINT AT S,T;"% %<\..%>% "
112 PRINT AT 19,15;"% % \''% % "
120 PRINT AT S+A,T+A;"% % % % % "
130 LET V=V-A
140 IF INKEY$="Z" THEN LET T=T-A
150 IF INKEY$="M" THEN LET T=T+A
160 IF INKEY$="A" THEN LET S=S-A
170 IF T<B THEN LET T=B
180 IF T>25 THEN LET T=25
190 IF V=B THEN GOTO 500
200 IF S=B THEN GOTO 350
210 IF T=X AND S=Y-A THEN GOTO 300
220 IF S=Y-A AND T<>X THEN GOTO 50
230 GOTO 110
300 LET Y=Y-5
310 GOTO 80
350 LET R=R+A
351 PRINT AT 0,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
352 PRINT AT 1,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
355 LET G=G+110+100
356 PRINT AT 20,1;"%P%O%I%N%T%S% ";G
357 GOSUB 702
361 GOTO 50
500 CLS
510 PRINT AT 10,11;"%G%A%M%E% %O%V%E%R"
520 PRINT AT 12,5;"**YOU SAVED ";R;" SHIPS**"
530 PRINT AT 14,8;"TOTAL POINTS ";G
550 FOR P=1 TO 100
575 NEXT P
642 CLS
645 GOTO 1
650 PRINT AT RND*15,RND*31;"%."
651 PRINT AT RND*15,RND*31;"%."
652 PRINT AT RND*15,RND*31;"%."
653 PRINT AT RND*15,RND*31;"%."
654 POKE 16418,0
655 PRINT AT 22,0;"% SPACE DOCKING---INST.GOTO 9000% "
656 PRINT AT 23,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
701 RETURN
702 PRINT AT 3,13;"%S%A%V%E%D"
704 LET P=0
706 GOSUB 724
708 PRINT AT 3,13;"%S%A%V%E%D"
710 GOSUB 724
712 PRINT AT 3,13;"% % % % % "
714 GOSUB 724
716 LET P=P+1
718 IF P=3 THEN RETURN
720 GOTO 708
724 LET T=0
726 LET T=T+1
728 IF T=3 THEN RETURN
730 GOTO 726
\n9000 PRINT AT 2,0;"PRESS(A)TO MAKE YOUR SHIP GO UP"
\n9002 PRINT AT 4,0;"PRESS(Z)TO GO LEFT"
\n9004 PRINT AT 6,0;"PRESS(M)TO GO RIGHT"
\n9006 PRINT AT 8,0;"YOU MUST BE DIRECTLY UNDER THE"
\n9008 PRINT AT 9,0;"FUEL SATELLITE TO CONTINUE."
\n9010 PRINT AT 11,0;"WHEN CONTACT IS MADE, HOLD KEY (A)MOMENTARILY"
\n9020 STOP
\n9998 SAVE "SPACE DOCKIN%G"
\n9999 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
