Rifle Range

This file is part of and SINCUS Exchange Tape 103 - Potpourri. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

This is a shooting gallery game called “Ye Olde Rifle Range” in which the player fires at a scrolling row of UDG-drawn targets from a moving gun at the bottom of the screen. The program loads several blocks of Z80 machine code at addresses 60000, 60050, 60100, 60200, and 60250, used for tasks including screen copying, border color effects, and animated display routines. Twenty-one User Defined Graphics (UDGs \a through \u) are defined from DATA statements to draw six distinct target types, each worth 100–600 points. A bubble-sort high-score table tracks the top five players with names and scores persisted in arrays across rounds, and ammunition decreases each round until exhausted.


Program Analysis

Program Structure

The program is divided into clearly separated functional regions:

  1. Lines 1–11, 20–50: Machine code loading and UDG data. Five separate MC blocks are POKEd into high memory, and DATA for 21 UDGs is defined across multiple DATA lines.
  2. Lines 100–361: UDG initialization and screen drawing — the rifle range backdrop, tent poles, prize board, and decorative elements are all rendered with PLOT/DRAW/CIRCLE.
  3. Lines 363–680: Main game loop. The gun moves left and right; the player fires with any key; hits are detected and scored.
  4. Lines 1000–1060: Subroutines that set up each wave of targets (six target types, increasing value and difficulty).
  5. Lines 2000–2210: Title screen, menu, and instructions pages.
  6. Lines 3000–3420: End-of-game sequence, high-score entry and display with bubble sort.

Machine Code Blocks

Five distinct Z80 machine code routines are loaded via POKE loops driven by READ/DATA:

AddressLines loadedApparent purpose
600003Screen copy routine (ED B0 LDIR from 0x9C40 to 0x4000)
600504Reverse screen copy (LDIR from 0x4000 to 0x9C40)
601005Border color cycling / flash effect (OUT (254),A loop)
602009 (first loop)Target scrolling / display logic using pixel manipulation
602509 (second loop)Border animation driven by value at address 59990

The routine at 60000–60011 uses LD DE,9C40h / LD HL,4000h / LD BC,1B00h / LDIR / RET to copy the display file to a buffer area. The 60050 block reverses this. The 60100 routine cycles the border color while waiting for a keypress. The 60250 routine reads a border color from address 59990 (set by POKE 59990,f before calling) and uses an OUT (254),A loop to flash it — used for the end-of-round flash effect.

UDG Definitions

Lines 20–50 contain DATA for 21 UDGs (\a through \u), loaded at line 100 via FOR f=0 TO 167: READ a: POKE USR "\a"+f,a: NEXT f. Each UDG is 8 bytes; 21 × 8 = 168 bytes total. The UDGs define six two-character-wide target sprites used throughout the game:

  • \c/\d\e — 100-point target (yellow, line 1000)
  • \f\h/\g\i — 200-point target (white, line 1010)
  • \j\l/\k\m — 300-point target (cyan, line 1020)
  • \n\o/\p\q — 400-point target (green, line 1030)
  • \r\s/\t\u — 500-point target (magenta, line 1040)
  • Mixed row — 600-point target (line 1050)

Game Mechanics

The gun position is tracked in variable a, bouncing between columns 7 and 23 using variable x (+1 or -1). The gun sprite (UDGs \a and \b) is printed at rows 20–21. When the player presses any key, flag f is set. Hit detection at line 570 checks CODE(b$(a-5))>32 — i.e., whether the character in the scrolling target string at the gun’s current column is non-space, exploiting the fact that the target strings scroll character by character each game cycle. The delay between firing and the hit check simulates bullet travel time, as described in the instructions.

The target strings (a$ and b$) are rotated each tick using the idiom LET a$=a$(2 TO )+a$(1), creating the illusion of horizontal scrolling without machine code. Five targets per wave are spaced by two spaces each.

Wave Progression and Difficulty

