Adventure is a computerised version of the game Dungeons and Dragons, both of which are enormously popular. In Dungeons and Dragons a player is assigned the role of dungeon master, devising the dungeons which the other players explore in an attempt to acquire the treasures hidden there, often after having fought their way past monsters of various kinds.
Each player announces his action to the dungeon master who then tells him of the outcome, usually after spinning various dice to generate a random element.
Adventure, run on PDP-11 systems everywhere, is similar to Dungeons and Dragons except that the dungeons are devised by the original programmer and the computer then assumes the role of dungeon master.
Somewhere nearby is Colossal Cave, where others have found fortunes in treasure and gold, though it is rumoured that some who enter are never seen again. Magic is said to work in the cave. I will be your eyes and hands. Direct me with commands of one or two words. You are standing at the end of a road before a small brick building. Around you is a forest. A small stream flows out of the building and down a gully. ENTER BUILDING You are inside a building. A well house for a large spring. There are some keys on the ground here. There is a shiny brass lamp nearby. There is food here. There is a bottle of water here. GET KEYS OK GET LAMP OK RUB LAMP Rubbing an electric lamp is not particularly rewarding. Anyway, nothing exciting happens. EXIT You're at the end of the road again. Go SOUTH You are in a valley in the forest beside a stream tumbling along a rocky bed GO SOUTH You are in a 20-ft. depression floored with bare dirt. Set into the dirt is a strong steel grate mounted in concrete. The grate is locked UNLOCK GRATE The grate is unlocked.Once having opened the grate, for which he must have the keys, the player then has access to Colossal Cave where there are problems to solve and treasures to gather. However, if he does not have the keys, there is no way that the grate can be opened. In fact, it may take him, a while to find the entrance as it is all too easy to become lost in the forest.
As you can see from the example, playing Adventure is rather like reading a novel, with one important difference. Instead of following the story passively, the reader is involved actively, deciding what is the best action to take in a given situation, often having to think very carefully as the wrong decision may lead to death.
That affinity with a novel is Adventure's main disadvantage. Once all the problems have been solved, which may take several weeks, interest wanes and another Adventure is required.
The original version of Adventure, programmed by Will Crowther at Stanford Research Institute, is coded in Fortran, requires 64Kbytes of memory, disc back-up and is very difficult to modify to generate new games as many of its features are buried deep within the program code. That explains the current shortage of Adventures.
A better solution would be to have a general Adventure program driven by a separate database allowing new games to be generated without having to overcome the programming complexities every time. In fact, that approach was used by Scott Adams who has now produced a number of excellent adventures for some of the more popular systems such as the TRS-8O and Sorcerer.
The program described here carries this concept one step further. Instead of one person producing adventures for a limited range of systems the idea is to describe a program which can be implemented on almost any system and driven by an entirely separate and machine-independent database. That allows owners of the program to write adventures in a simple form and swap games with someone who may have an entirely different processor.
1. The vocabulary of words recognised in the game. 2. The objects that may be manipulated 3. The places that may be visited 4. The actions performed by specific words.All that is required to produce the database and the program is an assembler and examples of various table entries are shown for a Z-8O type assembler.
The vocabulary is held as the first four letters of a word followed by an identifying code. That permits the program to reduce words to simple numbers which are much easier to manipulate. It also allows different words to have the same code and hence the same meaning.
VOCAB: DEFM 'NORT' ;Word "NORTH"
DEFB 1 ;Identifying code "1"
DEFM 'EAST'
DEFB 2 ;EAST has code "2"
DEFM is the instruction to define an ASCII string and DEFB is to define a byte.
The table has the name "VOCAB" and terminated by a byte of 0FFH (255 or -1).
The words for movement - north, south, etc. - must have codes in the range 1 to
12 as the program prints the message - I cannot go in that direction - if it cannot
find anything to do with words in that range. Other unmatched words generate the
simpler response: I can't.
Objects are anything which may be moved from one place to another and/or transformed from one thing to another. A lamp, for example, may be carried with the player and it may be transformed from a "LIT LAMP" to an 'UNLIT LAMP" and, of course, back again.
Each object has an entry in each of two tables: the object location table which records the current position of the object and the object description table which contains the text used to describe the object.
The current location table is named "OBJLOC" and the descriptive text table "OBJTXT". OBJLO is terminated by a byte of OFFH. OBJTXT needs no termination.
OBJLOC: DEFB 3,0 ;Object 0 at location 3
DEFB 5,0 ;Object 1 at locations 5
;Similarly for other objects
OBJTXT: DEFW M0 ;Address of text for object 0
DEFW M1 ;Address of text for object 1
M0: DEFM 'A little axe' ;Description of object 0
DEFB 80H ;String terminator
Ml: DEFM 'A bunch of keys'
DEFB 80H
Note that the object position information is two bytes to allow it to be at
a location - first byte is 0-225 - or in some special place, such as carried
by the player - second byte is used. Also, the object description table OBJTXT
contains the address of the actual description for each object.
The locations are the places that the player may visit. They may be rooms, caves or anything desired by the Adventure writer. Each location has an entry in two tables: The description of the location and the list of directions the player may go from there. The location descriptions are held in a table named LOCTXT and the possible movements in MOVEMT. Both of those tables consist of pointers to the actual data as described for the object descriptions above.
MOVEMT: DEFW D0 ;Pointer to location 0 moves
DEFW D1 ;Pointer to location 1 moves
;etc. for rest of locations
The following example movement shows an entry that says that word 0 takes us to
location 1 and word 3 will take us to location 5. Note that a -1 terminates the list.
D0: DEFB 0,1,3,5,-1
LOCTXT: DEFW L0 ;Pointer to descriptions
DEFW L1
L0: DEFM 'I am in an empty room
DEFB 80H
L1: DEFM 'I am by a stream'
DEFB 80H
The action table is the section of the database interpreted or executed by the
main program. It consists of word, conditions and actions performed. If there is
an entry in the table for the words entered by the user and the conditions specified
are met, the actions are performed.
For example, he may be in the same room as a Vampire without a crucifix so the computer may make the Vampire attack. The user action table is named EVENT and the computer's table STATUS. Both have the same format:
EVENT: DEFB 0,1 ;words 0 and 1
DEFW C0 ;Pointer to conditions
DEFW A0 ;Pointer to actions
DEFB 3,-1 ;Only word 3 required
DEFW C1 ;Pointers
DEFW Al
C0: DEFB 0,1,1,2,-1 ;Must be at location 1 (0,1)
;Object 2 must be here(1,2)
A0: DEFB 5,3,-1 ;Print message 3
The lists of actions and conditions are terminated by a byte of 0FFH (-1). Note that
the examples are only very small extracts from a real table. A full-size database may
have up to 255 locations and any number of entries in the event and object tables.
Assembly listings for every processor would occupy far more space than the magazine can provide and flowcharts would not really describe the action of the program at the level of detail we want. For those reasons, the program is represented in pseudo-code.
For those not familiar with the term, pseudo-code is a non-existent language or shorthand representation of a program often used by programmers for detailed design when the actual target language is not yet known. Pseudo-code provides far more detail than flowcharts and is, in fact, detailed instructions for the actual coding of the program.
Although the listing should be more or less self-explanatory, it's worth mentioning two conventions used. If a variable is preceded by a "@" it means that the variable is used as a pointer to the data. For example, if "HL" contains the value 100 and we say "A=@HL", "A" is loaded with the contents of memory location 100.
A Similar convention is used to identify the address of a variable except the "#" character is used - also used by the IF statement for not equal to. For example, if we say "HL=#OBJLOC", it means that the variable HL is loaded with the address of OBJLOC and not the contents.
Variables used are defined as either BYTE, 8-bit, or WORD, 16-bit, and the contents are assumed to be set to zero unless a value is included between two 'P's. For example, to define two 8-bit variables in memory, one set to zero and the other to 3 we use:
BYTE VARA,VARB/3/
A memory block is reserved by:
BYTE VARC/<7>/
which means reserve seven bytes of memory starting at label "VARC".
That leads to the implementation of arrays used by the program. All references to arrays mean an offset to the base label of a memory area. For example, VARC(3) simply means the address found by adding three to the value of label VARC.
Thus VARC(0) is exactly equivalent to VARC. Remember that words occupy two bytes, so, if VARC was a word array, VARC(3) would actually be addressing VARC + 6 and also VARC + 7 for the top byte.
Knowing this, you should now be able to produce a version of the program for your particular system by working through the listing and generating the appropriate assembly code for your machine. If you have access to a medium-level language; such as PL/M for example, that is of course, equally acceptable.
The pseudo-code program shown here has in fact been compiled by a specially-written compiler to ensure that it is sound.
Let us work through the program considering what makes it tick and explaining the meaning of the pseudo-code representation.
Referring to the listing, we can see that the first section is simply the definition of items not within this listing, that is the items marked "GLOBAL". Four subroutines not described here are called, but as these are relatively simple entities they should present no problem in coding.
The first subroutine required is called "$REPLY" and it is simply a routine to read a response from the user and return a value of one if it was a "Y", and a value of zero if it was a "N". The routine should check that either a "Y" or a "N" was entered and prompt "PLEASE ANSWER YES OR NO" for any other reply.
The second routine is named $MESS and is the routine used to print messages on the console. It must take the ADDRESS of a message as a parameter and print all the bytes found there until a byte with the most significant bit set is encountered. The routine used also had the additional feature that it printed a return/line feed if it was called with an address of zero.
The next routine, $LINE, is the opposite of $MESS; it obtains a line from the user and passes back the address of the stored text.
It can be done by reading the refresh register if you have a Z-80 system, or if your keyboard is software controlled, you may increment a counter in, the keyboard - wait loop and use that value as the random number. If you want a more elegant solution, the random numbers used in the prototype program were generated using the algorithm:
[Generated number] = 11x[Last generated number] + 999 MOD 101although this does require 16-bit multiply and divide.
The next group of globals refer to the addresses of the various tables in the database.
A further point is that some items are used for temporary storage only and may be replaced by the processor registers if you desire. The only variables that must be in memory are Here, the current location and User, the variables the data- base may access. If you run out of registers, remember they may be saved on the stack while a register is used for something else.
Proceeding to the code, we can see that the program begins at label "Start" which simply sets the first location to zero. The code beginning at "Desc" describes the current location by printing the description found adding the contents of 'HERE' to the base address LOCTXT and using the pointer there
The current location will, of course, change as the game progresses. A small piece of code checks to see if the database has set user flag zero and if so, we are in dark locations and object zero must be present (a lamp) to obtain the location description. Otherwise the message "Everything is dark. I cannot see" is displayed.
The code then goes onto scan through the object location table "Objloc" and if any objects position is the same as the current position "Here", the object description is printed.
Next, the program looks quickly as the status table which is effectively the computer's turn at the game. However, as the same mechanism which decodes the player's command is used, we will consider it later. That function, when completed returns to the label "PROC".
The routine that obtains a line from the user is called ($LINE) and the address of the entered text obtained. The routine used returned the address on the top of the stack and the instruction "HL = @ SP" finds that address.
That reduction of the line allows complex sentences like "TURN ON THE LAMP" to be reduced to simpler entities like "ON LAMP", provided the words TURN and THE are not in the vocabulary. Hence it is important to consider carefully which words are not in the vocabulary as well as which ones are.
If none of the entered words is found in the vocabulary, the message "I don't understand" is printed and we go and obtain another line from the player.
After we have converted the user's command into one or two single-byte codes, we take the first code and see if it is one of the words which cause movement at the location. If it is the current position (HERE) is updated and we return to label "MOVED" to describe the new place. If it is not, we proceed to examine the main event table to see if there is an entry there.
If the first word code '"W1"' matches the first byte of an entry and "W2" matches the second byte, we proceed to extract the conditions and test them. If all the conditions are satisfied, we extract the list of actions and execute them.
If all the conditions do not match or the two-word codes do not match, we try the next entry in the table. That is repeated until an explicit command to leave the table is given-or the table is exhausted.
The action or condition is decoded by using it as an index into a list of addresses for the function we want and simply moving the address to the program counter (PC). It can usually be done on most machines by pushing the address on to the stack and executing a return from subroutine instruction.
The comments in the program listing explain the operation in greater detail and indicate what actions and conditions are available.
Looking at some examples of a database should further clarify the operation of the program. To make the database more readable, the example extracts shown below were produced using a macro assembler and calling various macros to make the entries in the appropriate table.
VOCAB:: TABLE <SOUT> ,1 TABLE <S> ,1 TABLE <EAST> ,2 TABLE <E> ,2 TABLE <WEST> ,3 TABLE <W> ,3 TABLE <NE> ,4 TABLE <NW> ,5 TABLE <SE> ,6 TABLE <SW> ,7 TABLE <UP> ,8 TABLE <U> ,8 TABLE <DOWN> ,9 TABLE <D> ,9 TABLE <NORT> ,12 TABLE <N> ,12 TABLE <END> ,13 TABLE <TOP> ,13 TABLE <QUIT> ,13 TABLE <ABOR> ,13In the objects shown here, note how items which can change state are two objects although only one of the pair may exist at any given time.
OBJECT 0, <0,8>, <A lit lamp> OBJECT 1, <S7,0>, <An old oil lamp> OBJECT 2, <S5,0>, <A small cloth bag> OBJECT 3, <S5A,0>, <A bottle of holy water> OBJECT 4, <0,8>, <An empty bottle> OBJECT 5, <0,8>, <A match> OBJECT 6, <0,8>, <A spent match>The first byte of the location information is used to mark the location of the object. If the second byte is non-zero, the object is at one of the special places. These are:
2 - Object is carried [512] 4 - Object is worn [1024] 8 - Object does not exist (yet) [2048]The value in "[]" indicates the number obtained when the two bytes are considered as a single 16-bit word.
LOC S0, <HELP,S1,BEGI,S2> TXT <Welcome to Adventure!> TXT <If you know what to do type BEGIN otherwise type HELP> LOC S1, <BEGI,S2> TXT <I have managed to get myself lost in the forest on my> TXT <quest for the seven golden keys of Waydor and don't know> TXT <what to do next. So it is up to you to help me.> TXT <> TXT <Give me your instructions and I will obey. For example,> TXT <if you want me to go to the north. Type "Go NORTH", if> TXT <we should come across some keys and you want me to get> TXT <them, type "GET THE KEYS".> TXT <Some other words that you may find useful are:> TXT <INVENTORY to find out what I'm carrying> TXT <QUIT to give up.> TXT <> TXT <Type "BEGIN" when you are ready to start.> LOC S2, <S,S4,PATH,S4> TXT <I am in a clearing in a very dense forest.> TXT <There is a path leading off to the south.> LOC S5, <N,S2,E,S5,W,S6> TXT <I am at a "T" junction with exits to the north, west and east> LOC S5, <W,S4,EXIT,S4,E,S5A,ALTA,S5A> TXT <I am amongst the ruins of a church. At the far end there> TXT <are the remains of an altar. The exit is to the west.> LOC S5A, <EXIT,S5,W,S5> TXT <I'm beside the altar.> LOC S6, <E,S4,IN,S7,CRYP,S7> TXT <I'm outside the entrance of a crypt.> LOC S7, <EXIT,S6,DOOR,S6> TXT <I'm in a vaulted chamber. Thick cobwebs hide the ceiling. TXT <There is an empty coffin in the corner and a passage leading> TXT <off into darkness to the north.> LOC S8, <D,S9,STEP,S9> TXT <I'm at the top of a steep flight of steps. I can see a> TXT <dim light to the south.>The event table is the real heart of the database as it contains the actions performed by each command from the user. This section also contains the various messages which may appear under database control.
EVT 2 <N,-1> <0,S7,-l> <9,0,8,S8,6> EVT 3 <S,-1> <0,S8,-1> <10,0,8,S7,6> EVT 4 <GET,LAMP> <1,0,-1> <2,0,13> EVT 5 <GET,LAMP> <1,1,-1> <2,1,13> EVT 6 <DROP,LAMP> <1,0,-1> <3,0,13> EVT 7 <DROP,LAMP> <1,1,-1> <3,1,13> EVT 8 <LIGH,LAMP> <1,1,1,5,-1> <11,0,11,5,5,11,18,-1> EVT 9 <OFF,LAMP> <1,0,-1> <11,0,13> EVT 10 <LIGH,LAMP> <1,1,-1> <5,14,-1> Status: EVT A <-1,-1> <7,5,5,0,2,10,-l> <5,7,15,2,8,9,5,-1> EVT B <-1,-1> <6,2,1-1> <5,8,12> EVT C <-1,-1> <5,2,-1> <5,5,-1> EVT Z <-1,-1> -1 7 MSG 5,<I feel sick and dizzy!> MSG 7,<Some one has lept out of the shadows and BITTEN MY NECK!!!!> TXT <He vanished as suddenly as he appeared!> MSG 8,<Everything is getting dark! I Think I'm dy...> MSG 11,<I have lit the lamp with the-match which has now burned out> MSG 14,<1 don't have anything to light it with.>It is worthwhile examining some of the entries in the table in detail to show just what can be accomplished in the database. For example in the location S7 shown, there is a passage leading north, but there is no entry in the movement list for it.
That is because rooms past there are dark and we want to tell the program. So let us look at entry 2. The word codes which must match are "N" (north) and anything will do for the second. There is a single condition, namely that he must be at location S7. If that is so, actions are performed which are: 9,0 - Set flag zero; 8,S8 - Go to location S8; 6 - Describe the location and obtain another command from the player.
An informative message is also printed. The final command (18) aborts the scanning of the table as a little later in the table, there is an entry for LIGHT LAMP when no match is present - which gives message 14 - and we do not want to fall through to it if we have already lit the lamp.
The table is terminated by a word code of zero. Note that in the example the words GET, DROP etc., are shown but in a real table the word code is used.
The entries in the STATUS table show an example of how a "wandering monster" may be implemented. The conditions are: Flag 5 must be zero; he must be in "dark" locations and 10 percent probability will generate the actions. The actions are: print message 7; store 8 in flag 2 - counted-down by the program - and set flag 5 to prevent more vampires.
The program should fit in less than 4K but you will find that the descriptive text, particularly for locations, will eat memory.
In terms of software, all you need are an editor and an assembler. However, if you have access to a disc-based system, all the better. Perhaps the best way to go about it is through your local computer club working on the program as a team and generating your own adventures.
As the database is pure data, any database will run on any machine - providing there is enough memory. However, the program still needs to know the position of the tables in memory.
ORG 2000W ;start of program LOCTXT EQU 200H ;Define table address VOCAB EQU 1000H ;ETC for rest of tables OBJLOC EQU 50HAnother approach would be to make the tables of a fixed length and define specific addresses for them. That removes the need to re-assemble the program for each database but does not use memory very efficiently.
Unfortunately, Adventure is not the kind of game you can describe in such a way that the program can be blindly copied and played. However, I hope that the description given here will allow anyone to implement it on his system. If you're wondering if it is worth the effort, ask anyone who has played before.
! ************************************************
! * ADVENTURE *
! * *
! * Programmed by - K Reed *
! * Date - 12-May 80 *
! * *
! ************************************************
BEGIN DATA
! External subroutines
! $REPLY - Gets a YES/NO response from the user
! $MESS - Output to console
! $LINE - Read a line from the console
! $RAND - Get a random number (Range 1-100)
GLOBAL $REPLY,$MESS,$LINE,$RAND
! Driving database labels
! Message - User messages
! Vocab - Basic vocabulary
! Loctxt - Location descriptions
! Objloc - Object locations
! Objtxt - Object descriptions
! Event - Main event table
! Movemt - Location movements
! Status - Status check table
GLOBAL Message,Vocab,Loctxt,Objloc,Objtxt
GLOBAL Event,Movemt,Status
WORD Here,HL,BD,DE,Rnum,I,J,User/<15>/
BYTE Flag,W1,W2,Btemp,Ctemp,Domeit
BYTE Word1/<4>/,Space/' '/,Cret/0/,Bneg1/-1/,Bzero/0/
END DATA
PROGRAM Adventure
Start: here=0 ! Start at location 0
Moved: CALL $mess(0) ! New line
! User flag 0 when set indicates a dark location
! He cant see unless object 0 is here
! Note that Objloc(0) is equivalent to simply Objloc
Desc: BEGIN IF (User#0)
IF (User(3)#0)User(3)=User(3)-1
IF (Objloc=Here)GO TO Seen ! Object here
IF (Objloc=512)GO TO Seen ! Carried
TYPE 'Everything is dark. I cannot see'
IF (User(4)#0)User(4)=User(4)-1
GO TO Command
ENDIF
Seen: CALL $MESS(Loctxt(HERE)) ! Describe Here
Look: Flag=0 ! List objects here
I=0
Look1: IF (objloc(I)=-1)GO TO command ! End of objects
IF (objloc(I)#here)GO TO next
BEGIN IF (Flag=0) ! Object here
CALL $mess(0) ! New line
TYPE 'I can also see'
Flag=1 ! That message only once
ENDIF
CALL $mess(objtxt(I)) ! Describe object
CALL $mess(0)
Next: I=I+1 ! Next entry
GO TO look1
Command:
HL=$Status ! See if anything happens
GO TO Active
Proc: ! Returns here
IF (User(2)#0)User(2)=User(2)-1 ! Count down active
CALL $RAND(#Rnum) ! Keep random spinning
CALL $Mess(0)
CALL $Line ! Get a line
HL=@SP ! Point to it
GETWD: CALL Lookup(#W1) ! See if we know it
BEGIN IF (W1=Bneg1) ! Not found in table
BEGIN IF (@HL=Cret) ! No more words
Err1: Type 'I just don't understand what you mean'
BEGIN IF (Word1>90)
TYPE 'Perhaps if you used UPPER CASE'
ENDIF
GO TO Command ! Try again
ENDIF
Scan: BEGIN IF (@HL=Space) ! Next word
HL=HL+1
GO TO getwd
ENDIF
IF (@HL=Cret)GO TO Err1 ! No more words
HL=HL+1
GO TO Scan
ENDIF
! If we fall out here we have a known word in W1. Now see
! if we can find one for word number 2
W2=Bneg1 ! No word yet
Scan2: IF (@HL=Space)GO TO Second ! Found one
IF (@HL=Cret)GO TO Allin ! No more
HL=HL+1
GO TO Scan2
Second: HL=HL+1 ! Point to word
CALL Lookup(#W2) ! See if an object
BEGIN IF (W2=Bneg1) ! Not found
Scan3: IF (@HL=Cret)GO TO Allin
IF (@HL=Space)GO TO Second ! Another word found
HL=HL+1
GO TO Scan3
ENDIF
! See if this word causes a change of location
Allin: HL=Movemt(Here) ! Point to movements
Moveit: IF (@HL=Bneg1)GO TO Nomove ! End of list
BEGIN IF (@HL=W1) ! Entry found
HL=HL+1 ! Point to dest
Btemp=@HL ! Go there
Here=Btemp ! Keep to bytes
GO TO Moved
ENDIF
HL=HL+2 ! Next entry
GO TO Moveit
Nomove:
! Look up the words in the main event table to see
! what (if anything) happens
HL=#Event ! Point to table
Doneit=0 ! Clear flag
Active: BEGIN IF (@HL=Bzero) ! End of table
IF (Doneit#0)GO TO Command ! We did something
BEGIN IF (W1<13) ! Explicit movement
TYPE 'I cannot go in that direction'
ELSE
TYPE 'I cant'
ENDIF
GO TO Command ! Get another command
ENDIF
IF (@HL=Bneg1)GO TO Entry ! Any match
IF (@HL=W1)GO TO Entry ! Exact match
HL=HL+6 ! Next entry
GO TO Active
Entry: HL=HL+1 ! Point to 2nd word
IF (@HL=Bneg1)GO TO Match ! Any match
IF (@HL=W2)GO TO Match ! Exact match
HL=HL+5 ! Next entry
GO TO Active
Match: HL=HL+1 ! Condition pointer
BC=@HL ! Get it
HL=HL+2 ! Point to actions
Check: IF (@BC=Bneg1)GO TO Doit ! End of conditions
Btemp=@BC ! Get this condition
BC=BC+1 ! Next operand
Ctemp=@BC ! Preload
PC=TABLE1(Btemp) ! Computed GO TO
C0: IF (Ctemp=Here)GO TO passed ! Check current location
Cont: HL=HL+2 ! Next word pair
GO TO Active ! Try next table entry
C1: IF (Objloc(Ctemp)=HereGO TO passed ! Object present
IF (511<Objloc(Ctemp)<1025)GO TO passed
GO TO Cont
C2: CALL $RAND(#Rnum) ! Probable event
IF (Ctemp>Rnum)GO TO passed
GO TO Cont
C3: IF(Objloc(Ctemp)=Here)GO TO Cont ! Object not here
IF (511<Objloc(Ctemp)<1025)GO TO Cont
GO TO passed
C4: IF (Objloc(Ctemp)#1024)GO TO passed ! Object not worn
GO TO Cont
C5: IF (User(Ctemp)=0)GO TO Cont ! Flag not zero
Passed: BC=BC+1 ! Next condition
GO TO Check
C6: BC=BC+1 ! Check flag value
Btemp=@BC !
IF (User(Ctemp)#Btemp)GO TO Cont
GO TO Passed
C7: IF (User(Ctemp)#0)GO TO Cont ! Flag zero
GO TO Passed
C8: IF (Objloc(Ctemp)#512)GO TO Cont ! Object carried
GO TO Passed
! Condition met so perform actions
Doit: BC=@HL ! Point to actions
HL=HL+2 ! Point to next entry
Doneit=1 ! Say we've done something
Nxtact: IF (@BC=Bneg1)GO TO Active ! All done
Btemp=@BC ! Get action
BC=BC+1 ! Point to next
Ctemp=@BC ! Preload value
PC=TABLE2(Btemp) ! Computed GO TO
! In the following TABLE3 is simply a continuation of TABLE2
! and not a separate entity. It is done this way to keep the
! compiler happy as it can't handle continuation lines
BEGIN DATA
WORD TABLE2/A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10/
WORD TABLE3/A11,A12,A13,A14,A15,A16,A17,Done/
END DATA
A0: TYPE 'I have with me' ! Inventory
Flag=0
I=0
Inven: IF (Objloc(I)=-1)GO TO inven0 ! End of list
BEGIN IF (511<Objloc(I)<1025) ! Carried
Flag=1
CALL $mess(objtxt(I))
BEGIN IF (Objloc(i)=1024) ! Worn
TYPE ' which I am wearing'
ELSE
CALL $mess(0) ! New line
ENDIF
ENDIF
Nextob: I=I+1
GO TO inven
Inven0: IF (Flag=0)TYPE 'Nothing at all'
GO TO Done
A1: BEGIN IF (Objloc(Ctemp)#1024) ! Remove worn object
TYPE 'I am not wearing it'
GO TO Done
ENDIF
BEGIN IF (User(1)=4) ! Hands full
TYPE 'I cant. My hands are full'
GO TO Done
ENDIF
Objloc(Ctemp)=512 ! Say carried
User(1)=User(1)+1 ! Update tote
GO TO Nxtop
A2: BEGIN IF (User(1)=4) ! Pick up object
TYPE 'I cannot carry any more'
GO TO Done
ENDIF
BEGIN IF (Objloc(Ctemp)=Here
Objloc(Ctemp)=512 ! Say carried
User(1)=User(1)+1 ! Update total
GO TO Nxtop
ENDIF
TYPE 'Im already carrying it'
GO TO Done
A3: BEGIN IF (Objloc(Ctemp)=Here) ! Drop object
TYPE 'I don't have it'
GO TO Done
ENDIF
IF (Objloc(Ctemp)=512)User(1)=User(1)-1
Objloc(Ctemp)=Here
GO TO Nxtop
A4: BEGIN IF (Objloc(Ctemp)=512) ! Wear it
Objloc(Ctemp)=1024 ! Say carried
User(1)=User(1)-1
GO TO Nxtop
ENDIF
BEGIN IF (Objloc(Ctemp)=1024)
TYPE 'I am already wearing it'
ELSE
TYPE 'I don't have it'
ENDIF
GO TO Done
A5: CALL $Mess(Message(Ctemp)) ! Type message
GO TO Nxtop ! Get next action
A6: GO TO Desc ! Describe location
A7: GO TO Proc ! Procede
A8: Here=Ctemp ! Immediate move
GO TO Nxtop
A9: User(Ctemp)=255 ! Set flag
GO TO Nxtop
A10: User(Ctemp)=0 ! Clear flag
Nxtop: BC=BC+1
GO TO Nxtact
A11: DE=Objloc(Ctemp) ! Swap objects
Objloc(Ctemp)=Objloc(Ctemp+1) ! Move 1st object
Objloc(Ctemp+1)=DE ! Move 2nd object
GO TO Nxtop
A12: STOP ! Stop the program
A13: TYPE 'Okay' ! Say okay
GO TO Done ! And procede
A14: TYPE 'Are you sure you want to quit now'
CALL $reply(#i)
IF (I=0)GO TO Nxtact
STOP 'Okay ... bye'
A15: BC=BC+1 ! Store value in flag
Btemp=@BC ! Get it
User(Ctemp)=Btemp
GO TO Nxtop
A16: Objloc(Ctemp)=Here ! Create object
GO TO Nxtop
A17: Objloc(Ctemp)=2048 ! Destroy object
GO TO Nxtop
Done: GO TO Command
! Lookup - Find word in table
! Each entry consists of a four byte name
! followed by an byte identification code. Eg 'FRED',2
! this code is returned if found, otherwise -1.
SUBROUTINE lookup(DE)
LOOP J=0 TO 3 ! Clear out word
Word(J)=Space
ENDLOOP J
LOOP J=0 TO 3 ! Extract 1st 4 letters
IF (@HL=Space)GO TO Gotwrd ! End of word
IF (@HL=Cret)GO TO Gotwrd ! End of word
Word(J)=@HL ! Get character
HL=HL+1
ENDLOOP J
Gotwrd: BC=$Vocab ! Point to table
@DE=Bneg1 ! Assume no match
Find: Flag=0 ! fndit Flag
LOOP I=0 TO 3 ! 4 bytes
IF (@BC=Bneg1)RETURN ! End of table
IF (Word1(I)#@BC)Flag=1 ! No match
BC=BC+1
ENDLOOP I
BEGIN IF (Flag=0) ! Matched
Btemp=@BC ! Get ID
@DE=Btemp ! Pass it to caller
RETURN
ENDIF
BC=BC+1 ! Skip over ID
GO TO Find ! And try again
END
(Practical Computing - August 1980)