Target Practice

This file is part of Timex Sinclair Public Domain Library Tape 1006 . Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Game, Software

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:

  1. Initialisation (lines 1–5): Sets FAST mode, calls machine code, restores SLOW mode, and zeroes the high-score variable U.
  2. Round setup subroutine (lines 1000–1500): Initialises the scrolling target string A$, resets score accumulator S, and draws the playfield borders.
  3. Main game loop (lines 10–700): A FOR K=1 TO 70 loop advances the scroll, reads keys, and dispatches to the fire subroutine.
  4. 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.
  5. 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 charMeaningBase bonus
%XStandard target+1 (from generic hit check)
%MMedium target+1 (generic) +1 (specific) = +2
%HHigh-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 column Y left (decrements).
  • "8" — moves cursor column Y right (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 REM at 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 given USR 16514 does 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 to Y-1.
  • Lines 5510–5530 (CLEAR / SAVE / RUN) are unreachable during normal play; they would only execute if control somehow fell through past RETURN at line 5500, making them effectively a save-and-restart utility embedded in the listing.
  • The IF A$(Y)<>"% " THEN LET S=S+1 check at line 5000 awards a generic point for any non-space hit, and the subsequent specific checks for %H and %M stack additional points on top, so an %H hit correctly scores 3 total.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10252 – 10293.

Related Products

Related Articles

Related Content

Image Gallery

Target Practice

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.

People

No people associated with this content.

Scroll to Top