Variable tam starts at 51 (ammo count) and decreases by 5 each completed wave (line 1070). If tam drops below 30, the player gets a 10,000-point bonus and the game ends (line 1080). The go variable is used as a GO SUB target: it starts at 1000 and increments by 10 each completed wave (LET go=go+10), stepping through subroutines 1000, 1010, 1020, 1030, 1040, 1050. This is an elegant use of computed GO SUB to select the next difficulty level.

High Score Table

Arrays h(5) and h$(5,10) hold up to five scores and ten-character names. After each game, if the score exceeds h(5) (the lowest stored score), name entry is triggered. A bubble sort (lines 3110–3180) then orders the table. The name entry loop at lines 3054–3066 supports backspace via CHR$ 12 detection, decrementing index g and overwriting the display — a manual line editor in BASIC.

Screen Construction

The rifle range backdrop is drawn entirely with PLOT/DRAW/CIRCLE calls (lines 200–345), including the tent roof perspective lines (lines 240–270), tent poles, and circular target rings (line 300). The decorative curtain/tent posts at line 345 use UDGs \c, \d, \e printed with PAPER 2; INK 6. The title screen at line 2010 and the high-score header at line 3190 use packed block graphic escape sequences to render stylized large text using Spectrum block graphics characters.

Notable Idioms and Techniques

  • RANDOMIZE USR nnnnn is used throughout to call machine code routines — the return value from USR is discarded by RANDOMIZE.
  • POKE 59990,g before RANDOMIZE USR 60250 passes a parameter to the MC border flash routine via a fixed memory address rather than a register, since BASIC cannot pass arguments to USR directly.
  • The scrolling target string trick (string rotation via slicing) avoids any machine code for animation of the target row.
  • LET go=go+10: GO TO 380 / GO SUB go uses a variable as a subroutine address — this works on the Spectrum because GO SUB evaluates its argument as a numeric expression.
  • The FOR/NEXT loop at lines 2025–2055 acts as a timeout on the title menu: if neither key is pressed within 500 iterations, the program falls through to display the high-score table at line 3190.

Potential Anomalies

  • Line 270 duplicates PLOT 188,48: DRAW 14,-32 — this appears to be a copy-paste error in the tent roof construction, drawing one line twice with no visible effect.
  • Line 500 references variable in (the ink color for the target row) but in is only set inside the subroutines at lines 1000–1050. On the very first call before GO SUB go, the initial value of in is 0 (uninitialized), which would print the targets in the default ink. However, GO SUB go at line 380 is always called before line 500 is first reached, so in practice this is not an issue.
  • UDG \b is referenced in line 530 ("\b" for the gun sprite bottom row) but is not explicitly defined in the DATA blocks labeled for UDGs \a–\u. UDG \b occupies the second 8-byte slot of the UDG area immediately following \a, so it is implicitly defined by the 168-byte DATA block starting at line 20, which covers all 21 UDGs.

Content

Appears On

A little of everything — play Battleship with adjustable AI, solve Klondike Solitaire with custom card graphics, guide Santa's reindeer into their pen, or track your stock portfolio on tape. The potpourri tape lives up to its name.

Related Products

Related Articles

Related Content

Image Gallery

Rifle Range

