Treasure Hunt

Developer(s): Paul Sherwood
Date: 1983
Type: Program
Platform(s): TS 1000
Tags: Game

This is a Hunt the Wumpus-style cave adventure game in which the player navigates a network of interconnected caves, shoots arrows at monsters, and attempts to escape with treasure. The cave map is encoded in the string B$ using ASCII-offset character codes (subtracting 37 from the CODE of each character) to store up to three exits per room in a compact format. Movement uses the classic Sinclair key layout (5/6/7/8), and the program employs PEEK of the system variable at address 16396/16397 to find the top of the BASIC program area for collision detection via character-cell scanning. A special cave (PR=21) triggers a boss-room sequence with a bouncing enemy that uses a simple reflection algorithm for wall collision.


Program Analysis

Program Structure

The program is divided into several functional blocks:

  1. Initialisation (lines 5–95): Dimensions arrays, builds the decorative border string C$, sets up the cave map in B$, and jumps to line 1300 (which is absent — likely a separate loader or the game starts at line 1340 via fall-through to the nearest higher line).
  2. Room renderer (lines 150–265): Draws the cave walls with block graphics, places monsters (DEM enemies), shows arrow count and room numbers in the border.
  3. Main game loop (lines 265–360): Reads keys 5/6/7/8 for movement, fires arrows with “F”, detects wall collisions via PEEK, and calls monster-movement subroutine.
  4. Room transition (lines 805–970): Handles movement between caves, decodes exits from B$, and re-renders the new room.
  5. Arrow flight (lines 1000–1125): Traces the arrow’s path cell by cell, checking for monster hits and boundary collisions.
  6. Monster movement (lines 1201–1255): Moves each monster one step toward the player using SGN.
  7. Entrance hall / scoring (lines 1340–1660): Starting cave selection, safe-zone score banking, and arrow purchase system.
  8. Death screen (lines 2005–2040): Penalises the score by 15 if the player has enough points; otherwise stops.
  9. Boss room — cave 21 (lines 2050–2115): Draws a special diamond-shaped room using sliced string printing, places treasure markers, and launches the bouncing enemy loop.
  10. Bouncing enemy (lines 3000–3035): Moves the Wumpus-like creature and handles wall reflection.

Cave Map Encoding

The map data is stored compactly in B$ (lines 70–76). Each cave occupies exactly three characters in the string; the exit room numbers are retrieved by CODE R$ - 37, converting printable ASCII characters (starting at code 38, i.e., &) to room indices 1–20. The three exits per room are stored at positions PR*3-2, PR*3-1, and PR*3. When the player arrives from room LR, the code at lines 960–965 replaces whichever exit leads back to LR with the third exit R3, so only two novel directions are shown on screen.

Collision Detection via PEEK

Line 55 computes Q = PEEK 16396 + 256*PEEK 16397 + 1, which reads the display file address from the ZX81 system variables (D_FILE, address 16396). Adding 33*row + column to Q gives the character-cell content of any screen position. Lines 320–325 use this to test whether the player is walking into a wall character (code > 62), and line 1053 does the same for the arrow’s path. This avoids storing a separate map array and directly queries the display.

Movement and Key Handling

Player movement uses the standard Sinclair cursor-key layout. Lines 310–315 use the Boolean-arithmetic idiom (1 AND INKEY$="x") to add or subtract 1 from the row/column variables in a single expression, avoiding IF statements in the hot loop. Arrow firing on key “F” calls GOSUB 1000, which traces the projectile cell by cell using a direction vector (MX, MY) derived from the last key pressed before “F” was held.

Boss Room (Cave 21)

Cave 21 is a special case throughout the code. The diamond-shaped room at lines 2050–2115 is drawn by printing substrings of C$C$(TO AI) where AI = ABS I for I from -10 to 10 — creating a diagonal border effect purely with string slicing. The bouncing creature at lines 3000–3035 uses a reflection algorithm: if the next cell is occupied, the direction vector components are swapped or negated to simulate a bounce off a wall.

Scoring and Economy

Two score accumulators are used: S for banked permanent score and TR for treasure collected in the current run. Dying deducts 15 from S provided S+TR >= 50+PS (where PS is the previous high-water mark), giving a soft continue system. Arrows cost 4 points each and are bought at the entrance hall between runs. Killing a monster awards 5 points (line 1098).

