Dormirians

Date: 198x
Type: Cassette
Platform(s): TS 2068

This is a science-fiction text adventure in which the player navigates a network of rooms to collect letters that spell a five-letter code word, then guesses the code before a countdown timer expires. Each playthrough randomizes the target code word from one of five pre-encoded choices stored in a DATA string. Navigation directions and room connections are packed into parallel string arrays read from DATA, with each room’s exits encoded as single characters and destinations as ASCII-offset letters. A centered-text subroutine at line 3000 handles word-wrapping for messages shorter and longer than 32 characters. The game uses the TS2068’s SOUND and BORDER commands for audio-visual effects including a ticking alarm when time runs low.


Program Analysis

Program Structure

The program is organized into a main game loop, two subroutines, and DATA blocks. Execution flows as follows:

  1. Lines 10–30: Initialize LC (last code) and read all data strings into R$, L$, C$, U$, S$, N$.
  2. Lines 60–80: Set up a new game — choose a random code index C, reset ROOM, move counter MC, and timer TM.
  3. Lines 110–350: Main navigation loop — display room info, available exits, collect letters, accept movement keypresses, and decrement the timer.
  4. Lines 360–390: Guess phase — triggered after visiting at least 3 rooms (MC>2), accepts INPUT and checks against the target word.
  5. Lines 400–450 / 460–570: Win and lose branches, with a replay prompt.
  6. Lines 1000–1010: Sound effect subroutine using BEEP and SOUND.
  7. Lines 3000–3020: Centered/word-wrapped text display subroutine.
  8. Lines 4000–4040: DATA records encoding all room, letter, code, and hint information.

Data Encoding

All game content is packed into six strings read from DATA at line 30. Their roles are:

VariableDATA lineContent
R$400054-character string; each room occupies 4 characters giving N/S/E/W exits or * for no exit
L$401054-character string; destination room encoded as ASCII letter (A=room 1, B=room 2, …)
C$402025-character string; five 5-letter code words concatenated (NIMRON, IMOR, MINOR, IRON, NIROM…)
U$4020 (second field)13-character string; for each room, an ASCII-offset letter giving the number of clue letters available (A=0 means no letter)
S$4030Caesar-cipher hint string (each character shifted +1 from the intended message)
N$4040Room name string, three characters per room

The code word is selected by C=(INT(RND*5)+1)*5-4, yielding values 1, 6, 11, 16, or 21 — the starting index of each 5-letter word in C$.

Room Navigation Logic

With 13 rooms inferred from U$‘s length, each room’s four directional exits occupy positions ROOM*4-3 TO ROOM*4 in R$. An exit of * is treated as impassable. On a valid keypress, line 310 looks up the destination by decoding CODE L$(X)-65 to get the target room number. The clue letter for a room is fetched at line 150 via T=C+NR-1, where NR=CODE(U$(ROOM))-65; a value less than 1 means the room has no letter to give.

Timer and Urgency Mechanics

The timer TM starts at 240 (notionally seconds) and is decremented continuously. Line 230 decrements it by 1 per display loop iteration. Movement costs 0.55 units (line 320), and failed movement attempts cost an additional 1.1 units (line 350). When TM<15, lines 250–260 trigger a rapid BEEP-and-BORDER flash loop, further consuming time, creating genuine urgency. If TM reaches zero, the player loses via line 460.

The countdown is displayed at AT 17,4 in MM:SS format. Line 240 pads seconds below 10 with a leading zero using string concatenation — a standard BASIC idiom.

Centered Text Subroutine (Lines 3000–3020)

The subroutine at line 3000 centers and word-wraps all game messages stored in M$. If LEN M$<32, it prints centered using TAB ((32-LEN(M$))/2+.6) — the +.6 corrects for integer truncation bias. If the string is 32 characters or longer, it scans backward from position 32 to find the last space (line 3010), prints the first segment centered, strips it from M$, and recurses via GO TO 3000. This makes the subroutine a tail-recursive word-wrapper implemented with a GO TO.

