This is a ZX81/TS1000 shooting-gallery style game where a scrolling target string moves across the screen and the player steers a cursor left or right with keys 5 and 8, firing with key B. The program opens with a machine-code call via RAND USR 16514 before entering the main game loop. Targets in the string are marked with special inverse characters (X, M, H) worth different point values, and a running high-score is maintained across rounds using variable U. The score calculation at line 5040 multiplies hits by 6453 and adds a small random offset, and the SAVE command at line 5520 with an inverse character in the filename acts as an auto-run marker.
Program Analysis
Program Structure
The program is divided into clearly separated functional blocks:
- Initialisation (lines 1–5): Sets FAST mode, calls machine code, restores SLOW mode, and zeroes the high-score variable
U. - Round setup subroutine (lines 1000–1500): Initialises the scrolling target string
A$, resets score accumulatorS, and draws the playfield borders. - Main game loop (lines 10–700): A
FOR K=1 TO 70loop advances the scroll, reads keys, and dispatches to the fire subroutine. - Fire subroutine (lines 5000–5500): Checks the character under the cursor, awards points, animates a shot, recalculates score
Q, and conditionally drifts the cursor position. - Save block (lines 5510–5530): Dead code reached only by fall-through; saves and re-runs the program.
Machine Code Usage
Line 3 executes RAND USR 16514. Address 16514 (0x4082) is in the ZX81/TS1000 system variable area rather than in free RAM, suggesting this call patches or reads a system variable rather than running a standalone routine. No POKE sequence loads machine code before this call, so it relies on whatever bytes happen to reside there — likely a short return or a known ROM entry point used as an initialisation trick by the original author.
Target String and Scrolling
The target string A$ (line 1000) is 33 characters wide and contains three types of inverse-video targets embedded in a field of inverse spaces:
| Inverse char | Meaning | Base bonus |
|---|---|---|
%X | Standard target | +1 (from generic hit check) |
%M | Medium target | +1 (generic) +1 (specific) = +2 |
%H | High-value target | +1 (generic) +2 (specific) = +3 |
Scrolling is achieved at line 200 with the classic Sinclair BASIC string-rotation idiom: LET A$=A$(2 TO )+A$(1), which shifts every character one position left and wraps the first character to the end, cycling the pattern indefinitely over the 70-iteration round.
Key Handling and Player Control
Three keys are polled inside the main loop using INKEY$:
"5"— moves cursor columnYleft (decrements)."8"— moves cursor columnYright (increments)."B"— triggers the fire subroutine at line 5000.
Keys 5 and 8 match the standard ZX81 left/right convention. There is no boundary clamping on Y from the movement keys, though the fire subroutine at line 5070 only randomises drift if Y>2 AND Y<30.
Scoring
Hit accumulator S is incremented in the fire subroutine (lines 5000–5003). The final displayed score Q is computed as S*6453+INT(RND*3). Multiplying by 6453 inflates raw hit counts into large, impressive-looking scores; the random offset of 0–2 adds minor unpredictability. The score is only printed (line 5050) when it exceeds 5000, i.e. roughly after one confirmed hit. High score U is updated and displayed at lines 520–530 at round end.
Shot Animation
When B is pressed, the subroutine at line 5000 runs a FOR A=18 TO 1 STEP -3 loop (lines 5008–5030), printing an inverse asterisk %* then immediately overwriting it with an inverse space % at each row, creating a crude upward-travelling bullet animation without any PAUSE delay — relying on the inherent SLOW-mode display overhead for timing.
Round Transition and High Score Persistence
After 70 iterations the program prints “END OF ROUND” in inverse video (line 510), updates the high score, waits 60 iterations of an empty loop (lines 540–550), briefly flashes a “STAND BY” message, then uses LET Z=RND*RND (line 560) as a dummy delay before looping back to start a new round via GOTO 10. The high score variable U persists across rounds because GOTO 10 does not re-execute line 5 where U=0 was set.
Notable Techniques and Anomalies
- The
REMat line 1 contains block graphics and inverse characters, which on the ZX81 is a common location for machine-code bytes; the content here appears decorative rather than functional givenUSR 16514does not point into it. - The cursor display at line 100 uses
"% %*% "— an inverse space, an asterisk, and a plain space — as the player’s gun sight marker, printed relative toY-1. - Lines 5510–5530 (CLEAR / SAVE / RUN) are unreachable during normal play; they would only execute if control somehow fell through past
RETURNat line 5500, making them effectively a save-and-restart utility embedded in the listing. - The
IF A$(Y)<>"% " THEN LET S=S+1check at line 5000 awards a generic point for any non-space hit, and the subsequent specific checks for%Hand%Mstack additional points on top, so an%Hhit correctly scores 3 total.
Content
Source Code
1 REM Y% \.'\. :%KNOT $TAB \@@RND\: TAB \'.RNDTAN
2 FAST
3 RAND USR 16514
4 SLOW
5 LET U=0
10 GOSUB 1000
90 FOR K=1 TO 70
100 PRINT AT 3,0;A$;AT X,Y-1;"% %*% "
200 LET A$=A$(2 TO )+A$(1)
300 IF INKEY$="5" THEN LET Y=Y-1
350 IF INKEY$="8" THEN LET Y=Y+1
360 IF INKEY$="B" THEN GOSUB 5000
500 NEXT K
510 PRINT AT 12,9;"%E%N%D% %O%F% %R%O%U%N%D"
520 IF Q>U THEN LET U=Q
530 IF U<>0 THEN PRINT AT 1,1;"%H%I%G%H%E%S%T% %S%C%O%R%E%:% ";U
540 FOR D=1 TO 60
550 NEXT D
555 PRINT AT 12,9;"**STAND*BY**"
560 LET Z=RND*RND
570 PRINT AT 12,9;"% % % % % % % % % % % % % "
700 GOTO 10
\n1000 LET A$="% % %X% % %X% % %X% % %X% % %X% % %M% % % % %M% % % %M% % % %H"
\n1020 LET S=0
\n1030 LET X=18
\n1040 LET Y=16
\n1050 PRINT AT X,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
\n1060 PRINT AT 20,7;"% % % % % % % % % % % % % % % % % "
\n1500 RETURN
\n5000 IF A$(Y)<>"% " THEN LET S=S+1
\n5002 IF A$(Y)="%H" THEN LET S=S+2
\n5003 IF A$(Y)="%M" THEN LET S=S+1
\n5005 LET A$(Y)="% "
\n5008 FOR A=18 TO 1 STEP -3
\n5010 PRINT AT A,Y;"%*"
\n5020 PRINT AT A,Y;"% "
\n5030 NEXT A
\n5040 LET Q=S*6453+INT (RND*3)
\n5050 IF Q>5000 THEN PRINT AT 20,1;"%S%C%O%R%E%:% ";Q
\n5070 IF Y>2 AND Y<30 THEN LET Y=Y+INT (RND*3)-INT (RND*3)
\n5500 RETURN
\n5510 CLEAR
\n5520 SAVE "1027%2"
\n5530 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
