--- title: "Ground Attack" id: 70789 type: "computer_media" slug: "ground-attack" url: "http://localhost/computer_media/ground-attack/" markdown_url: "http://localhost/computer_media/ground-attack.md" published_at: "2026-08-23T15:08:09+00:00" modified_at: "2026-08-23T19:22:30+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/ground-attack.png" alt: "Ground Attack screen" excerpt: "Defend your base station against alien invaders in this scrolling shoot-'em-up featuring custom sprites, a difficulty-scaled countdown timer, and persistent high-score entry." 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_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Ground%20Attack%20%28198x%29%28-%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/ground-attack.png" alt: "Ground Attack screen" media_type_tags: "Arcade, Game" --- # Ground Attack Ground Attack is a shoot-’em-up game in which the player defends a base station against alien spacecraft by moving and firing using keys 5, 6, and 8. The game defines twelve User Defined Graphics (UDGs, characters 144–155) via DATA statements POKEd into UDG memory using USR and CHR$, providing custom sprites for the player’s craft, alien ships, terrain features, and explosions. Difficulty is controlled by a player-entered time countdown (20–100), which shrinks with each successful hit and can yield negative scores if the timer overruns. The scrolling alien craft is simulated by printing a substring of a 44-character string array A$ at varying column offsets, creating horizontal movement across the play area. A high-score table with name entry persists across games within the same session, and the elaborate title screen uses BORDER color cycling, FLASH, and OUT 254 for audio-visual effects. *** ### Program Structure The program is organized into clearly separated functional blocks, though most are accessed via `GO SUB` rather than being self-contained. The main sections are: 1. **Lines 1–9:** Initialization — variable setup, UDG data loading. 2. **Line 10:** Game setup — border, intro sequence (`GO SUB 4000`), difficulty input. 3. **Lines 20–26:** Screen draw and per-life initialization. 4. **Lines 27–30:** Array setup and first alien launch. 5. **Lines 31–400:** Main game loop — timer, collision detection, movement, firing. 6. **Lines 500–590:** Hit/explosion animation subroutine. 7. **Lines 900–930:** Sky/background drawing subroutine. 8. **Lines 1000–1400:** Detailed base station drawing subroutine (PRINT and PLOT/DRAW combined). 9. **Lines 1500–1520:** Decorative border drawing subroutine. 10. **Lines 2001–2010:** Between-life logic (difficulty adjustment, life management). 11. **Lines 3010–3070:** Alien approach animation subroutine. 12. **Lines 4000–4023:** Title screen and instructions. 13. **Lines 5000–5200:** Game over, high score check, and name entry. ### UDG Sprite System Lines 3–8 load twelve UDGs (characters 144–155, i.e., `\a` through `\l`) using a loop that calls `POKE USR CHR$ i+j, b` for each of the 8 bytes per character. This is a compact but slightly unconventional approach — `USR CHR$ i` returns the address of the UDG bitmap, so adding `j` inside the `POKE` target steps through the 8 bytes sequentially. The DATA (lines 6–9) defines sprites for the player ship (4 UDGs forming a 1×4 composite), alien craft parts, explosion segments, terrain/wall pieces, and ground details. ### Alien Movement via String Slicing The alien craft is represented by a 44-character string `A$(1)` (a one-row string array). The aircraft sprite occupies columns 32–35 of this string (set at line 28 with four UDG characters). Horizontal scrolling is achieved by printing a substring `A$(1, x TO Px)` at row `y`, column 1 (lines 130 and 3050). By varying `x` (left index) and `Px` (right index, clamped to 44 or 29), the sprite appears to slide across the screen. This is an efficient scrolling technique that avoids rewriting the underlying screen data directly. ### Main Game Loop Logic The main loop runs from line 90 back to line 400 (`GO TO 90`). Each iteration decrements the countdown `co`, prints it, and then checks several conditions: - **Line 91:** When `co=0`, prints flashing “lives lost” UDGs at random positions as a visual warning. - **Line 92:** Checks `ATTR (11, 34-x)=12` (attribute value 12 = PAPER 1, INK 4 — the alien color) to detect when the alien reaches the base row. If so, triggers a near-miss explosion, reverses the alien’s approach direction (`C=-1`), deducts a life, and re-launches. - **Lines 100–115:** Handle movement. With no key or key “6” pressed, the alien drifts randomly (`z = INT(RND*3)`, offset by −1). Keys “5” and “8” move the alien left/right (counter-intuitively labeled as player movement keys but actually shifting the alien). - **Line 116:** Key “6” fires — animates missile UDGs (`\k`, `\l`) moving outward from the center of the screen. - **Line 140:** Hit detection for firing: checks `INKEY$="6"` and `34-x=15` (alien centered), awards 100 + remaining time, triggers explosion subroutine, and goes to between-life logic. ### Attribute-Based Collision Detection Line 92 uses `ATTR (11, 34-x)=12` to detect the alien reaching the base. Attribute value 12 corresponds to PAPER 1 (blue) + INK 4 (green), which is the color combination used to print the alien sprite in the approach subroutine (line 3050: `PAPER 1; INK 9` — note INK 9 is a “transparent” or “contrast” ink on some builds, but the ATTR check uses value 12). This is a lightweight collision method that avoids per-pixel coordinate tracking. ### Difficulty Scaling The difficulty system is noteworthy. The player enters a value `tco` (20–100) which acts as the countdown timer per wave. Line 30 sets `co=tco` after decrementing `tco` by 1 each wave. Line 2002 halves `tco` if the player used more than 90% of the time (`co/tco > 0.9`), rapidly escalating pressure. Line 2001 awards a bonus life if the difficulty reaches exactly 25 and score exceeds 3,500 — though the condition `tco=25 OR tco=25 AND sc>3500` is logically equivalent to just `tco=25` due to operator precedence, meaning the score condition is never independently evaluated. ### Title Screen Effects The intro subroutine (lines 4000–4023) uses nested loops to cycle the BORDER through colors 6 down to 0 while POKEing system variable 23607 to adjust the screen’s color attributes, combined with `OUT 254, 16` (which also controls the border/speaker port) and `FLASH 1`. This creates a rapid strobing effect. The delay loop at line 4007 (`FOR f=0 TO 300: NEXT f`) provides a brief pause before the instructions appear. ### Base Station Artwork The base station rendering (lines 1000–1400) is the most elaborate section, combining both PRINT-based character graphics and PLOT/DRAW vector graphics. Nested PLOT/DRAW sequences at lines 1100–1115 draw the structural outlines of the base using straight lines, while PRINT statements layer UDG characters and colored attribute blocks over them. The result is a composite image built from both the character grid and the pixel-level graphics layer simultaneously. ### Bugs and Anomalies - **Line 2001 logic error:**`IF tco=25 OR tco=25 AND sc>3500` — the `AND` binds tighter than `OR`, so this reads as `tco=25 OR (tco=25 AND sc>3500)`, which simplifies to just `tco=25`. The score guard is never effective. - **Line 2000 missing:** Lines 92 and 140 both `GO TO 2000`, but there is no line 2000 — execution falls through to line 2001. This is intentional use of the fall-through behavior. - **Line 4019 typo:**`"IS DEDUCTEDM"` — trailing “M” is a typographical error. - **Line 1511–1520 unreachable:** Lines 1511–1520 draw a rectangular target indicator but sit between `RETURN` at line 1400 and the call at line 3070 (`GO SUB 1511`). They are only reachable via `GO SUB` and are correctly placed after the dead code gap. - **Line 27:**`DIM A$(1,44)` declares a single-row, 44-column string array. Accessing `A$(1, x TO Px)` with `Px=44` at the array bounds is safe but requires `x` to never be 0 or negative — partially guarded by lines 121 and 3041. ### Variable Summary | Variable | Purpose | | --- | --- | | `hs` | High score (persists across games) | | `h$` | High score holder name | | `tco` | Base countdown (difficulty level, shrinks over time) | | `co` | Current countdown per wave | | `lf` | Lives remaining | | `sc` | Current score | | `x` | Alien horizontal position (index into A$) | | `y` | Alien vertical row | | `Px` | Right bound for A$ substring print | | `A$` | 44-char string containing alien sprite at cols 32–35 | | `A, B, C` | Loop bounds and step for alien approach (line 3010) | ## Source Code ``` 1 REM Ground Attack 2 LET hs=0:LET h$="NO ONE YET" 3 FOR i=144 TO 155 4 FOR j=0 TO 7:READ b 5 POKE USR CHR$ i+j,b:NEXT j:NEXT i 6 DATA 0,0,0,0,0,3,191,0,0,0,0,0,0,192,253,0,192,32,49,59,127,255,227,192,3,4,140,220,254,255,199,3 7 DATA 0,255,0,0,255,255,255,0,144,144,255,213,255,157,157,255,9,9,255,171,255,185,185,255,0,0,90,255,189,231,195,195 8 DATA 255,127,63,31,15,7,3,1,255,254,252,248,240,224,192,128 9 DATA 240,240,240,248,24,4,2,1,15,15,15,31,24,32,64,128 10 BORDER 0:PAPER 7:INK 0:CLS :GO SUB 4000:INPUT "DIFFICULTY 20-100 ";tco 20 INK 0:DRAW 255,0:DRAW 0,175:DRAW -255,0:DRAW 0,-175 21 GO SUB 900 22 GO SUB 1000 24 GO SUB 1500 25 LET lf=3 26 LET sc=0 27 DIM A$(1,44) 28 LET A$(1,32 TO 35)="[UDG-A][UDG-C][UDG-D][UDG-B]" 30 LET A=4:LET B=9:LET C=1:LET x= INT (RND*34):LET y=4:GO SUB 3000:LET tco=tco-1:LET co=tco 31 PRINT AT 15,17; PAPER 1; INK 7;"SCORE"; AT 16,17;" "; AT 16,17;sc; AT 18,17;"TIME "; AT 19,17;" " 90 LET co=co-1:PRINT AT 19,17; PAPER 1; INK 7;co;" " 91 IF co=0 THEN FOR k=1 TO lf:PRINT AT 11, INT (RND*15)+4; PAPER 1; INK 4;"[UDG-F][UDG-H][UDG-G]":NEXT k 92 IF ATTR (11,34-x)=12 AND co<0 THEN PRINT AT 11,32-x; OVER 1; PAPER 1; INK 3;"****":LET A=9:LET B=4:LET C=-1:LET sc=sc+co:GO SUB 3000:LET lf=lf-1:GO TO 2000 100 IF INKEY$="" OR INKEY$="6" THEN LET z= INT (RND*3):LET x=x+z-1:BEEP .005,x 110 IF INKEY$="5" THEN LET x=x+1:BEEP .005,x 115 IF INKEY$="8" THEN LET x=x-1:BEEP .005,x 116 IF INKEY$="6" THEN LET f=1:PAPER 1:INK 7:FOR i=4 TO 8 STEP 2:BEEP .002,i:PRINT AT i,f+9;"[UDG-K]"; AT i,22-f;"[UDG-L]"; AT i,f+9;" "; AT i,22-f;" ":LET f=f+2:NEXT i 120 LET Px=x+29 121 IF x<2 THEN LET x=1 122 IF x>15 THEN LET Px=44 130 PRINT AT y,1; PAPER 8; INK 7;A$(1,x TO Px) 140 IF INKEY$="6" AND 34-x=15 THEN LET sc=sc+100+co:PRINT AT 9,14; PAPER 1; INK 2; OVER 1;"@**@":GO SUB 500:GO TO 2000 400 GO TO 90 500 LET fh=9 501 PAPER 1:INK 6 502 LET tr=15:FOR j=16 TO 28 503 BEEP .005,j:PRINT AT 9,j;" ";"[UDG-B]"; AT 9,tr-1;"[UDG-A] "; AT fh,tr;" "; AT fh,j;" " 504 LET tr=tr-1:LET fh=fh-.3 505 BEEP .002,fh:PRINT AT fh,tr;"[UDG-C]"; AT fh,j;" [UDG-D]":NEXT j 590 RETURN 900 PRINT AT 3,10; PAPER 1;" " 902 PRINT AT 2,7; PAPER 1;" " 903 PRINT AT 3,9; PAPER 7; INK 0;"[UDG-I]"; AT 3,22;"[UDG-J]"; AT 2,7;"[UDG-I]██"; AT 2,22;"██[UDG-J]" 904 PRINT AT 3,7; INK 7; PAPER 1;"[UDG-I]"; AT 3,24;"[UDG-J]" 906 PRINT AT 3,3; PAPER 1;" "; AT 3,25;" " 909 FOR i=4 TO 11 910 PRINT AT i,1; PAPER 1;" " 920 NEXT i 930 RETURN 1000 INK 7:PLOT 8,80:DRAW 240,0:INK 0 1001 PRINT #1; INK 7;"HIGH SCORE ";hs,"BY ";h$ 1002 FLASH 1:PRINT AT 12,1; PAPER 6;"[UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E][UDG-E]" 1003 PRINT AT 13,1; PAPER 6; INK 0;" " 1004 PRINT AT 14,1; PAPER 6; INK 0;" "; AT 14,23;" " 1005 PRINT AT 15,1; PAPER 0; INK 6;" "; AT 15,23;" " 1007 PRINT AT 16,4; PAPER 0; INK 6;" "; AT 16,23;" " 1008 PRINT AT 17,4; PAPER 6; INK 0;" "; AT 17,23;" " 1009 PRINT AT 18,4; PAPER 6; INK 0;" "; AT 18,23;" " 1010 PRINT AT 19,4; PAPER 6; INK 0;" "; AT 19,23;" " 1011 PRINT AT 20,4; PAPER 0; INK 6;" "; AT 20,23;" " 1012 PRINT AT 21,4; FLASH 0; PAPER 7; INK 0; OVER 1;"[UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H] [UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H]" 1019 FLASH 0 1020 LET t=3:FOR i=16 TO 18 1030 PRINT AT i,t; INK 4; PAPER 7;"[UDG-J]"; AT i,31-t;"[UDG-I]":LET t=t-1:NEXT i 1040 PRINT AT 16,1; PAPER 4; INK 0;" "; AT 16,29;" "; AT 17,1;"[UDG-J]"; AT 17,30;"[UDG-I]" 1050 PRINT AT 3,1; INK 7; PAPER 2;" [UDG-I]"; AT 3,29;"[UDG-J] "; AT 2,1;"[UDG-I]"; AT 2,30;"[UDG-J]" 1100 PLOT 133,10 1102 DRAW 0,49:DRAW 45,0:DRAW 0,-49:DRAW -45,0:PLOT 134,34:DRAW 44,0:DRAW 0,1:DRAW -44,0 1109 PLOT 76,10 1110 DRAW 0,49:DRAW 56,0:DRAW 0,-49:DRAW -56,0:PLOT 81,35:DRAW 46,0 1111 PLOT 73,8 1112 DRAW 0,54:DRAW 109,0:DRAW 0,-54:DRAW -109,0 1113 PLOT 0,175:DRAW 24,-24:PLOT 255,175:DRAW -24,-24 1114 PLOT 40,168:DRAW 16,-16:PLOT 215,168:DRAW -16,-16 1115 PLOT 40,168:DRAW 0,7:PLOT 215,168:DRAW 0,7 1120 PRINT AT 18,2; PAPER 0; INK 7;"[UDG-J]"; AT 18,29;"[UDG-I]"; BRIGHT 1; AT 19,2;"[UDG-J]"; AT 19,29;"[UDG-I]"; AT 20,2;"[UDG-J]"; AT 20,29;"[UDG-I]"; BRIGHT 0 1130 PRINT AT 0,5; OVER 1;"[UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H][UDG-H]":OVER 0 1140 FOR j=1 TO 21 STEP 2 1150 PRINT AT j,0; OVER 1;"x"; AT j,31;"x":NEXT j 1160 LET de=0:FOR j=167 TO 153 STEP -2 1170 PLOT 8+de,j:DRAW 32,0:PLOT 247-de,j:DRAW -32,0:LET de=de+2:NEXT j 1200 FOR i=15 TO 19 1210 PRINT AT i,10; OVER 1; PAPER 4;" ":NEXT i:OVER 0 1400 RETURN 1500 PLOT 2,2 1501 DRAW 251,0:DRAW 0,171:DRAW -251,0:DRAW 0,-171 1502 PLOT 4,4 1503 DRAW 247,0:DRAW 0,167:DRAW -247,0:DRAW 0,-167 1504 PLOT 6,6 1505 DRAW 243,0:DRAW 0,163:DRAW -243,0:DRAW 0,-163 1506 RETURN 1511 INK 7:PLOT 107,94:DRAW 0,-3:DRAW 40,0:DRAW 0,3 1512 PLOT 107,110:DRAW 0,3:DRAW 40,0:DRAW 0,-3 1520 RETURN 2001 IF tco=25 OR tco=25 AND sc>3500 THEN LET lf=lf+1:BEEP .05,lf 2002 IF co/tco>.9 THEN LET tco= INT (tco/2) 2003 FOR i=1 TO 50:BEEP .001,i 2004 NEXT i 2005 IF lf=0 THEN GO TO 5000 2006 GO SUB 900 2007 PRINT AT 11,1; PAPER 1;"______________________" 2010 GO TO 30 3010 FOR i=A TO B STEP C 3011 PAUSE 10 3020 LET z= INT (RND*5) 3030 PRINT AT y,1; PAPER 1;" " 3040 LET x=x+z-2:LET y=i:LET Px=29 3041 IF x<2 THEN LET x=1 3042 IF x>15 THEN LET Px=44 3050 PRINT AT y,1; PAPER 1; INK 9;A$(1,x TO Px) 3060 NEXT i 3070 GO SUB 1511:RETURN 4000 FOR I=0 TO 10:FOR j=6 TO 0 STEP -1 4001 POKE 23607,I:BORDER j:OUT 254,16:FLASH 1 4002 IF i=10 AND j=0 THEN POKE 23607,60 4003 PRINT AT 10,9;"GROUND ATTACK" 4004 PRINT AT 7,14; INK 2; FLASH 0;"[UDG-A][UDG-C][UDG-D][UDG-B]" 4005 NEXT j:NEXT I 4006 FLASH 0 4007 FOR f=0 TO 300:NEXT f 4008 CLS :PRINT AT 1,14;"[UDG-A][UDG-C][UDG-D][UDG-B]" 4009 PRINT AT 2,9;"GROUND ATTACK" 4010 PRINT AT 4,0;" YOU ARE IN COMMAND OF BASE"''"STATION ALPHA,THE MOST POWERFUL"''"DEFENCE STATION ON THE PLANET."''" USE KEYS 5,6, & 8 TO DESTROY"''"THE ALIEN CRAFT INVADING YOUR"''"HOME WORLD." 4011 PRINT AT 16,4;"KEYS:-" 4012 PRINT AT 18,6;"6 = FIRE"; AT 19,6;"5 = LEFT"; AT 20,6;"8 = RIGHT" 4013 PRINT #1;"PRESS ANY KEY TO CONTINUE---" 4014 PAUSE 0 4015 CLS :PRINT AT 1,14;"[UDG-A][UDG-C][UDG-D][UDG-B]" 4016 PRINT AT 2,9;"GROUND ATTACK" 4017 PRINT AT 4,2;"THE SCORE WILL BE KEPT AS"''"FOLLOWS:-"''"THE DIFFICULTY LEVEL YOU ENTER"''"IS A TIME LIMIT WHICH COUNTS"''"DOWN BACKWARDS" 4018 PRINT AT 14,1;"WHEN YOU HIT A SHIP YOU SCORE"''"100 POINTS PLUS THE TIME LEFT." 4019 PRINT AT 18,1;"IF THE TIME IS A ""-"" THE TIME"''"IS DEDUCTEDM" 4020 PRINT #0;"GOOD LUCK " 4021 PRINT #1;"PRESS ANY KEY TO START" 4022 PAUSE 1:PAUSE 0 4023 CLS :RETURN 5000 BEEP .5,0:BEEP .5,-10:PRINT AT 10,11; PAPER 2; INK 6; FLASH 1;"GAME OVER" 5010 FOR i=1 TO 200:NEXT i:IF sc>hs THEN GO SUB 5100 5020 GO TO 10 5100 PAPER 1:INK 7:FLASH 1 5110 FOR i=1 TO 10 5120 PRINT AT 10,11;" NEW ":BEEP .25,10 5130 PRINT AT 10,11;" HIGH ":BEEP .25,20 5140 PRINT AT 10,11;" SCORE ":BEEP .25,15 5150 NEXT I 5160 FLASH 0 5170 PRINT AT 10,2;"PLEASE ENTER YOUR NAME..... " 5180 INPUT LINE h$ 5190 LET hs=sc 5200 RETURN ```