
*** C Adventure Toolkit (CAT) - Introduction

This file introduces the concepts behind the C Adventure Toolkit (CAT),
tells you how to install it, and explains how it should be used.

******************************************************************************

The CAT system is shipped on a 720K MS-DOS formatted disk, with both PC and ST 
versions included. The ST can use MS-DOS format disks with no problems, so 
the system is available to users of both families of machines.

The principle behind CAT is simple: You provide details of your adventure to 
CAT in a very high level language, which will be 'compiled' into C source 
code. Your generated C code can  then be compiled, along with standard CAT C
code, to produce your finished adventure! The code generated by CAT is
portable - I have tested in on Sozobon C; MWC; and LaserC on the ST, as well 
as TurboC on the PC.

The CAT system comprises of a generator program, standard definition
files, and standard C code to be compiled with your generated code.

   The generator program (GEN.TTP or GEN.EXE) lives in the \CAT folder.
   The standard definition files live in the \CAT\STD folder.
   The standard C code files live in the \CAT\GENSRC folder.

******************************************************************************

To use CAT, you will need the following:

    PC
    ==
    At least 512K memory.
    At least 720K floppy.
    A C compiler.
    A text editor that will write pure ASCII files.
    A vivid imagination
    A basic understanding of C is recommended.

    ST
    ==
    At least 512K memory.
    At least 720K floppy.
    A C compiler.
    A text editor that will write pure ASCII files.
    A vivid imagination
    A basic understanding of C is recommended.

    Note: Whilst CAT will run happily with 512K on an ST, you may find that 
          some memory intensive C compilers run out of memory when compiling
          the generated C code. 

          Sozobon C is memory intensive - source generated by CAT will
          probably be too big to be compiled by Sozobon C with just 512K.

          MWC is disk intensive - this means it can compile far bigger 
          programs, as all of its' work is done on disk, not in memory!

******************************************************************************

Installation:
=============

 1) Make a back up copy of the production disk!

 2) Copy the CAT folder, and all sub-folders to the root folder on your
    working drive. It is recommended that CAT is run from a Hard disk, but a
    floppy will be okay, as long as it is formatted to at least 720K.

 2) If you are running CAT on a PC, modify your AUTOEXEC.BAT file to 
    include \CAT in the PATH. Add this line to the end of the file...
    PATH %PATH%;\CAT

 3) If you are running CAT on a PC, make sure that at least 30 FILES are
    available. You should have a line like this in your CONFIG.SYS file...
    FILES=30

 4) If you are running CAT on an ST, and you are using a shell program 
    (i.e. Gulam; MSH etc), then set your PATH environment variable to 
    include \CAT - the command will be something like this for MSH...
       setenv PATH=$PATH,\CAT
    or this for GULAM...
       setenv PATH $PATH,\CAT
       rehash

 5) If you are running CAT from a PC, you can delete any .PRG and .TTP 
    files - these are for the ST version and you won't be needing them!

 6) If you are running CAT from an ST, you can delete all .EXE and .BAT 
    files - these are for the PC version and you won't be needing them!

 7) You are now ready to use CAT!
 
******************************************************************************

The main program (GEN.TTP on an ST, or GEN.EXE on a PC), processes your
adventure definition, and generates C code for your adventure program.

When GEN starts up, it looks in the current folder for a file called 
'GENLIST'. The GENLIST file should contain the names of each definition file
that is to be used to generate the adventure source. These definition files 
can have any names, but it would be advisable to use the standard extendor '.d'
e.g. - file1.d, file2.d file3.d. You can use any number of definition files
to create your adventure.

Each line in the GENLIST file can contain a simple file name, or a file 
with a pathname, and optionally a drive - so a typical GENLIST file may be:

   OBJECTS.D
   ROOMS.D
   MESSAGES.D
   LOGIC.D
   A:\MYSTDS.D
   \CAT\STD\ZZRQD.D 
   \CAT\STD\ZZSTD.D  
                        
The next thing GEN will do is look for a sub-folder from the current folder,
called CSOURCE. This is the destination folder for the generated C code. 

If all is okay, GEN will begin it's work. As it works, GEN will display any
potential errors it encounters on the screen, and these will also be written
to the file 'GENOUT.TXT'.

******************************************************************************

You will notice the two standard defintion files ZZRQD.D and ZZSTD.D are
included in the sample GENLIST file detailed above. These definition files are
supplied with CAT, and provide the vast majority of the processing you need.
You should use these files, or a version of them to create your adventure.

ZZRQD.D - contains all the required definitions. CAT refers to anything that
          is defined in this file internally. You can change this file, 
          but make sure all the names remain the same.

ZZSTD.D - contains standard logic for your adventures. The definitions in this
          file are not referred to internally by CAT, so you can change 
          anything contained in it.

******************************************************************************

The GEN program has the following command line options:

   -Spath   - use this to specify the source folder. This option is useful if
              you are using GEN via the GEM desktop on the ST. The option
              forces GEN to change directory to the selected folder - i.e.
              the folder where your GENLIST lives. The -S option does not
              allow a drive to be specified.

   -L       - This tells GEN to list the definition source as it processes it.

   -V       - This tells GEN to give a verbose list of all possible errors 
              it discovers. By default, GEN only reports the more rare and
              possibly hazardous errors.

   -E       - This tells GEN to encrypt the code it produces, safe from 
              prying eyes. You should always use this option when producing
              a finished copy of your adventure.

   -C       - This tells GEN to compress the text in your adventure.
              WARNING: compressing adventures with small amounts of text may
                       result in LARGER programs being generated. Compression
                       will be most successful in games with a lot of text.

   -I       - This tells GEN to print the names of all the items that are
              defined. By default, GEN only reports those items that are
              defined but are not directly referred to.
   
   -F       - This tells GEN to do full logic checks. i.e. it makes sure that
              low priority logic is only used in low priority logic, that 
              logic tests are not used in commands, that logic tokens are
              recognised tokens, etc. This switch is additional to -V.
   
   -R       - Perform a report only run. Do not write any files. This is 
	      FAST, and allows you to easily check the syntax of your source.

   -Dpath   - Specify the destination path (override default of CSOURCE).
              This can include a drivespec. The path should be direct i.e.
              -DF:\output or relative to the folder to where the GENLIST file
              lives i.e. -Dtest\output. This option is useful if you want to
              direct the output to a ramdrive - much faster!

   -Apath   - Autocopy GENSRC files to destination folder. By default, the 
              GENSRC files will be copied from \CAT\GENSRC, but you can 
              optionally specify the folder where GEN can find GENSRC files.
              The folder can include a drivespec.
 
GEN -E -I -F
   would look for a GENLIST in the current folder, encrypt all output, and
   produce a list of all the items that were defined. Full logic checking will
   be performed.

GEN -S\ADVENT -V -L
   would look for a GENLIST in the folder \ADVENT. It would list the definition
   files as it processed them, and give a verbose list of ALL errors. It would
   not encrypt the generated C source. Only those items that are defined but
   not directly referred to will be listed. Full logic checking will not be 
   performed.
 
GEN -R
   would look for a GENLIST in the current folder, and perform a report run.

GEN -A -E
   would look for a GENLIST in the current folder, encrypt all output and
   automatically copy the GENSRC files from \CAT\GENSRC.

GEN -AA:\CAT\GENSRC -S\AWE -Df:\ 
   would look for a GENLIST in \AWE. Output would be created in F:\ - GENSRC
   files would be automatically copied to F:\ from A:\CAT\GENSRC.

******************************************************************************

GEN switches can now be specified in your GENLIST file. Any switches 
included in the GENLIST file will override conflicting switches from the
command line.

     For example, the following GENLIST will automatically copy GENSRC from
     \CAT\GENSRC, and output will be encrypted.

     -e
     -a 
     \cattutr5\first.d
     \cattutr1\tutor1.d
     \cattutr2\tutor2.d
     \cattutr3\tutor3.d
     \cattutr4\tutor4.d
     \cattutr5\tutor5.d
     \cat\std\zzstd.d
     \cat\std\zzrqd.d
     \cattutr5\last.d

******************************************************************************

Once your C source has been generated, if you didn't use the -Autocopy option,
then you will need to copy all the files from the \CAT\GENSRC folder into your
destination folder (CSOURCE by default). After this, you can compile your
adventure with your favourite C compiler.

If you are compiling on a PC, you must define PC, and use the large model i.e.
  
   TCC *.c -DPC -ml

FAILING TO DEFINE PC WHEN COMPILING A PC ADVENTURE WILL RESULT IN FAILURE!

******************************************************************************

Two batch files have been supplied, with PC and ST versions of each:

The first batch file (GEN1) generates encrypted C code in CSOURCE, and copies
all the standard C files from \CAT\GENSRC into CSOURCE.

The second batch file (GEN2) compiles the C source in CSOURCE, and produces
the runnable adventure program 'ADVENT' in the current folder.

******************************************************************************

ST version of GEN1 - suitable for MSH (and possibly Gulam?)

GEN1
----
gen -e -a

******************************************************************************

ST version of GEN2 - suitable for MSH (and possibly Gulam?)

GEN2
----
cd csource
cc *.c -o advent.prg
mv advent.prg ..
cd ..

******************************************************************************

PC version of GEN1 - suitable for Turboc

GEN1.BAT
--------
gen -e -a

******************************************************************************

PC version of GEN2 - suitable for Turboc

(In my case the TurboC libraries live in D:\PC\TURBOC
                TurboC header files live in D:\PC\TURBOC\INCLUDE)

GEN2.BAT
--------
@cd csource
tcc -Ld:\pc\turboc -Id:\pc\turboc\include -ml -DPC -eADVENT.EXE *.c
@copy advent.exe ..
@cd ..

******************************************************************************


                           THE C ADVENTURE TOOLKIT
                           =======================

  (a quote from a strange person wearing a rather peculiar orange stetsun)

" Text adventures have now been with us for over a decade, and I strongly
  believe they will be with us for at least another decade. As available 
  hardware has improved, so have adventures. Various forms of graphical 
  adventures have come, and they have gone - but the text adventure is 
  protected by a cult following that will never allow it to die.          "

*******************************************************************************

The C Adventure Toolkit (CAT) is supported on both the IBM PC and Atari ST
families of machines. Both versions are shipped on one 3.5" disk, along with
a cross reference manual (this document) and step by step tutorials. 

The toolkit allows you to define your adventure in a very high level adventure
orientated language, which will then be compiled into C source code that you can
compile into a runnable adventure using your favourite C compiler. The system
has no rigid limitations other than those implied from your C compiler, or
memory limitations. CAT source has been tested on MWC; Sozobon C; and LaserC
on the ST as well as TurboC on the IBM PC. Adventure source can be generated
on the ST and then compiled on the PC, or vice-verser.

The CAT allows any number of characters to be controlled by the user, both
indirectly AND directly. It also allows any number of non player characters 
to interact with each other and/or the player characters. Full compound 
commands are fully acceptable. SCRIPT and VERBOSE modes are supported.

As well as constantly keeping a check on mundane adventure processing 
(such as light sources, compound object weights etc.), CAT provides a very
extensive set of logic control functions with which you can manipulate your
adventure universe to your hearts content.

Because CAT references all objects, rooms, messages and verbs by NAME, and not
number... it is very easy for anyone to look at a CAT source file and know 
instantly what it is doing/affecting. This feature also makes it a lot easier
to write an adventure with CAT, than any other system (no more lists of numbers)

It is a very simple process to convert a CAT adventure to a foreign language.

Registered users of CAT have full rights to sell/distribute any adventures 
that they may have created with the system (see REGISTER.TXT).

*******************************************************************************

Please read the CATINTRO.TXT document for details on how to install CAT, and
what you will need to use it successfully.

This manual is a cross-reference manual. I have provided five step by step
tutorials in the folders CATTUTR1-5 - each of these tutorials builds on the 
topics covered in previous lessons. You should use the tutorials to learn the
syntax of CAT, and then use this document as a future reference. Tutorial
number 5 has a runnable adventure (ADVENT.EXE for PC, ADVENT.PRG for ST).

The rest of this document is ordered alphabetically by keyword.

Advanced users may be interested in the CATEXPRT folder. This details how CAT
logic can be interfaced with custom C code.

*******************************************************************************
* @ADDCOMMAND(obj) * Logic command
******************** 

 Makes obj commandable, and active (allows 'obj, GET HAT'). 

*******************************************************************************
* @ADDCOUNT(cnt,val) * Logic command
**********************

 Add val to counter cnt.

*******************************************************************************
* @ADDPLAYER(obj) * Logic command
******************* 

 Makes obj a player object, and active (allows 'BECOME obj').

*******************************************************************************
* @ADDPOINTS(obj,val) * Logic command
***********************

 Add val to the object points of obj.

*******************************************************************************
* @ADDSTRENGTH(obj,val) * Logic command
*************************

 Add val to the strength of obj.

*******************************************************************************
* @ADDVALUE(obj,val) * Logic command
**********************

 Add val to the value of obj.

*******************************************************************************
* @ADDWEIGHT(obj,val) * Logic command
***********************

 Add val to the weight of obj.

*******************************************************************************
* @BECOME(obj) * Logic command
****************

 Make obj the current player, and the commanding player.

*******************************************************************************
* @BRIEF * Logic command
**********

 Enter BRIEF mode. Long room descriptions will be given the first time a 
 room is entered. After the first visit to a room, only the short description
 will be given, UNLESS the player specifically 'LOOK's.

*******************************************************************************
* CATHELP keyword.. *
*********************

 The program CATHELP has been provided to allow very quick access to this
 document (CATMAN.TXT).

 When you supply keywords to CATHELP, it will scan the manual for headings
 that contain your keywords, and display each of the matching sections.
 You can supply as many keywords as you like.

 For example, the following command would find all topics relating to 
 strings, and messages: CATHELP str msg

 Or this would find details of all definition tokens: CATHELP defin

 Or this would find all details to do with logic: CATHELP logic
 
 Or this command would find the section you are reading now: CATHELP HELP


 CATHELP will look in the current folder, the root folder, the \CAT folder
 and the \CATSRC folder for a CATMAN.TXT file. If it doesn't find the 
 file in any of these folders, it will give up.

     
 If you are running CATHELP from the GEM desktop, then you will have the
 opportunity to type your keywords on the parameters screen.

******************************************************************************
* @CARRIED_WEIGHT(obj) * Logic - return value
************************

 Returns the weight carried by obj. 

******************************************************************************
* CHARACTERS *
**************

 CAT will support any number of characters in your adventure, whether they
 are characters that you can control fully (i.e. BECOME TONY), characters 
 that you can issue commands to (TONY, GIVE THE HAT TO ME), characters that
 are entirely independant of you, or a mixture of the above! This one feature
 sets CAT out from any other adventure development systems.

 An object can be active (@OBJACT) - i.e. alive. 

 An object can be commandable (@OBJCMD) - i.e. the player can get one of 
 his player characters to issue a command to this object. Commandable objects
 are active, by definition.

 An object can be a player object (@OBJPLR) - i.e. the user has full control
 over this object.. it is one of the users entourage in the adventure universe.
 The user can issue 'BECOME object', and from then on all actions will be 
 performed by the selected character. Player objects are active, and commandable
 by definition.

 You can make objects player objects, commandable objects, or active objects
 with the @ADDPLAYER, @ADDCOMMAND, @REVIVE logic tokens. You can remove these
 abilities with @REMOVEPLAYER, @REMOVECOMMAND and @KILL.

 You can find out the current player object with @PLAYER.

 You can find out the commanding object with @CPLAYER - this will be the same
 as @PLAYER, except when one object is commanding another.

 You can find out whether the player is a particular object with @PLAYERIS.

 You can determine whether an object is a player object, commandable or active
 with the @ISPLAYER, @ISCOMMANDABLE and @ISACTIVE logic tokens.

 You can change the current player object, and the commanding player with
 @BECOME.

 You can change the current player object with @CONTROL - this leaves the 
 commanding player unchanged.
 
 When these concepts have sunk in, you will begin to realise that these 
 features can open up whole new dimensions in your adventure games... 
 you could easily have a cast of a dozen characters - all doing their own 
 thing, interacting with each other, or EVEN interacting with you. The 
 possibilities REALLY ARE LIMITLESS! 

 You can easily build logic into your adventure so that Bob will only accept
 commands from Tony, whereas Tony will not accept commands from Bob, but he
 will accept commands from Simon... personality clashes? Pecking order? It's 
 up to you!

