--- title: "Caverns" id: 55060 type: "computer_media" slug: "caverns" url: "http://localhost/computer_media/caverns/" markdown_url: "http://localhost/computer_media/caverns.md" published_at: "2024-06-14T01:24:05+00:00" modified_at: "2026-04-03T07:59:08+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "Navigate a 416-cell string-encoded cavern, collect the Power-Sword and treasure, battle randomized monsters with improving odds, and face a guardian dragon at the exit." 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: "Wesley Weeks" slug: "wesley-weeks" taxonomy: "indiv" url: "http://localhost/indiv/wesley-weeks/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Program" programmers: - name: "Wesley Weeks" slug: "wesley-weeks" taxonomy: "indiv" url: "http://localhost/indiv/wesley-weeks/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Caverns%20%281983%29%28Weeks%2C%20Wesley%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "1983" media_type_tags: "Game" --- Caverns is a text-based maze adventure game in which the player navigates a 416-cell grid (stored as a single string) searching for the Power-Sword, treasure, and the exit while fighting randomly selected monsters. The map is represented as a flat string `L$` built by concatenating sub-strings `Z$` through `K$`, with cell contents encoded as single characters (e.g., `CHR$ 128` for walls, `CHR$ 0` for open passages, and letters for special locations). Combat uses a percentage-based random system where the player’s survival chance (`PER`) starts at 70 and increases by 5 with each victory, and holding the Power-Sword raises the chance to 95. The game supports saving progress to tape mid-session, and the final boss is a dragon that can only be fought if the player has obtained the Power-Sword. *** ## Program Analysis ### Program Structure The program is organized into a main game loop beginning around line 570, with subroutines handling movement, combat, and display. Lines 20–55 initialize game state and build the map; lines 240–500 display the introduction and instructions; lines 570–1270 form the core movement/input loop; lines 1270–3490 handle cell-event dispatch; lines 5000–5210 handle generic monster combat; lines 5250–7000 handle the dragon endgame; and lines 8000–8180 provide an alternative title-screen entry point. Line 9000 is an isolated SAVE line that serves as a tape-save entry. ### Map Representation The entire cavern is stored as a single string `L$` of 416 characters, constructed at line 41 by concatenating twelve sub-strings (`Z$` through `K$`, bookended by two `Z$` copies). This string acts as a flat 2D grid with a row width of 32 characters, so moving north/south adjusts the position pointer `P` by ±32, and moving east/west adjusts it by ±1. Cell contents are encoded as single characters: - `CHR$ 128` — wall (originally `"X"` in the source data, converted at lines 53–54) - `CHR$ 0` — open passage (originally `"."`) - `" "` — empty traversable space where items can be placed - Various letters (`A`–`O`, `S`, etc.) — special locations and items Lines 52–55 scan the whole map string and convert `"X"` to `CHR$ 128` and `"."` to `CHR$ 0`, likely because these two characters need a representation that avoids clashing with keyboard input characters. ### Cell Event Dispatch After every move, lines 1270–1440 check `L$(P)` against a table of known cell types and GOTO the corresponding handler. The mapping is: | Cell Value | Event | Handler Line | | --- | --- | --- | | `"A"` | Pit trap | 1450 | | `"S"` | Power-Sword found | 2370 | | `"B"` | Gas room | 1690 | | `"C"` | $50,000 treasure | 1820 | | `"D"` | Secret passage | 1910 | | `"E"` | Unseen force (moves player) | 1990 | | `"F"` | Thief (halves treasure) | 2100 | | `"H"` | Cave-in | 2420 | | `"I"` | $150,000 treasure | 2510 | | `"J"` | Monster encounter | 2550 | | `"K"` | Teleport to entrance | 2600 | | `"L"` | $500,000 treasure | 2730 | | `"M"` | Dragon / exit | 5250 | | `"O"` | Victory (reached exit) | 2830 | | `CHR$ 128` | Wall — can’t go this way | 2870 | | `CHR$ 0` | Open passage | 3390 | ### Combat System Generic monster combat is handled by the subroutine at line 5000. A random monster name is selected using the string-AND idiom (line 5010), and a random number `F` (1–100) is compared to `PER` (starting at 70). If `F < PER` the player wins; otherwise they die. Each victory raises `PER` by 5 (capped at 99), creating a leveling system. Holding the Power-Sword (`S=1`) overrides `PER` to 95 for all non-dragon fights. The dragon fight (lines 6000–7000) is separate: without the Power-Sword the player dies immediately. With the sword, the combat probability is recalculated as `50 + INT(PER/2)`, giving a harder fight than ordinary monsters. ### Random Item Placement At lines 60–120 the player start position and 10 item positions are chosen randomly from empty cells (`" "`) in `L$`. Items 1–4 are monsters (`"J"`), items 5–6 are cave-ins (`"C"` — noting this is a naming collision; the dispatch table at line 1290 sends `"C"` to the $50,000 treasure handler, not cave-in), items 7–8 are teleporters (`"K"`), and items 9–10 are thieves (`"F"`). The sword start position is hard-coded at `L$(192)` (line 46) and the exit at `L$(257)` (line 45). ### Key BASIC Idioms - **String-AND selection**: Lines 110 and 5010 use `("STRING" AND condition)` to select one of several string values based on a boolean condition, a common ZX81/TS1000 technique for avoiding IF chains. - **SCROLL-based display**: Rather than CLS, the game uses repeated `SCROLL` calls (subroutine at 3500 issues three SCROLLs) to push old text off screen, keeping the display tidy within the limited screen area. - **Flat string as 2D array**: Using a single string as a 2D map with arithmetic indexing is a well-known memory-saving idiom, avoiding the need for a two-dimensional array. - **PAUSE 40000** at line 370 serves as a long wait for keypress (effectively indefinite on this hardware). ### Bugs and Anomalies - **Line 1450 is missing**: The dispatch at line 1270 sends cell `"A"` to line 1450, but the pit handler code starts at line 1460. The GOTO 1450 will find line 1460 as the next executable line, so this works correctly in practice. - **Line 1690 is missing**: Similarly, cell `"B"` (gas room) dispatches to line 1690, but the handler begins at line 1700. Same next-line behavior applies. - **Lines 2470–2480** (cave-in handler): `LET L=L$(126)=CHR$ 128` uses chained assignment syntax that sets `L$(126)` to `CHR$ 128` and assigns the boolean result (0 or 1) to a numeric variable `L`. This is intentional for the side effect of modifying the map, but the variable `L` is unused. - **Line 1530**: `LET T=T-T` is a roundabout way of writing `LET T=0`; it zeroes the treasure counter after falling in a pit. - **Line 5080**: `LET PER=(PER+5)+(PER<99)` — the boolean `(PER<99)` adds 1 if PER is below 99, so the total increment is 6 when PER < 99 and 5 otherwise. This means PER can reach 100, bypassing the intended 99 cap. - **Lines 2551 and 2560**: The monster encounter handler at line 2550 dispatches to line 2551 (GOSUB 5000) rather than the label line 2550 itself, and line 2565 checks `IF D THEN` but `D` is never initialized before first use, relying on the default value of 0. - **Line 2410** returns to line 570 after finding the sword, which resets the facing direction display but does not re-enter the map at a new position — this is correct behavior. - **Lines 8000–8180** form an alternative entry point that is never called from within the main game flow; they appear to be an earlier version of the intro screen, reachable only by direct RUN or line-number entry. ## Source Code ``` 0# COPYRIGHT 1983 ORIGINAL PROGRAMS 1 REM ********CAVERNS******** 2 REM ****BY [W][E][S][L][E][Y]█[W][E][E][K][S]**** 3 REM AND STEVE 4 REM COPYRIGHT 1983 5 REM ORIGINAL PROGRAMS 20 LET PER=70 30 LET S=0 35 LET T=0 40 FAST 41 LET L$=Z$+A$+B$+C$+D$+E$+F$+G$+H$+I$+J$+K$+Z$ 45 LET L$(257)="O" 46 LET L$(192)="I" 52 FOR N=1 TO 416 53 IF L$(N)="X" THEN LET L$(N)=CHR$ 128 54 IF L$(N)="." THEN LET L$(N)=CHR$ 0 55 NEXT N 60 LET I=INT (RND*416+1) 65 IF L$(I)<>" " THEN GOTO 60 70 LET L$(I)="S" 80 FOR I=1 TO 10 90 LET J=INT (RND*416+1) 100 IF L$(J)<>" " THEN GOTO 90 110 LET L$(J)=("J" AND I<=4)+("C" AND (I=5 OR I=6))+("K" AND (I=7 OR I=8))+("F" AND (I=9 OR I=10)) 120 NEXT I 240 CLS 250 PRINT TAB 6;"WELCOME TO CAVERNS" 260 PRINT TAB 4;"THE ULTIMATE ADVENTURE" 270 PRINT ,," YOU MUST TRY TO FIND THE EXIT" 280 PRINT "OUT OF THIS DREADFUL PLACE." 290 PRINT "BUT, BE CAREFUL, MONSTERS LURK" 300 PRINT "EVERYWHERE, AND THE EXIT IS PRO-" 310 PRINT "TECTED BY A BEAST TOO POWERFUL" 320 PRINT "FOR A MAN TO KILL WITHOUT THE" 330 PRINT "POWER-SWORD, SO IT MUST BE FOUND" 340 PRINT "BEFORE YOU LEAVE. THE SWORD WILL" 345 PRINT "ALSO INCREASE YOUR CHANCES OF" 347 PRINT "KILLING THE OTHER MONSTERS." 350 PRINT " THERE IS TREASURE EVERYWHERE" 352 PRINT "SO YOU COULD END UP A VERY RICH" 354 PRINT "PERSON." 360 PRINT ,,TAB 10;"GOOD LUCK" 365 PRINT ,," TOUCH ANY KEY TO START" 370 PAUSE 40000 380 CLS 410 PRINT ,,"USE THESE KEYS TO MOVE:" 420 PRINT ,,"(F)=FORWARD" 430 PRINT "(B)=BACKWARD" 440 PRINT "(L)=LEFT" 450 PRINT "(R)=RIGHT" 460 PRINT "(S)=SAVE GAME" 470 PRINT ,,"WHEN YOU SAVE THE GAME, YOU" 480 PRINT "START IN THE SAME POSITION YOU" 490 PRINT "LEFT THE NEXT TIME YOU PLAY." 500 PAUSE 1000 530 PRINT ,,"YOU HAVE ENTERED THE CAVERNS..." 540 LET P$="W" 550 LET M=0 555 LET S=0 560 LET P=192 570 SCROLL 580 PRINT "YOU ARE FACING:";P$ 590 SCROLL 600 SLOW 610 LET M=M+1 620 SCROLL 630 PRINT "WHICH DIRECTION?" 635 SCROLL 640 PRINT "(F)-(B)-(L)-(R)-(S)" 645 GOSUB 3500 650 LET M$=INKEY$ 655 IF M$="" THEN GOTO 650 680 IF M$<>"F" THEN GOTO 730 690 IF P$="N" THEN GOSUB 1190 700 IF P$="E" THEN GOSUB 1230 710 IF P$="S" THEN GOSUB 1210 720 IF P$="W" THEN GOSUB 1250 725 GOTO 1270 730 IF M$<>"B" THEN GOTO 780 740 IF P$="N" THEN GOSUB 1210 750 IF P$="E" THEN GOSUB 1250 760 IF P$="S" THEN GOSUB 1190 770 IF P$="W" THEN GOSUB 1230 775 GOTO 1270 780 IF M$<>"L" THEN GOTO 950 790 IF P$<>"N" THEN GOTO 830 800 LET P$="W" 810 GOSUB 1250 815 GOTO 1270 830 IF P$<>"E" THEN GOTO 870 840 LET P$="N" 850 GOSUB 1190 855 GOTO 1270 870 IF P$<>"S" THEN GOTO 910 880 LET P$="E" 890 GOSUB 1230 895 GOTO 1270 910 IF P$<>"W" THEN GOTO 950 920 LET P$="S" 930 GOSUB 1210 940 GOTO 1270 950 IF M$<>"R" THEN GOTO 1120 960 IF P$<>"N" THEN GOTO 1000 970 LET P$="E" 980 GOSUB 1230 990 GOTO 1270 1000 IF P$<>"E" THEN GOTO 1040 1010 LET P$="S" 1020 GOSUB 1210 1030 GOTO 1270 1040 IF P$<>"S" THEN GOTO 1080 1050 LET P$="W" 1060 GOSUB 1250 1070 GOTO 1270 1080 IF P$<>"W" THEN GOTO 1180 1090 LET P$="N" 1100 GOSUB 1190 1110 GOTO 1270 1120 SCROLL 1130 PRINT "PUT TAPE IN RECORDER, PRESS RE-" 1131 SCROLL 1132 PRINT "CORD AND THEN PRESS ENTER (N/L)." 1140 GOSUB 3500 1160 IF INKEY$ <>CHR$ 118 THEN GOTO 1160 1170 SAVE "CAVERNS" 1180 GOTO 570 1190 LET P=P-32 1200 RETURN 1210 LET P=P+32 1220 RETURN 1230 LET P=P+1 1240 RETURN 1250 LET P=P-1 1260 RETURN 1270 IF L$(P)="A" THEN GOTO 1450 1275 IF L$(P)="S" THEN GOTO 2370 1280 IF L$(P)="B" THEN GOTO 1690 1290 IF L$(P)="C" THEN GOTO 1820 1300 IF L$(P)="D" THEN GOTO 1910 1310 IF L$(P)="E" THEN GOTO 1990 1320 IF L$(P)="F" THEN GOTO 2100 1340 IF L$(P)="H" THEN GOTO 2420 1350 IF L$(P)="I" THEN GOTO 2510 1360 IF L$(P)="J" THEN GOTO 2550 1370 IF L$(P)="K" THEN GOTO 2600 1380 IF L$(P)="O" THEN GOTO 2830 1390 IF L$(P)="L" THEN GOTO 2730 1395 IF L$(P)="M" THEN GOTO 5250 1420 IF L$(P)=CHR$ 128 THEN GOTO 2870 1430 IF L$(P)=CHR$ 0 THEN GOTO 3390 1440 STOP 1460 SCROLL 1470 PRINT "YOU HAVE FALLEN INTO A PIT." 1480 SCROLL 1490 PRINT "IN GETTING OUT YOU LOST YOUR" 1500 SCROLL 1510 PRINT "TREASURE." 1520 SCROLL 1530 LET T=T-T 1540 GOSUB 3500 1680 GOTO 570 1700 SCROLL 1710 PRINT "YOU HAVE ENTERED A ROOM OF GAS." 1715 SCROLL 1720 PRINT "WHEN THE GAS CLEARS YOUR POSI-" 1730 SCROLL 1740 PRINT "TION IN THE CAVERN IS DIFFERENT." 1770 GOSUB 3500 1800 LET P=P+32 1810 GOTO 1270 1830 SCROLL 1840 PRINT "YOU FOUND A TREASURE OF " 1850 SCROLL 1860 PRINT "** ** $50,000 ** **" 1870 LET T=T+50000 1875 LET P=P+32 1890 GOSUB 3500 1900 GOTO 1270 1920 SCROLL 1930 PRINT "YOU HAVE FOUND A SECRET PASSAGE" 1940 SCROLL 1950 PRINT "THAT GETS YOU CLOSER TO THE" 1951 SCROLL 1952 PRINT "EXIT." 1960 SCROLL 1970 LET P=P-7 1980 GOTO 1270 2000 SCROLL 2010 PRINT "AN UNSEEN FORCE HAS MOVED YOU" 2015 SCROLL 2020 PRINT "CLOSER TO THE ENTRANCE." 2030 GOSUB 3500 2080 LET P=P+5 2090 GOTO 1270 2110 SCROLL 2120 PRINT "A THIEF STOLE HALF OF YOUR" 2130 SCROLL 2140 PRINT "TREASURE. YOU NOW HAVE :" 2150 SCROLL 2160 LET T=T-(INT (T/2)) 2170 PRINT "$";T 2180 GOSUB 3500 2210 GOTO 3390 2370 SCROLL 2380 PRINT " YOU HAVE FOUND THE POWER-SWORD." 2385 LET S=1 2390 GOSUB 3500 2410 GOTO 570 2430 SCROLL 2440 PRINT "THIS PART HAS CAVED IN." 2450 SCROLL 2470 LET L=L$(126)=CHR$ 128 2480 LET L=L$(217)=CHR$ 128 2490 SCROLL 2500 GOTO 2870 2520 GOSUB 3500 2530 PRINT "YOU FOUND A TREASURE WORTH :" 2535 SCROLL 2540 LET L$(P)=" " 2541 PRINT "** ** $150,000 ** **" 2542 LET T=T+150000 2543 LET P=P-1 2544 GOSUB 3500 2545 GOTO 1270 2551 GOSUB 5000 2560 SCROLL 2565 IF D THEN PRINT "TOO BAD. YOU LOSE. HA HA HA HA." 2566 IF NOT D THEN GOTO 570 2570 GOSUB 3500 2571 PRINT "PLAY AGAIN?" 2572 IF INKEY$ ="" THEN GOTO 2572 2573 IF INKEY$ ="Y" THEN GOTO 1 2580 STOP 2610 SCROLL 2620 PRINT "YOU WERE TELEPORTED TO THE" 2630 SCROLL 2640 PRINT "ENTRANCE, TOO BAD." 2650 SCROLL 2660 LET P=160 2670 LET P$="W" 2720 GOTO 570 2740 SCROLL 2750 PRINT "YOU HAVE FOUND A TREASURE WORTH:" 2760 SCROLL 2770 PRINT "** ** $500,000 ** **" 2780 GOSUB 3500 2800 LET T=T+500000 2805 LET L$(P)=" " 2810 LET P=P+1 2820 GOTO 1270 2830 CLS 2840 PRINT AT 10,5;"YOU MADE IT, AND YOU HAVE : " 2850 PRINT TAB 10;"$";T 2865 GOTO 2571 2880 SCROLL 2890 PRINT "YOU CAN""T GO THIS WAY." 2900 IF M$<>"F" THEN GOTO 2950 2910 IF P$="N" THEN GOSUB 1210 2920 IF P$="E" THEN GOSUB 1250 2930 IF P$="S" THEN GOSUB 1190 2940 IF P$="W" THEN GOSUB 1230 2950 IF M$<>"B" THEN GOTO 3000 2960 IF P$="N" THEN GOSUB 1190 2970 IF P$="E" THEN GOSUB 1230 2980 IF P$="S" THEN GOSUB 1210 2990 IF P$="W" THEN GOSUB 1250 3000 IF M$<>"L" THEN GOTO 3170 3010 IF P$<>"N" THEN GOTO 3050 3020 GOSUB 1210 3030 LET P$="E" 3040 GOTO 3340 3050 IF P$<>"E" THEN GOTO 3090 3060 GOSUB 1250 3070 LET P$="S" 3080 GOTO 3340 3090 IF P$<>"S" THEN GOTO 3130 3100 LET P$="W" 3110 GOSUB 1190 3120 GOTO 3340 3130 IF P$<>"W" THEN GOTO 3170 3140 LET P$="N" 3150 GOSUB 1230 3160 GOTO 3340 3170 IF M$<>"R" THEN GOTO 3340 3180 IF P$<>"N" THEN GOTO 3220 3190 LET P$="W" 3200 GOSUB 1210 3210 GOTO 3340 3220 IF P$<>"E" THEN GOTO 3260 3230 LET P$="N" 3240 GOSUB 1250 3250 GOTO 3340 3260 IF P$<>"S" THEN GOTO 3300 3270 LET P$="E" 3280 GOSUB 1190 3290 GOTO 3340 3300 IF P$<>"W" THEN GOTO 3340 3310 LET P$="S" 3320 GOSUB 1230 3340 GOSUB 3500 3380 GOTO 570 3400 SCROLL 3410 PRINT "ALL IS CLEAR." 3420 GOSUB 3500 3440 PRINT "LAST MOVE : ";M$ 3450 GOSUB 3500 3490 GOTO 570 3500 SCROLL 3505 SCROLL 3510 SCROLL 3515 RETURN 5000 LET M=INT (RND*5+1) 5010 LET M$=("WEREWOLF" AND M=1)+("VAMPIRE" AND M=2)+("MUMMY" AND M=3)+("ZOMBIE" AND M=4)+("GHOUL" AND M=5) 5020 SCROLL 5030 PRINT "YOU HAVE TO FIGHT A ";M$;"." 5040 SCROLL 5060 LET F=INT (RND*100+1) 5061 FOR I=1 TO 30 5062 NEXT I 5063 SCROLL 5065 SCROLL 5066 IF S THEN LET PER=95 5070 IF FF THEN GOTO 7000 6035 SCROLL 6040 PRINT "THE DRAGON ATE YOU, TOO BAD." 6042 SCROLL 6045 PRINT "[H][A] HA [H][A] HA [H][A] HA [H][A] HA [H][A] HA [H][A]" 6050 GOTO 2571 7000 CLS 7010 PRINT TAB 8;"CONGRATULATIONS..." 7020 PRINT "YOU HAVE KILLED THE DRAGON." 7030 GOTO 2840 8000 PRINT TAB 10;"CAVERNS" 8010 PRINT ,," IN THIS FAST MOVING ADVENTURE" 8020 PRINT "GAME, YOU ARE IN A MAZE THAT IS" 8030 PRINT "FULL OF MONSTERS, PITS, STRANGE" 8040 PRINT "GAS, AND THE POWER-SWORD. ALL" 8050 PRINT "YOU KNOW OF THIS MAZE IS THAT IT" 8060 PRINT "IS DANGEROUS. AT FIRST IT IS" 8070 PRINT "DIFFICULT, BUT AS YOU FIGHT YOUR" 8080 PRINT "EXPERIENCE INCREASES MAKING IT" 8090 PRINT "EASIER. THE COMPUTER WILL TELL" 8100 PRINT "YOU THE DIRECTION YOU ARE FACING" 8110 PRINT "AND THE LAST MOVE YOU MADE. THE" 8120 PRINT "REST IS UP TO YOU. GOOD LUCK." 8130 PRINT ,," TOUCH ANY KEY TO START." 8150 IF INKEY$ ="" THEN GOTO 8150 8160 PRINT ,,TAB 8;"SETTING UP" 8170 PAUSE 150 8180 GOTO 1 9000 SAVE "CAVERN[S]" 9010 SLOW 9020 GOTO 8000 ```