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,4at 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 Jwith 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)/2depends on the last value ofSfrom the scroll loop, which may not always be a clean integer, potentially misaligning the jet target address.
Content
Image Gallery
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
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.