Caesar Cipher Hint

Lines 560–570 decode the hint stored in S$: each character has its CODE decremented by 1, reversing a Caesar shift of +1 applied when the data was written. This produces the hint text “COUNT THE WAYS EACH NATIVE DIFFERS FROM THE KING”. The decoded string is built into M$ and displayed, then the code loops back to start a new game.

Sound Effects

The subroutine at lines 1000–1010 plays a win/lose fanfare. It uses BEEP for 69 rapid tones followed by the TS2068-specific SOUND command for a descending sweep — SOUND 0,X in a loop from 255 to 0 creates a falling pitch effect. The final SOUND 8,0;7,63 resets the sound chip.

Anti-Repeat Guard

Line 70 uses IF C=LC THEN GO TO 20 to re-roll the code word if the same one was just used, preventing immediate repetition. Since line 20 does not exist, this is a deliberate technique: on the ZX Spectrum/TS2068, a GO TO to a non-existent line searches forward and wraps, which in this context effectively re-executes the randomization at line 60. The variable LC (last code) is set at line 80 only after a new unique code is confirmed.

Notable Idioms and Anomalies

  • Line 220 polls INKEY$ in a busy loop, decreasing TM on each iteration — this doubles as both input handler and timer engine.
  • CHR$ 34 is used at line 210 to embed a literal quote character inside a PRINT string, the standard workaround for the lack of escaped quotes in Sinclair BASIC.
  • Line 560 has a bare :: after the string assignment — this is a null statement separator used to separate the LET M$="" from the FOR loop, harmlessly executed as an empty statement.
  • Line 70 sets TM=240 before the anti-repeat check, so the timer is reset regardless — the guard only re-randomizes C.
  • The PAUSE 60 at line 280 before looping back to the keypress poll introduces an approximately one-second delay between timer display updates, roughly calibrating the countdown to real seconds.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