******************************************************************************
* @CHECK(C,L,obj) * Logic test
******************* 

  Performs a similar level of checking within CAT logic to that performed by
  verb checking, but this time it is at an object level rather than verb.

  C can be one of: NO_CHECK
                   HERE
                   CARRIED_NOT_WORN
                   WORN
                   AVAIL
                   AVAIL_NOT_WORN
                   CARRIED
                   NOT_CARRIED
                   EXIST

  L can be either @NEED_LIGHT or @NO_LIGHT.

  TRUE will be returned if all the above conditions are passed, otherwise
  FALSE will be returned and an appropriate message printed.

*******************************************************************************
* @CLOSE(obj) * Logic command
***************
 
 Changes the lock type of obj to CLOSED.

******************************************************************************
* @CNOUNIS("text") * Low priority logic test
******************** 

 Returns TRUE if the compound object is a synonym for "text".

 You should avoid this token for the following reasons:
     "text" will not be encrypted.
     @CNOUNNOIS is much faster.

 You should NOT use this token before you have made sure that there is a 
 compound object, with @ISCOMPOUND.

 Only available in low priority processing.

******************************************************************************
* @CNOUNNOIS(obj) * Low priority logic test
******************* 

 Returns TRUE if the compound object number = obj.
 You must use the actual object name, NOT a synonym.

 You should NOT use this token before you have made sure that there is a 
 compound object, with @ISCOMPOUND.

 Only available in low priority processing.

******************************************************************************
* COMPILING *
************* 

 Once your C source has been generated, you will need to copy all the files
 from the \CAT\GENSRC folder into your CSOURCE folder. After this, you can 
 compile your adventure with your favourite C compiler.

 If you are compiling on a PC, you must define PC, and use the large model i.e.
  
   TCC *.c -DPC -ml

 FAILING TO DEFINE PC WHEN COMPILING A PC ADVENTURE WILL RESULT IN FAILURE! 

 Two batch files have been supplied with PC and ST versions of each:
 (ST versions will require a shell program such as Gulam, MSH etc).

 The first batch file (GEN1) generates encrypted C code in CSOURCE, and copies
 all the standard C files from \CAT\GENSRC into CSOURCE.

 The second batch file (GEN2) compiles the C source in CSOURCE, and produces
 the runnable adventure program 'ADVENT' in the current folder.

******************************************************************************
* COMPOUND *
************

 What is a 'compound' command? It's a command that refers to more than one
 object. The following example is NOT a compound command.. It is two 
 non-compound commands 'GET HAT' and 'WEAR HAT'.
 
 GET THE HAT AND WEAR IT.

 The following example IS a compound command, because it refers to more than
 one object:

 TAKE THE HAT FROM THE CHEST.

 We need a mechanism to tell CAT that a verb is a compound verb - so that 
 it does recognise the above example as being compound. A verb can be defined
 as being a 'prepositioner verb' in the verbs definition. I.e. the verb FROM
 has been defined as a prepositioner verb.

 If CAT passes a compound command to low priority logic, the logic test
 @ISCOMPOUND will return TRUE, otherwise it will return FALSE. You should 
 NOT try to refer to the compound verb (@CVERBNOIS) or the compound noun
 (@CNOUNNOIS) until you have established that the command is a compound command
 with the @ISCOMPOUND test.
 
******************************************************************************
* COMPRESSION *
***************

 The GEN program supports switch (-C), which tells it to compress any textual
 words that are more than 4 characters long, into a dictionary. 

 It should be noted that the word 'compression' is notional. Depending on the 
 amount of text in your adventure, you may make the resulting program LARGER
 by compressing! Generally, the more text there is in your adventure, the higher
 the chance that compression will succeed - especially when the same words are
 used many times.

 Using the -C option will cause your generation to take longer, and also your
 finished adventure will run slower. This is because each word of more than
 4 characters has to be 'extracted' from the dictionary before it can be
 displayed/printed. 

******************************************************************************
* @CONFIRM * Logic test
************ 

 Waits for 'Y/y' or 'N/n' to be pressed - determined from the
 contents of messages YES_CHARS and NO_CHARS in ZZRQD.D

 Returns TRUE if 'Y/y' pressed.

*******************************************************************************
* @CONT * Low priority logic command
*********

 Stop processing this command, but keep the command line ready to process the
 next command contained on it. 

 You cannot use @CONT to 'block' room paths (@ROOMPTH) - use @STOP instead. 

*******************************************************************************
* @CONTROL(obj) * Logic command
*****************

 Make obj the current player object, but leave the commanding player as it is.

******************************************************************************
* @COUNT(cnt) * Logic - return value
***************

 Returns the value contained in counter cnt.

******************************************************************************
* COUNTERS * 
************

 CAT provides 500 counters to be used in logic code.
 These are numbered from 0 to 499, and are all initialised to 0 at the start
 of each game - i.e. just before initialisation logic.
 
 Counters 451->499 are reserved for use by the standard files ZZRQD and ZZSTD

 Counter 496 has a special meaning - this is the room where objects 
             should be placed in order to get a score. This defaults to 
             the inventory of the first player character.

 Counter 497 has a special meaning - this is the number of points given
             to the player for things other than object points. You should
             add to this counter if you wish to award extra points.
 
 Counters can be modified with @SETCOUNT, @ADDCOUNT, @SUBCOUNT.
 The value in a counter can be returned with @COUNT.
 
 It is a good idea to refer to counters by object name where appropriate.
 I tend to use counters above 300 for miscellaneous functions, and those 
 below 300 for object related tasks. We can do this because the first object
 is #0, the second is #1 etc. This approach makes a lot more sense, and is 
 far more legible. If we have a counter that says the lamp has run out of
 fuel, it makes sense to SHOW that it is to do with the lamp! E.g.

 @high
 @if @islit(lamp) @do @addcount(lamp,1) @endif
 @if @count(lamp) ge 30 @do @unlight(lamp) @endif

 @low
 @if @verbnois(light) and @nounnois(lamp) and @count(@thisobj) ge 30 @do
    @pmsg(its_out_of_fuel)
    @cont
 @endif

******************************************************************************
* @CPLAYER  * Logic - return value
*************

 Returns the object number of the current player.

******************************************************************************
* @CPLAYERIS(obj) * Logic test
******************* 

 Returns TRUE if the commanding player is obj. If TONY issues the command 
 'BILL, GET THE HAT', then the commanding player will be TONY and the current
 player will be BILL... otherwise the commanding player is the current player.

******************************************************************************
* @CVERBIS("text") * Low priority logic test
********************

 Returns TRUE if the compound verb is a synonym for "text".

 You should avoid this token for the following reasons:
     "text" will not be encrypted.
     @CVERBNOIS is much faster.

 You should NOT use this token before you have made sure that there is a 
 compound verb, with @ISCOMPOUND.

 Only available in low priority processing.

******************************************************************************
* @CVERBNOIS(verb) * Low priority logic test
*******************

 Returns TRUE if the compound verb number = verb.
 You must use the actual verb name, NOT a synonym.

 You should NOT use this token before you have made sure that there is a 
 compound verb, with @ISCOMPOUND.

 Only available in low priority processing.

*******************************************************************************
* DARKNESS *
************

 CAT has a very sophisticated way of automatically checking whether a room 
 is dark or not as follows:

 A room can be defined as being dark via the room definition token @ROOMDRK.

 You can make a dark room light, or a light room dark with @MAKELIGHT,@MAKEDARK
 - this can be viewed as 'switching the light on', or 'opening the window' etc.

 Objects can be defined as being alight with the object definition token
 @OBJLIT, or being lightable with the @OBJLGT object definition token.

 You can light or unlight an object with @LIGHT/@UNLIGHT.

 When you use the @ISDARK logic test, or when CAT checks to see if a room is 
 dark, it does the following:

   1) If the current room is light, then FALSE is returned.

   2) If any object in the current room is alight then FALSE is returned.

   3) If any object in the current room has an in-room, that is neither CLOSED
      nor LOCKED, and any of the objects in this object are alight - then
      FALSE will be returned.

   4) For each of the objects discovered in step 3) above, perform step 3).
      (This is recursive code).

   5) If after checking all possible objects, there are no lit objects
      THEN TRUE will be returned (it is dark).

 The above code effectively means that Bob can be in a dark room. There are
 no immediate sources of light... but Harry is in the same room. Harry is 
 carrying an open chest, which contains an open box, which contains a lit 
 lamp - therefore, the light will emanate to Bob and @ISDARK will return FALSE!
 
*******************************************************************************
* @DO * Logic control
*******

 Signifies the start of a CAT 'Logic command' group.

*******************************************************************************
* @DRINK(obj) * Logic command
***************

 Move obj to the NOWHERE room.

*******************************************************************************
* @DROP(obj) * Logic command
**************

 Move obj to the current players room.

*******************************************************************************
* @EAT(obj) * Logic command
*************

 Move obj to the NOWHERE room.

*******************************************************************************
* EDITOR *
**********

 CAT adventures provide a command line editor, for the user. The following keys
 can be pressed by the users to enter their commands quickly:

     7  8  9
      \ | /     The numeric keypad can be used for directional movement.
                (i.e. 8-North, 3-Southeast etc)
     4- 5 -6 

      / | \     additionally 5-Up and 0-Down.
     1  2  3

      
     [          Repeat last command line

     ]          Delete entire command line

     *          Delete one word from command line

     Ctrl(A)    Repeat last verb
          B     Repeat last noun
          C     Repeat last compound verb
          D     Repeat last compound noun
          E     Examine
          F     Drop
          G     Get
          I     Inventory
          J     Jump
          K     Kill
          L     Look
          N     No
          O     Open
          P     Close
          Q     Quit
          R     Restore
          S     Save
          T     Lock
          U     Unlock
          V     Vocabulary
          W     Whoami
          X     Exits
          Y     Yes
          Z     Copyright line

*******************************************************************************
* @ELSE * Logic control
*********

 Signifies alternative processing for an @IF 'logic control' group.

*******************************************************************************
* ENCRYPTION *
**************

 When you generate your C source from your adventure definition, you can tell
 CAT to encrypt the generated C source code. This is not a sophisticated 
 system, but it ensures that the casual hacker can't read all the secret
 messages etc.

 You can tell CAT to encrypt code by using the '-E' option on the GEN program.

 All text strings will be encrypted, except those in CAT logic.

 When the adventure starts up, it will take a couple of seconds to decrypt
 all the text in the adventure - the title screen will remain on display.

*******************************************************************************
* @ENDCHAR('c') * Logic command
*****************

 The next piece of text that is printed will have character 'c' appended - 
 therefore the following would print 'Hello there!'

 @MSG 	 HELLO
 @MSGTXT Hello there
 @ENDMSG

 @ENDCHAR('!')
 @PMSG(HELLO)

*******************************************************************************
* @ENDGAME * Logic command
************

 Print the score, and turns taken - then end the game.

*******************************************************************************
* @ENDIF * Logic control
**********

 Signifies the end of an @IF/@ELSE 'logic control' group.

 Each @ENDIF must match up to an @IF.

*******************************************************************************
* @ENDMSG * Message definition
***********

 Signifies the end of a message definition.

*******************************************************************************
* @ENDOBJ * Object definition
***********
 
 Signifies the end of an object definition.

*******************************************************************************
* @ENDSTR * String definition
***********

 Signifies the end of a string definition.

*******************************************************************************
* @ENDVERB * Verb definition
************

 Signifies the end of a verb definition.

*******************************************************************************
* @ENTER(obj) * Logic command
***************

 Move the current player to the room pointed to by obj - i.e. the room pointed
 to by @OBJDOOR or @OBJPORTAL. The room is not described on entry.

*******************************************************************************
* @FIRST * Logic control
**********

 Signifies that any following logic is FIRST processing, i.e. it will be 
 executed ONCE as soon as the adventure is loaded - before the title screen
 AND before any decryption has taken place.

******************************************************************************
* @FIRSTOB(room) * Logic - return value
******************

 Returns the number of the first object in room, or -1 if there are no
 objects in room.

*******************************************************************************
* @FVERB("text") * Low priority logic command
******************

 Forces the verb to be "text". For example, in ZZSTD, if the user types 
 'LOOK APPLE' - this is forced to 'EXAMINE APPLE'. In this manner, we only
 need to provide one set of validation logic....

 @IF @VERBNOIS(LOOK) AND @THISOBJ NE -1 @DO @FVERB("EXAMINE") @ENDIF

******************************************************************************
* GEN *
*******

 The main program (GEN.TTP on an ST, or GEN.EXE on a PC), processes your
 adventure definition, and generates C code for your adventure program. 

 When GEN starts up, it looks in the current folder for a file called 
 'GENLIST'. The GENLIST file should contain the names of each definition file
 that is to be used to generate the adventure source. These definition files 
 can have any names, but it would be advisable to use the standard extendor '.d'
 e.g. - file1.d, file2.d file3.d. You can use any number of definition files
 to create your adventure.

 Each line in the GENLIST file can contain a simple file name, or a file 
 with a pathname, and optionally a drive - so a typical GENLIST file may be:

   OBJECTS.D
   ROOMS.D
   MESSAGES.D
   LOGIC.D
   A:\MYSTDS.D
   \CAT\STD\ZZRQD.D 
   \CAT\STD\ZZSTD.D  
                        
 The next thing GEN will do is look for a sub-folder from the current folder,
 called CSOURCE. This is where the generated C code will be placed.  

 If all is okay, GEN will begin it's work. As it works, GEN will display any
 potential errors it encounters on the screen, and these will also be written
 to the file 'GENOUT.TXT'.

 The GEN program has the following command line options:

   -Spath   - use this to specify the source folder. This option is useful if
              you are using GEN via the GEM desktop on the ST. The option
              forces GEN to change directory to the selected folder - i.e.
              the folder where your GENLIST lives. The -S option does not
              allow a drive to be specified.

   -L       - This tells GEN to list the definition source as it processes it.

   -V       - This tells GEN to give a verbose list of all possible errors 
              it discovers. By default, GEN only reports the more rare and
              possibly hazardous errors.

   -E       - This tells GEN to encrypt the code it produces, safe from 
              prying eyes. You should always use this option when producing
              a finished copy of your adventure.

   -C       - This tells GEN to compress the text in your adventure.
              WARNING: compressing adventures with small amounts of text may
                       result in LARGER programs being generated. Compression
                       will be most successful in games with a lot of text.

   -I       - This tells GEN to print the names of all the items that are
              defined. By default, GEN only reports those items that are
              defined but are not directly referred to.

   -F       - This tells GEN to do full logic checks. i.e. it makes sure that
              low priority logic is only used in low priority logic, that 
              logic tests are not used in commands, that logic tokens are
              recognised tokens, etc. This switch is additional to -V.
   
   -R       - Perform a report only run. Do not write any files. This is FAST,
              and allows you to easily check the syntax of your source.

   -Dpath   - Specify the destination path (override default of CSOURCE).
              This can include a drivespec. The path should be direct i.e.
              -DF:\output or relative to the folder to where the GENLIST file
              lives i.e. -Dtest\output. This option is useful if you want to
              direct the output to a ramdrive - much faster!

   -Apath   - Autocopy GENSRC files to destination folder. By default, the 
              GENSRC files will be copied from \CAT\GENSRC, but you can 
              optionally specify the folder where GEN can find GENSRC files.
              The folder can include a drivespec.
 
 GEN -E -I -F
   would look for a GENLIST in the current folder, encrypt all output, and
   produce a list of all the items that were defined. Full logic checking will
   be performed.

 GEN -S\ADVENT -V -L
   would look for a GENLIST in the folder \ADVENT. It would list the definition
   files as it processed them, and give a verbose list of ALL errors. It would
   not encrypt the generated C source. Only those items that are defined but
   not directly referred to will be listed. Full logic checking will not be 
   performed.
 
 GEN -R
   would look for a GENLIST in the current folder, and perform a report run.

 GEN -A -E
   would look for a GENLIST in the current folder, encrypt all output and
   automatically copy the GENSRC files from \CAT\GENSRC.

 GEN -AA:\CAT\GENSRC -S\AWE -Df:\ 
   would look for a GENLIST in \AWE. Output would be created in F:\ - GENSRC
   files would be automatically copied to F:\ from A:\CAT\GENSRC.


 Additionally, GEN switches can be specified in your GENLIST file. Any switches 
 included in the GENLIST file will override conflicting switches from the
 command line.

     For example, the following GENLIST will automatically copy GENSRC from
     \CAT\GENSRC, and output will be encrypted.

     -e
     -a 
     \cattutr5\first.d
     \cattutr1\tutor1.d
     \cattutr2\tutor2.d
     \cattutr3\tutor3.d
     \cattutr4\tutor4.d
     \cattutr5\tutor5.d
     \cat\std\zzstd.d
     \cat\std\zzrqd.d
     \cattutr5\last.d

