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



@rem This file cannot be generated, but tutor4.d can.



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



@rem CAT provides three distinct logic modes. These are initialisation

     logic (executed once at the start of the adventure), low priority logic

     (used to interpret player commands), and high priority logic 

     (executed each turn regardless of players command). The three tokens

     INIT, LOW, and HIGH tell CAT which type of logic it should be creating.

     You can switch between logic modes at any time by using these logic

     switch tokens.

     

     *** ONLY LOW PRIORITY LOGIC CAN ACCESS THE PLAYERS COMMAND ***



     CAT logic is processed in the order it is encountered in the definition

     files. Because we are including our files before the ZZSTD files, the

     order of processing will be:



       Our initialisation logic    | Before the first

       ZZSTD initialisation logic  |      game turn



         Our low priority logic    | After every 

         ZZSTD low priority logic  |    valid command



         Our high priority logic   | After every 

         ZZSTD low priority logic  |     command (valid or not)



     Because of this ordering, we can use ZZSTD as a 'trap-all', with all

     our custom logic being processed before it.



     Here's an example of each type of logic. Don't worry if you don't fully

     understand them yet - I will explain shortly.



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



@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



@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 CAT provides 500 counters to be used in logic code.

     These are numbered from 0 to 499. Counters 451->499 are reserved 

     for use by the standard files ZZRQD.D and ZZSTD.D



     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.

 

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



