*** 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