*******************************************************************************
* @GET(obj) * Logic command
*************

 Move obj to the current players in-room (@OBJINRM).

*******************************************************************************
* @GETSTR(str,size,sep) * Logic command
*************************

 Waits for the user to enter a string, and stores it in str.
 size is a value that defines the maximum number of characters to allow.
 sep can be 1-allow separators, or 0-do not allow separators i.e.

   @Rem get up to 50 characters from the user, allowing separators.

   @GETSTR(mystr,50,1)

 Always be sure that you to do not write past the end of any string.
 
*******************************************************************************
* @GOTO(room) * Logic command
***************

 Move the current player to room. The room will be described.

*******************************************************************************
* @HIDE(obj) * Logic command
**************

 Hide obj - hidden objects will not be shown in inventory lists, room
            descriptions etc. Hidden objects are not picked up by ALL variants
            (e.g. 'GET ALL').

*******************************************************************************
* @HIGH * Logic control
*********

 Signifies that any following logic is HIGH priority processing.

*******************************************************************************
* @IF * Logic control
*******

 Signifies the start of an @IF 'logic control' group.

 Each @IF must match up to an @ENDIF.

*******************************************************************************
* @INIT * Logic control
*********

 Signifies that any following logic is INITialisation processing.

*******************************************************************************
* @INVENTORY * Logic command
**************

 Prints a list of the current players inventory.

******************************************************************************
* @ISACTIVE(obj) * Logic test
******************

 Returns TRUE if obj is active (i.e. alive)

******************************************************************************
* @ISAVAIL(obj) * Logic test
*****************

 Returns TRUE if obj is available (i.e. @ISHERE(obj) or @ISCARRIED(obj))

******************************************************************************
* @ISBOX(obj) * Logic test
***************

 Returns TRUE if obj has an in-room, but is not active.

******************************************************************************
* @ISCARRIED(obj) * Logic test
*******************

 Returns TRUE if obj is being carried by the current player.

******************************************************************************
* @ISCARRIEDANY(obj) * Logic test
**********************

 Returns TRUE if obj is carried by any object. 

******************************************************************************
* @ISCARRIEDBY(obja,objb) * Logic test
***************************

 Returns TRUE if obja is carried by objb. 

 This is identical to @ISIN.

******************************************************************************
* @ISCLOSED(obj) * Logic test
******************

 Returns TRUE if obj is closed.

******************************************************************************
* @ISCOMMANDABLE(obj) * Logic test
***********************

 Returns TRUE if obj is commandable, AND active.
 (i.e. can user type 'obj, GET HAT')

******************************************************************************
* @ISCOMPOUND * Low priority logic test
***************

 Returns TRUE if command is compound i.e. 'TAKE x FROM y'.

 Only available in low priority processing.

******************************************************************************
* @ISDARK * Logic test
***********

 Returns TRUE if it is dark in the current players current room, and there
 are no sources of light available.

******************************************************************************
* @ISDRINKABLE(obj) * Logic test
*********************

 Returns TRUE if obj is drinkable.

******************************************************************************
* @ISEDIBLE(obj) * Logic test
******************

 Returns TRUE if obj is edible.

******************************************************************************
* @ISEXIT(obj) * Logic test
****************

 Returns TRUE if obj is an exit
 (i.e. obj has either @OBJDOOR or @OBJPORTAL defined)

******************************************************************************
* @ISHERE(obj) * Logic test
****************

 Returns TRUE if obj is in the same room as the current player.

******************************************************************************
* @ISHIDDEN(obj) * Logic test
******************

 Returns TRUE if obj is hidden.

******************************************************************************
* @ISIN(obja,objb) * Logic test
********************

 Returns TRUE if obja is inside objb. I.e. is obja in the @OBJINRM of objb?

 This logic test is identical to @ISCARRIEDBY.
                                 
******************************************************************************
* @ISLIGHT(obj) * Logic test
*****************

 Returns TRUE if obj is a light source.

******************************************************************************
* @ISLIT(obj) * Logic test
***************

 Returns TRUE if obj is alight.

******************************************************************************
* @ISLOCKED(obj) * Logic test
******************

 Returns TRUE if obj is locked.

******************************************************************************
* @ISMOVABLE(obj) * Logic test
*******************

 Returns TRUE if obj is movable.

******************************************************************************
* @ISOPEN(obj) * Logic test
****************

 Returns TRUE if obj is open.

******************************************************************************
* @ISPATH(verb) * Logic test
*****************

 Returns TRUE if verb is a valid path.
 (i.e. if verb has been defined as a @ROOMPTH from this room)

******************************************************************************
* @ISPLAYER(obj) * Logic test
******************

 Returns TRUE if obj is a player object, AND active.
 (i.e. can user type 'BECOME obj')

******************************************************************************
* @ISREADABLE(obj) * Logic test
********************

 Returns TRUE if obj is readable.

******************************************************************************
* @ISWEARABLE(obj) * Logic test
********************

 Returns TRUE if obj is wearable.

******************************************************************************
* @ISWITH(obja,objb) * Logic test
**********************

 Returns TRUE if obja is in the same room as objb.

******************************************************************************
* @ISWORN(obj) * Logic test
****************

 Returns TRUE if obj is worn.

******************************************************************************
* @ISWORNANY(obj) * Logic test
*******************

 Returns TRUE if obj is worn by any object.

******************************************************************************
* @ISWORNBY(obja,objb) * Logic test
************************

 Returns TRUE if obja is worn by objb.

******************************************************************************
* ITEM LIST *
*************

 When the GEN program runs, it builds a list of all the defined items.
 (verbs, objects, messages, rooms).
 
 By default, GEN will print a list of all those items that are not referred
 to directly in definitions, or logic. If you use the -I switch on the GEN
 program, it will list ALL items, and signify any that are not directly
 referred to. 

 In the item list, object names will be preceded with 'O_', verbs with 'V_',
 messages with 'M_' and rooms with 'R_'. This is the way CAT holds the names
 internally.

 It is quite normal for objects to not be referred to. Objects will remain 
 unreferenced unless your logic refers to the object specifically... since
 CAT provides so much processing automatically, it is normally the case
 that there are more objects that you do NOT need to refer to!

 Messages will all normally be referred to, except when you have referred to
 them indirectly i.e. @PMSG(@COUNT(305)). You should know which messages you
 have referred to indirectly - any that remain are not required and can be 
 removed!

 If you see any rooms that are not referred to - this is a cause for concern.
 If a room isn't referred to, it implies that the room can never be visited -
 which in turn implies that you do not need the room! The over-ruling and
 rare exception to this is when a room is only referred to indirectly.
 i.e. @GOTO(@COUNT(343))

 The GEN program will also give a list of all those items that HAVE been 
 referred to, but that have not been defined. If you have ANY items in this 
 list, your adventure will not compile!

*******************************************************************************
* @KILL(obj) * Logic command
**************

 Makes obj inactive - i.e. not alive.
       (this will also make @ISPLAYER(obj) and @ISCOMMANDABLE(obj) fail)

*******************************************************************************
* LANGUAGES * converting CAT adventures to a foreign language!
*************

 It is a very easy procedure to fully convert CAT adventures to foreign
 languages. Perform the following steps:

 1) First of all, remember - DO NOT CHANGE ANY NAMES...
    (@OBJ, @ROOM, @MSG, @VERB, @STR).

 2) Translate all text in your definition files, and in ZZRQD, ZZSTD.
    (@MSGTXT, @OBJSHT, @OBJLNG, @ROOMSHT, @ROOMLNG, @STRTXT). Note: The messages
    YES_CHARS and NO_CHARS in ZZRQD determine the keypresses to be checked
    for when @CONFIRM is used (standard is 'Yy' for Yes and 'Nn' for No).

 3) For each object to be translated, leave the original name the same 
    (i.e. @OBJ) - add synonyms for the foreign versions - you can remove
    the English synonyms - BUT only if you know you haven't used these
    synonyms in @NOUNIS or @CNOUNIS! ZZSTD/ZZRQD do not use @NOUNIS/@CNOUNIS.

 4) For each verb to be translated, leave the original name the same 
    (i.e. @VERB) - add synonyms for the foreign versions - you can remove
    the English synonyms - BUT only if you know you haven't used these 
    synonyms in @VERBIS or @CVERBIS! ZZSTD/ZZRQD do not use @VERBIS/@CVERBIS.

 5) PLEASE send me a copy of your translated ZZSTD/ZZRQD files, so that
    I can send a copy to all registered users of CAT.

 6) Regenerate your adventure, and you're done!

*******************************************************************************
* @LAST * Logic control
*********

 Signifies that any following logic is LAST processing, i.e. it will be
 executed ONCE just before the adventure program ends.

******************************************************************************
* @LASTOB(room) * Logic - return value
*****************

 Returns the number of the last object in room, or -1 if there are no
 objects in room.

*******************************************************************************
* @LC * Logic control
*******

 This token can be used to ensure that each @IF has a matching @ENDIF, and
 that each @WHILE has a matching @WEND. The @LC token should only be used 
 at points where you think there are no @IF/@WHILEs remaining open.

*******************************************************************************
* @LF * Logic command
*******

 Print a linefeed character (same as @NEWLINE).

*******************************************************************************
* LIGHT *
*********

 See darkness.
 
*******************************************************************************
* @LIGHT(obj) * Logic command
***************

 Make obj a light source, and lit.

*******************************************************************************
* LIMITATIONS *
***************

 CAT has the following limitiations:
 -----------------------------------

 Maximum length of text strings                 = 255 characters
 (possibly higher dependant on C compiler)
 
 Maximum number of messages                     = 32767

 Maximum number of objects                      = 32767

 Maximum number of rooms                        = 32766

 Maximum number of verbs                        = 32767

 Maximum number of active objects               = 32767

 Maximum number of commandable objects          = 32767

 Maximum number of player objects               = 32767

 Maximum number of strings                      = 100

 
 Note: It should be obvious from the above that the CAT system itself is
       very flexible and will allow potentially HUGE adventures to be created..
       the only limiting factors that need be considered are any specific
       contraints on program size from your C compiler, and also the amount
       of memory available.

*******************************************************************************
* @LOAD * Logic command
*********

 Ask for an 8 character filename, and load saved game. (extendor is .SAV)

*******************************************************************************
* @LOCK(obj) * Logic command
**************

 Change the lock type of obj to LOCKED.

*******************************************************************************
* @LOCKTYPE(obj) * Logic - return value
******************

 Returns the lock type of obj. I.e. LOCKED, CLOSED, OPEN, NO_LOCK.

*******************************************************************************
* LOGIC *
*********

 CAT supports five distinct flavours of logic processing. These are
 first time round logic, initialisation logic, low priority logic, high
 priority logic and last time round logic. These modes can be switched between
 using the @FIRST, @INIT, @LOW, @HIGH and @LAST tokens.

 First time round logic is executed ONCE PER LOAD OF THE PROGRAM - before the
 title is printed AND before decryption takes place. This can be used for 
 system level initialisation.

 Initialisation logic is executed ONCE PER GAME before the first player command.
 This can be used to initialise the game status, or display a welcome screen.

 Low priority logic is executed ONCE FOR EACH VALID COMMAND that it stripped
 from the command line that the user entered. Only low priority logic has
 the ability to interrogate the commands that the user enters.

 High priority logic is executed after every turn, regardless of whether 
 successful or not. This can be used to code events that are not directly
 related to the players command.

 Last time round logic is executed ONCE PER LOAD OF THE PROGRAM, just before
 the program ends and returns to the calling program, or the operating system.
 This can be used to restore the original state of the system.

 You can alter the flow of CAT logic by using logic control tokens and 
 logic comparison tokens.

*******************************************************************************
* LOGIC COMMANDS *
******************

 CAT logic commands do whatever they are told to do. No checking is performed
 - they presume that any checking that was required has already been made.

 The following tokens can be used to instruct CAT logic to perform a task:

   Available in any logic mode
   ---------------------------
   @ADDCOMMAND(obj)
   @ADDPLAYER(obj)
   @ADDSTRENGTH(obj,val)
   @ADDVALUE(obj,val)
   @ADDWEIGHT(obj,val)
   @BECOME(obj)
   @BRIEF
   @CLOSE(obj)
   @CONTROL(obj)
   @DRINK(obj)
   @DROP(obj)
   @EAT(obj)
   @ENDCHAR('c')
   @ENDGAME
   @ENTER(obj)
   @GET(obj)
   @GOTO(room)
   @HIDE(obj)
   @INVENTORY
   @KILL(obj)
   @LF
   @LIGHT(obj)
   @LOAD
   @LOCK(obj)
   @LOOK
   @MAKEDARK(room)
   @MAKELIGHT(room)
   @NEWLINE
   @OPEN(obj)
   @PAUSE(sec)
   @PCONTENTS(obj)
   @PEXITS
   @PMSG(msg)
   @POBJL(obj)
   @POBJS(obj)
   @PROOML(room)
   @PROOMS(room)
   @PNUM(val)
   @RAMLOAD
   @RAMSAVE
   @READ(obj)
   @REMOVE(obj)
   @REMOVECOMMAND(obj)
   @REMOVEPLAYER(obj)
   @REVIVE(obj)
   @SAVE
   @SCRIPT
   @SETSTRENGTH(obj,val)
   @SETVALUE(obj,val)
   @SETWEIGHT(obj,val)
   @SUBSTRENGTH(obj,val)
   @SUBVALUE(obj,val)
   @SUBWEIGHT(obj,val)
   @SWAP(obja,objb)
   @UNHIDE(obj)
   @UNLIGHT(obj)
   @UNLOCK(obj)
   @UNSCRIPT
   @VERBOSE
   @VOCAB
   @WAITKEY
   @WEAR(obj)
   @WHOAMI

   Low priority logic only
   -----------------------
   @CONT
   @FVERB("text")
   @STOP

******************************************************************************
* LOGIC COMPARISONS *
********************* 

 The following can be used to compare values returned by CAT logic, in 
 conjunction with logic control tokens:

 	Equals                          EQ              ==
     	Does not equal                  NE              !=
	Is less than                    LT              <
 	Is less than or equal to        LE              <=
	Is greater than                 GT              >
	Is greater than or equal to     GE              >=
	Or                              OR              ||
	And                             AND             &&
	Not				NOT             !

 Whenever you use NOT, you should protect the condition with ( and ).
 i.e. @IF (NOT @PLAYERIS(BOB)) @DO

*******************************************************************************
* LOGIC CONTROL *
*****************

 The following tokens can be used in conjuction with logic comparison tokens to 
 affect the flow of CAT logic.

   @FIRST
   @INIT
   @LOW
   @HIGH
   @LAST

   @IF
   @ELSE
   @ENDIF
   @WHILE
   @WEND
   @DO
   @LC

*******************************************************************************
* LOGIC RETURN VALUES *
***********************

 The following tokens can be used to return values to CAT logic:

   Available in any logic mode
   ---------------------------
   @CARRIED_WEIGHT(obj)
   @COUNT(cnt)
   @CPLAYER 
   @FIRSTOB(room)
   @LASTOB(room)
   @MSGNO(msg)
   @OBJINRM(obj)
   @OBJKEY(obj)
   @OBJLCK(obj)
   @OBJNO(obj)
   @OBJRM(obj)
   @PLAYER
   @POINTS(obj)
   @RANDOM(x)
   @ROOMNO(room)
   @SCORE 
   @SIZE(obj)
   @STRENGTH(obj)
   @THISROOM
   @TURNS 
   @VALUE(obj)
   @VERBPATH(verb)
   @WEIGHT(obj)
   
   Low priority logic only
   -----------------------
   @THISCOBJ 
   @THISCVERB
   @THISOBJ 
   @THISVERB

*******************************************************************************
* LOGIC TESTS *
***************

 The following tokens can be used to perform TRUE/FALSE tests in CAT logic.

   Available in any logic mode
   ---------------------------
   @CHECK(C,L,obj)
   @CONFIRM
   @CPLAYERIS(obj)
   @ISACTIVE(obj)
   @ISAVAIL(obj)
   @ISBOX(obj)
   @ISCARRIED(obj)
   @ISCARRIEDANY(obj)
   @ISCARRIEDBY(obja,objb)
   @ISCLOSED(obj)
   @ISCOMMANDABLE(obj)
   @ISDARK
   @ISDRINKABLE(obj)
   @ISEDIBLE(obj)
   @ISEXIT(obj)
   @ISHERE(obj)
   @ISHIDDEN(obj)
   @ISIN(obja,objb)
   @ISLIGHT(obj)
   @ISLIT(obj)
   @ISLOCKED(obj)
   @ISMOVABLE(obj)
   @ISOPEN(obj)
   @ISPATH(verb)
   @ISPLAYER(obj)
   @ISREADABLE(obj)
   @ISWEARABLE(obj)
   @ISWITH(obja,objb)
   @ISWORN(obj)
   @ISWORNANY(obj)
   @ISWORNBY(obja,objb)
   @OBJHASL(obj)
   @OBJROOMIS(room,obj)
   @PLAYERIS(obj)
   @ROOMIS(room)
   
   Low priority logic only
   -----------------------
   @CNOUNIS("text")
   @CNOUNNOIS(obj)
   @CVERBIS("text")
   @CVERBNOIS(verb)
   @ISCOMPOUND
   @NOUNIS("text")
   @NOUNNOIS(obj)
   @VERBIS("text")
   @VERBNOIS(verb)