@rem CAT has a massive set of logic tokens. I am going to list each one,

     and give a brief explanation of it. Don't worry about fully understanding

     them now, they are just here so you can get an idea what is available:



     The following logic tokens return a TRUE/FALSE answer

     =====================================================



     @CONFIRM                  : Waits for 'Y/y' or 'N/n' to be pressed.

                                 Returns TRUE if 'Y/y' pressed.



     @ISCOMPOUND               : Returns TRUE if command is compound

                                 i.e. 'TAKE x FROM y'.



     @VERBIS("text")           : Returns TRUE if the verb is a synonym for

                                 "text". You should avoid this, @VERBNOIS

                                 is faster.



     @VERBNOIS(verb)           : Returns TRUE if the verb number = verb. You

                                 must use the actual verb name, NOT a synonym.



     @CVERBIS("text")          : Returns TRUE if the compound verb is a synonym

                                 for "text". You should avoid this, @CVERBNOIS

                                 is faster.



     @CVERBNOIS(verb)          : Returns TRUE if the compound verb number equals

                                 verb. You must use the actual verb name, 

                                 NOT a synonym.



     @ISPATH(verb)             : Returns TRUE if verb is a valid path.



     @CHECK(C,L,obj)           : Performs checking within CAT logic. 

                                 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 is returned if the tests are passed.

                                 

     @NOUNIS("text")           : Returns TRUE if the noun is a synonym for

                                 "text". You should avoid this, @NOUNNOIS

                                 is faster.



     @NOUNNOIS(obj)            : Returns TRUE if the noun number = obj. You

                                 must use the actual object name, NOT a synonym.



     @CNOUNIS("text")          : Returns TRUE if the compound noun is a synonym

                                 for "text". You should avoid this, @CNOUNNOIS

                                 is faster.



     @CNOUNNOIS(obj)           : Returns TRUE if the compound noun number equals

                                 obj. You must use the actual object name,

                                 NOT a synonym.



     @OBJHASL(obj)             : Returns TRUE if obj has a long description.



     @ISIN(obja,objb)          : Returns TRUE if obja is inside objb.

                                 This is identical to @ISCARRIEDBY

                                 

     @ISWITH(obja,objb)        : Returns TRUE is obja is in same room as objb.



     @ISEXIT(obj)              : Returns TRUE if obj is an exit.

                                 i.e. a DOOR or a PORTAL.



     @ISREADABLE(obj)          : Returns TRUE if obj is readable.



     @ISHIDDEN(obj)            : TRUE if obj is hidden.



     @ISWORN(obj)              : TRUE if obj is worn by current player.



     @ISWORNBY(obja,objb)      : TRUE if obja is worn by objb.



     @ISWORNANY(obja)          : TRUE if obja is worn by any object.



     @ISWEARABLE(obj)          : TRUE if obj can be worn.



     @ISHERE(obj)              : TRUE if obj is in same room as current player.



     @ISCARRIED(obj)           : TRUE if obj is carried by current player.



     @ISCARRIEDBY(obja,objb)   : TRUE if obja is carried by objb.

                                 This is identical to @ISIN.



     @ISAVAIL(obj)             : TRUE if @ISHERE(obj) or @ISCARRIED(obj).



     @ISEDIBLE(obj)            : TRUE if obj is edible.



     @ISDRINKABLE(obj)         : TRUE if obj is drinkable.



     @ISLIGHT(obj)             : TRUE if obj is a lightsource.



     @ISLIT(obj)               : TRUE if obj is alight.



     @ISMOVABLE(obj)           : TRUE if obj is movable.



     @ISLOCKED(obj)            : TRUE if obj is locked.

   

     @ISCLOSED(obj)            : TRUE if obj is closed.



     @ISOPEN(obj)              : TRUE if obj is open.



     @ISBOX(obj)               : TRUE if obj has an in-room, and is not

                                 an active object.



     @PLAYERIS(obj)            : Returns TRUE if the current player = obj.

 

     @CPLAYERIS(obj)           : Returns TRUE if the commanding player = 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 = the current player.



     @ISPLAYER(obj)            : TRUE if obj is a player object, and is active.

                                 i.e. can user BECOME obj.



     @ISCOMMANDABLE(obj)       : TRUE if obj is commandable, and is active i.e.

                                 can user use command 'obj, GET HAT'.



     @ISACTIVE(obj)            : TRUE if obj is active, i.e. alive.



     @ROOMIS(room)             : Returns TRUE if the current room = room.



     @OBJROOMIS(room,obj)      : Returns TRUE if obj is in room.



     @ISDARK                   : TRUE if it is dark in the current players 

                                 room, and there are no lit objects present.





     The following logic tokens return a value 

     =========================================

     

     @PLAYER                   : object number of current player.

     

     @CPLAYER                  : object number of commanding player.

     

     @TURNS                    : number of turns player has taken.

     

     @SCORE                    : the current score.

     

     @THISOBJ                  : number of object referred to by the players

                                 command, or -1 if none.

     

     @THISCOBJ                 : number of compound object referred to by the

                                 players command, or -1 if none.

                                 

     @THISVERB                 : number of verb referred to by the players 

                                 command, or -1 if none.

                                 

     @THISCVERB		       : number of compound verb referred to by the 

                                 players command, or -1 if none.



     @THISROOM                 : room number of current room.

     

     @RANDOM(x)                : random number between 1 and x (inclusive).

     

     @COUNT(cnt)	       : Value of counter cnt.

     

     @VERBPATH(verb)	       : the room number that verb would lead to, 

                                 or -1 if it is not a valid path.

     

     @ROOMNO(room)             : The room number of room.

     

     @MSGNO(msg)               : The message number of msg.

     

     @OBJNO(obj)               : The object number of obj.

     

     @STRENGTH(obj)            : the strength of obj.

     

     @WEIGHT(obj)              : the total weight of obj (includes carried).

     

     @SIZE(obj)                : the weight of obj, without carried weight.

     

     @CARRIED_WEIGHT(obj)      : the total weight carried by obj.

                                 This includes the weight of objects in 

                                 other objects that are carried.

                                 

     @POINTS(obj)              : the number of points obj is worth.

     

     @OBJRM(obj)               : the room number obj is currently in.

      

     @OBJINRM(obj)             : the in-room of obj. (NOWHERE if no in-room).

     

     @FIRSTOB(room)	       : number of first object in room, or -1 if none.

     

     @LASTOB(room)	       : number of last object in room, or -1 if none.

     

     @VALUE(obj)	       : the value of obj.

     

     @OBJKEY(obj)              : the number of the object that is required 

                                 to lock/unlock obj (NO_KEY if no key).

                                 

     @LOCKTYPE(obj)            : the lock type of obj. Could be any of:

                                 LOCKED, CLOSED, OPEN, NO_LOCK.



                                 

     The following logic tokens do something 

     =======================================

     (these are blind servants - they do what you tell them without checking)



     

     @SCRIPT                   : Start script mode - all output echoed to PRN:

     

     @UNSCRIPT                 : End script mode.

     

     @VERBOSE                  : Start verbose mode - long room descriptions 

                                 will always be given.

                                 

     @BRIEF                    : End verbose mode.

     

     @SAVE                     : Ask for 8 char file name, and save the game.

     

     @LOAD                     : Ask for 8 char file name, and restore game.

     

     @STOP                     : Stop processing of low priority logic,

                                 and kill the rest of the command line.

                                 

     @CONT                     : Stop processing low priority logic,

                                 do not kill the command line.

                                 

     @ENDGAME                  : End the game, print the score and the

                                 number of turns taken.

                                 

     @WAITKEY		       : Wait for a key press.

     

     @VOCAB                    : Print a list of all verbs.

     

     @LOOK		       : prints long description of current room

     

     @INVENTORY                : print the inventory of the current player

     

     @WHOAMI                   : Print 'You are:' and the short text for 

                                 the current player.

                                 

     @NEWLINE                  : Print a linefeed character (same as @LF).

     

     @LF                       : Print a linefeed character (same as @NEWLINE).

     

     @PROOMS(room)             : Print short description for room.

     

     @PROOML(room)             : Print long description for room.

     

     @POBJS(obj)               : Print short description for obj.

     

     @POBJL(obj)               : Print long description for obj.

     

     @PMSG(msg)                : Print message msg.

     

     @PEXITS                   : Print obvious exits leading from room.

                                 (ie ROOMPTH)

    

     @PCONTENTS(obj)           : Print a list of all the objects in the 

                                 in-room for obj.

                                 

     @PNUM(val)                : Print the numeric value val.

     

     @ENDCHAR('c')             : The next piece of text that is printed

                                 will have character 'c' appended.

                                 

     @GOTO(room)               : move the current player to room, and give a 

                                 long or short description depending on 

                                 whether room has already been visited or not.

                                 

     @MAKELIGHT(room)          : Make room light.

     

     @MAKEDARK(room)           : Make room dark.

     

     @SETCOUNT(cnt,val)        : Set counter cnt to val.

     

     @ADDCOUNT(cnt,val)        : Add val to counter cnt.

     

     @SUBCOUNT(cnt,val)        : Subtract val from counter cnt.

     

     @SETPOINTS(obj,val)       : Set the points of obj to val.

     

     @ADDPOINTS(obj,val)       : Add val to the points of obj.

     

     @SUBPOINTS(obj,val)       : Subtract val from the points of obj.

     

     @SETSTRENGTH(obj,val)     : Set the strength of obj to val.

     

     @ADDSTRENGTH(obj,val)     : Add val to the strength of obj.

     

     @SUBSTRENGTH(obj,val)     : Subtract val from the strength of obj.

     

     @SETVALUE(obj,val)        : Set the value of obj to val.

     

     @ADDVALUE(obj,val)        : Add val to the value of obj.

     

     @SUBVALUE(obj,val)        : Subtract val from the value of obj.

     

     @SETWEIGHT(obj,val)       : Set the weight of obj to val.

     

     @ADDWEIGHT(obj,val)       : Add val to the weight of obj.

     

     @SUBWEIGHT(obj,val)       : Subtract val from the weight of obj.

     

     @BECOME(obj)              : make obj the current player, and also

                                 the commanding player.

     

     @CONTROL(obj)             : make obj the current player - useful for

                                 controlling active objects in high priority

                                 logic. DOES NOT CHANGE commanding player.

                                 

     @ADDPLAYER(obj)           : Make obj a player object, commandable, active.

     

     @REMOVEPLAYER(obj)        : Make obj not a player object.

     

     @ADDCOMMAND(obj)          : Make obj commandable, active.

     

     @REMOVECOMMAND(obj)       : Make obj not commandable.

     

     @REVIVE(obj)              : Make obj active.

     

     @KILL(obj)                : Make obj not active.

     

     @REMOVE(obj)              : make obj wearable, but not worn.

     

     @WEAR(obj)                : make obj worn.

     

     @DROP(obj)                : move obj to the room of the current player.

     

     @GET(obj)                 : move obj to the current players in-room.

     

     @EAT(obj)                 : move obj to NOWHERE.

     

     @DRINK(obj)               : move obj to NOWHERE.

     

     @LIGHT(obj)               : make obj lit.

     

     @UNLIGHT(obj)             : make obj unlit, but a lightsource.

     

     @LOCK(obj)                : change locktype of obj to LOCKED.

     

     @UNLOCK(obj)              : change locktype of obj to CLOSED.

     

     @OPEN(obj)                : change locktype of obj to OPEN.

     

     @CLOSE(obj)               : change locktype of obj to CLOSED.

     

     @ENTER(obj)               : move player to the room that obj points to

                                 (as defined by OBJDOOR, OBJPORTAL).

                                 

     @READ(obj)                : print the read message for obj.

     

     @TOROOM(room,obj)         : Move obj to room.

     

     @SWAP(obja,objb)          : swap the rooms of obja and objb.

     

     @FVERB("text")            : Force the verb to "text".

     

     @HIDE(obj)                : Make obj hidden.

     

     @UNHIDE(obj)              : Make obj not hidden.

     

     @PAUSE(sec)	       : Pause for sec seconds.



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



