--- title: "Treasure Hunt" id: 56740 type: "computer_media" slug: "treasure-hunt-2" url: "http://localhost/computer_media/treasure-hunt-2/" markdown_url: "http://localhost/computer_media/treasure-hunt-2.md" published_at: "2024-09-22T23:31:59+00:00" modified_at: "2026-04-03T07:58:52+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/Treasure.jpeg" excerpt: "Navigate a network of caves, fire arrows at pursuing monsters, and haul your treasure to safety in this compact action-adventure with encoded room maps." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" indiv: - name: "Paul Sherwood" slug: "paul-sherwood" taxonomy: "indiv" url: "http://localhost/indiv/paul-sherwood/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Program" programmers: - name: "Paul Sherwood" slug: "paul-sherwood" taxonomy: "indiv" url: "http://localhost/indiv/paul-sherwood/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Treasure%20Hunt%20%281983%29%28P%20Sherwood%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "1983" images: - url: "http://localhost/wp-content/uploads/2024/09/Treasure.jpeg" - url: "http://localhost/wp-content/uploads/2024/09/Treasure-Hunt.jpg" article_media: - id: 20160 title: "Treasure Hunt" type: "article" url: "http://localhost/article/treasure-hunt/" media_type_tags: "Game" --- # Treasure Hunt 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. ## 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 1003 IF PR=21 THEN GOSUB 3000 1005 IF RND<.5 THEN GOSUB 1200 1010 LET F$=INKEY$ 1015 IF F$="" OR F$="F" THEN GOTO 1000 1020 LET Y1=N 1025 LET X1=M 1030 LET MY=(F$="6")-(F$="7") 1035 LET MX=(F$="8")-(F$="5") 1040 LET X1=X1+MX 1045 LET Y1=Y1+MY 1050 IF ABS (15-X1)=15 OR ABS (10-Y1)=10 THEN GOTO 1125 1053 IF PEEK (Q+33*Y1+X1)<>0 THEN GOTO 1070 1055 PRINT AT Y1,X1;"+"; 1060 PRINT AT Y1,X1;" "; 1065 GOTO 1040 1070 LET DHIT=DEM 1075 FOR I=1 TO DHIT 1080 LET Y=D(I,1) 1085 LET X=D(I,2) 1090 IF X<>X1 OR Y<>Y1 THEN GOTO 1115 1095 PRINT AT Y1,X1;"%+"; 1098 LET S=S+5 1100 LET D(I,1)=D(DEM,1) 1105 LET D(I,2)=D(DEM,2) 1110 LET DEM=DEM-1 1115 NEXT I 1117 IF PR=21 THEN LET FX=X1 1118 IF PR=21 THEN LET FY=Y1 1120 PRINT AT Y1,X1;" "; 1125 RETURN 1201 FOR I=1 TO DEM 1205 LET X=D(I,2) 1210 LET Y=D(I,1) 1215 PRINT AT Y,X;" "; 1220 LET Y=Y+SGN (N-Y) 1225 LET X=X+SGN (M-X) 1235 PRINT AT Y,X;"%M"; 1238 IF M=X AND Y=N THEN GOTO 2000 1240 LET D(I,1)=Y 1245 LET D(I,2)=X 1250 NEXT I 1255 RETURN 1340 PRINT Z$,,, 1342 PRINT "CHOOSE CAVE 1, 2, 3, OR 4",, 1345 INPUT PR 1350 IF PR<1 OR PR>4 THEN GOTO 1345 1360 LET LR=0 1500 GOTO 915 1505 PRINT Z$,,, 1510 PRINT "YOUR TREASURE IS SAFE HERE",,, 1515 PRINT "YOUR SCORE IS ";S+TR,,,, 1518 PRINT TAB 0;"YOU HAVE ";ARR;" ARROWS" 1520 PRINT TAB 0;"ARE YOU GOING BACK IN?",,,,, 1525 INPUT F$ 1530 IF F$="NO" THEN PRINT "YOU SCORED ";S+TR 1535 IF F$="NO" THEN STOP 1540 LET S=S+TR 1545 LET TR=0 1550 PRINT "HOW MANY ARROWS DO YOU WANT?",,, 1560 PRINT "THEY ARE 4 POINTS EACH",,, 1570 INPUT F 1580 IF F*4>S THEN GOTO 1650 1590 LET S=S-F*4 1600 LET ARR=ARR+F 1610 GOTO 1342 1650 CLS 1655 PRINT " YOU CAN""T AFFORD THEM",,, 1660 GOTO 1550 2005 CLS 2010 PRINT AT 5,1;"UNFORTUNATELY YOU HAVE PERISHED" 2015 PRINT AT 8,1;"YOU SCORED ";S+TR 2018 PRINT 2019 PRINT 2020 IF S+TR<50+PS THEN STOP 2025 LET S=S-15 2028 LET PS=S+TR 2029 PRINT "YOU PLAYED WELL.",,, 2030 PRINT "I SHALL DEDUCT 15" 2031 PRINT 2032 PRINT "FOR DAMAGE TO THE BODY"; 2033 PRINT 2034 PRINT 2035 PRINT "YOU MAY CONTINUE"; 2036 FOR I=1 TO 50 2037 NEXT I 2038 CLS 2040 GOTO 1505 2050 PRINT AT 0,0; 2052 CLS 2055 FOR I=-10 TO 10 2058 LET AI=ABS I 2060 PRINT TAB 0;C$( TO AI); 2065 PRINT TAB (30-AI);C$( TO AI) 2070 NEXT I 2075 PRINT AT 0,10;C$( TO 10) 2080 PRINT AT 20,10;C$( TO 10) 2085 PRINT AT 10,0;"% ";TAB 29;"##" 2086 LET DEM=1 2087 LET QW=INT (RND*4) 2090 FOR I=1 TO QW+1 2095 PRINT AT 12+I,12+(RND*2);"***"; 2100 NEXT I 2105 LET N=10 2106 LET MY=-1 2107 LET MX=0 2108 LET K=18 2109 LET J=7 2110 LET M=2 2111 LET FX=J 2112 LET FY=K 2115 GOTO 265 3000 IF PEEK (Q+33*(K+MY)+J+MX)=0 THEN GOTO 3015 3002 LET AD=MY 3005 IF AD=0 THEN LET MY=MX 3006 IF AD=0 THEN LET MX=0 3007 IF AD<>0 THEN LET MY=0 3008 IF AD<>0 THEN LET MX=-AD 3015 LET J=J+MX 3020 LET K=K+MY 3025 PRINT AT K,J;"'."; 3030 IF RND>.5 THEN PRINT AT FY,FX;"'." 3032 IF RND<.25 THEN GOSUB 1200 3035 RETURN ```