*******************************************************************************
* @LOOK * Logic command
*********

 Print a long room description for the current players room.
 List any non-hidden objects.

*******************************************************************************
* @LOW * Logic control
********

 Signifies that any following logic is LOW priority processing.

*******************************************************************************
* MACROS * Macros within text
**********

@rem As well as 'LF', other macros can be included in any piece of text - these
     will be expanded whenever the text is displayed as follows:

     $1, $2, $3, $4 etc. - replaced with value in 1st, 2nd, 3rd, 4th string etc.

     #1, #2, #3, #4 etc. - replaced with value of 1st, 2nd, 3rd, 4th counter etc

     $A                  - replaced with the actor, from command line.

     $V                  - replaced with verb, from command line.

     $VC                 - replaced with compound verb, from command line.

     $N                  - replaced with noun, from command line.

     $NC                 - replaced with compound noun, from command line.

@rem For example, the following would print:

     BOB: "I have no time to PUT KEY IN BED" ...

     (If the user issued the command 'bob, put the key in the bed')

     @str    tmp_str		@Rem String number 11 (1-10 already defined)
     @strtxt I have no
     @endstr

     @msg    tmp_msg
     @msgtxt $A: "$11 time to $V $N $VC $NC" ...
     @endmsg

     @low
        @if @playeris(bob) @do 
           @pmsg(tmp_msg)
        @endif

*******************************************************************************
* @MAKEDARK(room) * Logic command
*******************

 Make room dark.

*******************************************************************************
* @MAKELIGHT(room) * Logic command
********************

 Make room light.

*******************************************************************************
* MESSAGE (msg) DEFINITION *
****************************

 The following tokens can be used to define messages:

   @MSG name
   @MSGTXT text
   @ENDMSG
 
*******************************************************************************
* @MSG name * Message (msg) definition
*************

 Starts the definition of a message, where 'name' is the name of the message.
 See NAMES for more details.

******************************************************************************
* @MSGNO(msg) * Logic - return value
***************

 Returns the message number of msg.

*******************************************************************************
* @MSGTOSTR(msg,str) * Logic command
**********************

 Copy msg into str.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @MSGTOSTR(msg,@STRNO(str))

*******************************************************************************
* @MSGTXT text * Message (msg) definition
****************

 Describes the text behind the message that is currently being defined.
 
 You can include 'LF' in messages - this will print a linefeed character.
 See MACROS for additional information.

*******************************************************************************
* NAMES *
*********

 CAT allows all references to objects, verbs, rooms and messages to be made
 by NAME - rather than number. This means you can refer to the master_bedroom
 rather than room number 56, or the You_have_died message rather than message
 number 264. This feature is a tremendous advantage when developing, or indeed
 when viewing another authors CAT source code.

 All names allow each of the letters of the alphabet (A through Z). No 
 differentiation is made between upper and lower case. The underbar character
 (_) is allowed in names, and it has a different meaning for each type of item:

 Rooms
 -----
 No special meaning.

 Messages
 --------
 No special meaning.

 Verbs
 -----
 Used to define two word verbs, for example 'PUT ON' for 'WEAR' would 
 be given the name PUT_ON. You can only use ONE underbar in a verb name. The
 user doesn't know that the underbar is there, and cannot enter one - he just
 knows that he wants to 'PUT ON' something.

 Objects
 -------
 Used to QUALIFY objects, for example a 'RED KEY' would be called RED_KEY.
 You can only use ONE underbar in an object name. The user doesn't know that
 the underbar is there, and cannot enter one - he just knows he wants to refer
 to a 'RED KEY'. See QUALIFIERS for more details.

*******************************************************************************
* @NEWLINE * Logic command
************

 Print a linefeed character (same as @LF).

******************************************************************************
* @NOUNIS("text") * Low priority logic test
******************* 
 
 Returns TRUE if the object is a synonym for "text".

 You should avoid this token for the following reasons:
     "text" will not be encrypted.
     @NOUNNOIS is much faster.

 Only available in low priority processing.

******************************************************************************
* @NOUNNOIS(obj) * Low priority logic test
******************

 Returns TRUE if the object number = obj.
 You must use the actual verb name, NOT a synonym.

 Only available in low priority processing.

*******************************************************************************
* NOUNS *
*********

 Within CAT, a noun is just a users reference to an object. 

*******************************************************************************
* @NUMTOSTR(val,str) * Logic command
**********************

 Convert val to a string, and store it in str.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @NUMTOSTR(123,@STRNO(str))

*******************************************************************************
* @OBJ name * Object definition
*************

 Starts the definition of an object, where 'name' is the name of the object.
 See NAMES for more details.

*******************************************************************************
* @OBJACT * Object definition
***********

 Sets the object to ACTIVE, i.e. 'alive'. By default, the player can give 
 things to active objects. An object will automatically default to being 
 active if it is defined with either @OBJPLR or @OBJCMD. The default is 
 not-active.

 All active objects should have an in-room defined (their inventory).

*******************************************************************************
* @OBJCMD * Object definition
***********

 Sets the object to commandable. If an object is commandable, the user can
 command the object with 'object, GET HAT'. If @OBJCMD is selected, @OBJACT
 is automatically selected. The default is not-commandable.

 All commandable objects should have an in-room defined (their inventory).

*******************************************************************************
* @OBJDOOR roomname1,roomname2 * Object definition
********************************

 Makes the object a door between the rooms roomname1 and roomname2. By default,
 objects are not doors.

 CAT automatically sorts out which room a door should be in - because a door
 is effectively in TWO rooms, it has to be moved to where it is currently
 needed. Whenever a player enters a room, CAT checks to see if there should
 be any doors here. If an object is a door, you needn't bother with @OBJROOM.

*******************************************************************************
* @OBJDRINK val * Object definition
*****************

 Makes the object drinkable, where the players strength will be affected by
 val if he does drink it. The default is non-drinkable.

*******************************************************************************
* @OBJEAT val * Object definition
***************

 Makes the object edible, where the players strength will be affected by val
 if he does eat it. The default is non-edible.

******************************************************************************
* OBJECT DEFINITION *
*********************

 The following tokens are available to define objects:

   @OBJ name
   @OBJACT
   @OBJCMD
   @OBJDOOR roomname1,roomname2
   @OBJDRINK val
   @OBJEAT val
   @OBJHIDE
   @OBJINRM roomname
   @OBJKEY objname
   @OBJLCK open/closed/locked
   @OBJLGT
   @OBJLIT
   @OBJLNG text
   @OBJNGT
   @OBJPLR
   @OBJPNT val
   @OBJPORTAL roomname
   @OBJREAD msgname
   @OBJROOM roomname
   @OBJSHT text
   @OBJSTR val
   @OBJSYN synname..
   @OBJVAL val
   @OBJWEAR
   @OBJWGT val
   @OBJWORN
   @ENDOBJ

******************************************************************************
* @OBJHASL(obj) * Logic test
*****************

 Returns TRUE if obj has any long text defined, as defined by @OBJLNG.

*******************************************************************************
* @OBJHIDE * Object definition
************

 Makes the object hidden. Hidden objects are not displayed in inventory lists,
 or room descriptions, they will not be picked up by 'ALL' variants, BUT the
 player can still interact with them in the same way as any other object - 
 if he realises they are there! The default is not-hidden.

*******************************************************************************
* @OBJINRM roomname * Object definition
*********************

 Defines the objects in-room - the room in which objects that are carried by
 this object will be placed. The default @OBJINRM for an object is NOWHERE - 
 this means that the object does not have an in-room.

 If an object doesn't have an @OBJINRM, then it cannot hold/contain anything.

******************************************************************************
* @OBJINRM(obj) * Logic - return value
*****************

 Returns the in-room for obj, or NOWHERE if the object has no in-room.

*******************************************************************************
* @OBJKEY objname * Object definition
*******************

 Defines the object that is required to lock/unlock this object.
 
 @OBJKEY has no effect if the object has no @OBJLCK defined.

 The default for @OBJKEY is NO_KEY - i.e. object cannot be locked/unlocked.

******************************************************************************
* @OBJKEY(obj) * Logic - return value
****************

 Returns the number of the object required to lock/unlock obj, or NO_KEY
 if obj does not have a lock.

*******************************************************************************
* @OBJLCK open/closed/locked * Object definition
******************************

 Defines the object lock type of the object (OPEN/CLOSED/LOCKED/NO_LOCK).
 The default of NO_LOCK means that the object cannot be locked/closed/opened.

 Just because an object doesn't have a lock type, that DOESN'T mean that the
 player can't enter it/put things in it - if OBJDOOR/OBJPORTAL/OBJINRM are 
 defined - for example a doorway, or a pond.

******************************************************************************
* @OBJLCK(obj) * Logic - return value
****************

 Returns the lock type of obj. Could be any of: LOCKED, CLOSED, OPEN, NO_LOCK.
 NO_LOCK means that the object cannot be locked/unlocked/open/closed.

*******************************************************************************
* @OBJLGT * Object definition
***********

 Defines the object as being a lightsource, but not currently lit.
 The default is non-lightsource.

*******************************************************************************
* @OBJLIT * Object definition
***********

 Defines the object as being a lightsource, AND being lit.
 The default is not-lit.

*******************************************************************************
* @OBJLNG text * Object definition
****************

 Describes the long text for the object.
 Blank text will be added if this is omitted. When the object is examined,
 the user will be told 'You don't see anything unusual'.

 You can include 'LF' in object text - this will print a linefeed character.
 See MACROS for additional information.

*******************************************************************************
* @OBJNGT * Object definition
***********

 Signifies that the object cannot be taken/dropped/given. This is a derivation
 of @OBJWGT. It effectively gives the object a weight of 32767 - which is a 
 special value and should be avoided!

******************************************************************************
* @OBJNO(obj) * Logic - return value
***************

 Returns the object number of obj.

*******************************************************************************
* @OBJPLR * Object definition
***********

 Defines the object as being a player object i.e. user can 'BECOME object'.
 If @OBJPLR is selected, @OBJCMD and @OBJACT will automatically be selected.
 
 All player objects should have an in-room defined (their inventory).

*******************************************************************************
* @OBJPNT val * Object definition
***************

 Defines the number of points that the object is worth. The default is 0.

*******************************************************************************
* @OBJPORTAL roomname * Object definition
***********************

 Describes the room that the current player will be moved to if he ENTERs this
 object. By default, the object is not a portal.

*******************************************************************************
* @OBJREAD msgname * Object definition
********************

 Makes this object readable. Message msgname will be displayed if the player
 reads this object. By default, objects are not readable.

******************************************************************************
* @OBJRM(obj) * Logic - return value
***************

 Returns the room number that obj is currently in.

*******************************************************************************
* @OBJROOM roomname * Object definition
*********************

 Defines the starting room for the object. The default starting room for an 
 object is the NOWHERE room.

******************************************************************************
* @OBJROOMIS(room,obj) * Logic test
************************

 Returns TRUE if obj is in room.

*******************************************************************************
* @OBJSHT text * Object definition
****************

 Describes the short text for the object. This should always be given, if 
 the object can ever be seen.

 You can include 'LF' in object text - this will print a linefeed character.
 See MACROS for additional information.

*******************************************************************************
* @OBJSTR val * Object definition
***************

 Defines the strength of the object. The default is 0. You should be careful
 to define an @OBJSTR for any object that has an in-room (players,boxes etc) -
 or they will not be able to carry anything!

*******************************************************************************
* @OBJSYN synname.. * Object definition
*********************

 Describes synonyms for the object. An object may have many synonyms. The 
 default is that an object has no synonyms. Object synonyms are like object 
 names - see NAMES for further details.

*******************************************************************************
* @OBJVAL val * Object definition
***************

 Defines the value of this object, the default being 0.

*******************************************************************************
* @OBJWEAR * Object definition
************

 Makes this object wearable, but not worn. The default is not wearable.

*******************************************************************************
* @OBJWGT val * Object definition
***************

 Defines the weight of this object. The default weight is 0. 

*******************************************************************************
* @OBJWORN * Object definition
************

 Makes this object wearable, AND worn. The default is not worn.

*******************************************************************************
* @OLTOSTR(obj,str) * Logic command
*********************

 Copy object long text into str.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @OLTOSTR(obj,@STRNO(str))

*******************************************************************************
* @OPEN(obj) * Logic command
**************

 Changes the lock type of this object to OPEN.

*******************************************************************************
* ORDER OF PROCESSING *
***********************

 All modes of logic are processed in the order that they were encountered
 by GEN - therefore the order of files in your GENLIST can be important.

 First time round logic will be processed as soon as the program loads.
 This will only happen ONCE - as soon as the program is loaded.

   At the start of each game, CAT processes initialisation logic. 

   Each time a valid command is found (i.e. @VERBLGT and @VERBCHK passed),
   then low priority logic will be processed - UNTIL either an @STOP or an
   @CONT token is processed. If @STOP is found, the command line will be
   scrapped, if @CONT is found, the command line is kept.

   If low priority logic was not stopped by @STOP, then CAT will check to see
   if the verb is a valid path from the room - and if it is then the player will
   be moved to whichever room the path leads to.

   After each command (whether valid or not), high priority logic is processed.

   CAT will continue to find another command on the command line, or request
   a new command line if the current line has been exhausted or scrapped.
 
 Just before the program ends, last time round logic is executed.

*******************************************************************************
* @OSTOSTR(obj,str) * Logic command
*********************

 Copy object short text into str.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @OSTOSTR(obj,@STRNO(str))

*******************************************************************************
* @PAUSE(sec) * Logic command
***************

 Pause processing for sec seconds.

*******************************************************************************
* @PCONTENTS(obj) * Logic command
*******************

 Prints all objects that are in the in-room of obj.

*******************************************************************************
* @PEXITS * Logic command
***********

 Print all the obvious exits leading from the current players room.
 (i.e. @ROOMPTHs).

******************************************************************************
* @PLAYER * Logic - return value
***********

 Returns the object number of the current player.

******************************************************************************
* @PLAYERIS(obj) * Logic test
******************

 Returns TRUE if the current player is obj.

******************************************************************************
* PLAYERS *
***********

 See characters.

*******************************************************************************
* @PMSG(msg) * Logic command
**************
 
 Print the message called msg.
 
*******************************************************************************
* @PNUM(val) * Logic command
**************

 Print the integer value val.

*******************************************************************************
* @POBJL(obj) * Logic command
***************

 Print the long description of obj.

*******************************************************************************
* @POBJS(obj) * Logic command
***************

 Print the short description of obj.

******************************************************************************
* @POINTS(obj) * Logic - return value
****************

******************************************************************************
* PORTABILILITY * Porting CAT adventures to another compiler/computer
***************** 

 In theory, it should be a relatively easy job to convert CAT adventures to
 work with another compiler or machine. All machine specific code can be found
 in \cat\gensrc\portab.i - this has been commented as to its' purpose in life,
 so C programmers should be able to determine what is required.

*******************************************************************************
* @PROOML(room) * Logic command
*****************

 Print the long description of room.

*******************************************************************************
* @PROOMS(room) * Logic command
*****************

 Print the short description of room.

*******************************************************************************
* @PSTR(str) * Logic command
**************

 Print the text contained in str.