@rem CAT logic tokens can be nested. In the code below, I am using the 

     @ROOMNO logic token inside the @SETCOUNT logic token. What is this doing?

     First of all, it obtains the room number for the room IN_BED, then it 

     places this value in counter 496........

       processing will always be from the inside to the outside.

     

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



@rem The player will only get a score for objects that are in the bed!



     @init

     @setcount(496,@roomno(in_bed))



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



@rem I could have done the above in a more long-winded way like this:



     @init

     @setcount(400,@roomno(in_bed))

     @setcount(496,@count(400))



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



@rem Now, we need a way to condition our processing within CAT logic. CAT 

     supplies the following tokens @IF, @ELSE, @ENDIF, @WHILE, @WEND, @DO

     

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



@rem The following will print 'Bob says Hello.' if the player is in the same

     room as BOB, and @RANDOM(10) returns 1 (i.e. 10% chance).

     

     The syntax is {if this and this are true, then do this}.

     

     Pay careful attention to the @DO token - it tells CAT that this is 

     the end of the condition, and the rest is what we want to DO!

     

     Also note the @ENDIF token. Every @IF must have a matching @ENDIF.

     

     @high

     @if @ishere(bob) and @random(10) eq 1 @do

        @pmsg(bob_says_hello)

     @endif

     

     @msg    Bob_says_hello

     @msgtxt Bob says Hello!

     @endmsg

    

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



