MobScripts
----------

The MobScripts are a fundamentally useful form similar to MobProgs.  MobProgs,
in their current state, are the buggiest things I have _ever_ seen, and even
the guys at Merc decided to have you people extricate them from your code.
Either way, I'll put on a Beatles album and explain my replacement.

MobScripts, written completely by           /---------------------------------\
Herb Gilliland, and are copyrighted        | In the town where I was born
1994 to Herb Gilliland.  All rights        | lived a man who sailed to sea
reserved.  You are free to distribute,     | and he told us of his life
modify, clip, copy or critique the code,   | in the land of submarines
documentation and overall package as long  | so we sailed out to the suns
as credit is given to its original         | til we found the sea of greens
author.                                    | and we lived beneath the waves
                                           | in a yellow submarine
MercMUD is copyrighted to Merc Industries. \---------------------------------/

Enough formality:

MobScripts are based, as MobProgs are, on a set of commands organized into
Triggers, or procedures, which are called a multitude of different ways.

Currently, the scripts work on the premise of unlimited variables, and are
stored in a variety of lists on the mobile that is running.  The original
version of the scripts is copied from the mobile index onto the mobile when
the mob is created.

This:                                   > variables
                                        |
Index 7                                Mob 7
 |                                      |
 >  script          created mob         > script
 |                                      |
 >  script                              > script

Thus each mob has a list of variables and of triggers.  Each trigger is
a list of commands.  Look at it this way:

               > variable
               |
               > variable
               |
              MOBILE
               |       trigger 1
               >-------------
   trigger 2   |            |
     ----------<    command <
     |                      |
     > command      command <
     |                      |
     > command      command <

WARNING: Variables can be accessed by any trigger, so try to use unique
variable names unless you actually WANT crossing of triggers.  Which could
be useful.

Ok, so thats the basic outline of how the mob looks in memory, its easier
once you get it into the file.  Now, here is how a mobile is assigned
a script: by filename.  In the online editor, you can set the mobile's
script to be loaded, upon next reboot, into that mobile.  Remember,
each mobile that has a script has its own copy of that script.

If the script guard.scr takes 400 bytes of memory:

Mob1 -> guard.scr                            400
Mob2 -> gaurd.scr                            400
Existing Mob1 (mload'd) -> guard.scr         400
Existing Mob2 (mload'd) -> guard.scr      +  400
                                          ------
                                            1600 bytes total

Now, lets look at how you code.

First, you have to do it offline.  Its too much of a risk coding scripts
online.  Second, you have to be careful what commands you use.  If you have
a mobile that advances people every time you pass them, does this make sense?
Probably not.  Even if you only have 1 mob loaded, there is a good chance
that you can run past them over and over again, etc.  Now, there are ways to
cap such a mobile.   There are also ways to get two mobiles to recurse into
each other.  There are easy ways to add infinite loops, aside from the update
loops, as well as getting a mob to indefinitely do something over and over
again.

Possible uses of MobScripts:

Quests
Creating an interactive countryside
Creating intelligent responses to world actions
Creating informative, talkative and eccentric mobiles
Adding to the realism of the game
Improving a mobs' combat or magical ability

Like a programming language, Mobscripts has its own rules and syntax.
Lets look at a sample file, used on the old Isles before I removed the town
it was written for:

#TRIGGER payguard
*
* Script: Gate guard
* Security: must have a bounty of less than or equal to 70
* Location Sensitivity: Yes, requires the gate to be the northern exit
* Triggers when: Someone says 'open the portcullis'
*
Keywords open the portcullis~
Type 6
*
* Check for the overall bounty of a player.  This is important if you are
* using these guards to keep theives/killers out.
*
* mfunc puts the player's bounty into a variable called %bounty%
* Note the use of four commands in a single execution
*
Sc
mfunc %payguard-from% %bounty% bounty
if (%bounty% > 70)
say Get out of here, scoundrel!
halt once~
*
* In pseudo-code:
*
* bounty = bounty of player that triggered the mob
* if (bounty > 70)
* {
*     You say, "Get out of here, scoundrel!"
*     end script execution
* }
* else go to next script command
*
Sc eyebrow %payguard-from%~
Sc nod~
Sc emote takes the key and unlocks the crank.~
*
* Ok, its ok to open the gate, so lets do it.
* wfunc grabs the vnum of the room to the north and puts in variable %north%
* then the mob unlocks/opens the gate, using the mob command, the player
* wont see:
*
* The guard takes the key and unlocks the crank.
* The guard unlocks the gate.
* The guard opens the gate.
* You watch as the heavy iron gate raises to a point high above you.
*
Sc
wfunc %north% north
mob unlock north
mob open north
recho You watch as the heavy iron gate raises to a point high above you.
at %north% recho The iron portcullis raises slowly.~
*
* In pseudo-code:
*
* north = vnum of the room just north of this location
* without showing anything, unlock the north exit and open it
* show the room "You watch ...."
* at the northern room, show that room "The iron portcullis raises slowly."
*
Sc say You may pass.~
*
* Waiting is the lame way of allowing someone to pass.  See, we have to close
* the gate anyways, so its best just to wait instead of checking if they are
* in the room.  It can be done, however.
* So we wait 20 or so seconds and then shrug indifferently, then do the
* closing commands to shut the place up again.
*
Sc wait 20~
Sc shrug~
Sc
emote slowly cranks the portcullis to the floor.
at %north% recho The iron portcullis closes slowly.
mob close north
mob lock north~
End
#END



Basic file structure:


#TRIGGER <single-word-no-spaces-unique>
Keywords <command-type dependant match>~
Type <number denoting how/when this is triggered>
* comments
Sc <command or commands>~
End

#TRIGGER <single-word-no-spaces-unique>
.
.
.
End

#END


Now, I know this ain't the best file in the world, but I hope you guys
can get what you can out of it until I can figure out how to write a new
one.  Now here we go, this is the list of the commands you can use and most
of the possible combinations.   Not all have been fully tested.  Its easy
to know when you've made a mistake, since it just wont work.  Now, not
everything is possible, there are some problems, but basically this is it.
After the command list is a small tutorial on how to manipulate variables,
while loops and a few other things.

---------commands------------------------------------------------------------

Nimud scripts.
     This script parser was begun on 5/7/94 by Herb Gilliland
(aka Locke of The Isles).  It was written to allow a more advanced mud
software to come into play.  The next_command() and multi_interpret()
routines were derived from the MOBprograms in Merc 2.2, and the work of
the buggy code of Natasha.  I found the whole MOBprograms to be bugged
to hell, and, since I myself didn't want to remain with the primitive
and crude script language that I developed, I wanted to make something
that was really useful.  I must thank the writers of MudOS (LpMUD) and
all MOOs, MUSEs, MUSHes and MUCKs, this really is based on the ideas
made by them.
                                     Enjoy.
See adjoining text for information on the syntax.


This little command helps a user debug the scripts online.  It can give
information about a single trigger, or general info on the mob's current
state of execution.


Syntax:  SCRIPT <mob> [<trigger>]

Script <mob> will show you the basic script information, variables currently
on the mob, and the triggers loaded, if any.

Script <mob> <trigger>  will show you the commands for an individual trigger,
this helps you in figuring out if the syntax is neglect or its a logical
error.


Syntax: MSIGN <mob> <value> <deliminator>

Msign is MOB-ASSIGN, which sets a variable on a mobile to a specific value.
The value can be a variable (%variable%) or it can be a number, string in ""s,
anything that would make sense as a value to set the deliminator to.  MSIGN
will take the deliminator, figure out what variable its addressing on the
actual mob structure, and convert the value to a numeral if required.  (if
you supply a string where a number is supposed to be, then the numeric value
will be 0).  Can be applied to players.  If the mob doesn't exist, the script
will halt itself.

hunting     - set the person who the mob is hunting
spectracer  - set the numeric value of the spec tracer
bounty      - set the monetary value of the bounty of the mob (players mainly)
exp         - set the experience earned of the mob
act         - set the act to a specific number
act2        - "   "
affected_by - set the affected_by to a specific number
practice    - set the practice points to a specific number
learn       - set the learns
sex         - set the sex (I think its a number (0,1,2), try 'male' tho)
race        - set the numeric value of the race of the mob
level       - CAREFUL - set the level
hit         - set the current hitpoints
maxhit      - set the maximum hitpoints
move        - set the move points
maxmove     - set the max move points
str
int          players only
dex
wis          set their attributes
con


Syntax: OSIGN <object> <value> <deliminator>

OSIGN is OBJECT-ASSIGN, and sets values on the physical object.  A number
for the deliminator denotes that object value, and the number must fall
between 0 and 9 (not 1 and 10).   If the object does not exist, the script
will halt itself (not exist=cannot be found).

cost          - set the monetary value of the object
wear_flags    - set its wear flags to a specific value
wear_loc      - set its current wear location (Careful)
weight        - set its weight
item_type     - set its item type
level         - set its level
timer         - set its current timer
extra_flags   - set its extra flags to a specific value
0,1,3 .. 9    - set a value[] on the object


Syntax: WSIGN <value> <deliminator>

WSIGN, aka WORLD-ASSIGN, assigns a global variable.  Currently, its rather
low.  In the future it would be nice if we could use OLC with mobiles,
but at this time you can't.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
MOBILES USING ONLINE CREATION COMMANDS (medit/oedit/redit/aedit) WILL CRASH
THE MUD.  YOU HAVE BEEN FORWARNED.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

hour
day
month             sets time/weather stuff
year
sunlight
mmhg
winddir
windspeed
temperature
weather




Syntax: WFUNC %variable-to-go-in% <what> [<min random> <max random>]

Grabs world stuff/random numbers.  Puts it in a variable.  Lets you get
random numbers.

What could be one of the following:

hour        - game hour  ( 0-23)
day         - game day   ( 0-31)
month       - game month ( 0-17)
year        - game year  ( 453 )
sunlight    - level of sunlight (see weather stuff)
mmhg        - mm of mercury
winddir     - 0-35
windspeed   -
temperature - in Farenheigt (argh I hate that word)
weather     - see weather stuff
topmob      - top vnum
topobj      - top vnum
toproom     - top vnum
random      -  requires two params, min and max, returns a random number
               in that range



Syntax: MFUNC <mob> %variable-to-go-in% <what>

Get values from a mobile.  Put it in a variable.  'self' denotes the mob
that is calling it.  If the mob doesnt exist it returns NOONE.

What could be one of the following:

position    - grabs the position off the mob     - 7 = standing  (etc)
gold        - grabs the tallied amount of coins
name        - grabs the name of the mob
hunting     - grabs who its hunting
room        - grabs the vnum of the room its in
specproc    - grabs the proc of it (mobs only)
spectracer  - grabs the tracer of it (mobs only)
bounty      - grabs the bounty value
exp         - grabs the experience value (how much earned)
expneeded   - grabs the experience value (how much needed for next level)
act         - grabs the act value (a numeric)
act2        - grabs the act2 value (a numeric)
affected_by - grabs the bits that affects this dude
practice    - grabs the practice points (players only)
learn       - grabs the learn points (players only)
hitroll     - hitroll val
damroll     - damroll val
age         - the age (17 for newbies etc, this is actually age * 2700)
sex         - 0, 1 or 2
race        - the race number of the player
level       - level
hit         - cur hits
maxhit      - max hits
move        - cur move
maxmove     - max move
str
int
dex                 players only - get their attribute levels
wis
con


Syntax: OFUNC <obj> %variable-to-go-in% <what>

Get values from an object.  Put it in a variable.  If the obj doesnt exist
it returns NOTHING.

What could be one of the following:

cost        - get cost value
name        - get name of object
action      - get action string
room        - get vnum of room its in
inobj       - get name of object its in
carried_by  - get carried by
wear_flags  - get flags
wear_loc    - get wear location
weight      - get weight
item_type   - get item type
level       - get object level
timer       - get timer level
extra_flags - get extra flags
0,1,2..9    - return value# from object


Syntax: SFUNC "<string>" %variable-to-put-it-in%  <deliminator>

Returns the value of the argument <deliminator>.

ex:

sfunc "I am the third" %argument% 4
say %argument%

You say, "third"


Syntax: WALKTO <vnum>

A mobile walks towards a room.  If no path can be found, the mobile teleports
to the location.  Each pulse would be 1 step towards that location.


Syntax: MOB <command> <delim> [<delim>]

Command: MOB LOCK <direction>

Locks a door in <direction> without checking the mobile for a key, or showing
anything to the room.

Command: MOB UNLOCK <direction>

Unlocks a door in <direction> without checking the mobile for a key, or showing
anything to the room.

Command: MOB OPEN <direction>

Opens an exit in <direction> without checking the door for a lock, or showing
anything to the room.

Command: MOB CLOSE <direction>

Closes an exit in <direction> without checking the door for a lock, or showing
anything to the room.

Command: MOB TRANS <victim>

Does a transfer of the victim to a new location without showing the victim
anything, or looking in the room, or notifying the room at the mobile's
location.

NOTE:  MOB <x> <x> commands cannot be called by the AT procedure.  An
alternate decision would be to transfer the mob to the location using
MOB TRANS me
and then at the new location do what you want, then MOB TRANS him/her back.


Syntax: LOOP

Loop calls the procedure  JUMP  without any parameters, thus returning the
script-execution pointer to the top of the TRIGGER.


Syntax: HALT <type>

Interrupts script execution in the following manners:

HALT ONCE            Stops the TRIGGER execution this time only, aborting
HALT TRIGGER         Deactivates TRIGGER until next reboot
HALT ALL             Deactivates the MOBILE completely until killed/reset
HALT STATEMENT       Aborts the current statement, proceeds to the next one


Syntax: WAIT <value,time> [<amount>]

Pauses the TRIGGER for a duration.

WAIT <number>         - wait for X script-pulses
WAIT TIME <hour>      - wait until game time reaches X hour


Syntax: JUMP <number, :label>

Labels can be defined in the SCRIPTS (by putting : name at the beginning of
a command-set), JUMP : label  will force the script to relocate the current
command interpret there for the next turn.

JUMP <number>  jumps to command-set X, where the first Sc define is 0.


BOOLEANS-

Boolean expressions are either numerical (boolean algebra) or function checks.
They must be surrounded by () if there are more than one.  They are checked
somewhat-recursively.

[!](<value> <operand> [<value>])

If the ! operator is used before the () in an expression, the evaluation
returns the opposite of the value.

Value can either be an actual value (a numeric or a string surrounded by
quotation "" marks) or it can be a variable expression such as %money% or
%x-location%

Where operand is:

==         equal to
!=         not equal to
|          binary or
&          binary and
^          binary xor
<          less than
<=         less than or equal to
>=         greater than or equal to
>          greater than
in         non-case sensitive substring of
pre        non-case sensitive prefix string of
cmp        non-case sensitive string match of
substr     substring, case sensitive, match of


You can validly have the following boolean statements (simple form):

("boodea" in "I am a boodea foxen hound.")    true   (str_infix)
("da" pre "dance")                            true   (str_prefix)
("this" cmp "that")                           false  (str_cmp)
("This is a Test" substr "s a Tes")           true   (strstr)
(54444 num)                                   true   (is_number)
(34 > 43)                                     false
(5413 < 33)                                   false
(1ase < 0)                                    false  (1ase evals to 0)
(666 <= 666)                                  true

More statements (complex form):

(7 < 3) && (3 != 3)                            false
(34 == 43) || (7 < 9)                          true


IF STATEMENTS-

Syntax:

if <boolean expression>
command
command
command~

If the boolean expression evaluates true, the commands following the if will
be executed, otherwise the command will halt and advance to the next command
set.  Either way, the next turn will end up doing the next command set, the
if-statement determines if it will continue the current command set.

if (4 == %value%)
say Wow, I've got %value%, which is four!~

If the variable %value% were 4, it would execute the next command(s).


WHILE STATEMENTS

Syntax:

while <boolean expression>
command
command
command~

The while statement repeats a command set over and over again until the boolean
expression evaluates false.  See IF STATEMENTS for information on making
valid boolean expressions.


while (%time% < 2)
say Its a bit after midnight.
~

Each pulse, as long as the time is 0 or 1, the mobile would say that it is
a bit after midnight.


LET STATEMENTS

Let statements allow certain mathematical and concatinational evaluations to
occur.  Takes a plain and simple 1 + 2 + 4 * 2 and does a infix left to right
evaluation, returning the final numeric.

let <variable> <equals> <value> [<operand>,<value>]

Operands:                             Equals:
                                      ==       assign
+      addition                       =        assign
-      subtraction                    +=       increment by
/      division (rounded integer)     -=       decrement by
*      multiplication                 |=       OR by
&      binary and                     &=       AND by
|      binary or                      ^=       XOR by
^      binary xor                     ++       increase by 1
                                      --       decrease by 1

NOTE: You cannot do  et %variable%++, there must be a space before the ++

Examples:

let %numbers%  =  1 2 3 4 5 6 7 8               1 2 3 4 5 6 7 8
let %bill% = 1 + 3 * 5                          20
let %old%  = 10                                 10
let %old% += 4                                  14
let %old% ++                                    15
let %str% = "Jim is rich."                      Jim is rich.
let %str% = %str% He has a boat.                Jim is rich. He has a boat.
let %act% = 1 & 2                               3
let %act% = %act% | 2                           1
let %act% &= 2                                  3



WHAT THE TYPE VALUES MUST BE.

In the file, to denote what type of trigger this is (what triggers it), the
Type operand must be set to one of the following numbers:

  name              num     what
------------------------------------------------------------
TRIG_COMMAND          0    When a player types x command
TRIG_EACH_PULSE       1    Increments every pulse
TRIG_COMBAT           2    Every combat pulse
TRIG_TICK_PULSE       3    Every tick (one mud-hour)
TRIG_BORN             4    Happens upon creation
TRIG_GETS             5    Happens when a mob gets/is given  NOT IMPLEMENTED
TRIG_SAY              6    Happens when a mob sees a string
TRIG_TELL             7    Happens when a mob sees a string
TRIG_KILLS            8    Happens when a mob kills another  NOT IMPLEMENTED
TRIG_DIES             9    Happens when the mob is killed
TRIG_ENTER           10    Happens on arrival (for each person)
TRIG_MOVES           11    Happens whenever a mobile moves

When the trigger is set in motion, certain ones recieve variables on them,
the variable is in the form %<trigname>-<type>%   Examples:

If the trigger  XGT  was triggered as a say, the person who was saying the
trigger would be set (their name) in the variable  %XGT-from%  What they
said would be in %XGT-arg%

In certain ones, there are triggers which return a %XGT-to%

Experiment to find out which ones use which ones.