******************************************************************************
* QUALIFIERS *
**************

     Qualifiers
     ---------- 

     You can have any number of objects with the same unqualified name
     (i.e. RED KEY, GREEN KEY, YELLOW KEY), as long as their qualifiers are
     unique, i.e. a RED key, a BLUE key, a YELLOW key etc. Note however, that
     if you have a qualified object, you cannot have an unqualified object of
     the same name, i.e. you could not have a red key and a key.

     CAT will do the following if the player gives an unqualified name:
     
        If there is more than one object available with this unqualified name,
        then each of the objects will be listed and the player will be asked
        to be more specific.
        
        If there is only one object available with this unqualified name, then
        CAT will presume that this is the object the player is refering to.
        
        If there are no objects available with this unqualified name, but
        there are some in the adventure universe (i.e. in any room other than
        NOWHERE), then CAT will presume that the player is refering to the 
        first one of these it can find.

        If there are no objects in the adventure universe with this
        unqualified name, then CAT will presume that the player is refering to
        the first object of the same name that is in the NOWHERE room.
        
     Qualified objects are very easy to define, The underbar (_) separates 
     the qualifier, and the unqualified name. (see NAMES).


     Dummy qualifiers
     ----------------

     It is possible to give an object a two character qualifier (aa->zz).
     Within CAT, you must always refer to the object with it's qualified name,
     but the player will never see the qualifier. This allows several objects
     that 'seem' to have the same name.

     CAT will regard any two character qualifier as a 'dummy' qualifier.

     For example, you may want 'a door' to appear in different rooms.
     You may define one door as AA_DOOR, and the other as AB_DOOR.

     Dummy qualifiers will only work if each of the objects with a dummy
     qualifier can NEVER be in the same room as any other object with the
     same unqualified name. If two such objects did happen to be in 
     the same room, the player would not be able to qualify them, but CAT
     would insist that the player was more specific! Uno problema!
     OBJNGT is a good way of ensuring this rule is met. 

     Using dummy qualifiers, you COULD have a RED DOOR and a DOOR, as
     long as they are in different rooms. The RED door would be defined as 
     RED_DOOR, and the DOOR would be defined as AA_DOOR, XY_DOOR, BQ_DOOR etc.
     (the player would never see the AA, XY, BQ etc).

******************************************************************************
* @RAMLOAD * Logic command
************

 Load a previously saved game position from RAM. This command will fail with
 a suitable message if there is no saved game position in RAM.

******************************************************************************
* @RAMSAVE * Logic command
************

 Save the game position to RAM. If there is insufficient memory available,
 this command will fail with a suitable message.

******************************************************************************
* @RANDOM(x) * Logic - return value
**************

 Returns a random value between 1 and x inclusive.

*******************************************************************************
* @READ(obj) * Logic command
**************

 Prints the message attached to this object, defined via @OBJREAD.

*******************************************************************************
* @REM text * Remark
*************

 Any following text is a remark.

*******************************************************************************
* @REMOVE(obj) * Logic command
****************

 Make obj wearable, but not worn.

*******************************************************************************
* @REMOVECOMMAND(obj) * Logic command
***********************

 Remove command from obj (i.e. do not allow 'obj, GET HAT'). 

*******************************************************************************
* @REMOVEPLAYER(obj) * Logic command
**********************

 Make obj a non-player object (i.e. do not allow 'BECOME obj').

*******************************************************************************
* @REVIVE(obj) * Logic command
****************

 Make obj active - 'alive'.

*******************************************************************************
* @RLTOSTR(room,str) * Logic command
**********************

 Copy room long text into str.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @RLTOSTR(obj,@STRNO(str))

*******************************************************************************
* ROOM DEFINITION *
*******************

 The following tokens can be used to define rooms:

   @ROOM name
   @ROOMDRK
   @ROOMLNG text
   @ROOMPNT val
   @ROOMPTH verbname,roomname..
   @ROOMSHT text
   @ENDROOM

 CAT automatically supplies a room called NOWHERE. Objects in the NOWHERE room
 are effectively out of the adventure universe. You should not create any 
 paths that lead into the NOWHERE room!

*******************************************************************************
* @ROOM name * Room definition
**************

 Starts the definition of a room, where 'name' is the name of the room.
 See NAMES for more details.

*******************************************************************************
* @ROOMDRK * Room definition
************

 Defines the room as being dark. The default is light.

******************************************************************************
* @ROOMIS(room) * Logic test
*****************

 Returns TRUE if the current room is room.

*******************************************************************************
* @ROOMLNG text * Room definition
*****************

 Describes the long text for the room. If you give no long text for a room,
 the short text will be used.

 You can include 'LF' in room text - this will print a linefeed character.
 See MACROS for additional information.

******************************************************************************
* @ROOMNO(room) * Logic - return value
*****************

 Returns the room number of room.

*******************************************************************************
* @ROOMPNT val * Room definition
****************

 Defines the number of points the player will be awarded when he enters this 
 room AND it is not dark. The default is 0 points.

*******************************************************************************
* @ROOMPTH verbname,roomname.. * Room definition
********************************

 Defines the paths leading from the room (verbname), and the rooms to which 
 they lead. There may be many paths leading from one room. The default is that
 there are no paths leading from a room.

*******************************************************************************
* @ROOMSEEN(room) * Logic test
*******************

 Returns TRUE, if a long description has been displayed for room, or FALSE
 if the long description has not been displayed.

*******************************************************************************
* @ROOMSHT text * Room definition
*****************

 Describes the short text for the room. You should always define a short 
 description for a room, if the room can EVER be visited.

 You can include 'LF' in room text - this will print a linefeed character.
 See MACROS for additional information.

*******************************************************************************
* @RSTOSTR(room,str) * Logic command
**********************

 Copy room short text into str.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @RSTOSTR(obj,@STRNO(str))

*******************************************************************************
* @SAVE * Logic command
*********

 Ask for an 8 character filename, and save game position. (extendor is .SAV)

******************************************************************************
* @SCORE  * Logic - return value
***********

 Returns the current score.

******************************************************************************
* SCORING *
***********

 A room can be given a number of points with @ROOMPNT. When the player enters
 this room and it is not dark, he will be awarded these points.

 An object can be given a number of points with @OBJPNT. When the player puts
 this object in the designated object points room, then the player will be 
 awarded a score.
 
   By default, the object points room will be the in-room of the first 
   player object. You can change this by setting counter 496 to the number
   of another room - i.e. @SETCOUNT(496,@ROOMNO(IN_BED)) will change the object
   points room to IN_BED - the objects have to be in the bed for the player
   to qualify for the points.

 In addition to the above, you can award the player points for completing 
 tasks, or deduct points when help is given etc. These arbitrary points are 
 stored in counter 497 - i.e. @ADDCOUNT(497,10) would add 10 to the players
 score, and @SUBCOUNT(497,1) would deduct 1 from the players score.

*******************************************************************************
* @SCRIPT * Logic command
***********

 Start script mode - all output will be echoed to the printer.

*******************************************************************************
* @SETCOUNT(cnt,val) * Logic command
**********************

 Set counter cnt to val.

*******************************************************************************
* @SETPOINTS(obj,val) * Logic command
***********************

 Set the object points of obj to val.

*******************************************************************************
* @SETSTRENGTH(obj,val) * Logic command
*************************

 Set the strength of obj to val.

*******************************************************************************
* @SETVALUE(obj,val) * Logic command
**********************

 Set the value of obj to val.

*******************************************************************************
* @SETWEIGHT(obj,val) * Logic command
***********************

 Set the weight of obj to val.

******************************************************************************
* @SIZE(obj) * Logic - return value
**************

 Returns the size of obj. This is the basic weight of the object - 
                          not including carried weight.

*******************************************************************************
* @STOP * Low priority logic command
*********

 Stop processing this command, and kill the rest of the command. 

 @STOP can be used to stop players from taking an exit defined as a @ROOMPTH -
       there may be a huge green slime monster in the way!

*******************************************************************************
* @STR name * String definition
*************

 Starts the definition of a string, where 'name' is the name of the string.
 See NAMES for more details.

******************************************************************************
* @STRADDC(str,c) * Logic command
*******************

 Add character c onto the end of str.

 Always be sure that you to do not write past the end of any string.
 
*******************************************************************************
* @STRASC(str) * Logic - return value
****************

 Returns the ascii value of the first character in str.

******************************************************************************
* @STRCAP(str) * Logic command
****************

 Convert the first character of str to upper case.

******************************************************************************
* @STRCAT(str1,str2) * Logic command
**********************

 Concatenates str2 onto the end of str1.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @STRCAT(str1,@STRNO(str2))

******************************************************************************
* @STRCLR(str) * Logic command
****************

 Clear str.

******************************************************************************
* @STRCMP(str1,str2) * Logic - return value
**********************

 Compares str1 and str2. Returns 0 if the strings match, <0 if str1 is less
 than str2, or >0 if str1 is greater than str2.

 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @STRCMP(str1,@STRNO(str2))

******************************************************************************
* @STRCPY(str1,str2) * Logic command
**********************

 Copy str2 into str1.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @STRCPY(str1,@STRNO(str2))

******************************************************************************
* @STRENGTH(obj) * Logic - return value
******************

 Returns the strength of obj.

******************************************************************************
* @STRFCHR(str,c) * Logic - return value
*******************

 Returns the position of the first occurence of character c in str, or -1 if
 no matches. 
 
 Remember, the first character of a string is in position 0, and so on.

******************************************************************************
* @STRFSTR(str1,str2) * Logic - return value
***********************

 Returns the position of the first occurence of str2 in str1, or -1 if
 no matches. 

 Remember, the first character of a string is in position 0, and so on.

 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @STRFSTR(str1,@STRNO(str2))

******************************************************************************
* STRING DEFINITION *
*********************

 The following tokens are available to define strings:

   @STR name
   @STRSIZE val
   @STRTXT text
   @ENDSTR

 Ten strings are created for you automatically by GEN. These ten strings are 
 the only strings that will be saved with saved game positions - so you should
 use these strings to hold variable information that is relevant to the current
 state of the game. You can of course define your own strings, but you should 
 only use these to contain permanent unchanging data, or temporary data.
 The ten automatic strings have names and sizes as follows:
 
   S1       200 characters
   S2       200 characters
   S3       100 characters
   S4       100 characters
   S5       100 characters 
   S6       100 characters
   S7        50 characters
   S8        50 characters
   S9        50 characters
   S10       50 characters
 
   *** WARNINGS ***

   When referring to a CAT string, you are actually referring to a number,
   it is therefore very important that you do not use standard C functions 
   to access them - always use the CAT logic tokens.

   The first character of a string is in position 0, and NOT 1.

   With any string functions where a string name appears anywhere other than
   as the first parameter, you must use @STRNO to convert the parameter
   to a string - otherwise CAT will presume the parameter is the number of
   an object. I.e.

      @rem Copy characters 10-14 from MY_STRING into S1.

      @STRPCPY(s1,@strno(my_string),10,5)

   It is your responsibility to ensure that you do not write past the end
   of any given string - i.e. if a string is defined with @STRSIZE 50, 
   then make sure it never contains more that 50 characters. 
   IF THIS HAPPENS, UNPREDICTABLE RESULTS MAY OCCUR!

*******************************************************************************
* @STRLEN(str) * Logic - return value
****************

 Returns the length of str.

******************************************************************************
* @STRLOW(str) * Logic command
****************

 Convert str to lower case.

*******************************************************************************
* @STRNO(str) * Logic - return value
***************

 Returns the string number of str.

*******************************************************************************
* @STRNUM(str) * Logic - return value
****************

 Returns the integer value contained in str, or an undefined result if 
 str does not contain a number.

******************************************************************************
* @STRPCPY(str1,str2,start,len) * Logic command
*********************************

 Copy part of str2 into str1.
     start=start position in str2.
     len= number of characters to copy.

 Remember, the first character of a string is in position 0, and so on.

 Always be sure that you to do not write past the end of any string.
 
 You should always use @STRNO to pass the second parameter as a string, or 
 otherwise GEN will presume that it refers to an object. For example:

   @STRPCPY(str1,@STRNO(str2),10,2)

*******************************************************************************
* @STRSIZE val * String definition 
****************

 Defines the size in characters of the string that is currently being defined.

 The default size for a string is 254 characters, and this is also the 
 maximum size for a single string.

*******************************************************************************
* @STRTXT text * String definition
****************

 Describes the initial text for the string that is currently being defined.
 By defauly, a string is blank.
 
 You can include 'LF' in strings - this will print as a linefeed character.
 See MACROS for additional information.

******************************************************************************
* @STRUPP(str) * Logic command
****************

 Convert str to upper case.

*******************************************************************************
* @SUBCOUNT(cnt,val) * Logic command
**********************

 Subtract val from counter cnt.

*******************************************************************************
* @SUBPOINTS(obj,val) * Logic command
***********************

 Subtract val from the object points of obj.

*******************************************************************************
* @SUBSTRENGTH(obj,val) * Logic command
*************************

 Subtract val from the strength of obj.

*******************************************************************************
* @SUBVALUE(obj,val) * Logic command
**********************

 Subtract val from the value of obj.

*******************************************************************************
* @SUBWEIGHT(obj,val) * Logic command
***********************

 Subtract weight from the weight of obj.

*******************************************************************************
* @SWAP(obja,objb) * Logic command
********************

 Swap the rooms of obja and objb.

******************************************************************************
* @THISCOBJ * Low priority logic - return value
*************

 Return the number of the compound object referred to by the user, or -1 if 
 no object was referred to.

 You should only use this after you have determined that the command is 
 compound via the @ISCOMPOUND token.

 Only available in low priority logic.
 
******************************************************************************
* @THISCVERB * Low priority logic - return value
**************

 Returns the number of the compound verb referred to by the user, or -1 if
 no compound verb was used.

 You should only use this after you have determined that the command is 
 compound via the @ISCOMPOUND token.

 Only available in low priority logic.

******************************************************************************
* @THISOBJ * Low priority logic - return value
************

 Returns the number of the object referred to by the user, or -1 if no
 object was referred to.

 Only available in low priority logic.

******************************************************************************
* @THISROOM * Logic - return value
*************

 Returns the room number of the current players current room.

******************************************************************************
* @THISVERB * Low priority logic - return value
*************

 Returns the number of the verb referred to by the user, or -1 if no verb
 was used. (should never happen!)

 Only available in low priority logic.

******************************************************************************
* TITLE *
*********

 When your adventure starts up, it will look in the current directory for 
 a file called TITLE.TXT. If it finds this file, it will centre the text
 lines and display them on screen whilst decryption is taking place.

 You can use this feature to include your own little welcome screen. 
 For an example, see TITLE.TXT in the \CATTUTR5 folder.

******************************************************************************
* TOKENS *
**********

 When CAT reads a definition file, it looks for 'tokens', and other words. 
 A token is just a word that CAT recognises. CAT tokens generally begin with
 the @ character. For example, the following line contains the token '@OBJPNT',
 and the word '500'.

 @OBJPNT 500

******************************************************************************
* @TOROOM(room,obj) * Logic command
*********************

 Move obj to room. 
 
******************************************************************************
* @TURNS  * Logic - return value
***********

 Returns the number of turns taken.

*******************************************************************************
* @UNHIDE(obj) * Logic command
****************

 Unhide obj - hidden objects will not be shown in inventory lists, room
              descriptions etc. Hidden objects are not picked up by ALL
              variants (e.g. 'GET ALL').

*******************************************************************************
* @UNLIGHT(obj) * Logic command
*****************

 Make obj a light source, but NOT alight.

*******************************************************************************
* @UNLOCK(obj) * Logic command
****************

 Change the lock type of obj to CLOSED.

*******************************************************************************
* @UNSCRIPT * Logic command
*************

 End script mode - output will not be echoed to the printer.

******************************************************************************
* @VALUE(obj) * Logic - return value
***************

 Returns the value of obj.

*******************************************************************************
* VERB DEFINITION *
*******************

 The following tokens can be used to define verbs:

   @VERB name
   @VERBCHK type
   @VERBLGT
   @VERBPREP
   @VERBSYN synname..
   @ENDVERB

*******************************************************************************
* @VERB name * Verb definition
**************

 Starts the definition of a verb, where 'name' is the name of the verb.
 See NAMES for further details.

*******************************************************************************
* @VERBCHK type * Verb definition
***************** 

  Defines verb checking for the verb. Only one @VERBCHK can be defined for 
  each verb, the default being NO_CHECK.

  'type' can be one of: NO_CHECK
                        HERE
                        CARRIED_NOT_WORN
                        WORN
                        AVAIL
                        AVAIL_NOT_WORN
                        CARRIED
                        NOT_CARRIED
                        EXIST

   If the users command contains a verb that has verb checking selected, CAT
   will perform verb checking. If the object on the command line does not 
   pass the checks specified for the verb, then an appropriate message will be 
   displayed, and control will NOT be passed to low priority logic.

   When 'ALL' is used, CAT uses VERBCHK to intelligently determine which
   objects should be included in the ALL list.

******************************************************************************
* @VERBIS("text") * Low priority logic test
******************* 
 
 Returns TRUE if the verb is a synonym for "text".

 You should avoid this token for the following reasons:
     "text" will not be encrypted.
     @VERBNOIS is much faster.

 Only available in low priority processing.

*******************************************************************************
* @VERBLGT * Verb definition
************

 Specifies that it must be light for the user to use this verb. If the user
 tries to use this verb when it is dark, he will be given an appropriate 
 message, and control will NOT be passed to low priority logic.

