Frenzy

This file is part of Synchro-Sette December 1982 . Download the collection to get this file.
Date: December 1982
Type: Program
Platform(s): TS 1000
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):

OffsetHexZ80 MnemonicNotes
03E 1ELD A, #1ELoad accumulator with 30
2ED 47LD I, ASet interrupt vector register to 30
4C9RETReturn 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.

Content

Appears On

Cassette to accompany the December 1982 issue of Synchro-Sette.

Related Products

Related Articles

Related Content

Image Gallery

Frenzy

Source Code

   1 REM E itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57584 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"E\ED\C9
   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 
\n1000 CLS 
\n1005 LET C$="FRENZY "
\n1006 LET D$="%F%R%E%N%Z%Y "
\n1010 FOR N=24 TO 13 STEP -1
\n1020 PRINT AT 11,N;C$;AT 11,N;D$;AT 11,N;C$;AT 11,N;D$
\n1030 NEXT N
\n1040 FOR I=1 TO 30
\n1050 PRINT AT 11,N;C$;AT 11,N;D$
\n1060 NEXT I
\n1070 RETURN 
\n2010 PRINT AT 11,0;"YOUR SCORE IS ";B
\n2030 INPUT A$
\n2040 RUN 
\n9998 SAVE "FRENZ%Y"
\n9999 RUN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top