--- title: "Earth" id: 53795 type: "computer_media" slug: "earth" url: "http://localhost/computer_media/earth/" markdown_url: "http://localhost/computer_media/earth.md" published_at: "2024-05-13T18:56:52+00:00" modified_at: "2026-03-30T21:41:46+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "Dodge and shoot a drifting alien invader using custom sprite characters, a laser beam drawn with PLOT/DRAW, and lives tracked on screen." 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: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 53877 title: "SINCUS Exchange Tape 101 – Entertainment" type: "computer_media" url: "http://localhost/computer_media/sincus-exchange-tape-101-entertainment/" - id: 55430 title: "Timex Sinclair Public Domain Library Tape 2004" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2004/" media_type: "Program" images: - url: "http://localhost/wp-content/uploads/2024/05/earth.png" media_type_tags: "Game" --- This program implements a single-alien space shooter game where the player moves a ship left and right along the bottom row to intercept a descending alien that drifts randomly across the screen. The player uses keys 5 and 8 to move and 0 to fire a laser beam, which is drawn using PLOT and DRAW with INVERSE 1 for the erase pass and OVER 1 for cleanup. Three custom UDGs are defined at startup via POKEs into USR memory using packed sprite data read from DATA statements: UDG \a (player ship), UDG \b (alien), and UDG \c (explosion). The alien’s horizontal drift is kept in bounds with a corrective nudge using the expression 3 AND st<-30 and 3 AND st>30. A lives counter is maintained with up to five aliens displayed as icons on the status line, and a high-score is tracked across rounds within the same session. *** ## Program Analysis ### Program Structure The program is organized into a main game loop, a laser-fire subroutine, a UDG initialization subroutine, and an end-of-round handler. Control flow is as follows: 1. Line 5: Call subroutine at 1000 to define UDG sprites. 2. Lines 10–80: Initialize screen, high score, star field, status bar, and lives counter. 3. Lines 90–170: Main game loop — move player, drift alien downward, check collisions, handle laser firing. 4. Lines 200–222: End of round (alien reached player or hit); update high score, prompt for replay. 5. Lines 300–340: Laser fire subroutine — draw and erase beam, test hit. 6. Lines 500–520: Alien-reaches-bottom handler — deduct score, decrement lives, return or restart. 7. Lines 1003–1010: UDG definition subroutine using READ/DATA. ### UDG Sprite Definitions Three UDGs are defined at lines 1003–1004 using `POKE USR "\b"`, `POKE USR "\a"`, and `POKE USR "\c"` to set the alien, player ship, and explosion sprites respectively. Each UDG occupies 8 bytes, and all three are packed together in a single `DATA` statement at line 1005, read with a triple-variable `READ n,m,o` inside a loop from 0 to 7. This is an efficient technique that avoids separate READ statements for each UDG. ### Laser Beam Rendering The laser subroutine at line 300 uses a two-pass technique common in Spectrum BASIC graphics: - `PLOT INVERSE 1` followed by `DRAW INK 5,0,-117` draws the visible laser beam upward from the player position. - A `BEEP` provides audio feedback. - `PLOT INVERSE 1` and `DRAW OVER 1,0,-117` erase the beam using XOR mode. The player column is converted to pixel coordinates with `c*8+3`, placing the beam at the center of the character cell. ### Alien Movement and Boundary Correction The alien’s horizontal position `st` drifts each frame with `INT (RND*3)-1`, giving a random step of −1, 0, or +1. A soft boundary correction is applied at line 138: ``` LET st=st+INT (RND*3)-1+(3 AND st<-30)-(3 AND st>30) ``` The expression `3 AND st<-30` evaluates to 3 (true=1 in numeric context, but here `AND` returns the left operand when the condition is true) when `st` drifts too far left, nudging it back. This is a classic Sinclair BASIC idiom using the numeric value of boolean `AND`. ### Collision Detection Two collision checks are used: - **Alien reaches player row:** Line 145 checks `i=1 AND st=c` — if the alien is at row 1 and the same column as the player, a hit animation triggers and the round ends. - **Laser hits alien:** Line 320 checks `(i<17 AND i>1) AND st=c` after the beam is fired. A successful hit awards 100 points, adds a laser charge, plays a multi-tone explosion sequence, and jumps to line 85 (which does not exist, causing an implicit fall-through to line 90 — a deliberate technique to restart the alien). ### Lives Display Lives are stored in variable `co`, initialized to 5. The subroutine at line 504 renders alien icons (`\b` UDG) on the status line for each remaining life, and blanks icons for lost lives. The flag variable `l` controls whether the subroutine returns (during initialization) or falls through to restart the alien loop. ### Score and High Score Tracking The score `p` is updated both positively (hits, +100) and negatively (alien reaches bottom, −50). The high score `hp` persists across rounds within the same session; it is checked and updated at line 210. Both values are displayed inline via `INPUT` with expression printing at line 222, a space-saving Sinclair BASIC trick that uses `INPUT`‘s output capability without actually reading input in the usual sense — the semicolon suppresses the question mark prompt. ### Variable Summary | Variable | Purpose | | --- | --- | | `hp` | High score (persists across rounds) | | `p` | Current round score | | `c` | Player column (0–31) | | `co` | Lives remaining (0–5) | | `la` | Laser shots remaining | | `i` | Alien row (counts down from 20 to −1) | | `st` | Alien column (drifts randomly) | | `l` | Flag: 1=return from lives display subroutine | | `f` | Loop counter (reused for stars, UDGs, lives display) | | `g` | Loop counter for explosion sound | ### Notable Anomalies Line 90 is referenced by the laser hit handler (GO TO 85 jumps to a nonexistent line, which resolves to line 90 as the next existing line) and by line 520 after life loss. However, there is no line 90 in the listing — the program continues from line 92. This is intentional: GO TO a nonexistent line number between two existing lines is a recognized Spectrum BASIC technique that safely lands on the next higher line. Line 85 used as a restart target after a kill effectively maps to line 92. Line 165 trims the laser counter display with `PRINT AT 21,31;" "` when `la<10`, preventing a stale tens digit from remaining on screen after the count drops to a single digit. This is a straightforward display-cleanup idiom. ## Source Code ``` 1 REM earth 5 GO SUB 1000 10 PAPER 0: INK 7: BORDER 1: CLS 20 LET hp=0 50 CLS : FOR f=1 TO 50: PLOT INK RND*3+4,255.5*RND,175.5*RND: NEXT f 60 LET la=50: LET l=1: PRINT AT 21,0;"ALIENS";TAB 12;"PLAYER";TAB 24;"LASER" 70 LET p=0: LET c=16: LET co=5 80 GO SUB 504: LET l=0 92 LET i=20: LET st=INT (RND*20)+5 93 IF co=0 THEN GO TO 210 95 PRINT AT i,st; INK 1;"\b" 100 PRINT AT 1,c;" " 110 LET c=c+(INKEY$="8" AND c<31)-(INKEY$="5" AND c>0) 115 PRINT AT 1,c; INK 6;"\a" 122 BEEP .005,c 125 PRINT OVER 1;AT i,st; INK 5;"\b" 131 LET i=i-1 133 IF i=-1 THEN GO TO 500 138 LET st=st+INT (RND*3)-1+(3 AND st<-30)-(3 AND st>30) 140 PRINT OVER 1;AT i,st; INK 4;"\b" 143 PRINT AT 21,19;p;" " 145 IF i=1 AND st=c THEN PRINT AT 1,c; INK 5; FLASH 1;"\c": GO TO 200 160 IF INKEY$="0" AND la>0 THEN LET la=la-1: PRINT AT 21,30;la: GO SUB 300 165 IF la<10 THEN PRINT AT 21,31;" " 170 GO TO 100 200 FOR g=1 TO 30 205 OUT 254,RND*255 206 BEEP RND*.05,RND*24-12 208 NEXT g 210 IF p>hp THEN LET hp=p 221 PRINT AT 21,0 222 INPUT ;"Your Score=";(p)''"Hi'Score=";(hp): PAUSE 500: GO TO 10 224 GO TO 10 300 PLOT INVERSE 1,c*8+3,159 305 DRAW INK 5,0,-117 308 BEEP .05,12 309 PLOT INVERSE 1,c*8+3,159 310 DRAW OVER 1,0,-117 320 IF (i<17 AND i>1) AND st=c THEN LET p=p+100: LET la=la+1: PRINT AT 21,30;la: BEEP .1,2: PRINT OVER 1;AT i,c; INK 2;"\c": BEEP .2,3: PRINT OVER 1;AT i,c; INK 5;"\c": BEEP .1,4: PRINT AT i,c;" ": GO TO 85 340 RETURN 500 LET p=p-50: LET co=co-1 503 PRINT AT 21,19;" " 504 FOR f=1 TO 5 505 IF fco THEN PRINT AT 21,5+f;" " 510 NEXT f: IF l=1 THEN RETURN 520 GO TO 90 1003 FOR f=0 TO 7: READ n,m,o: POKE USR "\b"+f,n: POKE USR "\a"+f,m: POKE USR "\c"+f,o 1004 NEXT f 1005 DATA 16,165,165,16,189,24,56,255,165,124,255,90,186,126,90,254,36,165,254,60,24,170,24,165 1010 RETURN 9999 SAVE "earth" LINE 1: BEEP 1,32 ```