******************************************************************************
* @VERBNOIS(verb) * Low priority logic test
*******************

 Returns TRUE if the verb number = verb. You must use the actual verb name,
 NOT a synonym.

 Only available in low priority processing.

*******************************************************************************
* @VERBOSE * Logic command
************

 Enter VERBOSE mode. Long room descriptions will always be given.  
 
******************************************************************************
* @VERBPATH(verb) * Logic - return value
*******************

  Returns the room number that verb would lead to, or -1 if verb is  
  not a valid @ROOMPTH from the current room.

*******************************************************************************
* @VERBPREP * Verb definition
*************

 Defines the verb as being a prepositioner verb. 'TO' and 'WITH' are examples
 of prepositioner verbs. A verb must be defined as a prepositioner verb if 
 it should be allowed as the second part of a compound command.
 (i.e. 'GIVE THE HAT TO BOB')

*******************************************************************************
* @VERBSYN synname.. * Verb definition
**********************

 Defines synonyms for the verb. A verb can have many synonyms. Verb synonyms 
 follow the same rules as verb names - see NAMES for more details.

*******************************************************************************
* @VOCAB * Logic command
**********

 Prints a list of all the accepted verbs.

*******************************************************************************
* @WAITKEY * Logic command
************

 Waits for a key to be pressed.

*******************************************************************************
* @WEAR(obj) * Logic command
**************

 Makes the object wearable, AND worn.

******************************************************************************
* WEIGHT *
**********

 CAT will automatically update compound object weights, i.e. the weight of
 each object will be the basic weight of the object, PLUS any objects that
 object is carrying, plus any objects that those objects may be carrying etc.
 
 The total weight of an object can be determined by @WEIGHT.
 
 The basic weight of an object can be determined by @SIZE.
 
 The carried weight of an object can be determined by @CARRIED_WEIGHT.
 
 Objects defined with @OBJNGT will have an effective weight of zero - 
 i.e. these objects are ignored when calculating weights.

******************************************************************************
* @WEIGHT(obj) * Logic - return value
****************

 Returns the weight of obj.

*******************************************************************************
* @WEND * Logic control
*********

 Signifies the end of an @WHILE 'logic control' group.

 Each @WEND must match up to an @WHILE.

*******************************************************************************
* @WHILE * Logic control
**********

 Signifies the start of an @WHILE 'logic control' group.

 Each @WHILE must match up to an @WEND.

 @WHILE groups will repeat until the test conditions fail.

*******************************************************************************
* @WHOAMI * Logic command
***********

 Print 'You are', and the short description of the current player.

*******************************************************************************
* ZZRQD * 
*********

 This is a standard definition file for CAT. Any definitions in this file
 are referred to internally by CAT. You should not change any NAMES in this 
 file, but you can change synonyms and text.

*******************************************************************************
* ZZSTD *
*********

 This is the standard definition file for CAT. It provides all generic 
 CAT logic. You can change this file, or add to it as required.

*******************************************************************************
* ZZZZZZZZZZZZZZZZZ * 
*********************

 Time for bed!


@rem C Adventure Toolkit (CAT) - Tutorial #1

@rem This file introduces the initial concepts of the Adventure Toolkit.

@rem ***************************************************************************

@rem This is a remark line. If the CAT sees a word with an @ at the beginning
     of it, it checks to see whether it is a recognised token. @REM is one of
     the recognised tokens, and it tells CAT to ignore everything it sees until
     it recognises another token. I will be using the @REM token a lot!

@rem CAT doesn't mind how many spaces, tabs, or blank lines you leave between 
     words. It is only interested in the words themselves.

@rem You can use any ascii (printable) characters in a CAT source file.

@rem ***************************************************************************

@rem The first concept that you will need to understand is 'Rooms'. The 
     adventure world is divided into rooms. These need not actually be enclosed
     rooms in the traditional sense.. a room may be 'At the top of a tree',
     'In a field' etc.

@rem Rooms have a short description and a long description. They can be dark,
     or they can be light. There may be a number of paths leading from a room
     into another room. It is possible to award a player points the first time
     he enters a room, and it is light.

@rem We are going to define two rooms to CAT. The first room is a Hallway. It
     is dark, and there is a path leading north to the bedroom. The bedroom is
     not dark, and it obviously has a path leading south to the hallway. The 
     player will be awarded 10 points the first time he enters Hallway, when
     it isn't dark.

@rem **************************************************************************

@room 		Hallway
@roomsht	Hallway.
@roomlng	You are standing in a magnificent hallway. You can go north
		to the bedroom from here.
@roompth	north,bedroom
@roomdrk
@roompnt	10
@endroom

@room		Bedroom
@roomsht	Bedroom.
@roomlng	You are in a tiny bedroom. You can go south to the hallway 
		from here.
@roompth	south,hallway
@endroom

@rem **************************************************************************

@rem The ROOM token tells CAT the name of the room you are defining.
     Names within CAT can contain any letters of the alphabet, and the underline
     character (_). i.e. BEDROOM, MAIN_HALLWAY, X_GARDEN.

     The ROOMSHT token describes the short description for this room.

     The ROOMLNG token describes the long description for this room.

     The ROOMPTH token describes all the paths leading from this room,
     and the rooms to which they lead. Notice that you must specify the
     directional verb (NORTH/SOUTHEAST etc), immediately followed by a ','
     immediately followed by the name of the room to which the path leads. 
     A room can have many paths leading to many rooms.

     The ROOMDRK token tells CAT that this room is dark.

     The ROOMPNT token tells CAT that the player should receive a number of
     points when he first enters a room (10 points for the hallway).

     The ENDROOM token tells CAT that we have finished defining this room.

@rem *************************************************************************

@rem When the player enters a room for the first time, they will be given the
     long description of the room. When they enter it a second and subsequent
     times, they will be given the short text. The short text for the current 
     room is always shown at the top of the adventure screen. Neither the long
     nor the short room description will be given if the current room is dark
     and there is no source of light available. It is possible to make a dark
     room light, or a light room dark. (see CATMAN.TXT)

@rem *************************************************************************

@rem CAT will automatically define a special room for you. This room is called
     NOWHERE, and is used to hold objects that are not currently in the 
     adventure universe, but may be at a later point.

@rem *************************************************************************

@rem CAT places no limits on the maximum length of text... all pieces of 
     text are stored in strings. C compilers have a limit on the maximum 
     size of a string (255 for Sozobon C), it is therefore recommended that
     none of your text is longer than 255 characters. This will ensure that 
     your adventure is portable between compilers. The long and short
     descriptions of rooms are pieces of text, as are descriptions of objects
     and message texts. (i.e. anything that will be presented to the player).

     'LF' can be included in any piece of text, and it will print a linefeed
     character.

@rem *************************************************************************

@rem The next concept you will need to understand is that of the 'object'.
     Objects are the heart of adventures. Some objects are 'a huge statue',
     'a key', 'a chest', 'a door'.

     In fact, the player is a special type of object in the adventure, a
     player object! Every adventure must have at least one player object, so
     let's look at how to define one. The player can type 'BECOME x', where x
     is the name of any player object. All his commands will then be followed
     by player object x.

     CAT allows ANY NUMBER of player objects. This feature is unique to CAT - 
     any other system available only allows you to directly control ONE player.

@rem *************************************************************************

@rem Player objects must have a room attached to them (an in-room). This 
     is the room in which any objects that player is carrying will be placed.
     The definition below defines the player object Tony, and his 'in-room'.

     Player objects are presumed to be 'Active'. An active object is any 
     object that is alive. We will be covering Active objects shortly.

@rem *************************************************************************

@obj 		Tony
@objplr
@objsyn		Dude
@objsht 	Tony
@objlng 	Tony is just an average guy.
@objroom 	Bedroom
@objinrm 	In_Tony
@objwgt		125
@objstr 	100
@endobj

@room		In_tony
@roomsht	Carried by Tony.
@roomlng	You are being carried by Tony.
@roompth	down,carried
@endroom

@rem **************************************************************************

@rem The OBJ token tells CAT the name of the object you are defining.

     The OBJPLR token tells CAT that this object is a player. i.e. the player
     can BECOME TONY. 

     The OBJSYN token tells CAT that 'dude' is a Synonym for 'Tony'. The
     player can refer to the TONY object with either 'Tony', or 'Dude'. Each
     object can have many synonyms.

     The OBJSHT token describes the short text for this object.
     The short text for an object is used when listing objects, i.e. Inventory.

     The OBJLNG token describes the long text for this object.
     The long text for an object is used when examining an object etc.
     If an object has no long text, examining it will produce the standard
     message 'You don't see anything unusual.'

     The OBJROOM token tells CAT which room the object will start in.
     If an OBJROOM token is not specified, the object will start in the 
     NOWHERE room - which should not be accessible by the player.

     The OBJINRM token tells CAT the in-room for this object. I.e. when 
     objects are placed in this object, they will be in room IN_TONY. Any 
     object can have an in-room. For example, a box would have an in-room, 
     thus allowing the player to put things inside it.

     The OBJWGT token tells CAT the weight of this object.
     The default weight for an object is 1.

     The OBJSTR token tells CAT the strength of this object. This means 
     something slightly different for active objects compared to other
     objects: 

       When considering an active object, this is the maximum TOTAL weight of 
       objects he/she can carry, i.e. taking count of each object he is 
       carrying PLUS the weight of any objects contained within them!
     
       When considering a non active object, this is the maximum weight of the
       objects contained within it, NOT including the weight of any objects
       that may be within them - a simulation of volume.

     Objects without OBJSTR defined will have a strength of 0.

     The ENDOBJ token tells CAT that we have finished defining this object.

******************************************************************************

@rem The in-room for TONY needn't have been called IN_TONY. It could have been
     called TONY_INV or GOT_TONY or anything else you may like.

     The room IN_TONY has been given a long and short description, because it
     is always possible that another player object will be in this room, i.e.
     being carried by TONY!

     Notice the ROOMPTH leading DOWN from IN_TONY. The special room CARRIED
     is not really a room. It is a way of ensuring that when this path is
     taken, you will end up in the same room as TONY, without having to worry
     about where TONY actually is. You can use CARRIED as an exit from any
     room that has been defined as an in-room.

@rem *************************************************************************

@rem Now, we are going to introduce another object - the lamp. This will 
     give us some light to see in the hallway. You can define an object as 
     being a light source, or being a light source AND being lit.

     The OBJLGT token tells CAT that this object is a light source. The OBJLIT 
     token tells CAT that this object is a light source, and it is lit.

     Here's the definition for the lamp, which is lit and in the bedroom.

@rem **************************************************************************

@obj 	 lamp
@objsht  a lamp
@objlng  Just an ordinary lamp.
@objlit 
@objroom bedroom
@objwgt  10
@endobj

@rem *************************************************************************

@rem The following code ensures that TONY is the currently controlled player
     when the adventure starts, but don't worry about understanding it now.

@rem *************************************************************************

@init @become(tony)

@rem *************************************************************************

@rem Review any areas of this tutorial that you have not fully understood.
 
@rem *************************************************************************
@rem ****************           End of Tutorial #1           *****************
@rem *************************************************************************


@rem C Adventure Toolkit (CAT) - Tutorial #2

@rem This file introduces messages, further objects, and qualified objects.

@rem **************************************************************************

@rem Now is a good time to introduce 'messages'. A message is just a piece of
     text that will appear somewhere in the adventure. A message just has a 
     name, and some text. Let's define an object that can be read (a leaflet),
     and the message that is written upon it.

@rem **************************************************************************

@msg 		leaflet_msg
@msgtxt 	There's a treasure in the blue box!
@endmsg

@obj 		leaflet
@objsht 	a leaflet
@objlng		It has something written on it.
@objroom	bedroom
@objread	leaflet_msg
@endobj

@rem **************************************************************************

@rem The MSG token tells CAT the name of the message that we are defining.

     The MSGTXT token tells CAT the text for the message.
     
     The ENDMSG token tells CAT that we have finished defining this message.
     
@rem The OBJREAD token tells CAT that the leaflet can be read, and when the 
     player reads it, the message called LEAFLET_MSG should be displayed.
     
@rem **************************************************************************

@rem An object can be wearable, or wearable AND worn. We are going to define 
     a coat that is being worn by Tony, and a pair of trousers that can be 
     worn - left in the hallway. 

@rem **************************************************************************

@obj		coat
@objsht		a coat
@objroom	in_tony
@objwgt		20
@objworn
@endobj

@obj		trousers
@objsyn		breeches jeans
@objsht		a pair of trousers
@objwgt		5
@objroom	hallway
@objwear
@endobj

@rem *************************************************************************

@rem Okay, now I'm going to introduce two qualified objects. i.e. a RED KEY
     and a BLUE KEY - where RED and BLUE are the qualifiers. You can have any
     number of objects with the same unqualified name, as long as their 
     qualifiers are unique, i.e. a red key, a blue key, a yellow key etc.
     Note however, that if you have a qualified object, you cannot have an
     unqualified object of the same name, i.e. you could not have a red key
     and a key.

     CAT will do the following if the player gives an unqualified name:
     
        If there is more than one object available with this unqualified name,
        then each of the objects will be listed and the player will be asked
        to be more specific.
        
        If there is only one object available with this unqualified name, then
        CAT will presume that this is the object the player is refering to.
        
        If there are no objects available with this unqualified name, but
        there are some in the adventure universe (i.e. in any room other than
        NOWHERE), then CAT will presume that the player is refering to the 
        first one of these it can find.

        If there are no objects in the adventure universe with this
        unqualified name, then CAT will presume that the player is refering to
        the first object of the same name that is in the NOWHERE room.
        
     Qualified objects are very easy to define, The underbar (_) separates 
     the qualifier, and the unqualified name.
     
@rem *************************************************************************

@obj		red_key
@objroom	hallway
@objsht		a red key 
@endobj

@obj		blue_key
@objroom	in_red_box
@objsht		a blue key
@endobj

@rem **************************************************************************

@rem Now, we'll define two boxes, again qualified objects. These boxes can 
     contain things, so they must have an in-room, and since they have an 
     in-room, they should also have strength. The BLUE BOX will be locked,
     and the BLUE KEY will fit the lock. The RED BOX will be closed, and the 
     RED KEY will fit its lock.
     
@rem **************************************************************************

@obj		blue_box
@objsht		a blue box
@objlck		locked
@objkey		blue_key
@objinrm	in_blue_box
@objwgt		10
@objstr		8
@objroom	bedroom
@endobj

@room in_blue_box @endroom

@obj		red_box
@objsht		a red box
@objlck		closed
@objkey		red_key
@objwgt		20
@objinrm	in_red_box
@objstr		15
@objroom	in_tony
@endobj

@room in_red_box @endroom

@rem **************************************************************************

@rem I haven't bothered giving the rooms IN_RED_BOX, or IN_BLUE_BOX a long or 
     a short description. Because players can never enter these rooms, the
     text would never be displayed.
     
@rem The OBJLCK token tells CAT the lock state of this object. Valid values
     are OPEN, CLOSED, LOCKED. Players may not enter, place anything inside,
     or remove anything from an object that is either locked, or closed.
     
@rem The OBJKEY token tells CAT which object is required to lock/unlock 
     this object. If no OBJKEY is specified for an object, the player will not
     be able to lock/unlock the object. The OBJKEY token has no effect if
     an object doesn't have OBJLCK specified.
     
@rem **************************************************************************

@rem Now, we'll put a treasure in the blue box. The OBJPNT token tells CAT how 
     many points an object is worth to the player. The player will have 50
     points added to his score when he is carrying the coin.
     
@rem **************************************************************************

@obj		coin
@objsht		a gold coin
@objpnt		50
@objroom	in_blue_box
@endobj

@rem **************************************************************************

@rem Now, we're going to define a door that leads from the hallway to the 
     bathroom (a new room). CAT will automatically ensure that doors are
     where they should be, i.e. when the player is in the hallway, the door
     will be there - when the player is in the bathroom, the door will be 
     moved to the bathroom. This is important when there is more than one
     active object in an adventure - they could be on either side of the door!

@rem **************************************************************************

@obj 		door
@objsht		a door
@objdoor 	hallway,bathroom
@objlck		closed
@objkey		blue_key
@objngt
@endobj

@room		bathroom
@roomsht	Bathroom.
@roomlng	You are in a smelly bathroom, the toilet stinks to high heaven.
@roompnt	5
@endroom

@rem *************************************************************************

