Earth Attack

Developer(s): David Mold, Alvin Albrecht
Date: 1983
Type: Program
Platform(s): TS 2068
Tags: Arcade

Earth Attack is a side-scrolling shoot-’em-up in which the player pilots a ship across a cityscape, firing lasers at enemy craft and deploying smart bombs while protecting a set of shield units. The game relies heavily on machine code routines POKEd into RAM from DATA statements, covering functions including side-scrolling, collision/firing detection, smart-bomb blasts, and city building. Six UDG characters (A–F) are defined for the ship, enemies, refueling station, city blocks, and explosion graphics. Laser ammunition is tracked numerically and displayed on-screen, with score bonuses awarded for hits and penalties for enemy collisions; a high-score entry routine prompts the player for three initials when a new record is set. The attract-mode loop cycles through a title screen, a scoring guide, and a high-score table before waiting for the “S” keypress to start a game.


Program Structure

The program is organized into three broad phases: initialization (lines 20–50), the attract/menu loop (lines 1140–1400), and the main game (lines 80–690). Subroutines are clearly demarcated with REM labels and occupy lines 280–690 for game logic and lines 700–1130 for setup.

  1. Lines 20–50: Hardware setup — screen POKEs, beeps, and calls to UDG and machine-code loading subroutines.
  2. Lines 60–70: Variable initialization, then jump to attract loop at 1140.
  3. Lines 80–270: Main game loop — player movement, enemy spawning, collision, and firing.
  4. Lines 280–460: Firing, hit detection, life loss, and game-over logic.
  5. Lines 470–550: Smart-bomb subroutine with shield management.
  6. Lines 560–680: High-score name entry.
  7. Lines 700–790: UDG definition from DATA.
  8. Lines 800–1130: Machine code loading from DATA into RAM.
  9. Lines 1140–1400: Attract loop (title, scoring guide, high-score table).

Machine Code Usage

The game’s performance-critical routines are implemented as Z80 machine code, loaded from DATA statements into fixed RAM addresses. Five distinct routines are identified:

LabelStart AddressPurpose
Smart Bomb62400 (approx)Clears enemies from screen area
Side Scroll62426 (approx)Scrolls the playfield one step; called via USR 62426
Build City~62450Draws city graphics at game start
Check Firing62507 (approx)Traces laser beam, returns hit count in A register
Misc routines62300, 62350Loaded via p1/p2 pairs at lines 1040–1100

Machine code is loaded using a generalized loader subroutine at line 1110–1130: p1 holds the byte count and p2 the destination address; the loop READs and POKEs each byte. The value -12, -18, -4 etc. appearing in the DATA are signed relative jump offsets for Z80 DJNZ and JR instructions. A variable a appears in several DATA lines (e.g. lines 730–780) where the literal value 0 is expected; this is likely a bug — a will have whatever numeric value it held at READ time rather than the intended constant.

UDG Definitions

Six UDGs (A–F) are defined at lines 700–790 by POKEing 8 bytes each starting at USR "[UDG-A]". The loop structure has a minor anomaly: line 710 ends with NEXT p and line 720 also has a stray NEXT p, which would cause an error in most interpreters — this appears to be a listing artifact or typo. The UDG characters represent:

  • [UDG-A] — Player ship
  • [UDG-B] — Enemy craft (10 points)
  • [UDG-C] — Refueling station
  • [UDG-D] — Shield/city block
  • [UDG-E] — City pattern (inverse stripes)
  • [UDG-F] — Bonus enemy (20 points)

Key BASIC Idioms

Line 240 uses a conditional string expression to select which enemy graphic to print based on rg (a random value), using the Spectrum’s string AND idiom: ("string1" AND condition)+("string2" AND NOT condition) — when a boolean condition is true it returns 1 (string kept) or 0 (empty string). This selects between UDG-C and a colored UDG-F character inline without branching.

Line 200 uses a double-PEEK to read a two-byte system variable: PEEK (PEEK 23684 + 256 * PEEK 23685) retrieves the attribute of the character under the player sprite for collision detection via the ATTR system variable pointer.

