--- title: "Invaders" id: 51902 type: "computer_media" slug: "invaders-2" url: "http://localhost/computer_media/invaders-2/" markdown_url: "http://localhost/computer_media/invaders-2.md" published_at: "2023-08-16T01:42:21+00:00" modified_at: "2026-04-03T07:59:11+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "A complete Space Invaders clone with five alien types, direct memory animation, a bonus jet sequence, and a persistent high-score display — all in BASIC." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Bug-Byte Software" slug: "bug-byte-software" taxonomy: "post_tag" url: "http://localhost/tag/bug-byte-software/" - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Arcade" slug: "arcade" taxonomy: "genre" url: "http://localhost/type/arcade/" - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/Invaders (1982)(Bug-Byte)(UK)(TS1000)(Cassette).zip" mediadate: "1982" producer_company: - id: 10706 title: "Bug-Byte Software" type: "company" url: "http://localhost/company/bug-byte-software/" related_products: - id: 12934 title: "Invaders" type: "product" url: "http://localhost/product/invaders/" media_type_tags: "Arcade, Game" --- Invaders is a Space Invaders-style arcade game that uses direct memory PEEK and POKE operations to manipulate the display file for smooth character-cell animation. The player sprite and alien formations are positioned using absolute memory addresses calculated from the system variable at address 16398/16399 (the display file pointer, stored in E1), allowing the gun to move left and right along the bottom row while waves of aliens scroll downward. Five alien types are cycled through using a pattern-index variable D, each rendered with a different block-graphic character combination, and each worth a different point value (20–50 points). The game includes a high-score tracker, a multi-wave progression system, a bonus jet escape sequence, and a “DANGER” warning when aliens reach a critical row. *** ## Program Analysis ### Program Structure The program is organized into several functional regions, loosely separated by line number ranges: - **Lines 1–10:** Initialization, high-score reset, title block, jump to setup. - **Lines 80–99:** Per-wave setup — reset score display, draw play field, branch to alien shape selector via `GOTO 100*D`. - **Lines 100–510:** Alien shape definitions (five variants) and animation frame cycling. - **Lines 600–630:** Subroutine to fill the play area rows with solid inverse blocks. - **Lines 1500–1840:** Keyboard input handler and player gun movement via POKE. - **Lines 1900–2900:** Main game loop — alien scroll, collision, bonus jet sequence, scoring. - **Lines 7000–7100:** Game-over handler with flashing death animation and score display. - **Lines 7397–7450:** Title/attract screen with animated “GET YOURSELF READY” text. - **Lines 7500–7695:** Wave-start subroutine — animates player gun appearing from top of screen. - **Lines 8020–8600:** Fire (laser) subroutine — traces bullet upward using POKEs, tests for hit. - **Lines 9005–9950:** Screen setup subroutine — reads display file base address into `E1`, draws border and title banner. ### Display File Addressing The core technique throughout is computing absolute display-file addresses to animate characters without using `PRINT AT`. The subroutine at line 9005 reads the display file start address from system variables 16398–16399 and stores it in `E1`. All subsequent POKE/PEEK operations use offsets from `E1`; for example, each row is 33 bytes wide (32 character columns plus one attribute/newline byte in the ZX81 file format), so adding 33 advances one row. The player gun position is tracked in `Y1`, initialized at `E1+705` (row 21, roughly column 12), and incremented or decremented by 1.5 per keypress — an unusual fractional step that still produces integer POKE targets due to how BASIC truncates addresses. ### Alien Shape Cycling Five alien shapes are defined in `A$` at lines 100, 200, 300, 400, and 500, each using different block graphic characters to simulate animation frames. The variable `D` (1–5) selects the current frame, and `GOTO 100*D` at line 99 is a computed branch — a classic BASIC optimization avoiding a chain of `IF` statements. After printing, line 510 advances `D` with wrap-around: `LET D=D+1-5*(D=5)`, cycling D through 1→2→3→4→5→1. ### Main Game Loop and Alien Scroll The alien formation is drawn using `PLOT`/`PRINT` pairs. `PLOT col,row` positions the cursor, then `PRINT A$` renders the alien string. Ten columns of aliens are drawn per pass (lines 2001–2091), with the loop variable `S` counting down from a difficulty-dependent starting row `Q` (10, 22, 22, 18, or 14 depending on `D`) toward row 4 in steps of 4. After each alien print, `GOSUB 1500` checks for key input, giving the player opportunities to move and fire during the alien descent. When aliens reach row 6 (`S=6`), a “DANGER” warning is printed and `T1` is incremented. After three such warnings (`T1=3`, line 2091), the game jumps to the bomb-hit sequence at line 2900. ### Laser Fire Mechanism Firing is handled at line 8020. The subroutine traces a bullet upward from the gun position `Y1` by POKEing character codes at successive addresses 66 bytes apart (two rows up per step), creating a moving dot effect. Hit detection at line 8125 checks whether the bullet’s column position falls within the alien string bounds by comparing `(Y1-U)` against a range derived from `PEEK 16438` (the print position register). Line 8150 then checks whether the character at that position in `A$` equals `CHR$ 52` (the character “4”, used as the alien center pixel “O”) to confirm a hit rather than striking empty space. ### Bonus Jet Sequence When the aliens are defeated (scroll completes without collision), the game triggers a bonus sequence (line 2200 onward). A jet icon (`▝X▘`) appears randomly at the left or right edge of row 20. The player must guide their gun to intercept it: the code traces a path across the display file from `W+33` downward, animating movement with POKEs (characters 189, 190, 128), then checks alignment with the gun. A successful intercept awards 100 points and triggers an explosion animation (lines 2355–2365) using `+`, `*`, `=`, and inverse-block characters in a loop. ### Scoring and High Score Points are accumulated in `S1`. Each alien hit scores `D*10` points (line 8500), so wave 1 aliens are worth 10 pts and wave 5 aliens worth 50 pts — matching the score table displayed on the attract screen (lines 7400–7404). The bonus jet awards a flat 100 pts. The high score is stored in `HI` (initialized to 500) and `HS` flags a new high score. When a new high score is achieved, lines 7057–7070 POKE a flashing “NEW HIGH SCORE” message directly into the display file using alternating normal and inverse character codes (toggled by `128*(INT(J/2)=J/2)`). ### Notable Techniques - `GOTO 100*D` — computed GOTO used as a jump table for five alien sprite variants. - `LET D=D+1-5*(D=5)` — Boolean arithmetic for modular cycling without IF. - Fractional gun step (`Y1±1.5`) — unusual but functionally equivalent to ±1 for POKE addressing due to integer truncation in the memory address context. - Display file manipulation via PEEK 16398/16399 — portable within the platform, since the display file can move depending on program size. - Row width of 33 bytes — correctly accounts for the ZX81 display file format where each row is 32 character bytes plus a NEWLINE token. - Attract screen animation (lines 7406–7414) — builds “GET YOURSELF READY” one character at a time across successive PRINT statements for a typewriter effect. - `POKE 16442,4` at line 9123 — sets the system variable MARGIN, adjusting the left margin of the display. ### Bugs and Anomalies - Line 1700 is referenced by line 1510 (`GOTO 1700`) but the actual movement code starts at line 1710. Line 1700 does not exist, so the branch falls through to 1710 — a well-known technique that works correctly here. - The empty loops at lines 7565–7570, 7595–7596, and 7645–7646 (`FOR J=1 TO 5: NEXT J` with no body) serve as deliberate timing delays. - `B$` is set at line 98 but its length (13 characters) and the hit-detection comparison at line 8590 check for 14 characters (`"██████████████"`) — a possible off-by-one that may prevent the all-clear condition from triggering reliably. - Line 2200 computes `B=33*((42-S)/2)+(Y1-U)`; the factor `(42-S)/2` depends on the last value of `S` from the scroll loop, which may not always be a clean integer, potentially misaligning the jet target address. ## Source Code ``` 1 REM █[I][N][V][A][D][E][R][S]█ 2 GOTO 5 3 SAVE "INVADER[S]" 4 REM █[P][R][O][G][R][A][M]█[L][O][A][D][E][D]█ 5 LET S1=0 6 LET HS=0 7 LET HI=500 10 GOSUB 9000 20 GOTO 7400 80 LET D=1 81 LET S1=0 82 PRINT AT 1,16;S1;"...." 90 GOSUB 600 93 LET T1=0 98 LET B$="█████████████" 99 GOTO 100*D 100 LET A$="██[H]O[H]██[H]O[H]█[H]O[H]" 101 GOTO 510 200 LET A$="██▗O▖██▗O▖█▗O▖" 201 GOTO 510 300 LET A$="██▚O▞██▚O▞█▚O▞" 301 GOTO 510 400 LET A$="██▛O▜██▛O▜█▛O▜" 401 GOTO 510 500 LET A$="██▀O▀██▀O▀█▀O▀" 510 LET D=D+1-5*(D=5) 512 GOSUB 7500 514 GOTO 1900 600 FOR J=8 TO 21 610 PRINT AT J,0;"████████████████████████████████" 620 NEXT J 630 RETURN 1500 IF INKEY$ ="P" THEN GOTO 1800 1510 IF INKEY$ ="O" THEN GOTO 1700 1520 IF INKEY$ ="A" THEN GOTO 8000 1530 RETURN 1710 POKE Y1,128 1720 LET Y1=Y1-1.5 1730 IF PEEK Y1<>128 THEN LET Y1=E1+694 1740 POKE Y1,19 1750 RETURN 1800 POKE Y1,128 1810 LET Y1=Y1+1.5 1820 IF PEEK Y1<>128 THEN LET Y1=E1+723 1830 POKE Y1,18 1840 RETURN 1900 LET Q=10 1910 IF D=1 THEN LET Q=26 1920 IF D=2 THEN LET Q=22 1930 IF D=3 THEN LET Q=18 1940 IF D=4 THEN LET Q=14 2000 FOR S=Q TO 4 STEP -4 2001 PLOT 0,S 2003 PRINT A$ 2004 GOSUB 1500 2007 PLOT 4,S 2009 PRINT A$ 2011 GOSUB 1500 2014 PLOT 8,S 2016 PRINT A$ 2018 GOSUB 1500 2026 PLOT 12,S 2028 PRINT A$ 2030 GOSUB 1500 2038 PLOT 16,S 2040 PRINT A$ 2042 GOSUB 1500 2048 PLOT 20,S 2050 PRINT A$ 2051 GOSUB 1500 2056 PLOT 24,S 2058 PRINT A$ 2059 GOSUB 1500 2060 PLOT 28,S 2067 PRINT A$ 2068 GOSUB 1500 2076 PLOT 32,S 2078 PRINT A$ 2080 GOSUB 1500 2088 PLOT 34,S 2090 PRINT A$ 2091 IF T1=3 THEN GOTO 2900 2097 IF S=6 THEN PRINT AT 14,10;"[D][A][N][G][E][R]" 2098 IF S=6 THEN LET T1=T1+1 2099 IF S=6 THEN GOTO 2001 2100 NEXT S 2200 LET B=33*((42-S)/2)+(Y1-U) 2201 LET W=E1+B 2202 PRINT AT 14,10;"[1][0][0][P][T][S]" 2203 PRINT AT 10,10;"[R][U][N]█[T][O]█[T][H][E]█[J][E][T][.][.][.]" 2206 LET O=INT (RND*2) 2207 IF O=1 THEN GOTO 2210 2208 PRINT AT 20,1;"▝X▘" 2209 GOTO 2225 2210 PRINT AT 20,28;"▝X▘" 2225 POKE W+33,148 2226 GOSUB 1500 2227 POKE W+66,148 2228 GOSUB 1500 2229 IF PEEK (W+99)<>128 THEN GOTO 7000 2230 IF Y1>(W+99) THEN LET I=1 2235 IF Y1<(W+99) THEN LET I=-1 2236 PRINT AT 14,10;"██████" 2238 FOR J=I TO I*30 STEP I 2239 IF PEEK (W+99+J)<>128 THEN GOTO 7000 2240 POKE W+99+J,189 2245 POKE W+99+J,190 2250 POKE W+99+J,128 2255 GOSUB 1500 2256 IF PEEK (Y1-33)=61 THEN GOTO 2300 2260 NEXT J 2300 LET R=2 2301 IF O=1 THEN LET R=29 2305 POKE W+99+J,190 2310 POKE W+R,128 2320 FOR J=20 TO 9 STEP -1 2330 PRINT AT J,R-1;"▝X▘" 2335 PRINT AT J,R-1;"███" 2340 NEXT J 2350 PRINT AT J,R-1;"███" 2355 FOR N=1 TO 4 2360 PRINT AT J,R;" " 2361 PRINT AT J,R;"[+]" 2362 PRINT AT J,R;"[*]" 2363 PRINT AT J,R;"[=]" 2364 PRINT AT J,R;"█" 2365 NEXT N 2370 LET S1=S1+100 2380 PRINT AT 1,16;S1;"." 2390 GOTO 90 2900 POKE Y1-100,173 2910 POKE Y1-99,52 2920 POKE Y1-98,173 2930 GOTO 2200 7000 PRINT AT 10,10;"████[D][A][M][N][E][D]█[.][.][.]█" 7001 FOR J=1 TO 30 7002 POKE Y1,0 7003 POKE Y1,149 7004 POKE E1,103 7005 POKE Y1,128 7007 POKE E1,128 7010 NEXT J 7020 PRINT AT 1,16;S1 7040 IF S1>HI THEN LET HS=1 7050 IF HS THEN LET HI=S1 7054 PRINT AT 1,0;"████[*][*][*]█[H][I][G][H]█[S][C][O][R][E]█.....█[*][*][*]████" 7055 PRINT AT 1,19;HI 7056 IF HS=0 THEN GOTO 7080 7057 FOR J=1 TO 10 7058 LET I=0+128*(INT (J/2)=J/2) 7060 POKE E1+41,45+I 7061 POKE E1+42,46+I 7062 POKE E1+43,44+I 7063 POKE E1+44,45+I 7064 POKE E1+45,0+I 7065 POKE E1+46,56+I 7066 POKE E1+47,40+I 7067 POKE E1+48,52+I 7068 POKE E1+49,55+I 7069 POKE E1+50,42+I 7070 NEXT J 7080 FOR J=1 TO 21 7090 PRINT AT 20,J;"█[G][A][M][E]█[O][V][E][R]" 7100 NEXT J 7397 LET HS=0 7398 PRINT AT 0,0; 7399 GOSUB 9000 7400 PRINT AT 10,10;"[H]O[H][.][.][.][2][0][P][T][S]" 7401 PRINT AT 12,10;"▗O▖[.][.][.][3][0][P][T][S]" 7402 PRINT AT 14,10;"▚O▞[.][.][.][4][0][P][T][S]" 7403 PRINT AT 16,10;"▛O▜[.][.][.][5][0][P][T][S]" 7404 PRINT AT 18,10;"▀O▀[.][.][.][1][0][P][T][S]" 7405 PRINT AT 1,16;S1 7406 PRINT AT 20,15;"[G][Y]" 7407 PRINT AT 20,14;"[G][E][D][Y]" 7408 PRINT AT 20,13;"[G][E][T][A][D][Y]" 7409 PRINT AT 20,12;"[G][E][T]█[E][A][D][Y]" 7410 PRINT AT 20,11;"[G][E][T]█[Y][R][E][A][D][Y]" 7411 PRINT AT 20,10;"[G][E][T]█[Y][O]█[R][E][A][D][Y]" 7412 PRINT AT 20,9;"[G][E][T]█[Y][O][U][F]█[R][E][A][D][Y]" 7413 PRINT AT 20,8;"[G][E][T]█[Y][O][U][R][L][F]█[R][E][A][D][Y]" 7414 PRINT AT 20,7;"[G][E][T]█[Y][O][U][R][S][E][L][F]█[R][E][A][D][Y]" 7415 GOSUB 600 7420 PRINT AT 12,11;"[P][.][.][.][L][E][F][T]" 7421 PRINT AT 15,11;"[O][.][.][.][R][I][G][H][T]" 7422 PRINT AT 18,11;"[A][.][.][.][F][I][R][E]" 7423 FOR J=20 TO 1 STEP -1 7424 PRINT AT 20,J;"[G][A][M][E]█[B][E][G][I][N][S]█" 7425 NEXT J 7450 GOTO 80 7500 PRINT AT 1,16;S1;"." 7501 LET Y1=E1+705 7505 LET X=E1+248 7510 POKE X,0 7511 POKE X,149 7512 POKE X,189 7513 POKE X,155 7514 POKE X,128 7520 IF X-E1=578 THEN GOTO 7550 7530 LET X=X+33 7540 GOTO 7510 7550 PRINT AT 17,16;"▝X▘" 7565 FOR J=1 TO 5 7570 NEXT J 7580 POKE X+33,148 7585 POKE X+66,148 7586 POKE X+99,148 7587 POKE X+132,148 7595 FOR J=1 TO 5 7596 NEXT J 7600 POKE X+33,189 7605 POKE X+33,148 7610 POKE X+66,189 7615 POKE X+66,148 7620 POKE X+99,189 7625 POKE X+99,148 7630 POKE X+132,189 7635 POKE X+132,148 7640 POKE X+131,189 7641 POKE X+131,128 7642 POKE X+127,189 7643 POKE X+127,190 7644 POKE X+127,61 7645 FOR J=1 TO 5 7646 NEXT J 7650 POKE X+132,128 7655 POKE X+99,128 7660 POKE X+66,128 7665 POKE X+33,128 7670 POKE X-1,128 7675 POKE X+1,128 7680 FOR J=1 TO 6 7685 POKE X,189 7686 POKE X,148 7687 POKE X,149 7688 POKE X,128 7689 NEXT J 7695 RETURN 8020 LET Y=Y1 8050 POKE Y-66,173 8055 POKE Y-132,173 8060 POKE Y-66,128 8065 POKE Y-132,128 8070 POKE Y-198,173 8075 POKE Y-264,173 8080 POKE Y-198,128 8085 POKE Y-264,128 8090 POKE Y-330,173 8095 POKE Y-396,173 8100 POKE Y-330,128 8105 POKE Y-396,128 8110 POKE Y-462,173 8115 POKE Y-462,128 8120 LET T=(PEEK 16438)/2 8125 IF (Y1-U)<(T+2) OR (Y1-U)>(T+13) THEN RETURN 8130 LET A=(Y1-U)-T 8150 IF A$(A)<>CHR$ 52 THEN RETURN 8160 IF S<7 THEN GOTO 2200 8500 LET S1=S1+(D*10) 8515 POKE E1,103 8580 LET A$(A-1 TO A+1)="███" 8585 POKE E1,128 8590 IF A$="██████████████" THEN GOTO 90 8600 RETURN 9005 LET E1=PEEK 16398+256*PEEK 16399 9006 LET U=E1+693 9100 PRINT "████████████████████████████████" 9101 PRINT "██████[*][*][*]█[S][C][O][R][E]█.....█[*][*][*]███████" 9102 PRINT "████████████████████████████████" 9103 PRINT "████████████████████████████████" 9104 PRINT "█████▌▐ ▐▐ █▌▐ ▖▐ ▝▌▗▟▗ ▌ ▟█████" 9105 PRINT "█████▌▐ ▞▐▌▐ █ ▘▐▐▌▌ █ ▄▙▖▐█████" 9106 PRINT "█████▌▐ ▌▐█ ▐█ ▖▐ ▗▌▝▜▐ ▌ ▐█████" 9107 FOR J=7 TO 21 9108 PRINT AT J,0;"████████████████████████████████" 9109 NEXT J 9123 POKE 16442,4 9124 PRINT "▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒" 9950 RETURN ```