@rem The OBJDOOR token tells CAT that this object is a door between the 
     hallway and the bathroom. Note the ',' between the two rooms.
     
     The OBJLCK token tells CAT that this door is closed.
     
     The OBJKEY token tells CAT that the blue key will lock/unlock this door.

     The OBJNGT token tells CAT that this cannot be moved (No GeT). It also
     means that the object cannot be dropped, if it is already carried - 
     useful for things 'attached' to the players body, like arms!
          
     We do not need to tell CAT which room the door should be in. CAT will 
     move this around automatically for us, because the object is a door!
     
@rem The bathroom does not have any paths leading from it, the player has
     to use the door. The player receives 5 points on entering the bathroom.
     
@rem *************************************************************************

@rem Now I'll show you how to hide objects. If any object is hidden, it won't
     be shown on any inventory lists or room descriptions etc, BUT the player
     can still interact with it the same way as he can any other object. Hidden
     objects will not be picked up by commands using ALL - i.e. GET ALL!

     I'm going to create a toilet in the bathroom. I'm hiding it, because it is
     already mentioned in the room description of the bathroom. I'm also going
     to put some slime, and a necklace in the toilet. The slime cannot be 
     taken, but the necklace can. 'TAKE NECKLACE FROM TOILET'.

@rem Notice that I haven't given the toilet a short description. This will 
     never be displayed because the object is hidden. I have given it a long
     description, because it could be examined.

     The OBJHIDE token tells CAT that the toilet is hidden.

@rem *************************************************************************

@obj 		toilet
@objlng		This is a very smelly toilet indeed.
@objsyn		wc loo pan
@objroom	bathroom
@objhide
@objngt
@objinrm	in_toilet
@objstr		50
@endobj

@room in_toilet @endroom

@obj		slime
@objsht		some smelly slime
@objroom	in_toilet
@objngt
@endobj

@obj		necklace
@objsht		a necklace
@objwear
@objroom	in_toilet
@objwgt		2
@objpnt		10
@endobj

@rem **************************************************************************

@rem Here's an apple, that can be eaten. The OBJEAT token tells CAT that this
     object can be eaten, and how much the players strength should be affected
     (+/-) when he eats the object. The players strength will be increased 
     by 5 when he eats the apple.
     
@rem **************************************************************************

@obj		apple
@objsht		an apple
@objroom	hallway
@objeat		5
@endobj

@rem **************************************************************************

@rem Here's a puddle of water, that can be drunk. The OBJDRINK token tells CAT
     that this object can be drunk, and how much the players strength should
     be affected (+/-) when he drinks the object. The players strength will be
     decreased by 5 when he eats the apple.

     Because the puddle cannot be moved, it will not disappear when the player
     drinks from it. The same applies to edible objects that cannot be moved.
     
@rem **************************************************************************

@obj		puddle
@objsht		a puddle of dirty water
@objsyn		water
@objlng		It doesn't look too tasty.
@objroom	hallway
@objdrink	-5
@objngt
@endobj

@rem *************************************************************************

@rem Now, I'm going to introduce another concept that may appear confusing 
     at first - dummy qualifiers. It is possible to give an object a two
     character qualifier (aa->zz). Within CAT, you must always refer to the
     object with it's qualified name, but the player will never see the 
     qualifier. This allows several objects that 'seem' to have the same name.

     CAT will regard any two character qualifier as a 'dummy' qualifier.

     For example, you may want 'a door' to appear in different rooms.
     You may define one door as AA_DOOR, and the other as AB_DOOR.

     Dummy qualifiers will only work if each of the objects with a dummy
     qualifier can NEVER be in the same room as any other object with the
     same unqualified name. If two such objects did happen to be in 
     the same room, the player would not be able to qualify them, but CAT
     would insist that the player was more specific! Uno problema!
     OBJNGT is a good way of ensuring this rule is met. 

     Dummy qualifiers can be used to get around one of the problems I mentioned
     earlier. Using dummy qualifiers, you COULD have a RED DOOR and a DOOR, as
     long as they are in different rooms. The RED door would be defined as 
     RED_DOOR, and the DOOR would be defined as AA_DOOR, XY_DOOR, BQ_DOOR etc.

@rem *************************************************************************

@rem I'm going two define two objects with dummy qualifiers... AA_BEDROOM and
     AA_HALLWAY. These objects will be placed in the BEDROOM and the HALLWAY 
     respectively, and will allow the player to 'EXAMINE THE BEDROOM' when he
     is in the bedroom, or 'EXAMINE THE HALLWAY' when he is the the hallway.

     You will see why I have qualified them in a minute. Notice that both
     objects are hidden, and cannot be moved.

@rem *************************************************************************

@obj		aa_bedroom
@objngt	
@objhide
@objroom	bedroom
@objlng		This is just an average bedroom.
@endobj

@obj		aa_hallway
@objsyn		aa_hall
@objngt	
@objhide
@objroom	hallway
@objlng		This hallway is truly magnificent.
@endobj

@rem *************************************************************************

@rem Now we'll introduce two more objects with dummy qualifiers... AB_BEDROOM
     and AB_HALLWAY. These are going to provide another way for the player to
     move between the hallway and the bedroom. I.e. from the hallway, the 
     player will be able to use 'GO BEDROOM', from the bedroom he will be 
     able to use 'GO HALLWAY', or 'GO HALL'.

     Notice that these objects cannot be moved, and they are in a different
     room to their AA_ counterparts.

     The OBJPORTAL token tells CAT that this object is a portal into another
     room - the player can enter it. Portals are like doors, except they only
     work in one direction. CAT does not sort out the location of portals.. 
     it's up to you to define where they should be placed with OBJROOM.

@rem *************************************************************************

@obj		ab_bedroom
@objngt	
@objhide
@objroom	hallway
@objportal	bedroom
@objlng		It's just an average bedroom.
@endobj

@obj		ab_hallway
@objsyn		ab_hall
@objngt	
@objhide
@objroom	bedroom
@objportal	hallway
@objlng		The hallway is truly magnificent.
@endobj
 
@rem *************************************************************************

@rem I am now going to introduce another player, Simon, and I am going to
     create a bed that is too small for Tony, but big enough for Simon.

     Note: because the bed is a portal, AND it has an in-room, a player can
     enter it, or they can place things inside it.

@rem *************************************************************************

@obj		Simon
@objsht		Simon
@objwgt		100
@objstr		75
@objplr
@objroom	hallway
@objinrm	In_simon
@endobj

@room 		In_simon
@roomsht	Carried by Simon.
@roomlng	You are being carried by Simon.
@roompth	down,carried
@endroom

@obj		Bed
@objsht		a small bed
@objroom	bedroom
@objngt
@objinrm	in_bed
@objstr		100
@objportal	in_bed
@endobj

@room		In_bed
@roomsht	In bed.
@roomlng	You are in bed.
@roompth	up,carried leave,carried
@endroom

@rem *************************************************************************

@rem I have covered player objects. Now, I'm going to introduce two new types
     of 'live' objects... Commandable objects (OBJCMD), and active objects
     (OBJACT). The current player object can issue commands to any
     'commandable' object like this 'BILL, DROP THE RED KEY'. 'Active' 
     objects are 'alive'... the player cannot control them in any way, but
     he can still interact with them.. i.e. he could give things to them.

     OBJPLR automatically selects OBJCMD and OBJACT.

     OBJCMD automatically selects OBJACT.

     If an object has any of OBJPLR, OBJCMD, or OBJACT specified, it should
     also have an in-room defined - its' inventory.

     Let's introduce a commandable character, Bob. He'll start off wearing 
     a hat. The player could issue a command such as this: 
     BOB, TAKE OFF THE HAT AND GIVE IT TO ME, THEN GO SOUTH.

     We'll also introduce Harry. He's active, but the player has no direct
     control over him.

     Because both BOB and HARRY have OBJNGT selected, neither Tony nor Simon
     will be able to carry either of them.
     
@rem *************************************************************************

@obj		Bob
@objsht		Bob
@objcmd
@objroom	Bedroom
@objngt
@objstr		50
@objinrm	In_bob
@endobj

@room    In_bob
@roomsht Carried by Bob.
@roomlng You are being carried by Bob.
@roompth down,carried
@endroom

@obj		Hat
@objsht		a hat
@objroom	In_bob
@objworn
@endobj
	
@rem *************************************************************************

@obj		Harry
@objsht		Harry
@objact
@objroom	Hallway
@objngt
@objstr		50
@objinrm	In_Harry
@endobj

@room    In_harry
@roomsht Carried by Harry.
@roomlng You are being carried by Harry.
@roompth down,carried
@endroom

@rem *************************************************************************

@rem Now, there is only one more characteristic that an object can have.
     That is a value. This can be viewed as a monetary value. OBJVAL doesn't 
     provide any default actions by CAT, but an objects value can be checked
     and changed by user logic (to be covered shortly).

     The OBJVAL token tells CAT the value of this object.

@rem *************************************************************************

@obj		note
@objsyn		fiver money
@objsht		a five pound note
@objval		5
@objroom	in_simon
@endobj

@rem *************************************************************************

@rem Review any areas of this tutorial that you have not fully understood.
 
@rem *************************************************************************
@rem ****************           End of Tutorial #2           *****************
@rem *************************************************************************


@rem C Adventure Toolkit (CAT) - Tutorial #3

@rem This file introduces verbs.

@rem *************************************************************************

@rem Now, I'm going to introduce verbs. CAT has lots of verbs already defined
     for you in the ZZRQD and ZZSTD definition files, but you may want to 
     create more that are specific to your adventure. Consider the following:

@rem *************************************************************************

@verb 		Rub
@verbsyn	Shine Polish
@verblgt
@verbchk	Avail_not_worn
@endverb

@rem *************************************************************************

@rem The VERB token tells CAT the name of the verb we are about to define.

     The VERBSYN token describes some synonyms for the verb RUB. e.g.
     RUB LAMP, SHINE LAMP, and POLISH LAMP are all the same.

     The VERBLGT token tells CAT that it must be light for the player to 
     successfully use this verb. If the player uses this verb when it is 
     dark, he will get a standard message 'It's too dark to do that.'

     The VERBCHK token tells CAT that the verb RUB must refer to an object, and 
     that object must be available (in the current room, or carried), and
     not worn. If the player uses the command 'RUB' without any object, 
     he will be told that he must specify an object. If he tries to RUB 
     something that he is wearing, or is not available, then he will be 
     given an appropriate message 'You're wearing that' or 'That's not here'.

     Only one VERBCHK can be specified for each object. Valid VERBCHKs are:

        NO_CHECK         - no checking is performed, an object is not required.
        HERE             - an object is required, and it must be here
                           (in the same room as the player).
        CARRIED_NOT_WORN - an object is required, it must be carried but
                           it must not be worn.
        WORN             - an object is required, and it must be worn.
        AVAIL            - an object is required, it must be available 
                           (in the same room as the player, or carried).
        AVAIL_NOT_WORN   - an object is required, it must be available 
                           (in the same room as the player, or carried), and
                           not worn.
        CARRIED          - an object is required, and it must be carried.
        NOT_CARRIED      - an object is required, it must not be carried.
        EXIST            - an object is required, and it must exist.

     If no VERBCHK is selected, the default is NO_CHECK

     You will notice that worn objects still count as being carried.

@rem *************************************************************************

@rem When used properly, the VERBLGT and VERBCHK tokens can provide nearly all
     of your validity checking - gone are the days when your logic has to 
     specifically check out the details of each object that the player refers
     to! This is a VERY powerful feature of CAT, and will eliminate many hours
     of consistency debugging!

@rem *************************************************************************

@rem Okay, now you know how to allow simple two word commands, but what about
     things like: GIVE THE HAT TO TONY. We can break this command into four 
     distinct parts: the verb (GIVE), the object (HAT), the compound verb (TO),
     and the compound object (TONY).

     If CAT wasn't told otherwise, it would interpret the above command as
     TWO commands i.e. 'GIVE HAT' and 'TO TONY' - this obviously doesn't make
     sense, so we need a way to tell CAT that 'TO' is a compound verb. We use
     the VERBPREP (prepositioner verb) token to do this. Consider the following
     extract from ZZSTD: 

@rem *************************************************************************

NOTE: THESE ARE NOT REAL DEFINITIONS - THERE IS NO @ AT THE START OF THE TOKENS.

verb     give
verblgt 
verbsyn  pass hand
verbchk  carried_not_worn
endverb

verb 	 to 
verbprep 
verbchk  avail_not_worn
endverb

@rem ignore the underbars (_) after the tokens - I have added these so that
     CAT doesn't recognise the tokens, or the 'GIVE' and 'TO' verbs would be
     processed twice (once here, and once in ZZSTD).

@rem *************************************************************************

@rem You will note that both the 'GIVE' and the 'TO' verbs have a VERBCHK
     defined. If the command 'GIVE THE HAT TO TONY' was given by the player,
     CAT would automatically perform the following checks:

     Make sure it isn't dark           (from VERBLGT defined on GIVE)
     Make sure the HAT is carried
     Make sure the HAT is not worn
     Make sure TONY is carried, or here
     Make sure TONY is not worn

     The command would only be passed to CAT logic if all of the above tests 
     pass successfully, otherwise an appropriate message will be displayed
     and CAT will wait for another command from the player.
 
@rem *************************************************************************

@rem Now I'm going to show you another extract from ZZSTD, Consider the verbs
     WEAR and REMOVE. It would be nice if the player could use any of the 
     following:
                WEAR HAT
                PUT ON THE HAT
                REMOVE THE HAT
                TAKE OFF HAT

     We are talking about TWO WORD verbs, i.e. 'PUT ON' is a synonym for 'WEAR'
     as 'TAKE OFF' is a synonym for 'REMOVE'. These are very easy to define 
     within CAT - we use an underbar to separate the two words:

@rem *************************************************************************

NOTE: THESE ARE NOT REAL DEFINITIONS - THERE IS NO @ AT THE START OF THE TOKENS.

verb	  wear
verblgt
verbsyn   put_on
verbchk   carried_not_worn
endverb

verb      remove
verbsyn   take_off
verbchk   worn
endverb

@rem *************************************************************************

@rem CAT uses each verbs VERBCHK to intelligently handle ALL. E.g.

     RUB ALL          - would rub all objects that are available, not worn. 
     WEAR ALL         - would wear all objects that are carried, but not worn.
     GIVE ALL TO TONY - would give all objects that are carried, but not worn
                        to Tony.

     Consider you are in a room. There is a lamp here. You are carrying a 
     coat and wearing a pair of gloves. 

     'RUB ALL' would generate the commands:

        RUB LAMP
        RUB COAT

     'WEAR ALL' would generate the commands:

        WEAR COAT

     'GIVE ALL TO TONY' would generate the command:
     
        GIVE COAT TO TONY

@rem *************************************************************************

@rem We have defined the verb 'RUB' in this tutorial. We haven't yet provided
     any logic to process this verb, this will be covered in tutorial 4.

@rem *************************************************************************

@rem Review any areas of this tutorial that you have not fully understood.
 
     Take a look at \CAT\STD\ZZSTD.D and \CAT\STD\ZZRQD.D, to see the 
     definitions of all the standard verbs. Try to understand what they are
     doing - it should all click into place fairly quickly!

     Note in particular the definition for GET. This is a 'funny' - we should
     be able to give it a VERBCHK of HERE. We can't do this, or we would 
     block commands like 'TAKE THE KEY FROM THE BOX'...... because the key
     isn't here (it's in the box), verbchecking would block the command.
     Instead, we have to use NOT_CARRIED, and use CAT logic to make sure that
     the object is here before we actually GET it!

@rem *************************************************************************
@rem ****************           End of Tutorial #3           *****************
@rem *************************************************************************


@rem C Adventure Toolkit (CAT) - Tutorial #4

@rem Before reading this file, read tutor4.txt.

@rem *************************************************************************

@rem The following will print a welcome message on starting the adventure.
     The player will be set to TONY - this is duplicated from the first 
     tutorial, but that doesn't matter.

@init @pmsg(intro) @lf @lf @become(tony)

@msg 	Intro
@msgtxt	Hello, and welcome to the CAT tutorial adventure. Have fun!
@endmsg

@rem *************************************************************************

@rem The player has to put objects in the bed, in order to get a score.

     @init 
     @setcount(496,@roomno(in_bed))
     
@rem *************************************************************************

@rem By default the VOCAB command prints a list of all the available verbs.
     We're going to be difficult and block the command before it gets to 
     the logic in ZZSTD! We have to use low priority logic here because 
     we are interpreting a command from the player.

@low
@if @verbnois(vocab) @do @pmsg(sorry) @cont @endif
@lc

@msg sorry @msgtxt Sorry! @endmsg

@rem *************************************************************************

