--- title: "Computer Combat" id: 57258 type: "computer_media" slug: "computer-combat" url: "http://localhost/computer_media/computer-combat/" markdown_url: "http://localhost/computer_media/computer-combat.md" published_at: "2024-10-04T07:42:19+00:00" modified_at: "2026-03-30T21:18:56+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/146_CC.png" excerpt: "A tense one-dimensional tank battle where you manoeuvre, aim, and fire before your 25 rounds run out — and the enemy shoots back." 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 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: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 56734 title: "Timex Sinclair Public Domain Library Tape 1003" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1003/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/146_CC.png" article_media: - id: 8658 title: "Computer Combat!" type: "article" url: "http://localhost/article/computer-combat/" media_type_tags: "Game" --- Computer Combat is a one-dimensional shooting gallery game where the player manoeuvres a tank along the bottom row of the screen and fires at an enemy unit moving across the display. The player uses keys 5 and 8 to move left and right, and 0 to fire, with a starting ammunition budget of 25 rounds stored in variable B. The enemy scrolls horizontally using AT coordinates, and a random GOSUB at line 155 occasionally fires back at the player, deducting 5 points on a hit. Scoring awards +5 for a hit on the enemy and −1 for a missed shot, with the game ending when ammunition runs out or the enemy completes 20 rows of travel. *** ## Program Analysis ### Program Structure The program is organised into a main game loop, a firing subroutine, and an enemy counter-attack subroutine. Initialisation occurs in lines 5–25, the main loop runs from line 30 to line 95 via `GOTO VAL "40"`, and end-of-game display is at line 100. Two subroutines handle player firing (lines 115–140) and enemy retaliation (lines 155–185). 1. **Lines 5–25**: Initialise ammunition `B=25`, score `S=0`, enemy row `M=0`, player X position `X=16`, and enemy column `Y=0`. 2. **Lines 30–95**: Main loop — advance enemy row, check row limit, clear screen, randomly trigger counter-attack, draw enemy, advance enemy column, wrap column, draw player tank, read movement keys, check fire key, check ammo, repeat. 3. **Lines 115–140**: Player fire subroutine — draws a `+` marker, checks hit/miss, updates score, decrements ammo. 4. **Lines 155–185**: Enemy counter-attack subroutine — draws a missile character at the enemy column on row 21, checks if it hits the player, penalises score. ### Key Variables | Variable | Role | | --- | --- | | `B` | Ammunition remaining (starts at 25) | | `S` | Player score | | `M` | Enemy row position (increments by 2 each loop) | | `X` | Player tank column position | | `Y` | Enemy column position | | `R` | Random value 0–4 controlling counter-attack frequency | ### Notable Techniques `VAL "number"` is used pervasively in place of numeric literals (e.g. `GOTO VAL "40"`, `LET B=VAL "25"`). This is a well-known memory optimisation on this platform: storing a number as a string literal consumes less RAM than storing it as a floating-point constant in the tokenised line. Zero-initialisation uses `PI-PI` rather than the literal `0`, exploiting the fact that `PI` is a single-token keyword, making `PI-PI` shorter in tokenised form than the numeric constant `0` with its five-byte floating-point representation. Player movement at line 75 uses a Boolean arithmetic idiom: `INKEY$="8"` evaluates to 1 (true) or 0 (false), multiplied by 3 to give a step size of 3 columns. This avoids an explicit `IF`/`THEN` branch for movement. The enemy sprite at line 55 uses block graphic characters (`\:'\:'\:'` — rendered as ▌▘▌▘▌▘) drawn with `PRINT AT M,Y`. The player tank at line 70 uses `\.:\..` (▖▄▖▖ approximating a tank silhouette). The counter-attack at line 155 uses `CHR$ 23` as a missile glyph. On the ZX81/TS1000, character 23 is a block graphic, giving a visual projectile without defining a UDG. ### Bugs and Anomalies - Line 75 reads `INKEY$` twice in the same statement for movement, then line 80 reads it again for firing. Because `INKEY$` is sampled instantaneously each time, pressing 0 while moving could register, but pressing a movement key simultaneously with 0 may cause the movement read to shadow the fire check depending on key held at that instant — no debouncing is implemented. - There is no boundary check on `X`: the player can move off-screen left (below column 0) or right (beyond column 31), potentially causing a `PRINT AT` error or wrap-around. - The hit-detection at line 120/125 checks `X+1=Y`. Given that the player tank sprite is drawn at column `X` and the enemy at column `Y`, only a single-column offset constitutes a hit, making the effective target window very narrow. - Lines 145–150 (`PAUSE VAL "50"` then `GOTO VAL "40"`) are never reached by any branch in the program; they are dead code. - Line 35 checks `M>VAL "20"` but `M` increments by 2 each iteration starting from 0, so `M` reaches 22 before triggering, meaning the enemy can briefly appear below row 20 before the game ends. - After game over at line 100, line 110 calls `RUN` which resets all variables and restarts — the score flash at line 100 is visible only briefly before the restart, and there is no way to review it. ## Source Code ``` 1 REM COMPUTER COMBAT 2 REM KEYS 5/8 TO MOVE--0 TO FIRE 5 LET B=VAL "25" 10 LET S=PI-PI 15 LET M=PI-PI 20 LET X=VAL "16" 25 LET Y=PI-PI 30 LET M=M+2 35 IF M>VAL "20" THEN GOTO VAL "100" 40 CLS 45 LET R=INT (RND*5) 50 IF R=3 THEN GOSUB 155 55 PRINT AT M,Y;"\:'\:'\:'" 60 LET Y=Y+VAL "2" 65 IF Y=VAL "30" THEN GOTO 25 70 PRINT AT 21,X;" \.:\.. " 75 LET X=X+(INKEY$="8")*3-(INKEY$="5")*3 80 IF INKEY$="0" THEN GOSUB 115 85 IF B<=VAL "0" THEN GOTO VAL "100" 95 GOTO VAL "40" 100 PRINT AT 12,10;"SCORE= ";S 110 RUN 115 PRINT AT M,X;"+" 120 IF X+1<>Y THEN LET S=S-1 125 IF X+1=Y THEN PRINT AT M,X-1;"***" 130 IF X+1=Y THEN LET S=S+5 135 LET B=B-VAL "1" 140 RETURN 145 PAUSE VAL "50" 150 GOTO VAL "40" 155 PRINT AT 21,Y;CHR$ 23 160 IF X=Y THEN GOSUB VAL "170" 165 RETURN 170 PRINT AT 21,Y;"<*>" 175 PAUSE VAL "40" 180 LET S=S-VAL "5" 185 RETURN 190 SAVE "1014%6" 200 LIST ```