Notable Techniques

  • RAND (PR*10+NOW) at line 162 seeds the random number generator deterministically per room and session start time, so each room visit produces consistent but varied layouts.
  • The decorative border C$ is built using concatenation with block graphic escapes (\## = solid block, % = space/checker pattern) at initialisation rather than being recomputed each frame.
  • Monster positions are stored in the 2-D array D(3,2) — limiting the maximum number of monsters per room to 3 — with a swap-and-decrement idiom at lines 1100–1110 for O(1) deletion from the active list.
  • GOTO 1300 at line 95 targets a non-existent line, so execution falls through to line 1340, a well-known ZX81 technique for computed or conditional entry points.
  • The T(20) array tracks whether each cave has been visited before; an asterisk is printed on the exit marker only for unvisited caves (line 222), and the flag is cleared on entry (line 224).

Potential Bugs and Anomalies

  • Line 800 is referenced by GOTO 800 at line 335 (triggered when character code 8 — a ZX81 backspace/delete glyph — is detected underfoot), but the actual label is line 805. On the ZX81, GOTO to a non-existent line jumps to the next higher line, so this works correctly.
  • The arrow-firing subroutine starts at line 1000 but the first executable line is 1003. Lines 1000–1002 are absent; the entry point relies on fall-through from GOSUB 1000 landing at 1003.
  • DIM D(3,2) limits monsters to 3, but DEM = INT(RND*4) at line 230 can produce values 0–3, so the maximum of 3 is valid. However, line 86 in the boss room sets DEM=1 without re-dimensioning, reusing the same array safely.
  • The arrow direction is taken from F$ (last non-fire keypress) at lines 1030–1035, but F$ is also used as a general input variable elsewhere, so rapid key changes could theoretically affect arrow direction.

Content

Appears On

Related Products

Related Articles

Maze game.

Related Content

Image Gallery

Treasure Hunt

Source Code

   5 DIM D(3,2)
   7 DIM T(20)
   8 LET Z$="YOU ARE IN THE ENTRANCE HALL"
  10 LET LR=0
  11 LET C$="% % % % % % % % % % % % "
  13 LET C$=C$+"\##\##\##\##"
  15 LET C$=C$+"% % % % % % % % % % % % % % "
  20 LET ARR=5
  25 FOR I=1 TO 20
  30 LET T(I)=1
  35 NEXT I
  37 LET PS=0
  40 LET S=0
  55 LET Q=PEEK 16396+256*PEEK 16397+1
  60 LET TR=0
  65 RAND 
  68 LET NOW=INT (RND*5000)
  70 LET B$="9BE9AF9DG9CHAHIBIJ"
  72 LET B$=B$+"CJKDEKEFLFGMGHN"
  74 LET B$=B$+"IOQJOPKPTLMRMNS"
  76 LET B$=B$+"LRTOQUPTUNQS9RS"
  80 LET R1=0
  82 LET R2=0
  84 LET R3=0
  95 GOTO 1300
 150 CLS 
 155 FAST 
 162 RAND (PR*10+NOW)
 165 FOR I=0 TO 20
 170 LET IY=RND*16+2
 175 LET IX=RND*27+2
 180 PRINT AT IY,IX;"% ";
 185 IF RND>.5 THEN PRINT AT IY-1,IX-1;CHR$ (128+RND*2);
 190 PRINT AT IY,IX+1;"\:.";
 195 PRINT AT IY+1,IX;CHR$ (128+RND*2);
 200 IF RND>.6 THEN PRINT AT IY+1,IX+1;CHR$ 130;
 205 PRINT AT I,0;"% ";AT I,31;"% ";
 210 NEXT I
 212 PRINT AT 0,1;C$;AT 20,1;C$;
 214 PRINT AT 0,17;R1;AT 20,17;R2;
 215 LET N=11
 220 LET M=1
 222 IF T(PR)=1 THEN PRINT AT IY,IX+1;"*";
 224 LET T(PR)=0
 230 LET DEM=INT (RND*4)
 235 FOR I=1 TO DEM
 240 LET D(I,1)=INT (RND*19+1)
 245 LET D(I,2)=INT (RND*30+1)
 250 PRINT AT D(I,1),D(I,2);"%M";
 255 NEXT I
 256 SLOW 
 275 PRINT AT N,M;"X";
 280 IF INKEY$<>"F" THEN GOTO 300
 285 IF ARR=0 THEN GOTO 300
 290 LET ARR=ARR-1
 295 GOSUB 1000
 298 PRINT AT 21,0;"ARROWS:";ARR;
 300 LET N1=N
 305 LET M1=M
 310 LET M=M+(1 AND INKEY$="8")-(1 AND INKEY$="5")
 315 LET N=N+(1 AND INKEY$="6")-(1 AND INKEY$="7")
 320 LET Q1=PEEK (Q+33*N+M)
 325 IF Q1>62 THEN GOTO 2000
 330 IF Q1=23 AND TR<50 THEN LET TR=TR+10
 335 IF Q1=8 THEN GOTO 800
 338 IF ABS (10-N)=10 THEN GOTO 2000
 339 IF PR=21 THEN GOTO 355
 340 IF DEM=0 AND RND<.03 THEN LET DEM=1
 342 IF RND<.3+TR/200 THEN GOSUB 1200
 345 PRINT AT N1,M1;" ";
 350 GOTO 265
 355 GOSUB 3000
 360 GOTO 345
 805 CLS 
 810 LET LR=PR
 812 IF PR<>21 THEN GOTO 815
 813 LET PR=INT (RND*19+1)
 814 GOTO 825
 815 IF N=0 THEN LET PR=R1
 820 IF N=20 THEN LET PR=R2
 822 IF PR=0 THEN GOTO 1505
 825 PRINT AT 3,2;"YOU ARE IN THE TUNNEL"
 830 PRINT AT 5,2;"BETWEEN ";LR;" AND ";PR
 835 PRINT AT 8,2;"YOU HAVE ";ARR;" ARROWS";
 840 PRINT AT 11,2;"YOUR SCORE IS ";TR+S
 915 IF PR=21 THEN GOTO 2050
 920 LET R$=B$(PR*3-2)
 925 LET R1=CODE R$-37
 930 LET R$=B$(PR*3-1)
 935 LET R2=CODE R$-37
 940 LET R$=B$(PR*3)
 945 LET R3=CODE R$-37
 960 IF R1=LR THEN LET R1=R3
 965 IF R2=LR THEN LET R2=R3
 970 GOTO 150
\n1003 IF PR=21 THEN GOSUB 3000
\n1005 IF RND<.5 THEN GOSUB 1200
\n1010 LET F$=INKEY$
\n1015 IF F$="" OR F$="F" THEN GOTO 1000
\n1020 LET Y1=N
\n1025 LET X1=M
\n1030 LET MY=(F$="6")-(F$="7")
\n1035 LET MX=(F$="8")-(F$="5")
\n1040 LET X1=X1+MX
\n1045 LET Y1=Y1+MY
\n1050 IF ABS (15-X1)=15 OR ABS (10-Y1)=10 THEN GOTO 1125 
\n1053 IF PEEK (Q+33*Y1+X1)<>0 THEN GOTO 1070
\n1055 PRINT AT Y1,X1;"+";
\n1060 PRINT AT Y1,X1;" ";
\n1065 GOTO 1040
\n1070 LET DHIT=DEM
\n1075 FOR I=1 TO DHIT
\n1080 LET Y=D(I,1)
\n1085 LET X=D(I,2)
\n1090 IF X<>X1 OR Y<>Y1 THEN GOTO 1115
\n1095 PRINT AT Y1,X1;"%+";
\n1098 LET S=S+5
\n1100 LET D(I,1)=D(DEM,1)
\n1105 LET D(I,2)=D(DEM,2)
\n1110 LET DEM=DEM-1
\n1115 NEXT I
\n1117 IF PR=21 THEN LET FX=X1
\n1118 IF PR=21 THEN LET FY=Y1
\n1120 PRINT AT Y1,X1;" ";
\n1125 RETURN 
\n1201 FOR I=1 TO DEM
\n1205 LET X=D(I,2)
\n1210 LET Y=D(I,1)
\n1215 PRINT AT Y,X;" ";
\n1220 LET Y=Y+SGN (N-Y)
\n1225 LET X=X+SGN (M-X)
\n1235 PRINT AT Y,X;"%M";
\n1238 IF M=X AND Y=N THEN GOTO 2000
\n1240 LET D(I,1)=Y
\n1245 LET D(I,2)=X
\n1250 NEXT I
\n1255 RETURN 
\n1340 PRINT Z$,,,
\n1342 PRINT "CHOOSE CAVE 1, 2, 3, OR 4",,
\n1345 INPUT PR
\n1350 IF PR<1 OR PR>4 THEN GOTO 1345
\n1360 LET LR=0
\n1500 GOTO 915
\n1505 PRINT Z$,,,
\n1510 PRINT "YOUR TREASURE IS SAFE HERE",,,
\n1515 PRINT "YOUR SCORE IS ";S+TR,,,,
\n1518 PRINT TAB 0;"YOU HAVE ";ARR;" ARROWS"
\n1520 PRINT TAB 0;"ARE YOU GOING BACK IN?",,,,,
\n1525 INPUT F$
\n1530 IF F$="NO" THEN PRINT "YOU SCORED ";S+TR
\n1535 IF F$="NO" THEN STOP 
\n1540 LET S=S+TR
\n1545 LET TR=0
\n1550 PRINT "HOW MANY ARROWS DO YOU WANT?",,,
\n1560 PRINT "THEY ARE 4 POINTS EACH",,,
\n1570 INPUT F
\n1580 IF F*4>S THEN GOTO 1650
\n1590 LET S=S-F*4
\n1600 LET ARR=ARR+F
\n1610 GOTO 1342
\n1650 CLS 
\n1655 PRINT "  YOU CAN""T AFFORD THEM",,,
\n1660 GOTO 1550
\n2005 CLS 
\n2010 PRINT AT 5,1;"UNFORTUNATELY YOU HAVE PERISHED"
\n2015 PRINT AT 8,1;"YOU SCORED ";S+TR
\n2018 PRINT 
\n2019 PRINT 
\n2020 IF S+TR<50+PS THEN STOP 
\n2025 LET S=S-15
\n2028 LET PS=S+TR
\n2029 PRINT "YOU PLAYED WELL.",,,
\n2030 PRINT "I SHALL DEDUCT 15"
\n2031 PRINT 
\n2032 PRINT "FOR DAMAGE TO THE BODY";
\n2033 PRINT 
\n2034 PRINT 
\n2035 PRINT "YOU MAY CONTINUE";
\n2036 FOR I=1 TO 50
\n2037 NEXT I
\n2038 CLS 
\n2040 GOTO 1505
\n2050 PRINT AT 0,0;
\n2052 CLS 
\n2055 FOR I=-10 TO 10
\n2058 LET AI=ABS I
\n2060 PRINT TAB 0;C$( TO AI);
\n2065 PRINT TAB (30-AI);C$( TO AI)
\n2070 NEXT I
\n2075 PRINT AT 0,10;C$( TO 10)
\n2080 PRINT AT 20,10;C$( TO 10)
\n2085 PRINT AT 10,0;"% ";TAB 29;"\##"
\n2086 LET DEM=1
\n2087 LET QW=INT (RND*4)
\n2090 FOR I=1 TO QW+1
\n2095 PRINT AT 12+I,12+(RND*2);"***";
\n2100 NEXT I
\n2105 LET N=10
\n2106 LET MY=-1
\n2107 LET MX=0
\n2108 LET K=18
\n2109 LET J=7
\n2110 LET M=2
\n2111 LET FX=J
\n2112 LET FY=K
\n2115 GOTO 265
\n3000 IF PEEK (Q+33*(K+MY)+J+MX)=0 THEN GOTO 3015
\n3002 LET AD=MY
\n3005 IF AD=0 THEN LET MY=MX
\n3006 IF AD=0 THEN LET MX=0
\n3007 IF AD<>0 THEN LET MY=0
\n3008 IF AD<>0 THEN LET MX=-AD
\n3015 LET J=J+MX
\n3020 LET K=K+MY
\n3025 PRINT AT K,J;"\'.";
\n3030 IF RND>.5 THEN PRINT AT FY,FX;"\'."
\n3032 IF RND<.25 THEN GOSUB 1200
\n3035 RETURN 

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

Scroll to Top