--- title: "Robot Invasion" id: 55721 type: "computer_media" slug: "robot-invasion" url: "http://localhost/computer_media/robot-invasion/" markdown_url: "http://localhost/computer_media/robot-invasion.md" published_at: "2024-07-05T00:18:47+00:00" modified_at: "2026-03-30T21:45:13+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/07/SCR-20240704-oaac.png" excerpt: "A Space Invaders-style shooter with machine code routines, custom UDG sprites, and escalating difficulty — all packed into a tight BASIC game loop." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Arcade" slug: "arcade" taxonomy: "genre" url: "http://localhost/type/arcade/" - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 55711 title: "ISTUG Public Domain Library 8" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-8/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Robot%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/07/SCR-20240704-oaac.png" - url: "http://localhost/wp-content/uploads/2024/07/SCR-20240704-oaek.png" media_type_tags: "Arcade, Game" --- 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. 1. Lines 630–670: Initialization — load UDG sprite data and machine code routines via `READ`/`POKE`. 2. Lines 520–610: Title screen and instructions, printed character-by-character with BEEP for a typewriter effect. 3. Lines 50–110: Game variable initialization (score, lives, level, positions). 4. Lines 300–340: Main game loop — calls paddle subroutine, alien movement subroutine, increments difficulty. 5. Lines 150–180: Player input and cannon movement (keys 5/8), fire detection (key 0). 6. Lines 190–270: Alien movement, drawing, and landing detection. 7. Lines 280–290: Score/lives display subroutine. 8. Lines 350–400: Landing/game-over handling. 9. 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 of `FOR n=1 TO …` — `SGN PI` evaluates to 1, saving a byte over the literal `1`. - `NOT PI` evaluates 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 300` rather than a `FOR` loop, 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 0` toggle on the bullet beam provides XOR-based sprite erasure without saving the background. - `POKE 23609,5` at 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 with `PAUSE 3` and `BEEP`, 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), `p` will 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<30` at 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. ## 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+(RND25)+(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 ```