--- title: "Chainsaw" id: 57583 type: "computer_media" slug: "chainsaw" url: "http://localhost/computer_media/chainsaw/" markdown_url: "http://localhost/computer_media/chainsaw.md" published_at: "2024-10-05T22:34:38+00:00" modified_at: "2026-04-04T08:32:50+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/chainsaw2.png" excerpt: "A scrolling chain-saw shooting gallery where you fire upward bullets at inverse-video targets moving in opposite directions — can you rack up the highest score in 10 shots?" 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: 56722 title: "Synchro-Sette December 1982" type: "computer_media" url: "http://localhost/computer_media/synchro-sette-december-1983/" media_type: "Program" mediadate: "December 1982" images: - url: "http://localhost/wp-content/uploads/2024/10/chainsaw2.png" - url: "http://localhost/wp-content/uploads/2024/10/chainsaw.png" media_type_tags: "Game" --- # Chainsaw This program implements a carnival shooting-gallery style game called “CHAIN-SAW” for the ZX81/TS1000. Three rows of a scrolling marquee — built from inverse-video characters — move across the screen in opposite directions, simulating a moving target belt; the top and bottom rows scroll left-to-right and right-to-left respectively. The player presses any key to fire a “bullet” (an asterisk) that travels upward from row 21, and the program checks whether it strikes a target on row 12 (the lower belt, string C$) or row 10 (the upper belt, string A$), awarding points equal to the character code of the hit symbol minus 156. The game ends after 10 shots, displaying total shots and score before restarting via RUN. *** ## Program Analysis ### Program Structure The program is organized into a main animation loop and two subroutines: 1. **Initialization (lines 5–6):** Score `S` and shots `J` are set to zero. 2. **String setup (lines 10–30):** Three 32-character display strings `A$`, `B$`, and `C$` are defined. 3. **Main loop (lines 40–80):** Prints the three-row display, scrolls `A$` and `C$` in opposite directions, then calls the input/bullet subroutine before repeating. 4. **Input and bullet subroutine (lines 100–220):** Checks for a keypress; if pressed, animates a bullet travelling upward from row 21 to row 0, calling hit-detection subroutines at rows 12 and 10. 5. **Hit detection — lower belt (lines 300–340):** Increments shot count, scores if target at position 11 of `C$` is not already blank, then blanks it. 6. **Hit detection — upper belt (lines 400–430):** Scores and blanks if target at position 11 of `A$` is not already blank, then advances the scroll. 7. **Game over (lines 500–550):** Displays result, waits for ENTER, and restarts via `RUN`. ### Display Strings and Scrolling `A$` (line 10) and `C$` (line 30) are 32-character strings. Each character pair consists of a block graphic followed by an inverse-video digit or letter (0–9, A–F), making 16 pairs that fill the 32-column display exactly. `B$` (line 20) is a static 32-character string spelling “CHAIN-SAW” in inverse video, centred with inverse spaces. Scrolling is achieved by simple string slicing each frame: - `A$` scrolls left: `A$(2 TO 32)+A$(1)` — drops the first character and appends it to the end. - `C$` scrolls right: `C$(32)+C$( TO 31)` — moves the last character to the front. Because the marquee characters are two-character pairs (graphic + label), scrolling by one character per frame causes the pairs to break up midway through a cycle, giving an asymmetric visual shimmer rather than a clean per-symbol scroll. ### Bullet Animation When a key is detected (line 110–120), the bullet loop (lines 140–190) runs from row 20 down to row 0 in `STEP -1`, printing an asterisk `*` at the current row and erasing the previous position one row below. The horizontal position `I` starts at 1 and increments each step, so the bullet travels diagonally upward-right rather than straight up. Hit-detection subroutines are called when `N=12` and `N=10`, corresponding to the rows occupied by `C$` and `A$` respectively. ### Scoring Mechanism Scoring exploits the character codes of the block graphics used in the target strings. The formula `CODE C$(11)-156` (line 320) and `CODE A$(11)-156` (line 410) extract a numeric value from whichever symbol the bullet strikes at column position 11. The block graphic `▀` (ZX81 char 156) used in `C$` and the block graphic `▖` (ZX81 char 154) used in `A$` both yield small non-negative differences from 156, effectively giving a score of 0 or −2 respectively for a blank hit — though the blank-check guard (lines 310, 400) prevents scoring a previously-hit cell. Targets that have already been hit are replaced with the respective “blank” graphic. ### Notable Techniques and Idioms - **Inverse video in strings:** The `%X` escape encodes inverse-video characters directly in string literals, used extensively for the title bar and score display. - **Block graphics as target markers:**`\..` (▖) marks an active upper-belt target; `\'\'` (▀) marks an active lower-belt target; hitting changes the cell to the same graphic, effectively making it look identical but registering as spent — a subtle visual bug. - **FAST/SLOW around restart:** Lines 520–540 bracket `CLS` with `FAST`/`SLOW` to clear the screen quickly without display flicker. ### Bugs and Anomalies | Location | Issue | | --- | --- | | Lines 310 / 400 | The “already hit” check compares `C$(11)` to `\'\'` (▀) and `A$(11)` to `\..` (▖), but these are the *same* graphics used to represent active targets, so an un-hit cell and a previously-hit cell are visually and logically identical. Scoring is blocked by the guard but the player receives no visual feedback that a target was already spent. | | Line 150 | The erase step prints a space at `AT N+1,I-1` using the *previous* row and column. When `N=20` (first iteration), this prints at row 21, column 0 — overwriting the inverse-asterisk prompt printed at line 100. | | Line 430 | The upper belt `A$` is scrolled an extra step inside the hit-detection subroutine (line 430), meaning a hit causes the belt to advance one extra character that frame, creating a slight lurch in the animation. | | Lines 310–320 vs 400–410 | Shot counter `J` is only incremented in the lower-belt subroutine (line 300/310), not in the upper-belt subroutine (line 400). Hitting the upper belt does not consume a shot, potentially allowing more than 10 scoring events. | ## Source Code ``` 5 LET S=0 6 LET J=0 10 LET A$="..%0..%1..%2..%3..%4..%5..%6..%7..%8..%9..%A..%B..%C..%D..%E..%F" 20 LET B$="% % % % % % % % % % % %C%H%A%I%N%-%S%A%W% % % % % % % % % % % % " 30 LET C$="''%0''%1''%2''%3''%4''%5''%6''%7''%8''%9''%A''%B''%C''%D''%E''%F" 40 PRINT AT 10,0;A$;AT 11,0;B$;AT 12,0;C$ 50 LET A$=A$(2 TO 32)+A$(1) 60 LET C$=C$(32)+C$( TO 31) 70 GOSUB 100 80 GOTO 40 100 PRINT AT 21,0;"%*" 110 LET D$=INKEY$ 120 IF D$="" THEN RETURN 130 LET I=1 140 FOR N=20 TO 0 STEP -1 150 PRINT AT N,I;"*";AT N+1,I-1;" " 160 IF N=12 THEN GOSUB 300 170 IF N=10 THEN GOSUB 400 180 LET I=I+1 190 NEXT N 200 PRINT AT 0,0;"%S%H%O%T%S% %= ";J;AT 0,12;" %S%C%O%R%E% %= ";S 210 IF J=10 THEN GOTO 500 220 GOTO 40 300 LET J=J+1 310 IF C$(11)="''" THEN GOTO 480 320 LET S=S+CODE C$(11)-156 330 LET C$(11)="''" 340 RETURN 400 IF A$(11)=".." THEN RETURN 410 LET S=S+CODE A$(11)-156 420 LET A$(11)=".." 430 LET A$=A$(2 TO 32)+A$(1) 480 RETURN 500 PRINT AT 6,0;"GAME OVER - PRESS ENTER","TO RESTART :::" 510 INPUT A$ 520 FAST 530 CLS 540 SLOW 550 RUN 9998 SAVE "CHAINSA%W" 9999 RUN ```