@rem And now some HIGH priority logic. Remember this happens after every turn,
     whether successful or not. 

     If the door is not locked, there is a 1 in 4 chance that Harry will
     lock it! If the player is in the same room as Harry and the door,
     we print the message 'Harry locks the door'. If the player is in the
     same room as the door, but Harry isn't here, 'Someone locks the door'.
     If it's dark, the player won't be told anything, whatever is there!

@high
@if (not @islocked(door)) and @random(4) eq 1 @do
   @lock(door)
   @if (not @isdark)
      @if @ishere(door)
         @if @ishere(harry) @do
            @pmsg(harry_locks_door)
         @else @do
            @pmsg(someone_locks_door)
         @endif
      @endif
   @endif
@endif
@lc

@msg 	Harry_locks_door
@msgtxt Harry locks the door!
@endmsg

@msg 	Someone_locks_door
@msgtxt Someone locks the door from the other side!
@endmsg

@rem *************************************************************************

@rem This hypothetical example will print 'Hello' 10 times, if the command
     'HELLO' is found. I need to use low priority logic because we are
     interpreting a command.
     
     @low 
     @if @verbnois(hello) @do
        @setcount(400,1)
        @while @count(400) le 10 @do
           @pmsg(hello)
           @addcount(400,1)
        @wend
        @cont
     @endif
     @lc
     
     @verb hello @endverb
     @msg hello @msgtxt Hello! @endmsg
     
@rem *************************************************************************

@rem I'm going to create two vases. The first is a 'fragile vase', the second
     is a broken vase. The fragile vase will start off being carried by 
     Simon. If this vase is dropped, it will be replaced with the broken one.

     We need to make sure that the command is not compound, i.e. we are
     going to allow 'PUT THE VASE IN THE BED' without it breaking!

@obj		aa_vase
@objsht		a vase
@objlng 	This vase looks valuable, AND fragile.
@objroom	In_simon
@objpnt		25
@endobj

@obj		ab_vase
@objsht		a broken vase
@objlng 	This vase WAS fragile. It is now broken!
@endobj

@low 
@if @verbnois(drop) and @nounnois(aa_vase) and (not @iscompound) and 
    (not @roomis(in_bed)) @do
   @pmsg(smash)
   @drop(aa_vase)
   @swap(aa_vase,ab_vase)
   @cont
@endif
@lc

@msg	Smash
@msgtxt S-M-A-S-H-!
@endmsg

@rem *************************************************************************

@rem Okay, let's go back to our RUB verb! If we rub the lamp, a genie pops 
     out and drops a gem. If we rub anything else, we get a nice corny message.
     We also need to make sure that the genie only appears ONCE!! Let's 
     add a touch of humour as well - what if the player rubs an active object?
     
     @low 
     @if @verbnois(rub) @do
        @if @nounnois(lamp) and @count(lamp) eq 0 @do
           @pmsg(genie_stuff)
           @toroom(@thisroom,gem)
           @setcount(lamp,1)
        @else @do
           @if @isactive(@thisobj) @do
              @pobjs(@thisobj)
              @pmsg(slaps_your_face)
           @else @do
              @pmsg(now_shiny)
           @endif
        @endif
        @cont
     @endif
     @lc
     
     @obj gem @objsht a gem @objpnt 10 @endobj

     @msg    genie_stuff
     @msgtxt POOF! A genie pops out of the lamp, curses when he sees you,
             and then pops right back in. I think he dropped something!
     @endmsg
     
     @msg    Slaps_your_face
     @msgtxt slaps your face!
     @endmsg
     
     @msg    Now_shiny
     @msgtxt Okay, it's nice and shiny now!
     @endmsg

     @rem I'm defining the genie for completeness - so when the player types
          'EXAMINE GENIE' he won't be told there is no object by that name!
          
     @obj genie @endobj
          
@rem *************************************************************************

@rem Okay, here's an example of interpreting a compound command:

     If the player tries to give the blue key to harry, he won't take it!

@if @verbnois(give) and @nounnois(blue_key) and @iscompound and 
    @cverbnois(to) and @cnounnois(harry) @do
   @pmsg(harry_doesnt_want_blue_key)
   @cont
@endif

@msg    Harry_doesnt_want_blue_key
@msgtxt Harry doesn't want the blue key!
@endmsg

@rem *************************************************************************


@rem C Adventure Toolkit (CAT) - Tutorial #5

@rem This last tutorial demonstrates some tricks.
     Before reading this tutorial, have a look at FIRST.D and LAST.D

@rem *************************************************************************

@rem After CAT has completed all low priority logic without being stopped
     (i.e. the STOP logic token has not been encountered) - THEN it will go 
     on to see if the verb matches a ROOMPTH for the current room. If it 
     does, then the player will be moved to the new room.

     If you want to sometimes 'block' players from taking a certain, path
     you must block it in the low priority logic using the STOP logic token.
     THE CONT logic token will not work!

     In this example, Harry will occasionally block the player from using
     'North' go get from the hallway to the bathroom. Remember...........
     YOU MUST USE STOP, or CAT will continue and allow you to take the path
     anyway!

     @low 
     @if @roomis(hallway) and @verbnois(north) and @random(5) eq 1 @do
        @pmsg(harry_wont_let_you_past)
        @stop
     @endif

     @msg 	Harry_wont_let_you_past
     @msgtxt	Harry stands in your way!
     @endmsg

@rem *************************************************************************

@rem I'm going to create another layer to the house, and the stairs between
     the two floors.

@obj 		aa_stairs
@objsyn		aa_stair
@objsht         a flight of stairs going down
@objroom	hallway
@objngt
@objportal	downstairs_hallway
@endobj

@obj 		ab_stairs
@objsyn		ab_stair
@objsht         a flight of stairs going up
@objroom	downstairs_hallway
@objngt
@objportal	hallway
@endobj

@room		Downstairs_hallway
@roomsht	Downstairs hallway.
@roomlng	You are in the downstairs hallway.
@roompth	east,lounge north,kitchen
@endroom

@room		Lounge
@roomsht	Lounge.
@roomlng	You are in the lounge.
@roompth	west,downstairs_hallway north,dining_room
@endroom

@room		Dining_room
@roomsht	Dining room.
@roomlng	You are in the dining room.
@roompth	west,kitchen south,lounge
@endroom

@room		Kitchen
@roomsht	Kitchen.
@roomlng	You are in the kitchen.
@roompth	east,dining_room south,downstairs_hallway
@endroom

@rem *************************************************************************

@rem Now, let's animate Bob a touch more. We'll give him a random chance of 
     walking around rooms, taking the 'obvious exits' - i.e. ROOMPTHs.
     We could make Bob do whatever we wanted - he could be a real character!

     If the player is Bob, he's already following a command, so leave him be.
     If the player isn't Bob, we'll animate him. First of all, we have to save
     the current player (in counter 450). Then we say we want to control Bob-
     from now on Bob is the current player. Now we come up with a random number
     between 1 and 6, corresponding to North,East,South,West,Up,Down - we store
     this number in counter 449. Now we check to see if the path corresponding
     to counter 449 is a valid path. If it is, then we'll move Bob (I have used
     TOROOM rather than GOTO so we don't get a room description). If Bob is 
     moving from the room of the player (counter 450), then print a message 
     'Bob leaves to the ...'. If Bob is moving into the room of the player
     (counter 450), then print a message 'Bob enters from the ...'.
     Last of all, we need to restore control to the original player (count 450)

     Note up/down relate to climbing either ab_stairs or aa_stairs.

@high
@if (not @playeris(bob)) @do
   @setcount(450,@player)
   @setcount(449,@random(6))
   @control(bob)
   @if @count(449) eq 1 and @verbpath(north) ne -1 @do
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_goes_north)
      @endif
      @toroom(@verbpath(north),@player)
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_enters_from_south)
      @endif
   @endif
   @if @count(449) eq 2 and @verbpath(east) ne -1 @do
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_goes_east)
      @endif
      @toroom(@verbpath(east),@player)
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_enters_from_west)
      @endif
   @endif
   @if @count(449) eq 3 and @verbpath(south) ne -1 @do
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_goes_south)
      @endif
      @toroom(@verbpath(south),@player)
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_enters_from_north)
      @endif
   @endif
   @if @count(449) eq 4 and @verbpath(west) ne -1 @do
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_goes_west)
      @endif
      @toroom(@verbpath(west),@player)
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_enters_from_east)
      @endif
   @endif
   @if @count(449) eq 5 and @ishere(ab_stairs) @do
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_goes_up)
      @endif
      @enter(ab_stairs)
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_enters_from_down)
      @endif
   @endif
   @if @count(449) eq 6 and @ishere(aa_stairs) @do
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_goes_down)
      @endif
      @enter(aa_stairs)
      @if @ishere(@count(450)) and (not @isdark) @do
         @pmsg(bob_enters_from_up)
      @endif
   @endif
   @control(@count(450))
@endif

@msg 	Bob_goes_north
@msgtxt Bob goes north.
@endmsg

@msg	Bob_enters_from_north
@msgtxt Bob enters from the north.
@endmsg

@msg 	Bob_goes_east
@msgtxt Bob goes east.
@endmsg

@msg	Bob_enters_from_east
@msgtxt Bob enters from the east.
@endmsg

@msg 	Bob_goes_south
@msgtxt Bob goes south.
@endmsg

@msg	Bob_enters_from_south
@msgtxt Bob enters from the south.
@endmsg

@msg 	Bob_goes_west
@msgtxt Bob goes west.
@endmsg

@msg	Bob_enters_from_west
@msgtxt Bob enters from the west.
@endmsg

@msg 	Bob_goes_up
@msgtxt Bob goes up the stairs.
@endmsg

@msg	Bob_enters_from_up
@msgtxt Bob comes down the stairs.
@endmsg

@msg 	Bob_goes_down
@msgtxt Bob goes down the stairs.
@endmsg

@msg	Bob_enters_from_down
@msgtxt Bob comes up the stairs.
@endmsg

@rem *************************************************************************

@rem I am now going to introduce Molly - she lives in the kitchen. When she
     sees Bob, she will give him the key to the cupboard (the iron key).
     Otherwise, she'll get on with a random mundane task!

@obj 		Molly
@objsht		Molly
@objlng		Molly is the kitchen maid.
@objroom	Kitchen
@objngt
@objact
@objstr		40
@objinrm	In_molly
@endobj

@room In_molly @endroom

@obj		Cupboard
@objsht		a cupboard
@objlck		locked
@objkey		iron_key
@objroom	Kitchen
@objinrm	In_cupboard
@objngt
@objstr		60
@endobj

@room In_cupboard @endroom

@obj 		Iron_key
@objsht		an iron key
@endobj

@obj		ladle
@objsht		a golden ladle
@objpnt		50
@objwgt		5
@objroom	in_cupboard
@endobj

@rem Note: I am referencing the messages Molly_task_[1-4] indirectly, 
     by number. I find the number of Molly_task_1. I know that Molly_task_2
     is equal to Molly_task_1 + 1, because one occurs after the other!

@high
@if @iswith(molly,bob) and @count(molly) eq 0 @do
   @setcount(molly,1)
   @toroom(@objinrm(bob),iron_key)
   @if @playeris(bob) @do
      @pmsg(molly_gives_key_to_you)
   @else
      @if @ishere(molly) @do
         @pmsg(molly_gives_key_to_bob)
      @endif
   @endif
@else @do
   @if @ishere(molly) @do
      @setcount(450,@random(4))
      @addcount(450,@msgno(molly_task_1))
      @subcount(450,1)
      @pmsg(@count(450))
   @endif
@endif

@msg 	Molly_gives_key_to_you
@msgtxt	Molly pats you on the head, and gives you an iron key.
@endmsg

@msg	Molly_gives_key_to_bob
@msgtxt Molly pats Bob on the head, and gives him something.
@endmsg

@msg	Molly_task_1
@msgtxt Molly kneads some bread.
@endmsg

@msg	Molly_task_2
@msgtxt	Molly washes some dishes.
@endmsg

@msg	Molly_task_3
@msgtxt	Molly washes the windows.
@endmsg

@msg	Molly_task_4
@msgtxt	Molly cleans the floor.
@endmsg

@rem *************************************************************************

@rem Now, I'm going to be a bit sneaky! I'll create a hidden object 'floor'
     in the kitchen. When the player examines it the first time, he won't 
     find anything BUT if he examines it a second time then he will find a 
     tiny diamond! If he examines it more than twice he will be told there
     is nothing else!

     (I'll also create bread, and dishes for completeness)

@obj 		floor
@objhide
@objngt
@objroom	Kitchen
@endobj

@obj 		bread
@objhide
@objngt
@objroom	Kitchen
@endobj

@obj 		dishes
@objsyn		dish
@objhide
@objngt
@objroom	Kitchen
@endobj

@obj		diamond
@objsht 	a tiny diamond
@objlng		No wonder you missed this... it really is tiny!
@objpnt		20
@endobj

@rem Notice, the first time we examine the floor, we just add one to the 
    counter and then fall through to the default logic in ZZSTD 'nothing'.

@low 
@if @verbnois(examine) and @nounnois(floor) @do
   @addcount(@thisobj,1)
   @if @count(@thisobj) eq 2 @do
      @pmsg(found_diamond)
      @toroom(@thisroom,diamond)
      @cont
   @endif
   @if @count(@thisobj) gt 2 @do
      @pmsg(nothing_else_here)
      @cont
   @endif
@endif

@msg 	found_diamond
@msgtxt Oh look, there is something here after all, you have just found a 
        tiny diamond.
@endmsg

@msg	Nothing_else_here
@msgtxt No, there isn't anything else.
@endmsg

@rem *************************************************************************

@rem What about the window that Molly is cleaning? Let's create it now,
     but it will be hidden. The window is actually a doorway between the  
     kitchen and garden, where the player will find a golden gnome!

@obj 		windows
@objsyn		window
@objhide
@objngt
@objdoor	kitchen,garden
@objlck		closed
@endobj

@room		garden
@roomsht	Garden.
@roomlng	You are in a beautiful, and well tended garden.
@roompth	leave,carried
@endroom

@obj		gnome
@objsht		a golden gnome
@objroom	garden
@objpnt		30
@objwgt		20
@endobj

@rem Some atmosphere here I think!

@high
@if @isopen(windows) and @roomis(kitchen) @do @pmsg(draught) @endif

@msg 	draught 
@msgtxt A gentle draught blows in through the window.
@endmsg

@rem Good old Molly might shut the window.

@if @isopen(windows) and @random(3) eq 1 @do
   @close(windows)
   @if @ishere(windows) @do
      @pmsg(molly_closes_window)
   @endif
@endif

@msg 	Molly_closes_window
@msgtxt Molly tuts and closes the window.
@endmsg

@rem *************************************************************************

@rem Another nail in the coffin.... Once Bob has the iron key.... he might
     give it to Harry - and then the player can never get it back!!!!!!!

     You can see we have built inter-relationships between the characters
     in this adventure. They can happily go about their business without 
     the player knowing anything. The possibilities are endless!

     The scenario now is... Bob goes to see Molly to get the key, he then
                            goes and gives the key to Harry!

@high 
@if @iswith(bob,harry) and @iscarriedby(iron_key,bob) and @random(2) @do
   @toroom(@objinrm(harry),iron_key)
   @if @ishere(bob) and (not @isdark) @do
      @pmsg(bob_gives_key_to_harry)
   @endif
@endif

@msg 	Bob_gives_key_to_harry
@msgtxt	Bob gives something to harry.
@endmsg

@rem *************************************************************************

@rem One more trick, we'll give the lampp a limited lifespan.
     It can be alight for 30 turns. 
     
     @high 
     @if @islit(lamp) @do
        @addcount(200,1)
        @if @count(200) eq 30 @do
           @unlight(lamp)
           @if @isavail(lamp) @do
              @pmsg(lamp_goes_out)
           @endif
        @endif
     @endif

     @low
     @if @verbnois(light) and @nounnois(lamp) and @count(200) eq 30 @do
        @pmsg(no_fuel)
        @cont
     @endif

     @msg	lamp_goes_out
     @msgtxt    Phut! The lamp goes out!
     @endmsg

     @msg  	No_fuel
     @msgtxt    Sorry, there is no fuel left!
     @endmsg

@rem *************************************************************************
@rem ****************           End of Tutorial #5           *****************
@rem *************************************************************************

@rem Okay, we have covered a lot of ground - but we haven't covered all of 
     the features of CAT. I hope that by now, you have enough of an overview
     of CAT to experiment with your own adventures. Remember that there is 
     a cross reference manual in CATMAN.TXT, and that the program CATHELP
     is a very useful method of quickly scanning the manual by keyword.

     It might be a good idea to generate this tutorial now so that you
     get an idea of the processing involved.


     Cheerio, and thanks for attending!

	Tony



