Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_SRC_3_19910112
-
utilities/cave.mac
There are no other files named cave.mac in the archive.
TITLE CAVE ANOTHER GAME TO EXPLORE DUNGEONS
SUBTTL COMMENTS/DAVID I. BELL/DZN
;THIS IS A PSEUDO-DUNGEON CAVE EXPLORATION PROGRAM. THIS IS MUCH
;SIMPLER THAN ALL THE VARIOUS DUNGEON PROGRAMS NOW IN EXISTANCE.
;HOWEVER, THERE ARE THREE BIG FEATURES IN THIS PARTICULAR PROGRAM,
;WHICH IS THE MAJOR REASON FOR WRITING IT. THESE ARE:
;
;1. PLAYERS WILL COMPETE AGAINST EACH OTHER IN EXPLORING THE
; DUNGEON, KILLING MONSTERS, AND COLLECTING TREASURE.
; THE PROGRAM WILL BE ABLE TO LIST THE PLAYERS AND THEIR
; ACCOMPLISHMENTS.
;
;2. THE DUNGEON IS DYNAMICALLY ALLOCATED AS THE PLAYERS EXPLORE
; NEW PATHS. THUS NOBODY WILL EVER BE ABLE TO COMPLETELY MAP
; THE DUNGEON, SINCE IT GROWS FOREVER. THIS MEANS THAT NEW
; PLAYERS WILL HAVE A CHANCE TO DISCOVER NEW STUFF, AND THE
; OLD PLAYERS WON'T RUN OUT OF STUFF TO DO.
;
;3. LIKE THE REAL GAME OF DUNGEONS AND DRAGONS (WHICH I HAVE NEVER
; PLAYED), THIS DUNGEON CONSISTS OF MANY LEVELS, WHERE THE
; DEEPER THE LEVEL, THE TOUGHER THE MONSTERS ARE AND THE GREATER
; THE VALUE OF THE TREASURE YOU FIND. PLAYERS CAN ONLY GO TO THE
; DEEPER LEVELS AS THEY GAIN EXPERIENCE AT THE EASIER LEVELS.
SUBTTL DEFINITIONS
SEARCH MONSYM,MACSYM ;GET DEFINITIONS
SALL ;MAKE NICE LOOKING MACROS
;VERSION INFORMATION:
VMAJOR==1 ;MAJOR VERSION
VMINOR==0 ;MINOR VERSION
VEDIT==100 ;EDIT NUMBER
VWHO==4 ;WHO LAST EDITED
;ACCUMULATORS:
F=0 ;FLAGS
T1=1 ;TEMPORARY AC'S
T2=2
T3=3
T4=4
I=5 ;RANDOM INDEX
U=6 ;ADDRESS OF USER DATA
R=7 ;ADDRESS OF CURRENT ROOM DATA
S=10 ;ADDRESS OF NEW ROOM DATA
C=11 ;CHARACTER AC
ZR=12 ;AC USED FOR TESTING FOR ROOM ZERO
PL=13 ;LEVEL WE'RE PLOTTING
PR=14 ;ROOM WE'RE PLOTTING
P=17 ;STACK POINTER
;FLAG BITS IN AC F:
FR.GOD==1 ;WE ARE A PRIVILEGED PLAYER
FR.PLY==2 ;THE PLAY COMMAND HAS BEEN GIVEN
FR.BLD==4 ;COMMAND TABLE NEEDS TO BE REBUILT
FR.DEB==10 ;DEBUGGING INFORMATION IS TYPED OUT
FR.VRB==20 ;VERBOSE OUTPUT IS DESIRED
FR.VR2==40 ;VERBOSE OUTPUT DESIRED, BUT TEMPORARILY
FR.LCK==100 ;THE DATA FILE IS LOCKED
FR.FND==200 ;SOMETHING WAS FOUND IN THIS ROOM
FR.KIL==400 ;DEFAULT COMMAND IS TO BE "KILL"
FR.TMP==1000 ;TEMPORARY USE FOR LOOPS
FR.CRL==2000 ;CRLFS IN OUTPUT ARE REAL
FR.MAP==4000 ;THE DATA FILE IS OPENED AND MAPPED
INIFLG==FR.BLD!FR.VRB ;INITIAL FLAGS ON STARTUP
;OTHER DEFINITIONS:
GODUSR==20 ;USER WHICH IS GODLY BY DEFAULT
USRLH==500000 ;LEFT HALFS OF USER NUMBERS
HDRVER==3 ;VERSION OF THE DATA FILE
PLRMAX==^D100 ;NUMBER OF PLAYERS WHO CAN PLAY
PDLSIZ==30 ;STACK SIZE
TXTLEN==^D200 ;SIZE OF COMMAND BUFFERS
COLMIN==^D60 ;MINIMUM WIDTH OF TERMINAL
COLMAX==^D200 ;MAXIMUM WIDTH
TTYMAX==^D60 ;COLUMN WHEN CRLF IS TO BE DONE
PTHMAX==^D100 ;WORDS USED TO STORE PATH DEFINITIONS
PTHWID==4 ;NUMBER OF BITS NEEDED TO HOLD DIRECTIONS (AND 2 MORE)
WRDMAX==^D25 ;NUMBER OF MAGIC WORDS TO GENERATE
DEFMAX==^D100 ;NUMBER OF WORDS TO HOLD PATH DEFINITIONS
DEFWID==3 ;BITS USED TO A DIRECTION IN A PATH DEFINITIONS
ITMWID==3 ;NUMBER OF BITS TO HOLD ITEM COUNTS
SFPMAX==6 ;MAXIMUM SHIFT FOR NEW ROOM IN PRIMARY DIRECTION
SFPMIN==4 ;MINIMUM SHIFT IN PRIMARY DIRECTION
SFSMAX==1 ;MAXIMUM SHIFT IN SECONDARY DIRECTION
CONMAX==2 ;DISTANCE WHERE ROOMS WILL CONNECT
DIRMAX==4 ;NUMBER OF DIRECTIONS FROM A ROOM
PWRMAX==^D100 ;HIGHEST STRENGTH OF A PLAYER
MOVMAX==^D100 ;MAXIMUM NUMBER OF MOVES IN ONE TURN
TREMAX==^D50 ;HIGHEST TREASURE PER LEVEL PER STRENGTH UNIT
MID==^D100000 ;COORDINATE OF MIDDLE OF DUNGEON
MIN==^D50000 ;MINIMUM COORDINATE TO RANDOMLY SELECT FROM
MAPADR==100000 ;ADDRESS WHERE FILE STARTS BEING MAPPED
MAPLST==760000 ;LAST ADDRESS TO MAP
PAGSIZ==1000 ;SIZE OF A PAGE
PLTADR=MAPADR-PAGSIZ ;LOCATION OF PLOT BUFFER
PLTPAG==PLTADR/PAGSIZ ;PAGE NUMBER OF PLOT BUFFER
IWIDTH==^D29 ;INTEGER WIDTH OF PAPER
FWIDTH==29.0 ;FLOATING POINT "
ISTEPS==^D100 ;INTEGER STEPS PER INCH
FSTEPS==100.0 ;FLOATING POINT "
.JBUUO==40 ;LOCATION WHERE LUUOS ARE STORED
.JB41==41 ;LOCATION TO XCT ON AN LUUO
;PLOTTER COMMANDS
XY%UP==40 ;RAISE PEN COMMAND
XY%DWN==20 ;LOWER PEN COMMAND
XY%MX==10 ;-X INCREMENT
XY%PX==4 ;+X INCREMENT
XY%PY==2 ;+Y INCREMENT
XY%MY==1 ;-Y INCREMENT
;DERIVED QUANTITIES:
PLRWDS==<PLRMAX+^D35>/^D36 ;WORDS NEEDED FOR BIT TABLES
ITMMSK==<1_ITMWID>-1 ;MASK FOR ITEMS
PTHMSK==<1_PTHWID>-1 ;MASK FOR PATH DEFINITIONS
OPDEF STROUT [1B8] ;OUTPUT A STRING
OPDEF DECOUT [2B8] ;OUTPUT A DECIMAL NUMBER
OPDEF OCTOUT [3B8] ;OUTPUT AN OCTAL NUMBER
OPDEF DATOUT [4B8] ;OUTPUT A STANDARD DATE
OPDEF CHROUT [5B8] ;OUTPUT A SINGLE CHARACTER
OPDEF PUTCHR [CALL TTYOUT] ;OUTPUT A CHARACTER IN AC C
OPDEF DOCRLF [CALL TTYCRL] ;FORCE A CRLF NOW
SUBTTL MACROS
DEFINE CMMD(ARG),< ;;MACRO TO DO A GENERAL COMMAND
MOVEI T2,ARG
CALL DOCMMD
>
DEFINE NOISE(TEXT),< ;;MACRO FOR NOISE
MOVEI T2,[ASCIZ/TEXT/]
CALL DONOIS
>
DEFINE CONFRM,< ;;MACRO FOR CONFIRMING A LINE
CALL DOCNFM
>
DEFINE AA(NAME,ADDR,BITS<0>),< ;;STANDARD COMMAND TABLE MACRO
[ASCIZ/NAME/],,[BITS,,ADDR]
>
DEFINE AB(NAME,ADDR),< ;;MACRO FOR ABBREVIATIONS
[EXP CM%FW!CM%INV!CM%ABR
ASCIZ/NAME/],,ADDR
>
DEFINE AC(NAME,ADDR),< ;;THE NORMAL KEYWORD MACRO
[ASCIZ/NAME/],,ADDR
>
DEFINE TEXT(STRING),< ;;MACRO FOR ASCIZ TEXT
XLIST
ASCIZ @STRING@
LIST
>
DEFINE FATAL(TEXT),< ;;MACRO FOR FATAL ERRORS
CALL [HRROI T4,[ASCIZ/
? TEXT
/] ;;GET ERROR STRING
JRST DOFATL] ;;AND JUMP TO ERROR HANDLER
>
DEFINE ERROR(INST1,INST2,TEXT),< ;;MACRO FOR NORMAL ERRORS
CALL [ ;;GO TO ERROR CODE
IFB <TEXT>,< SETZM ERRTXT> ;;SAY NO MESSAGE
IFNB <TEXT>,< IFB <INST2>,<
MOVEI T1,[ASCIZ/
TEXT
/] ;;GET MESSAGE WITH CRLFS
>
IFNB <INST2>,<
MOVEI T1,[ASCIZ/
TEXT/] ;;OR MESSAGE WITH NO ENDING CRLF
>
>
MOVEM T1,ERRTXT ;;SAVE FOR LATER
DMOVE T1,[EXP <INST1>,<INST2>]
JRST DOERR] ;;GO TO ERROR
>
SUBTTL DATA FILE FORMAT
;ALL DATA ABOUT THE DUNGEON AND ITS PLAYERS IS KEPT IN ONE FILE
;WHICH IS KEPT MAPPED INTO CORE WHILE THE PROGRAM IS RUNNING.
;THE FILE IS OPENED IN THAWED MODE, SO THAT DATA IS ALWAYS CURRENT
;FOR ALL PLAYERS. AN INTERLOCK IS USED SO THAT ONLY ONE PLAYER
;AT A TIME CAN CHANGE THE FILE.
;
;THE FILE IS DIVIDED INTO THREE PARTS. THE FIRST PART IS THE HEADER
;AREA, WHICH DESCRIBES THE STATE OF THE DUNGEON AS A WHOLE. THE
;MIDDLE PART CONTAINS INFORMATION ON EACH PLAYER IN THE GAME. THE
;LAST PART CONTAINS INFORMATION ABOUT THE ROOMS OF THE DUNGEON. ONLY
;THE THIRD PART CAN GROW, SO THAT THERE IS A LIMIT ON THE NUMBER OF
;PLAYERS WHO CAN BE PLAYING.
DEFINE XX(NAME,SIZE<1>),< ;;MACRO TO DEFINE OFFSETS
NAME==.XX. ;;DEFINE THIS OFFSET
.XX.==.XX.+SIZE ;;THEN MOVE OFFSET
>
;THE HEADER AREA OF THE FILE. SINCE THERE IS ONLY ONE OF THESE
;AREAS, THERE IS NO OFFSET. INSTEAD WE DEFINE THE ACTUAL LOCATION
;IN CORE WHERE THE HEADER WILL BE MAPPED.
.XX.==MAPADR ;LOCATION WHERE HEADER STARTS IN CORE
;(WORD 0 OF THE DATA FILE)
XX H.VERS ;VERSION OF THIS DATA FILE
XX H.LOCK ;LOCK WORD, -1 IF AVAILABLE
XX H.LTIM ;TIME WHEN LOCK WAS LAST OBTAINED
XX H.LJOB ;JOB NUMBER WHICH OBTAINED THE LOCK
XX H.LUSR ;USER NUMBER WHO OBTAINED THE LOCK
XX H.DATE ;DATE WHEN DUNGEON WAS CREATED
XX H.UADR ;BEGINNING ADDRESS OF THE USER DATA
XX H.USIZ ;SIZE OF EACH USER'S DATA AREA
XX H.PLRS ;NUMBER OF PLAYERS
XX H.RADR ;BEGINNING ADDRESS OF THE ROOM DATA
XX H.RSIZ ;SIZE OF EACH ROOM'S DATA
XX H.ROOM ;NUMBER OF ROOMS IN DUNGEON
XX H.LEVL ;LOWEST LEVEL IN DUNGEON
XX H.LROM ;NUMBER OF ROOMS IN LOWEST LEVEL
XX H.LDOR ;NUMBER OF LEVEL DOORS DOWN FROM THIS LEVEL
XX H.LGRW ;HOW MANY DOORS ALLOW THIS LEVEL TO GROW
XX H.LDWN ;ROOMS IN LEVEL BEFORE LEVEL-CHANGE IS ALLOWED
XX H.LLUK ;ROOM NEXT TO FIRST LEVEL-CHANGE DOOR IN LEVEL
XX H.WORD ;HOW MANY MAGIC WORDS ARE IN USE
XX H.MONS ;NUMBER OF MONSTERS IN DUNGEON
XX H.XTRA,^D43 ;EXTRA FOR EXPANSION
HDRSIZ==.XX.-MAPADR ;SIZE OF THE HEADER
;DEFINITIONS FOR THE OFFSETS INTO THE SECOND SECTION OF THE FILE.
;THIS IS DATA FOR EACH PLAYER, AND IS USUALLY REFERENCED BY INDEXING
;OFF OF AC "U". THIS SECTION IS SEARCHED LINEARLY TO FIND THE ENTRY
;FOR THE PLAYER.
PLRADR==MAPADR+HDRSIZ ;ADDRESS IN CORE WHERE THIS SECTION STARTS
.XX.==0 ;OFFSETS START AT ZERO
XX U.USER ;DIRECTORY NUMBER OF THIS USER
XX U.BDAT ;DATE WHEN PLAYER ENTERED DUNGEON
XX U.LDAT ;DATE WHEN PLAYER LAST MOVED
XX U.ROOM ;THE CURRENT ROOM THE PLAYER IS IN
XX U.FLAG ;FLAGS ABOUT THE PLAYER
XX U.TURN ;NUMBER OF MOVES MADE BY THE PLAYER
XX U.BLDR ;NUMBER OF ROOMS "BUILT" BY PLAYER
XX U.NEWR ;NUMBER OF ROOMS VISITED
XX U.LEVL ;LEVEL NUMBER OF THE PLAYER
XX U.CTRE ;AMOUNT OF TREASURE BEING CARRIED
XX U.STRE ;AMOUNT OF TREASURE SAFELY BROUGHT OUT
XX U.MONK ;NUMBER OF MONSTERS KILLED
XX U.MSGT ;TIME WE SAY MESSAGE FILE WRITTEN
XX U.BACK ;DIRECTION TO GO BACKWARDS
XX U.POWR ;STRENGTH OF THE PLAYER
XX U.DIES ;NUMBER OF REINCARNATIONS
XX U.POWM ;MAXIMUM POWER
XX U.ITEM ;ITEMS WE ARE CARRYING
XX U.ITEL ;WHICH LEVELS HAVE PROVIDED ITEMS
XX U.PATH,PTHMAX ;STORAGE FOR PATH DEFINITIONS
XX U.PATN ;NAME OF PATH BEING TAKEN
XX U.PATI ;INDEX INTO THE PATH SEQUENCE
XX U.PATR ;ROOM WHERE PATH IS GOOD FROM
XX U.CHET ;NUMBER OF TIMES CHEATED USING MOVE COMMAND
XX U.TELP ;LAST ROOM WE TELEPORTED FROM
XX U.ROBR ;WHO HAS ROBBED US
XX U.XTRA,^D17 ;EXTRA LOCATIONS FOR EXPANSION
PLRSIZ==.XX. ;SIZE OF EACH PLAYER'S BLOCK
;FLAGS IN THE FLAG WORD:
UF.OKM==1 ;WE CAN MOVE ANY DIRECTION TO AVOID MONSTERS
UF.NIV==2 ;CAN'T USE INVISIBILITY ROOM HERE
;THE THIRD SECTION OF THE FILE. THIS CONTAINS ALL OF THE ROOMS,
;WHICH ARE NUMBERED CONSECUTIVELY AS THEY ARE EXPLORED. ROOM 0 IS
;ALWAYS THE STARTING POINT, WHERE TREASURE HAS TO BE BROUGHT BACK
;TO BE SAFE. THE WAY THAT ROOMS ARE LINKED TO EACH OTHER DETERMINES
;THE STRUCTURE OF THE DUNGEON. EACH ROOM HAS AN X AND Y ADDRESS WHOSE
;ONLY PURPOSE IS TO MAKE THE MAPS REASONABLE. I.E., ROOMS WILL JOIN
;EACH OTHER IN REASONABLE WAYS. GIVEN A ROOM NUMBER, YOU CAN COMPUTE
;WHERE IN THE FILE THE DATA FOR THAT ROOM IS.
ROMADR==PLRADR+PLRMAX*PLRSIZ ;ADDRESS WHERE ROOMS START
.XX.==0 ;THESE ARE OFFSETS ALSO
XX R.ROOM ;-1 IN LEFT HALF, ROOM NUMBER IN RIGHT
XX R.LOC ;X AND Y COORDINATE OF THIS ROOM
XX R.LEVL ;LEVEL NUMBER OF THIS ROOM (0-N)
XX R.FLAG ;FLAGS FOR THIS ROOM
XX R.DIRS,DIRMAX ;POINTERS TO ROOMS WHICH COME FROM HERE
XX R.VTRE ;AMOUNT OF VISIBLE TREASURE HERE
XX R.HTRE ;AMOUNT OF HIDDEN TREASURE HERE
XX R.VIST ;NUMBER OF TIMES ROOM HAS BEEN VISITED
XX R.FVIS ;FIRST VISITOR TO THIS ROOM
XX R.LVIS ;LAST VISITOR TO THIS ROOM
XX R.VISF,PLRWDS ;BIT TABLE FOR WHICH PLAYERS HAVE BEEN HERE
XX R.SRCF,PLRWDS ;WHICH PLAYERS KNOW SECRET DOORS HERE
XX R.WORD ;WHICH MAGIC WORD IS SCRAWLED IN THIS ROOM
XX R.TREF,PLRWDS ;WHICH PLAYERS HAVE GENERATED TREASURE HERE
XX R.MONS ;-1,,MONSTER TYPE OR ZERO IF NONE
XX R.MONH ;NUMBER OF HITS LEFT BEFORE CROAKING
XX R.MONK ;NUMBER OF DEAD MONSTERS IN THE ROOM
XX R.VITM ;VISIBLE ITEMS IN THIS ROOM
XX R.HITM ;INVISIBLE ITEMS IN THIS ROOM
XX R.DIES ;NUMBER OF PLAYERS WHO DIED HERE
XX R.KILF,PLRWDS ;WHO HAS KILLED MONSTERS IN THIS ROOM
XX R.HIDF,PLRWDS ;WHICH PLAYERS KNOW ABOUT HIDDEN TREASURE
XX R.XTRA,^D4 ;EXTRA WORDS
ROMSIZ==.XX. ;SIZE OF DATA FOR A ROOM
SUBTTL DEFINITIONS FOR CONNECTIONS BETWEEN ROOMS
;THE WORDS IN THE ROOM DESCRIPTIONS WHICH LINK TO OTHER WORDS HAVE THE
;FOLLOWING FORMAT. THE RIGHT HALF IS THE ROOM NUMBER THAT TAKING THIS
;DIRECTION LEADS TO (MAY BE MEANINGLESS, THOUGH). THE LEFT HALF IS A
;CODE SAYING WHAT IS REQUIRED TO TRAVERSE THIS PATH. THIS CODE ALSO
;AFFECTS THE OUTPUT OF THE DESCRIPTION OF THE ROOM.
DR%DAT==777700,,0 ;MASK FOR DOOR DATA
DR%TYP==000077,,0 ;MASK FOR DOOR TYPE
DR%NXT==000000,,777777 ;MASK FOR LINK TO NEXT ROOM
DR.UNK==0 ;THIS PATH HAS NOT YET BEEN DETERMINED
DR.NEV==1 ;THERE IS NO WAY TO GO THIS WAY
DR.ALW==2 ;YOU CAN ALWAYS TRAVEL THIS WAY
DR.SRC==3 ;A SECRET DOOR CAN BE FOUND BY SEARCHING
DR.LVL==4 ;DOOR CAN BE OPENED IF LEVEL IS GOOD ENOUGH
DR.WRD==5 ;THE PROPER MAGIC WORD CAN OPEN THIS DOOR
DR.MAG==6 ;A MAGIC ITEM CAN CREATE A DOOR HERE
DR.BLK==7 ;THIS PASSAGEWAY IS BLOCKED DUE TO A CAVE-IN
;THE DIRECTIONS THAT CAN BE TRAVERSED. THESE MUST BE PAIRED SO THAT
;THE EVEN AND ODD DIRECTIONS ARE IN OPPOSITE DIRECTIONS.
DIR.N==0 ;NORTH
DIR.S==1 ;SOUTH
DIR.E==2 ;EAST
DIR.W==3 ;WEST
DIR.BK==DIRMAX ;NOT A REAL DIRECTION, BUT NEEDED
;TO INDICATE BACKWARDS
SUBTTL MAGIC ITEMS
;THE FOLLOWING MACRO DEFINES THE KINDS OF MAGICAL ITEMS WHICH CAN
;APPEAR IN THE DUNGEON. THESE ITEMS CAN EITHER EXIST IN A ROOM,
;OR CAN BE CARRIED BY A PLAYER. THERE IS A MAXIMUM NUMBER OF A
;PARTICULAR ITEM THAT CAN EXIST IN A ROOM OR BE CARRIED, SINCE
;ALL THE MAGIC ITEMS SHARE THE SAME WORD OF STORAGE. ALL ACTIONS
;PERFORMED BY THESE ITEMS OCCUR "FOR FREE". THAT IS, NO SPECIAL
;ACTION IS NECESSARY TO MAKE THESE ITEMS WORK. YOU JUST HAVE TO
;BE CARRYING THEM.
DEFINE ITEMS,< ;;THE MAGICAL ITEMS FOLLOW
XX IT.ARM,ARMOR,a suit of armor ;MAGICAL ARMOR
XX IT.WD1,BLACK-MAGIC-WAND,a black magic wand ;FIRST MAGIC WAND
XX IT.GLS,GLASSES,a pair of glasses ;GLASSES
XX NOTITEM,GOLD ;GOLD
XX IT.WD3,GREEN-MAGIC-WAND,a green magic wand ;ANOTHER ONE
XX IT.FIX,HEALING-RING,a ring of healing ;RING OF HEALING
XX IT.INV,INVISIBILITY-RING,an invisibility ring ;INVISIBILITY RING
XX IT.WD4,ORANGE-MAGIC-WAND,an orange magic wand ;LAST MAGIC WAND
XX IT.SHV,SHOVEL,a shovel ;SHOVEL
XX IT.SWD,SWORD,a sword ;SWORD
XX IT.TEL,TELEPORTATION-RING,a ring of teleportation ;RING
XX IT.WD2,WHITE-MAGIC-WAND,a white magic wand ;ANOTHER
>
DEFINE XX(CODE,KEYWORD,TEXT),<
IFDIF <CODE><NOTITEM>,<
CODE==.XX. ;SYMBOL FOR TEXT
XLIST ;;SUPPRESS LISTING
.XX.==.XX.+1 ;;BUMP COUNTER
LIST ;;RESTORE LISTING
>
>
.XX.==0 ;START OFF COUNTER
ITEMS ;GENERATE ALL THE DEFINITIONS
SUBTTL MONSTERS WHICH APPEAR IN THE DUNGEON
;THE FOLLOWING MACRO DEFINES ALL OF THE MONSTERS WHICH CAN APPEAR.
;ARGUMENTS TO THE MACRO ARE AS FOLLOWS:
;
; XX TREASURE,HITS,MEANNESS,NAME
;
;THIS MACRO IS EXPANDED LATER INTO TABLES.
DEFINE MONS,< ;;MACRO TO DEFINE MONSTERS
XX 1,1,1,a Buzzardly Buzzard
XX 0,10,5,a Boogie Man
XX 1,1,1,a Cookie Monster
XX 1,2,6,a Giant Ant
XX 1,6,10,a Basilisk
XX 0,4,12,a Giant Beetle
XX 1,3,5,a Carrion Crawler
XX 0,10,24,a Black Pudding
XX 1,9,4,a Chimera
XX 1,8,18,a Black Dragon
XX 1,7,16,a White Dragon
XX 1,12,36,a Gold Dragon
XX 1,4,4,a Gargoyle
XX 1,10,10,a Ghost
XX 1,2,6,a Ghoul
XX 1,11,30,a Fire Giant
XX 1,7,6,a Goblin
XX 1,8,12,a Gorgon
XX 1,1,8,a Hobgoblin
XX 1,12,10,a Hydra
XX 1,4,8,a Jackalwere
XX 1,4,4,a Kobold
XX 0,4,4,a Giant Leech
XX 1,10,16,a Fire Lizard
XX 1,6,8,a Manticore
XX 1,6,8,a Minotaur
XX 1,6,12,a Mummy
XX 1,4,10,an Ogre
XX 1,1,8,an Orc
XX 0,6,8,a Giant Porcupine
XX 1,15,24,a Purple Worm
XX 0,12,20,a Roper
XX 1,5,10,a Giant Scorpion
XX 1,3,5,a Shadow
XX 1,1,6,a Skeleton
XX 1,7,8,a Spectre
XX 1,4,8,a Giant Spider
XX 0,2,8,a Giant Toad
XX 1,2,5,a Troglodyte
XX 1,6,8,a Troll
XX 1,8,10,a Vampire
XX 1,4,8,a Giant Wasp
XX 1,4,4,a Wight
XX 0,3,5,a Wolverine
XX 1,5,6,a Wraith
XX 0,2,8,a Zombie
XX 1,25,25,an unspeakable horror
>
SUBTTL INITIALIZATION
CAVE: RESET ;CLEAR EVERYTHING
MOVX F,INIFLG ;SET UP INITIAL FLAGS
MOVE P,[IOWD PDLSIZ,PDL] ;SET UP STACK POINTER
MOVEI ZR,-1 ;INITIALIZE MASK AC
MOVE T1,[CALL LUUO] ;GET LUUO INSTRUCTION
MOVEM T1,.JB41 ;SET IT UP
SETZM MSGJFN ;CLEAR MESSAGE JFN
SETZM RANNUM ;INITIALIZE RANDOM NUMBERS
SETZM OUTPTR ;NO STORAGE BUFFER YET
GJINF ;READ INFORMATION ABOUT ME
CAMN T1,GOD ;ARE WE THE GODLY PERSON?
TXO F,FR.GOD ;YES, REMEMBER THAT
MOVEM T1,PLYUSR ;SET WHO WE ARE PLAYING AS
MOVEM T1,MYUSER ;AND REMEMBER WHO WE REALLY ARE
MOVEM T3,MYJOB ;AND WHAT JOB NUMBER I AM
MOVEI T1,.PRIOU ;GET SET
MOVEI T2,.MORLW ;TO READ THE WIDTH
MOVEI T3,COLMIN ;GET MINIMUM AS DEFAULT
POKHER: MTOPR ;DO IT
ERJMP .+1 ;FAILED, USE DEFAULT
CAIGE T3,COLMIN ;TOO FEW COLUMNS?
MOVEI T3,COLMIN ;YES, RAISE THE WIDTH
CAILE T3,COLMAX ;TOO MANY COLUMNS?
MOVEI T3,COLMAX ;YES, LOWER THE WIDTH
IDIVI T3,5 ;DIVIDE BY CHARACTERS TO A WORD
ADDI T3,BUFF ;ADD IN ADDRESS OF BUFFER
MOVEM T3,FULADR ;STORE FOR LATER USE
JRST GETCMD ;GO READ COMMANDS
SUBTTL SUBROUTINE TO READ A COMMAND
;HERE FOR MAIN COMMAND DISPATCH FOR THE PROGRAM. NEVER RETURNS.
GETCMD: TXNE F,FR.BLD ;NEED TO REBUILD THE COMMAND TABLE?
CALL BLDCMD ;YES, DO THE WORK
MOVEM P,SAVEP ;SAVE STACK FOR REPARSING <
HRROI T1,[ASCIZ/CAVE>/] ;GET USUAL PROMPT
TXNE F,FR.KIL ;IN MIDDLE OF A BATTLE? <<
HRROI T1,[ASCIZ/KILL-MODE>>/] ;YES, GET OTHER PROMPT
MOVEM T1,CMDBLK+.CMRTY ;SET POINTER
MOVEI T1,CMDBLK ;POINT TO COMMAND BLOCK
CMMD [FLDDB. (.CMINI)] ;INITIALIZE
NEWPAR: MOVE P,SAVEP ;RESTORE THE STACK
CALL TTYINI ;INITIALIZE TERMINAL BUFFER
MOVEI T1,CMDBLK ;POINT TO THE COMMAND BLOCK
MOVEI T2,[FLDDB. (.CMKEY,,CMDTAB)] ;GET STANDARD KEYWORD FUNCTION
TXNE F,FR.KIL ;IN MIDDLE OF KILLING A MONSTER?
MOVEI T2,[FLDDB. (.CMCFM,CM%HPP+CM%SDH,,CRLF to do another "KILL",,<[FLDDB. (.CMKEY,,CMDTAB)]>)] ;YES, GET OTHER ONE
CALL DOCMMD ;READ COMMAND
TXNN F,FR.KIL ;DOING AUTOMATIC KILL COMMANDS?
JRST CALCMD ;NO, GO DO NORMAL ONE
TSC T3,T3 ;YEP, SEE WHAT COMND FUNCTION WAS DONE
JUMPN T3,CALCMD ;GO IF KEYWORD TYPED
MOVEI T2,AUTOKL ;GET ROUTINE
JRST DOCMD ;JOIN OTHER CODE
CALCMD: MOVE T2,(T2) ;GET ADDRESS OF DATA
MOVE T2,(T2) ;THEN ADDRESS OF ROUTINE AND FLAGS
TLNN T2,C.STS ;IS THIS A STATUS-TYPE COMMAND?
TXZ F,FR.KIL ;NO, CLEAR KILL MODE
DOCMD: CALL (T2) ;DO THE COMMAND
DOCRLF ;IF NONSKIP RETURN, END IN A CRLF
CALL SAVPNT ;FORCE OUTPUT OUT
JRST GETCMD ;READ NEXT COMMAND
;TABLE OF ALL POSSIBLE COMMANDS. THE ACTUAL TABLE OF COMMANDS IS
;BUILT AT RUNTIME BY CHECKING IF CERTAIN CONDITIONS ARE SATISFIED.
;THE FLAG FR.BLD IS SET WHENEVER THE COMMAND TABLE HAS TO BE
;CHANGED. THE CONDITIONS FOR A COMMAND BEING AVAILABLE ARE:
C.PLY==1 ;LEGAL ONLY IF PLAY COMMAND HAS BEEN GIVEN
C.NOP==2 ;LEGAL IF PLAY COMMAND WAS NOT YET GIVEN
C.GOD==4 ;ONLY LEGAL FOR THE DUNGEON MASTER
C.DEB==10 ;LEGAL ONLY WHEN DEBUGGING
;OTHER FLAGS FOR COMMANDS:
C.STS==20 ;THIS IS A STATUS TYPE COMMAND
CMDORG: CMDLEN,,CMDLEN ;HEADER
AB B,ABB5 ;ABBREVIATION FOR BACK
ABB5: AA BACK-UP,CMDBCK,C.PLY ;MOVE BACK TO PREVIOUS ROOM
AA BECOME,CMDBEC,C.DEB!C.STS ;BECOME ANOTHER PLAYER
AA BRIEF,CMDBRF,C.PLY!C.STS ;BRIEF OUTPUT IS WANTED
AA DEBUG,CMDDEB,C.GOD!C.STS ;TURN DEBUGGING ON OR OFF
AA DEFINE,CMDDEF,C.PLY!C.STS ;DEFINE A PATH
AA DELETE,CMDDEL,C.PLY!C.STS ;DELETE A PATH
AA DROP,CMDDRP,C.PLY ;DROP SOME TREASURE
AB E,ABB4 ;ABBREVIATION FOR EAST
ABB4: AA EAST,CMDMVE,C.PLY ;MOVE EAST
AA EXIT,CMDXIT,C.STS ;EXIT FROM PROGRAM
AB F,ABB6 ;ABBREVIATION FOR FIND
ABB6: AA FIND,CMDFND,C.PLY ;FIND HIDDEN STUFF
AA FOLLOW,CMDFOL,C.PLY ;FOLLOW A PREDEFINED PATH
AA GET,CMDGET,C.PLY ;GET SOME TREASURE
AB H,ABB3 ;ABBREVIATION FOR HELP
ABB3: AA HELP,CMDHLP,C.STS ;GET HELP
AA HIDE,CMDHID,C.PLY ;HIDE TREASURE IN THE ROOM
AA INFORMATION,CMDINF,C.STS ;GET INFORMATION
AA INITIALIZE,CMDINI,C.DEB!C.STS ;RESET THE DATA FILE
AA KILL,CMDKIL,C.PLY ;KILL MONSTERS
AB L,ABB2 ;ABBREVIATION FOR LOOK
AA LIST,CMDLST!C.STS ;LIST STATUS OF THE GAME
ABB2: AA LOOK,CMDLOK,C.PLY!C.STS ;LOOK AROUND
AA MOVE,CMDMOV,C.GOD!C.PLY!C.STS ;MOVE TO PARTICULAR ROOM
AA NORTH,CMDMVN,C.PLY ;MOVE NORTH
AA PLAY,CMDPLY,C.NOP!C.STS ;BEGIN PLAYING THE GAME
AA PLOT,CMDPLT,C.PLY!C.STS ;PLOT VISITED ROOMS ON A LEVEL
AA PROCEED,CMDPRO,C.PLY ;PROCEED ALONG PREVIOUS PATH
AA REST,CMDRST,C.PLY ;REST UP
AA ROB,CMDROB,C.PLY ;ROB ANOTHER PLAYER
AB S,ABB1 ;ABBREVIATION FOR SOUTH
AA SAY,CMDSAY,C.PLY ;SAY SOMETHING
ABB1: AA SOUTH,CMDMVS,C.PLY ;MOVE SOUTH
AA STATUS,CMDSTS,C.STS ;GIVE STATUS OF MYSELF
AA TYPE,CMDTYP,C.PLY!C.STS ;TYPE OUT A PATH DEFINITION
AA USE,CMDUSE,C.PLY ;USE A MAGIC ITEM
AA VERBOSE,CMDVER,C.PLY!C.STS ;VERBOSE OUTPUT
AA WEST,CMDMVW,C.PLY ;MOVE WEST
CMDLEN==.-CMDORG-1 ;NUMBER OF COMMANDS
SUBTTL THE SIMPLE COMMANDS
;HERE TO DO THE TRIVIAL COMMANDS, SUCH AS HELP AND QUIT.
CMDXIT: NOISE (FROM PROGRAM) ;DO NOISE
CONFRM ;CONFIRM THE LINE
HALTF ;LEAVE PROGRAM
RET ;RETURN
CMDHLP: CONFRM ;CONFIRM THE LINE
HRROI T1,HLPTXT ;POINT TO HELP MESSAGE
PSOUT ;TYPE IT
RET ;DONE
CMDPLY: NOISE (IN THIS DUNGEON) ;DO NOISE
CONFRM ;THEN CONFIRM THE LINE
CALL FILOPN ;OPEN UP THE DATA FILE
CALL FINDME ;FIND ME IN THE FILE
TXO F,FR.PLY!FR.BLD ;WE ARE PLAYING AND COMMANDS CHANGE NOW
TXNE F,FR.DEB ;DEBUGGING MODE?
JRST LOOKVR ;YES, DON'T TYPE MESSAGE
MOVX T1,GJ%SHT+GJ%OLD ;GET FLAGS
HRROI T2,TXTNAM ;POINT TO FILENAME
GTJFN ;TRY TO FIND THE FILE
ERJMP LOOKVR ;FAILED, GO SEE WHY
MOVEI T2,MSGTIM ;PLACE TO REMEMBER DATE
MOVEI T3,1 ;WANT ONE WORD
RFTAD ;READ WHEN FILE WAS LAST WRITTEN
MOVE T2,U.MSGT(U) ;GET WHEN WE LAST SAW THE MESSAGE
CAMN T2,MSGTIM ;SAME WRITE DATE?
JRST [ RLJFN ;YES, RELEASE FILE
JFCL
JRST LOOKVR] ;AND LOOK AROUND
CALL DOMESS ;TYPE OUT THE MESSAGE
STROUT [ASCIZ/- - - -
/] ;THEN SPACE DOWN
CALL LOCK ;LOCK UP THE FILE
MOVE T1,MSGTIM ;GET TIME OF LAST WRITE
MOVEM T1,U.MSGT(U) ;SET NEW TIME
CALL UNLOCK ;UNLOCK AGAIN
JRST LOOKVR ;THEN GO LOOK AROUND AND RETURN
CMDINF: NOISE (ON LATEST FEATURES AND CHANGES) ;DO NOISE
CONFRM ;CONFIRM THE LINE
MOVX T1,GJ%SHT+GJ%OLD ;GET FLAGS
HRROI T2,TXTNAM ;POINT TO THE FILE
GTJFN ;FIND THE FILE
ERROR (,,Unable to read information file.) ;FAIL
CALL DOMESS ;TYPE OUT NEWEST DATA
RET ;DONE
CMDDEB: NOISE (MODE TURNED) ;NOISE
CMMD [FLDDB. (.CMKEY,,ONOFF,,<ON>)] ;READ THE ANSWER
HRRZ T4,(T2) ;GET DATA HALFWORD
CONFRM ;CONFIRM THE LINE
SKIPN T4 ;WANTS DEBUG MODE SET?
TXZA F,FR.DEB ;NO, CLEAR FLAG
TXO F,FR.DEB ;YES, SET FLAG
TXO F,FR.BLD ;NEED NEW COMMAND TABLE NOW
JRST CPOPJ1 ;SKIP RETURN TO STOP CRLFS
ONOFF: XWD 2,2 ;TWO ENTRIES
AC OFF,0 ;OFF
AC ON,1 ;ON
CMDMOV: NOISE (TO ROOM) ;TYPE NOISE
CMMD [FLDDB. (.CMNUM,,^D10,,<0>)] ;READ A NUMBER
CONFRM ;THEN CONFIRM THE LINE
SKIPL T2 ;IS ROOM NEGATIVE?
CAML T2,H.ROOM ;OR TOO LARGE?
ERROR (,,Illegal room number) ;YES, COMPLAIN
CALL LOCK ;LOCK UP THE DATA FILE
MOVEM T2,U.ROOM(U) ;SET WHICH ROOM WE ARE IN
SETZM U.BACK(U) ;MOVING BACK IS ILLEGAL
AOS U.CHET(U) ;REMEMBER WE HAVE CHEATED AGAIN
CALL UNLOCK ;UNLOCK THE FILE NOW
MOVE R,T2 ;PUT ROOM NUMBER IN RIGHT AC
IMULI R,ROMSIZ ;COMPUTE OFFSET INTO ROOM TABLES
ADDI R,ROMADR ;OFFSET TO BEGINNING OF TABLE
JRST LOOKVR ;AND LOOK AROUND HERE
CMDFND: NOISE (HIDDEN DOORWAYS AND TREASURE) ;SOME NOISE
CONFRM ;FINISH THE LINE
SKIPE T4,R.MONS(R) ;ANY MONSTER IN THE ROOM?
JRST FNDBSY ;YES, SEARCHING NOT ALLOWED
CALL LOCK ;LOCK THE FILE
MOVEI T1,R.SRCF(R) ;GET ADDRESS OF BIT TABLE
CALL BITSET ;POINT AT THE PROPER BIT
IORM T2,(T1) ;REMEMBER THIS ROOM WAS SEARCHED
MOVEI T1,R.HIDF(R) ;GET ADDRESS OF OTHER BIT TABLE
CALL BITSET ;POINT AT PROPER BIT
IORM T2,(T1) ;REMEMBER WE SEARCHED FOR TREASURE TOO
CALL UNLOCK ;UNLOCK FILE NOW
TXZ F,FR.FND ;NOTHING FOUND HERE YET
DOCRLF ;START WITH A CRLF
CALL FDDOOR ;LOOK FOR SECRET DOORS
CALL FDTRES ;AND LOOK FOR HIDDEN TREASURE
TXNN F,FR.FND ;WAS ANYTHING FOUND?
STROUT [ASCIZ/There is nothing hidden here. /] ;NO SAY SO
DOCRLF ;FINISH WITH A CRLF
RET ;AND RETURN
;HERE TO LOOK FOR HIDDEN DOORS:
FDDOOR: MOVEI T1,DR.SRC ;GET CODE FOR SECRET DOORS
CALL FNDDOR ;SEE IF ANY EXIST HERE
JUMPE T1,CPOPJ ;IF NONE, DONE
CALL LKSEC2 ;SHOW SECRET DOORS
TXO F,FR.FND ;REMEMBER SOMETHING WAS FOUND
RET ;DONE
;HERE TO LOOK FOR HIDDEN TREASURE:
FDTRES: SKIPN T4,R.HTRE(R) ;ANY HIDDEN TREASURE HERE?
RET ;NO, SAY NOTHING
STROUT [ASCIZ/This room has /] ;TYPE
MOVE T1,T4 ;GET NUMBER
CALL GOLOUT ;OUTPUT HOW MUCH GOLD
STROUT [ASCIZ/ hidden in it!!! /] ;FINISH IT
TXO F,FR.FND ;REMEMBER SOMETHING FOUND
RET ;DONE
FNDBSY: STROUT [ASCIZ/
The /] ;START THE OUTPUT
HRRZ T1,MONTXT(T4) ;GET STRING FOR MONSTER
CALL MONOUT ;OUTPUT MONSTER NAME
STROUT [ASCIZ/ stops you from looking around the room.
/] ;EXPLAIN WHY HE CAN'T DO THIS
RET ;DONE
CMDLOK: NOISE (AROUND) ;NOISE
CONFRM ;CONFIRM THE LINE
JRST LOOKVR ;AND LOOK AROUND
CMDBRF: TDZA T4,T4 ;WANTS BRIEF OUTPUT
CMDVER: MOVX T4,FR.VRB ;OR WANTS VERBOSE OUTPUT
NOISE (OUTPUT IS DESIRED) ;DO NOISE
CONFRM ;CONFIRM THE LINE
TXZ F,FR.VRB ;FIRST CLEAR THE VERBOSITY FLAG
IOR F,T4 ;THEN SET IT IF WANTED
JRST CPOPJ1 ;SKIP RETURN SO CRLF NOT DONE
;THE HELP TEXT FOR THE HELP COMMAND:
HLPTXT: TEXT <
Commands are the following:
BRIEF Give a very short description of a room that you have seen
before. Anything interesting about the room will still be
typed, such as treasure, monsters, and magic words.
DEFINE Define a path name. This allows you to store a sequence of
commonly used directions that can be recalled later. Useful
for storing the route between levels, etc.
DELETE Deletes a previously defined path. If the path name of "ALL"
is specified, all definitions are deleted.
DROP Leave your treasure in the current room. Since it is in the
open, anyone wandering through the room can see it and take it.
In order to get credit for your treasure, you must return
it to the entrance of the dungeon and drop it there.
FIND Search the current room carefully looking for secret passages
and hidden treasure. You know all secret passages forever
once you have used FIND in a room. But if more treasure was
hid in a room after you have searched it, another FIND will be
needed to see it.
FOLLOW Traverse the named path which had been previously defined. If
something interesting appears along the way, the movement is
interrupted, and can be continued with the PROCEED command.
GET Pick up the specified treasure or magic items that are in
the current room.
HIDE Take your treasure and hide it in the current room. It can
only be found by someone if they search the room.
INFORMATION Type out the latest news about the CAVE program. This
is automatically done if necessary when the PLAY command is
given.
KILL Attempt to kill any monster in the current room. It can take
many KILL commands to finish off a monster. So this command
puts you into a mode where each CRLF will do KILL again.
LIST Type out a listing of all of the players in this dungeon,
giving statistics on each player and of the dungeon as a whole.
You can also show the statistics for just yourself.
LOOK Give the verbose description of a particular room you are in.
REST Wait in the current room and let your strength build up to the
specified value. Monsters can appear while you are resting.
PLOT Write the file CAVE.PLT which is a binary file suitable for
sending to a plotter. The plot shows all of the rooms you have
been to on a level with their proper location and connections.
ROB Attempt to rob another player in the same room as yourself.
If he is carrying treasure, you get some of that. Otherwise
you get one of his magic items. A player can only be robbed
once between turns.
SAY Speak a phrase which might have a magical effect. All phrases
which do something can be discovered before they are needed.
STATUS Show your current status, including what room you are in, your
strengths, and how much treasure and magic items are being
carried.
USE Use the specified magical item in its normal manner.
VERBOSE Indicate that all room descriptions are to be as detailed as
possible. This is the default mode.
>
SUBTTL COMMANDS TO HANDLE TREASURES
;HERE TO HIDE OR DROP TREASURE. IF TREASURE IS DROPPED AT THE
;ENTRANCE, IT IS SAFELY STASHED AWAY AND APPEARS IN THE STATUS
;LISTING. OTHERWISE, IT IS LIABLE TO BE GOTTEN BY ANOTHER PLAYER.
CMDDRP: SKIPA T2,[Z R.VTRE(R)] ;GET INDEX FOR VISIBLE TREASURE
CMDHID: MOVE T2,[Z R.HTRE(R)] ;OR INDEX FOR HIDDEN TREASURE
MOVEM T2,TEMP ;SAVE IT AWAY
CALL PARITM ;READ IN HOW MUCH TREASURE TO HIDE
SKIPL T4 ;**FOR NOW CAN ONLY DROP GOLD
ERROR (,,You can only drop gold so far.) ;**TEMP
MOVE I,T3 ;SAVE AMOUNT OF TREASURE
CALL LOCK ;LOCK UP THE FILE
SKIPN T1,U.CTRE(U) ;SEE IF WE HAVE ANY TREASURE
ERROR (,,You are not carrying any treasure.) ;NO
SKIPGE I ;WANTS ALL TREASURE DROPPED?
MOVE I,T1 ;YES, GET ALL WE HAVE
CAMLE I,T1 ;SEE IF ASKING FOR TOO MUCH
ERROR (,,You are not carrying that much treasure.) ;YES
MOVN T1,I ;GET NEGATIVE TREASURE
ADDM T1,U.CTRE(U) ;REDUCE HOW MUCH WE ARE CARRYING
TDNN ZR,R.ROOM(R) ;ROOM ZERO?
JRST SAFTRS ;YES, MAKE TREASURE SAFE
ADDB I,@TEMP ;ADD TREASURE IN AND REMEMBER TOTAL
HRRZ T4,TEMP ;SEE IF WE HID TREASURE
CAIE T4,R.HTRE ;DID WE?
JRST NOTHID ;NOPE, SKIP ON
MOVEI T1,R.HIDF+1(R) ;GET ADDRESS OF SECOND WORD OF HIDE FLAGS
SETZM -1(T1) ;CLEAR FIRST WORD
HRLI T1,-1(T1) ;FINISH BLT POINTER
BLT T1,R.HIDF+PLRWDS-1(R) ;NOBODY KNOWS ABOUT THIS TREASURE NOW
MOVEI T1,R.HIDF(R) ;GET ADDRESS OF FLAGS
CALL BITSET ;CREATE OUR BIT
IORM T2,(T1) ;THEN SAY WE KNOW ABOUT TREASURE
NOTHID: CALL UNLOCK ;FREE UP THE LOCK
DOCRLF ;START WITH A CRLF
STROUT [ASCIZ/The room now has /] ;START OUTPUT
MOVE T1,I ;GET AMOUNT
CALL GOLOUT ;OUTPUT HOW MUCH
CAIN T4,R.HTRE ;HIDDEN?
STROUT [ASCIZ/ hidden/] ;YES
STROUT [ASCIZ/ in it. /] ;FINISH
SKIPN T2,U.CTRE(U) ;CARRYING ANY TREASURE STILL?
STROUT [ASCIZ/You are carrying no treasure now.
/] ;NO, SAY SO
JUMPE T2,CPOPJ ;RETURN IF DONE
STROUT [ASCIZ/You are still carrying /] ;GET TEXT
MOVE T1,T2 ;PUT IN RIGHT AC
CALL GOLOUT ;OUTPUT HOW MUCH GOLD WE HAVE
STROUT [ASCIZ/.
/] ;THEN A CRLF
RET ;DONE
SAFTRS: ADDB I,U.STRE(U) ;ADD TO TOTAL SAFE TREASURE
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
Congratulations!!! You have now safely brought out /] ;START
MOVE T1,I ;GET AMOUNT OF GOLD
CALL GOLOUT ;TYPE IT
STROUT [ASCIZ/!!!!
/] ;FINISH TEXT
RET ;DONE
TRETOM: CALL UNLOCK ;UNLOCK FILE
SKIPN T4 ;NO TREASURE LEFT?
STROUT [ASCIZ/
You cannot carry any more treasure.
/] ;YES, SAY HE IS PEGGED
JUMPE T4,CPOPJ ;DONE IF NO MORE TREASURE TO CARRY
STROUT [ASCIZ/
You can only carry /] ;START OUTPUT
MOVE T1,T4 ;GET NUMBER
CALL TTYDEC ;OUTPUT IT
SKIPE U.CTRE(U) ;CARRYING ANY TREASURE?
STROUT [ASCIZ/ more/] ;YES, INCLUDE THIS
STROUT [ASCIZ/ gold piece/] ;MORE
CAIE T4,1 ;ONE?
CHROUT "s" ;NO, MAKE PLURAL
STROUT [ASCIZ/.
/] ;FINISH IT
RET ;DONE
;HERE TO PICK UP TREASURE WHICH IS LAYING AROUND IN THE ROOM.
;WE ARE ABLE TO PICK UP HIDDEN TREASURE IF THE ROOM WAS SEARCHED.
CMDGET: CALL PARITM ;READ IN HOW MUCH TO GET
DMOVEM T3,ITMWNT ;REMEMBER ITEM TYPE AND AMOUNT
CALL LOCK ;GET THE INTERLOCK
SKIPE T4,R.MONS(R) ;ANY MONSTER HERE?
JRST GETBSY ;YES, CAN'T DO THIS THEN
SKIPL T1,ITMWNT+1 ;SEE IF WHAT WE WANTED WAS TREASURE
JRST GETITM ;NO, GO GET AN ITEM THEN
MOVEI T1,R.HIDF(R) ;GET ADDRESS OF THE SEARCH FLAGS
CALL BITSET ;COMPUTE OFFSET AND BIT
TDNN T2,(T1) ;HAS THIS ROOM BEEN SEARCHED?
TDZA T1,T1 ;NO, WE KNOW OF NO HIDDEN TREASURE
MOVE T1,R.HTRE(R) ;YEP, GET HIDDEN TREASURE
ADD T1,R.VTRE(R) ;ADD IN TREASURE WE CAN SEE
SKIPN T1 ;ANY?
ERROR (,,There is no treasure here.) ;NO
SKIPGE I,ITMWNT ;WANTS ALL OF THE TREASURE?
MOVE I,T1 ;YES, GET ALL THERE IS
CAMLE I,T1 ;MAKE SURE THAT MUCH IS HERE
ERROR (,,There is not that much treasure here.) ;NOPE
MOVE T4,U.LEVL(U) ;GET LEVEL
IMUL T4,U.POWR(U) ;MULTIPLY BY POWER
IMULI T4,TREMAX ;AND BY CONSTANT TO GET MAXIMUM WE CAN CARRY
SUB T4,U.CTRE(U) ;DECREMENT AMOUNT BEING CARRIED
CAMGE T4,I ;CAN WE CARRY THIS TOO?
JRST TRETOM ;NO, GO COMPLAIN
MOVE T1,R.VTRE(R) ;GET VISIBLE TREASURE
MOVE T2,R.HTRE(R) ;AND HIDDEN TREASURE
SUB T1,I ;DECREMENT VISIBLE TREASURE
JUMPGE T1,GETVOK ;PROCEED IF ENOUGH IS THERE
ADD T2,T1 ;NEED IT ALL, REDUCE INVISIBLE TREASURE
SETZ T1, ;AND CLEAR VISIBLE TREASURE
GETVOK: MOVEM T1,R.VTRE(R) ;UPDATE VISIBLE TREASURE
MOVEM T2,R.HTRE(R) ;AND INVISIBLE TREASURE
ADDM I,U.CTRE(U) ;GIVE US THE TREASURE
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
You are now carrying /] ;TYPE SOME TEXT
MOVE T1,U.CTRE(U) ;GET HOW MUCH GOLD
CALL GOLOUT ;TYPE HOW MUCH
STROUT [ASCIZ/.
/] ;FINISH THE OUTPUT
RET ;DONE
;HERE TO PICK UP A MAGICAL ITEM.
GETITM: CALL GETITR ;GET HOW MANY THE ROOM HAS
SKIPN T2 ;ANY?
ERROR (,,There are none of those here.) ;NO
CALL GETITU ;GET HOW MANY I HAVE NOW
CAIN T2,ITMMSK ;AM I FULL UP?
ERROR (,,You cannot carry any more of those.) ;YES
ADDI T2,1 ;GIVE ME ONE MORE
CALL PUTITU ;STORE IT
CALL GETITR ;GET BACK NUMBER ROOM HAS
SOSL T2 ;DECREMENT IT
CALL PUTITR ;PUT BACK NEW NUMBER
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
Done.
/] ;SAY WE DID IT
RET ;DONE
GETBSY: CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
The /] ;START OUTPUT
HRRZ T1,MONTXT(T4) ;GET STRING
CALL MONOUT ;OUTPUT IT
STROUT [ASCIZ/ prevents you from collecting anything.
/] ;COMPLAIN
RET ;AND RETURN
SUBTTL SUBROUTINE TO PARSE A MAGIC ITEM OR GOLD
;CALLED TO READ THE REST OF THE COMMAND LINE, AND RETURN WHAT THE
;USER WANTS TO TALK ABOUT.
;RETURNS:
; +1: PROPER AMOUNT OF GOLD OR ITEMS SPECIFIED
; T4/ MAGIC ITEM CODE, OR -1 FOR GOLD
; T3/ (ONLY FOR GOLD) -1 FOR ALL OF IT, OR DESIRED AMOUNT
;THE DEFAULT INPUT IS "GOLD ALL".
PARITM: NOISE (ITEM) ;TYPE NOISE
CMMD [FLDDB. (.CMKEY,,ITMKEY,,<GOLD>)] ;READ ITEM
HRRE T4,(T2) ;GET POSSIBLE ITEM CODE
JUMPL T4,PARGOL ;IF GOLD, GO GET HOW MUCH
CONFRM ;MAGIC ITEM, CONFIRM LINE
RET ;DONE
PARGOL: NOISE (NUMBER OF PIECES) ;PROMPT FOR AMOUNT OF GOLD
CMMD [FLDDB. (.CMKEY,,ALLKEY,,<ALL>,[FLDDB. (.CMNUM,,^D10)])]
TSC T3,T3 ;SEE WHAT MATCHED
SETO T4, ;ASSUME WANTS ALL
JUMPE T3,PARGOA ;GO IF RIGHT
SKIPGE T4,T2 ;MAKE SURE SPECIFIED RIGHT AMOUNT
ERROR (,,You can't use a negative amount of gold!)
PARGOA: CONFRM ;CONFIRM THE LINE
MOVE T3,T4 ;MOVE AMOUNT OF GOLD
SETO T4, ;SAY WE HAVE GOLD
RET ;RETURN
ALLKEY: XWD 1,1 ;NUMBER OF ENTRIES
AC ALL,0 ;JUST THIS KEYWORD
;NOW GENERATE THE KEYWORD TABLE FOR THE ITEMS:
DEFINE XX(CODE,KEYWORD,TEXT),<
IFIDN <CODE><NOTITEM>,<
AC KEYWORD,-1
>
IFDIF <CODE><NOTITEM>,<
AC KEYWORD,CODE
>
>
ITMKEY: XWD ITMKNU,ITMKNU ;NUMBER OF ENTRIES
ITEMS ;EXPAND MACRO
ITMKNU==.-ITMKEY-1 ;NUMBER OF ITEMS IN TABLE
SUBTTL COMMAND TO REST UP
;THIS COMMAND IS USED TO WASTE TIME SO THAT OUR STRENGTH CAN
;IMPROVE QUICKLY. THIS COUNTS AS MOVES.
CMDRST: NOISE (TO RECOVER STRENGTH UP TO) ;NOISE
CMMD [FLDDB. (.CMKEY,,RSTKEY,,<MAXIMUM>,[FLDDB. (.CMNUM,,^D10)])]
TSC T3,T3 ;SEE WHICH WAS TYPED
SKIPN T3 ;WANTS ALL?
MOVEI T2,PWRMAX ;YES, GET MAXIMUM
MOVEM T2,RSTMAX ;REMEMBER FOR LOOP
CONFRM ;FINISH THE LINE
CALL TELROB ;TALK ABOUT ANY ROBBERIES
SETZM RSTMOV ;CLEAR NUMBER OF MOVES TAKEN
CALL LOCK ;LOCK UP THE FILE
SKIPE T4,R.MONS(R) ;ANY MONSTER IN THIS ROOM?
JRST RSTNOP ;YES, CAN'T REST HERE
RSTLOP: CALL DOFIX ;FIX US UP IF NECESSARY
AOS U.TURN(U) ;COUNT A TURN
AOS RSTMOV ;REMEMBER FOR OUTPUT
MOVE T1,[^D100,,^D200] ;USE THESE CHANCES OF A MONSTER
CALL MAKMON ;SEE IF A MONSTER SHOWED UP
SKIPE T4,R.MONS(R) ;DID ONE?
JRST RSTMON ;YES, STOP NOW!
MOVE T1,U.POWR(U) ;GET STRENGTH NOW
CAMGE T1,U.POWM(U) ;REACHED MAXIMUM?
CAML T1,RSTMAX ;OR REACHED MAXIMUM SPECIFIED?
JRST RSTDON ;YES
JRST RSTLOP ;NO, KEEP LOOPING
RSTDON: GTAD ;GET TIME
MOVEM T1,U.LDAT(U) ;UPDATE WHEN WE LAST PLAYED
CALL UNLOCK ;UNLOCK THE FILE
MOVE T1,RSTMOV ;GET NUMBER OF TURNS
IMULI T1,^D50 ;SLEEP TO SIMULATE RESTING
DISMS ;A SECOND FOR EVERY 20 TURNS
STROUT [ASCIZ/
You used /] ;START OUTPUT
DECOUT RSTMOV ;SPECIFY NUMBER OF TURNS USED
STROUT [ASCIZ/ turn/] ;TYPE
SOSE RSTMOV ;EXACTLY 1?
CHROUT "s" ;NO, MAKE PLURAL
STROUT [ASCIZ/ to regain your strength.
/] ;FINISH
RET ;DONE
RSTMON: MOVX T1,UF.OKM ;GET FLAG
IORM T1,U.FLAG(U) ;REMEMBER WE CAN GO ANY DIRECTION
MOVE T3,U.POWR(U) ;GET OUR STRENGTH
CALL UNLOCK ;UNLOCK THE FILE
MOVE T1,RSTMOV ;GET TIME USED
IMULI T1,^D50 ;SCALE IT
DISMS ;WAIT PROPER TIME
STROUT [ASCIZ/
While you were resting /] ;GET TEXT
HRRZ T1,MONTXT(T4) ;THEN ADDRESS
CALL TTYSTR ;OUTPUT MONSTER NAME
STROUT [ASCIZ/ came into the room!! Your strength only reached /]
DECOUT T3 ;TYPE STRENGTH
STROUT [ASCIZ/.
/] ;FINISH IT
RET ;DONE
RSTNOP: CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
You can't rest with /] ;START
HRRZ T1,MONTXT(T4) ;GET STRING
CALL TTYSTR ;TYPE MONSTER
STROUT [ASCIZ/ in the room!!
/] ;FINISH IT
RET ;DONE
RSTKEY: XWD 1,1 ;TABLE
AC MAXIMUM,0 ;ONE KEYWORD
;HERE TO TRY TO FIX US AFTER A MOVE IS MADE:
DOFIX: MOVEI T1,PWRMAX ;GET MAXIMUM STRENGTH
TDNN ZR,R.ROOM(R) ;ROOM ZERO?
MOVEM T1,U.POWM(U) ;YES, RESET MAXIMUM STRENGTH
MOVE T1,U.POWR(U) ;GET OUR STRENGTH
CAML T1,U.POWM(U) ;REACHED MAXIMUM?
RET ;YES, DONE
MOVEI T1,3 ;GET RANDOM NUMBER
CALL RANDOM ;TO SEE IF WE GET FIXED
JUMPE T1,FIXYES ;YES, GO FIX US A LITTLE
MOVEI T1,IT.FIX ;NO, GET CODE FOR MAGIC RING
CALL GETITU ;FIND OUT IF WE HAVE ONE
SKIPE T2 ;DO WE?
FIXYES: AOS U.POWR(U) ;YES, FIX US A LITTLE
RET ;DONE
SUBTTL COMMAND TO USE A MAGIC ITEM
;THIS COMMAND LETS THE PLAYER USE THE MAGIC ITEM OF HIS CHOICE. SOME
;OF THEM ARE IN USE BY JUST BEING CARRIED. BUT OTHERS, SUCH AS THE
;TELEPORATION RING AND MAGIC SHOVEL HAVE TO BE USED TO WORK.
CMDUSE: CALL PARITM ;READ WHAT THE ITEM IS
SKIPGE I,T4 ;SAVE ITEM AND SEE IF GOLD
ERROR (,,The only thing you can do with gold is collect it.)
CALL LOCK ;LOCK UP THE FILE
MOVE T1,I ;GET READY
CALL GETITU ;SEE IF WE HAVE ANY OF THIS ITEM
SKIPN T2 ;DO I HAVE ONE?
ERROR (,,You do not have one of those to use.) ;NO
CAIN I,IT.SHV ;THE MAGIC SHOVEL?
JRST USESHV ;YES, GO DIG
CAIN I,IT.TEL ;TELEPORTATION RING?
JRST USETEL ;YES, GO TELEPORT
CAIE I,IT.WD1 ;A MAGIC WAND?
CAIN I,IT.WD2 ;WELL?
JRST ISWAND ;YES
CAIE I,IT.WD3 ;WELL?
CAIN I,IT.WD4 ;WELL?
ISWAND: ERROR (,,Waving the magic wand does nothing.)
ERROR (,,You use that item just by having it.) ;NO
;HERE TO USE THE TELEPORTATION RING:
USETEL: MOVE T1,R.ROOM(R) ;GET CURRENT ROOM
EXCH T1,U.TELP(U) ;SET AS THE SPECIAL ROOM, GET OLD ONE
JUMPE T1,TELNO ;IF NO OLD ONE, DO NOTHING SPECIAL
CAMN T1,R.ROOM(R) ;IN THE SAME ROOM?
JRST TELNO ;YEP, THAT IS A LOSER
ANDI T1,-1 ;KEEP ONLY THE ROOM NUMBER
CALL ENTER ;ENTER THAT ROOM NOW
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
Your ring glows brightly, and in an instant you are whisked into another room.
/]
JRST LOOKVR ;GO LOOK AROUND
TELNO: CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
Your ring glows brightly, but nothing else happens.
/] ;SAY THIS
RET ;AND RETURN
;HERE TO DIG WITH THE MAGIC SHOVEL:
USESHV: MOVEI T1,DR.BLK ;GET BLOCKED KIND OF DOOR
CALL FNDDOR ;SEE IF ANY OF THOSE ARE HERE
SKIPN T1 ;ANY BLOCKED DOORS?
ERROR (,,The walls around here are too hard to dig through.)
MOVEI T1,5 ;GET NICE NUMBER
CALL RANDOM ;TO SEE IF WE SUCCEED THIS TIME
JUMPE T1,SHVSRC ;GO IF SO
ERROR (,,You are making some progress in digging.)
SHVSRC: MOVEI T1,DIRMAX ;GET MAXIMUM DIRECTIONS READY
CALL RANDOM ;PICK ONE
SKIPN DORTAB(T1) ;IS THIS DIRECTION A CAVED-IN DOOR?
JRST SHVSRC ;NO, LOOK SOME MORE
MOVE T4,T1 ;REMEMBER DIRECTION
ADDI T1,R.DIRS(R) ;POINT TO ADDRESS
HRLOI T2,DR.ALW ;GET NORMAL DOOR TYPE
MOVEM T2,(T1) ;CHANGE CAVED IN DOOR TO NORMAL ONE!
MOVE T1,R.LEVL(R) ;GET LEVEL
CAMN T1,H.LEVL ;IS THIS ROOM IN THE LAST LEVEL?
AOS H.LGRW ;YES, BUMP GROWING DOORS
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
You opened up the cave-in that was in the /] ;START THE OUTPUT
STROUT @DORTXT(T4) ;TYPE DOOR DIRECTION
STROUT [ASCIZ/ wall!!!
/] ;FINISH
RET ;DONE
SUBTTL COMMAND TO KILL MONSTERS
;THIS COMMAND IS USED TO ATTEMPT TO KILL A MONSTER. BESIDES ADDING
;TO YOUR SCORE, KILLING MONSTERS IS NECESSARY TO GET TREASURE, CROSS
;THE ROOM, OR EXAMINE THE ROOM. IF A BATTLE IS NOT COMPLETED, THEN
;THE FR.KIL FLAG IS SET, WHICH WILL DEFAULT THE COMMAND TO "KILL"
;FOR EASE IN FINISHING OFF THE MONSTER.
CMDKIL: NOISE (MONSTERS) ;DO NOISE
CONFRM ;THEN CONFIRM THE LINE
AUTOKL: TXO F,FR.KIL ;PUT US INTO AUTO-KILL MODE
CALL LOCK ;LOCK UP THE FILE
SKIPN T1,R.MONS(R) ;ANY MONSTER IN THIS ROOM?
ERROR (<TRZ F,FR.KIL>,,There is nothing to attack here.)
HRRZM T1,MONTYP ;SAVE KIND OF MONSTER
CALL ATTACK ;SEE HOW WELL WE CRUMP THE MONSTER
JRST KILLOS ;WE GOT CRUMPED, GO DAMAGE US
SKIPN T3,T1 ;SAVE DAMAGE
ERROR (,,Your blow missed completely.) ;NONE
MOVN T4,T1 ;NEGATE DAMAGE
ADDB T4,R.MONH(R) ;DECREMENT HITS LEFT OF MONSTER
JUMPLE T4,DIDKIL ;JUMP IF WE FINISHED IT OFF
CALL UNLOCK ;UNLOCK THE FILE
DOCRLF ;START WITH A CRLF
MOVE T1,[XWD -STRWNU,STRWIN] ;POINT TO TABLE
MOVE T2,T3 ;GET STRENGTH
CALL GIVSTR ;TYPE IT
MOVEI T1,[ASCIZ/The /] ;GET TEXT
CAILE T4,^D8 ;STRONG MONSTER STILL?
MOVEI T1,[ASCIZ/However, the /] ;YES
CALL TTYSTR ;TYPE STRING
MOVE T1,MONTYP ;GET TYPE
HRRZ T1,MONTXT(T1) ;THEN TEXT
CALL MONOUT ;TYPE THE MONSTER NAME
STROUT [ASCIZ/ is /] ;THEN THIS
MOVE T1,[XWD -STRMNU,STRMON] ;POINT TO TABLE
MOVE T2,T4 ;GET STRENGTH
CALL GIVSTR ;OUTPUT IT
DOCRLF ;FINISH WITH A CRLF
RET ;DONE
;HERE IF WE FINISHED OFF THE MONSTER:
DIDKIL: TXZ F,FR.KIL ;WE ARE OUT OF AUTO-KILL MODE NOW
SETZM R.MONS(R) ;KILL OFF THE MONSTER
SETZM R.MONH(R) ;CLEAR THIS TOO
MOVE T4,MONTYP ;GET WHAT KIND OF MONSTER WAS KILLED
SKIPL MONTXT(T4) ;KIND OF MONSTER TO HAVE TREASURE?
JRST MONNOT ;NO, SKIP ON
MOVEI T1,2 ;GET A CHANCE
CALL RANDOM ;COMPUTE IT
JUMPE T1,MONNOT ;GO ON IF NO TREASURE ANYWAY
MOVEI T1,R.KILF(R) ;GET ADDRESS OF FLAGS
CALL BITSET ;GENERATE INDEX AND MASK
TDNE T2,(T1) ;GOTTEN TREASURE FROM A MONSTER HERE?
JRST MONNOT ;YES, NO MORE
IORM T2,(T1) ;NOW WE HAVE
HLRZ T1,MONPWR(T4) ;GET DEFENSE STRENGTH
ADD T1,MONPWR(T4) ;ADD OFFENSE POWER
ANDI T1,-1 ;KEEP ONLY RIGHT HALF
IMULI T1,^D10 ;SCALE IT
MOVE T2,R.LEVL(R) ;GET LEVEL
IMULI T2,^D50 ;SCALE TREASURE FOR LEVEL
ADD T1,T2 ;ADD TO TOTAL
ADDM T1,R.VTRE(R) ;GIVE TREASURE TO ROOM
CALL RANDOM ;COMPUTE RANDOM AMOUNT
ADDM T1,R.VTRE(R) ;GIVE SOME MORE TOO RANDOMLY
MONNOT: MOVEI T1,R.HIDF(R) ;GET READY
CALL BITSET ;TO SEE IF WE KNOW INVISIBLE TREASURE
TDNN T2,(T1) ;KNOW ABOUT INVISIBLE TREASURE?
TDZA T3,T3 ;NO, GET ZERO
MOVE T3,R.HTRE(R) ;YES, GET IT
ADD T3,R.VTRE(R) ;ADD VISIBLE TO GET TOTAL
AOS R.MONK(R) ;BUMP HOW MANY MONSTERS KILLED HERE
SOS H.MONS ;DECREMENT TOTAL MONSTERS IN CAVE
AOS U.MONK(U) ;ADD TO NUMBER WE HAVE KILLED
CALL UNLOCK ;RELEASE THE FILE
STROUT [ASCIZ/
Congratulations!! You have killed /] ;TYPE SOME
STROUT @MONTXT(T4) ;SAY WHAT WE KILLED
STROUT [ASCIZ/!!! /] ;FINISH TEXT
SKIPN T3 ;ANY TREASURE GUARDED BY MONSTER?
DOCRLF ;NO, TYPE A CRLF
JUMPE T3,CPOPJ ;DONE IF NO TREASURE
STROUT [ASCIZ/The monster was guarding /] ;YES, TYPE SOME
MOVE T1,T3 ;GET NUMBER
CALL GOLOUT ;OUTPUT HOW MUCH
STROUT [ASCIZ/!!
/] ;FINISH TEXT
RET ;RETURN SAYING BATTLE FINISHED
;HERE IF THE MONSTER HAS DAMAGED US, TO SEE WHAT HAPPENS AND DO IT:
KILLOS: SETZM DRPCNT ;ASSUME DROPPING NOTHING
MOVE T3,T1 ;SAVE AMOUNT OF DAMAGE
MOVE T4,U.POWR(U) ;GET CURRENT STRENGTH
SUB T4,T1 ;GET NEW STRENGTH
JUMPLE T4,KILDIE ;GO ON IF WE JUST DIED
MOVEM T4,U.POWR(U) ;SAVE NEW STRENGTH
MOVE T1,U.LEVL(U) ;GET OUR LEVEL
IMUL T1,T4 ;MULTIPLY BY CURRENT STRENGTH
IMULI T1,TREMAX ;AND BY CONSTANT
SUB T1,U.CTRE(U) ;SUBTRACT WHAT WE ARE CARRYING
JUMPGE T1,KILNOD ;GO ON IF DON'T HAVE TO DROP ANYTHING
ADDM T1,U.CTRE(U) ;DROPPING NECESSARY, REDUCE AMOUNT CARRIED
MOVM T1,T1 ;GET AMOUNT OF TREASURE DROPPED
ADDM T1,R.VTRE(R) ;GIVE IT TO ROOM
MOVEM T1,DRPCNT ;AND REMEMBER FOR TYPEOUT
KILNOD: MOVEI T1,5 ;GET NICE NUMBER
CALL RANDOM ;MAKE CHANCE
SKIPN T1 ;TIME TO REDUCE MAXIMUM?
SOS U.POWM(U) ;YES, REDUCE IT BY ONE
CALL UNLOCK ;UNLOCK THE FILE
DOCRLF ;START WITH A CRLF
MOVE T1,[XWD -STRLNU,STRLOS] ;POINT TO TABLE
MOVE T2,T3 ;COPY HIT
CALL GIVSTR ;TYPE DAMAGE
MOVEI T1,[ASCIZ/However, you are /] ;GET TEXT
CAIGE T4,^D50 ;HOW GOOD?
MOVEI T1,[ASCIZ/You are /] ;OTHER TEXT
CALL TTYSTR ;OUTPUT IT
MOVE T1,[XWD -STRUNU,STRUS] ;POINT TO TABLE
MOVE T2,T4 ;COPY STRENGTH
CALL GIVSTR ;OUTPUT IT
SKIPN T4,DRPCNT ;DROPPED ANY TREASURE?
DOCRLF ;NO, TYPE CRLF
JUMPE T4,CPOPJ ;DONE IF NO TREASURE
STROUT [ASCIZ/Because you were weakened, you have had to drop /]
MOVE T1,T4 ;GET AMOUNT
CALL GOLOUT ;OUTPUT IT
STROUT [ASCIZ/.
/] ;END THE TEXT
RET ;DONE
;HERE IF THE MONSTER HAS KILLED US OFF. WHAT A FATE! WE GET MOVED
;BACK TO ROOM ZERO WITHOUT OUR TREASURE, AND HAVE TO START OVER.
KILDIE: TXZ F,FR.KIL ;THIS UNDOES KILL MODE
MOVE T1,U.CTRE(U) ;GET ALL OUR TREASURE
SETZM U.CTRE(U) ;REMOVE IT
ADDM T1,R.VTRE(R) ;AND DROP IT IN THE ROOM
AOS R.DIES(R) ;ONE MORE DEATH IN THIS ROOM
SETZM U.BACK(U) ;UNABLE TO GO BACKWARDS NOW
SETZM U.ROOM(U) ;BLAST US BACK TO ROOM ZERO
MOVEI R,ROMADR ;AND RESET POINTER TO ROOM
AOS U.TURN(U) ;THIS COUNTS AS A TURN
GTAD ;GET CURRENT TIME
MOVEM T1,U.LDAT(U) ;UPDATE WHEN WE LAST PLAYED
AOS T1,U.DIES(U) ;INCREMENT NUMBER OF DEATHS FOR US
MOVE T4,T1 ;SAVE FOR OUTPUT LATER
IMULI T1,5 ;SCALE IT
MOVN T1,T1 ;NEGATE IT
ADDI T1,^D55 ;REDUCE FROM 55%
CAIGE T1,^D20 ;GETTING LOW?
MOVEI T1,^D20 ;YES, KEEP A MINIMUM
MOVEM T1,U.POWR(U) ;UPDATE OUR STRENGTH
MOVEI T1,PWRMAX ;GET MAXIMUM STRENGTH
MOVEM T1,U.POWM(U) ;AND RESET IT
CALL UNLOCK ;UNLOCK THE FILE
CAIN T4,1 ;FIRST DEATH?
STROUT [ASCIZ/
&That last blow was too much for you!!!! Everything turns black and
you slide into death. Fortunately, a compassionate spirit admires
your deeds, and decides to restore your life. So you unexpectedly
awaken back above ground at the entrance to the dungeon. You are still
weak, however, and should not fight too much for awhile.&
/]
CAIN T4,2 ;TWICE?
STROUT [ASCIZ/
&Again you have gotten yourself killed!!!! Once again, the world
goes black and the same stupid compassionate spirit restores your
life. You once again awaken at the entrance, and this time you
are even weaker than last time.&
/]
CAIN T4,3 ;THREE TIMES?
STROUT [ASCIZ/
&For the third time, you have been killed. And for the third time,
you are reincarnated, even weaker than before.&
/]
CAILE T4,3 ;MORE TIMES?
STROUT [ASCIZ/
&Another death for you!! Fortunately that friendly (but stupid) spirit
never gives up. Aren't you glad!!&
/]
RET ;AND RETURN
SUBTTL ROUTINE TO COMPUTE DAMAGE TO/FROM A MONSTER
;CALLED TO RETURN THE AMOUNT OF DAMAGE THAT WE HAVE DONE TO A
;MONSTER, OR THAT IT HAS DONE TO US. DAMAGE IS ALWAYS IN THE RANGE
;ZERO TO FIVE. RETURNS:
; +1: T1/ AMOUNT OF DAMAGE MONSTER DID TO US
; +2: T1/ AMOUNT OF DAMAGE WE DID TO MONSTER, MAYBE NONE
ATTACK: MOVEI T1,^D11 ;GET READY
CALL RANDOM ;GET A RANDOM NUMBER
SUBI T1,5 ;REDUCE AROUND ZERO
MOVE T4,U.LEVL(U) ;GET OUR LEVEL
SUB T4,R.LEVL(R) ;AND SUBTRACT LEVEL OF MONSTER
CAILE T4,4 ;MAKE SURE IT MAKES SENSE
MOVEI T4,4 ;SO FIX IT
CAMGE T4,[EXP -4] ;MAKE SURE
HRROI T4,-4 ;IF NOT FIX IT
ADD T4,T1 ;ADD INTO TOTAL
SKIPGE T4 ;DO WE ATTACK OR BE ATTACKED?
SKIPA T1,[EXP IT.ARM] ;GET ATTACKED, GET ARMOR CODE
MOVEI T1,IT.SWD ;ATTACK, GET SWORD CODE
CALL GETITU ;GET HOW MANY WE HAVE
SKIPE T2 ;DO WE HAVE MAGIC HELP IN BATTLES?
ADDI T4,1 ;YES, MAKE ODDS BETTER FOR US
CAILE T4,5 ;NOW MAKE SURE IN GOOD RANGE
MOVEI T4,5 ;NO, FIX IT
CAMGE T4,[EXP -5] ;WELL?
HRROI T4,-5 ;FIX IT
SKIPL T1,T4 ;MOVE TO RIGHT AC AND SEE IF WE WIN
JRST CPOPJ1 ;YES, SKIP RETURN
MOVM T1,T1 ;WE GET HURT, NEGATE IT
RET ;AND RETURN
SUBTTL SUBROUTINE TO OUTPUT A STRENGTH TEXT
;CALLED TO GIVE THE STATUS OF A MONSTER OR US, OR THE AMOUNT OF
;DAMAGE THAT WE RECEIVED. CALL:
; T1/ -NUMBER OF ENTRIES,,ADDRESS OF TABLE OF TEXTS
; T2/ STRENGTH
;PRESERVES T2.
GIVSTR: HLRZ T3,(T1) ;GET NEXT STRENGTH
CAMN T2,T3 ;EXACT MATCH?
AOJA T1,GIVSTH ;YES, GO USE IT
CAML T2,T3 ;LESS?
AOBJN T1,GIVSTR ;NO, KEEP LOOKING
GIVSTH: HRRZ T1,-1(T1) ;GET ADDRESS
JRST TTYSTR ;OUTPUT TEXT
SUBTTL COMMAND TO ROB ANOTHER PLAYER
;THIS COMMAND IS USED TO SWIPE TREASURE OR MAGIC ITEMS FROM ANOTHER
;PLAYER IN THE SAME ROOM AS YOURSELF. WHAT ITEM OR TREASURE GETS
;SWIPED IS RANDOM. A PARTICULAR PERSON CAN ONLY BE ROBBED ONCE BETWEEN
;MOVES, TO PREVENT HIM BEING TOTALLY TRASHED IF HE ISN'T PLAYING.
CMDROB: NOISE (THE PLAYER) ;DO NOISE
CALL PARUSR ;READ IN THE USER NAME
MOVEM T2,TEMP ;REMEMBER WHO WE ARE ROBBING
CONFRM ;THEN CONFIRM THE LINE
CALL TELROB ;TELL ABOUT ANY ROBBERIES
CALL LOCK ;LOCK UP THE DUNGEON
MOVE T1,TEMP ;GET BACK USER
CAMN T1,PLYUSR ;TRYING TO ROB MYSELF?
ERROR (,,You cannot rob yourself!!!) ;YES, LOSE
CALL FNDUSR ;LOOK FOR HIM
ERROR (,,There is no such player in this cave.) ;FAILED
MOVE I,T2 ;SAVE POINTER TO HIS DATA
MOVE T1,U.ROOM(I) ;GET ROOM HE IS IN
CAME T1,U.ROOM(U) ;MAKE SURE IN SAME ROOM AS US
ERROR (,,That player is not here with you.) ;NOPE
SKIPN T1 ;IN ROOM ZERO?
ERROR (,,The ghost police of Teser Nigeb prevent you from robbing anyo
ne here!)
SKIPE R.MONS(R) ;ANY MONSTERS HERE?
ERROR (,,You cannot rob anybody while there is a monster here!)
SKIPE U.ROBR(I) ;HAS HE ALREADY BEEN ROBBED?
ERROR (,,The player was ready for another attempt at robbery and fends
off your efforts.)
SKIPN T1,U.CTRE(I) ;DOES HE HAVE ANY TREASURE ON HIM?
JRST ROBITM ;NO, GO TRY FOR ITEMS
CAILE T1,^D10 ;ENOUGH TREASURE TO TAKE ONLY PART OF IT?
IDIVI T1,3 ;YES, GET 1/3 OF IT
CAILE T1,^D100 ;IF A SMALL AMOUNT TOTAL GET IT ALL
CALL RANDOM ;THEN MAKE RANDOM AMOUNT
JUMPE T1,NOROB ;FAIL TO ROB IF ZERO
MOVE T2,PLYUSR ;GET WHO I AM
MOVEM T2,U.ROBR(I) ;REMEMBER THAT HE WAS ROBBED BY ME
MOVN T4,T1 ;NEGATE AMOUNT
ADDM T4,U.CTRE(I) ;REDUCE HIS TREASURE
ADDM T1,U.CTRE(U) ;AND GIVE IT TO US
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
You have robbed the poor victim of /] ;START OUTPUT
MOVN T1,T4 ;GET BACK AMOUNT OF GOLD SWIPED
CALL GOLOUT ;OUTPUT IT
STROUT [ASCIZ/!!
/] ;FINISH
RET ;DONE
ROBITM: SKIPN U.ITEM(I) ;DOES HE HAVE ANY ITEMS TO SWIPE?
ERROR (,,The player has nothing to steal!) ;NO
MOVEI T4,^D10 ;YES, GET NUMBER OF TRIES
ROBLOP: MOVEI T1,ITMNUM ;NUMBER OF ITEMS POSSIBLE
CALL RANDOM ;PICK ONE RANDOMLY
CALL GETITU ;SEE HOW MANY WE HAVE ALREADY
CAIN T2,ITMMSK ;CAN WE CARRY ANY MORE?
JRST ROBNXT ;NO, TRY AGAIN
EXCH I,U ;POINT AT HIM TEMPORARILY
CALL GETITU ;THEN SEE HOW MANY HE HAS
JUMPN T2,ROBYES ;GO FINISH UP IF HE HAS SOME
EXCH U,I ;HE'S EMPTY, SWAP BACK POINTERS
ROBNXT: SOJG T4,ROBLOP ;TRY AGAIN
NOROB: ERROR (,,Your attempt at robbery failed!!) ;COMPLAIN
ROBYES: MOVE T3,PLYUSR ;GET WHO I AM
MOVEM T3,U.ROBR(U) ;REMEMBER I ROBBED HIM (AC U IS HIM HERE)
SUBI T2,1 ;ONE LESS ITEM
CALL PUTITU ;UPDATE NUMBER HE HAS
EXCH I,U ;RESTORE CORRECT POINTERS
CALL GETITU ;GET NUMBER OF THEM WE HAVE
ADDI T2,1 ;WE GET ONE MORE
CALL PUTITU ;GIVE IT TO US
MOVE T4,T1 ;REMEMBER ITEM NUMBER
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
The player was carrying no treasure, but you did get /] ;START OUTPUT
HRRZ T1,ITMTAB(T4) ;GET ADDRESS OF TEXT
CALL TTYSTR ;OUTPUT IT
STROUT [ASCIZ/ instead!!
/] ;FINISH
RET ;DONE
SUBTTL SUBROUTINE TO TELL ABOUT ROBBERIES
;CALLED ON EVERY NON-STATUS COMMAND TO SEE IF WE HAVE BEEN ROBBED,
;AND IF SO, TO OUTPUT THAT INFORMATION. THIS OUTPUT OCCURS BEFORE
;THE NORMAL ACTIONS OF A COMMAND.
TELROB: SKIPN U.ROBR(U) ;HAVE WE BEEN ROBBED?
RET ;NO, NOTHING TO DO
CALL LOCK ;YES, LOCK UP THE FILE
MOVE T4,U.ROBR(U) ;GET WHO ROBBED US
SETZM U.ROBR(U) ;CLEAR IT SO WE CAN BE ROBBED AGAIN
CALL UNLOCK ;UNLOCK FILE AGAIN
JUMPE T4,CPOPJ ;RETURN IF WE LOST THE RACE
STROUT [ASCIZ/
You have been robbed by /] ;OUTPUT SOME
MOVE T1,T4 ;GET USER
CALL USROUT ;OUTPUT WHO IT WAS
STROUT [ASCIZ/ while you were not looking!!!
/] ;FINISH IT
RET ;DONE
SUBTTL SUBROUTINE TO PARSE A USER NAME
;ROUTINE TO READ IN A USER NAME, AND RETURN THE USER NUMBER. IT
;IS POSSIBLE TO READ IN A NONEXISTANT USER NUMBER BY THE USE OF
;A NUMBER-SIGN. RETURNS USER NUMBER IN T2.
PARUSR: CMMD [FLDDB. (.CMTOK,,<-1,,[ASCIZ/#/]>,,,[FLDDB. (.CMUSR)])]
TSC T3,T3 ;SEE WHICH ONE MATCHED
JUMPN T3,CPOPJ ;DONE IF WAS USER NUMBER
CMMD [FLDDB. (.CMNUM,,^D8)] ;WAS NUMBER SIGN, GET NUMBER
TLNN T2,-1 ;TOO LARGE?
SKIPN T2 ;OR ZERO?
ERROR (,,Illegal user number specified.) ;YES
HRLI T2,USRLH ;IT'S OK, FINISH USER NUMBER
RET ;DONE
SUBTTL COMMAND TO SAY SOMETHING
;THIS COMMAND IS USED TO SAY SOME MAGIC WORD WHICH HOPEFULLY HAS
;A NICE EFFECT FOR THE PLAYER. MAGIC WORDS CAN RETURN THE PLAYER
;TO THE BEGINNING OF THE DUNGEON, OPEN DOORS, OR SLAY MONSTERS,
;AS EXAMPLES.
CMDSAY: NOISE (THE MAGIC WORDS) ;PROMPT HIM
CMMD [FLDDB. (.CMTXT)] ;READ REST OF LINE
MOVSI T1,-SAYNUM ;GET READY FOR A LOOP
SAYSRC: MOVEM T1,SAYIDX ;REMEMBER IT
CALL @SAYTAB(T1) ;SEE IF THIS ROUTINE USES THE PHRASE
SKIPA T1,SAYIDX ;NO, GET INDEX BACK
RET ;YES, RETURN
AOBJN T1,SAYSRC ;NO, TRY NEXT ROUTINE
STROUT [ASCIZ/
Nothing happens here.
/] ;NOBODY WANTED IT, SAY THIS
RET ;AND RETURN
;TABLE OF ROUTINES TO PARSE A PHRASE, IN THE ORDER SPECIFIED. IF A
;ROUTINE USES THE PHRASE, IT DOES WHAT ACTIONS AND TYPEOUT IT DESIRES,
;AND THEN SKIP RETURNS. OTHERWISE IT NON-SKIPS.
SAYTAB: EXP SAYJNK ;SAY ONE OF THE OLD MAGIC WORDS
EXP SAYBEG ;SAY "TESER NIGEB" AND GO TO BEGINNING
EXP SAYROM ;SAY MAGIC WORD IN THIS ROOM
SAYNUM==.-SAYTAB ;NUMBER OF ROUTINES
;ROUTINES TO CHECK THE VARIOUS CASES:
SAYBEG: MOVEI T1,[ASCIZ/TESER NIGEB/] ;GET STRANGE MAGIC PHRASE
CALL PHRASE ;DOES THIS MATCH?
RET ;NO, DON'T DO ANYTHING
TDNN ZR,R.ROOM(R) ;SAYING IT IN ROOM ZERO?
JRST BEGZER ;YES, SPECIAL
CALL LOCK ;LOCK UP THE DATA FILE
MOVE T1,U.CTRE(U) ;GET ALL OF OUR TREASURE
PUSH P,T1 ;SAVE FOR LATER
SETZM U.CTRE(U) ;ZERO WHAT WE HAVE
ADDM T1,R.VTRE(R) ;GIVE IT TO THE CURRENT ROOM
MOVEI T1,PWRMAX ;GET FULL STRENGTH
MOVEM T1,U.POWM(U) ;AND FIX US ALL UP
MOVEI T1,0 ;GET ROOM ZERO
CALL ENTER ;MOVE THERE
CALL UNLOCK ;UNLOCK THE FILE NOW
DOCRLF ;TYPE A CRLF FIRST
STROUT [ASCIZ/&As you complete the magic words, a bluish haze
forms around you, and you quickly pass out. When you awaken, you
find yourself back above ground at the entrance of the dungeon. /] ;TYPE
POP P,T1 ;RESTORE TREASURE DROPPED
SKIPE T1 ;WAS ANY?
STROUT [ASCIZ/&(By the way, you notice that you are no longer
carrying any treasure!!) /] ;YES, SAY SOME MORE
DOCRLF ;DO ONE
JRST CPOPJ1 ;AND GIVE SUCCESSFUL RETURN
BEGZER: STROUT [ASCIZ/
A slight breeze kicks up some dust for a minute. But that's all.
/] ;SAY SOMETHING STRANGE
JRST CPOPJ1 ;GOOD RETURN
SAYROM: SKIPN T1,R.WORD(R) ;DOES THIS ROOM HAVE A MAGIC WORD?
RET ;NO, FORGET IT THEN
CALL MAKWRD ;YES, EXPAND INTO THE PHRASE
MOVEI T1,MAGTXT ;POINT TO BUFFER
CALL PHRASE ;MATCH WHAT HE TYPED?
RET ;NOPE, IGNORE IT
CALL FAULT ;PUT ALL OF THE FILE IN CORE
CALL LOCK ;THEN LOCK UP THE FILE
MOVN S,H.ROOM ;GET READY FOR SEARCH
HRLZ S,S ;BUILD AOBJN POINTER
IORI S,ROMADR ;FINISH IT
MOVSI I,-MOVMAX ;GET STORAGE POINTER READY
MAGSRC: CAIN R,(S) ;THIS SAME ROOM?
JRST MAGSRN ;YES, SKIP IT
SKIPE T1,R.WORD(S) ;THIS ROOM HAVE A MAGIC WORD TOO?
CAME T1,R.WORD(R) ;AND MATCH THIS ROOM'S WORD?
JRST MAGSRN ;NO, LOOK AT NEXT ROOM
MOVE T1,R.LEVL(S) ;GET LEVEL OF THE ROOM
SUB T1,R.LEVL(R) ;SUBTRACT CURRENT LEVEL
MOVM T1,T1 ;GET DIFFERENCE
CAILE T1,2 ;WITHIN A FEW LEVELS OF EACH OTHER?
JRST MAGSRN ;NO, SKIP IT
MOVEI T1,R.VISF(S) ;POINT TO VISIT FLAGS
CALL BITSET ;GET TEST READY
TDNN T2,(T1) ;HAVE WE BEEN THERE BEFORE?
JRST MAGSRN ;NO, IGNORE THE ROOM
MOVEM S,MOVLST(I) ;FOUND A CANDIDATE, SAVE IT
AOBJP I,MAGSRD ;IF TOO MANY, STOP NOW
MAGSRN: ADDI S,ROMSIZ-1 ;MOVE TO NEXT ROOM
AOBJN S,MAGSRC ;AND CHECK IT OUT
MAGSRD: HRRZ T1,I ;GET NUMBER OF MATCHING ROOMS
JUMPE T1,SAYROF ;JUMP IF NONE
CALL RANDOM ;COMPUTE RANDOM NUMBER
HRRZ T1,MOVLST(T1) ;GET ADDRESS OF NEW ROOM
HRRZ T1,R.ROOM(T1) ;THEN GET ROOM NUMBER
CALL ENTER ;MOVE TO THAT ROOM
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
The room grows dim for an instant. Then you notice you have been moved!!
/] ;TYPE SOME
CALL LOOKVR ;LOOK AROUND
JRST CPOPJ1 ;AND SKIP RETURN
SAYROF: CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
The room seems to grow dim for an instant. But that's all.
/] ;SAY INTERESTING MESSAGE
JRST CPOPJ1 ;GOOD RETURN
SAYJNK: MOVSI I,-JNKNUM ;GET READY FOR A LOOP
HLRZ T1,JNKTAB(I) ;GET THE PHRASE TO CHECK
CALL PHRASE ;DOES IT MATCH?
AOBJN I,.-2 ;NO, KEEP SEARCHING
JUMPGE I,CPOPJ ;RETURN IF NO MATCH
HRRZ T1,JNKTAB(I) ;GET RESPONSE
CALL TTYSTR ;TYPE IT
JRST CPOPJ1 ;AND SKIP RETURN
DEFINE JK(TXT1,TXT2),<
XWD [ASCIZ/TXT1/],[ASCIZ/
TXT2
/]
>
JNKTAB: JK PLUGH,<A hollow voice says, "Good try, but no cigar.">
JK XYZZY,<You see a vision of a little dwarf throwing an axe at you
, but it quickly fades.>
JK Y2,<A small rock hits you on the head, with "Y2" scribbled on it
.>
JK ABRACADABRA,<You rise 5 feet off the ground, and then slowly set
tle back down.>
JK OPEN SESAME,<You hear doors opening and closing in the distance.
>
JNKNUM==.-JNKTAB ;NUMBER OF PHRASES
;SUBROUTINE TO PARSE A STRING TO SEE IF IT MATCHES WHAT THE USER TYPED.
;THE USER'S STRING IS IN THE ATOM BUFFER. CALL:
; T1/ ADDRESS OF STRING TO CHECK AGAINST
;RETURNS:
; +1: NO MATCH
; +2: PHRASE MATCHED.
;
;THIS ROUTINE IGNORES EXTRA SPACES. ALL TEMP AC'S AND "C" USED.
;LOWER CASE IS TRANSLATED TO UPPER CASE.
PHRASE: HRLI T1,(POINT 7,) ;FINISH BYTE POINTER TO TEST STRING
MOVE T2,[POINT 7,ATMBUF] ;POINT TO THE ATOM BUFFER
MOVEI C," " ;INITIALIZE LAST "MATCH"
PHRLP1: ILDB T3,T1 ;GET NEXT CHAR OF TEST STRING
PHRLP2: ILDB T4,T2 ;GET NEXT CHAR OF USER STRING
CAIL T4,"A"+40 ;LOWER CASE LETTER?
CAILE T4,"Z"+40 ;WELL?
SKIPA ;NO
SUBI T4,40 ;YES, TURN TO UPPER CASE
CAME T3,T4 ;MATCH?
JRST PHRDIF ;NO, GO SEE WHY
SKIPE C,T3 ;YES, SAVE LAST MATCH
JRST PHRLP1 ;AND PROCEED IF NON-NULL
JRST CPOPJ1 ;OTHERWISE THEY MATCHED
PHRDIF: SKIPE T3 ;DIFFERENCE MAYBE OK IF TEST STRING DONE
CAIN C," " ;OR IF LAST MATCH WAS A SPACE
CAIE T4," " ;BUT CURRENT USER CHAR HAS TO BE SPACE
RET ;NO, STRINGS DIFFER THEN
JRST PHRLP2 ;YES, CHECK NEXT CHAR THEN
SUBTTL COMMAND TO GIVE STATUS OF MYSELF
;CALLED TO OUTPUT WHAT I AM CARRYING, HOW STRONG I AM, AND
;WHERE I AM IN THE DUNGEON. ALL OF THE NICE STUFF WHICH THE
;RANDOM PLAYER WANTS TO KNOW ABOUT MYSELF.
CMDSTS: NOISE (ABOUT MYSELF) ;DO NOISE
CONFRM ;AND CONFIRM THE LINE
TXNE F,FR.PLY ;ARE WE PLAYING?
JRST DOSTS ;YES, PROCEED
CALL FILOPN ;NOPE, OPEN UP THE DATA FILE
MOVE T1,PLYUSR ;GET WHO WE ARE
CALL FNDUSR ;LOOK FOR ME
ERROR (,,You are not in this cave.) ;FAILED
MOVE U,T2 ;OK, SET UP POINTER
DOSTS: STROUT [ASCIZ/
Status for player /] ;START THE OUTPUT
MOVE T1,U.USER(U) ;GET WHO WE ARE
CALL USROUT ;TYPE THE NAME
STROUT [ASCIZ/ at /] ;MORE OUTPUT
HRROI T1,TMPBUF ;POINT TO TEMPORARY BUFFER
SETO T2, ;TIME RIGHT NOW
SETZ T3, ;NORMAL OUTPUT
ODTIM ;OUTPUT IT
STROUT TMPBUF ;THEN TYPE THE TEXT
STROUT [ASCIZ/
Current room: /] ;START IT OUT
SKIPN T4,U.ROOM(U) ;IN ROOM ZERO?
STROUT [ASCIZ/Entrance/] ;YES, SAY SO
SKIPE T1,T4 ;GET NUMBER
CALL TTYDEC ;OUTPUT IT IF NONZERO
JUMPE T4,STSCON ;PROCEED IF AT ENTRANCE
STROUT [ASCIZ/ in level /] ;TYPE MORE
DECOUT R.LEVL(R) ;OUTPUT LEVEL OF CURRENT ROOM
STSCON: STROUT [ASCIZ/
Strength: /] ;START OUTPUT
DECOUT U.POWR(U) ;TYPE THE STRENGTH
STROUT [ASCIZ/ out of /] ;MORE
DECOUT U.POWM(U) ;TYPE MAXIMUM
STROUT [ASCIZ/
Reincarnations: /] ;SAY HOW MANY TIMES WE DIED
SKIPN T4,U.DIES(U) ;GET COUNT OF DEATHS
STROUT [ASCIZ/None/] ;NONE, SAY SO
SKIPE T1,T4 ;MOVE TO RIGHT AC
CALL TTYDEC ;OUTPUT IF NONZERO
STROUT [ASCIZ/
Maximum level: /] ;MORE OUTPUT
DECOUT U.LEVL(U) ;TYPE IT
STROUT [ASCIZ/
Treasure carried: /] ;START NEXT LINE
SKIPN T4,U.CTRE(U) ;ANY TREASURE?
STROUT [ASCIZ/None/] ;NO, SAY SO
SKIPE T1,T4 ;WELL?
CALL TTYDEC ;TYPE NUMBER
STROUT [ASCIZ/ out of /] ;MORE
MOVE T1,U.LEVL(U) ;GET LEVEL
IMUL T1,U.POWR(U) ;MULTIPLY BY POWER
IMULI T1,TREMAX ;AND BY SCALE FACTOR
CALL GOLOUT ;OUTPUT IT
STROUT [ASCIZ/
Safe treasure: /] ;MORE
MOVE T4,U.STRE(U) ;GET SAFE TREASURE
DECOUT T4 ;TYPE IT
STROUT [ASCIZ/ for a score of /] ;MORE
MOVE T1,T4 ;GET TREASURE READY
MOVE T2,U.TURN(U) ;AND NUMBER OF TURNS
CALL TTYFI1 ;OUTPUT IT
STROUT [ASCIZ/
Magic items: /] ;START THE OUTPUT
SKIPN T4,U.ITEM(U) ;ANY MAGIC ITEMS BEING CARRIED?
STROUT [ASCIZ/None
/] ;NO, SAY SO
JUMPE T4,CPOPJ ;IF NONE, ALL DONE
TXZ F,FR.TMP ;CLEAR TEMPORARY USE FLAG
MOVSI T4,-ITMNUM ;GET READY FOR A LOOP
STSITL: HRRZ T1,T4 ;GET CODE
CALL GETITU ;SEE IF WE HAVE ANY
JUMPE T2,STSITN ;NO, SKIP ON
TXOE F,FR.TMP ;YES, NEED PRECEEDING TEXT?
STROUT [ASCIZ/ /] ;YES, DO IT
HRRZ T1,ITMTAB(T4) ;GET ADDRESS
CALL TTYSTR ;OUTPUT NAME
CAIN T2,1 ;MORE THAN ONE?
JRST STSITO ;NO, SKIP ON
STROUT [ASCIZ/ (/] ;YES, START MORE
DECOUT T2 ;TYPE NUMBER
CHROUT ")" ;FINISH
STSITO: DOCRLF ;DO A CRLF
STSITN: AOBJN T4,STSITL ;LOOP UNTIL DONE
RET ;DONE
SUBTTL COMMAND TO LIST THE STATUS OF THE DUNGEON
;THIS COMMAND IS USED TO LIST THE STATUS OF THE DUNGEON AND ALL
;PLAYERS IN IT.
CMDLST: NOISE (STATUS OF) ;NOISE
CMMD [FLDDB. (.CMKEY,,LSTKEY,,<EVERYONE>)]
HRRE T4,(T2) ;GET RESULT
MOVEM T4,LSTFLG ;AND SAVE IT
CONFRM ;THEN CONFIRM THE LINE
CALL FILOPN ;OPEN UP THE DATA FILE
SKIPN LSTFLG ;WANT TO LIST EVERYONE?
JRST LSTALL ;YES, GO DO IT
TXNE F,FR.PLY ;JUST US, ARE WE PLAYING?
JRST LSTME ;YES, GO SHOW US
MOVE T1,PLYUSR ;NOPE, GET WHO WE ARE
CALL FNDUSR ;LOOK FOR US
ERROR (,,You are not in this cave.) ;NOT THERE
MOVE U,T2 ;REMEMBER WHERE WE ARE
JRST LSTME ;THEN GO LIST ME
LSTKEY: XWD 2,2 ;TWO ENTRIES
AC EVERYONE,0 ;ALL PLAYERS
AC MYSELF,1 ;JUST ME
LSTALL: STROUT [ASCIZ/
Status of dungeon created on /] ;GET SOME STRING
DATOUT H.DATE ;TYPE DATE DUNGEON WAS BUILT
STROUT [ASCIZ/
Rooms: /] ;GET READY
MOVE T1,H.ROOM ;GET NUMBER OF ROOMS
SUBI T1,1 ;ACCOUNT FOR THE ENTRANCE
DECOUT T1 ;THEN TYPE IT
STROUT [ASCIZ/, Highest level: /] ;MORE
DECOUT H.LEVL ;TYPE HIGHEST LEVEL
STROUT [ASCIZ/, Players: /] ;MORE TEXT
DECOUT H.PLRS ;TYPE HOW MANY PLAYERS EXIST
STROUT [ASCIZ/, Monsters: /] ;MORE
DECOUT H.MONS ;SAY HOW MANY
DOCRLF ;TYPE A CRLF
SKIPN H.PLRS ;ANY PLAYERS TO SHOW?
RET ;NO, DONE
LSTME: DOCRLF ;START WITH A CRLF
SKIPN LSTFLG ;SHOWING EVERYONE?
STROUT [ASCIZ/ /] ;YES, SPACE OVER SOME
STROUT [ASCIZ/ Room Turn Lev Treas /] ;START IT
TXNE F,FR.DEB ;DEBUGGING?
STROUT [ASCIZ/Carry /] ;YES, SAY HOW MUCH CARRIED
STROUT [ASCIZ/ Kill/] ;MORE
TXNE F,FR.DEB ;WELL?
STROUT [ASCIZ/ Bld/] ;YES, TYPE THIS
STROUT [ASCIZ/ Visit Entered Played Name
/] ;GET HEADER LINE
SKIPE LSTFLG ;WANT TO LIST JUST ME?
JRST LSTPLR ;YES, GO DO IT AND RETURN
PUSH P,U ;SAVE POINTER TO MY LOCATION
HRLZ U,H.PLRS ;GET NUMBER OF PLAYERS
MOVN U,U ;NEGATE IT
ADDI U,PLRADR ;RELOCATE TO RIGHT ADDRESS
PLRLOP: SKIPN U.USER(U) ;MAKE SURE WE HAVE A REAL USER
TXNE F,FR.DEB ;OR THAT WE ARE DEBUGGING
CALL LSTPLR ;SHOW DATA ON THIS PLAYER
ADDI U,PLRSIZ-1 ;MOVE TO NEXT PLAYER
AOBJN U,PLRLOP ;LOOP FOR THEM ALL
POP P,U ;RESTORE ORIGINAL POINTER
RET ;DONE
;HERE TO LIST THE STATUS OF A PARTICULAR PLAYER WHOSE DATA BLOCK
;IS POINTED TO BY AC "U":
LSTPLR: SKIPE LSTFLG ;LISTING ONLY MYSELF?
JRST NOFLME ;YES, SKIP SOME
MOVE T2,U.USER(U) ;GET USER NUMBER
CAME T2,PLYUSR ;IS THIS ME?
CHROUT " " ;NO, TYPE A SPACE
CAMN T2,PLYUSR ;WELL?
CHROUT "*" ;YES, SHOW ME
CHROUT " " ;EXTRA SPACE
NOFLME: SKIPN T4,U.ROOM(U) ;GET ROOM NUMBER
STROUT [ASCIZ/ home /] ;IF ENTRANCE, SAY SO
SKIPN T1,T4 ;GET AGAIN
JRST LSHOTH ;SKIP ON
CALL DECSP4 ;OUTPUT IT
CHROUT "/" ;THEN A SLASH
MOVE T1,U.ROOM(U) ;GET POINTER TO CURRENT ROOM
IMULI T1,ROMSIZ ;COMPUTE OFFSET
MOVE T4,ROMADR+R.LEVL(T1) ;THEN GET LEVEL
DECOUT T4 ;TYPE IT
CAIGE T4,^D10 ;TWO DIGITS?
CHROUT " " ;NO, TYPE SPACE
LSHOTH: MOVE T1,U.TURN(U) ;GET TURNS USED
CALL DECSP6 ;OUTPUT IT
MOVE T1,U.LEVL(U) ;GET LEVEL OF PLAYER
CALL DECSP3 ;OUTPUT IT
MOVE T1,U.STRE(U) ;GET SAFE TREASURE
MOVE T2,U.TURN(U) ;AND TURNS
CALL TTYFI3 ;OUTPUT TREASURE PER TURN
MOVE T1,U.CTRE(U) ;GET AMOUNT CARRIED
TXNE F,FR.DEB ;DEBUGGING?
CALL DECSP6 ;YES, SAY HOW MUCH
MOVE T1,U.MONK(U) ;GET NUMBER OF MONSTERS KILLED
CALL DECSP5 ;OUTPUT IT
MOVE T1,U.BLDR(U) ;GET NUMBER OF ROOMS BUILT
TXNE F,FR.DEB ;DEBUGGING?
CALL DECSP5 ;YES, OUTPUT IT
MOVE T1,U.NEWR(U) ;GET NUMBER OF ROOMS VISITED
CALL DECSP5 ;OUTPUT IT
CHROUT " " ;SPACE OVER
DATOUT U.BDAT(U) ;TYPE OUT DATE HE BEGAN EXPLORING
CHROUT " " ;THEN A SPACE
DATOUT U.LDAT(U) ;TYPE OUT DATE HE LAST PLAYED
STROUT [ASCIZ/ /] ;SPACE OVER
MOVE T1,U.USER(U) ;GET WHO THS GUY IS
CALL USROUT ;AND TYPE IT
DOCRLF ;FINISH WITH A CRLF
RET ;DONE
SUBTTL COMMANDS -- PLOT (LEVEL) LEVEL-NUMBER
;HERE TO PLOT THE ROOMS ON A SPECIFIED LEVEL. ONLY THOSE ROOMS THAT THE
;PLAYER HAS VISITED ARE PLOTTED, AND ONLY HIDDEN DOORS LEADING FROM ROOMS
;IN WHICH THE PLAYER HAS TYPED 'FIND'. THUS, THE MAP WILL SHOW ONLY AS
;MUCH OF THE LEVEL AS THE PLAYER IS ENTITLED TO SEE.
;FIRST, PARSE THE COMMAND AND VERIFY THE LEVEL. THE DEFAULT LEVEL NUMBER TO PLOT
;IS THE LEVEL IN WHICH THE PLAYER IS. TO BE IN A LEVEL REQUIRES THAT THE USER IS
;ACTUALLY A PLAYER. THEREFORE, WE REQUIRE THE PLAY COMMAND TO HAVE BEEN
;PREVIOUSLY TYPED. THIS NECESSARILY PRECLUDES A PLAYER FROM GETTING A PLOT
;WITHOUT ACTUALLY PLAYING.
CMDPLT: NOISE (ROOMS ON LEVEL);GIVE PLAYER SOME HELP
HRROI T1,DEFBUF ;BUILD DEFAULT STRING FOR LEVEL PLAYER IS IN
MOVE T2,R.LEVL(R) ; ..
MOVX T3,^D10 ; ..
NOUT ; ..
JFCL ;BETTER NOT FAIL
MOVEI T1,CMDBLK ;RESET COMND STATE BLOCK
CMMD DEFBLK ;PARSE DECIMAL LEVEL NUMBER
MOVE PL,T2 ;SAVE SPECIFIED LEVEL NUMBER
CONFRM ;END THE LINE
SKIPL PL ;RANGE CHECK FOR VALID LEVEL
CAMLE PL,H.LEVL ; ..
ERROR (,,There aren't that many levels in the dungeon.)
; ..
; ..
;THE CRITICAL REGION CONSISTS OF TWO PASSES OVER THE ROOMS IN THE CAVE. THE
;FIRST DETERMINES THE MINIMUM AND MAXIMUM X AND Y COORDINATES OF THE ROOMS TO BE
;PLOTTED. FROM THIS, THE SCALE FACTORS USED TO KEEP THE PLOT WITHIN THE BOUNDS
;OF THE PAPER ARE COMPUTED. THEN, THE SECOND PASS PLOTS EACH ROOM AND ITS DOORS.
;LOCKING THE CAVE AROUND BOTH PASSES PREVENTS MORE VALID ROOMS FROM SHOWING UP
;IN THE SECOND PASS, AND POSSIBLY EXCEEDING THE PAPER BOUNDARIES.
CALL FAULT ;DRAG IN ALL ROOMS FOR SPEED WHILE LOCKED
CALL LOCK ;LOCK UP THE CAVE FOR THE DURATION
DMOVE T1,[EXP SCLFST,SCLRST] ;SET UP PROCESSING ROUTINES
DMOVEM T1,RMGENS ; ..
CALL GENRMS ;GENERATE VALID ROOMS, CALLING PROCESSING RTNS
ERROR (,,You haven't visited any rooms on that level.) ;NONE
CALL PLTSCL ;COMPUTE SCALE FACTOR
DMOVE T1,[EXP PLTFST,PLTRST] ;SET UP PLOT PROCESSING ROUTINES
DMOVEM T1,RMGENS ; ..
SETZM PLTNUM ;INITIALIZE NUMBER OF ROOMS BEING PLOTTED
CALL GENRMS ;GENERATE VALID ROOMS, PLOTTING THIS TIME
FATAL (First pass of plot found rooms but second pass didn't.)
MOVE T1,XMAX ;PLOT TO LOWER RIGHT CORNER OF PLOT
MOVE T2,YMIN ; ..
SETZ T3, ; ..
CALL PLOT ; ..
CALL PLTCLS ;CLOSE THE PLOTTER FILE
CALL UNLOCK ;DONE WITH THE CAVE
STROUT [ASCIZ/
The plot contains /] ;TYPE SOME
DECOUT PLTNUM ;SAY HOW MANY ROOMS
STROUT [ASCIZ/ room/] ;TYPE MORE
MOVEI C,"s" ;GET AN S
SOSE PLTNUM ;ONLY 1 ROOM?
PUTCHR ;NOPE, SO MAKE IT PLURAL
STROUT [ASCIZ/.
/] ;FINISH
RET ;DONE COMPLETELY
DEFBLK: <FLD .CMNUM,CM%FNC>!CM%HPP!CM%DPP ;FUNCTION BLOCK FOR DEFAULT LEVEL NUMBER
^D10 ;DECIMAL RADIX
POINT 7,[ASCIZ /level of rooms to plot,/]
POINT 7,DEFBUF ;DEFAULT STRING (SET TO PLAYER'S LEVEL)
;GENRMS GENERATES ALL ROOMS THAT THE CURRENT PLAYER HAS BEEN TO SO FAR, AND
;CALLS ONE OF TWO ROUTINES WITH EACH ROOM.
;
;CALL:
; RMGENS+0/ ADDR OF ROUTINE FOR FIRST ROOM
; RMGENS+1/ ADDR OF ROUTINE FOR REST OF ROOMS
; PL/ LEVEL OF INTEREST
;
;CALLS THE TWO ROUTINES WITH PR POINTING TO THE CURRENT ROOM. GENRMS GIVES
;A NON-SKIP RETURN IF THERE ARE NO MATCHING ROOMS (HAVING CALLED NEITHER
;ROUTINE), A SKIP RETURN OTHERWISE.
GENRMS: MOVEI PR,ROMADR-ROMSIZ;START WITH THE FIRST ROOM
CALL GETROM ;GET FIRST MATCHING ROOM
RET ;NONE THERE
CALL @RMGENS+0 ;CALL FIRST ROOM ROUTINE
GENRM1: CALL GETROM ;GET NEXT MATCHING ROOM
JRST CPOPJ1 ;DONE
CALL @RMGENS+1 ;CALL REST OF ROOMS ROUTINE
JRST GENRM1 ;LOOP UNTIL NO MORE ROOMS
;GETROM SCANS FOR THE NEXT ROOM THAT IS ON THE LEVEL SPECIFIED IN PL, AND
;HAS BEEN VISITED BY THE PLAYER. GIVES NON-SKIP IF NO FURTHER ROOMS MATCH
;THESE CRITERIA, SKIP RETURN WITH PR POINTING TO THE ROOM IF SO.
GETROM: ADDI PR,ROMSIZ ;ADVANCE TO NEXT ROOM
MOVE T1,H.ROOM ;SEE IF WE'VE SCANNED ALL ROOMS YET
IMULI T1,ROMSIZ ; ..
CAIL PR,ROMADR(T1) ; ..
RET ;YES--NO MORE ROOMS
CALL CHKROM ;ALLOWED TO LOOK AT THIS ROOM?
JRST GETROM ;NO--LOOP FOR NEXT
JRST CPOPJ1 ;YES--RETURN AS CURRENT ROOM
;ALWROM GIVES A SKIP RETURN IF THE PLAYER IS ACTUALLY ALLOWED TO SEE THE CURRENT
;ROOM, REGARDLESS OF WHETHER THE ROOM WILL BE DRAWN IN THIS PLOT. CHKROM FURTHER
;RESTRICTS THE CHECK TO ROOMS THAT WILL ACTUALLY BE DRAWN.
CHKROM: CAME PL,R.LEVL(PR) ;IS THIS ROOM ON THE PROPER LEVEL?
RET ;NO--TRY NEXT ROOM
ALWROM: MOVEI T1,R.VISF(PR) ;HAS PLAYER BEEN HERE BEFORE?
CALL BITSET ; ..
TDNE T2,(T1) ; ..
JRST CPOPJ1 ;YES--THEN THIS IS A GOOD ROOM
TXNN F,FR.DEB ;DEBUGGING?
RET ;NO--DON'T ALLOW THIS ROOM
JRST CPOPJ1 ;YES--ALLOW ALL ROOMS ON THIS LEVEL
;SCLFST IS THE SCALING ROUTINE TO CALL WHEN THE FIRST MATCHING ROOM IS FOUND
;BY GENRMS. SIMPLY REMEMBER THE COORDINATES OF THIS ROOM.
SCLFST: MOVE T1,R.LOC(PR) ;GET LOCATION OF FIRST MATCHING ROOM
HLRZM T1,XMIN ;SET XMIN
HLRZM T1,XMAX ; AND XAMX
HRRZM T1,YMIN ;SET YMIN
HRRZM T1,YMAX ; AND YMAX
RET ;DONE
;SCLRST IS THE SCALING ROUTINE TO CALL FOR ALL OF THE REST OF THE ROOMS. THE
;COORDINATES OF THE CURRENT ROOM IS COMPARED WITH THE X AND Y MAXIMA AND MINIMA,
;EXPANDING THE RANGES IF NECESSARY. WHEN ALL ROOMS HAVE BEEN SEARCHED, THIS
;LEAVES THE BOUNDS OF THE PORTION OF THE CAVE TO BE PLOTTED IN ?MIN AND ?MAX.
SCLRST: HLRZ T1,R.LOC(PR) ;RECOMPUTE X BOUNDS
CAMGE T1,XMIN ; XMIN
MOVEM T1,XMIN ; ..
CAMLE T1,XMAX ; XMAX
MOVEM T1,XMAX ; ..
HRRZ T1,R.LOC(PR) ;RECOMPUTE Y BOUNDS
CAMGE T1,YMIN ; YMIN
MOVEM T1,YMIN ; ..
CAMLE T1,YMAX ; YMAX
MOVEM T1,YMAX ; ..
RET ;DONE
;PLTSCL IS CALLED AFTER THE FIRST PASS OVER THE ROOMS TO DETERMINE THE SCALE
;FACTOR FOR THE PLOT. THERE ARE TWO SPECIAL NOTES. FIRST, THE BOUNDS OF THE PLOT
;ARE INCREASED BY THE MAXIMUM POSSIBLE LENGTH OF A DOOR SO THAT DOORS LEADING
;FROM ROOMS AT THE EDGE OF THE PLOT WILL NOT EXCEED THE PAPER. SECOND, A SCALE
;FACTOR LARGER THAN 1.0 IS DECREASED TO 1.0 TO KEEP SMALL LEVELS FROM LOOKING
;REALLY GROSS.
PLTSCL: FLTR T3,[SFPMAX+CONMAX] ;COMPUTE MAX DOOR LENGTH - HALF ROOM SIZE
FSBRI T3,(0.5) ; ..
FLTR T1,XMIN ;FLOAT AND ADJUST X BOUNDS
FLTR T2,XMAX ; ..
FSBR T1,T3 ; ..
FADR T2,T3 ; ..
DMOVEM T1,XMIN ;SAVE BACK AS MINS AND MAXES
FLTR T1,YMIN ;FLOAT AND ADJUST Y BOUNDS
FLTR T2,YMAX ; ..
FSBR T1,T3 ; ..
FADR T2,T3 ; ..
DMOVEM T1,YMIN ;SAVE BACK AS MINS AND MAXES
FSBR T2,T1 ;COMPUTE RANGE OF Y'S
MOVX T1,FWIDTH ;NOW SCALE EVERYTHING TO FIT ON THE PAPER
FDVR T1,T2 ;T1 = SCALE FACTOR FOR PLOTTING
CAMLE T1,[1.0] ;PREVENT PLOTTING HUGE ROOMS
MOVX T1,1.0 ; ..
MOVEM T1,SCALE ;SAVE AS SCALE FACTOR
RET ;DONE SCALING
;PLTFST IS THE PLOTTING ROUTINE TO CALL WITH THE FIRST MATCHING ROOM. THE
;PLOTTER IS INITIALIZED, AND THEN THE FIRST ROOM IS PLOTTED.
PLTFST: CALL PLTINI ;INITIALIZE THE PLOTTER
; JRST PLTRST ;THEN SIMPLY PLOT THE FIRST ROOM
;PLTRST IS THE PLOTTING ROUTINE TO CALL FOR THE REST OF THE ROOMS. PLOT THE ROOM
;OUTLINE (A SQUARE BOX), THE ROOM NUMBER, AND ALL VISIBLE DOORS.
PLTRST: CALL PLTSET ;SET UP THIS ROOM'S COORDINATES
MOVSI I,-4 ;LOOP OVER ALL DIRECTIONS
PLTRS1: CALL PLTWAL ;PLOT A WALL IN THE CURRENT DIRECTION
MOVEI T1,R.DIRS(PR) ;SET UP ADDRESS OF LINK WORD FOR THIS DIRECTION
ADDI T1,(I) ; FOR SPEED LATER
MOVEM T1,MOVLNK ; ..
LDB T1,[POINTR @MOVLNK,DR%TYP] ;GET DOOR TYPE
CALL @PLTDOR(T1) ;DRAW THE PROPER DOOR
AOBJN I,PLTRS1 ;LOOP FOR NEXT DIRECTION, IF ANY LEFT
AOS PLTNUM ;ONE MORE ROOM PLOTTED
RET ;DONE
PLTWAL: DMOVE T1,[EXP 0.5,0.5];DRAW ONE WALL OF A UNIT BOX
MOVX T3,0 ; ..
CALL @PLTDIR(I) ; ..
DMOVE T1,[EXP 0.5,-0.5] ; ..
MOVX T3,1 ; ..
CALLRET @PLTDIR(I) ; ..
PLTSET: HLRZ T1,R.LOC(PR) ;COMPUTE X AND Y CENTER COORDINATES
HRRZ T2,R.LOC(PR) ; ..
FLTR T1,T1 ; ..
FLTR T2,T2 ; ..
DMOVEM T1,X ;SAVE FOR EASY REFERENCE
RET ;DONE (FOR NOW)
SUBTTL PLOT (LEVEL) LEVEL-NUMBER -- DOOR SELECTION ROUTINES
;PLTDOR IS A TABLE OF ROUTINE ADDRESSES INDEXED BY DOOR TYPE. EACH ROUTINE IS
;RESPONSIBLE FOR FIGURING OUT WHETHER A DOOR IS ALLOWED TO BE SHOWN FOR THIS
;PLAYER, AND IF SO, FOR PLOTTING THE DOOR.
PLTDOR: PLTUNK ;UNKNOWN DOOR (USUALLY A BUG)
PLTNEV ;NON-EXISTENT DOOR
PLTALW ;USUAL DOOR
PLTSRC ;SECRET (HIDDEN) DOOR
PLTLVL ;LEVEL DOOR
PLTWRD ;MAGIC WORD DOOR
PLTMAG ;MAGIC ITEM DOOR
PLTBLK ;BLOCKED (CAVED-IN) DOOR
PLTUNK: RET ;BUG DOOR. MAYBE SHOW FOR DEBUGGING SOME DAY
PLTNEV: RET ;NO DOOR--DONE
;HERE TO PLOT A REGULAR DOOR. THERE ARE SEVERAL CASES. IF THERE IS NO CONNECTING
;ROOM, OR THE PLAYER IS NOT ENTITLED TO SEE THE CONNECTING ROOM, THEN WE SIMPLY
;INDICATE THAT THERE IS A DOOR, BUT NOT WHERE IT GOES. OTHERWISE, WE DRAW THE
;COMPLETE DOOR, EVEN IF THE CONNECTING ROOM WILL NOT BE DRAWN (THIS ALLOWS
;PLAYERS TO PLOT PIECES OF LEVELS AND TAPE THE PLOTS TOGETHER TO GET A GOOD
;SCALE FACTOR).
PLTALW: HRRZ T1,@MOVLNK ;IS THERE A CONNECTING ROOM?
CAIN T1,-1 ; ..
CALLRET PLTST1 ;NO--DRAW STUB DOOR
PUSH P,PR ;YES--RELOCATE TO THE CONNECTING ROOM
PUSH P,X ; ..
PUSH P,Y ; ..
IMULI T1,ROMSIZ ; ..
MOVEI PR,ROMADR(T1) ; ..
XORI I,1 ; (REMEMBER TO TURN DIRECTION AROUND)
CALL PLTSET ;COMPUTE NEW COORDINATES OF THIS ROOM
CALL ALWROM ;ALLOWED TO VIEW THIS ROOM?
CALLRET PLTSTB ;NO--DRAW STUB DOOR
CALL CHKROM ;ARE WE GOING TO PLOT THE CONNECTING ROOM?
JRST PLTAL1 ;NO--THEN DRAW THE DOOR
CAML PR,-2(P) ;YES--THEN ONLY DRAW THE DOOR IN ONE DIRECTION
JRST [CALL PLTBAK ;WE WILL DRAW (OR HAVE DRAWN) DOOR
RET] ; ..
PLTAL1: DMOVE T1,[EXP 0.5,0.0];WE CAN SHOW THE DOOR--START AT
MOVX T3,0 ; CONNECTING ROOM AND DRAW A DOOR
CALL @PLTDIR(I) ; FROM THE PROPER WALL TO THE PROPER
CALL PLTBAK ; WALL IN THE ORIGINAL ROOM
DMOVE T1,[EXP 0.5,0.0]; ..
MOVX T3,1 ; ..
CALLRET @PLTDIR(I) ; ..
;HERE TO PLOT A STUBBY DOOR. THIS REFLECTS THE FACT THAT A PLAYER KNOWS THAT
;THERE IS A DOOR, BUT DOES NOT KNOW WHERE IT GOES. THIS OCCURS, FOR INSTANCE, IF
;THE PLAYER CAN SEE THE DOOR IN THE CURRENT ROOM, BUT IS NOT ALLOWED TO SEE (HAS
;NOT VISITED) THE CONNECTING ROOM.
PLTSTB: CALL PLTBAK ;GET BACK TO ORIGINAL ROOM
PLTST1: DMOVE T1,[EXP 0.5,0.0];DRAW JUST A SHORT (STUBBY) LINE
MOVX T3,0 ; ..
CALL @PLTDIR(I) ; ..
DMOVE T1,[EXP 1.0,0.0]; ..
MOVX T3,1 ; ..
CALLRET @PLTDIR(I) ; ..
;HERE TO PLOT A SECRET DOOR. WE DETERMINE WHETHER TO DRAW NOTHING, A STUB DOOR,
;OR A REAL DOOR BY EITHER PLOTTING NOTHING, OR REDUCING THE PROBLEM TO A REGULAR
;DOOR.
PLTSRC: MOVEI T1,R.SRCF(PR) ;HAS PLAYER SEARCHED HERE?
CALL BITSET ; ..
TDNE T2,(T1) ; ..
CALLRET PLTALW ;YES--THEN JUST LIKE A REGULAR DOOR
HRRZ T1,@MOVLNK ;NO--SEE IF SEARCHED IN CONNECTING ROOM
CAIN T1,-1 ; (SEARCHED THERE IMPLIES VISITED THERE TOO)
RET ; (NO CONNECTING ROOM--SHOW NOTHING)
IMULI T1,ROMSIZ ; ..
ADDI T1,ROMADR+R.SRCF; ..
CALL BITSET ; ..
TDNN T2,(T1) ; ..
RET ;NOT VISIBLE THERE EITHER--SHOW NOTHING
CALLRET PLTALW ;VISIBLE THERE--TREAT AS USUAL DOOR
;HERE TO PLOT A LEVEL-CHANGE DOOR. SINCE WE ARE ONLY CONCERNED WITH ROOMS ON THE
;CURRENT LEVEL, WE MERELY INDICATE THE LEVEL CHANGE WITH AN ARROW.
PLTLVL: DMOVE T1,[EXP 0.5,0.5] ;DRAW AN ARROW TO INDICATE LEVEL CHANGE
MOVX T3,0 ; ..
CALL @PLTDIR(I) ; ..
DMOVE T1,[EXP 1.0,0.0]; ..
MOVX T3,1 ; ..
CALL @PLTDIR(I) ; ..
DMOVE T1,[EXP 0.5,-0.5] ; ..
MOVX T3,1 ; ..
CALLRET @PLTDIR(I) ; ..
PLTWRD: RET ;FOR NOW
PLTMAG: RET ;FOR NOW
;HERE TO PLOT A CAVED-IN (BLOCKED) DOOR. THIS LOOKS LIKE A STUBBY DOOR WITH AN
;EXTRA LINE INDICATING THE BLOCKAGE.
PLTBLK: DMOVE T1,[EXP 0.5,0.0];PLOT A CAVED-IN DOOR
MOVX T3,0 ; ..
CALL @PLTDIR(I) ; ROTATING IT TO PROPER DIRECTION
DMOVE T1,[EXP 1.0,0.0]; ..
MOVX T3,1 ; ..
CALL @PLTDIR(I) ; ..
DMOVE T1,[EXP 1.0,.25]; ..
MOVX T3,0 ; ..
CALL @PLTDIR(I) ; ..
DMOVE T1,[EXP 1.0,-0.25] ; ..
MOVX T3,1 ; ..
CALLRET @PLTDIR(I) ; ..
;PLTBAK IS USED AFTER RELOCATING TO THE CONNECTING ROOM, TO GET BACK TO THE
;ORIGINAL ROOM.
PLTBAK: POP P,T1 ;SAVE RETURN ADDRESS
POP P,Y ;RESTORE ROOM PARAMETERS
POP P,X ; ..
POP P,PR ; ..
XORI I,1 ; (TURN DOOR AROUND)
JRST (T1) ;DONE
SUBTTL PLOT (LEVEL) LEVEL-NUMBER -- DOOR ROTATION ROUTINES
;PLTDIR IS A TABLE OF ROUTINE ADDRESSES INDEXED BY DIRECTION (EAST, NORTH, SOUTH
;OR WEST). EACH ROUTINE HAS THE SAME ARGUMENTS AS PLOT, EXCEPT THAT THE X AND Y
;COORDINATES ARE RELATIVE TO THE CENTER OF THE ROOM BEING PLOTTED, AND THAT
;WHATEVER IS BEING PLOTTED IS IN THE EAST DIRECTION. EACH ROUTINE THEN ROTATES
;THE COORDINATES TO THE PROPER DIRECTION, AND ADDS IN THE CENTER COORDINATES OF
;THE CURRENT ROOM.
PLTDIR: PLOT.N ;ROTATE TO NORTH
PLOT.S ;ROTATE TO SOUTH
PLOT.E ;ROTATE TO EAST (NOT MUCH WORK)
PLOT.W ;ROTATE TO WEST
PLOT.E: FADR T1,X ;ALREADY ROTATED--OFFSET TO CURRENT ROOM
FADR T2,Y ; ..
CALLRET PLOT ;PLOT THE POINT
PLOT.N: EXCH T1,T2 ;ROTATE TO NORTH
MOVNS T1 ; ..
FADR T1,X ;OFFSET TO CURRENT ROOM
FADR T2,Y ; ..
CALLRET PLOT ;PLOT THE POINT
PLOT.S: EXCH T1,T2 ;ROTATE TO SOUTH
MOVNS T2 ; ..
FADR T1,X ;OFFSET TO CURRENT ROOM
FADR T2,Y ; ..
CALLRET PLOT ;PLOT THE POINT
PLOT.W: MOVNS T1 ;ROTATE TO WEST
MOVNS T2 ; ..
FADR T1,X ;OFFSET TO CURRENT ROOM
FADR T2,Y ; ..
CALLRET PLOT ;PLOT THE POINT
SUBTTL BASIC PLOTTING ROUTINES
;PLOT IS THE LOW-LEVEL PLOTTING ROUTINE FOR DRAWING LINES. PLTINI SHOULD BE
;CALLED PRIOR TO ANY PLOTTING, THEN THE CALL IS:
;
; T1/ X COORDINATE
; T2/ Y COORDINATE
; T3/ PEN POSITION (0 FOR UP, 1 FOR DOWN)
; XMIN/ LOWEST POSSIBLE X COORDINATE (FOR SCALING)
; YMIN/ LOWEST POSSIBLE Y COORDINATE (FOR SCALING)
; SCALE/ MULTIPLICATIVE SCALE FACTOR
;
;THE TWO COORDINATES SHOULD BE SINGLE-PRECISION FLOATING-POINT NUMBERS, AND
;REPRESENT THE COORDINATE TO PLOT TO. BOTH ARE SCALED THROUGH CAVE'S INTERNAL
;SCALE FACTORS TO FIT THE PLOT ON THE PAPER.
;
;THE ALGORITHM USED IS BASICALLY THE FOLLOWING:
;
; 1. SEE IF THE REQUESTED STATE OF THE PEN IS DIFFERENT FROM ITS CURRENT
; STATE, AND IF SO, CHANGE IT.
; 2. SCALE THE X AND Y COORDINATES TO FIT IN THE BOUNDS OF THE PLOTTING
; PAPER, THEN CONVERT TO PAPER INCREMENT COORDINATES.
; 3. DETERMINE THE (AT MOST) TWO INCREMENTS TO BE USED TO DRAW THE LINE. THIS
; WILL ALWAYS BE AN ON-AXIS INCREMENT AND (POSSIBLY) A COMBINED INCREMENT
; (E.G., +X+Y).
; 4. LOOP ALONG THE MAJOR AXIS (THE ONE WITH THE MAXIMUM ABSOLUTE COORDINATE
; OF THE VECTOR REPRESENTING OUR MOTION), SELECTING THE PROPER OF THE TWO
; INCREMENTS.
;
;THIS IS ESSENTIALLY THE SAME ALGORITHM AS THE ONE USED BY FOROTS, EXCEPT THAT
;YOU GET COMMENTS.
PLOT: CAMN T3,OLDPEN ;DO WE NEED A PEN CHANGE?
JRST PLOT1 ;NO--DON'T BOTHER
MOVEM T3,OLDPEN ;YES--REMEMBER NEW PEN STATE
PUSH P,T2 ;SAVE Y
MOVE T2,[EXP XY%UP,XY%DWN](T3) ;GET PLOTTER COMMAND FOR PEN STATE
CALL PUTPLT ;SEND THE COMMAND
POP P,T2 ;RESTORE Y
PLOT1: FSBR T1,XMIN ;SCALE X TO FIT THE PAPER
FMPR T1,SCALE ; ..
FMPRI T1,(FSTEPS) ;TURN INTO PLOTTER INCREMENTS
FIXR T1,T1 ;ROUND TO NEAREST INTEGER
FSBR T2,YMIN ;SCALE Y TO FIT THE PAPER
FMPR T2,SCALE ; ..
FMPRI T2,(FSTEPS) ;TURN INTO PLOTTER INCREMENTS
FIXR T2,T2 ;ROUND TO NEAREST INTEGER
SUB T1,OLDIX ;COMPUTE X VECTOR COMPONENT
ADDM T1,OLDIX ; AND SAVE NEW LOCATION AS OLD
SUB T2,OLDIY ;COMPUTE Y VECTOR COMPONENT
ADDM T2,OLDIY ; AND SAVE NEW LOCATION AS OLD
MOVX T3,XY%MX ;ASSUME WE'LL USE -X INCREMENTS
SKIPL T1 ;SEE IF SO
MOVX T3,XY%PX ;NO--WE'LL USE +X INCREMENTS
MOVX T4,XY%MY ;ASSUME WE'LL USE -Y INCREMENTS
SKIPL T2 ;SEE IF SO
MOVX T4,XY%PY ;NO--WE'LL USE +Y INCREMENTS
MOVMS T1 ;COMPUTE MAXIMUM ABSOLUTE COMPONENT OF VECTOR
MOVMS T2 ; WHICH DETERMINES MAJOR AXIS
CAMG T2,T1 ; AND PUT IT AND ITS INCREMENT FIRST
JRST PLOT2 ; ..
EXCH T1,T2 ; ..
EXCH T3,T4 ; ..
PLOT2: OR T4,T3 ;USE COMBINED INCREMENT AND ONE ASSOCIATED
; WITH MAJOR AXIS
DMOVEM T3,TWODIR ;SAVE THE INCREMENTS FOR LATER
JUMPE T1,PLOTDN ;DONE IF MAJOR AXIS COMPONENT = 0 (BOTH = 0)
JUMPN T2,PLOT3 ;IF MINOR AXIS COMPONENT = 0
SETZM MININC ;THEN NO INCREMENT TO MINOR AXIS PER UNIT
JRST PLOT4 ; MAJOR AXIS INCREMENT
PLOT3: FLTR T3,T1 ;ELSE COMPUTE INCREMENT TO MINOR AXIS PER
FLTR T4,T2 ; UNIT MAJOR AXIS INCREMENT
FDVR T4,T3 ; WHICH IS SLOPE, SORT OF
MOVEM T4,MININC ; ..
PLOT4: DMOVE T3,T1 ;PUT AXIS COUNTERS IN SAFE ACS
MOVX T1,0.5 ;INITIALIZE MINOR AXIS COUNTER
PLOT5: FADR T1,MININC ;SEE HOW FAR WE GO IN MINOR DIRECTION
MOVE T2,TWODIR+0 ;ASSUME WE ONLY INCREMENT MAJOR AXIS
CAML T1,[1.0] ;SEE IF SO
JRST [FSBRI T1,(1.0) ;NO, WE INCREMENT BOTH THIS TIME
MOVE T2,TWODIR+1 ; SO SET UP COMBINED INCREMENT
SOJA T4,.+1] ; AND ACCOUNT FOR MINOR AXIS
CALL PUTPLT ;MOVE THE PLOTTER
SOJG T3,PLOT5 ;COUNT ANOTHER MAJOR AXIS INCREMENT
PLOTDN: RET ;DONE WITH THIS LINE
;PLTINI INITIALIZES THE PLOTTER FILE BY OPENING IT UP, MAKING SURE IT'S REALLY
;A DISK, AND THEN SMASHING THE PEN INTO THE RIGHT SIDE OF THE PAPER TO ASSURE
;WE'RE ON THE RIGHT MARGIN.
PLTINI: MOVX T1,GJ%SHT!GJ%FOU;GET A NEW FILE
HRROI T2,[ASCIZ /CAVE.PLT/] ; ..
GTJFN ; ..
ERJMP PLTIN1 ;CAN'T--GO UNLOCK AND BOMB OUT
HRRZM T1,PJFN ;SAVE JFN FOR LATER
DVCHR ;SEE WHAT KIND OF DEVICE WE HAVE
LDB T1,[POINTR T2,DV%TYP] ; ..
CAIE T1,.DVDSK ;MUST BE A DISK
ERROR (,,Output can only go to a disk.) ;OTHERWISE YELL
MOVE T1,PJFN ;NOW OPEN THE FILE
MOVX T2,<<FLD 6,OF%BSZ>!OF%WR> ; ..
OPENF ; ..
ERJMP PLTIN1 ;CAN'T--GO UNLOCK AND BOMB OUT
MOVX T1,6*PAGSIZ ;INITIALIZE BUFFER COUNTS
MOVEM T1,PLTCNT ; ..
SETZM PLTTOT ; ..
MOVE T1,[POINT 6,PLTADR] ;INITIALIZE BUFFER BYTE POINTER
MOVEM T1,PLTPTR ; ..
HRLZ T1,PJFN ;INITIALIZE PAGE COUNTER
SUBI T1,1 ; SO AOS WILL WORK (OVERFLOW PROPERLY)
MOVEM T1,PLTPGN ; ..
MOVX T2,XY%UP ;START BY RAISING THE PEN
CALL PUTPLT ; ..
SETZM OLDPEN ;REMEMBER IT'S NOW RAISED
MOVSI T3,-IWIDTH*ISTEPS ;SMASH INTO EDGE OF PAPER
MOVX T2,XY%MY ; ..
CALL PUTPLT ; ..
AOBJN T3,.-1 ; ..
MOVSI T3,-ISTEPS/2 ;COME BACK OUT 1/2 INCH
MOVX T2,XY%PY ; ..
CALL PUTPLT ; ..
AOBJN T3,.-1 ; ..
SETZM OLDIX ;NOW WE'RE AT 0,0
SETZM OLDIY ; ..
RET ;DONE INITIALIZING THE PLOTTER
PLTIN1: HRROI T3,[ASCIZ /Can't initialize plotter file, /]
JRST JSFAIL ;UNLOCK CAVE AND PRINT REASON
;PLTCLS CLOSES THE PLOTTER FILE AT THE END OF THE PLOT, OR IF AN OUTPUT ERROR
;OCCURS. SINCE PMAP%'S WERE USED TO WRITE THE FILE, WE MUST SET THE END-OF-FILE
;POINTER MANUALLY. PLTTOT CONTAINS THE TOTAL NUMBER OF BYTES WRITTEN THROUGH THE
;LAST COMPLETE PAGE, AND PLTCNT ACCOUNTS FOR THE REST.
PLTCLS: SKIPN PLTCNT ;ANYTHING TO OUTPUT?
JRST PLTCLS1 ;NO--DON'T OUTPUT ANYTHING
MOVE T1,[.FHSLF,,PLTPAG] ;WRITE LAST OUTPUT BUFFER
AOS T2,PLTPGN ; TO PLOTTER FILE
MOVX T3,PM%RWX!PM%CNT+1 ; ..
SETZM PLTCNT ;PREVENT LOOPS IF LAST PAGE GETS ERROR
PMAP ; ..
ERJMP PUTPL2 ;NO LUCK--UNLOCK THE CAVE AND BOMB OUT
MOVX T1,<CF%NUD!<FLD .FBBYV,CF%DSP>> ;SET END-OF-FILE POINTER
HRR T1,PJFN ; ..
MOVX T2,FB%BSZ ; FIRST BYTE SIZE
MOVX T3,<FLD 6,FB%BSZ> ; ..
CHFDB ; ..
MOVX T1,<CF%NUD!<FLD .FBSIZ,CF%DSP>> ; NOW BYTE COUNT
HRR T1,PJFN ; ..
SETO T2, ; ..
MOVE T3,PLTTOT ; ..
ADDI T3,6*1000 ; COUNT A PARTIAL PAGE
SUB T3,PLTCNT ; ..
CHFDB ; ..
MOVE T1,PJFN ;CLOSE THE FILE
CLOSF ; ..
ERJMP . ;DON'T CARE
RET ;DONE
;PUTPLT WRITES THE PEN COMMANDS TO THE PLOTTER FILE. THE CALL IS:
;
; T2/ PLOTTER COMMAND
;
;SAVES ALL ACS, DOES NOT RETURN ON ERRORS.
PUTPLT: SOSGE PLTCNT ;ROOM FOR ANOTHER PEN COMMAND?
JRST PUTPL1 ;NO--WRITE CURRENT PAGE AND GET NEW ONE
IDPB T2,PLTPTR ;YES--WRITE BYTE
RET ;DONE
PUTPL1: PUSH P,T1 ;SAVE SOME ACS FOR PMAP
PUSH P,T2 ; ..
PUSH P,T3 ; ..
MOVE T1,[.FHSLF,,PLTPAG] ;WRITE OUTPUT BUFFER
AOS T2,PLTPGN ; TO PLOTTER FILE
MOVX T3,PM%RWX!PM%CNT+1 ; ..
PMAP ; ..
ERJMP PUTPL2 ;NO LUCK--UNLOCK THE CAVE AND BOMB OUT
MOVX T1,6*1000 ;RESET BYTE COUNTER
MOVEM T1,PLTCNT ; ..
ADDM T1,PLTTOT ; AND COUNT ANOTHER PAGE OF BYTES IN FILE
MOVE T1,[POINT 6,PLTADR] ;RESET BYTE POINTER
MOVEM T1,PLTPTR ; ..
POP P,T3 ;RESTORE SAVED ACS
POP P,T2 ; ..
POP P,T1 ; ..
CALLRET PUTPLT ;NOW GO WRITE THE PEN COMMAND
PUTPL2: MOVEI T3,[ASCIZ /Output error writing plotter file, /]
MOVX T1,.FHSLF ;GET THE REASON FOR FAILURE
GETER ; ..
HRRZ T4,T2 ;MAKE ARG FOR JEFAIL
CALL PLTCLS ;CLOSE THE PLOTTER FILE
JRST JEFAIL ;GO UNLOCK AND PRINT REASON
SUBTTL ERROR ROUTINES THAT BOMB THE CURRENT COMMAND
;JSFAIL IS CALLED WHEN A JSYS FAILS WHILE THE CAVE IS LOCKED. THE JSYS ERROR
;CODE IS SAVED, THE CAVE UNLOCKED, AND THEN THE MESSAGE PRINTED. THIS PREVENTS
;THE PLAYER FROM CAUSING THE TERMINAL TO HANG WHILE THE CAVE IS LOCKED. THE CALL IS:
;
; T3/ POINTER TO FIXED PART OF MESSAGE
JSFAIL: MOVX T1,.FHSLF ;GET LAST ERROR CODE
GETER ; ..
HRRZ T4,T2 ;SAVE OVER UNLOCK CALL
; JRST JEFAIL ;GO UNLOCK AND PRINT MESSAGES
;JEFAIL IS SIMILAR TO JSFAIL, BUT WHEN THE ERROR CODE IS ALREADY KNOWN. THE CALL IS:
;
; T3/ POINTER TO FIXED PART OF MESSAGE
; T4/ SYSTEM ERROR CODE OF REST OF MESSAGE
JEFAIL: CALL UNLOCK ;UNLOCK THE CAVE
HRROI T1,[ASCIZ /
? /] ;MAKE THIS AN ERROR
PSOUT ; ..
MOVE T1,T3 ;PRINT FIXED PART OF MESSAGE
PSOUT ; ..
MOVX T1,.PRIOU ;PRINT SYSTEM MESSAGE
MOVSI T2,.FHSLF ; ..
HRR T2,T4 ; ..
SETZ T3, ; ..
ERSTR ; ..
JFCL ;DON'T CARE HERE
JFCL ; ..
HRROI T1,[ASCIZ /
/] ;END THE MESSAGE AND ALSO A BLANK LINE
PSOUT ; ..
MOVE P,SAVEP ;UNWIND STACK TO COMMAND LEVEL
JRST GETCMD ;PROCESS A NEW COMMAND
SUBTTL FAULT -- PAGE IN ALL ROOMS
;THIS ROUTINE IS CALLED BEFORE LOCKING UP THE FILE IN CASES WHERE ALL
;THE ROOMS OF THE DUNGEON HAVE TO EXAMINED. THUS OTHER PLAYERS WILL NOT
;BE LOCKED OUT FOR A LONG TIME WHILE WE HAVE THE FILE LOCKED.
FAULT: MOVE T1,H.ROOM ;GET HIGHEST ROOM NUMBER
IMULI T1,ROMSIZ ;CONVERT TO LAST ADDRESS USED
ADDI T1,ROMADR ; ..
FLTLOP: SKIP (T1) ;TOUCH THIS PAGE TO BRING IT IN
SUBI T1,PAGSIZ ;BACK DOWN TO PREVIOUS PAGE
CAIL T1,MAPADR ;TOUCHED ALL PAGES YET?
JRST FLTLOP ;NO, KEEP GOING
RET ;YES, DONE
SUBTTL COMMANDS TO MANIPULATE PATHS
;THE DEFINE COMMAND. USED TO DEFINE A PATH NAME SO IT CAN BE TAKEN
;LATER.
CMDDEF: NOISE (PATH NAME) ;ASK WHAT WE WANT
CALL PARPTH ;READ IN A PATH NAME
SKIPN T2 ;WANTS ALL?
ERROR (,,You cannot define all names!) ;YEP, ILLEGAL
MOVEM T2,PTHNAM ;REMEMBER IT FOR AWHILE
NOISE (TO BE THE DIRECTIONS) ;MORE NOISE
CALL GETPTH ;READ IN LIST OF DIRECTIONS
CALL LOCK ;INTERLOCK THE FILE
MOVE T1,PTHNAM ;GET NAME OF PATH
SKIPN PTHCNT ;ANY DIRECTIONS SPECIFIED?
JRST UNPATH ;NO, GO REMOVE IT
CALL PTHADD ;DEFINE IT FOR LATER
ERROR (,,Not enough room to store this path.) ;FAILED
SKIPA ;OK
UNPATH: CALL PTHDEL ;DELETE THE PATH
CALL UNLOCK ;FREE UP FILE AGAIN
STROUT [ASCIZ/
OK.
/] ;SAY WE DID IT
RET ;DONE
;COMMAND TO DELETE PATH DEFINITIONS.
CMDDEL: NOISE (DEFINITION OF PATH) ;GET NOISE
CALL PARPTH ;GET IT
CONFRM ;CONFIRM THE LINE
CALL LOCK ;LOCK THE FILE
SKIPN T1,T2 ;MOVE AND SEE IF WANTS ALL NAMES DELETED
JRST DELALL ;YES
CALL PTHDEL ;NO, JUST DELETE THE NAMED PATH
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
OK.
/] ;DONE
RET ;RETURN
DELALL: SETZM U.PATN(U) ;CAN'T CONTINUE ANY PATH NOW
SETZM U.PATI(U) ;NO BYTE POINTER EITHER
SETZM U.PATH(U) ;CLEAR BEGINNING OF PATH DEFINITIONS
SETZM U.PATH+PTHMAX-1(U) ;AND LAST WORD JUST IN CASE
CALL UNLOCK ;UNLOCK
STROUT [ASCIZ/
All definitions cleared.
/] ;DONE
RET ;RETURN
;COMMAND TO TYPE OUT THE DEFINITION OF A PATH.
CMDTYP: NOISE (DEFINITION OF PATH NAME) ;NOISE
CALL PARPTH ;READ IT IN
MOVEM T2,PTHNAM ;SAVE IT FOR AWHILE
CONFRM ;CONFIRM THE LINE
CALL LOCK ;LOCK UP THE FILE
SKIPN T1,PTHNAM ;GET PATH NAME AND SEE IF ALL WANTED
JRST TYPALL ;YES, TYPE THEM ALL
CALL PTHSRC ;LOOK FOR THE NAME
ERROR (,,There is no such path defined.) ;FAILED
HLRZ T2,1(T1) ;GET LENGTH OF DATA
ADDI T2,MOVLST ;GET LAST WORD TO BLT TO
HRLZ T1,T1 ;PUT ADDRESS IN LEFT HALF
HRRI T1,MOVLST ;AND PLACE TO BLT TO
BLT T1,(T2) ;MOVE TO SAFE PLACE
CALL UNLOCK ;NOW UNLOCK THE FILE
DOCRLF ;START WITH A CRLF
STROUT [ASCIZ/Path /] ;START OUTPUT
MOVE T1,PTHNAM ;GET NAME
CALL TTYSIX ;TYPE IT IN SIXBIT
STROUT [ASCIZ/ is /] ;MORE OUTPUT
MOVE T4,[POINT PTHWID,MOVLST+1,17] ;SET UP POINTER
TXZ F,FR.TMP ;INITIALIZE TEMPORARY FLAG.
TYPPTL: ILDB T3,T4 ;GET NEXT DIRECTION
CAIN T3,PTHMSK ;END OF THE LIST?
JRST TYPPTF ;YES, GO FINISH
TXOE F,FR.TMP ;FIRST DIRECTION?
STROUT [ASCIZ/, /] ;NO, SPACE OVER
STROUT @DORTXT(T3) ;TYPE DIRECTION
JRST TYPPTL ;LOOP
TYPPTF: STROUT [ASCIZ/.
/] ;FINISH IT
RET ;DONE
;HERE TO LIST ALL THE PATHS WE KNOW ABOUT:
TYPALL: MOVSI I,-MOVMAX ;GET A COUNTER READY
MOVEI T1,U.PATH(U) ;POINT TO FIRST PATH NAME
TYPALN: CAILE T1,U.PATH+PTHMAX-2(U) ;MAKE SURE LEGAL
ERROR (,,Path definition format is bad.)
MOVE T2,0(T1) ;GET NAME OF PATH
MOVEM T2,MOVLST(I) ;SAVE AWAY
JUMPE T2,TYPALY ;GO ON IF DONE NOW
HLRZ T2,1(T1) ;GET LENGTH
ADDI T1,1(T2) ;MOVE TO NEXT NAME
AOBJN I,TYPALN ;LOOP
ERROR (,,Not enough storage for all path definitions.)
TYPALY: MOVEI T4,U.PATH+PTHMAX-1(U) ;GET LAST WORD
SUB T4,T1 ;REMEMBER HOW MANY FREE WORDS
CALL UNLOCK ;UNLOCK FILE
DOCRLF ;DO A CRLF
SKIPN MOVLST ;NO PATH NAMES?
STROUT [ASCIZ/No paths are defined. /] ;YEP
SKIPN MOVLST ;WELL?
JRST TYPFRE ;NONE, GO SAY WHAT IS FREE
STROUT [ASCIZ/Defined paths: /] ;START OUT
SETZB T3,LISOLD ;GET READY FOR LIST OUTPUT
TYPALZ: SKIPN MOVLST(T3) ;ALL DONE?
JRST TYPALX ;YES
HRLZ T1,T3 ;GET OFFSET READY
IORI T1,[MOVE T1,MOVLST(T1) ;GET ROUTINE TO GET NAME
JRST TTYSIX] ;AND OUTPUT IT
CALL DOLIST ;ADD TO LIST
AOJA T3,TYPALZ ;LOOP
TYPALX: CALL DOLISE ;END THE LIST
STROUT [ASCIZ/. /] ;TYPE PERIOD
TYPFRE: STROUT [ASCIZ/
Free words: /] ;GET READY
DECOUT T4 ;TYPE HOW MANY WORDS ARE FREE
DOCRLF ;FINISH WITH CRLF
RET ;DONE
;SUBROUTINE TO PARSE A PATH NAME WHICH IS A SIXBIT QUANTITY. RETURNS
;PATH NAME IN T2. IF THE SPECIAL PATH NAME "ALL" IS SPECIFIED, THEN
;ZERO IS RETURNED IN T2.
PARPTH: CMMD [FLDDB. (.CMFLD,CM%HPP+CM%SDH,,path name)] ;READ NAME
SETZ T2, ;START WITH NULL
MOVE T3,[POINT 6,T2] ;GET POINTER TO IT
MOVE T4,[POINT 7,ATMBUF] ;POINT TO ATOM BUFFER
PARPTL: ILDB C,T4 ;GET NEXT CHARACTER
JUMPE C,PARPTF ;NO MORE
TXNN T3,77B5 ;IS WORD FULL ALREADY?
ERROR (,,Path names can only have six characters.) ;YES
CAIL C,"A"+40 ;LOWER CASE?
CAILE C,"Z"+40 ;WELL?
SKIPA ;NO
SUBI C,40 ;YES, MAKE UPPER CASE
SUBI C," " ;CONVERT TO SIXBIT
IDPB C,T3 ;STORE IT
JRST PARPTL ;LOOP
PARPTF: SKIPN T2 ;VERIFY WE HAVE ONE
ERROR (,,Bad path name specified.) ;NO
CAMN T2,[SIXBIT/ALL/] ;IS IT THE SPECIAL "ALL" ONE?
SETZ T2, ;YES, CLEAR AC
RET ;DONE
SUBTTL COMMAND TO FOLLOW A PATH
;THIS COMMAND LETS THE USER FOLLOW A PATH WHICH HE HAS PREVIOUSLY
;DEFINED.
CMDFOL: NOISE (THE PATH) ;NOISE
CALL PARPTH ;READ THE PATH NAME
SKIPN T2 ;SEE IF SPECIFYING ALL
ERROR (,,You cannot follow all paths!) ;YES, ILLEGAL
MOVEM T2,PTHNAM ;SAVE FOR LATER
CONFRM ;CONFIRM THE LINE
CALL TELROB ;MENTION ANY ROBBERIES
CALL LOCK ;LOCK UP THE DATA FILE
MOVE T1,PTHNAM ;GET BACK NAME
CALL PTHSRC ;LOOK FOR IT
ERROR (,,There is no such path defined.) ;NOT FOUND
SETZM U.PATN(U) ;CLEAR ANY PREVIOUS PATH
MOVE T1,[POINT PTHWID,1,17] ;GET POINTER
MOVEM T1,U.PATI(U) ;REMEMBER POINTER INTO LIST
MOVE T1,PTHNAM ;GET BACK NAME
MOVEM T1,U.PATN(U) ;AND SET IT UP
MOVE T1,U.ROOM(U) ;GET CURRENT ROOM
MOVEM T1,U.PATR(U) ;AND SET AS ROOM TO PROCEED FROM
JRST DOPROC ;GO PROCEED FROM BEGINNING NOW
CMDPRO: NOISE (ALONG INTERRUPTED PATH) ;NOISE
CONFRM ;THEN CONFIRM THE LINE
CALL LOCK ;LOCK UP THE FILE
; JRST DOPROC ;FALL INTO MAIN CODE
;HERE TO DO THE WORK OF MOVING ALONG A PATH:
DOPROC: SKIPN T1,U.PATN(U) ;GET THE PATH NAME
ERROR (,,No path was being followed.) ;NONE, SAY SO
CALL PTHSRC ;LOOK FOR THE PATH
ERROR (<SETZM U.PATN(U)>,,The path to follow got lost!!)
SKIPN T2,U.PATI(U) ;GET BYTE POINTER INTO PATH
ERROR (<SETZM U.PATN(U)>,,I don't know where in the path you are!!)
ADD T1,T2 ;MAKE FINISHED POINTER
MOVEM T1,PTHBYT ;SAVE BYTE POINTER FOR LOOP
PROLOP: MOVE T4,U.PATR(U) ;GET ROOM WE SHOULD PROCEED FROM
CAME T4,U.ROOM(U) ;THE ONE WE ARE IN?
JRST PROBAD ;NO, COMPLAIN
ILDB T1,PTHBYT ;GET NEXT DIRECTION TO MOVE IN
CAIN T1,PTHMSK ;END OF THE PATH?
JRST PROFIN ;YES, GO FINISH UP
CALL DOMOVE ;TRY TO MOVE AS INDICATED
RET ;CANT, RETURN WITH MESSAGE TYPED
IBP U.PATI(U) ;DID IT, ADVANCE BYTE POINTER
MOVE T1,U.ROOM(U) ;GET NEW ROOM
MOVEM T1,U.PATR(U) ;SET AS ROOM TO PROCEED FROM
MOVE T1,PTHBYT ;GET READY TO PEEK AHEAD
ILDB T1,T1 ;TO SEE IF MORE TO DO
CAIN T1,PTHMSK ;WAS THAT THE LAST DIRECTION?
JRST PROFIN ;YES, STOP NOW
CALL NOTICE ;SEE IF WE SEE ANYTHING INTERESTING
JRST PROLOP ;NO, CONTINUE ON
MOVE T4,PTHBYT ;GET COPY OF POINTER
ILDB T4,T4 ;GET NEXT DIRECTION
CALL UNLOCK ;UNLOCK FILE
JRST INTRST ;GO SAY SOMETHING INTERESTING HERE
PROFIN: SETZM U.PATN(U) ;CLEAR PATH BEING FOLLOWED
SETZM U.PATI(U) ;AND BYTE POINTER
SETZM U.PATR(U) ;AND ROOM
CALL UNLOCK ;UNLOCK FILE
JRST LOOK ;THEN LOOK AROUND
PROBAD: CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
To proceed you first have to return to room /] ;START IT
DECOUT T4 ;SAY WHERE TO RETURN TO
STROUT [ASCIZ/.
/] ;FINISH TEXT
RET ;DONE
SUBTTL COMMANDS TO DO MOVEMENT
;HERE FOR THE NORTH, SOUTH, EAST, WEST, AND BACK-UP COMMANDS.
CMDMVN: SKIPA T2,[EXP DIR.N] ;GET DIRECTION FOR NORTH
CMDMVS: MOVEI T2,DIR.S ;OR FOR SOUTH
JRST SAVMOV ;JOIN COMMON CODE
CMDMVE: SKIPA T2,[EXP DIR.E] ;GET DIRECTION FOR EAST
CMDMVW: MOVEI T2,DIR.W ;OR FOR WEST
JRST SAVMOV ;JOIN COMMON CODE
CMDBCK: MOVEI T2,DIR.BK ;FLAG BACKWARDS MOTION WANTED
SAVMOV: CALL GETPTC ;READ IN THE LIST OF DIRECTIONS TO MOVE
CALL TELROB ;MENTION ANY ROBBERIES
MOVE T3,[POINT PTHWID,MOVLST] ;GET POINTER TO DIRECTIONS
MOVEM T3,MOVPTR ;SAVE POINTER
MOVLOP: ILDB T1,MOVPTR ;GET NEXT DIRECTION
CAIN T1,PTHMSK ;END OF THE LIST?
JRST LOOK ;YES, DESCRIBE VIEW
CALL LOCK ;LOCK UP THE FILE
LDB T1,MOVPTR ;GET BACK DIRECTION
CALL DOMOVE ;MAKE A MOVE IN THIS DIRECTION
RET ;CAN'T, RETURN WITH MESSAGE TYPED
CALL UNLOCK ;UNLOCK FILE AGAIN
CALL NOTICE ;SEE IF WE SHOULD STOP
JRST MOVLOP ;NO, CONTINUE MOVING
MOVE T4,MOVPTR ;GET COPY OF POINTER
ILDB T4,T4 ;GET NEXT DIRECTION
INTRST: CAIE T4,PTHMSK ;INTERRUPTED IN MIDDLE?
STROUT [ASCIZ/
While you are following this path, you stumble into a nonempty room.
/] ;YES, SAY SOMETHING
JRST LOOK ;GO LOOK AROUND NOW
SUBTTL SUBROUTINE TO MAKE A NORMAL TYPE MOVE
;THIS ROUTINE IS CALLED TO MOVE FROM THE CURRENT ROOM TO AN ADJACENT
;ROOM IN A CERTAIN DIRECTION. MUST BE CALLED WITH DATA FILE LOCKED.
;CALL: T1/ DIRECTION TO MOVE
; R/ POINTER TO CURRENT ROOM
;RETURNS:
; +1: MOVEMENT NOT POSSIBLE, FILE UNLOCKED AND MESSAGE TYPED
; +2: MOVEMENT COMPLETE, FILE STILL LOCKED
DOMOVE: CAIE T1,DIR.BK ;WANTS BACKWARDS MOTION?
JRST MOVNOB ;NO, PROCEED
SKIPN T1,U.BACK(U) ;YES, GET BACKWARDS DIRECTION
JRST NOBACK ;THERE WAS NONE, GO COMPLAIN
ANDI T1,-1 ;KEEP ONLY THE DIRECTION
MOVNOB: SKIPL T1 ;VERIFY THE DIRECTION
CAIL T1,DIRMAX ;AS VALID
FATAL (Trying to move in an illegal direction)
MOVEM T1,MOVDIR ;SAVE DIRECTION TO MOVE
ADDI T1,R.DIRS(R) ;MAKE ADDRESS OF PROPER LINK WORD
MOVEM T1,MOVLNK ;SAVE FOR LATER USE
SKIPN T4,R.MONS(R) ;IS THERE A MONSTER IN THIS ROOM?
JRST MOVNOM ;NOPE, PROCEED
HRRO T1,MOVDIR ;GET INTENDED DIRECTION
CAMN T1,U.BACK(U) ;JUST TRYING TO BACK OUT OF ROOM?
JRST MOVNOM ;YES, ALLOW THAT
MOVX T1,UF.OKM ;GET FLAG
TDNE T1,U.FLAG(U) ;CAN WE FLEE THE MONSTER?
JRST MOVNOM ;YES, LET US FLEE HIM
MOVEI T1,IT.INV ;GET CODE FOR INVISIBILITY RING
CALL GETITU ;SEE IF WE HAVE ANY
JUMPE T2,NOMMON ;NO, THEN CAN'T GET BY
MOVX T1,UF.NIV ;GET INVISIBILY NO GOOD FLAG
TDNE T1,U.FLAG(U) ;SEE IF WE TRIED ALREADY
JRST NOMMO2 ;YES, FAIL AGAIN
MOVEI T1,2 ;GET A CHANCE
CALL RANDOM ;SEE IF WE MAKE IT BY HIM
JUMPE T1,NOMMO2 ;NOPE
MOVNOM: HRRO T1,MOVDIR ;GET DIRECTION OF MOVEMENT
CAMN T1,U.BACK(U) ;IS HE TRYING TO BACK UP?
JRST EXTDOR ;YES, JUST LET HIM DO IT
LDB T1,[POINTR @MOVLNK,DR%TYP] ;GET TYPE OF DOOR TO GO THROUGH
CALL @TRYDIR(T1) ;SEE IF WE CAN GO THIS WAY
JRST NOMOVE ;NO, GO SAY WHY
HRRE T1,@MOVLNK ;GET ROOM LINK WORD POINTS TO
AOJN T1,EXTDOR ;GO ON IF GOES TO AN EXISTANT ROOM
MOVE T1,MOVDIR ;NEED A NEW ROOM, GET DIRECTION
CALL BUILD ;LINK IN A NEW ROOM TO THIS ONE
JRST NOBLD ;FAILED, HAVE TO CAVE IN THIS DOOR
EXTDOR: HRRZ T1,@MOVLNK ;GET WHICH ROOM LINK POINTS TO
CALL ENTERM ;MOVE TO THAT ROOM
MOVE T1,MOVDIR ;GET DIRECTION WE MOVED IN
XORI T1,1 ;REVERSE IT FOR BACKWARDS DIRECTION
HRROM T1,U.BACK(U) ;AND SAVE IT
JRST CPOPJ1 ;AND GIVE GOOD RETURN
NOBLD: MOVEI T1,[ASCIZ/That passageway has just caved in!!/] ;GET TEXT
HRLOI T2,DR.BLK ;GET DOOR TYPE FOR A CAVE-IN
EXCH T2,@MOVLNK ;GET OLD TYPE AND SAVE THIS TYPE
LDB T2,[POINTR T2,DR%TYP] ;GET TYPE
CAIE T2,DR.ALW ;NORMAL TYPE DOOR WE COLLAPSED?
CAIN T2,DR.SRC ;OR A SECRET DOOR?
SKIPA T2,R.LEVL(R) ;YES, GET LEVEL OF THIS ROOM
JRST NOMOVE ;NOPE, JUST GO COMPLAIN
CAMN T2,H.LEVL ;YES, REMOVING DOOR FROM LOWEST LEVEL?
SOS H.LGRW ;YES, REDUCE COUNT OF GROWABLE DOORS
JRST NOMOVE ;AND JOIN COMMON CODE
NOBACK: MOVEI T1,[ASCIZ/There is no way to back up from here./]
NOMOVE: PUSH P,T1 ;SAVE THE ERROR STRING
CALL UNLOCK ;UNLOCK THE DATA FILE FIRST
DOCRLF ;DO A CRLF
POP P,T1 ;RESTORE STRING
STROUT (T1) ;GIVE THE ERROR MESSAGE
DOCRLF ;END IN A CRLF
NOMOVF: LDB T1,[POINT PTHWID,MOVLST,2*PTHWID-1] ;GET 2ND BYTE
CAIE T1,PTHMSK ;JUST A 1 MOVE COMMAND?
CALL LOOKVR ;NO, DESCRIBE ROOM WE'RE IN
RET ;DONE
NOMMO2: MOVX T1,UF.NIV ;GET INVISIBILITY NO GOOD FLAG
IORM T1,U.FLAG(U) ;REMEMBER NOT GOOD HERE
CALL UNLOCK ;UNLOCK THE FILE
DOCRLF ;START WITH CRLF
STROUT [ASCIZ/Your invisibility ring was not effective this time. /]
SKIPA ;PROCEED
NOMMON: CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
The /] ;START OUTPUT
HRRZ T1,MONTXT(T4) ;GET STRING FOR THIS MONSTER
CALL MONOUT ;OUTPUT IT
STROUT [ASCIZ/ prevents you from crossing the room. /]
DOCRLF ;FINISH WITH CRLF
JRST NOMOVF ;AND FINISH
;COMND TABLE FOR FURTHER DIRECTIONS:
DIRCMT: XWD CMTLEN,CMTLEN ;HEADER WORD
AC BACK-UP,DIR.BK ;BACK TO PREVIOUS ROOM
AC EAST,DIR.E ;EAST
AC NORTH,DIR.N ;NORTH
AC SOUTH,DIR.S ;SOUTH
AC WEST,DIR.W ;WEST
CMTLEN==.-DIRCMT-1 ;SIZE OF TABLE
;TABLE OF ROUTINES TO SEE IF A PARTICULAR DIRECTION CAN BE
;TRAVERSED. SKIP RETURN IF THE DIRECTION IS ALLOWED. NON-SKIP
;IF NOT POSSIBLE, WITH T1 CONTAINING ADDRESS OF EXPLAINATORY
;TEXT, OR ZERO IF NONE.
TRYDIR: EXP NEWDOR ;(0) SHOULDN'T GET HERE
EXP NODOR ;(1) NEVER POSSIBLE
EXP CPOPJ1 ;(2) ALWAYS POSSIBLE
EXP SECDOR ;(3) SECRET DOOR
EXP LVLDOR ;(4) REQUIRES LEVEL DOOR
EXP WRDDOR ;(5) REQUIRES MAGIC WORD
EXP MAGDOR ;(6) REQUIRES MAGIC ITEM
EXP DEADOR ;(7) COLLAPSED DOOR
SECDOR: MOVEI T1,R.SRCF(R) ;GET WHICH WORD TO SET UP
CALL BITSET ;MAKE ADDRESS AND BIT FOR TESTING
TDNE T2,(T1) ;DID WE SEARCH THE ROOM?
JRST CPOPJ1 ;YES, ALLOW THIS THEN
NODOR: MOVEI T1,[ASCIZ/You can't go that way./]
RET ;RETURN ERROR
NEWDOR: MOVEI T1,[ASCIZ/This is a new door not yet completed./]
RET ;RETURN BAD
DEADOR: MOVEI T1,[ASCIZ/There is a cave-in in that direction!!/]
RET ;RETURN BAD
LVLDOR: JRST CPOPJ1 ;YES, GOOD RETURN
MOVEI T1,[ASCIZ/You are not good enough to go through the door./]
RET ;RETURN MAD
WRDDOR: LDB T1,[POINTR @MOVLNK,DR%DAT] ;GET DATA FOR THIS DOOR
JUMPN T1,CPOPJ1 ;IF NONZERO, CAN GO THROUGH THE DOOR
HRRE T1,@MOVLNK ;GET LINKED ROOM
JUMPL T1,WRDNO ;IF NONE, FAIL
IMULI T1,ROMSIZ ;COMPUTE ADDRESS OF THAT ROOM
MOVE T2,MOVDIR ;GET DIRECTION
XORI T2,1 ;REVERSE IT
ADD T1,T2 ;ADD IN
LDB T1,[POINTR R.DIRS(T1),DR%DAT] ;GET DATA THERE
JUMPN T1,CPOPJ1 ;SUCCESSFUL IF OPEN
WRDNO: MOVEI T1,[ASCIZ/The magic word door is not opened./]
RET ;RETURN BAD
MAGDOR: LDB T1,[POINTR @MOVLNK,DR%DAT] ;GET DATA
JUMPE T1,CPOPJ1 ;GOOD RETURN IF IT'S OPEN
MOVEI T1,[ASCIZ/You haven't used the proper magic item to open the doo
r./]
RET ;RETURN BAD
;SUBROUTINE TO SEE IF A MAGIC TORCH HAS LIT UP THE CURRENT ROOM.
DOTORC: MOVEI T1,IT.GLS ;GET CODE FOR MAGIC GLASSES
CALL GETITU ;SEE IF WE HAVE ANY
JUMPE T2,CPOPJ ;IF NONE, RETURN
MOVEI T1,R.SRCF(R) ;GET ADDRESS OF SEARCH FLAGS
CALL BITSET ;POINT TO PROPER BIT
IORM T2,(T1) ;SAY WE KNOW ABOUT SECRET PASSAGES
MOVEI T1,2 ;GET READY
CALL RANDOM ;TO SEE IF WE FIND TREASURE TOO
JUMPE T1,CPOPJ ;RETURN IF NO
MOVEI T1,R.HIDF(R) ;GET ADDRESS OF FLAGS
CALL BITSET ;POINT TO THE BIT FOR US
IORM T2,(T1) ;SAY WE CAN SEE TREASURE HERE
RET ;DONE
SUBTTL SUBROUTINE TO READ IN A LIST OF DIRECTIONS
;THIS SUBROUTINE IS USED TO READ IN THE REST OF THE COMMAND LINE,
;AND TO STORE THE DIRECTIONS IN THE MOVLST TABLE FOR LATER USE.
;NUMBER OF DIRECTIONS READ IS STORED IN PTHCNT. CALL
;AT GETPTC IF T2 HAS FIRST DIRECTION ALREADY.
;RETURNS:
; +1: REST OF LINE EATEN, WITH DIRECTIONS STORED IN MOVLST.
;USES LOTS OF AC'S.
GETPTH: CMMD [FLDDB. (.CMKEY,,DIRCMT)] ;PARSE DIRECTION
HRRZ T2,(T2) ;GET CODE
GETPTC: MOVE T3,[POINT PTHWID,MOVLST] ;GET POINTER
MOVEM T3,MOVPTR ;SET UP POINTER
SETZM PTHCNT ;CLEAR COUNTER
GETPTL: AOS T3,PTHCNT ;ADVANCE ENTRY
CAILE T3,MOVMAX-1 ;OVERFLOWED THE TABLE?
ERROR (,,Too many directions specified.) ;YES
IDPB T2,MOVPTR ;STORE THE DIRECTION
NOISE (THEN) ;GIVE SOME NOISE TEXT
CMMD [FLDDB. (.CMCFM,,,,,<[FLDDB. (.CMKEY,,DIRCMT)]>)]
TSC T3,T3 ;SEE IF GAVE ANOTHER KEYWORD
JUMPE T3,GETPTE ;NO, FINISH UP
HRRZ T2,(T2) ;GET THE DIRECTION CODE
JRST GETPTL ;AND LOOP
GETPTE: MOVEI T2,-1 ;GET READY
IDPB T2,MOVPTR ;END THE LIST OF MOVES
RET ;DONE
SUBTTL SUBROUTINE TO MOVE TO A ROOM
;THIS SUBROUTINE IS USED TO MOVE US TO A PARTICULAR ROOM. ALL
;THE NECESSARY BOOKKEEPING IS DONE HERE FOR THIS. IE, DOORS ARE
;BUILT, MONSTERS AND TREASURE ARE CREATED, VISIT AND MOVE COUNTS
;ARE UPDATED, ETC. CALL:
; T1/ NEW ROOM NUMBER
;RETURNS:
; +1: ALWAYS, WITH EVERYTHING UPDATED
; R/ POINTS TO THE NEW ROOM
;THE FLAG FR.VR2 IS SET IF WE HAVE NEVER BEEN HERE BEFORE.
;CALL AT ENTERM IF MONSTERS PREVENT MOVEMENT LATER.
ENTERM: TDZA T2,T2 ;GET NO FLAG
ENTER: MOVX T2,UF.OKM ;OR GET THE OK TO MOVE FLAG
SKIPL T1 ;MAKE SURE ROOM IS POSITIVE
CAMLE T1,H.ROOM ;AND NOT TOO LARGE
FATAL (Entering illegal room number)
MOVE T3,T1 ;GET COPY OF ROOM NUMBER
IMULI T3,ROMSIZ ;CREATE POINTER TO IT
ADDI T3,ROMADR ;FINISH IT
MOVE T4,R.ROOM(T3) ;GET ROOM NUMBER IT SAYS IT IS
TLC T4,-1 ;COMPLEMENT FOR CHECK
CAMN T1,T4 ;CORRECT?
TLNE T4,-1 ;WELL?
JRST BADROM ;NOPE, GO COMPLAIN
MOVE T4,R.LEVL(R) ;SAVE LEVEL OLD ROOM WAS IN
MOVE R,T3 ;THEN POINT TO THE NEW ROOM
SETZM U.BACK(U) ;BACKING UP IS ILLEGAL UNTIL KNOW OTHERWISE
IORM T2,U.FLAG(U) ;SET OK TO MOVE ANY DIRECTION FLAG
MOVEM T1,U.ROOM(U) ;SET OUR NEW ROOM NUMBER
SUB T4,R.LEVL(R) ;GET LEVEL CHANGE
MOVM T4,T4 ;KEEP ONLY ABSOLUTE VALUE
ADDI T4,1 ;ONE MORE IN CASE NO LEVEL CHANGE
ADDM T4,U.TURN(U) ;BUMP NUMBER OF MOVES USED
MOVE T1,PLYUSR ;GET MY USER NUMBER
SKIPN R.VIST(R) ;ANYBODY BEEN HERE BEFORE?
MOVEM T1,R.FVIS(R) ;NO, REMEMBER WE WERE FIRST
MOVEM T1,R.LVIS(R) ;ALSO REMEMBER WHO WAS LAST HERE
SKIPN R.VIST(R) ;WAS THIS ROOM VISITED BEFORE?
AOS U.BLDR(U) ;NO, ADD TO ROOMS WE'VE DISCOVERED
AOS R.VIST(R) ;INCREMENT NUMBER OF VISITS TO ROOM
MOVEI T1,R.VISF(R) ;GET ADDRESS OF VISIT TABLE
CALL BITSET ;THEN READY THE BIT
TDNN T2,(T1) ;HAVE WE BEEN HERE BEFORE?
AOSA U.NEWR(U) ;NO, INCREMENT ROOMS VISITED
TXZA F,FR.VR2 ;YES, CLEAR THE TEMPORARY VERBOSE FLAG
TXO F,FR.VR2 ;NO, SET TEMPORARY VERBOSITY
IORM T2,(T1) ;THEN REMEMBER WE'VE BEEN HERE
HRRZ T1,R.LEVL(R) ;GET LEVEL OF THIS ROOM
CAMLE T1,U.LEVL(U) ;LOWER DOWN THAN OUR OWN LEVEL?
MOVEM T1,U.LEVL(U) ;YES, REMEMBER OUR NEW LEVEL
MOVX T1,UF.OKM!UF.NIV ;GET FLAGS
ANDCAM T1,U.FLAG(U) ;CLEAR FROM FLAG WORD
CALL DOFIX ;TRY TO FIX US UP A LITTLE
CALL DOTORC ;SEE IF TORCH LIGHTS UP THE ROOM
CALL MAKDOR ;DECIDE WHAT KIND OF DOORS EXIST HERE
CALL MAKTRE ;PUT TREASURE IN THE ROOM IF NECESSARY
MOVE T1,[^D30,,^D60] ;GET NORMAL CHANCE FOR MONSTERS
CALL MAKMON ;PUT A MONSTER HERE IF NECESSARY
CALL MAKITM ;PUT A MAGICAL ITEM HERE IF NECESSARY
GTAD ;READ TIME
MOVEM T1,U.LDAT(U) ;REMEMBER WHEN WE LAST MOVED
RET ;DONE
;HERE IF WE ARE TRYING TO ENTER A BAD ROOM:
BADROM: MOVEM T1,TEMP ;SAVE ROOM NUMBER
CALL UNLOCK ;UNLOCK THE FILE
STROUT [ASCIZ/
You cannot enter room /] ;TYPE
DECOUT TEMP ;THEN GIVE ROOM NUMBER
STROUT [ASCIZ/ because it has been trashed.
/] ;FINISH IT
JRST DOERRF ;THEN FINISH THE ERROR
SUBTTL ROUTINE TO SEE IF A ROOM IS INTERESTING
;THIS IS CALLED WHILE MOVING ALONG A LONG PATH TO SEE IF SOMETHING
;INTERESTING IS IN THIS ROOM. INTERESTING MEANS THE ROOM CONTAINS
;TREASURE, ITEMS, OR MONSTERS. CALL:
; R/ POINTER TO ROOM
;RETURNS:
; +1: NOTHING INTERESTING FOUND
; +2: INTERESTING THINGS FOUND
;CALL AT HIDCHK TO JUST SEE IF WE HAVE SEARCHED ROOM.
;PRESERVES T4.
NOTICE: SKIPN R.VTRE(R) ;ANY VISIBLE TREASURE HERE?
SKIPE R.VITM(R) ;OR VISIBLE ITEMS?
JRST CPOPJ1 ;YES
SKIPE R.MONS(R) ;ANY MONSTERS HERE?
JRST CPOPJ1 ;YES
SKIPN R.HTRE(R) ;ANY HIDDEN TREASURE?
SKIPE R.HITM(R) ;OR HIDDEN ITEMS?
JRST HIDCHK ;YES, SEE IF SEARCHED ROOM
RET ;NO, NOTHING INTERESTING HERE
HIDCHK: MOVEI T1,R.HIDF(R) ;GET READY
CALL BITSET ;MAKE OFFSET AND MASK
TDNE T2,(T1) ;HAS ROOM BEEN SEARCHED BY US?
AOS (P) ;YES, SKIP RETURN
RET ;DONE
SUBTTL SUBROUTINE TO COMPUTE SHIFTS
;SUBROUTINE TO COMPUTE HOW MUCH TO SHIFT BY WHEN MOVING FROM A ROOM
;TO A NEARBY ROOM. WHEN WE GO A PARTICULAR DIRECTION, WE WILL SHIFT
;COORDINATES BY 10 OR SO, WITH A LITTLE BIT OF RANDOMNESS. IN ADDITION,
;WE WILL SHIFT SIDEWAYS A LITTLE BIT.
;CALL: T1/ CURRENT COORDINATES
; T2/ DIRECTION CODE OF SHIFT
;
;RETURNS:
; T1/ NEW COORDINATES
SHIFT: MOVEM T1,TEMP ;SAVE AWAY THE COORDINATES
MOVE T4,T2 ;AND PUT DIRECTION IN SAFE AC
MOVEI T1,SFPMAX-SFPMIN-1 ;GET A NICE RANGE
CALL RANDOM ;AND GENERATE A RANDOM NUMBER
MOVEI T3,SFPMIN(T1) ;THEN SAVE PRIMARY SHIFT DISTANCE
MOVEI T1,SFSMAX*2+1 ;GET ANOTHER NICE RANGE
CALL RANDOM ;THEN ANOTHER RANDOM NUMBER
SUBI T1,SFSMAX ;PRODUCE SECONDARY SHIFT DISTANCE
HLRZ T2,TEMP ;GET CURRENT X COORDINATE
XCT XSHIFT(T4) ;MODIFY IT DEPENDING ON DIRECTION
HRLM T2,TEMP ;SAVE RESULT
HRRZ T2,TEMP ;GET CURRENT Y COORDINATE
XCT YSHIFT(T4) ;MODIFY IT DEPENDING ON DIRECTION
HRRM T2,TEMP ;SAVE RESULT
MOVE T1,TEMP ;RETRIEVE NEW COORDINATES
RET ;DONE
XSHIFT: ADD T2,T1 ;NORTH
ADD T2,T1 ;SOUTH
ADD T2,T3 ;EAST
SUB T2,T3 ;WEST
YSHIFT: ADD T2,T3 ;NORTH
SUB T2,T3 ;SOUTH
ADD T2,T1 ;EAST
ADD T2,T1 ;WEST
SUBTTL SUBROUTINE TO PRODUCE A DESCRIPTION OF THE CURRENT ROOM
;CALLED AFTER EVERY MOVE HAS BEEN MADE, TO PRODUCE A DESCRIPTION OF
;THE CURRENT ROOM. THE DESCRIPTION DEPENDS ON THE LOCATION OF THE
;ROOM, THE ROOM NUMBER, AND WHICH KINDS OF PASSAGEWAYS LEAD AWAY.
LOOKVR: TXO F,FR.VR2 ;SET TEMPORARY VERBOSITY FLAG
LOOK: TXNN F,FR.DEB ;DOING DEBUGGING STUFF?
JRST LOOKNM ;NO, SKIP THIS STUFF
STROUT [ASCIZ/
Room /] ;GET READY
HRRZ T1,R.ROOM(R) ;GET THE ROOM NUMBER
CALL TTYDEC ;OUTPUT IT
STROUT [ASCIZ/ at /] ;MORE
HLRZ T1,R.LOC(R) ;GET X COORDINATE
CALL TTYDEC ;OUTPUT IT
CHROUT "," ;THEN A COMMA
HRRZ T1,R.LOC(R) ;GET Y COORDINATE
CALL TTYDEC ;OUTPUT IT
STROUT [ASCIZ/ in level /] ;MORE
DECOUT R.LEVL(R) ;OUTPUT LEVEL
STROUT [ASCIZ/ at file address /] ;MORE
HRRZ T1,R.ROOM(R) ;GET ROOM NUMBER
IMULI T1,ROMSIZ ;MULTIPLY BY SIZE OF EACH ROOM'S DATA
ADDI T1,ROMADR-MAPADR ;ADD IN OFFSET INTO THE FILE
CALL TTYOCT ;OUTPUT IT
STROUT [ASCIZ/
Discovered by: /] ;GET READY
MOVE T1,R.FVIS(R) ;GET WHO DISCOVERED THIS ROOM
CALL USROUT ;OUTPUT IT
STROUT [ASCIZ/, Visits: /] ;MORE
DECOUT R.VIST(R) ;TYPE IT
STROUT [ASCIZ/
Visible treasure: /] ;MORE
DECOUT R.VTRE(R) ;TYPE IT
STROUT [ASCIZ/, Hidden treasure: /] ;MORE TEXT
DECOUT R.HTRE(R) ;TYPE IT
STROUT [ASCIZ/, Monster: /] ;MORE
SKIPN T4,R.MONS(R) ;ANY?
STROUT [ASCIZ/None/] ;NO
JUMPE T4,DEBLNM ;SKIP IF THAT'S IT
HRRZ T1,MONTXT(T4) ;GET NAME
CALL MONOUT ;TYPE IT
STROUT [ASCIZ/ (strength = /] ;MORE
DECOUT R.MONH(R) ;OUTPUT IT
CHROUT ")" ;FINISH
DEBLNM: DOCRLF ;DO A CRLF
MOVSI I,-DIRMAX ;GET READY FOR LOOPING
ADDI I,R.DIRS(R) ;OVER ALL DIRECTIONS
LKDBLP: MOVE T1,(I) ;GET DOOR TYPE
CAMN T1,[DR.NEV,,-1] ;IS THIS A STANDARD NONEXISTANT DOOR?
JRST LKDBNX ;YES, SKIP ON
CHROUT " " ;SPACE OVER
MOVEI T1,(I) ;GET OFFSET
SUBI T1,R.DIRS(R) ;UNDO OFFSET
STROUT @DORTXT(T1) ;OUTPUT DIRECTION
STROUT [ASCIZ/: /] ;THEN TAB OVER
LDB T4,[POINTR 0(I),DR%TYP] ;GET TYPE
STROUT @LKDTBL(T4) ;GIVE THE DOOR TYPE
STROUT [ASCIZ/ door/] ;TYPE MORE
MOVE T1,(I) ;GET POINTER
HRREI T1,(T1) ;GET ROOM NUMBER
SKIPL LKDTBL(T4) ;DOES THIS GO TO ANY ROOM?
AOJE T1,LKDBDN ;OR IS ROOM ALLOCATED?
LKDTYR: HRRZ T4,(I) ;GET ROOM
CAIN T4,-1 ;UNALLOCATED ROOM?
STROUT [ASCIZ/ to an unallocated room/] ;YES, TYPE STUFF
CAIN T4,-1 ;WELL?
JRST LKDBDN ;YES, SKIP ON
STROUT [ASCIZ/ to room /] ;TYPE ROOM NUMBER STRING
HRRZ T1,(I) ;GET ROOM
DECOUT T1 ;OUTPUT IT
LKDBDN: DOCRLF ;DO A CRLF
LKDBNX: AOBJN I,LKDBLP ;LOOP OVER ALL DIRECTIONS
;HERE TO GIVE THE NORMAL DESCRIPTION THAT ALL PLAYERS SEE:
LOOKNM: DOCRLF ;TYPE A CRLF
TXNE F,FR.VRB!FR.VR2 ;VERBOSE OUTPUT?
TDZA T1,T1 ;YES, SUPPRESS ANY TEXT
MOVEI T1,[ASCIZ/This is the entrance to the dungeon/] ;GET TEXT
HRRZ T4,R.ROOM(R) ;GET ROOM NUMBER
SKIPE T4 ;IS THIS ROOM ZERO?
MOVEI T1,[ASCIZ/This is room /] ;NO, GET NORMAL TEXT
JUMPE T1,LOOKNT ;SKIP IF NO TEXT
CALL TTYSTR ;YES, OUTPUT IT
SKIPE T1,T4 ;GET ROOM NUMBER READY
CALL TTYDEC ;AND OUTPUT IT IF NONZERO
STROUT [ASCIZ/. /] ;TYPE MORE TEXT
LOOKNT: TXNN F,FR.VRB!FR.VR2 ;VERBOSE OUTPUT DESIRED?
JRST LOOKBF ;NO, SKIP SOME
CALL LKROOM ;MAKE UP SOME STUFF ABOUT THIS ROOM
CALL LKDEAD ;LOOK FOR DEAD THINGS
CALL LKPASS ;LOOK FOR OBVIOUS PASSAGES
CALL LKSECR ;LOOK FOR SECRET PASSAGES
CALL LKBLCK ;LOOK FOR BLOCKED PASSAGES
LOOKBF: CALL LKLEVL ;LOOK FOR LEVEL-CHANGE DOORS
CALL LKWORD ;LOOK FOR A WORD ON THE WALL
CALL LKUSER ;LOOK FOR OTHER USERS IN THE ROOM
CALL LKTRES ;LOOK FOR ANY TREASURE
CALL LKITEM ;LOOK FOR ANY MAGIC ITEMS
CALL LKMONS ;LOOK FOR ANY MONSTERS HERE
TXZ F,FR.VR2 ;CLEAR TEMPORARY VERBOSITY FLAG
DOCRLF ;TYPE A CRLF
RET ;DONE
;SUBROUTINE TO LOOK FOR OBVIOUS PASSAGES FROM THIS ROOM, AND OUTPUT
;THE DIRECTIONS THEY GO. ALSO HERE TO LOOK FOR SECRET PASSAGES.
LKSECR: TDNN ZR,R.ROOM(R) ;AT THE ENTRANCE?
RET ;YES, NONE OF THIS OUTPUT IS DONE
MOVEI T1,R.SRCF(R) ;GET ADDRESS OF SEARCH FLAGS
CALL BITSET ;THEN SETUP FOR TESTING
TDNN T2,(T1) ;WAS THIS ROOM SEARCHED BEFORE?
RET ;NO, RETURN
LKSEC2: MOVEI T1,DR.SRC ;YES, GET SECRET DOOR TYPE
CALL FNDDOR ;LOOK FOR THAT TYPE OF DOOR
MOVE T4,T1 ;REMEMBER HOW MANY
MOVEI T1,[ASCIZ/No secret passages leave here. /] ;TEXT
JUMPE T4,TTYSTR ;TYPE IT IF NO PASSAGES
MOVEI T1,[ASCIZ/A secret passage leads /] ;TEXT
CAIN T4,1 ;ONLY ONE SECRET PASSAGE?
CALL TTYSTR ;YES, OUTPUT IT
MOVEI T1,[ASCIZ/Secret passages lead /] ;TEXT
JRST OBSHOW ;JOIN OTHER CODE
LKBLCK: MOVEI T1,DR.BLK ;GET TYPE OF DOOR
CALL FNDDOR ;LOOK FOR THAT TYPE
SKIPN T4,T1 ;SAVE NUMBER OF CRASHED IN DOORS
RET ;IF NONE, TYPE NOTHING
CAIN T4,1 ;ONLY ONE CAVED IN DOORWAY?
STROUT [ASCIZ/A caved-in doorway prevents moving /] ;YES
MOVEI T1,[ASCIZ/Caved-in doorways prevent moving /]
JRST OBSHOW ;JOIN OTHER CODE
LKPASS: TDNN ZR,R.ROOM(R) ;AT ENTRANCE?
RET ;YES, DON'T MENTION PASSAGES
MOVEI T1,DR.ALW ;GET TYPE OF DOOR
CALL FNDDOR ;LOOK FOR THAT TYPE OF DOOR
MOVE T4,T1 ;REMEMBER NUMBER OF DOORS
MOVEI T1,[ASCIZ/No passages leave here. /] ;TEXT
JUMPE T4,TTYSTR ;TYPE IT IF NO PASSAGES
CAIN T4,1 ;ONLY ONE OBVIOUS PASSAGE?
STROUT [ASCIZ/A passage leads /] ;YES, TYPE TEXT
MOVEI T1,[ASCIZ/Passages lead /] ;TEXT
OBSHOW: CAIE T4,1 ;MORE THAN ONE PASSAGE?
CALL TTYSTR ;YES, SAY THAT
MOVEI T1,[ASCIZ/in all directions. /] ;TEXT
CAIN T4,DIRMAX ;ALL DIRECTIONS USED?
JRST TTYSTR ;YES, FINISH UP NOW
MOVSI I,-DIRMAX ;MAKE AOBJN POINTER TOO
SETZM LISOLD ;GET READY FOR LIST OUTPUT
OBLOOP: SKIPN DORTAB(I) ;IS THIS ONE OF THE DOORS?
JRST OBNEXT ;NO, LOOP ONWARD
HRLZ T1,DORTXT(I) ;GET ADDRESS OF TEXT
IORI T1,TTYSTR ;AND ROUTINE TO CALL
CALL DOLIST ;OUTPUT DIRECTION IN A LIST
OBNEXT: AOBJN I,OBLOOP ;LOOP OVER ALL DIRECTIONS
CALL DOLISE ;TERMINATE THE LIST
MOVEI T1,[ASCIZ/. /] ;GET TEXT
JRST TTYSTR ;OUTPUT IT
;SUBROUTINE TO TYPE OUT ALL DOORS WHICH CHANGE LEVELS.
LKLEVL: MOVSI I,-DIRMAX ;GET SET FOR A LOOP
LVLOOP: HRRZ T4,I ;GET INDEX BY ITSELF
ADDI T4,R.DIRS(R) ;MAKE ADDRESS OF THE DIRECTION POINTER
LDB T1,[POINTR 0(T4),DR%TYP] ;GET DOOR TYPE
CAIE T1,DR.LVL ;IS THIS A LEVEL CHANGE DOOR?
JRST LVLNXT ;NO, GO TO NEXT DIRECTION
STROUT [ASCIZ/There is a huge stone door on the /] ;TEXT
STROUT @DORTXT(I) ;TYPE DIRECTION
STROUT [ASCIZ/ wall, with the phrase "/] ;TEXT
HRRE T3,(T4) ;GET ROOM THAT WE LINK TO
JUMPL T3,[MOVE T3,R.LEVL(R) ;NOPLACE, THEN GET CURRENT LEVEL
AOJA T3,LVLOUT] ;INCREMENT IT AND TYPE IT
IMULI T3,ROMSIZ ;GET OFFSET INTO ROOM DATA
MOVE T3,ROMADR+R.LEVL(T3) ;THEN GET LEVEL WE ARE GOING TO
LVLOUT: MOVEI T1,[ASCIZ/DOWN TO LEVEL /] ;GET A TEXT
CAMGE T3,R.LEVL(R) ;ACTUALLY MOVING UP?
MOVEI T1,[ASCIZ/UP TO LEVEL /] ;YES, OTHER TEXT
SKIPN T3 ;GOING TO THE ENTRANCE?
MOVEI T1,[ASCIZ/ENTRANCE/] ;YES, GET THAT
CALL TTYSTR ;TYPE PROPER TEXT
SKIPE T1,T3 ;NEED NUMBER?
CALL TTYDEC ;YES, TYPE LEVEL NUMBER
STROUT [ASCIZ/" carved in it. /]
LVLNXT: AOBJN I,LVLOOP ;LOOP OVER ALL LEVELS
RET ;DONE
;TABLES FOR OUTPUT OF DEBUGGING INFORMATION:
LKDTBL: 0B0+[ASCIZ/unused/] ;(0)
0B0+[ASCIZ/non-existant/] ;(1)
1B0+[ASCIZ/direct/] ;(2)
1B0+[ASCIZ/secret/] ;(3)
1B0+[ASCIZ/level-change/] ;(4)
1B0+[ASCIZ/magic word/] ;(5)
1B0+[ASCIZ/magic item/] ;(6)
0B0+[ASCIZ/caved-in/] ;(7)
DORTXT: EXP [ASCIZ/North/] ;NORTH
EXP [ASCIZ/South/] ;SOUTH
EXP [ASCIZ/East/] ;EAST
EXP [ASCIZ/West/] ;WEST
EXP [ASCIZ/Back-up/] ;BACK-UP
SUBTTL SUBROUTINE TO MAKE UP A DESCRIPTION OF A ROOM
;CALLED WHEN DESCRIBING A ROOM, TO MAKE UP SOME STUFF ABOUT THE
;ROOM TO MAKE IT MORE INTERESTING. THIS IS DONE MY TAKING THE
;COORDINATES OF THE ROOM AS A RANDOM NUMBER, AND THEN USING THAT
;TO SELECT AMONG MANY PHRASES.
LKROOM: TDNN ZR,R.ROOM(R) ;AT THE ENTRANCE?
JRST ATENTR ;YES, SPECIAL OUTPUT FOR HERE
PUSH P,RANNUM ;SAVE REAL RANDOM NUMBER
MOVE T1,R.LOC(R) ;GET COORDINATES OF ROOM
IMUL T1,[^D<125*125*125*125*125>] ;JUMBLE
ADD T1,R.ROOM(R) ;ADD IN ROOM NUMBER
IMUL T1,[^D<125*125*125*125*125>] ;MORE
ADD T1,R.LEVL(R) ;FINALLY ADD LEVEL NUMBER
IMUL T1,[^D<125*125*125*125*125>] ;MORE
ADD T1,H.DATE ;ADD CREATION TIME OF DUNGEON
MOVEM T1,RANNUM ;AND SET AS SEED OF RANDOM NUMBER
CALL RANDOM ;CALL IT ONCE FIRST
MOVE T1,[TXN1,,TXT1] ;POINT TO THE INTRODUCTION TEXT
CALL RANTXT ;OUTPUT THE TEXT
STROUT [ASCIZ/ room is /] ;TEXT
MOVE T1,[TXN2,,TXT2] ;MORE
CALL RANTXT ;MORE TEXT
STROUT [ASCIZ/ with /] ;MORE
MOVE T1,[TXN3,,TXT3] ;MORE
CALL RANTXT ;MORE TEXT
STROUT [ASCIZ/. /] ;FINAL TEXT
POP P,RANNUM ;RESTORE REAL RANDOM NUMBER
RET ;DONE
;HERE IF AT THE ENTRANCE, TO OUTPUT SPECIAL TEXT.
ATENTR: STROUT [ASCIZ/&You are standing in the ruins of some ancient
town in the middle of a large desert. You have discovered by digging
through the ruins that the name of this town was "TESER NIGEB", and
that it was built around the entrance to a huge underground tunnel
system. Off in the distance are some pretty mountains, however the
only place you can go is down into the dungeon. /] ;TYPE STUFF
RET ;DONE
;ROUTINE TO OUTPUT ONE OF VARIOUS TEXTS, GIVEN NUMBER OF TEXTS IN
;LEFT HALF OF T1, AND ADDRESS OF TEXT POINTERS IN RIGHT HALF.
RANTXT: HRRZ T4,T1 ;SAVE ADDRESS
HLRZ T1,T1 ;GET NUMBER OF MESSAGES
CALL RANDOM ;GENERATE A RANDOM NUMBER
ADD T1,T4 ;ADD IN ADDRESS OF POINTERS
HRRZ T1,(T1) ;THEN GET ADDRESS OF PROPER TEXT
JRST TTYSTR ;GO OUTPUT IT
;TABLES USED TO DESCRIBE A ROOM.
DEFINE XX(TEXT),< ;;MAKE A USEFUL MACRO
EXP [ASCIZ/TEXT/]
>
TXT1: XX This
XX You can see that this
XX <Looking around, you see that this>
XX You notice that the
XX Here you see that the
XX Here the
TXN1==.-TXT1 ;NUMBER OF TEXTS
TXT2: XX small
XX thin and long
XX square
XX almost round
XX small and drafty
XX large
XX huge
XX dark and damp
XX filled with stalactites
XX packed with boulders
TXN2==.-TXT2 ;NUMBER OF TEXTS
TXT3: XX footprints in the soft sand
XX a hard floor
XX granite walls
XX sandstone walls
XX a small pool of water in the corner
XX illegible writing on the walls
XX a slightly sloping floor
XX dirty looking walls
TXN3==.-TXT3 ;NUMBER OF TEXTS
;SUBROUTINE TO TELL ABOUT OTHER USERS IN THIS ROOM.
LKUSER: HRLZ I,H.PLRS ;GET NUMBER OF PLAYERS
MOVN I,I ;MAKE INTO AOBJN POINTER
ADDI I,PLRADR ;POINT TO PLAYERS
MOVE T4,U.ROOM(U) ;GET MY ROOM NUMBER
SETZM LISOLD ;SET UP TO CALL LIST ROUTINE
LKUSRL: CAMN T4,U.ROOM(I) ;IS THIS PLAYER ALSO IN MY ROOM?
CAIN U,(I) ;AND NOT MYSELF?
JRST LKUSRN ;NO, TRY NEXT GUY
SKIPN U.USER(I) ;MAKE SURE THERE IS ONE
JRST LKUSRN ;NO, GO TO NEXT GUY
PUSH P,U ;SAVE MY LOCATION
MOVE U,I ;POINT TO HIS ENTRY
MOVEI T1,IT.INV ;GET INVISIBILITY CODE
CALL GETITU ;SEE IF HE HAS AN INVISIBILITY RING
POP P,U ;RESTORE AC
JUMPN T2,LKUSRN ;IF HAS ONE, DON'T SHOW HIM
MOVSI T1,U.USER(I) ;GET ADDRESS OF USER NUMBER
IORI T1,[MOVE T1,(T1) ;AND INSTRUCTIONS TO TYPE IT
JRST USROUT] ;CALLED FROM LIST ROUTINE
CALL DOLIST ;OUTPUT THE NAME AS PART OF A LIST
LKUSRN: ADDI I,PLRSIZ-1 ;MOVE TO NEXT BLOCK
AOBJN I,LKUSRL ;LOOP UNTIL DONE
CALL DOLISE ;FINISH THE LIST
SKIPN T2,LISCNT ;SEE HOW MANY PEOPLE WERE TYPED
RET ;NONE, RETURN
MOVEI T1,[ASCIZ/ is/] ;GET POSSIBLE TEXT
CAIE T2,1 ;MORE THAN ONE PERSON?
MOVEI T1,[ASCIZ/ are/] ;YES, GET OTHER TEXT
CALL TTYSTR ;TYPE THE TEXT
STROUT [ASCIZ/ here with you. /] ;FINISH IT
RET ;DONE
;SUBROUTINE TO OUTPUT HOW MUCH TREASURE IS HERE IN THIS ROOM.
;WE ALWAYS TELL ABOUT VISIBLE TREASURE, BUT ONLY HIDDEN TREASURE
;IF THE ROOM WAS SEARCHED.
LKTRES: SKIPE R.MONS(R) ;A MONSTER IN THE ROOM?
RET ;YES, WE CAN'T SEE STUFF THEN
MOVEI T1,R.HIDF(R) ;GET ADDRESS OF HIDE FLAGS
CALL BITSET ;MAKE A BIT MASK
TDNN T2,(T1) ;CAN WE KNOW ABOUT HIDDEN TREASURE?
TDZA T4,T4 ;NO, GET NONE
MOVE T4,R.HTRE(R) ;YES, GET AMOUNT HIDDEN
PUSH P,T4 ;SAVE FOR AWHILE
ADD T4,R.VTRE(R) ;ADD IN AMOUNT VISIBLE TOO
JUMPE T4,LKTREF ;NO OUTPUT IF NOTHING HERE
STROUT [ASCIZ/This room has /] ;TYPE SOME
MOVE T1,T4 ;PUT IN RIGHT AC
CALL GOLOUT ;OUTPUT HOW MUCH GOLD
CAMN T4,0(P) ;IS ALL OF IT HIDDEN?
STROUT [ASCIZ/ hidden/] ;YES, SAY SO
STROUT [ASCIZ/ in it/] ;FINISH IT
CAME T4,0(P) ;ALL HIDDEN?
SKIPN T4,0(P) ;OR NONE HIDDEN?
JRST LKTREH ;YES, SKIP SOME
STROUT [ASCIZ/ (/] ;START OFF
DECOUT T4 ;TYPE AMOUNT HIDDEN
STROUT [ASCIZ/ of them /] ;MORE
CAIN T4,1 ;JUST ONE?
STROUT [ASCIZ/is/] ;YES
CAIE T4,1 ;WELL?
STROUT [ASCIZ/are/] ;NO
STROUT [ASCIZ/ hidden)/] ;FINISH
LKTREH: STROUT [ASCIZ/!!! /] ;FINISH UP
LKTREF: POP P,T1 ;RESTORE AC
RET ;AND RETURN
;SUBROUTINE TO TELL ABOUT WORDS SCRAWLED ON THE WALLS. THESE WORDS
;WILL DO NICE THINGS LIKE OPEN MAGIC DOORS.
LKWORD: SKIPN T1,R.WORD(R) ;IS THERE ANY MAGIC WORD HERE?
RET ;NO, SAY NOTHING
CALL MAKWRD ;YES, GENERATE THE PHRASE
STROUT [ASCIZ/Scrawled on one of the walls is the phrase "/]
STROUT MAGTXT ;TYPE THE MAGIC PHRASE
STROUT [ASCIZ/". /] ;FINISH THE TEXT
RET ;DONE
;ROUTINE TO LOOK FOR MONSTERS.
LKMONS: SKIPN T4,R.MONS(R) ;ANY MONSTER IN THIS ROOM?
RET ;NO, SAY NOTHING
STROUT [ASCIZ/This room is guarded by /] ;START TEXT
STROUT @MONTXT(T4) ;OUTPUT IT
STROUT [ASCIZ/!!! /] ;MORE
RET ;DONE
LKDEAD: SKIPG T4,R.DIES(R) ;SEE IF ANY DEATHS HERE
JRST MONDED ;NOT US, SEE IF MONSTERS
STROUT [ASCIZ/Laying here /] ;START OUT
CAIN T4,1 ;ONE?
STROUT [ASCIZ/is the skeleton of an unlucky explorer. /] ;YES
CAIN T4,1 ;WELL?
JRST MONDED ;YES, SKIP ON
STROUT [ASCIZ/are the skeletons of /] ;NO
DECOUT T4 ;TYPE NUMBER
STROUT [ASCIZ/ unlucky explorers. /] ;FINISH
MONDED: SKIPG T4,R.MONK(R) ;ARE THERE ANY DEAD MONSTERS?
RET ;NO, RETURN
STROUT [ASCIZ/The remains of /] ;START TEXT
CAIN T4,1 ;ONE?
STROUT [ASCIZ/a monster/] ;YES
CAIN T4,2 ;TWO?
STROUT [ASCIZ/a couple of monsters/] ;YES
CAILE T4,2 ;3 OR MORE?
DECOUT T4 ;YES, SAY HOW MANY
CAILE T4,2 ;WELL?
STROUT [ASCIZ/ monsters/] ;YES, MORE OUTOUT
STROUT [ASCIZ/ are in this room. /] ;FINISH IT
RET ;DONE
;ROUTINE TO LOOK FOR MAGIC ITEMS IN THE ROOM.
LKITEM: SKIPN R.MONS(R) ;ANY MONSTERS IN THE ROOM?
SKIPN R.VITM(R) ;OR NO ITEMS IN THE ROOM?
RET ;YES, DONE
STROUT [ASCIZ/Laying on the floor is /] ;START OUT
SETZM LISOLD ;INITIALIZE LIST
MOVEI T1,ITMNUM-1 ;GET READY FOR LOOP
MOVEM T1,ITMCNT ;INITIALIZE COUNTER
ITMTEL: CALL GETITR ;SEE IF THE ROOM HAS ANY OF THESE
JUMPE T2,ITMTEX ;NO, SKIP ON
HRLZ T1,ITMCNT ;YES, REMEMBER TYPE
IORI T1,ITMTYP ;AND ADDRESS OF ROUTINE TO TYPE IT
CALL DOLIST ;DO THE LIST
ITMTEX: SOSL T1,ITMCNT ;MORE ITEMS TO TELL ABOUT?
JRST ITMTEL ;YES, DO SO
CALL DOLISE ;FINISH THE LIST
SKIPN LISCNT ;ANY ITEMS ACTUALLY FOUND?
STROUT [ASCIZ/nothing (somebody just took stuff)/] ;NO!!
STROUT [ASCIZ/!!!
/] ;FINISH TEXT
RET ;DONE
ITMTYP: MOVE T4,T1 ;SAVE TYPE OF ITEM
HRRZ T1,ITMTAB(T4) ;GET ADDRESS OF TEXT
CALL TTYSTR ;TYPE IT
MOVE T1,T4 ;GET BACK TYPE
CALL GETITR ;READ NUMBER OF THEM
CAIN T2,1 ;ONLY 1?
RET ;YES, DONE
MOVE T4,T2 ;SAVE NUMBER OF THEM
STROUT [ASCIZ/ (/] ;START OUTPUT
SKIPN T4 ;NONE?
STROUT [ASCIZ/which has just been taken!)/] ;NO, SAY THIS
SKIPE T1,T4 ;GET COUNT BACK
CALL TTYDEC ;OUTPUT NUMBER
SKIPE T4 ;WELL?
STROUT [ASCIZ/ of them)/] ;FINISH
RET ;DONE
SUBTTL SUBROUTINE TO BUILD MORE OF THE DUNGEON
;CALLED WHENEVER AN ATTEMPT IS MADE TO TRAVERSE A PASSAGEWAY
;WHICH GOES TO A NONEXISTANT ROOM. FIRST A SEARCH IS MADE FOR A
;NEARBY ROOM THAT THIS ROOM CAN CONNECT TO. IF THE SEARCH FAILS,
;AN ATTEMPT IS MADE TO CREATE A NEW ROOM. CALL IS:
;
; R/ ADDRESS OF CURRENT ROOM
; T1/ DIRECTION TO BUILD FROM
;
;RETURNS:
; +1: CANNOT BUILD A ROOM FROM HERE
; +2: ROOM BUILT, LINK WORDS CONNECT THE ROOMS
BUILD: MOVEM T1,BLDDIR ;REMEMBER THE DIRECTION TO BUILD IN
ADDI T1,R.DIRS(R) ;GET ADDRESS OF CURRENT LINK WORD
MOVEM T1,BLDLNK ;REMEMBER IT
LDB T2,[POINTR @BLDLNK,DR%TYP] ;GET TYPE OF DOOR TO BUILD FROM
MOVEM T2,BLDTYP ;REMEMBER TYPE OF DOOR BUILDING FROM
MOVE T1,BLDDIR ;GET BACK DIRECTION TO SEARCH IN
CAIE T2,DR.LVL ;ALWAYS BUILD NEW ROOMS FOR LEVEL DOORS
CALL LNKSRC ;LOOK FOR A ROOM TO HOOK UP TO
JRST NEWROM ;NONE THERE, GO TRY TO BUILD ONE
OLDROM: MOVE T4,BLDTYP ;GET DOOR TYPE READY
MOVE T1,BLDDIR ;GET DIRECTION WE BUILT FROM
XORI T1,1 ;REVERSE THE DIRECTION SINCE FROM OTHER ROOM
ADDI T1,R.DIRS(S) ;GET ADDRESS OF OTHER ROOM'S LINK WORD
MOVE T2,@BLDLNK ;GET LINK FROM CURRENT ROOM
MOVE T3,(T1) ;AND LINK FROM OTHER ROOM
TXNN T3,DR%TYP ;A NEW PASSAGEWAY?
DPB T4,[POINTR T3,DR%TYP] ;YES, INSERT THE ROOM TYPE
HRR T2,R.ROOM(S) ;POINT CURRENT ROOM AT NEW ROOM
HRR T3,R.ROOM(R) ;AND POINT NEW ROOM BACK AT THIS ROOM
MOVEM T2,@BLDLNK ;STORE LINK WORD INTO CURRENT ROOM
EXCH T3,(T1) ;AND ALSO STORE LINK WORD INTO NEW ROOM
CAIE T4,DR.ALW ;NORMAL KIND OF DOOR?
CAIN T4,DR.SRC ;OR A SECRET DOOR?
SKIPA T1,H.LEVL ;YES, GET HIGHEST LEVEL READY
JRST CPOPJ1 ;NO, ALL DONE
CAMN T1,R.LEVL(R) ;REMOVED A DOOR FROM THIS LEVEL?
SOS H.LGRW ;YES, REDUCE GROWTH COUNT
JUMPE T3,CPOPJ1 ;IF WAS A NULL LINK, JUST RETURN
CAMN T1,R.LEVL(S) ;REMOVED ANOTHER DOOR FROM THIS LEVEL?
SOS H.LGRW ;YES, REDUCE GROWTH COUNT MORE
JRST CPOPJ1 ;SUCCESSFUL RETURN
;HERE WHEN NO OLD ROOM WILL SUFFICE. TRY TO CREATE A NEW ROOM SOMEPLACE
;THAT IS ACCEPTABLE. T1 IS NONZERO IF SOMEPLACE NICE IS KNOWN.
NEWROM: LDB T2,[POINTR @BLDLNK,DR%TYP] ;GET TYPE OF DOOR FROM HERE
CAIE T2,DR.ALW ;ALWAYS TRAVELABLE?
CAIN T2,DR.SRC ;OR IS SO IF SEARCHING?
JRST NWHERE ;YES, RANDOMNESS IS NOT ALLOWED
MOVE T1,R.LEVL(R) ;GET CURRENT LEVEL NUMBER
CAIN T2,DR.LVL ;A CHANGE OF LEVEL DOOR?
ADDI T1,1 ;YES, CHANGE LEVEL
MOVEM T1,BLDLVL ;SAVE LEVEL NUMBER FOR LATER
NWRAND: MOVEI T1,<MID-MIN>*2+1 ;GET READY
CALL RANDOM ;COMPUTE A RANDOM COORDINATE
ADDI T1,MIN ;SOMEPLACE IN X DIRECTION
PUSH P,T1 ;SAVE IT FOR AWHILE
MOVEI T1,<MID-MIN>*2+1 ;DO IT AGAIN
CALL RANDOM ;FOR OTHER DIRECTION
ADDI T1,MIN ;FINISH IT
POP P,T2 ;RESTORE OTHER COORDINATE
HRL T1,T2 ;PUT THEM TOGETHER
MOVE T2,BLDLVL ;GET LEVEL TO BUILD ON
CALL SRCROM ;SEE IF A ROOM IS ALREADY THERE
SKIPA ;NO, ALL IS OK
JRST NWRAND ;YEP, HAVE TO TRY ANOTHER COORDINATE
CALL MAKROM ;TRY TO MAKE A NEW ROOM HERE
RET ;NO MORE SPACE
JRST OLDROM ;OK, NOW PROCEED TO LINK IT IN
NWHERE: JUMPE T1,CPOPJ ;FAIL IF ROOM WAS ALREADY HERE
MOVE T2,R.LEVL(R) ;GET CURRENT LEVEL
CALL MAKROM ;BUILD A NEW ROOM HERE
RET ;FAILED
JRST OLDROM ;OK, GO LINK IT IN
SUBTTL SUBROUTINE TO FIND A ROOM TO BUILD A PASSAGE TO
;THIS ROUTINE IS CALLED TO SEARCH FOR A PREVIOUSLY EXISTING ROOM WHICH
;WE CAN BUILD A PASSAGE TO. SUCH A ROOM HAS TO HAVE A NONEXISTANT
;ROOM POINTED TO BY A LINK WORD OPPOSITE THE GIVEN DIRECTION.
;CALL:
; R/ POINTER TO CURRENT ROOM
; T1/ DIRECTION TO BUILD ROOM IN
;RETURNS:
; +1: T1/ PLACE A ROOM CAN BE BUILT IF NONZERO
; +2: S/ ADDRESS OF ROOM THAT CAN BE LINKED TO
LNKSRC: MOVEM T1,TGTDIR ;SAVE DIRECTION TO MOVE
ADDI T1,R.DIRS(R) ;GET ADDRESS OF THIS DIRECTION'S LINK
LDB T1,[POINTR 0(T1),DR%TYP] ;GET TYPE OF DOOR TO MATCH UP
MOVEM T1,TGTTYP ;SAVE TYPE OF DOOR TO LOOK FOR
MOVE T1,R.LOC(R) ;GET COORDINATES OF CURRENT ROOM
MOVE T2,TGTDIR ;AND DIRECTION TO SHIFT TOWARDS
CALL SHIFT ;GENERATE COORDINATES IN RIGHT AREA
MOVEM T1,TGTLOC ;REMEMBER FOR LATER
MOVE T2,R.LEVL(R) ;GET CURRENT LEVEL
MOVEI T3,CONMAX ;RANGE FOR SEARCH ALSO
SETZB S,TGTMAT ;GET READY AND CLEAR MATCH FOUND FLAG
SETZM TGTNMT ;AND CLEAR NON-TARGET MATCH FLAG
LNKSRL: CALL SRCRON ;FIND ANOTHER ROOM WITHIN RANGE
JRST LNKSRD ;ALL DONE LOOKING
MOVE T4,R.LOC(S) ;GET LOCATION OF THIS ROOM
CAMN T4,TGTLOC ;IS IT AT EXACTLY THE RIGHT PLACE?
MOVEM S,TGTMAT ;YES, REMEMBER FOR LATER
MOVE T4,TGTDIR ;GET DIRECTION
XORI T4,1 ;FLIP SINCE LOOKING FROM THAT ROOM
ADDI T4,R.DIRS(S) ;GET ADDRESS OF LINK WORD
MOVE T4,(T4) ;GET THE LINK WORD
TXC T4,DR%NXT ;COMPLEMENT BITS
TXNE T4,DR%NXT ;DOES LINK POINT TO NONEXISTANT ROOM?
JRST LNKSRL ;NO, TRY NEXT ROOM
LDB T4,[POINTR T4,DR%TYP] ;YES, GET DOOR TYPE
CAME T4,TGTTYP ;IS THIS THE TYPE WE WANT?
JRST LNKSRL ;NO, TRY NEXT ROOM
MOVE T4,R.LOC(S) ;GET LOCATION AGAIN
CAMN T4,TGTLOC ;EXACTLY AT RIGHT PLACE?
JRST CPOPJ1 ;YES, RETURN THIS ROOM THEN
MOVEM S,TGTNMT ;NO, THEN REMEMBER AN OK ROOM
JRST LNKSRL ;AND LOOK FOR A BETTER ONE
LNKSRD: SKIPE S,TGTNMT ;WAS THERE A ROOM NEARBY WE CAN USE?
JRST CPOPJ1 ;YES, RETURN IT
SKIPE TGTMAT ;WAS THERE A ROOM AT OUR EXACT COORDINATE?
TDZA T1,T1 ;YES, SAY THERE WAS A ROOM THERE
MOVE T1,TGTLOC ;NO, RETURN THE ADDRESS OF THE HOLE THEN
RET ;FAIL RETURN
SUBTTL SUBROUTINE TO DECIDE WHAT KIND OF DOORS TO CREATE
;CALLED WHENEVER A ROOM IS ENTERED, TO CHECK ALL DIRECTIONS FROM THE
;ROOM, AND DECIDE WHAT KIND OF DOORS THIS ROOM WILL HAVE. DIRECTIONS
;WHICH ALREADY HAVE A DOORWAY SET ARE NOT CHANGED. ANY DOORS BUILT
;WILL BE CLOSED. ANY LINKS TO ROOMS WILL BE TO NONEXISTANT ROOMS.
;CALL:
; R/ ADDRESS OF ROOM TO MAKE DOORS OF
;RETURNS:
; +1: ALWAYS, WITH DOORS CREATED
MAKDOR: MOVEI T1,DIRMAX ;GET READY
MOVEM T1,DORDIC ;SAVE COUNT OF DIRECTIONS
CALL RANDOM ;PICK A STARTING DIRECTION AT RANDOM
MOVEM T1,DORDIR ;INITIALIZE IT
DORLOP: SOSGE DORDIC ;MORE DIRECTIONS TO EXAMINE?
RET ;NO, DONE
AOS T1,DORDIR ;MOVE TO NEXT DIRECTION
CAIL T1,DIRMAX ;RAN OFF THE END?
SETZB T1,DORDIR ;YES, WRAP AROUND
ADDI T1,R.DIRS(R) ;GET ADDRESS OF THE LINK WORD
SKIPE (T1) ;HAS THIS DOOR BEEN CHOSEN YET?
JRST DORLOP ;YES, TRY NEXT ONE
MOVSI I,-DORNUM ;GET READY FOR A LOOP
SETZM CHCTOT ;CLEAR TOTAL CHANCE COUNTER
CHCLOP: CALL @CHCDSP(I) ;SEE WHAT CHANCE THIS DOOR SHOULD GET
JUMPL T1,CHCHAV ;NEGATIVE MEANS PICK IT NOW!
MOVEM T1,CHCTAB(I) ;REMEMBER FOR LATER
ADDB T1,CHCTOT ;AND ADD INTO TOTAL CHANCES
AOBJN I,CHCLOP ;LOOP OVER ALL TYPE OF DOORS
CALL RANDOM ;PICK A RANDOM NUMBER
MOVSI I,-DORNUM ;GET READY FOR LOOPING
SUB T1,CHCTAB(I) ;SUBTRACT WORTH OF THIS ROOM
JUMPLE T1,CHCHAV ;IF WENT NEGATIVE, HAVE ANSWER
AOBJN I,.-2 ;KEEP GOING UNTIL GET IT
FATAL (Random door selection failed)
CHCHAV: MOVX T1,DR%NXT ;GET POINTER TO NONEXISTANT ROOM
DPB I,[POINTR T1,DR%TYP] ;AND STORE TYPE CODE
MOVE T2,DORDIR ;GRAB DIRECTION
ADDI T2,R.DIRS(R) ;CREATE ADDRESS OF LINK WORD
MOVEM T1,(T2) ;SET THIS DOOR
MOVE T1,R.LEVL(R) ;GET LEVEL OF THIS ROOM
CAME T1,H.LEVL ;IS THIS IN THE LOWEST LEVEL?
JRST DORLOP ;NO, JUST LOOP
ANDX I,DR%NXT ;KEEP ONLY THE DOOR TYPE
CAIE I,DR.ALW ;A NORMAL PASSAGE?
CAIN I,DR.SRC ;OR A SECRET PASSAGE?
AOS H.LGRW ;YES, INCREMENT GROWTH POTENTIAL
CAIN I,DR.LVL ;IS THIS A LEVEL CHANGE DOOR?
AOS H.LDOR ;YES, COUNT THEM UP
JRST DORLOP ;LOOP SOME MORE
;DISPATCH TABLE FOR VARIOUS TYPES OF DOOR CHANCES. THE COMPUTED
;CHANCE (WHERE ^D1000 IS "NORMAL") IS RETURNED IN T1. IF NEGATIVE,
;THEN THAT TYPE OR DOOR IS TO BE SELECTED OVER ALL OTHERS.
CHCDSP: EXP CHCUNK ;(0) UNKNOWN
EXP CHCNEV ;(1) NEVER
EXP CHCALW ;(2) ALWAYS
EXP CHCSRC ;(3) SECRET
EXP CHCLVL ;(4) LEVEL CHANGE
EXP CHCWRD ;(5) MAGIC WORD
EXP CHCMAG ;(6) MAGIC ITEM
EXP CHCBLK ;(7) CAVE IN
DORNUM==.-CHCDSP ;NUMBER OF DOORS TO SELECT FROM
;HERE TO SEE HOW MUCH WE WANT A WALL (IE, NO PASSAGE):
CHCNEV: MOVEI T1,^D1000 ;GET STANDARD CHANCE
RET ;DONE
;HERE TO SEE HOW MUCH WE WANT A LEVEL-CHANGE DOOR:
CHCLVL: MOVEI T1,^D25 ;GET A VERY SMALL CHANCE
SKIPE H.LDOR ;ALREADY HAVE A LEVEL CHANGE DOOR?
RET ;YES, DON'T WANT MORE EASILY
SETO T1, ;GET INFINITE CHANCE
MOVE T2,H.LGRW ;AND NUMBER OF GROWING DOORS ON THIS LEVEL
SOJLE T2,CPOPJ ;IF ON LAST DOOR, MAKE THIS KIND!!
MOVE T1,H.LROM ;GET NUMBER OF ROOMS IN THIS LEVEL
CAMGE T1,H.LDWN ;CREATED ENOUGH ROOMS IN THE LEVEL YET?
TDZA T1,T1 ;NO, DON'T ALLOW THESE YET
MOVEI T1,^D500 ;YES, GET LARGE CHANCE
RET ;DONE
;HERE TO SEE HOW MUCH WE WANT A NORMAL PASSAGEWAY:
CHCALW: MOVEI T1,^D400 ;GET A CHANCE THAT WILL CLOSE OFF EVENTUALLY
MOVE T2,R.LEVL(R) ;GRAB THIS ROOM'S LEVEL
CAMGE T2,H.LEVL ;IN THE LOWEST LEVEL?
RET ;NO, USE THIS CHANCE
MOVE T2,H.LGRW ;GET NUMBER OF GROWING REGIONS
CAILE T2,^D20 ;ENOUGH TO PLAY WITH?
RET ;YES, RETURN
MOVEI T1,^D1000 ;NO, GET A MUCH LARGER CHANCE
MOVE T2,H.LROM ;GET NUMBER OF ROOMS IN THIS LEVEL
CAIGE T2,5 ;LEVEL JUST STARTED?
SETO T1, ;YES, ALWAYS USE THIS DOOR TYPE
RET ;DONE
;HERE TO SEE HOW MUCH WE WANT A SECRET DOORWAY:
CHCSRC: CALL CHCALW ;SEE HOW MUCH A NORMAL PASSAGEWAY IS WANTED
JUMPL T1,CHCBLK ;IF DESIRED, SAY WE DON'T WANT OUR TYPE
IDIVI T1,^D10 ;REDUCE CHANCE BY 90% OR SO
RET ;AND USE THAT
;HERE TO SEE HOW MUCH WE WANT MAGIC DOORS OF VARIOUS TYPES:
CHCMAG:
CHCWRD: MOVE T1,R.LEVL(R) ;GET LEVEL OF THIS ROOM
IMULI T1,^D5 ;MULTIPLY BY NICE CHANCE
CAILE T1,^D50 ;GETTING RATHER HIGH?
MOVEI T1,^D50 ;YES, REDUCE TO MAXIMUM
RET ;DONE
;HERE FOR DOOR TYPES WE NEVER WANT TO SELECT:
CHCUNK:
CHCBLK: SETZ T1, ;THESE NEVER HAPPEN
RET ;DONE
SUBTTL SUBROUTINE TO PUT TREASURE IN A ROOM
;CALLED TO POPULATE A ROOM WITH TREASURE WHEN NECESSARY. THE AMOUNT
;OF TREASURE INCREASES WITH LEVEL NUMBER, THE LENGTH OF A DEAD END,
;AND WHETHER OR NOT SECRET DOORS HIDE IT. CALL:
;
; R/ ADDRESS OF ROOM TO MAKE TREASURE FOR
;
;RETURNS:
; +1: ALWAYS, WITH R.VTRE AND R.HTRE UPDATED IF NECESSARY
MAKTRE: SKIPN R.VTRE(R) ;ANY TREASURE IN ROOM ALREADY?
SKIPE R.HTRE(R) ;WELL?
RET ;YES, DON'T MAKE ANY MORE
TDNN ZR,R.ROOM(R) ;AT THE ENTRANCE?
RET ;YES, NO TREASURE FOR THERE
MOVEI T1,R.TREF(R) ;POINT TO TREASURE FINDING WORD
CALL BITSET ;COMPUTE OFFSET AND BIT
TDNE T2,(T1) ;TRIED TO GET TREASURE HERE BEFORE?
RET ;YES, CAN'T GET ANY MORE HERE
MOVEI T1,DR.NEV ;GET NONEXISTANT TYPE CODE
CALL FNDDOR ;SEE HOW MANY THERE ARE
MOVEM T1,TRETMP ;SAVE FOR AWHILE
MOVEI T1,DR.BLK ;GET CAVED-IN DOOR TYPE
CALL FNDDOR ;SEE HOW MANY OF THEM EXIST
ADD T1,TRETMP ;GET TOTAL NUMBER
CAIGE T1,DIRMAX-1 ;IS THIS ROOM A DEAD END?
SKIPA T1,[^D25] ;NO, GET VERY SMALL CHANCE
MOVEI T1,3 ;YES, GET MUCH BETTER CHANCE
MOVE T2,R.VIST(R) ;GET NUMBER OF VISITS
CAILE T2,1 ;ARE WE THE FIRST VISITOR TO ROOM?
ADDI T1,1 ;NO, REDUCE CHANCE OF TREASURE A BIT
CALL RANDOM ;COMPUTE RANDOMNESS
JUMPN T1,TRENOM ;JUMP IF NEVER FIND TREASURE HERE
MOVEI T1,DR.SRC ;WE FIND TREASURE, GET READY
CALL FNDDOR ;SEE IF THERE IS A HIDDEN ROOM
MOVEM T1,TRETMP ;SAVE RESULT
HRRZ T1,R.LEVL(R) ;GET LEVEL OF THIS ROOM
IMULI T1,^D100 ;MULTIPLY BY CONSTANT
CALL RANDOM ;GET A RANDOM NUMBER
AOS T4,T1 ;MOVE AND ALWAYS MAKE NONZERO
SKIPE TRETMP ;IS THIS ROOM HIDDEN BY A SECRET DOOR?
ADDI T4,^D100 ;YES, INCREASE THE BOOTY
MOVEI T1,^D10 ;GET SET TO DECIDE ON 10% CHANCE
CALL RANDOM ;MAKE A RANDOM NUMBER
SKIPE T1 ;VISIBLE TREASURE WANTED?
ADDM T4,R.VTRE(R) ;YES, ADD TO IT
ADDI T4,^D100 ;HIDDEN TREASURE GETS MORE
SKIPN T1 ;INVISIBLE TREASURE WANTED?
ADDM T4,R.HTRE(R) ;YES, ADD TO IT
TRENOM: MOVEI T1,R.TREF(R) ;POINT TO TREASURE FLAGS
CALL BITSET ;MAKE OFFSET AND BIT
IORM T2,(T1) ;SAY WE GET NO MORE TREASURE HERE
RET ;DONE
SUBTTL SUBROUTINE TO MAKE A MAGICAL ITEM
;CALLED WHEN WE ENTER A ROOM, TO GENERATE A MAGICAL ITEM FOR THAT ROOM.
;ONLY ONE MAGICAL ITEM CAN BE FOUND FOR EACH LEVEL IN THE DUNGEON FOR
;EACH PLAYER, SO THAT IT IS HARD TO COLLECT ALL OF THEM. THE FIRST
;ITEM FOUND WILL BE THE FIRST MAGIC WAND, SO THAT SOME OF THE MAGIC
;DOORS CAN BE OPENED. AFTER THAT, THEY APPEAR RANDOMLY.
MAKITM: TDNE ZR,R.ROOM(R) ;IS THIS THE ENTRANCE?
SKIPE R.VITM(R) ;OR THE ROOM ALREADY HAS ITEMS?
RET ;YES, NO ITEMS TO MAKE
MOVE T1,R.LEVL(R) ;GET CURRENT LEVEL
MOVEI T4,1 ;AND A BIT
LSH T4,(T1) ;SHIFT IT
JUMPE T4,CPOPJ ;TOO LOW FOR MAGIC ITEMS!!
TDNE T4,U.ITEL(U) ;HAVE AN ITEM ALREADY FROM THIS LEVEL?
RET ;YES, NO MORE FOR YOU!!
MOVEI T1,^D50 ;GET A CHANCE
CALL RANDOM ;TO SEE IF WE FIND IT YET
JUMPN T1,CPOPJ ;NO, RETURN
MOVEI T1,ITMNUM ;GET READY
SKIPN U.ITEL(U) ;GOTTEN SOMETHING BEFORE?
SKIPA T1,[EXP IT.WD1] ;NO, THEN GET A MAGIC WAND
CALL RANDOM ;OTHERWISE COMPUTE A RANDOM OBJECT
MOVEI T3,^D200 ;GET FAILSAFE COUNTER
ITMTRY: CALL GETITU ;SEE IF WE HAVE ANY OF THIS ITEM YET
JUMPE T2,ITMBLD ;NO, GO MAKE US ONE
MOVEI T1,ITMNUM ;YES, GET READY
CALL RANDOM ;PICK ANOTHER MAGIC ITEM
SOJG T3,ITMTRY ;AND TRY TO USE IT
IORM T4,U.ITEL(U) ;SOMETHING IS WRONG, RIP HIM OFF
RET ;AND RETURN
ITMBLD: MOVEI T2,1 ;WANT ONE ITEM
CALL PUTITR ;PLACE IT IN THE ROOM
IORM T4,U.ITEL(U) ;THAT'S ALL FROM THIS LEVEL
RET ;DONE
SUBTTL SUBROUTINE TO CREATE A MONSTER IN A ROOM
;CALLED WHENEVER WE MOVE INTO A ROOM, TO CREATE A NEW MONSTER HERE
;IF THE CONDITIONS ARE RIGHT. CALL:
; R/ ADDRESS OF CURRENT ROOM
; T1/ MULTIPLY-CONNECTED-CHANCE,,SINGLEY-CONNECTED-CHANCE
MAKMON: SKIPE R.MONS(R) ;ALREADY A MONSTER HERE?
RET ;YES, DO NOTHING
HRRZ T2,R.ROOM(R) ;GET ROOM NUMBER
CAIGE T2,^D20 ;ONE OF THE REAL EARLY ROOMS?
RET ;YES, NO MONSTERS YET
PUSH P,T1 ;SAVE CHANCE
MOVEI T1,DR.NEV ;GET NONEXISTANT TYPE CODE
CALL FNDDOR ;SEE HOW MANY THERE ARE
MOVEM T1,TRETMP ;SAVE FOR AWHILE
MOVEI T1,DR.BLK ;GET CAVED-IN DOOR TYPE
CALL FNDDOR ;SEE HOW MANY OF THEM EXIST
ADD T1,TRETMP ;GET TOTAL NUMBER
POP P,T2 ;RESTORE CHANCES
CAILE T1,DIRMAX-3 ;IS THIS ROOM MULTIPLY CONNECTED?
SKIPA T1,T2 ;NO, GET ONE CHANCE
MOVS T1,T2 ;YES, GET OTHER CHANCE
ANDI T1,-1 ;CLEAR LEFT HALF
CALL RANDOM ;COMPUTE RANDOM NUMBER
JUMPN T1,CPOPJ ;RETURN IF NOT TIME FOR A MONSTER
MOVEI T4,^D100 ;MAXIMUM TRIES IN CASE OF A BUG
MONSRC: SOJLE T4,CPOPJ ;FAIL IF TRIED TOO MUCH
MOVEI T1,MONNUM ;GET NUMBER OF MONSTERS
CALL RANDOM ;PICK ONE AT RANDOM
HLRZ T2,MONPWR(T1) ;GET STRENGTH OF MONSTER
ADD T2,MONPWR(T1) ;WHICH IS SUM OF ATTACK AND DEFENSE
ANDI T2,-1 ;KEEP ONLY RIGHT HALF
IDIVI T2,3 ;GET WHAT "LEVEL" THIS MONSTER IS
CAMLE T2,R.LEVL(R) ;ARE WE DOWN TO THAT LEVEL YET?
JRST MONSRC ;NO, DON'T USE THIS MEAN MONSTER
ADDI T2,^D10 ;ADD 10 LEVELS
CAMGE T2,R.LEVL(R) ;MONSTER TOO WIMPY FOR THIS LEVEL?
JRST MONSRC ;YES, DON'T USE IT
MOVE T4,T1 ;PUT INDEX IN SAFE AC
HLRZ T3,MONPWR(T4) ;GET MAXIMUM STRENGTH OF MONSTER
LSH T3,1 ;HALF IT
MOVE T1,T3 ;PUT IN RIGHT AC
CALL RANDOM ;RANDOMIZE IT
ADD T1,T3 ;ADD IN HALF STRENGTH ALSO
MOVE T2,R.LEVL(R) ;GET LEVEL
SUBI T2,1 ;DECREMENT
IMULI T2,3 ;MULTIPLY BY A CONSTANT
ADD T1,T2 ;MAKE IT STRONGER!
MOVEM T1,R.MONH(R) ;SAVE STRENGTH OF THE MONSTER
HRROM T4,R.MONS(R) ;SAY A MONSTER EXISTS NOW
AOS H.MONS ;INCREMENT NUMBER OF MONSTERS IN DUNGEON
RET ;DONE
SUBTTL SUBROUTINE TO ALLOCATE A NEW ROOM
;CALLED TO FIND THE NEXT FREE LOCATION IN THE DATA FILE, AND ALLOCATE
;A NEW ROOM. THE ROOM IS LEFT EMPTY, WITH NO LINKS TO ANY OTHER ROOM.
;ACCEPTS:
; T1/ COORDINATES WHERE THIS ROOM IS
; T2/ LEVEL THIS ROOM IS ON
;
;RETURNS:
; +1: UNABLE TO MAKE A NEW ROOM
; +2: S/ ADDRESS OF THIS ROOM'S DATA BLOCK
MAKROM: MOVE S,H.ROOM ;GET NEXT AVAILABLE ROOM NUMBER
IMULI S,ROMSIZ ;THEN COMPUTE OFFSET INTO ROOM DATA
ADDI S,ROMADR ;AND RELOCATE TO CORRECT ADDRESS
CAIL S,MAPLST-ROMSIZ-2 ;ROOM FOR A NEW ROOM?
RET ;NO, ERROR RETURN
MOVSI T3,0(S) ;GET READY TO CLEAR THE DATA
IORI T3,1(S) ;BEFORE USING IT
SETZM 0(S) ;CLEAR FIRST WORD
ERJMP CPOPJ ;NO MORE DISK, FAIL RETURN
BLT T3,ROMSIZ-1(S) ;THEN THE REST
ERJMP CPOPJ ;NO DISK, FAIL
MOVEM T1,R.LOC(S) ;SET WHERE THIS ROOM IS
MOVEM T2,R.LEVL(S) ;AND WHAT LEVEL IT IS ON
MOVE T3,H.ROOM ;GET ROOM NUMBER
HRROM T3,R.ROOM(S) ;AND SET IT
SETOM R.FVIS(S) ;CLEAR WHO FIRST VISITED ROOM
SETOM R.LVIS(S) ;AND WHO LAST VISITED ROOM
AOS H.ROOM ;INCREMENT NUMBER OF ROOMS TOTAL
CAMG T2,H.LEVL ;IS THIS A LOWER LEVEL THAN PREVIOUSLY?
JRST MAKRM2 ;NO, SKIP ON
MOVEM T2,H.LEVL ;YES, SET NEW LOWEST LEVEL
SETZM H.LROM ;CLEAR NUMBER OF ROOMS IN THIS LEVEL
SETZM H.LDOR ;AND NUMBER OF LEVEL CHANGE DOORS
SETZM H.LGRW ;INITIALIZE GROWABLE DOORS TOO
SETZM H.LLUK ;NO LUCKY ROOM YET
MOVEI T1,^D200 ;GET NICE NUMBER
CALL RANDOM ;RANDOMIZE IT SOME
ADDI T1,^D200 ;SHIFT SO IS IN RANGE 200-400
MOVEM T1,H.LDWN ;SET ROOMS NEEDED BEFORE LEVEL-CHANCE IS DONE
MOVE T2,H.LEVL ;RESTORE T2
MAKRM2: CAMN T2,H.LEVL ;BUILDING A ROOM ON THE LOWEST LEVEL?
AOS H.LROM ;YES, BUMP COUNT OF ROOMS THERE
TDNN ZR,R.ROOM(S) ;ENTRANCE ROOM?
JRST CPOPJ1 ;YES, NO MAGIC WORDS HERE
MOVEI T1,^D20 ;OTHERWISE GET A CHANCE
CALL RANDOM ;SEE IF WE NEED A MAGIC WORD HERE
JUMPN T1,CPOPJ1 ;NO, GOOD RETURN
MOVE T1,H.WORD ;GET NUMBER OF MAGIC WORDS IN USE
CAIGE T1,WRDMAX ;REACHED THE MAXIMUM?
AOSA H.WORD ;NO, INCREMENT NUMBER IN USE
CALL RANDOM ;YES, GENERATE RANDOM ONE
ADDI T1,1 ;COMPENSATE FOR WORD 0 WHICH ISN'T USED
MOVEM T1,R.WORD(S) ;REMEMBER WHICH WORD IS IN ROOM
JRST CPOPJ1 ;GOOD RETURN
SUBTTL SUBROUTINE TO SEARCH FOR ROOMS
;CALLED TO LOOK FOR THE NEXT ROOM MATCHING THE GIVEN CONDITIONS,
;AND RETURN THE ADDRESS OF IT'S DATA. CALL:
;
; T1/ ADDRESS TO SEARCH AROUND
; T2/ LEVEL OF ROOM
; T3/ RANGE FOR SEARCHING
; S/ LAST ROOM EXAMINED, OR 0
;
;RETURNS:
;
; +1: ROOM NOT EXISTANT
; +2: ROOM FOUND, ADDRESS IN AC S
;
;AC'S T1-T3 ARE PRESERVED. CALL SRCROM TO SEARCH FOR JUST ONE ROOM,
;SRCRON TO SEARCH WITH A RANGE.
SRCROM: SETZB T3,S ;RANGE OF ZERO, AND NONE KNOWN YET
SRCRON: SKIPN S ;WANT TO START AT THE BEGINNING?
MOVEI S,ROMADR-ROMSIZ ;YES, SET IT UP
MOVE T4,H.ROOM ;GET NUMBER OF ROOMS
IMULI T4,ROMSIZ ;MAKE SIZE
ADDI T4,ROMADR ;RELOCATE TO AN ADDRESS
MOVEM T4,MAXADR ;SAVE IT AWAY
SRCRLP: ADDI S,ROMSIZ ;ADVANCE TO THE NEXT ROOM
CAMLE S,MAXADR ;LOOKED AT THEM ALL YET?
RET ;YES, WE DIDN'T FIND IT
CAME T2,R.LEVL(S) ;IS THIS THE CORRECT DEPTH?
JRST SRCRLP ;NO, SKIP THE ROOM
CAMN T1,R.LOC(S) ;EXACT MATCH OF COORDINATES?
JRST CPOPJ1 ;YES, WE FOUND IT
JUMPE T3,SRCRLP ;GO ON IF HAS TO BE EXACT
HLRZM T1,TEMP ;STORE THE X COORDINATE FOR AWHILE
HLRZ T4,R.LOC(S) ;GET X COORDINATE OF THIS ROOM
SUB T4,TEMP ;GET DIFFERENCE
MOVM T4,T4 ;KEEP ABSOLUTE VALUE
CAMLE T4,T3 ;WITHIN RANGE?
JRST SRCRLP ;NO, GO TO NEXT ROOM
HRRZM T1,TEMP ;STORE Y COORDINATE
HRRZ T4,R.LOC(S) ;GET Y COORDINATE OF THIS ROOM
SUB T4,TEMP ;GET DIFFERENCE
MOVM T4,T4 ;KEEP ABSOLUTE VALUE
CAMLE T4,T3 ;WITHIN RANGE?
JRST SRCRLP ;NO, KEEP SEARCHING
CPOPJ1: AOS (P) ;WE FOUND ONE WITHIN RANGE
RET ;DONE
SUBTTL SUBROUTINE TO RETURN DESIRED DOORS
;THIS SUBROUTINE SEARCHES THE CURRENT ROOM, AND RETURNS IN THE TABLE
;DORTAB WHICH DIRECTIONS HAVE A SPECIFIED TYPE OF DOOR. THIS IS USED
;SO THAT THE OUTPUT OF WHICH KIND OF DOORS EXIST CAN BE DONE.
;CALL:
; R/ ADDRESS OF THIS ROOM
; T1/ DOOR TYPE
;RETURNS:
; +1: T1/ NUMBER OF DOORS FOUND
; DORTAB TABLE/ -1 IF DIRECTION HAS THAT DOOR, 0 IF NOT
FNDDOR: MOVSI T2,-DIRMAX ;GET READY FOR LOOPING
SETZ T3, ;CLEAR COUNTER
FNDDOL: HRRZ T4,T2 ;COPY DIRECTION
ADDI T4,R.DIRS(R) ;GET ADDRESS OF THE POINTER WORD
LDB T4,[POINTR 0(T4),DR%TYP] ;GET TYPE OF DOOR
SETOM DORTAB(T2) ;ASSUME FOUND THE DOOR
CAMN T1,T4 ;DID WE REALLY?
AOSA T3 ;YES, COUNT UP DIRECTIONS FOUND
SETZM DORTAB(T2) ;NO, CLEAR THE WORD
AOBJN T2,FNDDOL ;LOOP OVER ALL DIRECTIONS
MOVE T1,T3 ;COPY COUNT
RET ;DONE
SUBTTL SUBROUTINE TO MAKE HANDLING BIT TABLES EASY
;CALLED TO COMPUTE THE ADDRESS AND BIT POSITION INTO A TABLE WHICH
;IS TO BE INDEXED BY THE PLAYER NUMBER. CALL:
;
; T1/ ADDRESS OF START OF TABLE
;RETURNS:
; T1/ ADDRESS WHERE BIT IS
; T2/ BIT POSITIONED PROPERLY
;USES T1-T3
BITSET: MOVE T2,MYNUM ;GET WHICH PLAYER I AM
IDIVI T2,^D36 ;SPLIT INTO OFFSET AND BIT POSITION
ADD T1,T2 ;ADD OFFSET TO START OF TABLE
MOVEI T2,1 ;GET THE BIT READY
LSH T2,(T3) ;POSITION IT TO PROPER PLACE
RET ;DONE
SUBTTL SUBROUTINES TO USE FOR MAGICAL ITEMS
;THESE ROUTINES ARE CALLED TO MANIPULATE MAGICAL ITEMS. SINCE MANY
;ITEMS ARE PACKED INTO A WORD, IT IS USEFUL TO HAVE SUBROUTINES TO
;REFERENCE THEM.
;ROUTINES TO READ THE NUMBER OF ITEMS A PARTICULAR ROOM OR PERSON
;IS CARRYING. CALL:
; T1/ ITEM NUMBER
;RETURNS:
; T1/ ITEM NUMBER
; T2/ NUMBER OF ITEMS CARRIED
;SAVES T3 AND T4.
GETITR: SKIPA T2,R.VITM(R) ;GET WORD FROM ROOM
GETITU: MOVE T2,U.ITEM(U) ;OR FROM THE PLAYER
PUSH P,T3 ;SAVE T3
MOVN T3,T1 ;GET NEGATIVE NUMBER
IMULI T3,ITMWID ;MULTIPLY BY BITS PER ITEM
LSH T2,(T3) ;SHIFT TO SELECT RIGHT ITEM COUNT
ANDI T2,ITMMSK ;CLEAR ALL OTHER STUFF
POP P,T3 ;RESTORE AC
RET ;RETURN COUNT
;ROUTINES TO SAVE THE NUMBER OF ITEMS A PARTICULAR ROOM OR PLAYER IS
;CARRYING. CALL:
; T1/ ITEM NUMBER
; T2/ NUMBER OF ITEMS
;
;DESTROYS T2 AND T3. IF MORE ITEMS ARE SPECIFIED THAN WILL FIT IN
;THE FIELD, THE EXCESS IS IGNORED AND THE MAXIMUM IS STORED.
PUTITR: SKIPA T3,[Z R.VITM(R)] ;GET POINTER TO ROOM'S ITEMS
PUTITU: MOVE T3,[Z U.ITEM(U)] ;OR THE USER'S ITEMS
MOVEM T3,TEMP ;SAVE
TXNE T2,ITMMSK+1 ;MORE ITEMS THAN WE CAN STORE?
MOVEI T2,ITMMSK ;YES, USE THE MAXIMUM
MOVEI T3,ITMMSK ;GET MASK READY
PUSH P,T1 ;SAVE ITEM
IMULI T1,ITMWID ;FINISH SHIFT VALUE
LSH T2,(T1) ;POSITION NEW VALUE
LSH T3,(T1) ;AND MASK
ANDCAM T3,@TEMP ;CLEAR CURRENT VALUE
IORM T2,@TEMP ;AND SET NEW VALUE
POP P,T1 ;RESTORE ITEM
RET ;DONE
SUBTTL ROUTINES TO HANDLE PATH MANIPULATION
;THESE SUBROUTINES ARE USED TO INSERT, DELETE, OR SEARCH FOR
;PATH DEFINITIONS. THESE ARE STORED IN THE U.PATH AREA OF THE
;USER'S DATA BLOCK. EACH PATH DEFINITIONS LOOKS LIKE:
; 0/ SIXBIT NAME OF PATH
; 1/ LEFT HALF: NUMBER OF WORDS OF DIRECTION CODES
; 2/ RIGHT HALF: FIRST FEW DIRECTION CODES
; 3-N/ MORE DIRECTION CODES
;
;THE DIRECTION CODES ARE STORED IN BYTES, AND A -1 BYTE INDICATES THE
;END OF THE LIST. PATH DEFINITIONS FOLLOW EACH OTHER. END OF PATHS
;IS DETERMINED BY A ZERO NAME. LAST WORD OF TABLE IS ALWAYS ZERO.
;SUBROUTINE TO SEARCH FOR A SPECIFIED PATH. CALL:
; T1/ NAME OF PATH
;RETURNS:
; +1: NO SUCH PATH, T1/ FIRST FREE LOCATION IN TABLE
; +2: FOUND IT, T1/ ADDRESS OF THE PATH
;USES T2 AND T3.
PTHSRC: MOVEM T1,PTHTMP ;REMEMBER PATH LOOKING FOR
MOVEI T1,U.PATH(U) ;SET UP ADDRESS TO START AT
PTHSRL: SKIPN T2,0(T1) ;ANY NAME HERE?
RET ;NO MORE, GIVE FAILURE RETURN
HLRZ T3,1(T1) ;GET LENGTH OF THIS PATH
ADD T3,T1 ;COMPUTE LAST WORD OF DEFINITION
CAME T3,T1 ;SEE IF ZERO LENGTH
CAIL T3,U.PATH+PTHMAX-1(U) ;OR GOING OFF OF END
ERROR (,,? Size of path definition is illegal) ;YES
CAMN T2,PTHTMP ;IS THIS THE PATH?
JRST CPOPJ1 ;YES, RETURN IT
AOS T1,T3 ;NO, GET ADDRESS OF NEXT DEFINITION
JRST PTHSRL ;CONTINUE LOOKING
;SUBROUTINE TO DELETE A PATH DEFINITION. CALL:
; T1/ PATH NAME
;RETURNS:
; +1: ALWAYS, WITH PATH DEFINITION DELETED
;THIS IS A NO-OP IF THE PATH WAS NOT DEFINED.
;USES T1-T3.
PTHDEL: CAMN T1,U.PATN(U) ;DELETING THE PATH WE WERE FOLLOWING?
SETZM U.PATN(U) ;YES, CAN'T FOLLOW IT ANY LONGER
CALL PTHSRC ;LOOK FOR THE PATH FIRST
RET ;NOT THERE, SO NOTHING TO DO
MOVEI T2,U.PATH+PTHMAX-1(U) ;GET LAST ADDRESS OF DEFINITION AREA
HLRZ T3,1(T1) ;GET ONE LESS THAN SIZE OF BLOCK
ADDI T3,1 ;MAKE SIZE
SUB T2,T3 ;COMPUTE LAST WORD TO BLT TO
ADD T3,T1 ;GET ADDRESS OF NEXT BLOCK
HRL T1,T3 ;FINISH BLT POINTER
BLT T1,(T2) ;MOVE OTHER DEFINITIONS UP ON TOP OF OURS
RET ;DONE
;SUBROUTINE TO INSERT A PATH DEFINITION. THE PATH IS INSERTED BY SCANNING
;THE MOVLST TABLE. ANY NEW PATH WILL DELETE THE OLD ONE. CALL:
; T1/ PATH NAME
;RETURNS:
; +1: NOT ENOUGH STORAGE LEFT FOR THIS PATH
; +2: NEW DEFINITION STORED, T1/ PATH NAME, T2/ ADDRESS OF DEFINITION
;USES T2-T4.
PTHADD: MOVEM T1,PTHNAM ;SAVE PATH TO BE CREATED
CALL PTHDEL ;REMOVE ANY EXISTING DEFINITION
SETZ T1, ;GET READY
CALL PTHSRC ;LOOK FOR FIRST HOLE IN TABLE
JFCL ;CAN RETURN EITHER WAY
MOVEM T1,PTHTMP ;REMEMBER WHERE WE ARE ADDING
ADD T1,[POINT PTHWID,1,17] ;FINISH BYTE POINTER
MOVE T2,[POINT PTHWID,MOVLST] ;GET OTHER ONE
MOVEI T3,U.PATH+PTHMAX-1(U) ;GET ADDRESS OF FIRST ILLEGAL WORD
PTHADL: IBP T1 ;MOVE TO NEXT BYTE
CAIG T3,(T1) ;OVERFLOWING STORAGE?
RET ;YES, RETURN BAD
ILDB T4,T2 ;NO, GET NEXT DIRECTION
DPB T4,T1 ;STORE IT
CAIE T4,PTHMSK ;LIST TERMINATED?
JRST PTHADL ;NO, GO TO NEXT ONE
SETZM 1(T1) ;MAKE SURE NEXT WORD IS END OF TABLE
SUB T1,PTHTMP ;SEE HOW MANY WORDS WE USED
MOVE T2,PTHTMP ;GET ADDRESS OF LOCATION
HRLM T1,1(T2) ;STORE SIZE OF DEFINITION
MOVE T1,PTHNAM ;GET BACK NAME
MOVEM T1,0(T2) ;SET IT NOW
JRST CPOPJ1 ;GOOD RETURN
SUBTTL SUBROUTINE TO INITIALIZE THE DATA FILE
;THIS PRIVILEGED COMMAND WILL ZERO OUT THE DATA FILE AND MAKE A NEW
;DUNGEON. DOES THE "INITIALIZE" COMMAND.
CMDINI: NOISE (THE DUNGEON) ;DO SOME NOISE
CONFRM ;CONFIRM THE LINE
HRROI T1,[ASCIZ/
WARNING: This command will destroy the current dungeon. Type ^C
within 15 seconds if you want to abort this command.
/] ;GET STRING
PSOUT ;WARN HIM WHAT IS HAPPENING
MOVEI T1,^D15000 ;GET A TIME
DISMS ;WAIT THAT LONG
CALL FILCLS ;CLOSE UP THE CURRENT FILE
CALL FILINI ;THEN INITIALIZE THE NEW FILE
CALL FILOPN ;AND OPEN IT BACK UP
TXZ F,FR.PLY ;NO LONGER PLAYING
TXO F,FR.BLD ;MAKE SURE COMMANDS ARE RIGHT
STROUT [ASCIZ/
Done.
/] ;TYPE OUT WE DID IT
RET ;DONE
SUBTTL COMMAND TO BECOME ANOTHER PLAYER
;THIS PRIVILEGED COMMAND ALLOWS THE GODLY PERSON TO CHANGE WHO HE IS
;PLAYING AS, TO MAKE DEBUGGING EASIER.
CMDBEC: NOISE (THE PLAYER) ;DO NOISE
CALL PARUSR ;READ IN THE USER NUMBER
MOVE T4,T2 ;SAVE IT
CONFRM ;CONFIRM THE LINE
HRLI T4,USRLH ;PUT IN LEFT HALF CODE
MOVEM T4,PLYUSR ;SET WHO WE ARE PLAYING AS
TXZ F,FR.PLY ;WE ARE NOT PLAYING ANYMORE
TXO F,FR.BLD ;HAVE TO REBUILD COMMAND TABLE
SETZB U,R ;NO POINTERS ARE VALID ANYMORE
STROUT [ASCIZ/
Done.
/] ;SAY WE ARE DONE
RET ;RETURN
SUBTTL SUBROUTINE TO SEARCH DATA FILE FOR MY ENTRY
;CALLED TO SEARCH THE DATA FILE FOR MY ENTRY, AND RETURN THE OFFSET
;INTO THE FILE IN AC "U" SO MY DATA CAN BE REFERENCED. IF I AM NOT
;CURRENTLY IN THE FILE, I WILL BE INSERTED. DOESN'T RETURN ON ERRORS.
FINDME: CALL LOCK ;INTERLOCK THE FILE DATA
MOVE T1,PLYUSR ;GET MY USER NUMBER READY FOR SEARCHING
CALL FNDUSR ;LOOK FOR MY ENTRY
JRST NEWPLR ;NOT FOUND, GO INSERT ME
MOVE U,T2 ;OK, PUT ADDRESS INTO RIGHT AC
JRST OLDPLR ;AND GO FINISH UP
NEWPLR: CAIL T2,ROMADR ;ANY ROOM LEFT FOR A NEW PLAYER?
ERROR (,,<Sorry, no room left for new players>) ;NO
MOVE U,T2 ;REMEMBER ADDRESS
MOVSI T2,0(U) ;GET ADDRESS OF THIS ENTRY
HRRI T2,1(U) ;AND THE NEXT WORD
SETZM 0(U) ;CLEAR FIRST WORD
BLT T2,PLRSIZ-1(U) ;THEN CLEAR REST TOO
MOVEM T1,U.USER(U) ;REMEMBER WHO WE ARE
GTAD ;GET TODAY'S DATE
MOVEM T1,U.BDAT(U) ;REMEMBER WHEN WE ENTERED THE GAME
MOVEM T1,U.LDAT(U) ;AND SET WHEN LAST PLAYED TOO
AOS U.TURN(U) ;START US AT TURN 1
AOS U.LEVL(U) ;MAKE US A LEVEL 1 CHARACTER
MOVEI T1,^D100 ;MAKE US FULL STRENGTH
MOVEM T1,U.POWR(U) ;DO IT
MOVEM T1,U.POWM(U) ;AND SET MAXIMUM
AOS H.PLRS ;ONE MORE PLAYER EXISTS
OLDPLR: CALL UNLOCK ;UNLOCK THE FILE
ANDI U,-1 ;KEEP ONLY THE ADDRESS
MOVEI T1,-PLRADR(U) ;GET OFFSET INTO PLAYER AREA
IDIVI T1,PLRSIZ ;DIVIDE BY SIZE OF EACH DATA BLOCK
MOVEM T1,MYNUM ;REMEMBER FOR USE LATER
MOVE R,U.ROOM(U) ;GET THE ROOM NUMBER
IMULI R,ROMSIZ ;MULTIPLY BY SIZE OF EACH ROOM'S DATA
ADDI R,ROMADR ;OFFSET TO PROPER PLACE
CPOPJ: RET ;DONE
SUBTTL SUBROUTINE TO FIND A PARTICULAR PLAYER
;CALLED TO SEARCH THE DATA FILE FOR A PARTICULAR PLAYER, AND RETURN
;THE ADDRESS OF HIS DATA BLOCK.
;CALL:
; T1/ PLAYER NUMBER
;RETURNS:
; +1: NOT FOUND, FIRST FREE ADDRESS IN T2
; +2: FOUND, ADDRESS OF PLAYER'S DATA IN T2.
;USES NO OTHER ACS
FNDUSR: HRLZ T2,H.PLRS ;GET NUMBER OF PLAYERS READY
MOVN T2,T2 ;MAKE INTO AOBJN POINTER
ADDI T2,PLRADR ;OFFSET TO THE FIRST PLAYER'S DATA
CAIN T2,PLRADR ;ANY PLAYERS?
RET ;NO, NON-SKIP RETURN
FINDLP: CAMN T1,U.USER(T2) ;FOUND MY ENTRY YET?
JRST CPOPJ1 ;YES, SKIP RETURN
ADDI T2,PLRSIZ-1 ;NO, INCREMENT TO NEXT ENTRY
AOBJN T2,FINDLP ;AND KEEP SEARCHING
RET ;FAIL
SUBTTL SUBROUTINE TO LOCK AND UNLOCK THE FILE
;SUBROUTINES TO INTERLOCK THE DATA FILE TO PREVENT TWO USERS FROM
;WRITING DATA AT THE SAME TIME. THIS IS THE OLD "AOSE" INTERLOCK
;ALGORITHM. TO HELP DETERMINE WHAT IS WRONG IF THE INTERLOCK IS
;WRECKED, WE SAVE DATA WHEN THE LOCK IS OBTAINED. NO AC'S
;ARE CHANGED.
LOCK: TXNN F,FR.MAP ;MAKE SURE IT IS MAPPED IN
FATAL (Attempt to interlock file which is not mapped) ;FAIL
TXNE F,FR.LCK ;CALLING THIS WHILE LOCKED?
FATAL (Attempt to interlock file twice) ;YES
ADJSP P,4 ;ALLOCATE SOME STACK
DMOVEM T1,-1(P) ;SAVE SOME AC'S
DMOVEM T3,-3(P) ;SO THEY AREN'T HURT
MOVEI T4,^D60 ;TRY THIS FOR A MINUTE
LOCKLP: GTAD ;READ THE TIME OF DAY
MOVE T2,MYJOB ;GET MY JOB NUMBER
MOVE T3,MYUSER ;AND WHO I AM
AOSE H.LOCK ;TRY TO GET THE LOCK
JRST NOLOCK ;FAILED, GO WAIT
MOVEM T1,H.LTIM ;SAVE THE TIME
MOVEM T2,H.LJOB ;AND THE JOB NUMBER
MOVEM T3,H.LUSR ;AND WHO I AM
DMOVE T3,-3(P) ;RESTORE THE ACS
DMOVE T1,-1(P) ;THAT WERE SAVED
ADJSP P,-4 ;FIX STACK
TXO F,FR.LCK ;FILE IS LOCKED NOW
RET ;DONE
NOLOCK: MOVEI T1,^D1000 ;GET READY
DISMS ;WAIT A BIT
SOJG T4,LOCKLP ;TRY AGAIN UNLESS TIMED OUT
ERROR (,,Can't get interlock on data file) ;COMPLAIN
;HERE TO UNLOCK THE FILE. NO ACS ARE CHANGED.
UNLOCK: TXNN F,FR.LCK ;MAKE SURE FILE WAS LOCKED
FATAL (Attempt to unlock data file which wasn't locked)
SETOM H.LOCK ;MAKE THE INTERLOCK AVAILABLE
PUSH P,T1 ;SAVE SOME ACS
PUSH P,T2 ;THAT WE USE
HRLZ T1,FILJFN ;GET THE JFN READY
MOVEI T2,-1 ;GET ALMOST LARGE ENOUGH COUNT
UFPGS ;UPDATE THE FILE NOW
ERJMP DIE ;FAILED
POP P,T2 ;RESTORE THEM
POP P,T1 ;AS THEY WERE
TXZ F,FR.LCK ;NOT LOCKED NOW
RET ;DONE
SUBTTL SUBROUTINE TO OPEN DATA FILE AND MAP IT IN
;SUBROUTINE TO OPEN UP THE DATA FILE AND MAP IT IN. NEVER SKIPS.
;DOESN'T RETURN IF ANY ERROR IS ENCOUNTERED.
FILOPN: TXNE F,FR.MAP ;IS FILE MAPPED IN YET?
RET ;YES, DONE
SETZB U,R ;WE DON'T KNOW ROOM OR OUR LOCATION
MOVX T1,GJ%OLD+GJ%PHY+GJ%SHT ;FLAGS
HRROI T2,FILNAM ;FILE NAME
GTJFN ;TRY TO GET A JFN
ERJMP DIE ;FAILED
MOVEM T1,FILJFN ;SAVE THE JFN
MOVX T2,OF%RD+OF%WR+OF%THW+OF%DUD ;GET FLAGS
OPENF ;TRY TO OPEN THE FILE
ERJMP DIE ;FAILED
HRLZ T1,FILJFN ;GET READY
MOVE T2,[.FHSLF,,MAPADR/PAGSIZ] ;GET ARGS
MOVX T3,PM%RD+PM%WR+PM%CNT+<<MAPLST-MAPADR>/PAGSIZ> ;FLAGS
PMAP ;MAP IN THE FILE
ERJMP DIE ;FAILED
TXO F,FR.MAP ;FILE NOW MAPPED IN
MOVE T1,H.VERS ;GET THE VERSION OF THE FILE
CAIN T1,HDRVER ;IS THIS THE CORRECT VERSION?
RET ;YES, ALL DONE
CALL FILCLS ;NO, CLOSE IT
FATAL (Wrong version in data file) ;DIE
;HERE IF AN ERROR IS ENCOUNTERED:
DIE: HRROI T1,[ASCIZ/
? /] ;GET READY
PSOUT ;TYPE THE STRING
MOVEI T1,.PRIOU ;GET READY
HRLOI T2,.FHSLF ;TO TYPE MY ERROR
SETZ T3, ;ALL OF IT
ERSTR ;PRINT ERROR
JFCL ;IGNORE FAILURE
JFCL
HRROI T1,[ASCIZ/
/] ;FINISHING TEXT
PSOUT ;TYPE IT
HALTF ;QUIT
JRST .-1 ;STAY THAT WAY
SUBTTL SUBROUTINE TO CLOSE THE MAPPED FILE
;ROUTINE TO UNMAP THE FILE FROM CORE, AND CLOSE IT. NEVER SKIPS.
FILCLS: TXZN F,FR.MAP ;IS FILE MAPPED IN?
RET ;NO, NOTHING TO DO
SETO T1, ;WANT TO UNMAP FILE PAGES
MOVE T2,[.FHSLF,,<MAPADR/PAGSIZ>] ;FROM MY PROCESS
MOVX T3,PM%RD+PM%WR+PM%CNT+<<MAPLST-MAPADR>/PAGSIZ> ;FLAGS
PMAP ;UNMAP THEM
MOVE T1,FILJFN ;GET THE JFN
CLOSF ;RELEASE THE FILE
ERJMP DIE ;FAILED
SETZM FILJFN ;CLEAR THE JFN
RET ;DONE
SUBTTL SUBROUTINE TO INITIALIZE THE DATA FILE
;PRIVILEGED SUBROUTINE CALLED TO INITIALIZE THE DUNGEON. THIS CONSISTS
;OF WRITING A NEW VERSION OF THE DATA FILE, WITH NO ROOMS AND NO PLAYERS.
;THE HEADER AREA IS SET UP TO A GOOD STATE.
FILINI: MOVX T1,GJ%FOU+GJ%SHT ;WANT A NEW VERSION
HRROI T2,FILNAM ;OF THE FILE
GTJFN ;GET A JFN ON IT
ERJMP DIE ;FAILED
MOVEM T1,FILJFN ;SAVE THE JFN
MOVX T2,OF%RD+OF%WR ;WANT TO WRITE THE FILE
OPENF ;OPEN IT UP
ERJMP DIE ;FAILED
HRLI T1,<.FBSIZ(CF%NUD)> ;EOF OFFSET AND NO UPDATE BIT
SETO T2, ;WHOLE WORD IS TO BE CHANGED
HRLOI T3,377777 ;TO INFINITY
CHFDB ;MAKE THE CHANGE
ERJMP DIE ;FAILED
HRLI T1,<.FBBYV(CF%NUD)> ;WANT TO SET BYTE SIZE
MOVX T2,FB%BSZ ;MASK FOR IT
MOVX T3,<FLD(^D36,FB%BSZ)> ;VALUE
CHFDB ;CHANGE IT
ERJMP DIE ;FAILED
HRLZ T1,FILJFN ;MAP FROM PAGE ZERO
MOVE T2,[.FHSLF,,<MAPADR/PAGSIZ>] ;GET READY
MOVX T3,PM%RD+PM%WR+PM%CNT+<<MAPLST-MAPADR>/PAGSIZ> ;FLAGS
PMAP ;MAP PAGE ZERO OF THE FILE
ERJMP DIE ;FAILED
MOVE T1,[MAPADR,,MAPADR+1] ;GET READY
SETZM MAPADR ;TO CLEAR THE PAGE
BLT T1,MAPADR+HDRSIZ-1 ;CLEAR THE HEADER
MOVEI T1,HDRVER ;GET THE VERSION OF THE DATA FILE
MOVEM T1,H.VERS ;INITIALIZE IT
GTAD ;GET THE CURRENT TIME AND DATE
MOVEM T1,H.DATE ;REMEMBER IT
MOVEI T1,PLRADR-MAPADR ;GET OFFSET INTO FILE OF USER DATA
MOVEM T1,H.UADR ;REMEMBER IT
MOVEI T1,PLRSIZ ;GET SIZE OF EACH DATA AREA
MOVEM T1,H.USIZ ;REMEMBER IT
MOVEI T1,ROMADR-MAPADR ;GET OFFSET OF ROOM DATA
MOVEM T1,H.RADR ;REMEMBER IT
MOVEI T1,ROMSIZ ;GET SIZE OF EACH DATA AREA
MOVEM T1,H.RSIZ ;REMEMBER IT TOO
;MORE INITIALIZATION OF THE FILE:
MOVE T1,[MID,,MID] ;GET COORDINATES OF ROOM 0
MOVEI T2,0 ;WHICH IS IN LEVEL 0
CALL MAKROM ;BUILD IT
FATAL (Failed to build room 0)
HRLOI T1,DR.NEV ;GET CODE FOR NONEXISTANT DOORS
MOVEM T1,R.DIRS(S) ;PLACE IN FIRST DIRECTION
MOVSI T1,R.DIRS+0(S) ;GET ADDRESS
IORI T1,R.DIRS+1(S) ;AND NEXT ONE
BLT T1,R.DIRS+DIRMAX-1(S) ;MAKE ALL DIRECTIONS INVALID
HRLOI T1,DR.LVL ;NOW GET CODE FOR A LEVEL DOOR
MOVEM T1,R.DIRS(S) ;AND PLACE IN FIRST DIRECTION
SETOM H.LOCK ;MAKE THE INTERLOCK AVAILABLE
TXO F,FR.MAP ;ACT LIKE WE HAVE FILE MAPPED
CALL FILCLS ;CLOSE THE FILE
RET ;THEN RETURN
SUBTTL SUBROUTINE TO MAKE A MAGIC PHRASE
;CALLED WITH A GENERATING NUMBER IN T1, TO USE THE NUMBER AND THE
;WORD TABLES TO STORE A MAGIC PHRASE INTO THE MAGTXT BUFFER. CALL:
;
; T1/ GENERATING NUMBER
;
;RETURNS:
; +1: ALWAYS, WITH TEXT STORED.
;
;THE MAGIC PHRASE IS FROM 2 TO 4 WORDS LONG, WHERE EACH WORD IS FROM
;2 TO 3 SYLLABLES IN LENGTH.
MAKWRD: PUSH P,RANNUM ;SAVE RANDOM NUMBER
ADD T1,H.DATE ;ADD IN TIME OF DUNGEON CREATION
MOVEM T1,RANNUM ;AND STORE THE GIVEN SEED
CALL RANDOM ;JUMBLE IT ONCE
CALL RANDOM ;DO AGAIN TO HELP IT
MOVE T4,[POINT 7,MAGTXT] ;GET POINTER TO BUFFER READY
MOVEI T1,3 ;GET READY TO GET NUMBER OF WORDS
CALL RANDOM ;DO IT
ADDI T1,2 ;ALWAYS HAVE AT LEAST 2 WORDS
MOVEM T1,TEMP ;REMEMBER NUMBER OF WORDS TO DO
MAKWLP: MOVEI T1,MAGSZ1 ;GET NUMBER OF WORD PARTS IN TABLE
CALL RANDOM ;PICK ONE OUT
MOVE T1,MAGTB1(T1) ;GET THE WORD
CALL WRDSTF ;STORE IT IN THE BUFFER
MOVEI T1,MAGSZ2 ;GET WORDS IN SECOND TABLE
CALL RANDOM ;PICK ONE OUT
MOVE T1,MAGTB2(T1) ;GET THE WORD
CALL WRDSTF ;STORE IT IN THE BUFFER
MOVEI T1,2 ;GET SET
CALL RANDOM ;SEE IF WANT A THIRD SYLLABLE
JUMPE T1,WRDTWO ;NO, GO ON
MOVEI T1,MAGSZ3 ;YES, GET NUMBER OF ENTRIES
CALL RANDOM ;PICK ONE
MOVE T1,MAGTB3(T1) ;GET THE WORD
CALL WRDSTF ;STORE THE WORD
WRDTWO: MOVEI T1," " ;GET A SPACE
SOSG TEMP ;COUNT DOWN WORDS TO GO
SETZ T1, ;LAST WORD, GET A NULL
IDPB T1,T4 ;STORE A SPACE OR A NULL
JUMPN T1,MAKWLP ;CONTINUE IF NOT DONE
POP P,RANNUM ;OTHERWISE RESTORE RANDOM NUMBER
RET ;AND RETURN
;SUBROUTINE TO STORE THE ASCII WORD IN T1 INTO THE TEXT POINTED
;TO BY T4.
WRDSTF: JUMPE T1,CPOPJ ;DONE WHEN GET A NULL
SETZ T2, ;CLEAR NEXT WORD
ROTC T1,7 ;GET NEXT LETTER
IDPB T2,T4 ;STORE IT
JRST WRDSTF ;AND LOOP
SUBTTL RANDOM NUMBER GENERATOR
;CALLED TO OBTAIN A RANDOM INTEGER IN A SPECIFIED RANGE FROM 0 TO N-1.
;CALL:
; T1/ N
;RETURNS:
; T1/ A NUMBER FROM 0 TO N-1 INCLUSIVE.
;
;CAN TRASH T2.
RANDOM: PUSH P,T1 ;SAVE THE RANGE
SKIPN T1,RANNUM ;GET LAST RANDOM NUMBER
TIME ;IF NONE, USE TIME AS A SEED
IMUL T1,[^D<125*125*125*125*125>] ;5**15 IS MAGIC
ADDI T1,^D17 ;HELP ALONG IN CASE ZERO
TXZ T1,1B0 ;MAKE SURE IT IS POSITIVE
SKIPN T1 ;MAKE SURE NONZERO
MOVEI T1,^D17 ;IF SO, FIX IT
MOVEM T1,RANNUM ;REMEMBER FOR NEXT CALL
POP P,T2 ;RESTORE THE RANGE
MUL T1,T2 ;PRODUCE THE RESULT
RET ;DONE
SUBTTL SUBROUTINE TO TYPE OUT THE LATEST NEWS
;THIS ROUTINE IS CALLED TO LOOK UP AND TYPE THE LATEST INFORMATION
;ABOUT THE DUNGEON. THE OUTPUT IS JUSTIFIED AS USUAL. CALL:
; T1/ JFN OF THE MESSAGE FILE
;RETURNS:
; +1: OUTPUT COMPLETED, JFN CLOSED.
DOMESS: MOVEM T1,MSGJFN ;SAVE THE JFN
MOVX T2,OF%RD+7B5 ;WANT TO READ THE FILE
OPENF ;TRY TO OPEN IT
ERJMP MSGNO2 ;FAILED
DOCRLF ;START WITH A CRLF
TXZ F,FR.CRL ;MAKE CRLFS NOT MATTER AT FIRST
MSGLOP: MOVE T1,MSGJFN ;GET JFN
BIN ;READ NEXT CHARACTER
ERJMP MSGFIN ;ERROR, GO FINISH
SKIPN C,T2 ;MOVE TO RIGHT AC
JRST MSGLOP ;BUT IGNORE NULLS
CAIN C,"&" ;SPECIAL CHARACTER?
TXCA F,FR.CRL ;YES, TOGGLE FLAG AND IGNORE IT
PUTCHR ;NO, TYPE IT
JRST MSGLOP ;LOOP OVER ALL CHARACTERS
MSGFIN: MOVE T1,MSGJFN ;GET JFN READY
RLJFN ;RELEASE IT
JFCL ;FAILED
SETZM MSGJFN ;CLEAR FROM CORE
DOCRLF ;END IN A CRLF
RET ;DONE
MSGNO2: CALL MSGFIN ;FINISH CLOSING FILE
MSGNO1: STROUT [ASCIZ/
Failed to read text file.
/] ;COMPLAIN
RET ;AND RETURN
SUBTTL SUBROUTINE TO REBUILD THE COMMAND TABLE
;CALLED WHENEVER THE COMMAND TABLE IS NO LONGER VALID. WE BUILD
;A TABLE OF COMMANDS USING TBADD FOR COMND TO USE.
BLDCMD: MOVEI T1,CMDLEN ;GET MAXIMUM NUMBER OF COMMANDS
MOVEM T1,CMDTAB ;AND INITIALIZE THE TABLE OF COMMANDS
MOVSI T3,-CMDLEN ;GET READY FOR LOOPING
BLDCML: HRRZ T1,CMDORG+1(T3) ;GRAB ADDRESS OF DATA WORD
MOVE T1,(T1) ;AND GRAB IT
HLRZ T2,CMDORG+1(T3) ;GET ADDRESS OF TEXT STRING
MOVE T2,(T2) ;THEN GET FIRST WORD OF STRING
TXNN T2,177B6 ;IS THIS AN ABBREVIATION?
MOVE T1,(T1) ;YES, GET RIGHT DATA WORD
HLRZ T1,T1 ;KEEP ONLY REASONS FOR REJECTING COMMAND
TXNE F,FR.PLY ;ARE WE PLAYING?
TRZA T1,C.PLY ;YES, ZAP THAT REASON
TRZ T1,C.NOP ;OTHERWISE ZAP NON-PLAYING REASON
TXNE F,FR.GOD ;ARE WE GODLY?
TRZ T1,C.GOD ;YES, ZAP THAT REASON
TXNE F,FR.DEB ;DEBUGGING?
TRZ T1,C.DEB ;YES, ZAP THAT REASON
TRZ T1,C.STS ;CLEAR THIS BIT ALWAYS
JUMPN T1,BLDNO ;DISALLOW COMMAND IF ANY REASONS LEFT
MOVEI T1,CMDTAB ;POINT TO COMMAND TABLE
MOVE T2,CMDORG+1(T3) ;GET ENTRY TO ADD
TBADD ;INSERT IT
BLDNO: AOBJN T3,BLDCML ;LOOP OVER ALL COMMANDS
TXZ F,FR.BLD ;NO LONGER HAVE TO REBUILD THE TABLE
RET ;DONE
SUBTTL COMMAND JSYS SUBROUTINES
;SUBROUTINES TO DO THE COMND JSYS. THESE ROUTINES RETURN TO THE COMMAND
;SCANNER FOR A NEW COMMAND IF AN ERROR OCCURS, UNLESS THE CALL TO THEM
;WAS FOLLOWED BY AN ERJMP, IN WHICH CASE IT IS TAKEN.
;CALLED FROM NOISE MACRO TO PARSE A NOISE TEXT.
DONOIS: HRROM T2,NOIBLK+.CMDAT ;SAVE AS DATA
MOVEI T2,NOIBLK ;POINT TO BLOCK
JRST DOCMMD ;AND GO DO COMND JSYS
;CALLED FROM CONFRM MACRO TO CONFIRM A LINE. AC T2 IS PRESERVED.
DOCNFM: PUSH P,T2 ;SAVE THIS AC
CMMD [FLDDB. (.CMCFM)] ;DO THE CONFIRM
POP P,T2 ;RESTORE AC
RET ;DONE
;CALLED FROM CMMD MACRO TO DO THE ACTUAL WORK.
DOCMMD: COMND ;PARSE THE FUNCTION
ERJMP BADCMD ;ERROR, GO COMPLAIN
TXNN T1,CM%NOP ;PARSED CORRECTLY?
RET ;YES, DONE
BADCMD: TXNN F,FR.PLY ;ACTUALLY PLAYING THE GAME?
JRST BADCMT ;NO, COMPLAIN NORMALLY
MOVEI T1,.FHSLF ;GET READY
GETER ;READ LAST ERROR
HRRZ T1,T2 ;GET CODE BY ITSELF
CAIN T1,NPXNOM ;UNKNOWN COMMAND?
JRST UNKCMD ;YES
BADCMT: HRROI T1,[ASCIZ/
? /] ;GET STARTING TEXT
PSOUT ;TYPE IT
MOVEI T1,.PRIOU ;GET READY
HRLOI T2,.FHSLF ;TO OUTPUT ERROR
SETZ T3, ;ALL OF IT
ERSTR
JFCL
JFCL
HRROI T1,[ASCIZ/
/] ;MORE TEXT
PSOUT ;TYPE IT
MOVE P,SAVEP ;RESTORE STACK
JRST GETCMD ;DO REPARSE
UNKCMD: HRROI T1,[ASCIZ/
I don't know how to do that.
/] ;GET TEXT
PSOUT ;COMPLAIN
MOVE P,SAVEP ;RESTORE STACK
JRST GETCMD ;AND REPARSE
SUBTTL SUBROUTINE TO TYPE THE ELEMENTS IN A LIST
;CALLED TO HANDLE THE PUNCTUATION AND CONCATINATION OF THE ELEMENTS
;WHICH MAKE UP A LIST. THE LIST OF ELEMENTS ASSUMES ONE OF THE
;FOLLOWING FORMS, DEPENDING ON THE NUMBER OF ELEMENTS:
;
; ELEMENT1
; ELEMENT1 and ELEMENT2
; ELEMENT1, ELEMEN2, and ELEMENT3
; ...
;
;ARGUMENTS:
; T1/ DATA,,ADDRESS ;ADDRESS IS A SUBROUTINE TO TYPE OUT
; ;THE CURRENT ELEMENT, AND THE DATA WILL
; ;BE PUT IN T1 FOR THE SUBROUTINE'S USE
;
;OR: T1/ 0 ;NO MORE ELEMENTS IN LIST
;
;BEFORE THE FIRST CALL, CLEAR LOCATION LISOLD.
;WHEN DONE WITH THE LIST, LOCATION LISCNT WILL CONTAIN THE
;TOTAL NUMBER OF ELEMENTS THAT WERE TYPED. USES ONLY T1 AND T2.
DOLISE: SETZ T1, ;INDICATE END OF LIST
DOLIST: SKIPN T2,LISOLD ;GET PREVIOUS ELEMENT
SETZM LISCNT ;NONE, SO CLEAR NUMBER OF ELEMENTS
MOVEM T1,LISOLD ;REMEMBER CURRENT ELEMENT FOR NEXT CALL
SKIPN T1,LISCNT ;GET ELEMENTS TYPED
JRST DOLINC ;JUMP IF NONE YET
CAIN T1,1 ;JUST ONE?
SKIPA T1,[[ASCIZ/ and /]] ;GET SOME TEXT
MOVEI T1,[ASCIZ/, and /] ;OR OTHER TEXT
SKIPE LISOLD ;MORE COMING?
MOVEI T1,[ASCIZ/, /] ;YES, GET THIS TEXT INSTEAD
CALL TTYSTR ;TYPE STRING
DOLINC: JUMPE T2,CPOPJ ;DONE IF NO ELEMENT TO LIST
HLRZ T1,T2 ;GET THE DATA READY
CALL (T2) ;CALL ROUTINE TO TYPE THE ELEMENT
AOS LISCNT ;COUNT NUMBER OF ELEMENTS TYPED
RET ;DONE
SUBTTL ROUTINE TO FORMAT TERMINAL OUTPUT
;THIS SUBROUTINE BUFFERS OUTPUT FOR THE TERMINAL, AND INSERTS
;CRLFS AT APPROPRIATE PLACES SO THAT THE OUTPUT IS JUSTIFIED
;REASONABLY. EXTRA SPACES AT THE END OF A LINE ARE DISCARDED.
;USE OF ROUTINES:
;
; CALL TTYINI ;INITIALIZE BUFFERS AND POINTERS
;
;LOOP: MOVEI C,CHAR ;GET CHARACTER
; CALL TTYOUT ;GIVE TO FORMATTING SUBROUTINE
; ... ;CONTINUE
;
; CALL TTYPNT ;FORCE OUT REMAINING OUTPUT
;
;DESTROYS AC C.
;HERE TO FORCE OUT ANY REMAINING OUTPUT:
TTYPNT: MOVE T1,ENDLTR ;GET WHERE LAST LETTER WAS
CAMN T1,[POINT 7,BUFF] ;ANYTHING TO FORCE OUT?
RET ;NO
SETZ T1, ;GET A NULL
IDPB T1,ENDLTR ;MAKE THE STRING ASCIZ
HRROI T1,BUFF ;POINT TO BUFFER
PSOUT ;TYPE IT
;FALL INTO INITIALIZATION CODE
;HERE TO INITIALIZE THE BUFFER:
TTYINI: MOVE C,[POINT 7,BUFF];GET POINTER TO START OF BUFFER
MOVEM C,BUFPTR ;SET UP CURRENT POINTER
MOVEM C,ENDLTR ;AND WHERE "LAST LETTER" WAS
SETZM BEGWRD ;NO WORD HAS STARTED YET
SETZM @FULADR ;BUFFER IS NOT FULL YET
SETZM BUFOVR ;AND HAS NOT OVERFLOWED
RET ;DONE
TTYOUT: CAIN C,15 ;CARRIAGE RETURN?
RET ;YES, IGNORE IT
CAIN C,12 ;LINE FEED?
JRST TTYLIN ;YES, GO SEE WHAT TO DO
CAIN C," " ;A SPACE?
JRST TTYSPC ;YES, DIFFERENT HANDLING
CAIN C," " ;A TAB?
JRST TTYTAB ;YES, GO HANDLE IT
IDPB C,BUFPTR ;STORE THE CHARACTER
MOVE C,BUFPTR ;GET CURRENT POINTER
MOVEM C,ENDLTR ;AND SAVE AS LAST LETTER SEEN
SKIPN BEGWRD ;STARTING A NEW WORD?
MOVEM C,BEGWRD ;YES, REMEMBER WHERE IT STARTS
SKIPN @FULADR ;BUFFER FILLED UP?
RET ;NO, DONE
PUSH P,T1 ;YES, SAVE AN AC WE NEED
SETZ T1, ;GET A NULL
IDPB T1,ENDWRD ;TERMINATE STRING ENDING WITH LAST FULL WORD
HRROI T1,BUFF ;POINT TO BUFFER
CALL SAVOUT ;TYPE LINE UP TO LAST COMPLETE WORD
HRROI T1,[ASCIZ/
/] ;GET A CRLF
CALL SAVOUT ;TYPE IT
MOVE T1,[POINT 7,BUFF] ;GET INITIAL POINTER
MOVEM T1,BUFPTR ;AND RESET CURRENT LOCATION
SETO T1, ;WANT TO BACKUP A CHARACTER
ADJBP T1,BEGWRD ;POINT JUST BEFORE CURRENT WORD
BUFBLT: ILDB C,T1 ;GET ANOTHER LETTER OF CURRENT WORD
IDPB C,BUFPTR ;AND MOVE TO FRONT OF BUFFER
CAME T1,ENDLTR ;MOVED THE LAST LETTER SEEN?
JRST BUFBLT ;NOT YET, KEEP GOING
MOVE T1,BUFPTR ;GET CURRENT POINTER
MOVEM T1,ENDLTR ;AND SET WHERE LAST LETTER IS
MOVE T1,[POINT 7,BUFF,6] ;GET POINTER TO FIRST LETTER
MOVEM T1,BEGWRD ;AND REMEMBER WHERE WORD STARTS
SETZM @FULADR ;CLEAR THE BUFFER FULL INDICATOR
SETZM BUFOVR ;AND THE OVERFLOW WORD
POP P,T1 ;RESTORE THE AC
RET ;AND RETURN
;HERE WHEN RECEIVE A TAB:
TTYTAB: PUSH P,T1 ;SAVE SOME AC'S
PUSH P,T2 ;THAT WE'LL USE
LDB T1,[POINT 6,BUFPTR,5] ;GET POSITION OF LAST BYTE
IDIVI T1,7 ;OBTAIN WHICH BYTE IT IS
MOVEI T2,5 ;GET CHARS IN A WORD
SUB T2,T1 ;GET NUMBER OF CHARS IN THIS WORD
HRRZ T1,BUFPTR ;GET WORD WE'RE CURRENTLY ON
SUBI T1,BUFF ;SUBTRACT START OF BUFFER
IMULI T1,5 ;FIVE CHARACTERS TO A WORD
ADD T1,T2 ;ADD IN PARTIAL WORD
TABLOP: CALL TTYSPC ;OUTPUT A SPACE
ADDI T1,1 ;ADVANCE COLUMN
TRNE T1,7 ;REACHED A TAB STOP YET?
JRST TABLOP ;NO, KEEP GOING
POP P,T2 ;YES, RESTORE AC'S
POP P,T1 ;THAT WE USED
RET ;AND DONE
;HERE WHEN RECEIVE A SPACE:
TTYSPC: SKIPE BUFOVR ;STARTING TO OVERFLOW THE BUFFER?
RET ;YES, IGNORE MORE SPACES
MOVEI C," " ;GET A SPACE
IDPB C,BUFPTR ;STORE IT
MOVE C,ENDLTR ;GET WHERE LAST LETTER WAS
MOVEM C,ENDWRD ;THEN SET WHERE LAST WORD ENDED
SETZM BEGWRD ;NO NEW WORD YET BEGUN
RET ;DONE
;HERE TO FORCE OUT NEW LINES WHEN NECESSARY:
TTYLIN: TXNN F,FR.CRL ;WANT CRLFS PRESERVED?
JRST TTYSPC ;NO, MAKE IT A SPACE INSTEAD
TTYCRL: PUSH P,T1 ;SAVE AN AC
CALL TTYPNT ;FORCE OUTPUT OUT
HRROI T1,[ASCIZ/
/] ;GET A FINAL CRLF
CALL SAVOUT ;TYPE IT
POP P,T1 ;RESTORE THE AC
RET ;AND RETURN
SUBTTL OUTPUT STORAGE ROUTINES
;THESE ROUTINES ARE USED TO STORE OUTPUT FOR LATER TYPING. THIS IS
;NECESSARY WHEN OUTPUT IS GENERATED WHILE THE FILE IS LOCKED. WE
;CANNOT ACTUALLY TYPE STUFF WITH THE FILE LOCKED, BECAUSE WE MIGHT
;GO INTO AN OUTPUT WAIT. SO THE OUTPUT IS INTERCEPTED AND STORED,
;AND LATER WHEN THE FILE IS UNLOCKED, IT CAN BE OUTPUT.
;HERE TO INITIALIZE THINGS SO OUTPUT IS STORED:
SAVINI: SKIPE OUTPTR ;ALREADY SAVING OUTPUT?
RET ;YES, DO NOTHING
SETZM OUTBUF ;CLEAR FIRST WORD
SETZM OUTOVR ;AND OVERFLOW WORD
MOVE T1,[POINT 7,OUTBUF] ;GET BYTE POINTER
MOVEM T1,OUTPTR ;AND SET UP STORAGE POINTER
RET ;DONE
;HERE TO FINALLY TYPE FOR REAL THE STORED OUTPUT:
SAVPNT: CALL TTYPNT ;FORCE OUT STUFF WAITING TO GO
SKIPN OUTPTR ;ANY STORAGE POINTER?
RET ;NO, NOTHING TO PUNT
SETZ T1, ;YES, GET A NULL
IDPB T1,OUTPTR ;MAKE STRING ASCIZ
SETZM OUTPTR ;THEN CLEAR STORAGE POINTER
HRROI T1,OUTBUF ;POINT TO BUFFER
SKIPE OUTBUF ;ANYTHING ACTUALLY THERE?
PSOUT ;YES, TYPE IT
HRROI T1,[ASCIZ/
% Storage buffer overflowed, increase size to prevent lossage.
/] ;GET STRING
SKIPE OUTOVR ;DID WE OVERFLOW?
PSOUT ;YES, SAY WHAT HAPPENED
RET ;DONE
;HERE TO GIVE OUTPUT TO EITHER THE SCREEN, OR TO STORAGE FOR LATER
;OUTPUT. POINTER TO STRING IS IN T1.
SAVOUT: SKIPE OUTPTR ;ANY STORAGE OF OUTPUT WANTED?
JRST SAVYES ;YES, GO DO IT
TXNE F,FR.LCK ;TRYING TO OUTPUT WHILE FILE LOCKED?
FATAL (,,Attempting to output while data file is locked.)
PSOUT ;NO, TYPE STRAIGHT
RET ;AND RETURN
SAVYES: TLC T1,-1 ;SEE IF LEFT HALF IS -1
TLCN T1,-1 ;IS IT?
HRLI T1,(POINT 7,) ;YES, MAKE REASONABLE POINTER
MOVEM T1,OUTTMP ;SAVE FOR USE
SAVLOP: SKIPE OUTOVR ;OVERFLOWING?
RET ;YES, STOP
ILDB T1,OUTTMP ;GET NEXT CHARACTER
JUMPE T1,CPOPJ ;DONE ON A NULL
IDPB T1,OUTPTR ;STORE CHAR
JRST SAVLOP ;LOOP
SUBTTL LUUO HANDLER
;ROUTINE TO PROCESS LUUOS. LUUOS ARE USED AS A CONVENIENT WAY
;TO OUTPUT TEXT AND NUMBERS IN ONE INSTRUCTION. ALL THESE LUUOS
;CAN TRASH AC'S T1-T3.
LUUO: MOVE T1,@.JBUUO ;GET THE ARGUMENT FOR THE UUO
MOVEM T1,UUOARG ;SAVE IT IN A SAFE PLACE
LDB T1,[POINT 9,.JBUUO,8] ;GET THE OPCODE
CAILE T1,MAXUUO ;SEE IF IT IS LEGAL
BADUUO: FATAL (Illegal LUUO executed)
JRST @LUUTAB(T1) ;YES, GO TO IT
;TABLE OF THE LUUOS WE HANDLE:
LUUTAB: EXP BADUUO ;(0) ILLEGAL
EXP STRUUO ;(1) TYPE AN ASCIZ STRING
EXP DECUUO ;(2) OUTPUT A DECIMAL NUMBER
EXP OCTUUO ;(3) OUTPUT AN OCTAL NUMBER
EXP DATUUO ;(4) OUTPUT A DATE
EXP CHRUUO ;(5) OUTPUT A SINGLE CHARACTER
MAXUUO==.-LUUTAB-1 ;HIGHEST KNOWN LUUO
;ROUTINES TO HANDLE THE VARIOUS TYPES OF OUTPUT:
;HERE TO TYPE A STRING. THE USUAL CASE IS THAT CRLFS IN THE STRING
;ARE PRESERVED. THE SPECIAL CHARACTER "&" WILL TOGGLE THAT CONDITION,
;SO THAT A CRLF IS TREATED AS A SPACE, TO MAKE MULTI-LINE JUSTIFIED
;OUTPUT EASIER.
STRUUO: MOVE T1,.JBUUO ;GET THE ADDRESS OF THE STRING
TTYSTR: HRLI T1,(POINT 7,) ;CREATE A BYTE POINTER
TXO F,FR.CRL ;START OFF BELIEVING CRLFS
TTYSTL: ILDB C,T1 ;GET THE NEXT CHARACTER
JUMPE C,CPOPJ ;DONE WITH A NULL
CAIN C,"&" ;SPECIAL CHARACTER?
TXCA F,FR.CRL ;YES, COMPLEMENT FLAG AND FORGET IT
PUTCHR ;NO, OUTPUT IT
JRST TTYSTL ;LOOP UNTIL DONE
USROUT: MOVE T2,T1 ;MOVE TO BETTER AC
HRROI T1,TMPBUF ;POINT TO BUFFER
DIRST ;STORE IT
ERJMP [CHROUT "#" ;FAILED, TYPE HASH MARK TO INDICATE A NUMBER
HRRZ T1,T2 ;GET NUMBER
JRST TTYOCT] ;TYPE IT AND RETURN
STROUT TMPBUF ;OUTPUT NAME
RET ;AND RETURN
OCTUUO: SKIPA T1,UUOARG ;GET THE NUMBER TO TYPE
DECUUO: SKIPA T1,UUOARG ;GET THE NUMBER TO TYPE
TTYOCT: SKIPA T3,[^D8] ;SET FOR OCTAL
TTYDEC: MOVEI T3,^D10 ;SET FOR DECIMAL
JUMPGE T1,TTYNUM ;GO IF NONNEGATIVE
MOVEI C,"-" ;GET MINUS SIGN
PUTCHR ;OUTPUT IT
MOVM T1,T1 ;GET ABSOLUTE MAGNITUDE
TTYNUM: IDIVI T1,(T3) ;GET NEXT DIGIT
JUMPE T1,TTYNUF ;DONE WHEN HAVE A NULL
HRLM T2,(P) ;SAVE DIGIT
CALL TTYNUM ;LOOP
HLRZ T2,(P) ;GET BACK DIGIT
TTYNUF: MOVEI C,"0"(T2) ;MAKE ASCII
PUTCHR ;OUTPUT IT
RET ;AND DONE
DECSP7: MOVEI C," " ;GET SPACE
CAMGE T1,[^D1000000] ;LESS THEN SEVEN DIGITS?
PUTCHR ;YES
DECSP6: MOVEI C," " ;GET SPACE READY
CAIGE T1,^D100000 ;LESS THAN SIX DIGITS?
PUTCHR ;YES
DECSP5: MOVEI C," " ;GET A SPACE
CAIGE T1,^D10000 ;LESS THAN FIVE DIGITS?
PUTCHR ;OUTPUT IT
DECSP4: MOVEI C," " ;GET SPACE
CAIGE T1,^D1000 ;LESS THAN FOUR DIGITS?
PUTCHR ;OUTPUT IT
DECSP3: MOVEI C," " ;GET SPACE
CAIGE T1,^D100 ;LESS THAN THREE DIGITS?
PUTCHR ;YES, OUTPUT IT
DECSP2: MOVEI C," " ;GET SPACE
CAIGE T1,^D10 ;LESS THAN TWO DIGITS?
PUTCHR ;TYPE IT
JRST TTYDEC ;THEN OUTPUT THE NUMBER
TTYSIX: JUMPE T1,CPOPJ ;DONE WITH A NULL
SETZ T2, ;CLEAR NEXT AC
ROTC T1,6 ;SHIFT IN NEXT CHAR
MOVEI C," "(T2) ;MAKE ASCII
PUTCHR ;TYPE IT
JRST TTYSIX ;LOOP
;ROUTINES TO OUTPUT A NUMBER IN THE FORM NNN.NNNN, NN.NNNN, OR N.NNNN,
;WHERE THE DIVISOR IS IN T1, AND THE DIVIDEND IS IN T2.
TTYFI3: SKIPA T3,[EXP DECSP3] ;GET ROUTINE TO USE
TTYFI2: MOVEI T3,DECSP2 ;OR OTHER ROUTINE
SKIPA ;PROCEED
TTYFI1: MOVEI T3,TTYDEC ;STANDARD OUTPUT
PUSH P,T2 ;SAVE DIVIDEND
IDIV T1,T2 ;GET INTEGER PART FIRST
PUSH P,T2 ;SAVE REMAINDER
CALL (T3) ;OUTPUT INTEGER PART
CHROUT "." ;THEN A DOT
POP P,T2 ;RESTORE REMAINDER
MOVEI T3,4 ;GET NUMBER OF DIGITS TO PRINT
TTYFXL: MOVE T1,T2 ;COPY REMAINDER
IMULI T1,^D10 ;SCALE UP
IDIV T1,0(P) ;GET NEXT DIGIT
CHROUT "0"(T1) ;OUTPUT IT
SOJG T3,TTYFXL ;LOOP
POP P,T1 ;FIX STACK
RET ;DONE
;ROUTINE TO OUTPUT SINGULAR OR PLURAL TEXTS. CALL:
; T1/ NUMBER TO DETERMINE SINGULARNESS FROM
; T2/ [ASCIZ/PLURAL TEXT/],,[ASCIZ/SINGULAR TEXT/]
; OR: T2/ 0,,[ASCIZ/SINGULAR TEXT/] IF PLURAL IS SINGULAR + "S"
;CALL PLURNM TO OUTPUT NUMBER AND TEXT, OR PLURTX TO OUTPUT JUST THE
;TEXT. USES T1-T3
PLURNM: DMOVEM T1,PLURTM ;SAVE ARGUMENTS FOR AWHILE
SKIPN T1 ;ZERO SPECIFIED?
STROUT [ASCIZ/no/] ;YES, SAY THIS
SKIPE T1,PLURTM ;GET BACK NUMBER AND SEE IF NONZERO
CALL TTYDEC ;YES, OUTPUT IT
CHROUT " " ;THEN A SPACE
DMOVE T1,PLURTM ;RESTORE NUMBER AND TEXT
PLURTX: SOJN T1,PLURYS ;JUMP ON IF WANT PLURAL CASE
HRRZ T1,T2 ;SINGULAR, GET ADDRESS
JRST TTYSTR ;GO OUTPUT IT
PLURYS: HLRZ T1,T2 ;GET PLURAL STRING IF ANY
JUMPN T1,TTYSTR ;IF ONE, OUTPUT IT
HRRZ T1,T2 ;OTHERWISE GET SINGULAR TEXT
CALL TTYSTR ;OUTPUT IT
CHROUT "s" ;THEN MAKE IT PLURAL IN STANDARD WAY
RET ;DONE
GOLOUT: MOVEI T2,[ASCIZ/gold piece/] ;POINT TO TEXT
JRST PLURNM ;GO TO OTHER CODE
MONOUT: HRLI T1,(POINT 7,) ;FINISH BYTE POINTER
MONOUL: ILDB C,T1 ;GET NEXT CHARACTER
CAIN C," " ;SPACE?
JRST TTYSTL ;YES, GO START TYPING NOW
JUMPN C,MONOUL ;NO, KEEP EATING
RET ;STRING ENDED
DATUUO: HRROI T1,TMPBUF ;POINT TO BUFFER
MOVE T2,UUOARG ;GET THE DATE TO TYPE
MOVX T3,OT%NTM ;DON'T WANT THE TIME OUTPUT
ODTIM ;STORE STRING
MOVEI T1,TMPBUF ;POINT TO BUFFER
JRST TTYSTR ;AND OUTPUT IT
CHRUUO: HRRZ C,.JBUUO ;GET THE CHARACTER
PUTCHR ;OUTPUT IT
RET ;DONE
SUBTTL ERROR ROUTINES
;HERE FROM THE ERROR MACRO. THE ARGUMENTS TO THIS MACRO ARE:
; ERROR (INST1,INST2,TEXT)
;WHERE:
;
;INST1 IS AN INSTRUCTION EXECUTED BEFORE THE DATA FILE IS UNLOCKED.
; USUALLY THIS WILL PUT SOME DATA IN T3 OR T4 FOR USE LATER.
;INST2 IS AN INSTRUCTION EXECUTED AFTER THE FILE IS UNLOCKED AND
; THE BEGINNING TEXT HAS BEEN TYPED.
;TEXT IS THE TEXT TO TYPE AFTER THE FILE IS UNLOCKED, BUT BEFORE
; INST2 IS EXECUTED.
;
;ANY NULL ARGUMENT IS HANDLED PROPERLY. ON ENTRY TO THIS ROUTINE,
;ERRTXT HAS THE POINTER TO THE TEXT IF ANY, T1 HAS INST1 IF ANY,
;AND T2 HAS INST2 IF ANY.
DOERR: TXO F,FR.CRL ;CRLFS MATTER NOW
MOVEM T2,ERRXCT ;REMEMBER INSTRUCTION FOR LATER
SKIPE T1 ;ANY PRELIMINARY INSTRUCTION?
XCT T1 ;YES, DO IT
TXNE F,FR.LCK ;IS THE DATA FILE LOCKED?
CALL UNLOCK ;YES, FREE IT
SKIPE T1,ERRTXT ;ANY TEXT TO TYPE OUT?
CALL TTYSTR ;YES, TYPE IT
SKIPE T1,ERRXCT ;ANY TRAILING INSTRUCTION TO DO?
XCT T1 ;YES, DO IT
DOCRLF ;FINISH WITH EXTRA CRLF
DOERRF: CALL SAVPNT ;FORCE OUT ALL OUTPUT
MOVE P,SAVEP ;RESTORE COMMAND LEVEL STACK
JRST GETCMD ;AND GET A NEW COMMAND
;HERE FOR A FATAL ERROR. THESE ARE NOT SUPPOSED TO HAPPEN.
;WE JUST QUIT QUICKLY AND STAY THERE. T4 HAS POINTER TO
;STRING TO BE TYPED.
DOFATL: TXNE F,FR.LCK ;WAS THE FILE LOCKED UP?
CALL UNLOCK ;YES, UNLOCK IT FIRST
MOVE T1,T4 ;GET POINTER TO STRING
PSOUT ;TYPE THE ERROR
HALTF ;QUIT
JRST .-1 ;STAY THAT WAY
SUBTTL DATA FOR COMND JSYS
CMDBLK: EXP NEWPAR ;FLAGS,,REPARSE ADDRESS
XWD .PRIIN,.PRIOU ;INPUT,,OUTPUT JFNS
EXP 0 ;CONTROL-R POINTER, FILLED IN AT RUNTIME
XWD -1,TXTBUF ;POINTER TO TEXT BUFFER
XWD -1,TXTBUF ;POINTER TO CURRENT POSITION
EXP TXTLEN ;NUMBER OF CHARS IN BUFFER
EXP 0 ;COUNT
XWD -1,ATMBUF ;POINTER TO ATOM BUFFER
EXP TXTLEN ;NUMBER OF CHARACTERS IN BUFFER
EXP JFNBLK ;POINTER TO GTJFN BLOCK
JFNBLK: EXP GJ%OLD ;FLAGS,,GENERATION NUMBER
XWD .PRIIN,.PRIOU ;INPUT,,OUTPUT JFNS
BLOCK 20 ;NO DEFAULTS
NOIBLK: FLDDB. (.CMNOI) ;BLOCK FOR NOISE FUNCTION
SUBTTL TABLES ABOUT THE MONSTERS
;HERE TO EXPAND THE MONS MACRO DEFINED EARLIER INTO THE VARIOUS
;TABLES NEEDED FOR THE PROGRAM.
XALL ;ALLOW EXPANSIONS HERE
DEFINE XX(TF,HIT,MEAN,NAME),<
<TF>B0+[ASCIZ/NAME/] ;;GENERATE FLAGS AND TEXT
>
MONTXT: MONS ;EXPAND THE MACRO
MONNUM==.-MONTXT ;NUMBER OF MONSTERS
DEFINE XX(TF,HIT,MEAN,NAME),<
XWD ^D<HIT>,^D<MEAN> ;DEFENDING/ATTACKING DATA FOR NAME
>
MONPWR: MONS ;EXPAND THE MACRO
SALL ;RETURN TO NORMAL LISTING
SUBTTL ATTACK AND STRENGTH TEXTS
;THE FOLLOWING TABLES ARE USED TO OUTPUT THE RESULTS OF A BATTLE,
;AND ALSO HOW STRONG A MONSTER OR WE ARE. EACH TABLE IS IN THE
;SAME FORMAT, WHERE THE RIGHT HALF POINTS TO THE STRING TO OUTPUT,
;AND THE LEFT HALF IS THE AMOUNT OF STRENGTH OR DAMAGE REQUIRED
;FOR THAT OUTPUT TO APPLY. THE TABLES ARE ORDERED.
DEFINE STR(NUM,TEXT),<
XWD ^D<NUM>,[ASCIZ/TEXT /]
>
STRMON: STR 0,on it's last legs!!
STR 2,very very weak!!
STR 4,rather weak now.
STR 8,reasonably strong.
STR 16,powerful.
STR 25,amazingly powerful!!
STR 50,infinitely powerful!!
STRMNU==.-STRMON ;NUMBER OF ENTRIES
STRUS: STR 0,about ready to die!!!!
STR 5,extremely weak!!!
STR 10,very weak!
STR 20,pretty weak.
STR 30,less than half your normal strength.
STR 50,about half your normal strength.
STR 70,reasonably strong.
STR 80,very strong.
STR 90,almost at full strength.
STR 100,perfect!!
STRUNU==.-STRUS ;NUMBER OF ENTRIES
STRWIN: STR 0,You missed completely.
STR 1,The monster was barely nicked.
STR 2,You wounded the monster slightly.
STR 3,The monster was gashed by that blow.
STR 4,That blow slashed the monster greatly!
STR 5,What a teriffic blow!! Blood is pouring out of the wound!!
STRWNU==.-STRWIN ;NUMBER OF ENTRIES
STRLOS: STR 0,The monster missed you.
STR 1,The monster just nicked you.
STR 2,You were wounded by the monster.
STR 3,The monster wounded you a lot.
STR 4,You got damaged a lot in that attack!
STR 5,The monster gashed you terribly!!
STRLNU==.-STRLOS ;NUMBER OF TEXTS
SUBTTL TABLE OF MAGIC ITEMS
;THE FOLLOWING TABLE GIVES THE TEXT FOR THE MAGIC ITEMS. THIS
;IS DONE BY EXPANDING THE ITEMS MACRO DEFINED EARLIER.
DEFINE XX(CODE,KEYWORD,TEXT),<
IFDIF <CODE><NOTITEM>,<
XWD [ASCIZ/KEYWORD/],[ASCIZ/TEXT/]
>
>
ITMTAB: ITEMS ;BUILD THE TABLE
ITMNUM==.-ITMTAB ;NUMBER OF ITEMS IN TABLE
SUBTTL TABLE OF MAGIC PHRASES
;THE FOLLOWING THREE TABLES ARE USED TO GENERATE MAGIC WORDS.
;A MAGIC PHRASE IS FROM 1 TO 3 WORDS, WHERE EACH WORD IS FROM
;2 TO 3 SYLLABLES FROM THE FOLLOWING TABLES. THE PARTICULAR
;PHRASE GENERATED IS BASED ON A RANDOM NUMBER.
DEFINE SS(CHARS),<
IRP <CHARS>,<
ASCII /CHARS/
>
>
MAGTB1: SS <AB,AC,AL,AN,AS,BIN,BOR,CHO,CON,DAN,DIP,DRU,ED,EX,FOR,FREC>
SS <GRA,HER,IN,JOL,LIC,MAG,MOC,MOR,NIT,OM,ORA,PAR,PEN,PLAN>
SS <POR,REB,RET,SCOR,SEAR,SID,SPAR,SUB,TEN,THAN,TOG,TRAD,TUM>
SS <TYP,UND,VEC,VIOL,WAT,WON,YAW,ZERF>
MAGSZ1==.-MAGTB1 ;NUMBER OF WORDS
MAGTB2: SS <FEND,COB,WARE,DERM,WORT,TUBE,GAG,DATE,TINE,TOOT,PRES>
SS <TROS,VA,TENT,STER,GAL,NAT,CHIN,MAS,YON,ZUR,POD,DERN>
SS <DEL,PIAL,PHAR,LON,SER,TUS,STED,DON,FLAN,PEEN,PLEX>
SS <PHYT,FEL,LUD,VINC,VEAL,BRIC,PUL,FID,TORY,TION,THAT>
SS <KISH,LIZA,VER,WHAM,LES,ROR,EPID,NYS>
MAGSZ2==.-MAGTB2 ;NUMBER OF WORDS
MAGTB3: SS <BAT,LY,AGE,INE,PY,PHIC,OIL,THER,IUM,IAL,THOS,FY,ADE>
SS <NUE,EL,GLE,PER,EAT,LER,ANG,ENCE,ITY,INE,ASE,RUM>
SS <TIVE,SATE,MAND,LA,OOT,CON,NOMY,TICS,ACH,IZE,BLE,ILE>
SS <THER,ORB,KER,TOR,OUS,ISM,DEX,OOD,EAL,NAM,IZE,ERSE>
SS <ITH,VA,EVE,IE,GO,CIO,ETTE,ACT,ANT,OPE,USH,URT,ARB>
MAGSZ3==.-MAGTB3 ;NUMBER OF WORDS
SUBTTL DATA AREA
GOD: XWD 500000,GODUSR ;USER NUMBER WHICH IS GODLY
CMDTAB: BLOCK CMDLEN+1 ;ROOM FOR BUILDING OF COMMAND TABLE
PDL: BLOCK PDLSIZ ;STACK
DORTAB: BLOCK DIRMAX ;WHICH DIRECTIONS A TYPE OR DOOR IS ON
TMPBUF: BLOCK 10 ;TEMPORARY STRING USAGE
OUTPTR: BLOCK 1 ;BYTE POINTER INTO STORAGE AREA
OUTBUF: BLOCK ^D100 ;STORAGE FOR OUTPUT WHILE FILE LOCKED
OUTOVR: BLOCK 1 ;OVERFLOW FLAG
OUTTMP: BLOCK 1 ;TEMPORARY USE FOR OUTPUT
BUFF: BLOCK <COLMAX/5>+5 ;TERMINAL OUTPUT BUFFER
BUFOVR: BLOCK 1 ;OVERFLOW FLAG
BUFPTR: BLOCK 1 ;BYTE POINTER INTO BUFFER
FULADR: BLOCK 1 ;ADDRESS IN BUFFER TO KNOW WHEN IT'S FULL
ENDLTR: BLOCK 1 ;POINTER TO LAST LETTER IN BUFFER
BEGWRD: BLOCK 1 ;POINTER TO FIRST LETTER OF THIS WORD
ENDWRD: BLOCK 1 ;POINTER TO LAST LETTER OF PREVIOUS WORD
MYJOB: BLOCK 1 ;MY JOB NUMBER
MYNUM: BLOCK 1 ;MY PLAYER NUMBER
MAXADR: BLOCK 1 ;HIGHEST ADDRESS IN FILE TO SEARCH ON
TEMP: BLOCK 1 ;TEMPORARY USE
PLURTM: BLOCK 2 ;TEMPORARY USE FOR PLURNM ROUTINE
TRETMP: BLOCK 1 ;TEMPORARY USE DURING TREASURE BUILDING
MOVDIR: BLOCK 1 ;DIRECTION TO MOVE IN
MOVLNK: BLOCK 1 ;LINK WORD FOR DESIRED MOVE
BLDDIR: BLOCK 1 ;DIRECTION TO BUILD IN
BLDLNK: BLOCK 1 ;ADDRESS OF LINK WORD TO BUILD FROM
BLDTYP: BLOCK 1 ;TYPE OF DOOR TO BUILD
BLDLVL: BLOCK 1 ;LEVEL OF ROOM TO BE BUILT
DORDIR: BLOCK 1 ;DIRECTION CREATING DOORS ON
DORDIC: BLOCK 1 ;NUMBER OF DOORS LEFT TO CHECK FOR
CHCTOT: BLOCK 1 ;TOTAL CHANCE FOR DOORS
CHCTAB: BLOCK DORNUM ;TABLE OF CHANCES FOR DOORS
TGTLOC: BLOCK 1 ;COORDINATES OF A TARGET ROOM
TGTDIR: BLOCK 1 ;DIRECTION TO LOOK FOR TARGET ROOM
TGTMAT: BLOCK 1 ;ROOM WHICH EXISTS AT TARGET ADDRESS
TGTNMT: BLOCK 1 ;ROOM WHICH EXISTS NEAR TARGET ADDRESS
TGTTYP: BLOCK 1 ;TYPE OF DOOR TO FIND
MONTYP: BLOCK 1 ;KIND OF MONSTER BEING ATTACKED
ITMWNT: BLOCK 2 ;ITEM TYPE AND AMOUNT WANTED
UUOARG: BLOCK 1 ;WORD POINTED TO BY AN LUUO
PTHTMP: BLOCK 1 ;USED TO MANIPULATE PATHS
PTHNAM: BLOCK 1 ;PATH NAME BEING ADDED
PTHBYT: BLOCK 1 ;BYTE POINTER INTO CURRENT PATH
DRPCNT: BLOCK 1 ;AMOUNT OF TREASURE BEING DROPPED
RANNUM: BLOCK 1 ;LAST PRODUCED RANDOM NUMBER
MSGJFN: BLOCK 1 ;JFN FOR MESSAGE FILE
MSGTIM: BLOCK 1 ;TIME MESSAGE FILE LAST WRITTEN
PLTNUM: BLOCK 1 ;NUMBER OF ROOMS IN PLOT
ITMCNT: BLOCK 1 ;COUNTER FOR ITEM TYPEOUT
LSTFLG: BLOCK 1 ;WHETHER OR NOT TO LIST ONLY OURSELF
RSTMAX: BLOCK 1 ;HOW MUCH TO REST UP TO
RSTMOV: BLOCK 1 ;NUMBER OF MOVES TAKEN TO REST
ERRTXT: BLOCK 1 ;ADDRESS OF ERROR TEXT
ERRXCT: BLOCK 1 ;INSTRUCTION TO EXECUTE DURING ERROR
MYUSER: BLOCK 1 ;MY USER NUMBER
PLYUSR: BLOCK 1 ;USER NUMBER WE ARE PLAYING AS
FILJFN: BLOCK 1 ;JFN FOR THE DATA FILE
LISCNT: BLOCK 1 ;NUMBER OF ELEMENTS IN A LIST
LISOLD: BLOCK 1 ;PREVIOUS ELEMENT IN A LIST
SAYIDX: BLOCK 1 ;INDEX INTO SAYING TABLE
PTHCNT: BLOCK 1 ;NUMBER OF ENTRIES IN A PATH
MOVPTR: BLOCK 1 ;BYTE POINTER INTO MOVLST TABLE
MOVLST: BLOCK MOVMAX+1 ;TABLE OF MOVES TO BE MADE
FILNAM: ASCII /PS:<GAMES>CAVE.DAT;P776060/ ;FILE NAME
BLOCK ^D20 ;ROOM FOR PATCHING NAME
TXTNAM: ASCII /PS:<GAMES>CAVE.TXT/ ;MESSAGE FILE NAME
BLOCK ^D20 ;ROOM FOR PATCHING
SAVEP: BLOCK 1 ;STORAGE OF STACK POINTER
MAGTXT: BLOCK ^D20 ;CONTAINS A MAGIC PHRASE
TXTBUF: BLOCK TXTLEN/5+1 ;BUFFER FOR COMMAND JSYS
ATMBUF: BLOCK TXTLEN/5+1 ;BUFFER FOR ATOM BUFFER
DEFBUF: BLOCK 1 ;DEFAULT FIELD BUFFER FOR PLOT COMMAND
RMGENS: BLOCK 2 ;ROUTINES TO CALL FROM GENRMS
;PLOTTING VARIABLES.
SCALE: BLOCK 1 ;SCALE FACTOR
PJFN: BLOCK 1 ;JFN FOR THE PLOTTER
MININC: BLOCK 1 ;INCREMENT TO MINOR AXIS PER UNIT OF MAJOR AXIS
OLDPEN: BLOCK 1 ;LAST PEN STATE WE SENT
TWODIR: BLOCK 2 ;TWO DIRECTIONS MAKING UP OUR LINE
PLTCNT: BLOCK 1 ;COUNT OF BYTES LEFT TO WRITE IN BUFFER
PLTPTR: BLOCK 1 ;BYTE POINTER TO LAST BYTE WRITTEN
PLTPGN: BLOCK 1 ;JFN,,PAGE # OF PAGE WE'RE WRITING
PLTTOT: BLOCK 1 ;TOTAL NUMBER OF BYTES WE'VE WRITTEN SO FAR
;THE FOLLOWING GROUPS OF DATA SHOULD REMAIN CONTIGUOUS, SINCE THEY ARE
;REFERENCED BY DMOVES, ETC.
XMIN: BLOCK 1 ;LIMITS FOR PLOTTING, X AND Y MINS AND MAXES
XMAX: BLOCK 1 ; ..
YMIN: BLOCK 1 ; ..
YMAX: BLOCK 1 ; ..
OLDIX: BLOCK 1 ;LAST INCREMENTAL X LOCATION
OLDIY: BLOCK 1 ;LAST INCREMENTAL Y LOCATION
X: BLOCK 1 ;FLOATING-POINT X COORDINATE OF CURRENT ROOM
Y: BLOCK 1 ;FLOATING-POINT Y COORDINATE OF CURRENT ROOM
END CAVE