Source Code

   10 LET LC=0
   30 READ R$: READ L$: READ C$: READ U$: READ S$: READ N$
   60 LET C=(INT (RND*5)+1)*5-4: LET ROOM=1: LET MC=0
   70 LET TM=240: IF C=LC THEN GO TO 20
   80 CLS : LET LC=C: LET M$="I AM THE MASTER, THE PROTOTYPE."
   90 LET M$=M$+"ATTEND TO ME AND YOU WILL FIND WHAT YOU SEEK.": GO SUB 3000
  110 LET NR=CODE (U$(ROOM))-65: LET T=C+NR-1
  120 IF MC>0 THEN CLS 
  130 IF NR<1 THEN GO TO 160
  140 LET M$="I AM "+N$(ROOM*3-5 TO ROOM*3-3)+",": GO SUB 3000
  150 LET M$="AND THE LETTER I GIVE YOU IS *"+C$(T)+"*.": GO SUB 3000
  160 PRINT : PRINT : LET M$="YOU CAN MOVE IN THESE DIRECTIONS:": GO SUB 3000: PRINT : PRINT 
  170 LET M$=" ": FOR X=ROOM*4-3 TO ROOM*4
  180 IF R$(X)<>"*" THEN LET M$=M$+R$(X)+" "
  190 NEXT X: GO SUB 3000: PRINT : PRINT 
  200 IF MC<3 THEN LET M$="CHOOSE ONE:": GO SUB 3000: GO TO 220
  210 LET M$="CHOOSE ONE, OR PRESS "+CHR$ 34+"G"+CHR$ 34+" TO GUESS:": GO SUB 3000
  220 LET K=CODE INKEY$: IF K<>0 THEN GO TO 290
  230 LET TM=TM-1: LET T1=INT (TM/60)
  240 LET T2=INT (TM-T1*60): LET T$=STR$ T2: IF T2<10 THEN LET T$="0"+T$
  250 IF TM<15 THEN FOR I=1 TO 8: BEEP .011,34: BORDER (I-1): NEXT I: LET TM=TM-1
  260 IF TM<1 THEN GO TO 460
  280 PRINT AT 17,4;: LET M$="<TIME TO DEPARTURE>  "+STR$ T1+":"+T$: GO SUB 3000: PAUSE 60: GO TO 220
  290 LET G$=CHR$ K: IF G$="G" AND MC>2 THEN GO TO 360
  300 LET T=0: FOR X=ROOM*4-3 TO ROOM*4
  310 IF G$=R$(X) THEN LET ROOM=CODE L$(X)-65: LET T=1: LET MC=MC+1
  320 NEXT X: LET TM=TM-.55
  330 IF T<>0 THEN GO TO 110
  340 PRINT : LET M$="YOU CAN'T GET THERE FROM HERE!": GO SUB 3000
  350 FOR X=1 TO 345: NEXT X: CLS : LET TM=TM-1.1: GO TO 110
  360 CLS : LET M$="TYPE IN YOUR GUESS:": GO SUB 3000
  370 LET M$="THEN PRESS <RETURN>.": GO SUB 3000: PRINT : PRINT 
  380 INPUT G$: IF G$<>C$(C TO C+4) THEN GO TO 480
  390 CLS : LET M$="CONGRATULATIONS ... YOU MADE IT!": GO SUB 3000: PRINT 
  400 LET M$="ALL ABOARD.": GO SUB 3000: GO SUB 1000
  420 PRINT : PRINT : LET M$="DO YOU WANT TO PLAY AGAIN?": GO SUB 3000: PAUSE 0
  430 LET A$=INKEY$
  440 IF A$="Y" THEN GO TO 60
  450 STOP 
  460 CLS : LET M$="THE SHUTTLE HAS DEPARTED.": GO SUB 3000:
  470 LET M$="YOU ARE STUCK ON DORMIR UNTIL NEXT WEEK.": GO TO 500
  480 CLS : LET M$="NOPE!  YOUR SHIP LEFT WITHOUT YOU.": GO SUB 3000
  490 PRINT : LET M$="YOU WILL HAVE TO WAIT UNTIL NEXT WEEK."
  500 GO SUB 3000: GO SUB 1000
  510 PRINT : PRINT : PRINT "DO YOU WANT TO ...": PRINT " GET <H>ELP;"
  520 PRINT "<P>LAY AGAIN; OR": PRINT "<Q>UIT?"
  530 PAUSE 0: LET A$=INKEY$
  540 IF A$="Q" THEN CLS : STOP 
  550 IF A$="H" THEN GO TO 60
  560 PRINT : LET M$="":: FOR X=1 TO 48: LET M$=M$+CHR$ (CODE (S$(X))-1): NEXT X
  570 LET M$=N$+".": GO SUB 3000: FOR I=1 TO 345: NEXT I: GO TO 60
 1000 FOR X=1 TO 69: BEEP .01,33: NEXT X: SOUND 7,62;8,15
 1010 FOR X=255 TO 0 STEP -1: SOUND 0,X: NEXT X: SOUND 8,0;7,63: RETURN 
 3000 IF LEN M$<32 THEN PRINT TAB ((32-LEN (M$))/2+.6);M$: RETURN 
 3010 LET L=31: FOR I=2 TO 32: IF M$(I)=" " THEN LET L=I-1
 3020 NEXT I: PRINT TAB (32-L)/2;M$( TO L): LET M$=M$(L+2 TO ): GO TO 3000
 4000 DATA "NSEW*SE**SEW*S*WNSE*NSEWNS*WN*E*NSEW*S*WN*E*N*EWN**W"
 4010 DATA "GLJIAFDAAGECAHADCIGADBHFEJAGFABAHMKBANAJBAMAJANLKAAM"
 4020 DATA "NIMRONIMORMINORMIRONNIROM","ADBEBCBCCBBBF"
 4030 DATA "DPVOU!UIF!XBZT!FBDI!OBUJWF!EJGGFST!GSPN!UIF!LJOH"
 4040 DATA "MOXVOVTRIIMODIZKAKCEEZUUOOLUTOEEXJOL"

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

People

No people associated with this content.

Scroll to Top