The IN keyword is used extensively (lines 190, 210, 230, 260) to read the keyboard matrix ports directly, which is faster than INKEY$ and allows multiple keys to be detected each frame. Port values 64510, 63486, 61438, 32766, 65278 correspond to specific keyboard half-rows.

Line 440 uses PAUSE PI — since PI ≈ 3.14159 and PAUSE takes an integer argument, this effectively pauses for 3/50 of a second, a compact way to insert a very brief delay.

Game Logic and Scoring

Laser count (l) starts at 20 and decreases by 1 per shot. A pickup (attribute value 60, detected at line 360) grants 20 extra lasers. The shield system uses variable sb (starting at 3), decremented by smart bomb use; shields regenerate every 1000 score points via the bo (bonus) counter. Score is modified by machine code return values multiplied by 10 in lines 330 and 500.

Attract Loop

The attract sequence at lines 1140–1400 cycles through three screens — title/controls, scoring guide, high-score table — each waiting up to a PAUSE period for the “s” keypress. The title screen animates the game title in all seven INK colors (line 1199 loop). The scoring guide at lines 1270–1300 prints item descriptions character-by-character with a BEEP per character for a teletype effect.

Notable Anomalies

  • Variable a used as a literal 0 in DATA statements (lines 730–1000): BASIC’s READ will evaluate a as a numeric variable, so its value depends on prior computation — this is almost certainly a typographical error for the digit 0.
  • The double NEXT p at lines 710–720 in the UDG loader would cause a NEXT without FOR error on a second pass; the inner FOR loop at line 700 uses p, so the extra NEXT is spurious.
  • Line 690 contains a bare STOP statement that is never reached in normal execution; it serves as a safety barrier between subroutines.
  • Line 260 calls USR 62426 twice if a specific key is held, effectively double-scrolling — this appears intentional for the SHIFT “extra speed” feature mentioned in the instructions.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

