Robot Invasion is a Space Invaders-style arcade game in which the player controls a ground-based cannon that shoots upward to destroy three descending alien ships. The program uses UDG (User Defined Graphics) characters for the ship and cannon sprites, loaded via a DATA block into memory starting at USR “a” (character 144). Machine code routines are POKEd into addresses 23300–23550, and these are called via the USR function assigned to dummy variable lll, implementing sound and screen effects outside BASIC. The difficulty ramps up continuously through the variable lev, which increases each game loop iteration, making ships descend faster over time. The border color is set to black with a blue paper and bright attributes to create a space atmosphere, and POKE 23609,5 adjusts the keyboard repeat rate.
Program Analysis
Program Structure
The program is organized into distinct functional sections, with execution jumping around via GO TO and GO SUB. The entry point at line 5 is the title/credit REM, and actual execution begins at line 630 (via line 30), which loads UDGs and machine code before jumping to the intro/setup sequence.
- Lines 630–670: Initialization — load UDG sprite data and machine code routines via
READ/POKE. - Lines 520–610: Title screen and instructions, printed character-by-character with BEEP for a typewriter effect.
- Lines 50–110: Game variable initialization (score, lives, level, positions).
- Lines 300–340: Main game loop — calls paddle subroutine, alien movement subroutine, increments difficulty.
- Lines 150–180: Player input and cannon movement (keys 5/8), fire detection (key 0).
- Lines 190–270: Alien movement, drawing, and landing detection.
- Lines 280–290: Score/lives display subroutine.
- Lines 350–400: Landing/game-over handling.
- Lines 410–510: Fire (bullet) subroutine with hit detection.
Machine Code Integration
Two blocks of machine code are loaded into RAM via READ/POKE loops at lines 630–640. The first block fills UDG memory from USR "a" (address 65368 on a standard Spectrum/TS2068) through USR "a"+71, defining nine custom characters (9 × 8 bytes = 72 bytes). The second block occupies addresses 23300–23550, providing machine code routines for sound and display operations.
These routines are invoked throughout the game via the idiom LET lll=USR 23398, LET lll=USR 23375, LET lll=USR 23386, etc. The return value is discarded (assigned to dummy variable lll), which is a standard technique for calling machine code subroutines from BASIC without RANDOMIZE USR.
Distinct entry points within the machine code block suggest multiple routines: address 23375 (used during bullet travel), 23386 (used on a miss), and 23398 (used for sound/flash effects on hits and game-over).
UDG Sprite Usage
Nine UDGs are defined by the DATA at line 660. Their usage in the game (via \a through \i escapes) is mapped as follows:
| Escape | UDG | Usage |
|---|---|---|
\a | UDG A (144) | Player cannon body |
\c | UDG C (146) | Alien ship type 1 (INK 4, green) |
\d | UDG D (147) | Alien ship type 2 (INK 5, cyan) |
\e | UDG E (148) | Alien ship type 3 (INK 6, yellow) |
\g | UDG G (150) | Explosion / landed alien indicator |
\h | UDG H (151) | Hit flash overlay (OVER 1) |
\i | UDG I (152) | Bullet / explosion graphic |
Alien Movement Logic
Three aliens are tracked by row variables x1, x2, x3 (vertical position, rows 0–21) and column variables y1, y2, y3 (horizontal position, columns 0–31). Each frame, an alien descends by one row with probability proportional to lev (lines 200). Horizontal drift is random ±1 per frame (lines 210–230), with boundary clamping: -(y>25)+(y<5) nudges the column back within bounds.
The difficulty variable lev starts at 0.1 and increases by 0.005 each main loop iteration (line 320), so the descent probability gradually rises from 30% toward 100% as the game progresses. Each alien also has a slightly different base probability (lev+.2, lev+.1, lev), creating a speed hierarchy between the three ships.
Fire (Bullet) Subroutine
When the player fires (key 0), the subroutine at lines 410–510 draws a vertical line from the cannon’s position upward using OVER 1: PLOT … DRAW 0,140: OVER 0 (line 420), creating an XOR-drawn beam that erases itself on the next call. The bullet descends row by row from b=20 toward row 1, printing UDG \i at each row with a machine code delay call. Hit detection at lines 460–480 checks if the cannon’s column a matches each alien’s column (y1, y2, y3); a hit scores 100, 75, or 50 points respectively and resets the alien to a new starting row.
Game-Over Condition
Two distinct end conditions exist. First, if any alien reaches row 21 (line 260 triggers line 350): the game checks whether the player’s cannon column overlaps the landed alien’s column (line 360). If a life is lost (l=l-1) and lives remain, the game resets alien positions (line 370 jumps to line 60). Second, if a game-over occurs (line 380), a BEEP sweep plays and the program enters a loop (lines 390–400) that flashes the border at intervals using machine code, then restarts via RUN 520 (which clears variables and returns to the title screen).
Notable Techniques and Idioms
FOR n=SGN PI TO …is used in place ofFOR n=1 TO …—SGN PIevaluates to 1, saving a byte over the literal1.NOT PIevaluates to 0 (since PI is non-zero, NOT PI = 0), used throughout the DATA statements to represent zero bytes compactly.- The main loop at lines 300–340 uses
GO TO 300rather than aFORloop, which is faster for a real-time game loop. - Boolean arithmetic in movement expressions like
(INKEY$="8" AND a<25)returns 1 or 0, cleanly clamping the cannon’s column within bounds without IF statements. - The
OVER 1/OVER 0toggle on the bullet beam provides XOR-based sprite erasure without saving the background. POKE 23609,5at line 20 sets the keyboard REPDEL system variable to reduce key-repeat delay, improving responsiveness of the movement controls.- The typewriter effect in the instructions (line 590) uses
PRINT a$(n);in a loop withPAUSE 3andBEEP, a common Sinclair BASIC presentation technique.
Potential Bugs and Anomalies
- Line 360 computes
p=y1*(x1=21)+y2*(x2=21)+y3*(x3=21)to find the column of a landed alien. However, if two aliens land simultaneously (both at row 21),pwill be the sum of their columns rather than either individual column, potentially resulting in an out-of-range or incorrect position for the end-game graphic at line 370. - The condition
IF p<30at line 370 is used to distinguish a normal landing (loss of life) from an undefined scenario where the column sum exceeds 30, but the comment “when two ships land at the same time” (line 570) suggests this is the intended game-over trigger — however, two ships landing simultaneously could produce a sum less than 30 if both are in low-numbered columns, silently costing a life instead of ending the game. - The alien column boundary check
-(y>25)+(y<5)uses columns 5–25, but the screen is 32 columns wide, leaving the outer edges unused and providing a de-facto margin.
Content
Source Code
5 REM **FROM "SINCLAIR PROGRAMS"MAGAZINE,WRITTEN BY R.RAVEN of Oud-Beijerland,HOLLAND**
10 REM USE TIMEX-2068 OR SPECTRUM MODE
20 POKE 23609,5
30 GO TO 630
40 GO TO 520
50 LET s=0: LET l=3
60 LET lev=.1: LET a=15: LET x1=1: LET x2=1: LET x3=1
70 LET y1=INT (RND*10)+10
80 LET y2=INT (RND*10)+10
90 LET y3=INT (RND*10)+10
100 BRIGHT 1: BORDER 0: PAPER 1: INK 7: CLS
110 GO SUB 280
120 PRINT #0;AT 0,5; INK 6;"\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f"; INK 2;AT 1,5;"\.'\.'\.'\.'\.'\.'\.'\.'\.'\.'\.'\.'\.'\.'\.'"
130 FOR n=SGN PI TO 50: PLOT RND*255,RND*170: NEXT n
140 GO TO 300
150 LET a=a+(INKEY$="8" AND a<25)-(INKEY$="5" AND a>5)
160 PRINT AT 21,a-1; INK 7;" \a "
170 IF INKEY$="0" THEN GO SUB 410
180 RETURN
190 PRINT AT x1,y1;" ";AT x2,y2;" ";AT x3,y3;" "
200 LET x1=x1+(RND<lev+.2): LET x2=x2+(RND<lev+.1): LET x3=x3+(RND<lev)
210 LET y1=y1+INT (RND*3)-1-(y1>25)+(y1<5)
220 LET y2=y2+INT (RND*3)-1-(y2>25)+(y2<5)
230 LET y3=y3+INT (RND*3)-1-(y3>25)+(y3<5)
240 PRINT AT x1,y1; INK 4;"\c";AT x2,y2; INK 5;"\d";AT x3,y3; INK 5;"\d";AT x3,y3; INK 6;"\e"
250 BEEP .005,(x1+x2+x3)/5
260 IF x1>20 OR x2>20 OR x3>20 THEN GO TO 350
270 RETURN
280 PRINT AT 0,0; INK 6;"SCORE:";s;AT 0,15;"LIVES:";l;" "
290 RETURN
300 GO SUB 150
310 GO SUB 190
320 LET lev=lev+.005
330 IF RND>.9 THEN PLOT RND*255,RND*170
340 GO TO 300
350 PRINT AT 21,a;" ";#0;AT 1,5;" I N V A D E D "
360 LET p=y1*(x1=21)+y2*(x2=21)+y3*(x3=21)
370 IF p<30 THEN PRINT AT 21,p;"\g": LET lll=USR 23398: LET l=l-1: GO SUB 280: IF l>0 THEN GO TO 60
380 PRINT AT 10,10; INK 6;"GAME OVER": FOR n=-10 TO 10: BEEP .05,n: NEXT n
390 FOR n=SGN PI TO 1000: IF n=250 OR n=500 OR n=750 THEN LET lll=USR 23398: BORDER RND*6
400 NEXT n: RUN 520
410 LET b=20
420 OVER 1: PLOT a*8+4,22*8-8*b: DRAW 0,140: OVER 0
430 PRINT AT b,a; INK 2;"\i"
440 LET lll=USR 23375
450 OVER 1: PLOT a*8+4,22*8-8*b: DRAW 0,140: OVER 0
460 IF a=y1 THEN PRINT AT x1,y1; OVER 1;"\h": LET s=s+100: GO SUB 280: PRINT AT x1,y1; INK 2;"\i": LET lll=USR 23398: PRINT AT x1,y1;" ";AT b,a;" ": LET x1=1: LET y1=INT (RND*10)+10: RETURN
470 IF a=y2 THEN PRINT AT x2,y2; OVER 1;"\h": LET s=s+75: GO SUB 280: PRINT AT x2,y2; INK 2;"\i": LET lll=USR 23398: PRINT AT x2,y2;" ";AT b,a;" ": LET x2=1: LET y2=INT (RND*10)+10: RETURN
480 IF a=y3 THEN PRINT AT x3,y3; OVER 1;"\h": LET s=s+50: GO SUB 280: PRINT AT x3,y3; INK 2;"\i": LET lll=USR 23398: PRINT AT x3,y3;" ";AT b,a;" ": LET x3=1: LET y3=INT (RND*10)+10: RETURN
490 PRINT AT b,a;" "
500 LET lll=USR 23386
510 RETURN
520 INK 7: LET lll=USR 23398: BORDER 0: PAPER 1: BRIGHT 1: CLS
530 PRINT AT 1,8; INK 6;"ROBOT INVASION"
540 BEEP .5,-60: PRINT AT 4,1; INK 7;"The aim of this game is to"'"shoot down as many spaceships as possible."
550 FOR n=SGN PI TO 60: PRINT AT 8,RND*25+2; INK 5;"\g": BEEP .05,n: NEXT n: PRINT AT 8,2; INK 5;"\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g"
560 PRINT AT 10,1; INK 6;"Don't let them land."
570 PRINT AT 12,1;"You have 3 men."'"The game ends when you lose"'"them all, or when two ships"'"land at the same time.": BEEP 10,-50
580 LET a$=" Your controls are: 5 - LEFT 8 - RIGHT 0 - FIRE "
590 PRINT : FOR n=SGN PI TO LEN a$: PRINT a$(n);: BEEP .05,-40: PAUSE 3: NEXT n
600 LET lll=USR 23398
610 GO TO 50
620 STOP
630 RESTORE : FOR n=USR "a" TO USR "a"+71: READ code: POKE n,code: NEXT n
640 FOR n=23300 TO 23550: READ code: POKE n,code: NEXT n
650 GO TO 40
660 DATA NOT PI,NOT PI,8,8,28,62,85,NOT PI,NOT PI,8,8,8,8,8,8,NOT PI,NOT PI,60,90,255,219,66,90,NOT PI,NOT PI,60,126,255,165,126,60,NOT PI,NOT PI,NOT PI,28,34,65,127,42,NOT PI,255,255,170,85,170,NOT PI,NOT PI,NOT PI,24,36,189,165,102,60,36,66,NOT PI,129,66,36,NOT PI,36,66,129,128,13,33,2,16,34,4,48,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,197,213,67,16,254,10,203,199,203,207,203,215,211,254,12,21,32,240,209,193,201,197,213,175,203,199,203,207,203,215,67,16,254,203,231,211,254,67,16,254,203,167,211,254,21,32,239,209,193,201,22,3,30,128,205,50,91,29,32,250,201,30,NOT PI,22,32,205,29,91,28,21,32,249,201,30,NOT PI,22,128,205,29,91,28,21,32,249,201,33,3,91,35,86,35,94,35,78,35,205,29,91,13,32,250,125,254,28,56,239,201,33,3,91,35,86,35,94,35,78
670 DATA 35,205,50,91,13,32,250,125,254,28,56,239,201,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,NOT PI,0
680 SAVE "ROBOT" LINE 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

