Moonbase is a lunar lander simulation in which the player controls descent thrust and lateral drift to guide a spacecraft onto a randomly generated moonscape. Each game turn the program updates velocity, height, fuel, and time using simple physics: thrust reduces velocity by a cubed fraction, while random perturbations add realism to both trajectory and fuel consumption. The lunar surface is drawn each frame using a dense sequence of Spectrum block-graphic escape characters at line 210, including a randomly placed landing pad whose position is stored in variable M. Collision detection at line 20 checks that height, velocity, and horizontal proximity to the pad all fall within safe tolerances before awarding a score based on landing speed.
Program Analysis
Program Structure
The program is divided into several functional blocks:
- Initialisation (lines 420–510, then 700): Sets starting height
H=1450, randomises fuelF, landing pad positionM, lateral offsetZ, and zeroes velocity/time/thrust/drift. - Main game loop (lines 50–340): Updates physics, draws the scene, reads player input, and loops back via
GOTO 50. - Collision/boundary subroutine (lines 20–40): Called via
GOSUB 20; checks for successful landing, escape velocity, or out-of-bounds conditions. - Outcome screens (lines 350–410): Separate branches for crash, successful landing, and escape velocity, each ending in an infinite
GOTOloop.
Physics Model
The simulation uses a simplified but plausible physics model each turn:
LET A=A/7(line 50) — scales the raw thrust input down before it is applied.LET V=V+A**3-12-3*RND(line 70) — velocity changes by the cube of scaled thrust minus a gravitational constant (12) and a noise term. Using**(power) rather than squaring gives non-linear throttle response.LET H=H+V-20+10*RND(line 80) — height changes by velocity plus a small random perturbation.LET F=F-(ABS(A)+ABS(B/5)*6*RND)(line 90) — fuel is consumed by both thrust and lateral drift, with drift consumption randomised.LET Z=Z+B/2+2-RND*3(line 130) — lateral position drifts by inputB, a constant 2, and random noise.
Display Technique
The spacecraft sprite is a simple three-character shape printed with PRINT AT 16-U,Z+1;"\ .\''\. " (line 170), using Spectrum block graphics to form a lander outline. The previous sprite position is erased each frame with spaces at the saved coordinates W, X (line 160) before the new position is drawn — a straightforward sprite-erase idiom.
The lunar surface at line 210 is a single long PRINT AT 16,0 statement filled with block-graphic escape sequences, creating a textured ground strip. The expression ( TO M-1) is a Spectrum string-slice applied to the surface string, which means only the left portion up to the landing pad column is printed, leaving a gap at position M to represent the pad. This is a compact and clever way to insert a variable-width landing zone into a fixed graphic string.
Landing Detection
The subroutine at line 20 checks four simultaneous conditions for a successful landing:
H<50— near the surfaceV<20— descent velocity not too fastV>-15— not moving upward too fastABS(Z-M)<5— horizontally close to the landing pad
Line 30 checks H>1750 for escape velocity (the lander has climbed too high). Line 110 catches a crash via H<20 (hit the ground off-pad) or F<5 (fuel exhausted). A notable detail: the subroutine is reached via GOSUB 20, but the successful landing branch at line 370 is referenced in the condition yet line 370 does not exist in the listing — it likely falls through to line 380, which is the success screen, making this a deliberate line-number jump to the next available line.
Score Calculation
On a successful landing, line 380 computes a score as 100*(30-INT ABS V)+INT V. The first term rewards slower landings (lower ABS V gives a higher multiplier), while the second adds a small component from the signed velocity. For very soft landings near zero velocity the score approaches 3000.
Input Handling
<
Player input uses plain INPUT A and INPUT B statements (lines 300, 320). Line 302 enforces non-negative thrust with IF A<0 THEN LET A=A*-1 rather than ABS, which is functionally equivalent. A short delay loop (FOR K=1 TO 85, lines 332–333) paces the game between turns.
Infinite Loop Endings
All three outcome screens terminate in infinite GOTO loops (lines 363, 402, 410) — a common technique to hold the final display. Line 363 loops back to line 362, which prints a blank line, effectively scrolling the screen; this is a quirky but functional way to prevent the player returning to the game without a break/reset.
Notable Anomalies
- Lines 140, 150, 200, 220–270 are absent from the listing, leaving gaps in the line numbering. This suggests the program was edited or condensed from a longer original.
- Line 700 jumps directly into the middle of the main loop at line 60, bypassing the surface-draw and input sections on the very first iteration — the initial frame is never displayed before the first input is requested.
- The
REMat line 0 stores the program title and author credits, a common practice to embed metadata at a fixed, easily findable address. - Lines 720–740 (
CLEAR,SAVE,RUN) are utility lines appended afterSTOPat line 710 and are not part of normal execution flow.
Content
Source Code
0 REM "MOONBASE" BY TIM HARTNELL REVISIONS BY TONY WILLING
5 CLS
10 GOTO 420
20 IF H<50 AND V<20 AND V>-15 AND ABS (Z-M)<5 THEN GOTO 370
30 IF H>1750 THEN GOTO 400
40 RETURN
50 LET A=A/7
60 LET T=T+4+INT (RND*2+1)
70 LET V=V+A**3-12-3*RND
80 LET H=H+V-20+10*RND
90 LET F=F-(ABS (A)+ABS (B/5)*6*RND)
100 GOSUB 20
110 IF H<20 OR F<5 THEN GOTO 350
120 LET U=H/100
130 LET Z=Z+B/2+2-RND*3
160 PRINT AT W,X;" "
170 PRINT AT 16-U,Z+1;"\ .\''\. "
180 LET W=16-U
190 LET X=Z+1
210 PRINT AT 16,0;"\..\;;\!!\. \.'\.'\'.\..% \:'\:.\.:\:'\:'\.'\':\!!\;;\:.\.:\.:"( TO M-1);"\.'\..\,,\..\'."
280 PRINT AT 17,0;"VEL: ";INT V;" ","FUEL: ";INT F;" ","TIME: ";INT T;" ","HEIGHT: ";INT H;" "
290 PRINT "THRUST? ";
300 INPUT A
302 IF A<0 THEN LET A=A*-1
310 PRINT A;" ","DRIFT? ";
320 INPUT B
330 PRINT B
332 FOR K=1 TO 85
333 NEXT K
335 PRINT AT 19,23;" "
340 GOTO 50
350 PRINT "%C%R%A%S%H\ '\ '%S%P%E%E%D ";ABS V," ";
352 FOR K=1 TO 90
353 NEXT K
354 CLS
360 PRINT "%A% %C%R%A%T%E%R% ";INT (ABS V*(RND+1));"% %F%E%E%T% %D%E%E%P% %W%I%L%L% %B%E% % %N%A%M%E%D% %I%N% %Y%O%U%R% %H%O%N%O%R% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
361 PRINT "%T%H%E% %N%E%X%T%-%O%F%-%K%I%N% %W%I%L%L% %B%E% %N%O%T%I%F%I%E%D"
362 PRINT " "
363 GOTO 362
380 PRINT "%S%U%C%C%E%S%S%F%U%L% %L%A%N%D%I%N%G\@@%R%A%T%I%N%G ";100*(30-INT ABS V)+INT V;"\##";
390 GOTO 402
400 PRINT "%Y%O%U% %H%A%V%E% %R%E%A%C%H%E%D% %E%S%C%A%P%E% %V%E%L%O%C%I%T%Y"
402 PRINT " "
410 GOTO 402
420 LET H=1450
430 LET F=827+50*RND
440 LET T=0
450 LET Z=15*RND
460 LET A=1
470 LET B=0
480 LET M=19*RND
490 LET V=0
500 LET W=0
510 LET X=0
700 GOTO 60
710 STOP
720 CLEAR
730 SAVE "1020%1"
740 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