Source Code

   10 REM      >>  EARTH ATTACK  <<                                     © ZX COMPUTING,     Oct/Nov 1983by David Mold,   TS 2068 versionby Alvin Albrecht                
   20 POKE 23730,190:POKE 23731,243:BEEP .5,12:BEEP .5,24:CLS :PRINT AT 10,8;"STOP THE TAPE!!!"
   30 GO SUB 700
   40 GO SUB 800
   50 BORDER 0
   60 LET s$="...":LET s=0:LET t=s:LET hs=s:LET bo=s
   70 GO TO 1140
   80 PAPER 0:INK 7:CLS :FOR n=0 TO 20:BEEP .005,n:NEXT n
   90 LET x=9:LET y=5:LET b=1
  100 FOR n=0 TO 7:PRINT PAPER 1; AT n,0,,:NEXT n
  110 LET s=0
  120 PRINT AT 20,0;"SCORE:";s
  130 LET a$="[UDG-A] [UDG-A] [UDG-A] [UDG-A] ":PRINT AT 20,15;a$
  140 FOR n=16 TO 19:PRINT AT n,0; PAPER 5,,:NEXT n
  150 LET l=20
  160 PRINT AT 0,0;"LASERS:";l;" "
  170 PRINT AT 0,16;"HI-SCORE:";hs
  180 PRINT AT 18,15; INK 2; PAPER 5;"[UDG-D][UDG-D][UDG-D]":LET sb=3
  190 LET x=x+(IN 64510<31)-(IN 63486<31):PRINT AT x,y;"[UDG-A]";
  200 LET p= PEEK (PEEK 23684+256* PEEK 23685):IF p THEN GO SUB 360
  210 IF IN 61438<31 THEN IF l THEN GO SUB 280
  220 IF RND>.79 THEN PRINT AT RND*5+8,31; INK 6;"[UDG-B]"
  230 IF IN 32766<31 THEN GO SUB 470
  240 LET rg= RND:IF rg>.96 THEN PRINT AT 15-b,31; INK 4;("[UDG-C]" AND rg>.98)+(CHR$ 16+ CHR$ 6+"[UDG-F]" AND rg <=.98):BEEP .005,10:BEEP .005,20
  250 LET b= INT (RND*3)+1
  260 PRINT AT x,y;" ":POKE 62477,b:LET a= USR 62426:IF IN 65278<31 THEN LET a= USR 62426
  270 GO TO 190
  280 REM >>Firing Subroutine<<
  290 LET l=l-1
  300 BEEP .005,30:LET a= USR 62507:IF a THEN BEEP .01,7:BEEP .01,0:GO TO 330
  310 PRINT AT 0,7;l;" "
  320 RETURN 
  330 LET s=s+10*a
  340 PRINT AT 20,6;s;" "; AT 0,7;l;" "
  350 RETURN 
  360 IF p=60 THEN :LET l=l+20:BEEP .01,20:GO TO 340
  370 FOR f=1 TO 4:BEEP .01,f*2:NEXT f:FOR f=4 TO 1 STEP -1:BEEP .01,f*2:NEXT f
  380 PRINT AT x,y; OVER 1;"#":BEEP .01,0:BEEP .01,-.5:BEEP .01,-1
  390 IF a$="!" THEN GO TO 440
  400 LET a$=a$(3 TO ):IF a$="" THEN LET a$="!"
  410 LET s=s-10:PRINT AT 20,15;a$;"  "
  420 PRINT AT x,y; INK 1;"█":LET a= USR 62426
  430 LET x=9:BEEP .3,0:PRINT AT 20,6;s;" ":RETURN 
  440 PRINT AT 4,10;"GAME OVER":FOR n=1 TO 8:LET a= USR 62300:BEEP .1,n:NEXT n:PAUSE PI:IF hs<s THEN LET hs=s:GO SUB 560
  450 GO TO 1140
  460 GO TO 90
  470 LET sb=sb-1
  480 IF INT (s/1000)>bo THEN LET sb=3:PRINT AT 18,15; INK 2; PAPER 5;"[UDG-D][UDG-D][UDG-D]"
  490 IF sb<0 THEN RETURN 
  500 LET s=s+10* USR 62400:BEEP .5,7:BEEP .5,0:PRINT AT 20,6;s;" ":PRINT AT 18,15+sb; INK 5;"█"
  510 IF INT (s/1000)>bo THEN LET sb=3:PRINT AT 18,15; INK 2; PAPER 5;"[UDG-D][UDG-D][UDG-D]"
  520 LET bo= INT (s/1000)
  530 FOR n=0 TO 31:POKE 62477, INT (RND*3)+1:LET a= USR 62426
  540 PRINT AT x,y-1; PAPER 8;" [UDG-A]":BEEP .01,n
  550 NEXT n:RETURN 
  560 PAPER 0:INK 6:CLS 
  570 PRINT "         EARTH ATTACK"
  580 LET a$="WELL DONE, YOU HAVE BEATEN THE  HIGH SCORE: PLEASE ENTER YOUR   INITIALS NOW"
  590 PRINT '''
  600 FOR n=1 TO LEN a$:PRINT a$(n);:BEEP .003,0:NEXT n
  610 LET s$=""
  620 PRINT ''"     ---"; CHR$ 8; CHR$ 8; CHR$ 8;
  630 FOR n=1 TO 3
  640 PRINT "?";
  650 PAUSE 0:LET p$= INKEY$:IF LEN p$ <>1 THEN GO TO 650
  660 PRINT CHR$ 8;p$;:LET s$=s$+p$
  670 BEEP .1,n:NEXT n
  680 PAUSE 50:RETURN 
  690 STOP 
  700 FOR p=0 TO 47:READ a
  710 POKE USR "[UDG-A]"+p,a:NEXT p
  720 NEXT p
  730 DATA 224,48,248,127,a,248,48,224
  740 DATA 24,36,126,129,a,126,0,a
  750 DATA 60,66,129,66,60,a,a,a
  760 DATA 0,64,92,126,a,92,64,0
  770 DATA 255,153,a,255,153,a,255,a
  780 DATA 93,42,54,127,85,a,20,54
  790 RETURN 
  800 REM >>SMART BOMB<<
  810 DATA 33,255,88,14,0,6,255,35,126,254
  820 DATA 6,32,7,12,62,8,119,16,-12,201
  830 DATA 198,16,119,16,-18,201
  840 REM >>SIDE SCROLL<<
  850 DATA 6,64,33,0,72,17,32,0,62,0
  860 DATA 119,25,16,252,33,0,89,6,8,17
  870 DATA 32,0,62,7,119,25,16,-4,1,0
  880 DATA 8,17,0,72,33,1,72,237,176,1
  890 DATA 0,1,17,0,89,33,1,89,237,176
  900 REM >>BUILD CITY<<
  910 DATA 6,0,14,15,62,22,215,121,215,62
  920 DATA 31,215,62,16,215,62,5,215,62,17
  930 DATA 215,62,0,215,62,148,215,13,16,-26
  940 DATA 201
  950 REM >>CHECK FIRING<<
  960 DATA 14,0,42,132,92,17,0,3,25,229,6,5,126,254,129,40,16,254,127,40,11,54,255,35,16,-14,118,118,118,118,24,47,12,197,237,82
  970 DATA 229,205,142,243
  980 DATA 0,66,36,24,24,36,66,0,118,118,225
  990 DATA 229,205,142,243,153,90,16,199,227,8,90,153,118,a,225
 1000 DATA 205,142,243,0,a,a,a,a,a,a
 1010 DATA 0,193,12
 1020 DATA 225,62,5,54,0,35,4,184,32,-7,6,0,201
 1030 REM >> CODE DATA <<
 1040 LET p1=199:LET p2=62399
 1050 GO SUB 1110
 1060 DATA 62,7,33,0,89,6,255,119,35,16,-4,118,61,32,-13,6,1,33,255,79,14,32,175,126,203,63,119,43,13,32,-8,62,71,188,32,-16,16,-21,201
 1070 LET p1=39:LET p2=62299
 1080 GO SUB 1110
 1090 DATA 6,8,209,26,19,213,119,17,0,1,25,16,-11,201
 1100 LET p1=14:LET p2=62349
 1110 FOR n=1 TO p1
 1120 READ a:POKE p2+n,a:NEXT n
 1130 RETURN 
 1140 INK 7:PAPER 0:CLS 
 1150 LET a$=" DAVID MOLD "
 1160 FOR n=1 TO LEN a$
 1170 PRINT a$(n);
 1180 NEXT n
 1190 FOR n=0 TO 7:INK n:PRINT AT 3,9;"EARTH ATTACK":BEEP .1,n
 1200 LET a$="         ":PRINT '"Use Keys:"'a$;"1-5......Up"''a$;"Q-T......Down"''a$;"6-0......Fire"''a$;"SHIFT....Extra Speed"''a$;"SPACE....Smart Bombs"
 1210 PRINT '"PRESS 'S' TO START"
 1220 NEXT n
 1230 PAUSE 250
 1240 IF INKEY$="s" THEN GO TO 80
 1250 CLS 
 1260 PRINT "EARTH ATTACK"''''
 1270 LET a$= CHR$ 13+ CHR$ 13:LET a$="[UDG-B]........10 POINTS"+a$+"[UDG-F]........20 POINTS"+a$+"[UDG-C]........REFUELLING Stn"+a$+a$+"PRESS 'S' TO START"
 1280 FOR n=1 TO LEN a$
 1290 PRINT a$(n);:BEEP .003,0:NEXT n
 1300 PAUSE 250:IF INKEY$="s" THEN GO TO 80
 1310 CLS 
 1320 PRINT "EARTH ATTACK"
 1330 PRINT "------------"
 1340 PAUSE 50
 1350 PRINT '''"HIGH SCORE=";hs:BEEP .1,10:PAUSE 50
 1360 PRINT '"LAST SCORE=";s:BEEP .1,9:PAUSE 50
 1370 PRINT ''"HIGH SCORE BY ";s$:BEEP .1,8
 1380 PRINT '''''"PRESS 'S' TO START"
 1390 PAUSE 200:IF INKEY$="s" THEN GO TO 80
 1400 GO TO 1140

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top