@rem We could have done the above like this:



     Note here, the first @IF condition doesn't have an @DO token after it.

     This is because there is nothing to do, yet! I could have put an @DO

     token after each @IF, but it isn't required unless you are going to 

     DO something.

     

     Also note that because I have two @IF tokens, I also need two @ENDIFs.

     

     It is a matter of personal preference which approach you take.

     

     @high

     @if @ishere(bob)

        @if @random(10) eq 1 @do

           @pmsg(bob_says_hello)

        @endif

     @endif



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



     You don't actually need to neatly space logic. The following

     is strictly okay, but rather more difficult to read:

     

     @high @if @ishere(bob) @if @random(10) eq 1 @do @pmsg(bob_says_hello)

     @endif @endif

           

     (I would advise you to space out logic!!!)

     

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



@rem Did you notice I used 'and' and 'eq'? Well these are ways in which you

     can compare things in CAT logic. Heres a table of comparison tokens:

     C programmers may notice something here!

     

     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       !

     

     To test whether counter 1 was equal to counter 2, we could use:

          @if @count(1) eq @count(2) @do....

     OR   @if @count(1) == @count(2) @do....

     

     To test whether counter 1 was different to counter 2, we could use:

          @if @count(1) ne @count(2) @do....

     OR   @if @count(1) != @count(2) @do....

     

     To test whether counter 1 was greater than counter 2, we could use:

          @if @count(1) gt @count(2) @do....

     OR   @if @count(1) >  @count(20 @do....

     

     To test that counter 1 is greater than counter 2, but less than 3:

     

          @if @count(1) gt @count(2) and @count(1) lt 3 @do....

     OR   @if @count(1) > @count(2) 

             @if @count(1) < 3 @do....

             

     To test whether either counter 1, or counter 2 equal counter 3:

          @if @count(1) eq @count(3) or @count(2) eq @count(3) @do....

     OR   @if @count(1) == @count(3) || @count(2) eq @count(3) @do....

     

     If we wanted to make sure TONY is here, and active we could use:

          @if @isactive(tony) and @ishere(tony) @do....

          

     If we wanted to make sure TONY is NOT active, but that he is here:

          @if (not @isactive(tony)) and @ishere(tony) @do....

              ^                   ^

     Notice that I have protected the NOT condition. It is important that

     you protect NOT conditions with ( and ), or otherwise you will not

     get the results you intended - this is because of the order of 

     processing of NOT within C. If you are a programmer, you will know

     what I am talking about - if you are not, you don't need to know!

                    

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



@rem Okay, what if we want to do one thing if a condition is true, otherwise 

     we want to do another thing. We can use @IF @ELSE @ENDIF.

     

     After each turn: If the toilet is here, print 'The toilet is here.',

                      otherwise print 'The toilet isn't here.'

                      

     @high

     @if @ishere(toilet) @do 

        @pmsg(toilet_here)

     @else @do

        @pmsg(toilet_not_here)

     @endif

     

     @msg    Toilet_here

     @msgtxt The toilet is here.

     @endmsg

     

     @msg    Toilet_not_here

     @msgtxt The toilet isn't here.

     @endmsg

     

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



@rem We can negate the above condition, like this:



     @high

     @if (not @ishere(toilet)) @do 

        @pmsg(toilet_not_here)

     @else @do

        @pmsg(toilet_here)

     @endif

     

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



@rem Ocassionally, you will want to perform a given set of logic until a 

     given test fails. You can use @WHILE @WEND to do this.

     

     @WHILE is very similar to @IF. Each @WHILE must have a matching @WEND.

     @WHILE cannot have an @ELSE! An @WHILE loop will repeat the enclosed

     logic until the given conditions fail. 

     

     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

     

     @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



@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

     

     @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 One last thing... when you have a lot of logic it is easy to miss out a

     @ENDIF or a @WEND token. CAT will report on these whenever you switch

     from one logic mode to another (INIT/LOW/HIGH). But you can also

     force a logic check at the end of a group of logic with the @LC

     (logic check token). It is wise to use this when you are developing!



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



@rem This tutorial has covered a lot of ground. You should now be able to 

     understand tutor4.d. It contains some of the code from this file, and

     some extra. Have a look at it now - it should make sense!



     (I have used the @LC token in tutor4.d)

     

     When you think you understand the contents of tutor4.d, have another

     look at \CAT\STD\ZZSTD.D - you should be able to understand exactly 

     what is going on now... you will be able to see what processing is 

     provided for you, and therefore what you need to supply for yourself!

     

     When you have reviewed ZZSTD, go on to the last tutorial (#5), where

     I will be explaining a few interesting tricks.

 

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

@rem ****************           End of Tutorial #4           *****************

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

