MUSH Manual - Section II: Building and an Introduction to Programming
Commands:
@adrop,
@ahear,
@ause,
@create,
@describe,
@destroy,
@dig,
@drop,
@emit,
@entrances,
@failure,
@force,
@halt,
@link,
@listen,
@lock,
@odrop,
@open,
@osuccess,
@ouse,
@pemit,
@ps,
@set,
@sex,
@success,
@switch,
@teleport,
@trigger,
@use,
@va,
@vb,
@vc,
@vd,
@ve,
@verb,
@wait.
MUSHCode for MUSH Manual - Section II: Building and an Introduction to Programming
MUSH Manual Version 2.008:
Copyright 1993, 1994, 1995, Lydia Leong (lwl@netcom.com / Amberyl)
Last revised 5/22/95.
Section II: Building and an introduction to programming
Table of Contents:
3. Building.
3.1 Creating a room: @dig, FLOATING flag
3.2 Connecting rooms: @open, @link and @unlink, LINK_OK flag, @entrances
3.3 Refinements: ABODE and JUMP_OK flags, drop-tos and STICKY flag on rooms
3.4 Exit conventions and the TRANSPARENT flag
3.5 Do it! -- home
4. Introduction to Programming
4.1 The stack and string substitutions - % substitutions
4.2 General attributes and action lists - @trigger and GET()
4.3 The queue: @ps, @wait, and @halt. HALT flag
4.4 Decision making: @switch
4.5 Other ways of triggering: @use and @startup
4.6 User-defined commands: $command, @scan, @verb
4.7 Introduction to functions: ADD() and other math, RAND(), TIME()
4.8 Do it! -- falcon control
3. Building
3.1 Creating a room
Building a room is done quite simply, using the @dig command. The syntax
is: @dig <Room name>=<in1;in2;in3;etc>,<out1;out2;out3;etc>
in1, in2, and in3 are all exit "aliases" - typing any one of these names will
bring you through the exit into the room. You may have as many of these as
you wish; the names must be separated by semi-colons. in1 will be the visible
"primary" exit name, which appears in the room's Obvious Exits list.
out1, out2, and out3 are similar. This exit goes from the room you just dug
to the room that you are in.
On TinyMUDs, building convention dictates that exits be set DARK - i.e.
no exit names appear in the "Obvious Exits" list. Many people like visible
exits, however, and in the age of MUSHes, most exits are visible. Visible
exits are the default.
You must control the room that you are @digging from. If you don't
own a room, you should first @dig <Room name> and then @tel to that room.
(Or use @dig/teleport, which builds the room then moves you there).
You can then build off that room. If your room is not linked to something,
however, you will occasionally get the message "You own a disconnected room,
<Room name>." To avoid this, set the room FLOATING.
=============================
[ Example 3.1: Living Room ]
> l
Foyer(#3108R)
This is the foyer of a small private home.
Obvious exits:
Doorway
> @dig Living Room=Living Room;lr;living,Foyer;f;out;o
Living Room created with room number #3813.
Opened.
Trying to link...
Linked.
Opened.
Trying to link...
Linked.
> l
Foyer(#3108R)
This is the foyer of a small private home.
Obvious exits:
Living Room Doorway
> lr
Living Room(#3813R)
Obvious exits:
Foyer
=============================
3.2 Connecting rooms
To open an exit between two existing rooms, use the syntax
@open <in1;in2;in3;etc>=#<room>,<out1;out2;out3;etc> This will open and
link exits between the two rooms. You can also open an exit in but not
out by simply using @open <in1;in2;in3;etc>=#room
To change an exit destination, simply "@link <exit>=#<new room>".
(Certain older versions of MUSH might require you to first "@unlink exit".)
Be careful not to leave exits unlinked, because an unlinked exit will become
the property of whomever @links it. If you want to have an exit going no place,
like something called "sit" which displays the @fail message "You sit down."
@link the exit to the room it is in - i.e. @open sit=here. @lock sit=#0.
@fail sit=You sit down.
You can let people open/link exits to one of your rooms by setting it
LINK_OK. Note that people cannot open an exit from your room into something
else; they can only link an entrance.
* * * * *
The "@entrances <object>" command returns all links to <object> --
exits which are linked to the object, rooms which have their drop-tos set
to the object, and players and things which have their homes set to the
object. This command in 1.50 also takes switches, allowing you to specify
exits, rooms, players, or things alone. This command is computationally
expensive, costing the same as @find.
You can limit the dbref range which @entrances searches by specifying
"@entrances <object>=<first object>,<last object>". This is similar to
restricting the range on @find.
3.3 Refinements
If you want people to be able to @teleport to your room, set it
JUMP_OK. Beware - if you are in a JUMP_OK room and someone does a @whereis
on you, the room number will be listed, and that person will be able to
@tel to your location, so if you don't want unexpected visitors dropping
in, it might be best not to set the room JUMP_OK.
If you want other people to be able to set their homes in your room -
i.e. be sent there automatically when they type 'home' - set the room ABODE.
To set yourself or another object's home, @link <thing>=<here/#room>.
In older versions of MUSH code, most notably MicroMUSH, the JUMP_OK
and ABODE flags are merged; a room set ABODE may both be @linked to and
@teleported to.
* * * * *
Rooms may be @linked to other rooms, using @link <room1>=#<room2>.
This sets a "drop-to". Objects dropped in room1 will automatically be sent
to room2. "Drop-tos" may be delayed by setting the STICKY flag on room1.
If the room is STICKY, the drop-to will not be performed until the last
player has left the room.
3.4 Exit conventions
There are certain exit conventions used on TinyM*s which make following
other players around easier. Exits should, if possible, have an @osucc and
@odrop message. The @osucc message is triggered when someone uses an exit;
it is displayed to everyone else in the room that the person just left.
The @odrop message is triggered the same way, but is displayed to everyone
in the room that the person enters. Thus, you can tell where people are
going to, and where they are coming from.
For purely aesthetic purposes, exits often have @desc and @succ messages.
The @desc message is displayed when someone "looks" at an exit; the @succ
message is displayed to the person who walks through the exit.
* * * * *
Several clever things can be done with "null" exits. These are exits
that don't lead anywhere, but simply display a message to the player. For
example, an exit named "sit" could give the message "You sit down." These
exits are usually locked to #0, linked to the room they are in, and DARK.
Use of these kinds of exits is generally discouraged on MUSHes that enforce
building quotas and/or are trying to conserve disk space.
In areas that use a lot of directions - north/south/east/west etc. - it
is often helpful to have a null exit with the names of the remaining directions
in it. For example, if a room has exits in all directions except east and
west, a null exit called east;e;west;w with a @fail message of "You can't
go that way." is very helpful. Otherwise, the player who types "east" will
simply get a "Huh? (Type "help" for help.)" message. Before you make such
fake exits in your rooms, though, it might be a good idea to check that your
MUSH doesn't have them already defined in the Master Room.
MudCore provides the Master Room support for these fake direction
exits (and the message "There is no exit in that direction.") MudCore
takes this a step further, however, providing customization of these
fake exits without taking up more database space for extra "real"
exits. Sometimes, when building an area, you will want to have, for
example, a "north" exit which provides a message like, "You walk down
a long corridor, discover nothing interesting, and return to where you
started." and doesn't actually lead to another room. Such exits give
the illusion of "space", making a small area feel larger. In MudCore,
"fake" exits in the cardinal directions can be designed by placing the
attributes DESC_<direction> and FAIL_<direction> on the room. For the
above example, one might use, "&DESC_NORTH here=To the north is a
long, featureless corridor." and "&FAIL_NORTH here=You walk down a
long, corridor, discover nothing interesting, and return to where you
started."
* * * * *
There is a flag called TRANSPARENT, which can be set on exits. If this
flag is set, players looking at the exit see, after the exit description,
the description of the next room and its contents (but not its succ/fail
messages or exits). This is useful for creating the illusion of an archway
or similar portal, where it makes logical sense to be able to look through
it into the next room.
In 1.50, the TRANSPARENT flag can also be set on rooms. This causes
the obvious exits in the room to be displayed with each exit on a line
by itself, giving the destination room. For example, you might have:
Obvious exits:
South leads to Foyer of the Bank.
East leads to Intersection of Park and Hill Streets.
instead of:
Obvious exits:
South East
3.5 Do it! -- home
This builds a very simple home of three rooms, linked in a triangle:
Living Room
| \
Workroom------Bedroom
Issue the following commands:
@dig/teleport Living Room
[ The room will be dug and you will be moved into it. Note its dbref number ]
@set here=FLOATING
[ Suppresses disconnected room warnings ]
@desc here=<whatever the room looks like>
@dig Workroom=Workroom;w;work;south;s,Living Room;lr;living;north;n;out;o
go workroom
@desc here=<whatever the room looks like>
@dig Bedroom=Bedroom;b;east;e;bed,Workroom;w;work;west
go bedroom
@desc here=<whatever the room looks like>
@open Living Room;lr;living;northwest;nw;out;o=#<xxx>,Bedroom;b;bed;
southeast;se
[ Note: the previous line is wrapped-around. <xxx> is the room number of the
Living Room, which you should have noted earlier. ]
@set here=ABODE
@link me=here
[ Sets your home to this bedroom ]
All three rooms are dug and linked - now, all you have to do is to spiffy
up the exits, and you're all set!
4. Introduction to Programming
4.1 The Stack and string substitutions
The MUSH stores several variables, related to the cause of an action,
the object that is executing an action, and the program state during that
action, referred to as the "stack". These are accessed via a "percent
substitution".
One such variable is the "enactor" -- the object which caused an
action to be performed. For example, if Sareena looks at a Plush Shaav
Doll, Sareena is the enactor. The enactor is sometimes referred to as the
"cause". The percent substitution '%N' returns the name of the enactor; in
this case, it would be "Sareena". The substitution '%n' also returns the
name of the enactor, but the first letter is in lower-case. Another
substitution, '%#', returns the dbref number of the enactor.
It is also possible to get the appropriate pronoun for the enactor.
'%s' is the subjective pronoun (he/she/it). '%o' is the objective pronoun
(him/her/it). '%p' is the possessive pronoun (his/hers/its). The capital
letter forms ('%S', etc.) return the pronoun with the first letter
capitalized. The game determines the pronoun to use by looking the @sex
attribute on the enactor. These substitutions are equivalent to the
function evaluations "SUBJ(%#)", "OBJ(%#)", and "POSS(%#)". In the
example above, since Sareena is female, these substitutions would return
"she", "her", and "hers", respectively.
The substitution %l returns the dbref number of the enactor's
location. This is useful when programming objects in the Master Room,
and does not pose a "security risk", since the enactor has volunteered
his position by triggering a $command or similar.
The object performing the action can be referenced via '%!'. This
returns the dbref number of the object. It is equivalent to the function
evaluation "NUM(me)". In the above example, the object that has been
triggered (and thus is performing the action) is the Plush Shaav Doll.
* * * * *
The "stack" in MUSH is simply a place where strings are stored; it
is not a literal "stack" in the usual sense of having a top object which
can be pushed and popped (as in MUF, or as defined in a standard computer
science class). The stack consists of ten strings, numbered 0 through 9.
Strings on the stack are referred to as %0, %1, %2, and so on, through %9.
The mechanisms for copying strings into the stack will be explained later.
Related to "percent" substitution is the V() function. It produces
identical output to the equivalent percent substitution. For example,
'[v(0)]' is equivalent to '%0', and '[v(N)]' is the same is '%N'.
Throughout this manual, however, '%0' and other percent substitutions
will be used instead of 'v(0)', since the evaluation of percent subtitutions
is faster than the evaluation of V-functions.
26 registers, "numbered" va-vz, are available for programming, as part
of the "standard" collection of MUSH attributes. They may be accessed by
either %va, or [v(va)]. Note that the square brackets [] force something to
be evaluated as a string.
1.50 provides the additional registers wa-wz and xa-xz. These behave
in a manner identical to va-vz.
Percent substitutions should always be used instead of functions,
where possible. In fact, you should ALWAYS use the percent substitution,
unless you are SURE that the function version is required -- use %N instead
of v(N), %! instead of num(me), and so forth. There are virtually no
situations which require the functions, and thus using the function
versions is inefficient and wasteful. Furthermore, please note that
it's just "%0", NOT "[%0]"; the additional square brackets cause an
unnecessary extra evaluation and thus are inefficient.
Please note that if you access something with a percent-substitution, if
you capitalize the first letter of the substitution, then the first letter
of the text returned will also be capitalized.
The S() function forces an additional round of pronoun substitution.
This is useful if you are evaluating a string and want to force the parser
to substitute in the values for all (non-escaped) functions.
Percents can also be used to add in special characters. %r is a carriage
return, %t is a tab character, and %b is a blank space. To show a literal
"%", use "%%". '%r' is actually two characters (a carriage return and
newline), and functions like STRLEN() will count it as two.
Finally, there are temporary storage "registers", also numbered 0 through 9.
They are set via the function SETQ(), and retrieved via the function R(),
or through the %q-substitution. The values set via SETQ() are preserved
through the entire command list associated with a given command. SETQ()
is a function which just returns a blank string, and has the syntax,
"setq(<register number>,<value>)". "r(<register number>)" retrieves the
value. These functions will be explained in greater detail later.
For now, just believe that they allow you to keep values around
temporarily. The odd name SETQ comes from the programming language LISP.
======================================
[ Example 4.1: Percent demonstration ]
> @sex me=female
Set.
> @va me=test
Set.
> say %va
You say "test"
> say %Va
You say "Test"
> say %N is demonstrating %p example.
You say "Amberyl is demonstrating her example."
> say [setq(0,testing for fun)]-- %q0
You say "-- testing for fun"
> say [setq(0,testing for fun)]-- %Q0
You say "-- Testing for fun"
======================================
4.2 General attributes and action lists
The 26 registers are often referred to as "general attributes," since
they can be used to store anything. Often, they are good places to put
variables. In addition to being accessible by the v-function, they can
also be accessed by using the GET() function. The syntax for this is
"get(object/attribute)". "[get(me/va)]" is always equivalent to "[v(va)]"
or "%va".
GET() is very similar to the v-function, except it requires an object
to get the attribute from. It may be used to get any attribute - registers,
descriptions, non-standard attributes, etc. When working only with one object,
it is generally more efficient to use a v-function instead of using GET().
GET_EVAL() is similar to GET(), except that it also evaluates the
attribute. U() is also similar, and also evaluates the attribute, but
it can be used for user-defined functions which take parameters (more
on this later).
GET_EVAL()'s syntax is like GET()'s: "get_eval(object/attribute)"
U()'s basic syntax can be like either V()'s or GET()'s; either
"u(attribute)" or "u(object/attribute)" is valid. (For information
on how to pass parameters to U(), see a later section in this manual.)
There is a subtle difference between the two functions, in addition to
U()'s ability to take parameters
The enactor of a GET_EVAL() is the object which is actually
performing the GET_EVAL(); the enactor of a U() is the original enactor.
======================================
[ Example 4.2a: GET_EVAL() vs. U() ]
> say %!
You say "#3"
> @create Test
Test created as object #1034
> @va test=Enactor: %# -- Me: %!
Set.
> @vb test=$test: @pemit %#=Get_Eval: [get_eval(me/va)]%rU: [u(va)]
Set.
> test
Get_Eval: Enactor: #1034 -- Me: #1034
U: Enactor: #3 -- Me: #1034
======================================
If you're confused by the difference between GET(), GET_EVAL(), and U(),
don't worry about it; details will be provided later, and you don't need
to worry about the latter two functions if you're only doing very basic
things with MUSH.
* * * * *
General attributes are often used to store action lists, which are
long lists of commands, to be queued and executed. For example, you could
@create an object called Test, and "@va Test=:explodes.; @destroy me"
General attributes are usually activated by "triggers". The syntax for
this is @trigger object/attribute. @trigger is usually abbreviated to @tr.
Most of the time, one attribute will trigger another, but you can also type
directly @tr object/attribute.
For example, if you typed @tr Test/va, from the example above, you would see:
Triggered.
Test explodes.
You get back your 10 Mark deposit for Test.
Test has left.
You may also pass variables on the stack from attribute to attribute, using
trigger. Often, this is a must, since the stack is cleared when something
new is triggered. The syntax is "@tr object/attribute=thing,thing,thing,etc."
These new things become %0, %1, %2, etc., respectively, in the triggered
register. Almost anything can be legally passed on the stack - function
evaluations of any type, % arguments, numbers, strings, etc.
======================================
[ Example 4.2b: Sentence Reverser ]
[ This object listens for four words and prints them out backwards. ]
> @create Reverser
Reverser created as object #25789
> @listen reverser=* says "* * * *"
Set.
> @ahear reverser=@tr me/va=%4,%3,%2,%1
[ Note that %0 is left out, since %0 is the * says - the person talking ]
Set.
> @va reverser="%0 %1 %2 %3
Set.
> drop reverser
Reverser has left.
Reverser has arrived.
Dropped.
> "First second third fourth
You say "First second third fourth
Reverser says "fourth third second First"
===========================================
4.3 The queue and delayed execution
The queue is the list of commands that the MUSH is going to execute.
All commands are put into it. Most are evaluated quickly, in the order
that they enter the queue (first to last), although @trigger takes at
least one queue cycle to execute and @force at least two. Setting
an attribute also takes time. One must be careful, when programming, that all
commands are getting executed at the correct times. There is no hard and fast
rule for this; experimentation is generally the only way to find out if your
object is executing commands in the correct order.
The queue may be checked by doing a @ps. If you have an infinite loop,
this is likely to be very long. If you're not sure if an object of yours is
infinite looping, @ps is a surefire way of checking.
@ps separates the queue into four sections - Player, Object,
Wait, and Semaphore. The player queue shows what you have triggered; the
object queue shows what your objects have triggered. The Wait queue shows
commands that will be executed in the future - commands that you have queued
using @wait (explained below). The Semaphore queue shows semaphore countdowns
(explained later). The total number of queued commands is also displayed.
The default @ps switch is "@ps/brief". This shows the objects
and the commands they are running. For the wait queue, it also shows
the time to wait. For the semaphores, it shows the object that the command
is waiting on, and if the semaphore is using the timer option, it also
shows the remaining time. Finally, it displays the total count of queued
commands in each of the four categories.
"@ps/long" displays all the information that "@ps/brief" does,
plus the enactor of the object, and any variables which are being passed
on the stack for eventual execution as part of a @trigger.
"@ps/summary" shows just the total count of queued commands. Note
that @ps defaults to displaying the queue for the individual executing
the @ps; only wizards may specify a player name or the "/all" switch.
In the totals line, no matter what switches are specified, the numbers
in each category are shown as Number1/Number2. The first number is the
number of queued commands that you have in that category; the second
number is the total number of commands queued in that category.
Player and Object categories also have a "[#del]", where "#" is the
number of commands deleted from the queue via @halt.
* * * * *
@ps in 1.50 is somewhat different. "@ps" with no arguments shows
your personal queue - the objects and the commands they are running,
and, for the wait queue, the time to wait. It also displays the total
count of queued commands in each of the queues, in the format
<Number of your commands> / <Total number of commands in that queue>.
"@ps all" prints the queue for all players. Wizards can also do
"@ps *<player>" to get a queue for that player. In both cases, a queue
count is provided.
Anyone may do a "@ps count" to get a count of the number of
queued commands.
* * * * *
Infinite loops on objects are dangerous. Every queued command costs
1/64th of a penny. Plus, if an object loops badly enough, it can severely slow
down the game for others. If you have a loop, you can use @halt. It clears
your personal queue. @halt <command> clears your personal queue, and adds that
new command to the queue. @halt <object>=<new command> clears that object's
queue and adds that new command to the queue.
The other way of halting something is to set the HALT flag on it. An
object set HALT is essentially inert - it does not @listen, @triggers and
@force don't work on it, etc. Also, in 1.50, UFUN() and ZFUN() will return
"#-1 OBJECT HALTED" (recursion in a UFUN or ZFUN will automatically set
the object HALT).
The @halt command in 1.50 is slightly different. If you, or one of
your objects, does a "@halt", it wipes out your entire queue. There is no
way to clear the queue commands on just one object. You can also do
@halt <player>=<new command>, which wipes out the player's entire queue
and places the new command in it; if you are not a wizard, the player must
be yourself. "@halt <object>" in 1.50 with no new command also sets the
object HALT. If you just want to stop an infinite loop, use "@halt" with
no arguments.
There is one command called @allhalt (1.50. In 2.0, it's @halt/all)
which is wizard-only. It clears the queue for the entire MUSH, and is used
in emergencies. All connected players receive the message, "Your objects
have been globally halted by <Wizard>."
* * * * *
The syntax of @wait is simple: @wait <number of seconds>=<command list>
There is another, more complex, type of @wait which is timed on objects;
this type of @wait involves a "semaphore" and will be described later.
@wait is very useful for trying to get objects to execute commands in the
correct order, as well as for doing time-delayed sequences - for example,
descriptions on a room that change every few hours.
=============================
[ Example 4.3: Explosive
[ This will create an object which explodes fifteen seconds after being
dropped. It gives a warning five seconds before it explodes. ]
> @create Explosive
Explosive created as object #23083
> @drop explosive=You set down the explosive and ignite it.
Set.
> @adrop explosive=@wait 10=:pulses dangerously. It'll explode in another five
seconds!;@wait 15={:explodes!;@destroy me}
Set.
> drop explosive
Explosive has left.
You set down the explosive and ignite it.
[ 10 seconds pass ]
Explosive pulses dangerously. It'll explode in another five seconds!
[ another 5 seconds pass ]
Explosive explodes!
You get your 10 Marks deposit back for Explosive.
Explosive has left.
============================
4.4 Decision making: @switch
@switch is the closest thing to IF-THEN-ELSE on a MUSH. It is similar to
the CASE statement in many programming languages. Its syntax is
@switch <var>=<cond1>,<action1>,<cond2>,<action2>,<cond n>,<action n>,<default>
@switch statements may be nested. One must be very careful about using commas
and semi-colons when using @switch - any statements which contain either commas
or semi-colons should be surrounded by curly braces { }. A comma will signal
a new case/action, and a semi-colon the end of the @switch statement, if not
in the curly braces. This is a commonly made mistake - when programming
objects whose @switches do not appear to work, always check for misplaced
commas or semi-colons.
One thing to note is that the variable to switch on does not have to be
evaluated within square brackets [ ]. Percent substitutions, like %va, are
okay to switch on, as are functions simply stated, like words(v(va)).
After the variable name is ALWAYS an equals sign. @switch %va=>1,:foo
does NOT mean "if va is greater than or equal to one, :foo". It means "if va
is strictly greater than one, :foo". The equals sign is simply part of the
@switch syntax. If you want greater than or equal to, you will have to use
the GTE() function.
There are two option switches to @switch, /first and /all. In 2.0, which
one is the default will depend on the MUSH ("@list options" to see).
"@switch/all" performs the actions associated with all matching
targets. In other words, if the targets are not mutually exclusive, more
than one set of actions may be undertaken. Its 1.50 equivalent is the
standard "@switch" command.
"@switch/first" matches the first target it can, and executes the
statements associated with that. Even if the targets are not mutually
exclusive, only the actions associated with the first target matched will
be executed. The 1.50 equivalent of this is the "@select" command.
=============================
[ Example 4.4: Dog ]
[ The dog will respond to simple commands that someone says ]
> @create Dog
Dog created as object #23084
> @listen dog=*"Dog, *"
Set.
> @ahear dog=@switch %1=sit,:sits down.,roll over,:rolls over obediently,play
dead,:flops onto the ground.
Set.
> drop dog
Dog has left.
Dog has arrived.
Dropped.
> "Dog, sit
You say "Dog, sit"
Dog sits down.
> "Dog, play dead"
You say "Dog, play dead"
Dog flops onto the ground.
> "Dog, roll over
You say "Dog, roll over"
Dog rolls over obediently.
=============================
4.5 Other ways of triggering
It is frequently useful to be able to trigger an object without having
to pick it up, drop it, or have it listen for something. Therefore, MUSH
provides for "using" objects.
The attributes @use, @ouse, and @ause are associated with the "use"
command. "use <object>" triggers these three registers (note the absence of
the @ sign in triggering). An object can only be used if there is something in
the @ause register. The person who uses the object is shown the message in the
@use; the other people in the room see the @ouse message. The @ause command
list is executed. This, in essence, works just like "get" and "drop" - the
command "use" has simply been added.
========================================
[ Example 4.4: Bubbly pie revisited ]
[ @using the bubbly pie performs an "eating action" and destroy. ]
> @create Bubbly pie
Bubbly pie created as object #30216
> @ause pie=@emit %N gobbles down the bubbly pie.;@destroy me
Set.
> use pie
You use Bubbly pie
Elsa gobbles down the bubbly pie.
You get your 10 Marks deposit back for Bubbly pie.
Bubbly pie has left.
========================================
Another way to trigger an object is to set its @startup. The commands
in the @startup attribute are executed whenever the MUSH is restarted.
This is useful for objects that need to run continuously, such as clocks.
Objects with a @startup attribute are automatically given the STARTUP flag,
represented by "z". This flag is simply used for internal accounting and
does not affect anything else.
4.6 User-defined commands
Perhaps one of the most common ways of triggering an object, user-defined
commands are the closest things to MUCK @action that MUSH provides. They allow
other players to type "command <arguments, if any>" and have that execute just
as if the command was part of the MUSH. Unlike MUCK, however, there are few
global user-defined commands. One must be in the same room with, or carrying,
the object on which the command is defined. The only exceptions to this are
exits/commands defined on the "master room". See the wizard section of this
manual for details.
These commands may be set on any register or non-standard attribute.
The syntax is: @<attribute> <object>=$<command>: <action list>
The command may take arguments by using * or ?, etc., in a format similar to
that use by @ahear/@listen.
User-defined commands are matched on every object in the room or in
your inventory, so you may want to avoid command names that might be
extremely common. Commands on the MUSH are parsed in the order: exit
names, defined MUSH commands (like @desc, page, etc.), then
user-defined commands, then Master Room commands. You should be
extremely careful not to define commands on an object like $p
*:<action>, since this will be parsed as "page" and it will be ignored
by the object. Furthermore, note that many MUSHes have global commands
which begin with '+' and mailers which use '-' as an editing
indicator; thus, you should avoid starting your own commands with
either of those characters.
In 2.0, there are config options which determine two things:
The first is the ability of an object to trigger its own $commands. The
second is the ability to trigger $commands on players. One can, however,
always trigger $commands on an object one is carrying or is in the same room.
===============================
[ Example 4.6: Tray of Food ]
[ This object is a tray of food which you can "eat", "drink" and "discard" ]
> @create Tray of Food
Tray of Food created as object #482
> @va food=$eat: @emit %N takes a slice of bread off the try and eats it.
Set.
> @vb food=$drink: @emit %N takes a cup of water off the tray and drinks it.
Set.
> @vc food=$discard: @emit %N discards %p tray of food;@destroy me
Set.
> eat
Elsa takes a slice of bread off the tray and eats it.
> drink
Elsa takes a cup of water off the tray and drinks it.
> discard
Elsa discards her tray of food.
You get your 10 Marks deposit back for Tray of Food.
Tray of Food has left.
==============================
Sometimes it's useful to be able to find out what $commands are
triggered in a room. 1.50's @scan command allows you to check for a
command match on objects that you control or that are set VISUAL.
The syntax of this command is simply "@scan <string>". It checks for
all possible matches on your location, its contents, yourself, your
inventory, the zone or parent room of your location, your personal
zone, and the master room. It will display the name of any objects
which have commands which could match that string, followed by the
number of commands matched in brackets.
MudCore provides for similar functionality, via its '+scan' command.
It checks for matches, starting from a specific object, and lists
the attributes and command wildcard patterns which match (if you
can examine the object), or the object which matches the commands
(if you can't examine it).
* * * * *
One interesting and quite flexible command is "@verb". This command
essentially allows you to define your own @attr/@oattr/@aattr triplets,
allowing you to define your own "standard" verbs. This command is most
useful for someone who is a wizard.
This command is in the format:
@verb <obj to read attributes off (victim)>=<obj to be told messages (actor)>,
<attr name>, <default message for attr>,
<oattr name>, <default message for oattr>,
<aattr name>, <args>
Most of those those fields should be self-explanatory; <args> are
the values to be passed on the stack, as %0-%9. For example, to simulate
"drop" with a command like "put", you would use a user-defined command
something like:
$put *: @verb [v(0)]=[v(N)],DROP,Dropped.,ODROP,dropped [v(0)].,ADROP
Under 2.0, both the victim and actor must be controlled. Under
1.50, either both victim and actor must be controlled, or the thing which
triggered the verb must be <actor> AND the object which issued the @verb
command must be able to read the attributes from <victim>. Essentially,
though, one needs to be a wizard in order to make this command generally
useful. It is, however, a rather nifty thing to play with.
4.7 An introduction to functions
Functions are generally used to manipulate strings and other input, or
to generate or retrieve something. They are called using:
<function-name>(<arg1>,<arg2>,<etc>) and evaluation often requires square
brackets [ ] to be put around the function. It is imperative that the right
number of arguments be passed to the function, and that the parentheses are
correctly matched. You should always use %-substitutions instead of functions
where possible, i.e., %va instead of v(va). Functions may be nested. Only
one pair of square brackets is required around a given function call.
Certain functions, such as V() and GET(), have already been introduced.
Only a few functions require no arguments; TIME(), which simply
returns the current time on the MUSH, is probably the most commonly
used of these. All other functions require one or more arguments. The most
commonly used, aside from the v, s, and get() functions, is the RAND()
function. This generates a random integer between 0 and <number - 1>.
There _is_ a limit to the number of arguments a function can take; you
can find out what this is by asking a local wizard. This is generally 100.
The limit is something to keep in mind if you are doing extremely large calls
to a function like SWITCH(), which takes an arbitrary number of arguments.
Functions used to access basic db info include NUM(), FLAGS(), OWNER(),
LOC(), and MONEY(). These are publicly accessible, and give an object's
database reference number, flags, owner, location (for a player), and money
(also for a player). These functions will be discussed in more detail
later. Other publicly accessible attributes include DESC, and
are gotten using the GET() function. All attributes on an object set VISUAL
are publicly accessible.
Functions used to process lists will be covered later in this manual.
The following functions are used for arithmetic: ADD(), SUB(), MUL(), DIV().
Note that SUB() does not exist in many versions of MUSH code; instead, one
must add the negative of the second number. Some of these functions, such
as SUB(), take ONLY two arguments. Others, like ADD(), can take multiple
arguments (just like LISP arithmetic operators). For example,
"add(2,3,4)" is equivalent to (and more efficient than) "add(2,add(3,4))".
=============================
[ Example 4.7a: Abacus ]
[ An object that performs arithmetic ]
> @create Abacus
Abacus created as object #19831
> @va abacus=$*+*: @emit The sum of %0 and %1 is [add(%0,%1)].
Set.
> @vb abacus=$*-*: @emit The difference of %0 and %1 is [sub(%0,%1)].
Set.
> @vc abacus=$*x*: @emit The product of %0 and %1 is [mul(%0,%1)].
Set.
> @vd abacus=$*/*: @emit The quotient of %0 and %1 is [div(%0,%1)].
Set.
> 1+2
The sum of 1 and 2 is 3.
> 2x6
The product of 2 and 6 is 12.
> 8-5
The difference of 8 and 5 is 3.
> 9/3
The quotient of 9 and 3 is 3.
==============================
Here's another example, demonstrating the combined use of @switch and RAND(),
"use", and various %-substitutions.
======================================
[ Example 4.7b: Plush Shaav Doll ]
[ To conserve space, 'Set.' messages after attribute sets have been omitted. ]
> @create Life-size Plush Shaav Doll
Life-size Plush Shaav Doll created as object #3895
> @desc doll=This is a plush doll nearly six feet in height. It's fuzzy and
and cute, featuring the Grand Hierarch Shaav wearing his usual calm
expression, although the effect is somewhat spoiled by the fluffy stuffing
and bright green-button eyes. The life-sized doll is clothed in the black
robes of the Grolims, and would probably seem to radiate evil if it didn't
look so snuggly. It's probably made by the same people who made Belzoinks.
> @succ doll=You prop up a life-sized plush doll of Shaav.
> @osucc doll=grins evilly as %s props up a life-sized plush doll of Shaav.
> @drop doll=You drop a life-sized plush doll of Shaav on its head.
> @odrop doll=drops a life-sized plush doll of Shaav on its head.
> @use doll=You pull a string on the doll's neck.
> @ouse doll=pulls on a string on the plush Shaav doll's neck.
> @ause doll=@switch rand(4)=
0, {:points a finger at %N and squeaks. "Die!"},
1, {:screams:%tDeath!%tDestruction!%tChaos!},
2, {:looks at %N for a moment, then booms to %o, "DOOM."},
3, {:squeaks. "Mama!%b%bMama!%b%bMama!"}
[ If Polgara (a female) types "use doll", she sees "You pull a string on the
doll's neck", plus one of the following messages: ]
Life-size Plush Shaav Doll points a finger at Polgara and squeaks. "Die!"
Life-size Plush Shaav Doll screams: Death! Destruction! Chaos!
Life-size Plush Shaav Doll looks at Polgara for a moment, then booms to
her, "DOOM."
Life-size Plush Shaav Doll squeaks. "Mama! Mama! Mama!"
Note the use of "%b" and "%t" substitutions for blank spaces and
tabs. Because "%t" inserts a literal tab character, the spacing will
vary depending on where tab stops are set by the player's terminal.
Also note that the @switch action clauses had to be enclosed in braces,
since the statements used inside contained commas.
==============================
4.8 Do it! -- falcon control
This section assumes that you have created the falcon as per section
2.9 of this manual. The object you will create in this example will be used
to control it. <#FL> below refers to the dbref number of your falcon,
and <FL> refers to the name of your falcon.
The controller will give you the ability to force your falcon
remotely to pose and think messages, return to you on command, and go to a
player on command, using: '<message> to think a message, .<pose> to pose
something, return to recall the falcon, and goto <player> to go to a
player's location.
Issue the following commands:
@create <FL>'s controller
[ Then lock it, desc it, etc. ]
@va controller=$'*: @fo <#FL>=:chirps << %0 >>
[ This is used for "speech" ]
@vb controller=$.*: @fo <#FL>=:%0
[ This is used for forcing the falcon to pose ]
@vc controller=$fly *: @fo <#FL>={:soars into the air and flies off.; %0}
[ This is used to have the falcon fly in a given direction ]
@vd controller=$return: @fo <#FL>={:returns to %N.; @set me=!puppet;
@tel me=owner(me); leave; :soars towards you!; @set me=puppet}
[ This brings the falcon back to you, with appropriate messages. The
INHERIT flag must be set in order for this to work. ]
@ve controller=$goto *: @fo <#FL>={@switch loc(*%0)=#-1,{p <your name>=I can't
find %0}, {:goes to find %0.; @tel me=loc(*%0); :soars towards you!}}
[ This is used to go to the location of a player. It first checks to see if
the player can be found - if the player does not exist or the player is set
UNFINDABLE, #-1 is returned and the falcon pages the player with the
fail message - and then, if the player exists, teleports to that player's
location, with appropriate messages. ]
INDEX OF SECTION II EXAMPLES:
3.1 Living Room
3.5 Home
4.1 Percent demonstration
4.2a GET_EVAL() vs. U()
4.2b Sentence Reverser
4.3 Explosive
4.4 Dog
4.5 Bubbly pie revisited
4.6 Tray of food
4.7a Abacus
4.7b Plush Shaav Doll
4.8 Falcon control
Copyright 1993, 1994, 1995, Lydia Leong (lwl@netcom.com / Amberyl)
Last revised 5/22/95.
Section II: Building and an introduction to programming
Table of Contents:
3. Building.
3.1 Creating a room: @dig, FLOATING flag
3.2 Connecting rooms: @open, @link and @unlink, LINK_OK flag, @entrances
3.3 Refinements: ABODE and JUMP_OK flags, drop-tos and STICKY flag on rooms
3.4 Exit conventions and the TRANSPARENT flag
3.5 Do it! -- home
4. Introduction to Programming
4.1 The stack and string substitutions - % substitutions
4.2 General attributes and action lists - @trigger and GET()
4.3 The queue: @ps, @wait, and @halt. HALT flag
4.4 Decision making: @switch
4.5 Other ways of triggering: @use and @startup
4.6 User-defined commands: $command, @scan, @verb
4.7 Introduction to functions: ADD() and other math, RAND(), TIME()
4.8 Do it! -- falcon control
3. Building
3.1 Creating a room
Building a room is done quite simply, using the @dig command. The syntax
is: @dig <Room name>=<in1;in2;in3;etc>,<out1;out2;out3;etc>
in1, in2, and in3 are all exit "aliases" - typing any one of these names will
bring you through the exit into the room. You may have as many of these as
you wish; the names must be separated by semi-colons. in1 will be the visible
"primary" exit name, which appears in the room's Obvious Exits list.
out1, out2, and out3 are similar. This exit goes from the room you just dug
to the room that you are in.
On TinyMUDs, building convention dictates that exits be set DARK - i.e.
no exit names appear in the "Obvious Exits" list. Many people like visible
exits, however, and in the age of MUSHes, most exits are visible. Visible
exits are the default.
You must control the room that you are @digging from. If you don't
own a room, you should first @dig <Room name> and then @tel to that room.
(Or use @dig/teleport, which builds the room then moves you there).
You can then build off that room. If your room is not linked to something,
however, you will occasionally get the message "You own a disconnected room,
<Room name>." To avoid this, set the room FLOATING.
=============================
[ Example 3.1: Living Room ]
> l
Foyer(#3108R)
This is the foyer of a small private home.
Obvious exits:
Doorway
> @dig Living Room=Living Room;lr;living,Foyer;f;out;o
Living Room created with room number #3813.
Opened.
Trying to link...
Linked.
Opened.
Trying to link...
Linked.
> l
Foyer(#3108R)
This is the foyer of a small private home.
Obvious exits:
Living Room Doorway
> lr
Living Room(#3813R)
Obvious exits:
Foyer
=============================
3.2 Connecting rooms
To open an exit between two existing rooms, use the syntax
@open <in1;in2;in3;etc>=#<room>,<out1;out2;out3;etc> This will open and
link exits between the two rooms. You can also open an exit in but not
out by simply using @open <in1;in2;in3;etc>=#room
To change an exit destination, simply "@link <exit>=#<new room>".
(Certain older versions of MUSH might require you to first "@unlink exit".)
Be careful not to leave exits unlinked, because an unlinked exit will become
the property of whomever @links it. If you want to have an exit going no place,
like something called "sit" which displays the @fail message "You sit down."
@link the exit to the room it is in - i.e. @open sit=here. @lock sit=#0.
@fail sit=You sit down.
You can let people open/link exits to one of your rooms by setting it
LINK_OK. Note that people cannot open an exit from your room into something
else; they can only link an entrance.
* * * * *
The "@entrances <object>" command returns all links to <object> --
exits which are linked to the object, rooms which have their drop-tos set
to the object, and players and things which have their homes set to the
object. This command in 1.50 also takes switches, allowing you to specify
exits, rooms, players, or things alone. This command is computationally
expensive, costing the same as @find.
You can limit the dbref range which @entrances searches by specifying
"@entrances <object>=<first object>,<last object>". This is similar to
restricting the range on @find.
3.3 Refinements
If you want people to be able to @teleport to your room, set it
JUMP_OK. Beware - if you are in a JUMP_OK room and someone does a @whereis
on you, the room number will be listed, and that person will be able to
@tel to your location, so if you don't want unexpected visitors dropping
in, it might be best not to set the room JUMP_OK.
If you want other people to be able to set their homes in your room -
i.e. be sent there automatically when they type 'home' - set the room ABODE.
To set yourself or another object's home, @link <thing>=<here/#room>.
In older versions of MUSH code, most notably MicroMUSH, the JUMP_OK
and ABODE flags are merged; a room set ABODE may both be @linked to and
@teleported to.
* * * * *
Rooms may be @linked to other rooms, using @link <room1>=#<room2>.
This sets a "drop-to". Objects dropped in room1 will automatically be sent
to room2. "Drop-tos" may be delayed by setting the STICKY flag on room1.
If the room is STICKY, the drop-to will not be performed until the last
player has left the room.
3.4 Exit conventions
There are certain exit conventions used on TinyM*s which make following
other players around easier. Exits should, if possible, have an @osucc and
@odrop message. The @osucc message is triggered when someone uses an exit;
it is displayed to everyone else in the room that the person just left.
The @odrop message is triggered the same way, but is displayed to everyone
in the room that the person enters. Thus, you can tell where people are
going to, and where they are coming from.
For purely aesthetic purposes, exits often have @desc and @succ messages.
The @desc message is displayed when someone "looks" at an exit; the @succ
message is displayed to the person who walks through the exit.
* * * * *
Several clever things can be done with "null" exits. These are exits
that don't lead anywhere, but simply display a message to the player. For
example, an exit named "sit" could give the message "You sit down." These
exits are usually locked to #0, linked to the room they are in, and DARK.
Use of these kinds of exits is generally discouraged on MUSHes that enforce
building quotas and/or are trying to conserve disk space.
In areas that use a lot of directions - north/south/east/west etc. - it
is often helpful to have a null exit with the names of the remaining directions
in it. For example, if a room has exits in all directions except east and
west, a null exit called east;e;west;w with a @fail message of "You can't
go that way." is very helpful. Otherwise, the player who types "east" will
simply get a "Huh? (Type "help" for help.)" message. Before you make such
fake exits in your rooms, though, it might be a good idea to check that your
MUSH doesn't have them already defined in the Master Room.
MudCore provides the Master Room support for these fake direction
exits (and the message "There is no exit in that direction.") MudCore
takes this a step further, however, providing customization of these
fake exits without taking up more database space for extra "real"
exits. Sometimes, when building an area, you will want to have, for
example, a "north" exit which provides a message like, "You walk down
a long corridor, discover nothing interesting, and return to where you
started." and doesn't actually lead to another room. Such exits give
the illusion of "space", making a small area feel larger. In MudCore,
"fake" exits in the cardinal directions can be designed by placing the
attributes DESC_<direction> and FAIL_<direction> on the room. For the
above example, one might use, "&DESC_NORTH here=To the north is a
long, featureless corridor." and "&FAIL_NORTH here=You walk down a
long, corridor, discover nothing interesting, and return to where you
started."
* * * * *
There is a flag called TRANSPARENT, which can be set on exits. If this
flag is set, players looking at the exit see, after the exit description,
the description of the next room and its contents (but not its succ/fail
messages or exits). This is useful for creating the illusion of an archway
or similar portal, where it makes logical sense to be able to look through
it into the next room.
In 1.50, the TRANSPARENT flag can also be set on rooms. This causes
the obvious exits in the room to be displayed with each exit on a line
by itself, giving the destination room. For example, you might have:
Obvious exits:
South leads to Foyer of the Bank.
East leads to Intersection of Park and Hill Streets.
instead of:
Obvious exits:
South East
3.5 Do it! -- home
This builds a very simple home of three rooms, linked in a triangle:
Living Room
| \
Workroom------Bedroom
Issue the following commands:
@dig/teleport Living Room
[ The room will be dug and you will be moved into it. Note its dbref number ]
@set here=FLOATING
[ Suppresses disconnected room warnings ]
@desc here=<whatever the room looks like>
@dig Workroom=Workroom;w;work;south;s,Living Room;lr;living;north;n;out;o
go workroom
@desc here=<whatever the room looks like>
@dig Bedroom=Bedroom;b;east;e;bed,Workroom;w;work;west
go bedroom
@desc here=<whatever the room looks like>
@open Living Room;lr;living;northwest;nw;out;o=#<xxx>,Bedroom;b;bed;
southeast;se
[ Note: the previous line is wrapped-around. <xxx> is the room number of the
Living Room, which you should have noted earlier. ]
@set here=ABODE
@link me=here
[ Sets your home to this bedroom ]
All three rooms are dug and linked - now, all you have to do is to spiffy
up the exits, and you're all set!
4. Introduction to Programming
4.1 The Stack and string substitutions
The MUSH stores several variables, related to the cause of an action,
the object that is executing an action, and the program state during that
action, referred to as the "stack". These are accessed via a "percent
substitution".
One such variable is the "enactor" -- the object which caused an
action to be performed. For example, if Sareena looks at a Plush Shaav
Doll, Sareena is the enactor. The enactor is sometimes referred to as the
"cause". The percent substitution '%N' returns the name of the enactor; in
this case, it would be "Sareena". The substitution '%n' also returns the
name of the enactor, but the first letter is in lower-case. Another
substitution, '%#', returns the dbref number of the enactor.
It is also possible to get the appropriate pronoun for the enactor.
'%s' is the subjective pronoun (he/she/it). '%o' is the objective pronoun
(him/her/it). '%p' is the possessive pronoun (his/hers/its). The capital
letter forms ('%S', etc.) return the pronoun with the first letter
capitalized. The game determines the pronoun to use by looking the @sex
attribute on the enactor. These substitutions are equivalent to the
function evaluations "SUBJ(%#)", "OBJ(%#)", and "POSS(%#)". In the
example above, since Sareena is female, these substitutions would return
"she", "her", and "hers", respectively.
The substitution %l returns the dbref number of the enactor's
location. This is useful when programming objects in the Master Room,
and does not pose a "security risk", since the enactor has volunteered
his position by triggering a $command or similar.
The object performing the action can be referenced via '%!'. This
returns the dbref number of the object. It is equivalent to the function
evaluation "NUM(me)". In the above example, the object that has been
triggered (and thus is performing the action) is the Plush Shaav Doll.
* * * * *
The "stack" in MUSH is simply a place where strings are stored; it
is not a literal "stack" in the usual sense of having a top object which
can be pushed and popped (as in MUF, or as defined in a standard computer
science class). The stack consists of ten strings, numbered 0 through 9.
Strings on the stack are referred to as %0, %1, %2, and so on, through %9.
The mechanisms for copying strings into the stack will be explained later.
Related to "percent" substitution is the V() function. It produces
identical output to the equivalent percent substitution. For example,
'[v(0)]' is equivalent to '%0', and '[v(N)]' is the same is '%N'.
Throughout this manual, however, '%0' and other percent substitutions
will be used instead of 'v(0)', since the evaluation of percent subtitutions
is faster than the evaluation of V-functions.
26 registers, "numbered" va-vz, are available for programming, as part
of the "standard" collection of MUSH attributes. They may be accessed by
either %va, or [v(va)]. Note that the square brackets [] force something to
be evaluated as a string.
1.50 provides the additional registers wa-wz and xa-xz. These behave
in a manner identical to va-vz.
Percent substitutions should always be used instead of functions,
where possible. In fact, you should ALWAYS use the percent substitution,
unless you are SURE that the function version is required -- use %N instead
of v(N), %! instead of num(me), and so forth. There are virtually no
situations which require the functions, and thus using the function
versions is inefficient and wasteful. Furthermore, please note that
it's just "%0", NOT "[%0]"; the additional square brackets cause an
unnecessary extra evaluation and thus are inefficient.
Please note that if you access something with a percent-substitution, if
you capitalize the first letter of the substitution, then the first letter
of the text returned will also be capitalized.
The S() function forces an additional round of pronoun substitution.
This is useful if you are evaluating a string and want to force the parser
to substitute in the values for all (non-escaped) functions.
Percents can also be used to add in special characters. %r is a carriage
return, %t is a tab character, and %b is a blank space. To show a literal
"%", use "%%". '%r' is actually two characters (a carriage return and
newline), and functions like STRLEN() will count it as two.
Finally, there are temporary storage "registers", also numbered 0 through 9.
They are set via the function SETQ(), and retrieved via the function R(),
or through the %q-substitution. The values set via SETQ() are preserved
through the entire command list associated with a given command. SETQ()
is a function which just returns a blank string, and has the syntax,
"setq(<register number>,<value>)". "r(<register number>)" retrieves the
value. These functions will be explained in greater detail later.
For now, just believe that they allow you to keep values around
temporarily. The odd name SETQ comes from the programming language LISP.
======================================
[ Example 4.1: Percent demonstration ]
> @sex me=female
Set.
> @va me=test
Set.
> say %va
You say "test"
> say %Va
You say "Test"
> say %N is demonstrating %p example.
You say "Amberyl is demonstrating her example."
> say [setq(0,testing for fun)]-- %q0
You say "-- testing for fun"
> say [setq(0,testing for fun)]-- %Q0
You say "-- Testing for fun"
======================================
4.2 General attributes and action lists
The 26 registers are often referred to as "general attributes," since
they can be used to store anything. Often, they are good places to put
variables. In addition to being accessible by the v-function, they can
also be accessed by using the GET() function. The syntax for this is
"get(object/attribute)". "[get(me/va)]" is always equivalent to "[v(va)]"
or "%va".
GET() is very similar to the v-function, except it requires an object
to get the attribute from. It may be used to get any attribute - registers,
descriptions, non-standard attributes, etc. When working only with one object,
it is generally more efficient to use a v-function instead of using GET().
GET_EVAL() is similar to GET(), except that it also evaluates the
attribute. U() is also similar, and also evaluates the attribute, but
it can be used for user-defined functions which take parameters (more
on this later).
GET_EVAL()'s syntax is like GET()'s: "get_eval(object/attribute)"
U()'s basic syntax can be like either V()'s or GET()'s; either
"u(attribute)" or "u(object/attribute)" is valid. (For information
on how to pass parameters to U(), see a later section in this manual.)
There is a subtle difference between the two functions, in addition to
U()'s ability to take parameters
The enactor of a GET_EVAL() is the object which is actually
performing the GET_EVAL(); the enactor of a U() is the original enactor.
======================================
[ Example 4.2a: GET_EVAL() vs. U() ]
> say %!
You say "#3"
> @create Test
Test created as object #1034
> @va test=Enactor: %# -- Me: %!
Set.
> @vb test=$test: @pemit %#=Get_Eval: [get_eval(me/va)]%rU: [u(va)]
Set.
> test
Get_Eval: Enactor: #1034 -- Me: #1034
U: Enactor: #3 -- Me: #1034
======================================
If you're confused by the difference between GET(), GET_EVAL(), and U(),
don't worry about it; details will be provided later, and you don't need
to worry about the latter two functions if you're only doing very basic
things with MUSH.
* * * * *
General attributes are often used to store action lists, which are
long lists of commands, to be queued and executed. For example, you could
@create an object called Test, and "@va Test=:explodes.; @destroy me"
General attributes are usually activated by "triggers". The syntax for
this is @trigger object/attribute. @trigger is usually abbreviated to @tr.
Most of the time, one attribute will trigger another, but you can also type
directly @tr object/attribute.
For example, if you typed @tr Test/va, from the example above, you would see:
Triggered.
Test explodes.
You get back your 10 Mark deposit for Test.
Test has left.
You may also pass variables on the stack from attribute to attribute, using
trigger. Often, this is a must, since the stack is cleared when something
new is triggered. The syntax is "@tr object/attribute=thing,thing,thing,etc."
These new things become %0, %1, %2, etc., respectively, in the triggered
register. Almost anything can be legally passed on the stack - function
evaluations of any type, % arguments, numbers, strings, etc.
======================================
[ Example 4.2b: Sentence Reverser ]
[ This object listens for four words and prints them out backwards. ]
> @create Reverser
Reverser created as object #25789
> @listen reverser=* says "* * * *"
Set.
> @ahear reverser=@tr me/va=%4,%3,%2,%1
[ Note that %0 is left out, since %0 is the * says - the person talking ]
Set.
> @va reverser="%0 %1 %2 %3
Set.
> drop reverser
Reverser has left.
Reverser has arrived.
Dropped.
> "First second third fourth
You say "First second third fourth
Reverser says "fourth third second First"
===========================================
4.3 The queue and delayed execution
The queue is the list of commands that the MUSH is going to execute.
All commands are put into it. Most are evaluated quickly, in the order
that they enter the queue (first to last), although @trigger takes at
least one queue cycle to execute and @force at least two. Setting
an attribute also takes time. One must be careful, when programming, that all
commands are getting executed at the correct times. There is no hard and fast
rule for this; experimentation is generally the only way to find out if your
object is executing commands in the correct order.
The queue may be checked by doing a @ps. If you have an infinite loop,
this is likely to be very long. If you're not sure if an object of yours is
infinite looping, @ps is a surefire way of checking.
@ps separates the queue into four sections - Player, Object,
Wait, and Semaphore. The player queue shows what you have triggered; the
object queue shows what your objects have triggered. The Wait queue shows
commands that will be executed in the future - commands that you have queued
using @wait (explained below). The Semaphore queue shows semaphore countdowns
(explained later). The total number of queued commands is also displayed.
The default @ps switch is "@ps/brief". This shows the objects
and the commands they are running. For the wait queue, it also shows
the time to wait. For the semaphores, it shows the object that the command
is waiting on, and if the semaphore is using the timer option, it also
shows the remaining time. Finally, it displays the total count of queued
commands in each of the four categories.
"@ps/long" displays all the information that "@ps/brief" does,
plus the enactor of the object, and any variables which are being passed
on the stack for eventual execution as part of a @trigger.
"@ps/summary" shows just the total count of queued commands. Note
that @ps defaults to displaying the queue for the individual executing
the @ps; only wizards may specify a player name or the "/all" switch.
In the totals line, no matter what switches are specified, the numbers
in each category are shown as Number1/Number2. The first number is the
number of queued commands that you have in that category; the second
number is the total number of commands queued in that category.
Player and Object categories also have a "[#del]", where "#" is the
number of commands deleted from the queue via @halt.
* * * * *
@ps in 1.50 is somewhat different. "@ps" with no arguments shows
your personal queue - the objects and the commands they are running,
and, for the wait queue, the time to wait. It also displays the total
count of queued commands in each of the queues, in the format
<Number of your commands> / <Total number of commands in that queue>.
"@ps all" prints the queue for all players. Wizards can also do
"@ps *<player>" to get a queue for that player. In both cases, a queue
count is provided.
Anyone may do a "@ps count" to get a count of the number of
queued commands.
* * * * *
Infinite loops on objects are dangerous. Every queued command costs
1/64th of a penny. Plus, if an object loops badly enough, it can severely slow
down the game for others. If you have a loop, you can use @halt. It clears
your personal queue. @halt <command> clears your personal queue, and adds that
new command to the queue. @halt <object>=<new command> clears that object's
queue and adds that new command to the queue.
The other way of halting something is to set the HALT flag on it. An
object set HALT is essentially inert - it does not @listen, @triggers and
@force don't work on it, etc. Also, in 1.50, UFUN() and ZFUN() will return
"#-1 OBJECT HALTED" (recursion in a UFUN or ZFUN will automatically set
the object HALT).
The @halt command in 1.50 is slightly different. If you, or one of
your objects, does a "@halt", it wipes out your entire queue. There is no
way to clear the queue commands on just one object. You can also do
@halt <player>=<new command>, which wipes out the player's entire queue
and places the new command in it; if you are not a wizard, the player must
be yourself. "@halt <object>" in 1.50 with no new command also sets the
object HALT. If you just want to stop an infinite loop, use "@halt" with
no arguments.
There is one command called @allhalt (1.50. In 2.0, it's @halt/all)
which is wizard-only. It clears the queue for the entire MUSH, and is used
in emergencies. All connected players receive the message, "Your objects
have been globally halted by <Wizard>."
* * * * *
The syntax of @wait is simple: @wait <number of seconds>=<command list>
There is another, more complex, type of @wait which is timed on objects;
this type of @wait involves a "semaphore" and will be described later.
@wait is very useful for trying to get objects to execute commands in the
correct order, as well as for doing time-delayed sequences - for example,
descriptions on a room that change every few hours.
=============================
[ Example 4.3: Explosive
[ This will create an object which explodes fifteen seconds after being
dropped. It gives a warning five seconds before it explodes. ]
> @create Explosive
Explosive created as object #23083
> @drop explosive=You set down the explosive and ignite it.
Set.
> @adrop explosive=@wait 10=:pulses dangerously. It'll explode in another five
seconds!;@wait 15={:explodes!;@destroy me}
Set.
> drop explosive
Explosive has left.
You set down the explosive and ignite it.
[ 10 seconds pass ]
Explosive pulses dangerously. It'll explode in another five seconds!
[ another 5 seconds pass ]
Explosive explodes!
You get your 10 Marks deposit back for Explosive.
Explosive has left.
============================
4.4 Decision making: @switch
@switch is the closest thing to IF-THEN-ELSE on a MUSH. It is similar to
the CASE statement in many programming languages. Its syntax is
@switch <var>=<cond1>,<action1>,<cond2>,<action2>,<cond n>,<action n>,<default>
@switch statements may be nested. One must be very careful about using commas
and semi-colons when using @switch - any statements which contain either commas
or semi-colons should be surrounded by curly braces { }. A comma will signal
a new case/action, and a semi-colon the end of the @switch statement, if not
in the curly braces. This is a commonly made mistake - when programming
objects whose @switches do not appear to work, always check for misplaced
commas or semi-colons.
One thing to note is that the variable to switch on does not have to be
evaluated within square brackets [ ]. Percent substitutions, like %va, are
okay to switch on, as are functions simply stated, like words(v(va)).
After the variable name is ALWAYS an equals sign. @switch %va=>1,:foo
does NOT mean "if va is greater than or equal to one, :foo". It means "if va
is strictly greater than one, :foo". The equals sign is simply part of the
@switch syntax. If you want greater than or equal to, you will have to use
the GTE() function.
There are two option switches to @switch, /first and /all. In 2.0, which
one is the default will depend on the MUSH ("@list options" to see).
"@switch/all" performs the actions associated with all matching
targets. In other words, if the targets are not mutually exclusive, more
than one set of actions may be undertaken. Its 1.50 equivalent is the
standard "@switch" command.
"@switch/first" matches the first target it can, and executes the
statements associated with that. Even if the targets are not mutually
exclusive, only the actions associated with the first target matched will
be executed. The 1.50 equivalent of this is the "@select" command.
=============================
[ Example 4.4: Dog ]
[ The dog will respond to simple commands that someone says ]
> @create Dog
Dog created as object #23084
> @listen dog=*"Dog, *"
Set.
> @ahear dog=@switch %1=sit,:sits down.,roll over,:rolls over obediently,play
dead,:flops onto the ground.
Set.
> drop dog
Dog has left.
Dog has arrived.
Dropped.
> "Dog, sit
You say "Dog, sit"
Dog sits down.
> "Dog, play dead"
You say "Dog, play dead"
Dog flops onto the ground.
> "Dog, roll over
You say "Dog, roll over"
Dog rolls over obediently.
=============================
4.5 Other ways of triggering
It is frequently useful to be able to trigger an object without having
to pick it up, drop it, or have it listen for something. Therefore, MUSH
provides for "using" objects.
The attributes @use, @ouse, and @ause are associated with the "use"
command. "use <object>" triggers these three registers (note the absence of
the @ sign in triggering). An object can only be used if there is something in
the @ause register. The person who uses the object is shown the message in the
@use; the other people in the room see the @ouse message. The @ause command
list is executed. This, in essence, works just like "get" and "drop" - the
command "use" has simply been added.
========================================
[ Example 4.4: Bubbly pie revisited ]
[ @using the bubbly pie performs an "eating action" and destroy. ]
> @create Bubbly pie
Bubbly pie created as object #30216
> @ause pie=@emit %N gobbles down the bubbly pie.;@destroy me
Set.
> use pie
You use Bubbly pie
Elsa gobbles down the bubbly pie.
You get your 10 Marks deposit back for Bubbly pie.
Bubbly pie has left.
========================================
Another way to trigger an object is to set its @startup. The commands
in the @startup attribute are executed whenever the MUSH is restarted.
This is useful for objects that need to run continuously, such as clocks.
Objects with a @startup attribute are automatically given the STARTUP flag,
represented by "z". This flag is simply used for internal accounting and
does not affect anything else.
4.6 User-defined commands
Perhaps one of the most common ways of triggering an object, user-defined
commands are the closest things to MUCK @action that MUSH provides. They allow
other players to type "command <arguments, if any>" and have that execute just
as if the command was part of the MUSH. Unlike MUCK, however, there are few
global user-defined commands. One must be in the same room with, or carrying,
the object on which the command is defined. The only exceptions to this are
exits/commands defined on the "master room". See the wizard section of this
manual for details.
These commands may be set on any register or non-standard attribute.
The syntax is: @<attribute> <object>=$<command>: <action list>
The command may take arguments by using * or ?, etc., in a format similar to
that use by @ahear/@listen.
User-defined commands are matched on every object in the room or in
your inventory, so you may want to avoid command names that might be
extremely common. Commands on the MUSH are parsed in the order: exit
names, defined MUSH commands (like @desc, page, etc.), then
user-defined commands, then Master Room commands. You should be
extremely careful not to define commands on an object like $p
*:<action>, since this will be parsed as "page" and it will be ignored
by the object. Furthermore, note that many MUSHes have global commands
which begin with '+' and mailers which use '-' as an editing
indicator; thus, you should avoid starting your own commands with
either of those characters.
In 2.0, there are config options which determine two things:
The first is the ability of an object to trigger its own $commands. The
second is the ability to trigger $commands on players. One can, however,
always trigger $commands on an object one is carrying or is in the same room.
===============================
[ Example 4.6: Tray of Food ]
[ This object is a tray of food which you can "eat", "drink" and "discard" ]
> @create Tray of Food
Tray of Food created as object #482
> @va food=$eat: @emit %N takes a slice of bread off the try and eats it.
Set.
> @vb food=$drink: @emit %N takes a cup of water off the tray and drinks it.
Set.
> @vc food=$discard: @emit %N discards %p tray of food;@destroy me
Set.
> eat
Elsa takes a slice of bread off the tray and eats it.
> drink
Elsa takes a cup of water off the tray and drinks it.
> discard
Elsa discards her tray of food.
You get your 10 Marks deposit back for Tray of Food.
Tray of Food has left.
==============================
Sometimes it's useful to be able to find out what $commands are
triggered in a room. 1.50's @scan command allows you to check for a
command match on objects that you control or that are set VISUAL.
The syntax of this command is simply "@scan <string>". It checks for
all possible matches on your location, its contents, yourself, your
inventory, the zone or parent room of your location, your personal
zone, and the master room. It will display the name of any objects
which have commands which could match that string, followed by the
number of commands matched in brackets.
MudCore provides for similar functionality, via its '+scan' command.
It checks for matches, starting from a specific object, and lists
the attributes and command wildcard patterns which match (if you
can examine the object), or the object which matches the commands
(if you can't examine it).
* * * * *
One interesting and quite flexible command is "@verb". This command
essentially allows you to define your own @attr/@oattr/@aattr triplets,
allowing you to define your own "standard" verbs. This command is most
useful for someone who is a wizard.
This command is in the format:
@verb <obj to read attributes off (victim)>=<obj to be told messages (actor)>,
<attr name>, <default message for attr>,
<oattr name>, <default message for oattr>,
<aattr name>, <args>
Most of those those fields should be self-explanatory; <args> are
the values to be passed on the stack, as %0-%9. For example, to simulate
"drop" with a command like "put", you would use a user-defined command
something like:
$put *: @verb [v(0)]=[v(N)],DROP,Dropped.,ODROP,dropped [v(0)].,ADROP
Under 2.0, both the victim and actor must be controlled. Under
1.50, either both victim and actor must be controlled, or the thing which
triggered the verb must be <actor> AND the object which issued the @verb
command must be able to read the attributes from <victim>. Essentially,
though, one needs to be a wizard in order to make this command generally
useful. It is, however, a rather nifty thing to play with.
4.7 An introduction to functions
Functions are generally used to manipulate strings and other input, or
to generate or retrieve something. They are called using:
<function-name>(<arg1>,<arg2>,<etc>) and evaluation often requires square
brackets [ ] to be put around the function. It is imperative that the right
number of arguments be passed to the function, and that the parentheses are
correctly matched. You should always use %-substitutions instead of functions
where possible, i.e., %va instead of v(va). Functions may be nested. Only
one pair of square brackets is required around a given function call.
Certain functions, such as V() and GET(), have already been introduced.
Only a few functions require no arguments; TIME(), which simply
returns the current time on the MUSH, is probably the most commonly
used of these. All other functions require one or more arguments. The most
commonly used, aside from the v, s, and get() functions, is the RAND()
function. This generates a random integer between 0 and <number - 1>.
There _is_ a limit to the number of arguments a function can take; you
can find out what this is by asking a local wizard. This is generally 100.
The limit is something to keep in mind if you are doing extremely large calls
to a function like SWITCH(), which takes an arbitrary number of arguments.
Functions used to access basic db info include NUM(), FLAGS(), OWNER(),
LOC(), and MONEY(). These are publicly accessible, and give an object's
database reference number, flags, owner, location (for a player), and money
(also for a player). These functions will be discussed in more detail
later. Other publicly accessible attributes include DESC, and
are gotten using the GET() function. All attributes on an object set VISUAL
are publicly accessible.
Functions used to process lists will be covered later in this manual.
The following functions are used for arithmetic: ADD(), SUB(), MUL(), DIV().
Note that SUB() does not exist in many versions of MUSH code; instead, one
must add the negative of the second number. Some of these functions, such
as SUB(), take ONLY two arguments. Others, like ADD(), can take multiple
arguments (just like LISP arithmetic operators). For example,
"add(2,3,4)" is equivalent to (and more efficient than) "add(2,add(3,4))".
=============================
[ Example 4.7a: Abacus ]
[ An object that performs arithmetic ]
> @create Abacus
Abacus created as object #19831
> @va abacus=$*+*: @emit The sum of %0 and %1 is [add(%0,%1)].
Set.
> @vb abacus=$*-*: @emit The difference of %0 and %1 is [sub(%0,%1)].
Set.
> @vc abacus=$*x*: @emit The product of %0 and %1 is [mul(%0,%1)].
Set.
> @vd abacus=$*/*: @emit The quotient of %0 and %1 is [div(%0,%1)].
Set.
> 1+2
The sum of 1 and 2 is 3.
> 2x6
The product of 2 and 6 is 12.
> 8-5
The difference of 8 and 5 is 3.
> 9/3
The quotient of 9 and 3 is 3.
==============================
Here's another example, demonstrating the combined use of @switch and RAND(),
"use", and various %-substitutions.
======================================
[ Example 4.7b: Plush Shaav Doll ]
[ To conserve space, 'Set.' messages after attribute sets have been omitted. ]
> @create Life-size Plush Shaav Doll
Life-size Plush Shaav Doll created as object #3895
> @desc doll=This is a plush doll nearly six feet in height. It's fuzzy and
and cute, featuring the Grand Hierarch Shaav wearing his usual calm
expression, although the effect is somewhat spoiled by the fluffy stuffing
and bright green-button eyes. The life-sized doll is clothed in the black
robes of the Grolims, and would probably seem to radiate evil if it didn't
look so snuggly. It's probably made by the same people who made Belzoinks.
> @succ doll=You prop up a life-sized plush doll of Shaav.
> @osucc doll=grins evilly as %s props up a life-sized plush doll of Shaav.
> @drop doll=You drop a life-sized plush doll of Shaav on its head.
> @odrop doll=drops a life-sized plush doll of Shaav on its head.
> @use doll=You pull a string on the doll's neck.
> @ouse doll=pulls on a string on the plush Shaav doll's neck.
> @ause doll=@switch rand(4)=
0, {:points a finger at %N and squeaks. "Die!"},
1, {:screams:%tDeath!%tDestruction!%tChaos!},
2, {:looks at %N for a moment, then booms to %o, "DOOM."},
3, {:squeaks. "Mama!%b%bMama!%b%bMama!"}
[ If Polgara (a female) types "use doll", she sees "You pull a string on the
doll's neck", plus one of the following messages: ]
Life-size Plush Shaav Doll points a finger at Polgara and squeaks. "Die!"
Life-size Plush Shaav Doll screams: Death! Destruction! Chaos!
Life-size Plush Shaav Doll looks at Polgara for a moment, then booms to
her, "DOOM."
Life-size Plush Shaav Doll squeaks. "Mama! Mama! Mama!"
Note the use of "%b" and "%t" substitutions for blank spaces and
tabs. Because "%t" inserts a literal tab character, the spacing will
vary depending on where tab stops are set by the player's terminal.
Also note that the @switch action clauses had to be enclosed in braces,
since the statements used inside contained commas.
==============================
4.8 Do it! -- falcon control
This section assumes that you have created the falcon as per section
2.9 of this manual. The object you will create in this example will be used
to control it. <#FL> below refers to the dbref number of your falcon,
and <FL> refers to the name of your falcon.
The controller will give you the ability to force your falcon
remotely to pose and think messages, return to you on command, and go to a
player on command, using: '<message> to think a message, .<pose> to pose
something, return to recall the falcon, and goto <player> to go to a
player's location.
Issue the following commands:
@create <FL>'s controller
[ Then lock it, desc it, etc. ]
@va controller=$'*: @fo <#FL>=:chirps << %0 >>
[ This is used for "speech" ]
@vb controller=$.*: @fo <#FL>=:%0
[ This is used for forcing the falcon to pose ]
@vc controller=$fly *: @fo <#FL>={:soars into the air and flies off.; %0}
[ This is used to have the falcon fly in a given direction ]
@vd controller=$return: @fo <#FL>={:returns to %N.; @set me=!puppet;
@tel me=owner(me); leave; :soars towards you!; @set me=puppet}
[ This brings the falcon back to you, with appropriate messages. The
INHERIT flag must be set in order for this to work. ]
@ve controller=$goto *: @fo <#FL>={@switch loc(*%0)=#-1,{p <your name>=I can't
find %0}, {:goes to find %0.; @tel me=loc(*%0); :soars towards you!}}
[ This is used to go to the location of a player. It first checks to see if
the player can be found - if the player does not exist or the player is set
UNFINDABLE, #-1 is returned and the falcon pages the player with the
fail message - and then, if the player exists, teleports to that player's
location, with appropriate messages. ]
INDEX OF SECTION II EXAMPLES:
3.1 Living Room
3.5 Home
4.1 Percent demonstration
4.2a GET_EVAL() vs. U()
4.2b Sentence Reverser
4.3 Explosive
4.4 Dog
4.5 Bubbly pie revisited
4.6 Tray of food
4.7a Abacus
4.7b Plush Shaav Doll
4.8 Falcon control