--- title: "Frenzy" id: 57584 type: "computer_media" slug: "frenzy" url: "http://localhost/computer_media/frenzy/" markdown_url: "http://localhost/computer_media/frenzy.md" published_at: "2024-10-05T22:35:15+00:00" modified_at: "2026-04-03T07:58:19+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/frenzy2.png" excerpt: "A reflex-testing game where a bouncing cursor hides a five-byte machine-code routine and rewards precision timing with a hidden positional bonus score." 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/frenzy2.png" - url: "http://localhost/wp-content/uploads/2024/10/frenzy.png" media_type_tags: "Game" --- This ZX81/TS1000 program implements a reaction-timing game called “FRENZY” in which a moving cursor travels back and forth across the screen and the player must press “Z” at the right moment. A small machine-code routine is embedded in REM line 1 (opcodes LD A,#1E / LD I,A / RETN, five bytes at address 16514), called via USR to handle timing or interrupt control, with its result stored back via POKE 16515. The playing field is drawn with inverse-video border characters filling rows 3–19 and a highlighted window region at rows 8–14. Scoring tracks both the number of presses (A) and a positional bonus (B) awarded only when the special “NOW” target (K=30) is hit; the game ends after 10 presses and displays the final B score. *** ## Program Analysis ### Program Structure The program is divided into several functional blocks: 1. **Initialisation (lines 1–3):** REM line holds machine code; `B$` is set to a 12-character blank string; the title subroutine is called. 2. **Screen setup (lines 4–95):** Border rows are drawn with inverse-video dots; a central window is filled with `B$`. 3. **Main loop (lines 96–150):** Variables `A` (press count) and `B` (score) are initialised; the machine-code routine is called, a random column `K` is chosen, and a bounce subroutine is triggered. 4. **Bounce subroutine (lines 500–570):** A marker sweeps left-to-right then right-to-left; pressing “Z” during the sweep calls the scoring subroutine. 5. **Scoring subroutine (lines 600–640):** Updates and displays `A`, `C` (random extent), and `B`; ends the game after 10 presses. 6. **Title animation (lines 1000–1070):** Scrolls “FRENZY” in plain and inverse video from column 24 to 13, then flickers it 30 times. 7. **End game (lines 2010–2040):** Displays score, waits for `INPUT`, then restarts with `RUN`. 8. **Save/autorun (lines 9998–9999):**`SAVE` with an inverse-Y in the filename sets the autorun flag. ### Machine Code in REM Line Line 1 contains five bytes at address 16514 (the byte after the REM token at the start of the program area): | Offset | Hex | Z80 Mnemonic | Notes | | --- | --- | --- | --- | | 0 | `3E 1E` | `LD A, #1E` | Load accumulator with 30 | | 2 | `ED 47` | `LD I, A` | Set interrupt vector register to 30 | | 4 | `C9` | `RET` | Return to BASIC | The routine is called with `LET L=USR 16514` (line 100). Setting the I register to 30 (#1E) on the ZX81 is a known technique to enable IM 2 style interrupt handling or to manipulate the display; however, the ZX81 does not use I for its standard display driver. The result of USR is stored in `L` (unused) and the side-effect of POKEing address 16515 with `K` (line 140) overwrites the second byte of the REM data — effectively self-modifying the machine code’s operand each iteration. ### Key BASIC Idioms - **Self-modifying machine code via POKE:**`POKE 16515,K` overwrites the immediate operand of `LD A,n`, so each USR call loads a different value into A and subsequently into I. - **Inverse-video flicker for title:** Lines 1020–1050 rapidly print the plain string `C$` and inverse string `D$` over each other at the same position, creating a flashing effect without FLASH attributes. - **Clearing a window with a string:**`B$` (12 `\@@` pairs — space characters) is PRINTed across rows 8–14 to blank the play area without a full CLS. - **K=30 as a special “NOW” trigger:** When the random value K would be less than 10 it is forced to 30 (line 120). K=30 causes the “NOW” flash (line 505) and awards positional bonus `B=B+N` (line 600) only on that target. - **CLEAR without argument (line 95):** On ZX81 BASIC, bare `CLEAR` clears all variables; here it is used mid-program after the screen is drawn but before the game variables are set. ### Notable Techniques The bouncing cursor in the subroutine at line 500 uses two sequential FOR…NEXT loops (510–530 sweeping right, 540–560 sweeping left) and polls `INKEY$` inside each loop without pausing. This gives a continuous sweep with immediate key detection at each step. The `\@@%*\@@` print sequence places a space, an inverse asterisk (UDG or inverse `*`), and another space to form the visible cursor marker. The game end is triggered at line 630 with `IF A>9 THEN GOTO 2000`; however, the end-game code starts at line 2010, so line 2000 is non-existent — the interpreter will fall through to the next available line (2010), which is a deliberate ZX81 technique to skip directly into the block. ### Bugs and Anomalies - Variable `L` in `LET L=USR 16514` is assigned but never read; the USR call is made purely for its side-effects on the I register and to permit the subsequent POKE. - `CLEAR` at line 95 destroys all variables including any set before it; `A` and `B` are therefore correctly re-initialised immediately after at lines 96–97. - The variable `C$` and `D$` set in the title subroutine (lines 1005–1006) will also be erased by the `CLEAR` at line 95, which is harmless since the subroutine has already returned by then. - After 10 presses the program jumps to line 2000 (non-existent), falling through to line 2010 which prints the score but uses variable `B` without `C` or `A` labelling — only `B` is described as the score, even though `A` is always exactly 10 at that point. ## Source Code ``` 1 REM 3E1EED47C9 2 LET B$="@@@@@@@@@@@@@@@@@@@@@@@@" 3 GOSUB 1000 4 CLS 40 FOR N=3 TO 19 50 PRINT AT N,0;"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%."; 60 NEXT N 70 FOR Y=8 TO 14 80 PRINT AT Y,9;B$ 90 NEXT Y 95 CLEAR 96 LET A=0 97 LET B=0 100 LET L=USR 16514 110 LET K=INT (RND*29)+1 120 IF K<10 THEN LET K=30 130 GOSUB 500 140 POKE 16515,K 150 GOTO 100 500 LET C=INT (10*RND)+1 502 PRINT AT 8,18;"@@@@@@" 505 IF K=30 THEN PRINT AT 8,18;"%N%O%W";AT 8,18;"NOW";AT 8,18;"%N%O%W" 510 FOR N=1 TO C 520 PRINT AT 11,8+N;"@@%*@@" 525 IF INKEY$="Z" THEN GOSUB 600 530 NEXT N 540 FOR N=C TO 1 STEP -1 550 PRINT AT 11,8+N;"@@%*@@" 555 IF INKEY$="Z" THEN GOSUB 600 560 NEXT N 570 RETURN 600 IF K=30 THEN LET B=B+N 610 LET A=A+1 620 PRINT AT 8,9;"A";A;AT 14,9;"C";C;"@@";AT 14,19;"B";B 630 IF A>9 THEN GOTO 2000 640 RETURN 1000 CLS 1005 LET C$="FRENZY " 1006 LET D$="%F%R%E%N%Z%Y " 1010 FOR N=24 TO 13 STEP -1 1020 PRINT AT 11,N;C$;AT 11,N;D$;AT 11,N;C$;AT 11,N;D$ 1030 NEXT N 1040 FOR I=1 TO 30 1050 PRINT AT 11,N;C$;AT 11,N;D$ 1060 NEXT I 1070 RETURN 2010 PRINT AT 11,0;"YOUR SCORE IS ";B 2030 INPUT A$ 2040 RUN 9998 SAVE "FRENZ%Y" 9999 RUN ```