--- title: "CANNONADE" id: 71451 type: "computer_media" slug: "cannonade" url: "http://localhost/computer_media/cannonade/" markdown_url: "http://localhost/computer_media/cannonade.md" published_at: "2026-09-05T08:56:45+00:00" modified_at: "2026-09-05T08:57:13+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "A six-enemy cannon assault game where letter commands push back attackers advancing across a 20-position grid — but random row shifts keep you guessing." post_tag: - name: "1981" slug: "year-1981" taxonomy: "post_tag" url: "http://localhost/tag/year-1981/" - 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/" indiv: - name: "Drew Nisbet" slug: "drew-nisbet" taxonomy: "indiv" url: "http://localhost/indiv/drew-nisbet/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Program" programmers: - name: "Drew Nisbet" slug: "drew-nisbet" taxonomy: "indiv" url: "http://localhost/indiv/drew-nisbet/" download_url: "https://archive.org/download/timex-sinclair-software-archive/CANNONADE%20(1981)(Nesbit%2C%20Drew)(TS2068)(US)(Program).zip" mediadate: "1981" media_type_tags: "Game" --- # CANNONADE CANNONADE is a turn-based cannon battle game in which the player attempts to advance enemy gun crews (labeled by letter) across a 20-position battlefield before they reach position 20 and capture the cannon. Each of the six enemies occupies one of seven rows (M array tracks row, P array tracks column position), and the player inputs a letter code each turn to fire at a chosen enemy, nudging their position forward by a random 3–8 spaces. Enemy rows shift randomly each turn, and one enemy at a time is designated as the “danger” target (D), displayed using inverse video characters to highlight the threat. The game ends either when an enemy reaches position 20 or the player surrenders by pressing Enter, printing the number of moves taken. *** ### Program Structure The program is organized into four logical phases: 1. **Initialization (lines 10–130):** Arrays `L(20)` (the display line buffer), `M(6)` (row assignment per enemy), and `P(6)` (column position per enemy) are set up. Enemies 1–3 start on row 1, enemies 4–6 start on row 2. 2. **Display loop (lines 140–370):** The 7-row battlefield is drawn each refresh. Each row is assembled into `L()` and printed character by character using `CHR$`. 3. **Win/input check (lines 380–650):** After drawing, the program checks if any enemy has reached position 20, then prompts the player for a letter command, applies movement, and possibly designates a new danger target. 4. **End conditions (lines 660–680):** Either the gun is captured (enemy at position 20) or the player surrenders (empty input), both reporting the move count. ### Array and Display Technique The array `L(20)` serves as a one-dimensional frame buffer for each printed row. It is cleared to 0 at the start of each row iteration (lines 170–190), then enemy characters are written into it at their column position `P(J)`. The value stored is `J+37`, which when passed to `CHR$` produces the letters `%`, `&`, `'`, `(`, `)`, `*` for enemies 1–6 — these are the characters the player types to target an enemy. The danger enemy is stored as `J+165` instead, which yields an inverse-video character, visually highlighting it on screen. Position 20 is permanently set to `2` (line 320) which renders as a `"` character acting as the cannon marker. ### Danger Target Logic One enemy at a time is tracked as the “danger” target in variable `D`. Lines 590–630 scan all six enemies to find the one with the greatest column position (`P(I)`), making the most-advanced enemy the new danger. Its row `M(I)` is saved in `T` so the cannon graphic (a block graphic printed with `"\\''#\\.."`) is drawn on that row. When the danger target changes, the previous one’s position is reset to 1 (line 560), which is a significant gameplay mechanic: retreating an enemy when focus shifts away. ### Movement and Randomness When the player inputs a letter, its ASCII code minus 37 (line 450) recovers the enemy index `Q`. The targeted enemy advances by `RND*5+3` positions (a value from 3 to 7 inclusive on the ZX81). The enemy’s row is then randomly shifted: `RND*3` is compared to 1, 2, or 3 — if 1, no row change; if 2, shift up (`K=-1`); if 3, shift down (`K=1`). Boundary checks at line 530 prevent rows going below 1 or above 7. A further `RND*3=2` check (line 550) decides whether to redraw immediately or first recalculate the danger target. ### Notable Bugs and Anomalies - Line 390 checks `P(1)=20` inside a loop over `I=1 TO 6`, but always tests enemy 1’s position regardless of `I`. Only enemy 1 reaching position 20 triggers the end condition; the other five enemies are never checked for capture. This appears to be a bug — the condition should likely be `P(I)=20`. - Line 600 references variable `K` in `P(1)3 THEN LET M(I)=M(I)+1 130 NEXT I 140 RANDOMIZE 150 CLS 160 FOR I=1 TO 7 170 FOR K=1 TO 19 180 LET L(K)=0 190 NEXT K 200 PRINT I;" "; 210 FOR J=1 TO 6 220 IF NOT M(J)=I THEN GO TO 280 230 IF L(P(J))=0 OR L(P(J))=2 THEN GO TO 260 240 LET P(J)=P(J)+1 250 GO TO 230 260 LET L(P(J))=J+37 270 IF D=J THEN LET L(P(J))=J+165 280 NEXT J 290 FOR K=1 TO 20 300 PRINT CHR$ (L(K)); 310 NEXT K 320 LET L(20)=2 330 IF NOT T=I THEN GO TO 350 340 PRINT "\''#\.. ";I; 350 PRINT 360 NEXT I 370 PRINT 380 FOR I=1 TO 6 390 IF P(1)=20 THEN GO TO 660 400 NEXT I 410 PRINT "MAN:" 420 INPUT A$ 430 IF A$="" THEN GO TO 670 440 LET X=X+1 450 LET Q= CODE (A$)-37 460 LET P(Q)=P(Q)+ RND*5+3 470 IF P(Q)>20 THEN LET P(Q)=20 480 LET J= RND*3 490 IF J=1 THEN GO TO 550 500 IF J=2 THEN LET K=-1 510 IF J=3 THEN LET K=1 520 LET I=M(Q) 530 IF I+K=0 OR I+K=8 THEN GO TO 480 540 LET M(Q)=I+K 550 IF RND*3=2 THEN GO TO 140 560 LET P(D)=1 570 LET D=0 580 LET J= RND*3 590 FOR I=1 TO 6 600 IF P(1)