Source Code

    1 RESTORE : CLEAR 60000: REM   by Michael Housley of Bradford,Yorkshire
    2 DATA 17,64,156,33,0,64,1,0,27,237,176,201,17,0,64,33,64,156,1,0,27,237,176,201,33,0,88,1,0,3,197,62,0,1,100,0,11,60,211,254,120,177,32,248,54,7,35,54,54,193,11,120,177,32,231,201,32,228,201
    3 FOR f=60000 TO 60011: READ a: POKE f,a: NEXT f
    4 FOR f=60050 TO 60061: READ a: POKE f,a: NEXT f
    5 FOR f=60100 TO 60134: READ a: POKE f,a: NEXT f
    6 DIM h(5): DIM h$(5,10)
    7 FOR f=1 TO 5: LET h(f)=6000-(f*1000): NEXT f
    8 FOR f=1 TO 5: LET h$(f)="SPECTRUM": NEXT f
    9 FOR f=60200 TO 60241: READ a: POKE f,a: NEXT f: FOR f=60250 TO 60266: READ a: POKE f,a: NEXT f
   10 DATA 1,2,0,197,33,0,64,1,0,4,126,15,119,35,126,7,119,35,11,120,177,32,243,193,11,120,177,32,1,201,33,0,80,120,177,197,1,0,4,32,225,201,33,0,88,1,0,3,58,86,234,119,35,11,120,177,32,246,201
   11 DATA 108,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,0,0,28,30,46,126,30,28,60,62,31,31,15,15,7,3,31,124,252,252,248,248,240,224
   20 DATA 3,12,16,35,68,72,145,146,146,145,72,68,35,16,12,3,192,48,8,196,34,18,137,73,73,137,18,34,196,8,48,192
   30 DATA 1,1,1,3,3,3,31,255,255,31,3,3,3,1,1,1,128,128,128,192,192,192,248,255,255,248,192,192,192,128,128,128
   40 DATA 15,16,36,42,68,64,127,64,224,16,72,168,68,4,252,4,32,24,5,7,53,73,129,255,8,48,64,192,56,36,2,254
   50 DATA 1,1,1,3,3,255,63,7,128,128,128,192,192,255,252,224,7,15,14,28,56,112,224,192,224,240,112,56,28,14,7,3
  100 FOR f=0 TO 167: READ a: POKE USR "\a"+f,a: NEXT f
  150 PAPER 2: INK 0: BRIGHT 1: BORDER 2: CLS 
  160 FOR f=0 TO 3: PRINT PAPER 5;AT f,0;"                                ": NEXT f
  170 FOR f=0 TO PI^2 STEP .1: PLOT INK 6;235+SIN (f/PI)*14,160+COS (f/PI)*14: DRAW INK 6;-(((235+SIN (f/PI)*14)-235)*2),0: NEXT f
  175 PLOT INVERSE 1; PAPER 0; INK 6;225,156: DRAW INVERSE 1; INK 6; PAPER 0;20,0,1.5: DRAW INVERSE 1; PAPER 0; INK 6;-20,0,-.75
  177 CIRCLE INVERSE 1; INK 6; PAPER 0;232,162,3: PLOT INVERSE 1; INK 6; PAPER 0;233,162
  178 CIRCLE INVERSE 1; INK 6; PAPER 0;238,162,3: PLOT INVERSE 1; INK 6; PAPER 0;237,162
  179 CIRCLE INVERSE 1; INK 6; PAPER 0;235,157,2
  180 PLOT 0,0: FOR f=0 TO 15: PLOT f,f: DRAW 15-f,0: PLOT 255-f,-f: DRAW f-15,0: NEXT f
  200 PLOT 0,0: DRAW 48,48: DRAW 159,0: DRAW 48,-48: DRAW 0,140: DRAW -255,0: DRAW 0,-140
  210 PLOT 48,48: DRAW 0,92: PLOT 207,48: DRAW 0,92: PLOT 16,16: DRAW 223,0
  220 PLOT 10,10: DRAW 0,130: PLOT 20,20: DRAW 0,120: PLOT 30,30: DRAW 0,110: PLOT 40,40: DRAW 0,100
  230 PLOT 245,10: DRAW 0,130: PLOT 235,20: DRAW 0,120: PLOT 225,30: DRAW 0,110: PLOT 215,40: DRAW 0,100
  240 PLOT 58,48: DRAW -24,-32: PLOT 68,48: DRAW -14,-32: PLOT 78,48: DRAW -9,-32: PLOT 88,48: DRAW -5,-32
  250 PLOT 98,48: DRAW -4,-32: PLOT 108,48: DRAW -3,-32: PLOT 118,48: DRAW -2,-32: PLOT 128,48: DRAW 0,-32
  260 PLOT 138,48: DRAW 2,-32: PLOT 148,48: DRAW 3,-32: PLOT 158,48: DRAW 4,-32: PLOT 168,48: DRAW 5,-32
  270 PLOT 178,48: DRAW 9,-32: PLOT 188,48: DRAW 14,-32: PLOT 188,48: DRAW 14,-32: PLOT 198,48: DRAW 24,-32
  280 PLOT 48,95: DRAW 159,0: DRAW 10,-3: DRAW -179,0: DRAW 8,3: PLOT 38,92: DRAW 0,-2: DRAW 179,0: DRAW 0,2
  290 PLOT 0,140: DRAW 0,2: DRAW 255,0: DRAW 0,-2
  300 FOR f=67 TO 187 STEP 20: CIRCLE INK 7;f,106,10: CIRCLE INK 7;f,106,7: NEXT f
  310 PRINT PAPER 0; INK 7;AT 2,6;"YE OLDE RIFLE RANGE."
  320 PLOT 45,149: DRAW 165,0: DRAW 0,13: DRAW -165,0: DRAW 0,-13
  330 PLOT 80,149: DRAW 0,-6: PLOT 82,149: DRAW 0,-6: PLOT 175,149: DRAW 0,-6: PLOT 173,149: DRAW 0,-6
  340 PLOT 80,142: PLOT 82,142: PLOT 175,142: PLOT 173,142
  345 PRINT PAPER 2; INK 6;AT 5,8;"\c";AT 6,8;"\d\e";AT 5,22;"\c";AT 6,22;"\d\e"
  350 PRINT PAPER 7;AT 5,11;"YE PRIZES.";AT 11,12;"YE SCORE"; PAPER 0;AT 12,13;"      ";AT 14,6;"                    ";AT 15,6;"                    "
  360 PRINT PAPER 7;AT 0,11;"YE AMMO "; PAPER 0;"   ": PRINT PAPER 0;AT 20,2;"                            ";AT 21,1;"                              "
  361 PAUSE 60
  363 RANDOMIZE USR 60000
  365 GO TO 2000
  367 BORDER 0
  368 LET sc=0: LET bon=1000: LET tam=51
  369 RANDOMIZE USR 60050
  370 LET co=0: LET a=15: LET f=0: LET x=1: LET am=tam: LET go=1000
  375 PRINT PAPER 0; INK 6;AT 0,19;am
  380 GO SUB go
  390 LET f=0: LET am=am-1
  400 PRINT PAPER 0; INK 6;AT 0,19;am;" "
  500 PRINT PAPER 0; INK in;AT 14,6;a$;AT 15,6;b$
  510 IF INKEY$<>"" THEN LET f=1: BEEP .01,-10
  520 LET a$=a$(2 TO )+a$(1): LET b$=b$(2 TO )+b$(1)
  530 PRINT INK 5; PAPER 0;AT 20,a;" \a ";AT 21,a;" \b "
  540 LET a=a+x
  550 IF a<7 THEN LET x=1
  560 IF a>23 THEN LET x=-1
  570 IF f=1 AND CODE (b$(a-5))>32 THEN GO TO 600
  580 IF f=1 THEN LET f=0: LET am=am-1
  585 IF am=0 THEN GO TO 3000
  590 GO TO 400
  600 BEEP .01,20
  610 LET co=co+1
  620 LET b$(a-5)=" "
  630 IF CODE (b$(a-6))>32 THEN LET b$(a-6)=" "
  640 IF CODE (b$(a-4))>32 THEN LET b$(a-4)=" "
  650 LET a$(a-6 TO a-4)="   "
  660 LET sc=sc+va: PRINT INK RND*6+1; PAPER 0;AT 12,13;sc;" "
  670 IF co=5 THEN LET go=go+10: GO TO 380
  675 IF am=0 THEN GO TO 3000
  680 GO TO 580
 1000 LET va=100: LET in=6: LET a$="\c   \c   \c   \c   \c   ": LET b$="\d\e  \d\e  \d\e  \d\e  \d\e  ": RETURN 
 1010 LET co=0: LET va=200: LET in=7: LET a$="\f\h  \f\h  \f\h  \f\h  \f\h  ": LET b$="\g\i  \g\i  \g\i  \g\i  \g\i  ": RETURN 
 1020 LET co=0: LET va=300: LET in=4: LET a$="\j\l  \j\l  \j\l  \j\l  \j\l  ": LET b$="\k\m  \k\m  \k\m  \k\m  \k\m  ": RETURN 
 1030 LET co=0: LET va=400: LET in=5: LET a$="\n\o  \n\o  \n\o  \n\o  \n\o  ": LET b$="\p\q  \p\q  \p\q  \p\q  \p\q  ": RETURN 
 1040 LET co=0: LET va=500: LET in=3: LET a$="\r\s  \r\s  \r\s  \r\s  \r\s  ": LET b$="\t\u  \t\u  \t\u  \t\u  \t\u  ": RETURN 
 1050 LET co=0: LET va=600: LET in=7: LET a$="\r\s  \c   \f\h  \j\l  \n\o  ": LET b$="\t\u  \d\e  \g\i  \k\m  \p\q  ": RETURN 
 1060 FOR f=0 TO 10: FOR g=7 TO 0 STEP -1: POKE 59990,g: RANDOMIZE USR 60250: BEEP .001,f*2+20: NEXT g: NEXT f
 1065 RANDOMIZE USR 60050: BEEP .01,20
 1070 PRINT AT 20,a;"  ";AT 21,a;"  ": LET sc=sc+bon: LET tam=tam-5
 1080 IF tam<30 THEN LET sc=sc+10000: GO TO 3000
 1090 GO TO 370
 2000 BORDER 0: PAPER 0: INK 7: CLS 
 2001 LET ink=RND*5+1
 2005 FOR f=4 TO 5: PRINT INK ink;AT f,0;"\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.\'.";AT f+13,0;"\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':\':": NEXT f
 2010 PRINT INK ink;AT 8,6;"\ .\':\':\' \ .\' \ : \ .\'  \ .\':\ .\ :\ '\ :\ :\''\ :\''           \ .\':\ : \ . \ : \ .  \ .\':\ .\ :\ :\':\ :\ :\ :\'            \' \' \''\' \'  \''\' \''\'  \' \' \' \' \' \ '\ '\''\ '\''"
 2020 PRINT AT 12,0;"PRESS EITHER"''"1.FOR INSTRUCTIONS"'"          OR 2.TO PLAY"
 2025 FOR f=0 TO 500
 2028 RANDOMIZE USR 60200
 2030 IF INKEY$="1" THEN BEEP .01,10: GO TO 2060
 2040 IF INKEY$="2" THEN BEEP .01,10: GO TO 367
 2050 NEXT f
 2055 CLS : GO TO 3190
 2060 CLS : INK 0
 2070 PRINT "USE ANY KEY TO SHOOT AT THE"''"TARGETS."
 2080 PRINT '"THE GAME WILL END WHEN YOU HAVE"''"NO AMMUNITION LEFT."
 2090 PRINT '"IF YOU SHOOT ALL THE TARGETS"''"THEN YOU WILL GET SOME BONUS"''"POINTS AND START AGAIN WITH LESS"''"AMMUNITION."
 2095 PRINT ''"PRESS ANY KEY.": RANDOMIZE USR 60100: BORDER 0
 2096 PAUSE 0: CLS 
 2100 PRINT "WHILST YOU ARE PLAYING THE GAME"''"YOUR GUN WILL MOVE BACKWARDS"''"AND FORWARDS ACROSS THE"''"BOTTOM OF THE SCREEN JUST TO"''"MAKE THINGS HARDER."
 2110 PRINT '"REMEMBER TO ALLOW FOR THE DELAY"''"BEFORE THE BULLET REACHES THE"''"TARGET."
 2120 PRINT ''"PRESS ANY KEY."
 2125 RANDOMIZE USR 60100: BORDER 0
 2130 PAUSE 0: CLS 
 2140 PRINT "\c   \c   \c   \c   \c     100 POINTS"'"\d\e  \d\e  \d\e  \d\e  \d\e        EACH"
 2150 PRINT '"\f\h  \f\h  \f\h  \f\h  \f\h    200 POINTS"'"\g\i  \g\i  \g\i  \g\i  \g\i        EACH"
 2160 PRINT '"\j\l  \j\l  \j\l  \j\l  \j\l    300 POINTS"'"\k\m  \k\m  \k\m  \k\m  \k\m        EACH"
 2170 PRINT '"\n\o  \n\o  \n\o  \n\o  \n\o    400 POINTS"'"\p\q  \p\q  \p\q  \p\q  \p\q        EACH"
 2180 PRINT '"\r\s  \r\s  \r\s  \r\s  \r\s    500 POINTS"'"\t\u  \t\u  \t\u  \t\u  \t\u        EACH"
 2190 PRINT '"\c   \f\h  \j\l  \n\o  \r\s    600 POINTS"'"\d\e  \g\i  \k\m  \p\q  \t\u        EACH"
 2200 PRINT ''"PRESS ANY KEY."
 2205 RANDOMIZE USR 60100: BORDER 0
 2210 PAUSE 0: INK 7: CLS : GO TO 2001
 3000 FOR f=7 TO 0 STEP -1: POKE 59990,f: RANDOMIZE USR 60250: BEEP .01,f*2: PAUSE 10: NEXT f: BORDER 0: BEEP .2,-20: CLS 
 3010 IF sc>h(5) THEN GO TO 3050
 3020 PRINT FLASH 1;AT 8,8;"YOU SCORED ";sc
 3030 PRINT INK 7;AT 16,9;"PRESS ANY KEY."
 3040 PAUSE 0: GO TO 2000
 3050 LET h$(5)="": PRINT "     PLEASE ENTER YOUR NAME"
 3051 PRINT AT 10,10;"----------": PRINT AT 15,8;"YOU SCORED ";sc
 3052 LET g=1
 3054 PAUSE 0
 3056 LET l$=INKEY$: BEEP .005,10
 3058 IF l$=CHR$ 13 THEN GO TO 3080
 3059 IF g>1 AND l$=CHR$ 12 THEN LET h$(5,g)="": PRINT CHR$ 8;"-";CHR$ 8;: LET g=g-1: GO TO 3054
 3060 LET h$(5,g)=l$
 3062 PRINT AT 10,g+10;l$;
 3064 LET g=g+1
 3066 IF g<11 THEN GO TO 3054
 3080 CLS 
 3100 LET h(5)=sc
 3110 LET zx=4
 3120 FOR f=1 TO zx
 3130 IF h(f)>=h(f+1) THEN GO TO 3160
 3140 LET v=h(f): LET h(f)=h(f+1): LET h(f+1)=v
 3150 LET v$=h$(f): LET h$(f)=h$(f+1): LET h$(f+1)=v$
 3160 NEXT f
 3170 LET zx=zx-1
 3180 IF zx>0 THEN GO TO 3120
 3190 PRINT AT 0,2; INK RND*6+1;"\ :\ :\ .\'  \ :\ :\ .\ :\ : \ :  \ .\ :\ .\'  \ .\' \ .\ :\ .\ .\ :\ .\'     \':\' \ .  \ .\ :\ .\ :\ : \ :  \ :\ :\ .  \ . \ .\ :\ :\ :\ :\ .     \ ' \''\'  \' \' \' \' \''\' \''\'  \''\' \'   \'  \' \' \' \' \' \''\' "
 3200 FOR f=1 TO 5: PRINT INK f+2;AT (f*2)+3,0;f;"-------- ";h$(f);AT (f*2)+3,21;" ---- ";h(f): NEXT f
 3400 PRINT AT 18,5;"    PRESS ANY KEY.    "
 3405 FOR f=0 TO 1000
 3410 IF INKEY$<>"" THEN GO TO 365
 3420 NEXT f: GO TO 2000
 9997 STOP 
 9999 SAVE "Rifle*" LINE 1

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

People

No people associated with this content.

Scroll to Top