tinymush-3.1p2/game/backups/
tinymush-3.1p2/game/bin/
tinymush-3.1p2/game/data/
tinymush-3.1p2/game/modules/
tinymush-3.1p2/game/modules/old/
tinymush-3.1p2/src/modules/comsys/
tinymush-3.1p2/src/modules/hello/
tinymush-3.1p2/src/modules/mail/
tinymush-3.1p2/src/tools/
& help
 
This is the helpfile format of version 2.008 of Amberyl's MUSH Manual.
Some very tiny edits have been made to correct information that is now
egregiously out of date.
 
This manual is divided into five sections (labeled with Roman numerals),
but there are around fifteen subsections total. This helpfile is divided
by subsection. The Roman numerals themselves are only tables of contents
and introductions to each major section.
 
Sections are accessed as follows:
 
 man 1       This shows the name of chapter 1 and any notes the author
             included.
 man 2.5     This accesses page 1 of what's in section 2, subsection 5.
 man 3.4.2   This shows the second page of section 3, subsection 4.
 
For a list of sections, type 'man list'.
For some caveats, type 'man caveats'.
For credit information, type 'man credits'.
 
& caveats
 
This manual was written back in 1995. Over four years later, the
information within it is not entirely current. Though most of the
information, particularly the basic information, is still relevant
and more or less correct, details and common practices have changed
over the years with the evolution of the MUSH servers and trends
in MUSH administration and code systems. Indeed, the specific slant
of topics in the manual may seem a little odd to current readers,
due to the change in MUSH culture over those years. Read at your
own risk.
  
The author is presently at work on a from-scratch rewrite of the
manual, reflecting TinyMUSH 3.0 and current MUSH coding and
administration practices.
 
& credits
 
This manual was written by Lydia Leong (lwl@godlike.com), and converted
to helpfile format by Alierak and sTiLe. The author is deeply grateful
for their hard work.
 
& list
 
The following main topics are available for viewing:
README, Introduction, I, II, III, IV, V, wizeth, index1, index2, index3
 
README is the readme file that comes along with the manual, describing
copyright information and whatnot.
 
Introduction contains a main table of contents and a description of the
manual.
 
Wizeth contains an expanded version of the author's speech on wiz ethics.
The index# sections have an index of examples.
 
For a table of contents, you should read man intro. Partial tables of
contents can be viewed in the I, II, III, IV, and V sections.  There
should be a man topic for each sub-number listed in the tables of
contents. (e.g. 2.3)
 
& I
MUSH Manual Version 2.008:
   Copyright 1993, 1994, 1995, Lydia Leong (lwl@godlike.com / Amberyl)
   Last revised 5/22/95.
 
Section I: Getting Started. Basic commands and objects.
 
Table of Contents:
 
Introduction: A brief history of MUSH. Configurations and server differences.
 
1. The Basics
 1.1  Some information
        Common terms used on MUSHes.
        The format of this manual.
 1.2  Getting started
        Looking around: look, examine, @decompile, TERSE, MYOPIC, @grep
        Communications: ", :, @emits, page, whisper, basic flags and @set,
           HAVEN, GAGGED, NOSPOOF
        Going places: JUMP_OK, @tel, @whereis, UNFINDABLE
 
(Continued in 'man I1'.)
 
& introduction
(To skip the TOC, type 'man intro8'.)
MUSH Manual Version 2.008
  Written for TinyMUSH version 2.2.1
              TinyMUSH version 2.0.10 patchlevel 5
              PennMUSH version 1.50 patchlevel 12
              MudCore Starter Database version 1.0
  Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999,
            Lydia Leong (lwl@godlike.com / Amberyl)
 
Section I: Getting Started. Basic commands and objects.
 
Introduction: A brief history of MUSH. Configurations and server differences.
 
1. The Basics
 1.1  Some information
        Common terms used on MUSHes.
        The format of this manual.
 1.2  Basic commands
         Looking around: look, examine, @decompile, TERSE, MYOPIC, @grep
         Communications: ", :, @emits, page, whisper, basic flags and @set,
            HAVEN, GAGGED, NOSPOOF
 
(Continued in 'man intro2'.)
 
& intro2
         Going places: JUMP_OK, @tel, @whereis, UNFINDABLE
         Objects: get, drop, give, ENTER_OK, inventory
         Command syntax, @set and flags, special commands, @list
 1.3  Attributes: @desc, @succ, @fail, @drop, @kill, IMMORTAL, @move, @sex
 1.4  Editing: @edit, @mvattr, @cpattr
 1.5  Do it!  --  basic character set-up
 1.6  A parser discussion
2. Objects
 2.1  Basic object commands: @create, @destroy, @force, @name, VISUAL
 2.2  Puppets - the PUPPET flag. ROBOTs.
 2.3  A Note about Privacy: @sweep
 2.4  Attributes on Objects: Action Lists
 2.5  Machines: @cost, @pay, and @clone, QUIET and DESTROY_OK flags, @parent
 2.6  Limiting object uses: @charges and @runout
 2.7  Reacting to the environment: @listen and @ahear, ^, LISTENER/MONITOR
 2.8  Keeping your objects safe: @lock, @unlock, @chown, CHOWN_OK, STICKY,
         @search, @find, @stats
 2.9  Do it!  --  falcon
 
(Continued in 'man intro3'.)
 
& intro3
Section II: Building and an introduction to programming
 
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
 
(Continued in 'man intro4'.)
 
& intro4
Section III: Programming applications
 
5. Vehicle programming
 5.1  Entering and leaving objects: @enter, @aenter, @oenter, @oxenter,
      @leave, @aleave, @oleave, @oxleave
 5.2  Inside vehicles: @idesc, @listen, relays, and commands, @remit,
      AUDIBLE, @prefix, @filter, @forwardlist
 5.3  Do it!  --  Wagon controller
6. Complex programming
 6.1  Useful functions:
         General use: NUM(), LOC(), NEARBY()
         List creation: LCON(), LEXITS(), LWHO()
         Parsing: POS(), FIRST(), REST(), STRLEN(), MID(), WORDS()
         Matching: EXTRACT(), MATCH(), MEMBER(), UCSTR(), LCSTR(), CAPSTR()
 6.2  Non-standard attributes: & and attribute flags
 6.3  Introduction to @dolist
 6.4  Time synchronization: semaphores, complex @wait, @notify, @drain
 6.5  Security problems in programming, INHERIT, ESCAPE(), and SECURE(),
         @fsay, @femit, @fpose
 
(Continued in 'man intro5'.)
 
& intro5
 6.6  Debugging: PUPPET and VERBOSE
 6.7  On the New Programming Style
7. MUSH Programming: QuickStart Guide
 7.1  Basic syntax
 7.2  Conditional and loop constructs
 7.3  Functions
 

Section IV: A Guide for Administrators
 
8. Owning and seeing everything
  8.1  Special privileges, ROYALTY, and Powers
  8.2  Attribute ownership - @atrchown and @atrlock
  8.3  Object ownership - @chown and @chownall
  8.4  The queue - @ps and @allhalt, @kick
  8.5  The database - @entrances, @find, @search, and @stats
  8.6  A note about security and privacy
  8.7  The Master Room and command processing
9. Wiz-specific commands
 
(Continued in 'man intro6'.)
 
& intro6
  9.1  Talking to other wizards: @wizwall and @wizemit
  9.2  Messages: @wall, @listmotd, @motd, and @wizmotd
  9.3  Locking out players: @login and @rejectmotd
  9.4  Dealing with players: @newpassword, @pcreate, @boot, @toad, and @destroy
  9.5  Dumping the database: @dump and @shutdown
10. Database control
  10.1  Quota system: limited object creation - @allquota, @quota, and @squota
  10.2  Money control: give and @poor
  10.3  Consistency checking: @dbck and @purge, @dump/paranoid, @cut, @fixdb
11. Zones
  11.1  Object zones
  11.2  Parent room zones
  11.3  ZoneMaster players
  11.4  Some notes on local wizard control
12. The Fundamental Laws of Wizarding
  12.1  Wizard Etiquette
  12.2  The Five-Step Method of player management
          warning - nasty warning - gag - boot - newpassword
  12.3  Wizard commands and when they ought to be used
 
(Continued in 'man intro7'.)
 
& intro7
Section V: The Art of Psychocoding
13. Basic Concepts
  13.1  Attribute naming and coding style
  13.2  String concatenation and the switchless style
  13.3  What the parser really does
  13.4  Zones in TinyMUSH 2.2
14. List manipulation
  14.1  Adding to, removing from, and comparing lists
  14.2  Function building blocks: U() and SWITCH(), @function
  14.3  Formatting strings: SPACE(), REPEAT(), LJUST(), and RJUST()
  14.4  Lists instead of @dolists: ITER() and FILTER()
  14.5  Recursion: theory and practice, FOLD()
15. Efficiency
  15.1  Parameter passing: U(), ULOCAL(), local registers, SETQ(), and R()
  15.2  How the queue works
  15.3  Pipelining
  15.4  Queue cycles vs. CPU cycles
 
(Continued in 'man intro8'.)
 
& intro8
This is the table of contents for Amberyl's MUSH manual. She can be
found on PernMUSH, or at lwl@godlike.com. This manual should be current
through TinyMUSH version 2.2.1, and PennMUSH version 1.50 patchlevel 12.
Much of it should also apply to TinyMUSH version 2.0.10 patchlevel 5
(from which TinyMUSH 2.2 is derived). Differences between the two
versions will be noted where necessary; in general, 2.0 will refer to
features common to both 2.0 and 2.2, and 2.2 will denote features
specific to 2.2. Do note that because 2.0.10p5 is now an obsolete
version, and 2.0.10p6 is not much more advanced, that there may be
sections of this manual which simply do not function under those
code versions, or which require modification (for example, 2.0.10p5
does not have the %q-substitution, though it does have the R() function).
 
This manual version also covers commands that are softcoded in MUSH,
found in the MUSHcode starter database called MudCore. MudCore global
commands are found on a variety of MUSHes, most notably PernMUSH and
AmberMUSH; it is convenient to mention them in this manual, since
many tasks can be simplified by use of these globals, and even those
MUSHes that don't use MudCore or the equivalent do have globals which
perform similar functions.
 
(Continued in 'man intro9'.)
 
& intro9
The 2.0x manual series is a complete rewrite using the 1.15 manual as
a starting base. Unlike the previous manual, this one is intended to
replace anything that has come before, including Croaker's manual,
which is pretty much obsolete for this version of code.
 
Those programming MUSE should probably look at the 1.15 manual release
instead, or use Falryx's MUSE Manual, which is based upon this manual
(with permission). The MUSE parser is quite close to the original 1.x
parser, and the basic examples in this manual should work without any
problems. The MUSE powers system and related issues are beyond the
scope of this manual (and the author's knowledge, for the most part);
the helptext for MUSE and consultation with a MUSE programmer are
probably the best ways to figure out how to program MUSE.
 
(Continued in 'man intro10'.)
 
& intro10
TinyTIM players may still find Croaker's manual helpful. There is also
a TinyTIM supplemental manual, since TIM has diverged quite a bit from
the "mainstream" MUSH. The contents of the PernMUSH 1.15 manual and
this manual may or may not apply to TinyTIM. The parser on TIM,
however, is fairly similar to the standard 1.x parser. There is,
however, probably little of interest in this manual for the TinyTIM
player, since most of the features mentioned here do not exist on TIM.
 
This is the tenth revision of this manual. There have been some major
revisions in the servers since the prior revision, though these
primarily affect advanced programming techniques and administrative
commands. This manual only documents the most important of these; for
the rest, the helptext should suffice.
 
(Continued in 'man intro11'.)
 
& intro11
I have also corrected a number of previous errors, and further
expanded the notes on advanced programming techniques, which seem to
be in great demand. There are also a number of formatting changes,
which, in my opinion, make the text easier to read. A fair amount of
the text has been expanded (and hopefully clarified); I've also chosen
to introduce more "advanced" programming techniques earlier in the
manual. Finally, I've taken the opportunity to explicitly debunk a few
myths about MUSH programming, as well as provide specific methods for
things that I often see programmed incorrectly or inefficiently.
There are a lot of small changes, and a few sections added and
removed. The structure of this manual is slowly becoming obsolete,
due to the changing methods of MUSH programming, and, specifically,
learning to program MUSH; it is likely that future revisions of the
manual will restructure substantial portions of the text.
 
(Continued in 'man intro12'.)
 
& intro12
The tenth revision is also the first version of the manual to document
a softcoded package of MUSHcode, in this case, the MudCore Starter
Database. I regard the standardization of certain core pieces of
softcode as something which will ultimately make the transition from
one MUSH to another much easier, and thus I'm going to attempt to
support a standard by placing it in the manual. MudCore is slated
for an early-summer 1995 release; portions of it can be found on
games such as PernMUSH and AmberMUSH.
 
The ninth revision of the manual was relatively minor, correcting
previous mistakes, expanding various bits of material, attempting to
clarify the somewhat confused earlier explanation of semaphores, and
adding additional material on advanced programming topics.
 
(Continued in 'man intro13'.)
 
& intro13
The eighth revision of the manual was the first to cover advanced
programming, in a newly added section. The rest of the manual,
however, is not meant to be a guide to advanced programming, nor does
it necessarily show the "best" way to do something. It is intended to
show the most intuitive and basic way to get something done in MUSH.
It is also not a complete guide to MUSH; for that, you need to look at
the helptext. This manual is meant to act as a tutorial and as a
pointer to some of the more useful things available in MUSH, as well
as to clarify some of the things that are not easily covered in the
helptext. For the precise syntactic details on a command, look up the
help text; especially in the latter sections, this manual attempts to
avoid duplicating material found in the help, concentrating instead on
techniques and details.
 
(Continued in 'man intro14'.)
 
& intro14
The final "advanced programming" section of the manual convers the
"new" style of MUSH programming, which relies heavily on list
manipulation functions and string concatenation to produce the desired
result. This is commonly referred to as the "switchless style". While
I believe this is something best learned on one's own, an overview of
the common techniques is presented here. It also includes a discussion
of how to write programs that are efficient in their use of queue
cycles, without overburdening the server itself with very large,
complex function evaluations.
 
If you spot any errors in the manual, PLEASE send me email. You should
mention the specific MUSH version you are using, and mention as
specifically as possible where the error is.
 
Finally, by way of thanks to the various people who have, in the past,
contributed examples/typo reports/etc. to this manual, I've thrown
their names in as player examples in various places. I hope they enjoy
their brief moment of fame.
 
(Continued in 'man intro15'.)
 
& intro15
A "README.mushman" file accompanies this manual distribution,
and must be retained with any electronically-retrievable version of
this manual. To summarize the copyright notice contained therein:
 
This manual was written by Lydia Leong (lwl@godlike.com), and any
rights and privileges of reproduction are hers, in accordance with
United States or international Copyright Laws. Users are granted
permission to print and reproduce this manual in its unmodified
entirety, as long as this copyright notice is retained and due credit
given, and the material remains free of charge. It can be quoted, with
credit, within the bounds set by standard academic protocol. It may
NOT be used within another major document (such as another manual),
nor published in print form (whether or not the publisher makes a
profit from such publication), nor may it be hypertextified or
otherwise changed in format, without the explicit permission of the
author.
     --  Amberyl, May 22nd, 1995
 
& I1
        Objects: get, drop, give, ENTER_OK, inventory
        Command syntax, @set and flags, special commands, @list
 1.3  Attributes: @desc, @succ, @fail, @drop, @kill, IMMORTAL, @move, @sex
 1.4  Editing: @edit, @mvattr, @cpattr
 1.5  Do it!  --  basic character set-up
 1.6  A parser discussion
2. Objects
 2.1  Basic object commands: @create, @destroy, @force, @name, VISUAL
 2.2  Puppets - the PUPPET flag. ROBOTs.
 2.3  A Note about Privacy: @sweep
 2.4  Attributes on Objects: Action Lists, @decompile, the parser
 2.5  Machines: @cost, @pay, and @clone, QUIET and DESTROY_OK flags, @parent
 2.6  Limiting object uses: @charges and @runout
 2.7  Reacting to the environment: @listen and @ahear, ^, LISTENER/MONITOR
 2.8  Keeping your objects safe: @lock, @unlock, @chown, CHOWN_OK, STICKY,
         @search, @find, @stats
 2.9  Do it!  --  falcon
 
(Continued in 'man I2'.)
 
& I2
INTRODUCTION:
 
MUSH is a derivative of the original TinyMUD. In general, a MUSH is a
place where players can hang out, socialize, program, and build. There
are nearly four dozen public MUSHes running at the time of this
writing. Most MUSHes use variants of either the PennMUSH 1.50 or
TinyMUSH 2.0 servers (TinyMUSH 2.2 is derived from TinyMUSH 2.0);
although behavior for all MUSH versions should be similar, code
patches and unofficial modifications are very common, so what works on
one MUSH won't necessarily work on another. This manual describes the
"standard" behaviors for the official MUSH versions.
 
MUSH looks very similar to the text adventure games that were popular
in the mid-1980s. The difference between a MUSH and an Infocom game is
the crudity of the parser, the user-extendibility, and the
multi-player capability of the former. The programming language of
MUSH is most similar to LISP, in its emphasis on lists and the way
functions are evaluated.
 
(Continued in 'man I3'.)
 
& I3
The MUSH code dates back to spring of 1990, or so. The only presently
surviving MUSH from that era is TinyTIM. Somewhat later came
MicroMUSH, and TinyCWRU. All three were based off the original
TinyMUSH, which was a heavily modified TinyMUD, done by Lawrence
Foard.
 
In January of 1991, PernMUSH was started, using MicroMUSH code as a
base. Moonchilde began to distribute PernMUSH code a little while
later, while MicroMUSH became MicroMUSE. In the spring, the 2.0
rewrite project was started. MUSH had become a messy collection of
hacks, and most of them were non-standard; JT Traub (Moonchilde of
PernMUSH), Glenn Crocker (Wizard of TinyCWRU, Dave Peterson (Evinar of
TinyDungeon), and some other programmers got together to completely
rewrite the MUSH code.
 
(Continued in 'man I4'.)
 
& I4
"Vanilla" MUSH code - the unadulterated original by Larry Foard - is a
relic of the past; the MicroMUSH code off which PernMUSH is based has
also essentially disappeared. TinyTIM has never distributed its code,
and is significantly different from the other existing MUSH
codes. These three MUSH versions, therefore, are not covered in this
manual.
 
PernMUSH switched to 2.0 code in November of 1991. The 1.x code
fragmented into three versions - Spellbound, based off PernMUSH 1.13,
SouCon, based off PernMUSH 1.14, and PennMUSH, based off PernMUSH
1.15, Moonchilde's final distribution. Only the last still exists, and
it was the only one of the three versions to be publicly distributed;
the name was changed to "Penn" to avoid confusion, since PernMUSH
itself switched to using 2.0 (and now, 2.2).
 
(Continued in 'man I5'.)
 
& I5
In the fall of 1994, a number of wizards from large MUSHes got
together to discuss the difficulties of TinyMUSH 2.0. TinyMUSH 2.0
releases over the past year had been, by and large, fairly buggy, due
to lack of testing in a "production MUSH" environment (one open to
large numbers of players). Furthermore, gripes about the bugs
introduced with new "features" resulted in the virtual end of
development of new features. It was decided to begin work on a server
development project, called TinyMUSH 2.2 (there had been an aborted
TinyMUSH 2.1 project which attempted to use the UnterMUD OIF format
for a database). TinyMUSH 2.2 is more a continuing of TinyMUSH 2.0
development than an actual new server. It is the pet project of Jean
Marie Diaz (Ambar of PernMUSH), Devin Hooker (Tyleet of Two Moons),
and Lydia Leong (Amberyl of PernMUSH), in conjunction with a number of
other helpful people. Every reference to TinyMUSH 2.0 in this manual
also applies to TinyMUSH 2.2, unless specifically stated otherwise.
 
(Continued in 'man I6'.)
 
& I6
This manual is being written specifically for the PennMUSH 1.50 and
TinyMUSH 2.0 / TinyMUSH 2.2 code releases, currently available via
mellers1.psych.berkeley.edu, caisr2.caisr.cwru.edu, and
ftp.cis.upenn.edu, respectively. Should you wonder at the references
to dragons and similar objects throughout this manual, realize that
the examples were originally written to fit the world of PernMUSH,
presently located at astral.magic.ca 4201; as this manual has
evolved, other examples from other worlds, such as The Belgariad (once
at csa.bu.edu 4201) were thrown in, together with more generic
objects.
 
If you're trying to program any flavor of MUSH besides TinyMUSH 2.x,
or a MUSH version earlier than 1.16, you are better off getting
the version 1.15 of the Pern manual (mushman.1.15.shar.Z, probably
located at the same place you got this manual). This manual is more
detailed than that one; it is intended to cover MUSH programming
extensively. I have tried to make the examples useful; if you work
through the manual's Do It! sections, whether or not you completely
understand them, you should have some rooms built for a house, a
falcon, a vehicle, and some assorted other useful objects.
 
(Continued in 'man I7'.)
 
& I7
Please note that the 2.0 examples in this manual assume that your MUSH
has a certain set of "common" aliases and command options. TinyMUSH
2.0 is highly configurable. If something doesn't work, or works
differently from the way it is described in this manual, chances are
that the configuration is different. The command "@list options" lists
many of these options.
 
Differences between 1.50 configurations are generally less visible,
and generally only affect the way things are displayed, or the
internals of the server, instead of directly changing the behavior of
a command (for example, whether @switch matches all cases or just the
first one).
 
   --  Amberyl (lwl@godlike.com)
& 1
1. The Basics
 
& 1.1
1.1     Some information
 
These are terms which are in common use and which you should know:
 
Player: the person who is reading this manual.
Character: the virtual-person who wanders around the MUSH under the control
        of the player.
Puppet: an object that is under the control of a character, who can see and
        perform actions of its own.
Robot: something which appears to be a character, but is actually an
        external program, usually written in C or LISP, which, when run,
        connects to a remote computer and pretends to be a player. Some are
        quite sophisticated. This word is also used to refer to objects which
        are programmed, using MUSH code, to behave like players, or to perform
        a specific function, like deliver mail. Sometimes robots will be
        referred to as 'bots.
Machine: Objects which are programmed to do certain things, like dispense
        mugs of klah, or repeat the word "Die" every five minutes, or any one
        of a thousand different possibilities. The second type of robot
        mentioned above is a type of machine.
 
(Continued in 'man 1.1.2'.)
 
& 1.1.2
Flag: Something which controls behavior of an individual object. It can
        be either on or off, and usually affects the kind of output the
        object sees/gives. The '@set' command is used to turn a flag on
        or off on a particular object. A frequently used terminology in
        this manual is "<object> is [not] set <flagname>".
        "Joshua is set OPAQUE" simply means that 'Joshua' has the 'OPAQUE'
        flag set on himself (i.e. it is turned on).
Object Type: Objects are classified into one of four types: PLAYER, THING,
        ROOM, or EXIT. A 'player' is something which can be connected to
        via a name and password, who can own things and functions
        independently of anything else in the game. A 'thing' is a mobile
        object, which can be picked up, dropped, and manipulated in various
        ways. An 'exit' is a link which connects two locations in the game.
        These locations are normally known as 'rooms'. (You can be inside
        a thing, too, but a 'room' is the basic unit of building).
        In this manual, 'object' and 'thing' are sometimes used generically
        to refer to objects of any type.
 
(Continued in 'man 1.1.3'.)
 
& 1.1.3
Dbref: Every object in the database is assigned a number, called a
        "database reference number", or "dbref" for short. A hash sign
        normally prefixes a dbref, i.e., "#100". The dbref is the object's
        unique identifier (unlike its name, which could be the same as
        that of many other objects).
Client: a program which replaces telnet. Clients are designed specifically
        to connect to MUDs, and frequently provide many features that are not
        available with ordinary telnet, such as macros, logging, hiliting,
        and the ability to switch between several worlds very quickly. Two
        popular clients are TinyTalk and TinyFugue. The latter is an improved
        version of the former. Both run under UNIX.
Mark: the unit of currency on Pern. Other places use Pennies, Credits,
        Dollars, or even Cookies. The cost of an action varies from nothing to
        100 Marks, for commands which are computationally expensive. Players
        normally get a certain amount of money every day.
God: the person who is, overall, in charge of the MUSH. He is generally
        responsible for code maintenance and general order. He has powers
        not available to anyone else, and may not be @forced by anything.
 
(Continued in 'man 1.1.4'.)
 
& 1.1.4
Wizard: a game administrator, picked by God to help run the game. Wizards
        control all objects, and have special commands available to them.
        Wizards cannot hear things that ordinary players cannot.
Royalty: a game administrator, a kind of "sub-wizard". Royalty can see all
        objects as if they controlled them, but cannot change them.
Mortal: a non-wizard, non-royalty player.
Control: Every object in MUSH is controlled by one or more things. Players
        always control the objects they own. Wizards control everything.
        There are other ways to control objects; these will be explained
        later.
 
Commonly used abbreviations:
  IMHO: In My Humble (or Holy) Opinion
  RL: Real Life. The world outside MUDs.
  VR: Virtual Reality. The MUD world or worlds.
  OOC: Out of Character. Used when the player rather than the character
       is the one speaking, such as when a dragonrider character on PernMUSH
       wishes to comment on the features of the latest SPARC station.
       The opposite of this is 'IC' -- 'In Character'.
 
(Continued in 'man 1.1.5'.)
 
& 1.1.5
  LOL: Laughs Out Loud.
  ROTFL: Rolls On the Floor Laughing.
 
Now that the definitions are out of the way:
 
Examples in this manual will be set off by  [ Example Number ] at the
beginning and = signs around the example. Words that appear in <  >
aren't supposed to be typed in literally. For example, if I use
"<your name>", don't type that, but type your name instead. In examples,
lines that begin with "> " indicate something that I've typed in.
Words that appear in [ ] are optional; for example, if I use
"examine[/brief]", you could either type "examine" or "examine/brief".
Everything else is the MUSH's response. The 'main character' used in the
examples is Elsa, on PernMUSH. Various other characters are used as
props throughout the manual; most of them are PernMUSH players who have
contributed in some way to this manual and are thus being immortalized
by way of thanks.
 
& 1.2
1.2     Basic Commands
 
Looking around:
 
The "look" command (abbreviated "l") allows you to look at your
surroundings. "Look" by itself shows you the description of the room
you are in. "Look <object or exit>" shows you the description of that
object or exit. You may specify a thing by its name, its dbref number,
as *player, or as "me" or "here". "Read" is identical to look in all
respects.
 
Possessive "look" allows you to look at something that someone or
something is carrying. The syntax is just: "look <object>'s <thing>".
You cannot look at someone's inventory if they are set OPAQUE or DARK.
(OPAQUE and DARK are flags, and will be explained in more detail
later.)
 
(Continued in 'man 1.2.2'.)
 
& 1.2.2
You automatically "look" at every room you enter. If you are trying to
move rapidly through familiar areas, you may want to set yourself
TERSE.  This flag suppresses room descriptions and room success/fail
messages; the MUSH will display only the location name, its contents,
and the obvious exits.
 
The MYOPIC flag prevents you from seeing the dbref numbers and flags
on objects that you control. If you like your output "pure", you may
wish to set yourself MYOPIC.
 
* * * * *
 
The "examine" command (abbreviated "ex") provides more detailed
information about an object. If you do not control the object, this
command will tell you who the object is owned by, and (in some
configurations) show you any public attributes on that object, such as
the desc, sex, and "last" connect time. If you are in the same room
with the object, and the object is neither DARK nor OPAQUE, you are
also shown the list of all its non-DARK contents, and any non-DARK
exits. You can also use "examine/brief" to see just the owner's name.
 
(Continued in 'man 1.2.3'.)
 
& 1.2.3
1.50 has the "brief" command. This is like "examine", except
that brief shows all object information EXCEPT for attributes.
 
In 2.0, if the config directive "examine_public_attrs" is on,
normal players will trigger the looked-at object's adesc when they
examine/full the object, if the object is in the same room. Wizards,
however, do not trigger this.
 
If the object is not in the same room, you do not control it, and the
"examine_public_attrs" config directive is off, you will see <Too far
away to get a good look> instead of the description, and cannot get a
contents list, although you will still see other public attributes and
the owner's name.
 
If you own the object or the object is set VISUAL, examine will show
you the full list of attributes on the object, and other properties on
it.  To see a specific attribute, "examine object/attribute".
 
(Continued in 'man 1.2.4'.)
 
& 1.2.4
You may use wildcards - * and ? - in examine, to match a group of
attributes. The '?' wildcard matches any single character (but must match
at least one character); the '*' wildcard matches any number of characters
(including "none"). For example, "examine object/v*" would show all
attributes on an object whose names begin with v. "examine object/???"
would match those attributes whose names are exactly three letters long.
"examine object/a?*" would match those attributes whose names are at least
two letters long and begin with 'a'.
 
In 1.50, if you are set ANSI, the names of attributes and the dbref of
their owners will be hilited in boldface. This makes the boundaries
between attributes clearer, preventing large MUSHcode objects from
looking like several pages of random characters.
 
* * * * *
 
(Continued in 'man 1.2.5'.)
 
& 1.2.5
In 1.50, the @grep command can be used to search for a certain
pattern on an object. Doing a "@grep <object>/<attributes> = <pattern>"
prints a list of all attributes on <object> which contain text matching
<pattern>. This <pattern> may contain wildcards. <attributes> is a
possibly wildcarded pattern of attributes to match (like that for "examine"
above). If you merely do "@grep <object>=<pattern>", the game assumes
that you want to search all the attributes on <object>.
 
@grep can take one of two switches, "list" or "print". The default is
"list", which just returns the list of attributes that match the
pattern.  The "print" option can only be used if you are set ANSI. It
prints out all the attributes which contain the pattern, hiliting the
text which matches the pattern in boldface.
 
MudCore provides a similar command, called +grep. This performs a
similar task, though it only prints out the list of attribute names
that contain the pattern, rather than printing out the attributes
themselves. The syntax is, "+grep <object>[/<attributes>] = <pattern>".
 
(Continued in 'man 1.2.6'.)
 
& 1.2.6
MudCore also provides another useful command for listing the attributes
on an object, called +lattr; it displays the attribute names, and the
first line of text in that attribute. The syntax for this is,
"+lattr <object>[<attributes>]". The command also takes several
switches, which restrict the attributes displayed to those of certain
types (attributes which are $commands, ^monitors, globally-defined,
or none of the above).
 
* * * * *
 
The "@decompile <object>" command, when executed on an object that you
own, outputs the sequence of commands you would need to type in order
to duplicate that object. It may be used on any type of object.
 
@decompile is very useful for creating files which can be uploaded
onto another MUSH. To combine @decompile with TinyFugue, use the
following sequence of commands (presuming you want to save an object
called "Test" to a file called "testfile", and then upload it to
another MUSH called "NewWorld").
 
(Continued in 'man 1.2.7'.)
 
& 1.2.7
/wrap off             [ in TinyFugue 3.0 and later:  /set wraplog 0 ]
/log testfile
@decompile Test
/nolog
/world NewWorld
/quote 'testfile
/wrap on              [ in TinyFugue 3.0 and later:  /set wraplog 1 ]
 
This sequence does the following:
 
1. Turn off wordwrap so extra newlines aren't inserted into the output.
2. Save MUSH output to a logfile.
3. Decompile the object.
4. End saving of MUSH output to a logfile.
5. Log onto a new MUSH.
6. Upload the object to the new MUSH.
7. Turn wordwrap back on.
 
(Continued in 'man 1.2.8'.)
 
& 1.2.8
This method allows you to easily transport objects across MUSHes.
Also, if the game should unexpectedly crash, or the database gets
corrupted, or some other disaster occurs which causes you to lose the
original copy of the object, all you have to do is upload it
again. You should always try to @decompile any objects that are
especially valuable to you, and store them off-line, in case of
such a disaster.
 
                        ----------
 
Communications:
 
You can speak using "say <message>", or by typing a double quote
followed by the message (with no space after the "). Your name and the
word "says" will be appended to the beginning of the message. A
trailing " will be automatically added to the end of your message;
don't type one in.
 
(Continued in 'man 1.2.9'.)
 
& 1.2.9
You can pose (emote) using "pose <action", or by typing a colon
followed by the message (i.e., ":<action>"). Your name and a space
will be automatically added. If you want to avoid the added space, use
"pose/nospace <action>", or a semi-colon followed by the message
(i.e., ";<action>"), or a colon followed by a space and then the
message (i.e., ": <action>"). This is useful for doing possessives and
similar things.
 
In 1.50, most messages like "<person> <speech action> <message>" will
include a comma - i.e, 'Annalyn says, "Hi."' or 'Annalyn whispers, "Hi."'
In 2.0, this comma is missing, for historical reasons.
 
* * * * *
 
In 1.50, if you want to send a private message to yourself, you
can "think <expression>". Pronoun substitution and function evaluation
is performed. The equivalent command for 2.0 is "@pemit me=<expression>";
you can achieve a similar effect with "@pemit/silent me=<expression>"
in 1.50, but "think" is easier to type.
 
(Continued in 'man 1.2.10'.)
 
& 1.2.10
There will be many times when you wish to communicate privately.  The
commands "page" and "whisper" (abbreviated "p" and "w") are used for
this, as in, "page <person>=<message>" or "whisper <person>=<message>".
Whisper sends a private message to a person who is in the same room as
you. In certain configurations, people in the same room also see that
you whispered something to that person; most MUSHes, however, do not
use this "noisy" form of whisper. The page command sends a private
message to a person on the MUSH; you can use it to talk to someone in
a different room. The cost of page varies from MUSH to MUSH.
 
You can whisper and page poses to people, by using a ":" in front
of your message. If you whisper a pose to someone, you are told,
"<Person you posed> senses "<Your name> <pose>".  The person sees,
"You sense <Person who posed> <pose>". If you page a pose to someone, you
are told, "Long distance to <Person you paged>: <Your name> <pose>"
The person sees, "From afar, <Person who paged> <pose>".
 
Partial name-matching is performed on "page". You only have to type
as many letters of the name as needed to distinguish it from the other
players connected (for page) or the things in the room (for whisper).
 
(Continued in 'man 1.2.11'.)
 
& 1.2.11
"Lastpage" is supported in 1.50; to send a message to the person that
you last paged, type "p =<message>" or "p <message>". "p" by itself
will tell you the name of the person whom you paged last. Try to be
careful with this, since it's easy to mis-type when trying to page
someone different and accidentally sending the message to the wrong
person (this happens a lot when people substitute '-' for the '=',
accidentally).
 
There are two ways to block pages in 1.50. The HAVEN flag, when
set on a person, prevents them from receiving pages or @pemit *player
messages. Alternatively, the use of a page lock prevents those who do not
pass the lock from paging the player. Anyone who pages a HAVEN player is
told, "That player is not accepting any pages."  Anyone who fails the page
lock will be told, "That player is not accepting your pages."  If the target
player has a @haven attribute set, the message in that attribute is sent to
the paging player. The HAVEN player does not receive any notification that
someone tried to page him.  See the section on locks for instructions on
how to set a page lock.
 
(Continued in 'man 1.2.12'.)
 
& 1.2.12
In 2.0, only page locks can be used to block pages. Players who fail
the page lock will be told, "That player is not accepting pages.", or,
if the target player has a @reject attribute set, the message in that
attribute.
 
Specifically, to prevent a single person from paging you, use,
"@lock/page me=!*<player>". To prevent everyone except a single
player from paging you, "@lock/page me=*<player>". To prevent
everyone from paging you, "@lock/page me=#0".
 
If you set an @idle attribute on yourself, anytime someone pages you,
they will have that idle-message sent to them, and you will be
notified that they have received it, together with a timestamp. This
is very useful if you are unexpectedly called away from the keyboard
and want to know when people paged you, while politely notifying them
that you aren't there.
 
(Continued in 'man 1.2.13'.)
 
& 1.2.13
If you sent an @away attribute on yourself, if someone tries to page you
when you aren't connected, they will receive that message. Customarily,
this is used to tell people where you might be, when you will be back,
and where you can be contacted.
 
* * * * *
 
The GAGGED flag, when set on a person, prevents him from doing
anything but moving and looking. This flag may only be set by wizards,
and is used as a punishment for players who are being particularly
obnoxious.
 
Related to GAGGED is the SLAVE flag. It prevents the player from using
any commands that change the database. It may only be set by wizards.
 
Flags will be explained in more detail later.
 
* * * * *
 
(Continued in 'man 1.2.14'.)
 
& 1.2.14
The "emit" family of commands prints things without any name
prepended. This is handled by switches (the basic command name is
followed by a slash and the switch name) added to the commands @emit,
@oemit, and @pemit. In 1.50, and in many configurations of 2.0, these
command-switch combinations are aliased to shorter commands.
 
The basic command is "@emit <message>". The message will appear
exactly as you have typed it. Everyone in the room, including you,
will see the message.
 
In 2.0, normal "@emit" is shorthand for "@emit/here". An alternative
way of doing emits is "\\<message>". There should be no space between
the "\\" and the message. Also, two "\"s are necessary because \ is
used as an escape character.
 
(Continued in 'man 1.2.15'.)
 
& 1.2.15
@emit has another switch, "room". "@emit/room" is often aliased to
"@lemit". It shows a message to the outermost room you are in (the
"absolute room"). For example, if you are in a chair inside a wagon
inside a room, and you perform this command, the message is shown to
the room, not to any of the intermediate objects. There is a limit of
twenty intermediate layers.
 
Related to the @emit command are @pemit and @oemit, and their
variations.  "@pemit <player>=<message>" will emit a message to a
single person. If the person is in a different room, you must use
"@pemit *<player>=<message>". In 2.0, this normal @pemit is shorthand
for "@pemit/object". In 2.0, you are not told when you @pemit to
someone; certain configurations of 1.50 will notify you that you
@pemit'ed the message. In those configurations, using @pemit/silent
will eliminate the notification.
 
(Continued in 'man 1.2.16'.)
 
& 1.2.16
"@oemit <player>=<message>" will emit the message to everyone in the
room the @oemit'ing object is in, except the named player.  1.50 also
permits "@oemit <room>/<player>=<message>", which emits the message to
everyone in <room> but <player>; the @oemit'ing person must control or
be in <room>. This latter form of the command is somewhat unnecessary,
and thus non-existent, in 2.0; if it can locate where the named player
is, the message will automatically go to that room.
 
"@pemit/contents <object>=<message>" will emit a message to everyone
in a room or container object, as well as to the container
itself. @pemit/contents is generally aliased to @remit.  The <object>
is generally a dbref number or *player; if the object is a player,
@remit to that player will show the message to all that the player is
carrying, as well as the player himself. Note that @pemit without the
/contents switch does not show a message to anything a player is
carrying, unless the player is set with a @listen attribute of "*".
 
(Continued in 'man 1.2.17'.)
 
& 1.2.17
"@pemit/list <list of dbrefs>=<message>" will emit a message to a list
of objects. These objects must be specified by their dbref numbers.
This version of the command may also be combined with the /contents
list, to send a message to several rooms.
 
@emit, @pemit, @oemit, and @emit/room do not prepend the name of the
player using the command. If you want to see where these @emit
messages are coming from, you should set yourself NOSPOOF.
 
In 2.0, NOSPOOF tells you the origin of any output that did not
originate with you, directly or indirectly (i.e. you or an object that
you @forced). If the origin is a player, "[PlayerName(#dbref player)]"
will be prepended to the message. If the origin is an object,
"[ObjectName(#dbref object){PlayerName}<-(#dbref forcing object)]"
will be prepended by the NOSPOOF indicator. The forcing object may
be a controller object, the player himself, or a wizard. It is the
object which caused the command to be executed.
 
(Continued in 'man 1.2.18'.)
 
& 1.2.18
In 1.50, NOSPOOF tells you the origin of any type of @emit, whether
or not you or one of your objects is responsible for it. It prepends
"[<object name>]" to the output (or, if the configuration directive
"PARANOID" is on, "[<object name>(<dbref number>)]")
 
In 2.0, the HAVEN flag does not block out any type of @emit, though
page locks will block @pemit and its relatives @pemit/contents
(@remit) and @pemit/list; in 1.50, the HAVEN flag blocks @pemit and
@remit to players. 1.50 page locks do not block emits of any sort.
 
                        ----------
 
Going places:
 
The @teleport command allows you to move to a different location
instantaneously. Two criterion have to be passed in order for you to
be able to teleport to a location: you must pass the room's teleport
lock, and the room must either be JUMP_OK or controlled by you.  You
can teleport to a location by using "@tel <room number>".
 
(Continued in 'man 1.2.19'.)
 
& 1.2.19
You can teleport objects that you own, using "@tel <object>=<room
number>". If you have an unwelcome guest or object in a room that you
own, you may teleport that thing to any JUMP_OK location. You may also
teleport the thing to another room that you own or through an exit
that you own.
 
In 1.50, and older versions of 2.0, you can find out where a player is
with the command "@whereis <player>". The player will be told, "<Your
name> has just located your position."  @whereis will give you the
name of the player's location, and, if the room is JUMP_OK or is
controlled by you, the number of the location. If you can teleport to
that room, you can go to the player by using "@tel loc(*player)".
 
Some people find being "@whereis"'ed annoying. Generally, it is rude
to "@whereis" people that you don't know, or to "@whereis" them
without following up with a page message of some sort, explaining why
you wanted to know their location.
 
(Continued in 'man 1.2.20'.)
 
& 1.2.20
Players can prevent others from finding out where they are by setting
themselves UNFINDABLE. In this case, the locating player is told,
"That player wishes to have some privacy."  and the player who is set
UNFINDABLE is notified, "<Your name> tried to locate you and failed."
 
The UNFINDABLE flag can also be set on rooms. Anything inside an
UNFINDABLE room cannot be located by mortals. Paranoid players and
those having super-secret meetings may like this flag.
 
Sometimes, there are objects in a room which you may wish to enter,
such as a dragon. You can use "enter <object> to enter an object, provided
that you pass the enter lock on the object, and it is ENTER_OK or owned by
you.  In order to get out of the object, use "leave".  In 2.0, you must
pass the leave lock in order to do this.
 
(Continued in 'man 1.2.21'.)
 
& 1.2.21
You can put enter and leave aliases on objects. The words stored in
the @ealias and @lalias attributes on an object may be used in place
of "enter <object>" and "leave". For example, if a chair has the
@ealias "sit" and the @lalias "stand", "sit" may be typed in place of
"enter chair" and "stand" may be typed in place of "leave".  You can
use multiple aliases by making them semi-colon separated, like exits
are: "@ealias chair = sit down;sit;sit on chair" allows one to type
"sit down", "sit", or "sit on chair" to enter the chair.
 
                        ----------
 
Objects:
 
Picking up and dropping objects is easy - simply "get" or "drop" the
appropriate object. Possessive "get" also works - you can take from
something using "get <thing>'s <object>". The thing that you are
taking the object from must be ENTER_OK, and the object must not be
locked against you.  Also note that this applies to taking from
non-room objects in general; if you are inside a thing, you will not
be able to pick up obejcts inside of it unless it is ENTER_OK or you
control it.
 
(Continued in 'man 1.2.22'.)
 
& 1.2.22
You can give someone an object or money by using the "give" command,
i.e., "give <person>=<object>" or "give <person>=<amount of money>".
In 1.50, the person must be set ENTER_OK in order for them to receive
things.  In 2.0, the giver must also pass the recipient's ReceiveLock,
and the giver must pass the objects' GiveLock.
 
To get a list of objects you are carrying, do an "inventory"
(abbreviated "i"). This will show everything you are currently
holding, including DARK objects owned by other players.
 
                        ----------
 
Summary of command syntax:
 
The basic commands for looking, moving, etc. are few in number and
easy to remember. More complex commands, which generally are used to
change the database, begin with the "@" symbol.
 
(Continued in 'man 1.2.23'.)
 
& 1.2.23
Many commands have "switches" which change the meaning of the command
somewhat. "Examine" is one such command, with /brief and /full
switches. All commands with switches have a default. In 2.0, if a
command has more than one switch which are not mutually exclusive, you
may use several switches at once by doing command/switch1/switch2/etc.
1.50 also allows for switches, but you can only give one switch to a
command at a time.
 
Flags, mentioned repeatedly above, are used for a wide variety of
purposes. They are either on or off, with "@set <object>=<flag name>" to
turn one on and "@set <object>=!<flag name>" to turn one off.
 
Finally, three commands are extremely useful: WHO, LOGOUT, and QUIT.
The WHO command, for ordinary players, shows the list of all non-DARK
connected players, the time they have been on, the time since they
last typed a command, and their @doing, which is a short string set by
"@doing <message>". LOGOUT, which only exists in 2.0, disconnects a
player from a character, returning him to the login screen. QUIT
disconnects the player from the MUSH completely.
 
(Continued in 'man 1.2.24'.)
 
& 1.2.24
There is an inactivity timeout. If you idle too long, the MUSH will
disconnect you. The idle time allowed is generally one hour. It can be
found by doing a "@list options" in 2.0, and an "@config" in 1.50.  In
2.0, Wizards may change this value on themselves by setting their
@timeout attribute. Wizards who exceed the inactivity limit for
mortals are automatically set DARK. (In 1.50, this only occurs if the
Wizard is already set UNFINDABLE).
 
2.0's "@list" command can be used to find lists of all the commands,
flags, attributes, configuration parameters, options, command
switches, and other useful things. Typing "@list" by itself will give
the options. The closest 1.50 equivalent to "@list" is @config, which
outputs the important MUSH configuration parameters.
 
===============================================
(Continued in 'man 1.2.25'.)
 
& 1.2.25
[Example 1.2: Demonstration of Basic Commands]
> "Hi, everyone.
Elsa says "Hi, everyone."
> :waves.
Elsa waves.
F'jon waves back.
> ex/brief f'jon         [ 1.50: just plain "ex F'jon" ]
F'jon is owned by F'jon
> @emit The sun shines.
The sun shines.
> w f'jon=How are you?
You whisper "How are you?" to F'jon.
F'jon whispers "Fine."
> p jyrax=Hello.
You paged Jyrax with 'Hello.'.
Jyrax pages: Hello!
> @whereis Jyrax
Jyrax is at: Ramp of Ruatha Hold.
===============================================
 
& 1.3
1.3     Attributes
 
Attributes are places in an object where information can be stored.
The most common are the desc, succ, fail, and drop attributes. Each of
these have corresponding o- and a- attributes. For example, in addition
to succ, there are osucc and asucc. O stands for Other, and A stands for
Action. The name of the person who performed the action, and a space are
automatically prepended to the beginning of every O message. This person
is sometimes called the "enactor"; you will read more about enactors later
on in this manual.
 
The syntax for setting these and other standard attributes is
"@<attribute> <object>=<message>", as in "@desc me=A young woman."
 
"Desc" stands for Description. It is the message someone sees when they
look at something. An "odesc" is seen by everyone but the person looking
and the object being looked at. An "adesc" is the list of actions
executed by an object when it is looked at.
 
(Continued in 'man 1.3.2'.)
 
& 1.3.2
======================
[ Example 1.3a: Desc ]
> @desc me=Elsa is a slim young woman.
Set.
> @odesc me=looks at Elsa.
Set.
> @adesc me=:smiles.
Set.
[Now, if F'jon looks at me, he'll see: Elsa is a slim young woman.
 When he does that, Jyrax, who is also in the room, will see:
 F'jon looks at Elsa.]
Elsa smiles.
[Elsa's adesc forces her to do a pose, which is displayed to everyone,
 just as if she had typed :smiles. as usual.]
=======================
(Continued in 'man 1.3.3'.)
 
& 1.3.3
Note that many people find @odescs and @adescs rather irritating.  In
general, one should never use both (the above is for demonstration
purposes only). If you want to be notified that a person is looking at
you, one useful thing is: "@adesc me=@pemit me=%N just looked at you."
(or, in 1.50, "@adesc me=think %N just looked at you.")  The
abbreviation %N is explained in detail later; it means "eNactor Name",
and is the name of the person who triggered off the action.
 
Succ is short for success, and is the message seen by someone when
he successfully use something. Succ on an object is displayed when that
object is picked up. Succ on an exit is displayed when something walks
through it successfully. Succ on a room is displayed when someone looks
at it, under normal circumstances. An osucc is shown to everyone else in
the room, and an asucc is the action list taken when something is
successfully used.
 
(Continued in 'man 1.3.4'.)
 
& 1.3.4
======================
[ Example 1.3b: Succ ]
> @succ me=You lift up Elsa.
Set.
[ Now, when F'jon does a 'get Elsa', he sees, 'You lift up Elsa.'
  Elsa is now in F'jon's inventory, being carried around. ]
======================
 
Fail is short for failure, and is the message seen by someone when
he fails to successfully use something. Usually something fails to work
because it is locked. (Locks will be explained in detail, later).
Fail basically works like succ does.
 
Drop is seen by the person who drops an object. Odrop and adrop have
two uses: normally, they are performed when someone drops something, but
an odrop on an exit is shown to the people in the room that a person
enters (as opposed to an osucc, which is shown to the people in the room
that a person leaves).
 
(Continued in 'man 1.3.5'.)
 
& 1.3.5
===============================
[ Example 1.3c: Fail and Drop ]
[In the previous example, Elsa was picked up by F'jon. She's decided that
 she didn't much care for that, so she's going to take some action:]
> @lock me=me
Locked.
[This prevents anyone from picking Elsa up in the future.]
> @fail me=Elsa glares at you.
Set.
> @odrop me=drops Elsa, who looks rather irritated.
Set.
[Now, when F'jon types 'drop Elsa' he just sees "Dropped." since Elsa did
 not set a drop message on herself. Jyrax, however, sees: "F'jon drops
 Elsa, who looks rather irritated."  Elsa doesn't get any message, except
 for the description of the room she's dropped into.]
[F'jon tries to pick up Elsa again, but this time, she's locked, and
 'get Elsa' shows him the message, "Elsa glares at you."]
===============================
(Continued in 'man 1.3.6'.)
 
& 1.3.6
The @succ and @drop family of attributes is triggered in one
more case - when objects are given. The giver triggers off the @drop
family of attributes; the recipient triggers off the @succ family.
 
* * * * *
 
There is another attribute, kill, which is used when something is
killed. To kill something, use "kill <thing>=<money>". For every Mark you
spend, you have an additional 1% chance to kill the object. The default
cost of killing something is 10 marks. Spending 100 Marks always works.
Killing something halts it and sends it home, and pays it half the amount
of money that was used to kill it. It also triggers the @kill, @okill, and
@akill attributes (@death, @odeath, and @adeath in 1.50).
 
Killing is usually strongly discouraged. Certain things, like wizards,
cannot be killed. Objects with the IMMORTAL flag (or, in 1.50, with the
Immortal power) cannot be killed, but this privilege can only be granted
by a wizard.
 
* * * * *
 
(Continued in 'man 1.3.7'.)
 
& 1.3.7
The "move" set of attributes are used when something moves from one
location to another, no matter what the means of moving - going
through an exit, entering/leaving an object, going home, or
teleporting. The @move, @omove, and @amove attributes can only be set
on players and objects.
 
There is also a set of attributes specifically for messages sent when
a @teleport is done. The @tport, @otport, and @atport attributes are
used when you arrive at your new destination. The @oxtport works like
the @otport does, except the message is shown to the others in the
room that you just left. There is no @xtport or @axtport.
 
* * * * *
 
In 2.0, there are a large number of other attributes related to
succeeding or failing in attempts at various commands (usually related
to passing the appropriate lock). Only the "basic" form of the
attribute is listed in the table below; prepend "O" or "A" to it to
get the other forms.
 
(Continued in 'man 1.3.8'.)
 
& 1.3.8
@tfail:  failure in teleportation
@dfail:  failure to drop an object
@gfail:  failure to give an object
@rfail:  failure to receive an object when it is given
 
The only one of these which can easily be simulated in 1.50 is @tfail;
to get the effect of @tfail, use the "@efail" set of attributes.
 
* * * * *
 
The final attribute is not like the others. It's the sex attribute,
which is used for pronoun substitution, and lets you declare your gender.
The syntax is "@sex me=<male or female>". You don't have to make yourself
male or female, but it's strongly suggested. The gender "plural" is
also supported in 2.2, and modifies the grammar of messages appropriately.
 
(Continued in 'man 1.3.9'.)
 
& 1.3.9
There are more attributes, but these are the standard ones.  Certain
MUSHes may add their own global attributes, such as "EMAIL".  It is
also possible to make up attributes with arbitrary names, using "&" as
the beginning of the name rather than "@".  These user-named
("non-standard") attributes are described in greater detail later in
this manual; for now, just note that attribute sets of the format
"&<attribute name> <object>=<value>" are valid and set <attribute name>
on <object> with some text string <value>.
 
& 1.4
1.4     Editing
 
One rather useful command is @edit. This allows you to perform a
substitution on an attribute, so you can correct typos without having to
retype the entire thing. The syntax for this command is:
@edit <thing>/<attribute>=<old string>,<new string>
 
If <old string> is the character ^ by itself, <new string> will be
prepended to the contents of <attribute>. If <old string> is the
character $ by itself, <new string> will be appended to the contents
of <attribute>.
 
If commas, brackets, parentheses, percent signs, and other 'special
characters' appear in either string, curly braces { } must be used to
set each string off.
 
If <attribute> is a wildcard pattern, the @edit command does a
global replace for all attributes that match the pattern; for example,
@edit object/v*=a,b  would replace the letter a with the letter b
in all attributes whose names begin with v, in the object.
 
(Continued in 'man 1.4.2'.)
 
& 1.4.2
Certain types of patterns are extremely difficult to edit; these are
usually patterns which include the { or } characters, which are "special"
to @edit. Several methods exist to get around this problem; one is to
generate the string using edit(); the other is to take advantage of
some features of a client such as TinyFugue.
 
In TinyFugue, type, exactly as printed:
 
/def redit = /grab $(/recall %{0-1})
 
This command allows you to pull into your input buffer any number of lines
which could normally be obtained via the /recall command in TinyFugue.
This allows you to edit text that has already been displayed to you.
 
Therefore, to directly edit an attribute within TinyFugue, one can type,
"examine <object>/<attribute>" and then "/redit 1" to edit the text which
is then displayed.
 
* * * * *
 
(Continued in 'man 1.4.3'.)
 
& 1.4.3
To copy an attribute from one object to another, you can use:
@force me=&attrib1 object1=get(object2/attrib2)
 
It is also possible to copy attributes via a version of the @set command:
@set <new obj>=<new attrib>:_<old obj>/<old attrib>
This copies <old attrib> from <old obj>, setting it into <new attrib>
on <new obj>.
 
This somewhat clumsy method can be worked around by using a built-in
command -- @mvattr, and, in 1.50, @cpattr.
 
"@mvattr <object>=<old name>,<new 1>,<new 2>,<etc.>" will move an
attribute.  Moving an attribute always wipes it out. If you want to
copy the attribute, you must move it to itself as well, using
"@mvattr <object>=<old name>,<old name>,<new name 1>,<new name 2>,<etc.>"
(Continued in 'man 1.4.4'.)
 
& 1.4.4
In 1.50, there is, in addition to the @mvattr, a copy command:
@cpattr <obj>/<attr>=<obj1>/<attr1>,<obj2>/<attr2>,<etc.>
This copies <attr> from <obj> to <attrN> on <objN>. You can specify a
large number of object-attribute pairs (limited only by the MUSH
configuration, which is generally 100).  The original object-attribute
pair is NOT wiped out. Also, even if one copy fails (you specified a
non-existent object, or one that you don't control, etc.), the game
continues to try to finish copying to the other object-attribute pairs.
 
MudCore provides two alternatives: +cpattr and +mvattr.
"+cpattr <obj>/<attr> = <obj1>/<attr1> <obj2>/<attr2> <etc.>" is
more or less identical to the 1.50 @cpattr save in syntax.
 
There are two forms of the +mvattr command, one which moves one
attribute on an object, to another, and one which is used to move from
one object, mass groups of attributes which match a certain wildcard
pattern, to another object, keeping the attribute names the same:
"+mvattr <obj1>/<attr1> = <obj2>/<attr2>" does the first, and
"+mvattr <obj1>/<wildcard pattern> = <obj2>" does the second.
 
& 1.5
1.5     Do it!
 
Issue the following commands:
@desc me=<description>
@lock me=me
@adesc me=@pemit %N=<Your name> smiles and returns your glance.
@fail me=<message to show when someone tries to pick you up>
@sex me=<male or female>
@set me=enter_ok
 
You are now described, safe from robbery, and have a proper gender.
The adesc also allows you to see who is looking at you. (Don't worry
about the %N; it will be explained later). Also, since you are set
ENTER_OK, people can give you objects and money. One additional command
you may wish to issue is "@lock/enter me=me", which prevents people
from entering you.
  
& 1.6
1.6     A parser discussion
 
If you are completely new to MUSH, you may wish to skip this section
and come back to it later. Also, if you're programming 1.50 or 2.0
exclusively, you do not need to read this section, which explains
parser and game output differences between 1.50 and 2.0.
 
The command parsers for 2.0 and 1.50 are no longer significantly
different. Nested brackets, evaluation of the S() and U() functions,
and evaluation order should now be consistent.
 
There are some differences in messages between 1.50 and 2.0,
particularly in the building commands. Some of the more obvious ones:
 
@create:
  1.50   Created: Object <number>.
  2.0    <Object> created as object <number>
@clone:
  1.50   Cloned: Object <number>.
  2.0    <Object> cloned, new copy is object <number>.
 
(Continued in 'man 1.6.2'.)
 
& 1.6.2
@destroy:
  1.50   Halted.
         You get your 10 pennies deposit back for <object>.
         Destroyed.
  2.0    You get your 10 pennies deposit back for <object>.
         Destroyed.
         <Object> has left.
 
Errors in syntax are handled differently by the two parsers. Neither
parser reacts well to missing curly braces, brackets, and
parentheses. 2.0 in particular will often produce extremely garbled
output if matching is not correctly done; if you are getting output
from a 2.0 expression that begins with a large number of spaces and
ends with a group of right braces, brackets, or parentheses, you
almost certainly have a mismatch.  By contrast, 1.50 will generally
return the string up the point of the mismatch. This difference in
error handling should be noted by those attempting to debug code under
two different versions.
 
(Continued in 'man 1.6.3'.)
 
& 1.6.3
These differences, and some other minor cosmetic ones, will be
encountered frequently in the text of this manual. If you are using
1.50, please do not be alarmed at them.
 
& 2
2. Objects
 
Objects, for the purposes of this discussion, are anything which are
not rooms or exits. Players are very special kinds of objects, which
have rules and restrictions in addition to those normally imposed on
objects. Players cannot create other players (save for the wizard-only
@pcreate command, discussed later).
 
& 2.1
2.1     Basic object commands: @create, @destroy, @force, and @name
 
The syntax for object creation is "@create <object name>=<cost>".
If you do not specify a cost, the default is 10 marks. If you have enough
money, the MUSH will respond "<Name> created as object <#dbref>" and the
object will be placed in your inventory. You may refer to an object either
by its name, or by its object number. The MUSH parser performs name matching,
so after you create a Blue Tunic, for example, you can refer to it simply as
"Blue," unless you have a Blue fire-lizard with you. In that case, you
could use "Blue T" instead, or "Tunic."
 
You can change the name of an object with "@name <old name>=<new name>".
(This applies to things, exits, and rooms, not just things). Your name
can be changed by "@name me=<new name>" (1.50 requires, for player
name changes, "@name me=<new name> <password>").
 
(Continued in 'man 2.1.2'.)
 
& 2.1.2
The syntax for object destruction is "@destroy <objectname>".
@destroy may be abbreviated to @dest. In general, you may only destroy
objects that you own. It is important that you destroy objects once
you no longer need them, or they will clutter the database. MUDs have
a history of going down due to database bloat, so it is important to
try to conserve space. You will also get back whatever amount of money
it cost you to create the object.
 
If you want anyone to be able to destroy your object, you should set
it DESTROY_OK. This is useful for objects which are meant to be
temporary, such as messages.
 
If you want to avoid accidental destruction of an object, you should
set the object SAFE. This flag prevents the @destroy command from
being used on the object; instead, you must use @destroy/override
(@nuke). This overrides any protections on the objects, which include
the SAFE flag, wizard ability to destroy objects they don't own, and
wizard ability to destroy players.
 
(Continued in 'man 2.1.3'.)
 
& 2.1.3
You can make an object do something by using "@force <object>=<action>"
or "<dbref> <action>". The object behaves as if it had typed the
command. There are some restrictions on this, involving the INHERIT flag,
which will be explained later. Note that since the semi-colon character
is used to delimit commands, use of it in a @force will be considered
to separate different commands you want to force the object to do; if
this is not what you desire, you must surround the string with { braces }.
 
If you want someone else to be able to see the programming on one of
your objects, set it VISUAL. The other person can then "examine" it.
 
=======================================
[ Example 2.1: Basic object commands ]
> @create Test Object
Test Object created as object #8032
> i
You are carrying:
Test Object(#8032)
You have 168 Marks.
 
(Continued in 'man 2.1.4'.)
 
& 2.1.4
> drop test
Test Object has left.
Dropped.
> @force test=:bounces.
Test Object bounces.
> #8032 :rattles.
Test Object rattles.
> @set test=destroy_ok
Set.
> @destroy #8032
You get your 10 Mark deposit back for Test Object.
Destroyed.
Test Object has left.
=======================================
 
& 2.2
2.2     Puppets
 
Puppets are special objects which can hear and behave almost like
normal players. They are under the control of a player, and relay back
everything they see and do to that player.
 
Objects that have the KEY flag set cannot be picked up by puppets.
Exits set KEY cannot be used by puppets. In fact, more precisely,
puppets are treated as if they cannot pass any @locks that might be
set on those objects. This forces players to solve puzzles themselves,
instead of having their puppets do all the dirty work. In 1.50, the
KEY flag also causes objects to go home when the person carrying them
goes home or teleports.
 
(Continued in 'man 2.2.2'.)
 
& 2.2.2
=======================
[ Example 2.2: Puppet ]
> @create Test Puppet
Test Puppet created as object #8051
> @set test=puppet
Test Puppet grows ears and can now hear.      [2.2: "is now listening"]
Set.
> i
You are carrying:
Test Puppet(#8051p)
You have 168 Marks.
> drop test
Test Puppet>  Dropped.
Test puppet has left.
Test Puppet>  Elsa's Room
Test Puppet>  This is a small, sparsely furnished room.
Test Puppet>  Contents:
Test Puppet>  Elsa
Test Puppet>  F'jon
 
(Continued in 'man 2.2.3'.)
 
& 2.2.3
Test Puppet>  Obvious exits:
Test Puppet>  Out
Test Puppet has arrived.
Dropped.
> @force test=:squeaks.
Test Puppet squeaks.
> #8051 out
Test Puppet>  Corridor
Test Puppet>  A long, featureless corridor.
Test Puppet>  Contents:
Test Puppet>  Jyrax
Test Puppet>  Ball
Test Puppet>  Obvious exits:
Test Puppet>  Elsa's Room
> #8051 :squeaks.
Test Puppet>  Test Puppet squeaks.
> #8051 get ball
Test Puppet>  Taken.
Test Puppet>  Jyrax says "Hello, Test Puppet."
 
(Continued in 'man 2.2.4'.)
 
& 2.2.4
> @set #8051=!puppet
Test puppet loses its ears and becomes deaf.  [2.2: "is no longer listening"]
Cleared.
=======================
 
The puppet echoes back almost everything it hears. Note that when the
puppet is in the same room as its owner, it does not echo back the
output of commands like :. This feature prevents the puppet's owner
from getting a lot of annoying echoed messages.
 
Puppets and other objects that listen trigger the adescs of objects
that they enter, either via teleport, or via enter. This is because
they are considered to "look" at the object when they enter it.
 
* * * * *
 
(Continued in 'man 2.2.5'.)
 
& 2.2.5
Somewhat related to the PUPPET flag is the ROBOT flag. The ROBOT flag
cannot be set like other flags are; instead, you must use the "@robot"
command to create a robot. Something created via this command is a
cross between a player and a thing. Like a player, it may be connected
to and moved about independently. Like a thing, it owns no objects,
and belongs to the player who created it. It is "officially"
considered of type PLAYER.  Things which are set ROBOT cannot be
picked up by robots; exits which are set ROBOT cannot be gone through
by robots. This behavior is similar to KEY for puppets.
 
The robot flag is useful if you are running a "real" robot (an
external C or LISP construct), which needs to be a player, but still
needs to be under your control. Also, a robot can use the OUTPUTSUFFIX
and OUTPUTPREFIX commands, which many robot programs require.
 
When you are not connected to the robot as a player, you can use it
much like you would use a thing; for example, a robot may be set
PUPPET.  Creating a robot (via "@robot <name>=<password>") isn't
cheap, though; it will, on most MUSHes, cost you 1000 pennies. Once
created, it isn't possible to get rid of the robot without asking a
wizard to destroy it.
 
& 2.3
2.3     A Note about Privacy: @sweep
 
Occasionally, conversations of a private nature occur on MUDs. From
time to time, the presence of a puppet is forgotten. The @sweep command
shows everyone and everything in that room which is listening. Something
is considered to be listening if it is: a connected player, a puppet, an
object with a @listen attribute, an object with ^-listen patterns (explained
later), an AUDIBLE object or exit, or an object which has a user-defined
command on it. The latter will be explained later.
 
@sweep in 1.50 and 2.0 are significantly different, and so are
discussed here separately.
 
* * * * *
 
2.0 @sweep will show the following types and output:
 
(Continued in 'man 2.3.2'.)
 
& 2.3.2
Connected players. [player connected]
Disconnected players. [player]
Puppets belonging to connected players. [puppet(Owner name) connected]
Puppets belonging to disconnected players. [puppet(Owner name)]
Objects with a @listen or ^-pattern set. [messages]
Objects with $commands set. [commands]
Audible exits. [audible]
Audible objects, if you are in the object. [audible]
Parent objects. [parent]
 
This type of sweep, the default, checks both your location and
your inventory for listeners. There are also several switches for doing
more specific sweeps. Note that specific sweeps only warn you about one
form of listening - the form you are specifically sweeping for.
You may, however, combine several switches to make a @sweep of whatever
level of specificity you wish.
 
@sweep/commands lists only objects which have $commands set -
"[commands]" in the generic @sweep.
 
(Continued in 'man 2.3.3'.)
 
& 2.3.3
@sweep/listeners lists only objects which have a @listen set -
"[messages]" in the generic @sweep.
 
@sweep/exits checks for AUDIBLE exits in the room.
 
@sweep/players lists only players and puppets. It does not tell you
if a player or puppet's owner is connected, although it does tell you the
owner of a puppets.
 
@sweep/connected lists only connected players and puppets belonging
to connected players. It tells you who owns the puppets.
 
@sweep/here checks your location but not your inventory. Its reverse,
@sweep/inventory, checks your inventory but not your location.
 
* * * * *
 
1.50 @sweep will show the following types and output:
 
(Continued in 'man 2.3.4'.)
 
& 2.3.4
Connected players.                          [speech]. (connected)
Disconnected players.                       [speech].
Puppets belonging to connected players.     [speech].
Puppets belonging to disconnected players.  [speech].
Objects with a @listen or ^pattern set.     [speech].
Objects with $commands set.                 [commands].
Rooms with a @listen or ^pattern set.       (this room) [speech].
Rooms with $commands set.                   (this room) [commands].
AUDIBLE exits, if the room is AUDIBLE.      [broadcasting].
AUDIBLE objects, if you are in it.          (this room) [broadcasting].
 
1.50 "@sweep connected" will show the following types and output:
 
Connected players.                          is listening.
Puppets belonging to connected players.     [owner: <owner>] is listening.
 
Both types of 1.50 @sweep check both location and inventory.
1.50 will take the command switches "connected", "here", "inventory",
and "exits", but not in combination.
 
(Continued in 'man 2.3.5'.)
 
& 2.3.5
* * * * *
 
MudCore provides a command called +awake, which is a much more paranoid
version of @sweep; it allows you to discover not just objects which are,
in actuality, listening, but objects which might be listening. It follows
chains of message forwarding through AUDIBLE exits and @forwardlists,
as well as objects in the inventory of other objects set with @listen "*";
it thus allows you to discover just not what in the room might be
broadcasting, but where it's broadcasting to. The command displays
information in a tabular format, noting the Connected status of the
owners of the objects.
 
* * * * *
 
(Continued in 'man 2.3.6'.)
 
& 2.3.6
Puppets on MUSHes may be set DARK, but that flag has no effect on
them, just as it has no effect on a normal player. However, wizards and
wizard objects may be set DARK, and will disappear from the list of the
room's contents, although they still appear on a @sweep. As a further
caution, wizards who are set DARK also do not appear on the WHO list of
connected players. (The rationale for allowing wizards to do this is
explained in the last section of the manual).
 
Doing a @sweep several times throughout a private conversation is
strongly encouraged. Remember that you are not ever guaranteed privacy
on a MUD.
 
& 2.4
2.4     Attributes on Objects: Action Lists
 
The @asucc, @afail, and @adrop attributes are frequently used on
objects. Any command normally available to the object may be used in an
action list. Object may also re-program themselves, by enclosing the
commands which are to be deferred in curly brackets (braces), { }.
 
==========================
[ Example 2.4: Bubbly Pie]
> @create Bubbly Pie
Bubbly Pie created as object #1308
> @adrop pie = @adrop me={:splatters on the floor.;@destroy me};:lands on
  the floor. If it's dropped again, it'll splatter.
Set.
> drop pie
Bubbly Pie has left.
Dropped.
Bubbly Pie lands on the floor. If it's dropped again, it'll splatter.
> get pie
 
(Continued in 'man 2.4.2'.)
 
& 2.4.2
Bubbly Pie has left.
Taken.
> drop pie
Bubbly Pie has left.
Dropped.
Bubbly Pie splatters on the floor.
You get your 10 Mark deposit back for Bubbly Pie.
Bubbly Pie has left.
==========================
 
& 2.5
2.5  Machines: @cost, @pay, and @clone
 
Machines use up money as they run. Normally, the cost is 1/64 of a
Mark per command, plus the normal cost of the command. For example, if a
machine @creates something, the cost is 10 and 1/64 marks. In general, the
cost of running a machine is insignificant, but an object which is in an
infinite loop can quickly become extremely costly.
 
Many MUSHes have vending machines. These exist to provide some color
to the world, as well as to net the owner some money. It is generally
considered impolite to have set the cost of a vending machine to anything
far above what it costs to run the machine.
 
The @cost attribute is an integer, which is the amount of money a
machine must be given before it executes its "pay" programming. The @pay,
@opay, and @apay attributes are used to program vending machines.
 
(Continued in 'man 2.5.2'.)
 
& 2.5.2
The syntax of the commands is standard: "@<command> <object>=<whatever>"
and the attributes are triggered by the payment. The MUSH automatically
gives change to people who give a machine too much money, and rebukes those
who are too stingy, so you don't have to make sure that people are giving
your machine that correct amount of money.
 
Many vending machines produce objects. This is generally done by
having a copy of the object inside the machine, and then having the
machine clone the object. The syntax of that command is @clone <object>.
The object can be referred to either by name or number. @clone places the
newly created object in the room (or, in 2.0, if the /inventory switch is
given, in the object's inventory). The object is identical in all ways, save
for a different object number.
 
Clone-type vending machines should be set OPAQUE. This flag, when set
on something, prevents others from seeing what an object is carrying. Also,
objects given by a vending machine should be set DESTROY_OK so that people
can destroy them when they're done with them.
 
(Continued in 'man 2.5.3'.)
 
& 2.5.3
To @destroy an object you do not own, it must be DESTROY_OK and you
must be carrying it; if you @destroy such an object, you will receive
the message, "Destroyed.  <Owner>'s <Object>(<#dbref>)". In 2.0,
the owner will be told, "You get your 10 Mark deposit back for <Object>."
In 1.50, the owner is given that message, and gets the additional
notification, "Destroyed. <ObjectName>(<#dbref>) by <Player>."
 
If you don't want to see annoying "You get your 10 Mark deposit back
for <whatever>." messages every time someone destroys one of your
objects, set the object QUIET.
 
===================================
[ Example 2.5:  Bubbly Pie Vendor ]
> @create Hot Pie
Hot Pie created as object #8301
> @create Bubbly Pie Vendor
Bubbly Pie Vendor created as object #8302
> i
You are carrying:
 
(Continued in 'man 2.5.4'.)
 
& 2.5.4
Bubbly Pie Vendor(#8302)
Hot Pie(#8301)
You have 158 Marks.
> @set #8301=destroy_ok
Set.
> @succ #8301=You gobble down the hot bubbly pie.
Set.
> @asucc #8301=@destroy me
Set.
> @cost vendor=11
Set.
> @pay vendor=The bubbly pie vendor sets down a hot, steaming pie.
Set.
> @apay vendor=@clone #8301
Set.
> @tel #8301=#8302
Hot Pie has left.
> @set vendor=opaque
Set.
> drop vendor
 
(Continued in 'man 2.5.5'.)
 
& 2.5.5
Bubbly Pie Vendor has left.
Dropped.
> give vendor=11
You paid 11 Marks
The bubbly pie vendor sets down a hot, steaming pie.
> get hot pie
Hot Pie has left.
You gobble down the hot bubbly pie.
You get your 10 Mark deposit back for Hot Pie.
Hot Pie has left.
===================================
 

Database size is frequently an issue on MUSHes. One way of
preventing the dreaded "database bloat" syndrome is to avoid using
@clone whenever possible. MUSH provides for object "inheritance" via
"parenting".
 
(Continued in 'man 2.5.6'.)
 
& 2.5.6
An object becomes parented via "@parent <child>=<parent>", where
<child> and <parent> are of any type (and can be of different types).
A child object inherits all attributes of the parent, unless it
already has an attribute of that name, in which case the attribute on
the child "blocks" that of the parent. While no object is allowed to
have more than one parent, multiple levels of parents are allowed,
with the "ancestors" passing their traits down to the child.
 
In 2.0, objects also inherit any exits that their parents might have;
these show up on the "Obvious Exits" list. In neither version of MUSH
do objects inherit the locks or flags of the parent. Certain special
attributes, like @startup, are also not inherited.
 
Because in almost every regard, the child is identical to the parent,
cloning becomes almost unnecessary; instead of using @clone, @create
an object of the same name, set the flags and lock to be identical,
and then @parent the 'clone' to the original object, so all attributes
are 'inherited'. There is a convenient shortcut command in 2.0 which
does all of this: "@clone/parent <parent>".  This saves a large amount
of database space and also makes it very easy to maintain updates of
objects that you are making available for public consumption.
 
(Continued in 'man 2.5.7'.)
 
& 2.5.7
It is safe to allow someone to @chown an object after it is @parented;
the child does not inherit any special kind of control powers over the
parent. The child can, however, still inherits attributes off the
parent object, even if the owners of the child and parent are
different.
 
& 2.6
2.6  Limiting object uses:  @charges and @runout
 
An object may be given charges, limiting its number of uses. Each
success on the object uses one charge. To set the number of charges on an
object, use: "@charges <object>=<integer>".
 
When the charges on an object are exhausted, its @runout action list
is executed. The syntax is "@runout <object>=<action list>". The
action list is in the same form as the action lists used in asucc,
adrop, etc.
 
Any use of an action-attribute, such as @adrop, @asucc, @afail, @ause,
or @ahear, will constitute use of a charge. @trigger also uses up a
charge, although no other MUSH commands do. "@verb" triggered on
something uses up charges, if an @a-action is specified (see the
section on @verb later in the manual; basically, this command defines
@attr/@oattr/@aattr-like triplets).  Note that an object runs out when
the number of charges is equal to 0. In other words, an object with
@charges 2 can be used 3 times before it executes the @runout (the
@runout is executed immediately after the third use of the object).
 
(Continued in 'man 2.6.2'.)
 
& 2.6.2
============================
[ Example 2.6: Mug of Klah ]
> @create Mug of Klah
Mug of Klah created as object #135
> @asucc mug=@pemit %N=You drink some of the klah.
Set.
> @charges mug=2
Set.
> @runout mug=:is now empty.; @name me=Empty Mug; :shatters.; @destroy me
Set.
> drop mug
Mug of Klah has left.
Dropped.
> get mug
Mug of Klah has left.
Taken.
You drink some of the klah.
> drop mug
Mug of Klah has left.
 
(Continued in 'man 2.6.3'.)
 
& 2.6.3
Dropped.
> get mug
Mug of Klah has left.
Taken.
You drink some of the klah.
> drop mug
Mug of Klah has left.
Dropped.
> get mug
Mug of Klah has left.
Taken.
You drink some of the klah.
Mug of Klah is now empty.
Empty Mug shatters.
You get your 10 Mark deposit back for Empty Mug.
Empty Mug has left.
============================
 
& 2.7
2.7     Reacting to the Environment: @listen and @ahear
 
These two attributes allow machines to respond to things they hear,
including speech, poses, @emits, and whispers. The attributes are
extremely useful for programming machines that sit idle until they
hear the string "has arrived," or similar things.
 
The "listen" string usually contains one or more wildcard characters,
so that a single pattern of words can be listened for out of what may
be an extremely complex string. For example, an object whose "listen"
is set to "*smiles *" will match any occurrence of "smiles" followed
by a space, such as "Elisa smiles happily."
 
The "ahear" is the action list taken when the object's "listen" string
is matched. Ahear's general format is similar to asucc, adrop, etc.  There
are also two refinements of ahear: amhear and aahear. Amhear only responds
to strings that are generated by the object itself; ahear only responds to
strings that are not generated by the object itself. Amhear plus ahear
equals aahear, which allows the object to respond to anything it hears.
 
(Continued in 'man 2.7.2'.)
 
& 2.7.2
===================================
[ Example 2.7: Autogreet ]
> @listen me=* has arrived.
Elsa - Set.
> @ahear me=:waves to %N.
Elsa - Set.
[ This forces Elsa to automatically wave to something entering the room. ]
Abakin has arrived.
Elsa waves to Abakin.
===================================
 
Autogreets are somewhat annoying and are probably best used merely
as programming examples.
 
(Continued in 'man 2.7.3'.)
 
& 2.7.3
One particularly costly loop is to have an object with a @listen of
"*" and an @ahear which triggers on some particular pattern of words,
sitting in a noisy room where the @ahear is evaluated several times a
minute.  This will cause your money supply to drop rapidly, although
it is unlikely that you will notice the loop until your money is
gone. It is noted here in hopes that you will avoid making this
mistake.
 
MUSH allows an additional way for objects to listen. Attributes can be
scanned for ^ listen patterns (in 1.50, this only happens if no
@listen is set on an object). These pattern triggers are in the format
"^<pattern>:<action>". They function like a @listen/@ahear
combination.  Unlike @listen, messages which match the pattern do not
"go through" to the objects that the object is carrying. In order to
activate patterns on the object, though, it must be set LISTENER (in
1.50) or MONITOR (in 2.0).  Also, the object which is the origin of
the message must be able to pass the use lock of the object with the
^-pattern.
 
(Continued in 'man 2.7.4'.)
 
& 2.7.4
===================================
[ Example 2.8: Echo device ]
> @create Echo
Created: Object #4570.
> drop echo
Dropped.
> @va echo=^* says, "*":@emit You hear an echo... %1 %1 %1...
[ The first * matches %0, the second * matches %1. This is the "stack",
  described in more detail later. ]
Echo - Set.
> "Testing.
You say, "Testing."
You hear an echo... Testing. Testing. Testing....
===================================
 
& 2.8
2.8      Keeping your objects safe
 
Unless you enjoy having your stuff stolen, or are planning on giving
something away, it is usually a good idea to @lock the things you own.
"@lock <object>=me" will prevent anyone other than yourself from
picking up an object. Do note that it's usually rude to pick things
up without permission from the owner.
 
Locks are useful on more than just objects - they are often used on
exits. For example, you might want to lock the entrance to your
bedroom to yourself only. In general, successfully passing a lock -
going through an exit, picking up an object, etc. - will trigger the
@succ attributes. Failing to pass a lock will trigger the @fail
attributes.
 
The generic syntax is "@lock <object>=<key>". The object and key can
be name, number, "me" or "here". If the key is a player, you must
prefix the player name with a * - i.e. "@lock object=*Malachite".  In
general, if you want something to be locked against everything, lock
it to #0.
 
(Continued in 'man 2.8.2'.)
 
& 2.8.2
To unlock an object, simply use @unlock <object>.
 
Boolean expressions are allowed in locks, as are parentheses for
grouping.  A lock of 'obj1&obj2' means that the thing trying to pass
the lock must be BOTH obj1 and obj2. A lock of 'obj1|obj2' means that
the thing trying to pass the lock must be EITHER obj1 or obj2. Make
sure that you don't confuse these.  There is also a negation operator,
'!'.  '!obj1' means that the thing trying to pass the lock must NOT be
obj1.
 
Carry locks allow you to check if a player is carrying a certain
object. @lock <object>=+<key> only allows someone carrying <key> to pass the
lock. Is locks allow passage only if you are the key: @lock <object>==<key>.
 
The normal @lock <object>=<key> allows passage either if you carry
the key, or you are the key; thus, a carry lock plus an is lock equals a
normal lock.
 
(Continued in 'man 2.8.3'.)
 
& 2.8.3
Indirect locks allow you to lock an object to the key of another
object, thus creating "standard" locks. The syntax is @lock <object>=@<key>
For example, if the <key> is locked to obj1|obj2, then <object> will also
be locked to obj1|obj2.
 
Ownership locks allow you to lock to all objects with the same
owner. @lock <object>=+<key> only allows someone with the same owner as
<key> to pass the lock.
 
* * * * *
 
         You can lock things to attributes. For example, to make a door which
only allows females past, @lock door=sex:f*  Wild cards, greater than, and
less than signs may be used. The latter two refer to alphabetical order:
@lock door=name:<m  will set the door passable to only those people whose
names begin with a through l.
 
(Continued in 'man 2.8.4'.)
 
& 2.8.4
         One special variant of the attribute lock is the evaluation lock.
It evaluates an attribute, and compares it to a given value; if they are
the same, then the object passes the lock. The attribute is evaluated as
a U() function (see the discussion of user-defined functions later in
this manual for details). The syntax is @lock object=<attribute>/<value>
The person attempting to pass the lock is passed as the enactor to the
attribute U-function. Evaluation locks are an advanced programming technique;
don't worry if you don't understand them.
 
* * * * *
 
2.0 provides a wide variety of locks; in additional to the "basic" lock,
there are enter, leave, use, page, give, receive, telout, tport, and
link locks. They are set using @lock/<lock name> and @unlock/<lock name>.
 
An enter lock prevents someone from entering an object unless
he passes the lock. The object must also be ENTER_OK or owned by the
person trying to enter it.
 
(Continued in 'man 2.8.5'.)
 
& 2.8.5
Leave, give, and receive locks are obvious: they control who
is allowed to leave the object, who is allowed to give the object, and
who is allowed to give things to the object, respectively.
 
A use lock prevents someone from "use"ing, performing $commands,
or triggering ^-listen patterns on an object unless they pass the lock.
This provides another form of security on objects; to prevent someone from
abusing the $commands on your personal objects, all you need to do is to
@lock/use it to "me", so you are the only person who can use the object.
Please note that if you uselock yourself, you cannot be given money (since
that could potentially trigger the @apay attribute on you).
 
(Continued in 'man 2.8.6'.)
 
& 2.8.6
A page lock prevents someone unless they pass the lock. It does
not prevents their objects from paging you; to achieve this affect, you
need to use the ownership lock primitive ($). If you want to prevent someone
and all their objects from paging you, use "@lock/page me=!$*playername"  --
i.e., if Ambar wants to prevent Joarm and his objects from paging her, she
types "@lock/page me=!$*Joarm". The '!' signifies negation, the '$' signifies
ownership, and the '*Joarm' forces the game to parse the name as a player
name. Thus the lock reads "not objects owned by player Joarm". In 2.0, this
also prevents Joarm and his objects from @pemit'ing to Ambar; in 1.50, the
HAVEN flag is required to stop @pemits).
 
A link lock controls who may link to a LINK_OK location (for
linking exits or setting drop-tos for rooms) or an ABODE location (for
setting the homes of players or things).
 
* * * * *
 
(Continued in 'man 2.8.7'.)
 
& 2.8.7
Lock types in 1.50 are somewhat more limited. Enter locks and use
locks are provided. Page locks are a subset of use locks (a use lock
on a player is the page lock). Teleport locks are a subset of enter
locks (an enter lock on a room is the teleport lock). They are set
using the @lock/enter (@unlock/enter) and @lock/use (@unlock/use)
commands. Except for the fact that they set the Enter/Teleport and
Use/Page Keys instead of the regular Key field on an object, they
behave like @lock/@unlock. When you examine a room, you will be shown
the key "Teleport Key" instead of "Enter Key"; when you examine a
player, you will be shown the key "Page Key" instead of "Use Key".
1.50 will, however, recognize the /tport and /page switches, and set
the appropriate lock for you.
 
In 1.50, be careful, since a page lock also acts like a use lock,
on a player. If you @lock/use yourself to "me", not only will you prevent
people from using $commands on you, but you will prevent people from paging
you. You should, in general, avoid putting $commands on yourself. You
probably also want to leave yourself page-unlocked. A page lock is useful
if you don't want someone to page you but you don't want to set yourself
HAVEN (and thereby block out all pages).
 
(Continued in 'man 2.8.9'.)
 
& 2.8.9
                        ----------
 
Changing ownership of an object:  occasionally, you may want to give
a gift to someone, and let them own an object that you have created. The
@chown command allows you to change ownership of something.
 
For mortal players, to change ownership of something, the original
owner must set it CHOWN_OK. The player who is receiving the thing must then
@chown <thing>=me. If the thing is an object, the receiving player must be
able to pick it up. If the thing is a room or exit, the receiving player must
be in the same room. Wizards can simply @chown #<object>=player.
 
If you own an object that you want to make sure you don't lose,
set its home to yourself, using @link <object>=me, and then set the object
STICKY. Objects set STICKY will automatically go home when dropped; thus,
when the object is dropped, it will return to you.
 
                        ----------
 
(Continued in 'man 2.8.10'.)
 
& 2.8.10
If, somehow, you manage to lose one of your objects, the @find and
@search commands can be very useful. @find <string> will search the database
for all objects and rooms that you control whose names contain <string>.
@find without any arguments displays all objects and rooms controlled by you.
This command costs (usually) 100 pennies, since it is computationally
expensive. The exact cost can be found by "@list costs" (in 2.0) or
"@config" (in 1.50). The cost for "@find" is the standard cost for all
computationally expensive commands on a MUSH.
 
"@find <string>=<first dbref>,<last dbref>" will allow you to limit the
dbref range searched. This version of the command will check every object
from <first> to <last>, inclusive. If you do not specify a dbref, <first>
is assumed to be 0 and <last> is assumed to be the last object in the db
 
* * * * *
 
The @search command checks all rooms, objects, and exits owned by
you. If used without arguments, it prints all of them out. @search can be
restricted to certain classes - type (rooms, exits, objects, players),
name (search for a string, like @find), and flags. @search is generally
faster than @find.
 
(Continued in 'man 2.8.11'.)
 
& 2.8.11
The scope of a @search may be limited in a fashion similar to @find.
The range must be the _last_ argument to @search. For example:
"@search flags=p,100,500" would find all objects with the 'p' (PUPPET)
flag between dbrefs #100 and #500.
 
Note that @search and @find may be more expensive on certain MUSHes,
especially those that run on slower machines, or are disk-based. 2.0 MUSH
code is disk-based; limited @searches (restricted by a flag, for example)
may not be terribly slow, but a @find might hang the server for several
minutes (and bring the wrath of the wizards down upon you).
 
* * * * *
 
To get a count of how many objects you own, use "@stats". In 2.0,
"@stats" with no switches returns the total number of objects in the database.
"@stats/all" returns a breakdown of types in the database. "@stats/me"
returns a breakdown of what you own. 2.0 @stats breakdowns cost the same
as @find, so be careful with it.
 
(Continued in 'man 2.8.12'.)
 
& 2.8.12
In 1.50, "@stats" returns a breakdown of types in the database.
"@stats me" returns a breakdown of what you own. Wizards can use
"@stats <player>" to get a breakdown of what any player owns.
 
& 2.9
2.9    Do it!  --  falcon
 
Issue the following commands:
@create <falcon's name>
@set <name>=puppet
@desc <name>=<whatever it looks like>
@lock <name>=me
@succ <name>=You call to <name> and <he/she> lands on your arm.
@osucc <name>=calls to <name> and <he/she> lands on %p arm.
@fail <name>=You try to pick up <name> but <he/she> bites you!
@ofail <name>=tries to pick up <name> but <he/she> bites %o!
@drop <name>=You allow <name> to fly off your arm.
@odrop <name>=allows <name> to fly off %p arm.
@listen <name>=<Your name> has left.
@ahear <name>=@wait 5={:flies after <Your name>; @set me=!puppet;
   @tel owner(me); leave; @set me=puppet}
[ This last statement forces the puppet to follow you around. In order for
  this to work, however, the puppet must be set INHERIT. ]
[ Obviously, you can have your own variations on these. ]
 
& index1
 
INDEX OF SECTION I EXAMPLES:
 
1.2   Demonstration of basic commands
1.3a  Desc
1.3b  Succ
1.3c  Fail and Drop
1.5   Basic character set-up
2.1   Basic object commands
2.2   Puppet
2.4   Bubbly Pie
2.5   Bubbly Pie Vendor
2.6   Mug of Klah
2.7   Autogreet
2.8   Echo device
2.9   Falcon
 
& II
MUSH Manual Version 2.008:
   Copyright 1993, 1994, 1995, Lydia Leong (lwl@godlike.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
 
(Continued in 'man II1'.)
 
& II1
 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
3. Building
 
&3.1
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.
 
(Continued in 'man 3.1.2'.)
 
& 3.1.2
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...
 
(Continued in 'man 3.1.3'.)
 
& 3.1.3
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
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.
 
(Continued in 'man 3.2.2'.)
 
& 3.2.2
* * * * *
 
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
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.
 
* * * * *
 
(Continued in 'man 3.3.2'.)
 
& 3.3.2
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
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.
 
* * * * *
 
(Continued in 'man 3.4.2'.)
 
&3.4.2
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.
 
(Continued in 'man 3.4.3'.)
 
&3.4.3
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."
 
* * * * *
 
(Continued in 'man 3.4.4'.)
 
&3.4.4
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
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
 
(Continued in 'man 3.5.2'.)
 
&3.5.2
@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
4. Introduction to Programming
 
&4.1
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
 
(Continued in 'man 4.1.2'.)
 
&4.1.2
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.
 
* * * * *
 
(Continued in 'man 4.1.3'.)
 
&4.1.3
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.
 
(Continued in 'man 4.1.4'.)
 
&4.1.4
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.
 
(Continued in 'man 4.1.5'.)
 
&4.1.5
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.
 
(Continued in 'man 4.1.6'.)
 
&4.1.6
======================================
[ 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
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).
 
(Continued in 'man 4.2.2'.)
 
&4.2.2
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.
 
(Continued in 'man 4.2.3'.)
 
&4.2.3
======================================
[ 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.
 
(Continued in 'man 4.2.4'.)
 
&4.2.4
* * * * *
 
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.
 
(Continued in 'man 4.2.5'.)
 
&4.2.5
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
 
(Continued in 'man 4.2.6'.)
 
&4.2.6
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
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.
 
(Continued in 'man 4.3.2'.)
 
&4.3.2
@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.
 
(Continued in 'man 4.3.3'.)
 
&4.3.3
"@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>.
 
(Continued in 'man 4.3.4'.)
 
&4.3.4
"@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).
 
(Continued in 'man 4.3.5'.)
 
&4.3.5
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>."
 
* * * * *
 
(Continued in 'man 4.3.6'.)
 
&4.3.6
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
(Continued in 'man 4.3.7'.)
 
&4.3.7
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
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)).
 
(Continued in 'man 4.4.2'.)
 
&4.4.2
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.
 
(Continued in 'man 4.4.3'.)
 
&4.4.3
=============================
[ 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"
 
(Continued in 'man 4.4.4'.)
 
&4.4.5
Dog flops onto the ground.
> "Dog, roll over
You say "Dog, roll over"
Dog rolls over obediently.
=============================
 
&4.5
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.
 
(Continued in 'man 4.5.2'.)
 
&4.5.2
========================================
[ 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
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.
 
(Continued in 'man 4.6.2'.)
 
&4.6.2
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.
 
(Continued in 'man 4.6.3'.)
 
&4.6.3
===============================
[ 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.
==============================
(Continued in 'man 4.6.4'.)
 
&4.6.4
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).
 
* * * * *
 
(Continued in 'man 4.6.5'.)
 
&4.6.5
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
 
(Continued in 'man 4.6.6'.)
 
&4.6.6
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
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.
 
(Continued in 'man 4.7.2'.)
 
&4.7.2
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))".
 
(Continued in 'man 4.7.3'.)
 
&4.7.3
=============================
[ 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.
 
(Continued in 'man 4.7.4'.)
 
&4.7.4
> 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.
 
(Continued in 'man 4.7.5'.)
 
&4.7.5
> @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!"
 
(Continued in 'man 4.7.6'.)
 
&4.7.6
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
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. ]
 
(Continued in 'man 4.8.2'.)
 
&4.8.2
@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. ]
 
(Continued in 'man 4.8.3'.)
 
&4.8.3
@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. ]
 
&index2
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
 
&III
MUSH Manual Version 2.008:
   Copyright 1993, 1994, 1995, Lydia Leong (lwl@godlike.com / Amberyl)
   Last revised 5/22/95.
 
Section III: Programming Applications
 
5. Vehicle programming
 5.1  Entering and leaving objects: @enter, @aenter, @oenter, @oxenter,
      @leave, @aleave, @oleave, @oxleave
 5.2  Inside vehicles: @idesc, @listen, relays, and commands, @remit,
      AUDIBLE, @prefix, @filter, @forwardlist
 5.3  Do it!  --  Wagon controller
6. Complex programming
 6.1  Useful functions:
         General use: NUM(), LOC(), NEARBY()
         List creation: LCON(), LEXITS(), LATTR(), LWHO()
         Parsing: POS(), FIRST(), REST(), STRLEN(), MID(), WORDS()
         Matching: EXTRACT(), MATCH(), MEMBER(), UCSTR(), LCSTR(), CAPSTR()
 6.2  Non-standard attributes: & and attribute flags
 
(Continued in 'man III1'.)
 
& III1
 6.3  Introduction to @dolist
 6.4  Time synchronization: semaphores, complex @wait, @notify, @drain
 6.5  Security problems in programming, INHERIT, ESCAPE(), SECURE(),
         @fsay, @femit, @fpose
 6.6  Debugging: PUPPET and VERBOSE
 6.7  On the New Programming Style
 6.8  Hints and tips
7. MUSH Programming: QuickStart Guide
 7.1  Basic syntax
 7.2  Conditional and loop constructs
 7.3  Functions
 
&5
5. Vehicle programming
 
&5.1
5.1   Entering and leaving objects
Objects can be used as containers if they are set ENTER_OK. You can
enter an object by typing "enter <object>" and exit an object by typing
"leave". You may enter any object that you own or is set ENTER_OK, and,
in 1.50, that you pass the enter lock of.
 
You may set EALIAS and LALIAS attributes on objects. The string in
these two aliases may be used as a substitute for "enter <object>" and
"leave".
 
Entering an object triggers the messages @enter, @oenter, @oxenter, and
@aenter. The player who enters is shown the @enter message. The others inside
the object see the @oenter message. People in the room that the player just
left (which may not necessarily be the same room that the object is in, if
the object is @tel'ed to) see the @oxenter message. @aenter is the action
list to be executed.
 
(Continued in 'man 5.1.2'.)
 
&5.1.2
Leaving an object triggers the @leave, @oleave, @oxleave, and @aleave
messages. @leave is shown to the leaving player, @oleave is shown to the
things inside the object the player just left, @oxleave is shown to the
things in the room the player goes to (not the room that the container object
is in  - if the player teleports or goes home, for example, the @oxleave
message is shown at the player's destination). @aleave is the action list
to be executed.
 
========================
[ Example 5.1:  Wagon ]
[ This creates the most basic of container objects ]
> @create Wagon
Wagon created as object #953
> @enter wagon=You climb into the wagon.
Set.
> @oenter wagon=climbs up into this wagon.
Set.
> @oxenter wagon=climbs up into the wagon.
Set.
 
(Continued in 'man 5.1.3'.)
 
&5.1.3
> @leave wagon=You climb down from the wagon.
Set.
> @oleave wagon=climbs off this wagon.
Set.
> @oxleave wagon=climbs off the wagon.
Set.
> @set wagon=enter_ok
Set.
========================
 
&5.2
5.2   Inside objects: internal descriptions, echoing, and relays
An object's internal description - the description displayed to those
inside it - can be set using @idesc <object>=<description>. This functions
identically to @desc, except it is only visible by those inside.
 
To enable those inside the object to hear what is going on outside, set
the @listen of the container to *. Anything that is in the object's @listen
match will be relayed to the occupants.
 
Talking and posing within objects is identical to talking and posing in
rooms. Unless there is some sort of relay set up (described below), only those
inside the object can hear you.
 
* * * * *
 
It is frequently useful to be able to talk to the outside world, and
perform other actions, like looking at the room that the object is in. This
is best done with user-defined commands on an object which is placed inside
the container object. It's a bad idea to define the commands directly on the
container, since they can be used by those who are outside the object.
 
(Continued in 'man 5.2.2'.)
 
&5.2.2
The simplest way to handle looking outside is to do a user-defined
command which forces the object to do a "look".  This is extremely inelegant,
though. On MUSHes which provide it (all 1.50 and most 2.0), the command
"look/outside" will allow you to look outside the container you are in.
 
Taking objects which are outside, however, generally requires a
user-defined command which forces the object to do a 'get' or @teleport.
 
* * * * *
 
In the past:
 
The simplest way of doing relays is to add special user-defined commands
for say and pose which force the object to emit. When the object emits, both
players inside and outside the object will hear the message.
 
Another, more direct, way of talking to the outside world from the
inside - actually, of showing a message to only those outside - is to
use @emit/room. This outputs the message to the outermost container - the
room that the wagon or similar object is in.
 
(Continued in 'man 5.2.3'.)
 
&5.2.3
* * * * *
 
The 'best' way to relay information, however, is to use the AUDIBLE
flag. This flag essentially outputs text from one place to another, without
danger of looping.
 
When set on an object, anything "said" (posed, emitted, etc.) inside
the object will be broadcast to the object's location, prepended with the
string "From <name of AUDIBLE object>,"  The AUDIBLE object does not receive
its own propagated messages, nor does it bounce back things it hears via
"@listen *" from the outside world.
 
AUDIBLE exits "funnel" noise from their source room to their
destination room. In 1.50, the room itself must be set AUDIBLE, to activate
AUDIBLE exits. The AUDIBLE exit propagates the message to the next room
and no farther; if there are AUDIBLE exits in the next room, they do NOT
pass the information on to their destinations. Messages channeled through
AUDIBLE exits are prepended with, "From <name of AUDIBLE exit's source>,"
(1.50) or "From a distance,"  (2.0).
 
(Continued in 'man 5.2.4'.)
 
&5.2.4
2.0 also provides an additional command, @forwardlist. This command,
with the syntax "@forwardlist <object>=<space-separated list of dbrefs>",
forwards all messages heard by <object> to every object in the list of
dbrefs. <object> must have its AUDIBLE flag set.
 
You can filter out messages by setting the @filter attribute with
a (possibly wildcarded) pattern to suppress. For example, if you don't
want "<name> has left." messages, "@filter <exit>=* has left.", and messages
matching that pattern will not be propagated. You can have more than one
pattern; they should be separated by commas.  (i.e., you can do:
"@filter <exit>=* has left.,* has arrived." to suppress both arrival
and departure messages). If the pattern contains a comma, the entire
pattern should be enclosed in curly braces {} (just like in @switch).
 
(Continued in 'man 5.2.5'.)
 
&5.2.5
You can change the string prepended to propagated messages via
the "@prefix" attribute on the AUDIBLE object. The game always puts a
space between the prefix and the propagated message. Generally, prefixes
are of the format, "From Mnedranth's back,"  or  "In the gazebo,"  or
the like -- something which indicates where the message is coming from.
The game automatically prepends one if the @prefix attribute is not set.
There are times when it is desirable to have no prefix prepended at all;
in those cases, set the @prefix attribute to "\".
 
There is an additional refinement: @infilter and @inprefix.
@infilter suppresses text that is normally sent to the object via @listen
(usually "@listen *"). @inprefix will prefix text forwarded from the outside
with a string. Normally, text forwarded via @listen is not prepended with
anything.
 
&5.3
5.3   Do it!  --  Wagon controller
This section assumes that you have created a wagon as described in
example 5.1. Below, <#wagon> refers to the dbref number of that wagon, and
<#cont> refers to the dbref number of the controller.
 
Enter the following commands:
 
@idesc <#wagon>=<description>
@listen <#wagon>=*
@create Wagon controller
@lock control=me
drop control
 
Possibilities:
 
This is the old way of doing things:
@va <#cont>=$'*:@fo <#wagon>=@emit {On the wagon, %N says, "%0"}
@vb <#cont>=$.*:@fo <#wagon>=@emit {On the wagon, %N %0}
[ These two commands define ' and . as alternates to " and : inside the wagon.
  They relay to the outside world, as well as to those inside the vehicle.
 
(Continued in 'man 5.3.2'.)
 
&5.3.2
  There is one major problem with this: because of the @listen, the players
  inside the wagon hear exactly what the wagon hears, which is the message
  "You emit: <whatever>"  This is ugly, but it's effective. ]
@vc <#cont>=$view:@fo <#wagon>=l
@vd <#cont>=$view *:@fo <#wagon>=l %0
[ These two commands substitute for look. ]
 
This is the new way of doing things:
@set <#wagon>=AUDIBLE
@prefix <#wagon>=On the wagon,
[ There is no need for the view command; "look/outside" will suffice. ]
 
@ve <#cont>=$snag *:@fo <#wagon>=get %0
[ This command forces the wagon to get an object outside. ]
 
&6
6.    Complex programming
 
&6.1
6.1   Useful functions
Often, you will want to build machines that accept input from players
only; the NUM() function is useful for checking whether or not something
is a player. Simply evaluate: num(*%N), assuming that you are checking if
the enactor is a player. The * forces %N to be evaluated as a player; if
there is no player by that name, the function returns "#-1". The only case
in which this trick with num(*%N) fails is if the enactor has the same
name as a player.  You can also use the TYPE() function to see if an
object is a player.
 
* * * * *
 
The LOC() function is useful for several things. If it is used to
locate a player, it will return the number of the player's location, assuming
that the player is not set UNFINDABLE. If it is used to locate an object
that you control, it will return the number of its location. It will return
#-1 if you try to locate an object you don't control. Used on an exit,
LOC() will return the dbref number of the exit's destination (to get an
exit's source, use the HOME() function). The LOC() function returns the
drop-to of a room; usually, this is #-1.
 
(Continued in 'man 6.1.2'.)
 
&6.1.2
Related to the loc function is the %L substitution. This returns
the location of the enactor. Since it requires the enactor to trigger
off a command of some sort, however, it cannot replace the LOC() function,
unless you just want LOC(%#).
 
* * * * *
 
The NEARBY() function tests if one object is near another. It is
called with: nearby(obj1,obj2). For this function to work, you must control
at least one of the objects, or be near one of them. Object1 is considered
to be nearby Object2 if it is in the same location, if it is being carried
by Object2, or it is carrying Object2. If the two objects are nearby, the
function returns a 1; otherwise, it returns 0.
 
* * * * *
 
(Continued in 'man 6.1.3'.)
 
&6.1.3
The MUSH functions you will use most often will probably be those
which return names and dbrefs. But almost all of MUSH programming involves
the manipulation of lists - adding items, removing items, finding certain
items within, etc. Lists, for MUSH purposes, are generally defined as a
list of space-separated of words. The first word in a list is 1.
Strings, on the other hand, are composed of arbitrary characters. The
first character in a string is 0. Lists are basically special types of
strings. Everything in MUSH is eventually treated as a string.
 
Several functions create lists: LCON(), LEXITS(), LATTR(), and LWHO() are
perhaps the most frequently used of these. LCON() gives a list of the
dbref numbers of all objects in a room (including dark objects). LEXITS()
gives a list of the dbref numbers of all non-dark exits out of a room.
LATTR() gives a list of all attributes on an object. LWHO() gives a list
of all non-dark connected players.
 
* * * * *
 
(Continued in 'man 6.1.4'.)
 
&6.1.4
Several functions are useful for parsing lists. The POS() function,
called with pos(string1,string2), returns the position number of string1
in string2. If string1 is not in string2, the function returns #-1.
The first character is considered to be position 1. This function
is particularly useful when checking flags on an object. For example, to
check if an object is a puppet, check pos(p,flags(object))   If this returns
anything but #-1, the object is a puppet.  (An easier way to do this is to
use the HASFLAG function: HASFLAG(object,puppet) will return 1 if the object
is a puppet).
 
For parsing, FIRST() and REST() are useful. They return the "head"
and the "tail" of a list, respectively, and are basically identical to
the LISP functions CAR() and CDR(). The "head" of a list is the first
word in that list; the "tail" of the list is everything else. There's
also the useful LAST() function in TinyMUSH 2.2, which returns the last
word in a list.
 
(Continued in 'man 6.1.5'.)
 
&6.1.5
The WORDS() function counts the number of words in a list. This is
useful for a loop counter ("repeat this action until the counter variable
is greater than the number of words in the list"), and for finding the
last word in a list, which is done as follows:
  Assuming that the list is in %0: extract(%0,words(%0),1)
  This counts the number of words in the list, then uses extract to take a
  one-word long list starting from that position - the last.
(Of course, if you're programming in 2.2, you should just use the LAST()
function instead of this somewhat-complicated extraction.)
 
The STRLEN() function returns the length of an entire string (list).
It is extremely useful when used in conjunction with the MID() function.
The latter is called with: mid(string,position of first character,length)
and returns a string of <length> characters starting from <position>.
The first character in the string is numbered 0, not 1.
Supposing you wish to return a string starting with its third character.
You would use: mid(string,2,strlen(string))
 
* * * * *
 
(Continued in 'man 6.1.6'.)
 
&6.1.6
The EXTRACT() function, mentioned above, called with
extract(list,first,length), is used to pull out words from the middle
of a list. "Length" is the number of words to be extracted, _not_ the
number of letters.
 
MATCH(), called with match(list,pattern), returns the number of the
word where <pattern> first occurs. The first word in the list is numbered 1.
If no match is found, the function will return 0. The pattern may be straight
text, or it may contained the wildcards * and ?. The MEMBER() function is
similar, except that it does not take wildcards, and is case-sensitive,
so match(a B c d,b) will return 2, but member(a B c d,b) will return 0.
 
The case-sensitivity of MEMBER() can be worked around using the
UCSTR(), LCSTR(), and CAPSTR() functions. These functions return a list with
all letters capitalized, all letters in lowercase, or with the first letter
of the first word of the list capitalized, respectively.
 
(Continued in 'man 6.1.7'.)
 
&6.1.7
EXTRACT() and MATCH() functions can be combined to match two lists:
  Suppose you have two registers, va and vb. The first contains a list of first
  names, and the second contains a list of last names. Given a first name, you
  want to find the last name. Assume that the first name given as input is in
  %0, and that it is in the va. Then, the matching last name will be:
  extract(v(vb),match(%va,%0),1)
  It uses the match() function to find the position of the name in the first
  name list, then uses extract() to get the word in the corresponding position
  on the last name list.
 
There's a function which combines an EXTRACT() and MATCH(), called
GRAB(). It takes the syntax "grab(list, wildcard)"; it finds the first
element of the list which matches the wildcard, and returns that
element. This is useful if you want to partial-match something, and
then want to get its entire name. For example, the function call
"grab(banana:yellow apple:red pear:green plum:purple, pear:*)" will
return "pear:green".
 
* * * * *
 
(Continued in 'man 6.1.8'.)
 
&6.1.8
There are two functions related to EXTRACT() and MATCH(), which operate
on multiple elements of lists. They're called ELEMENTS() and MATCHALL().
"matchall(list, wildcard)" will return the element numbers of all elements
of the list which match. "extractall(list of words, list of numbers)"
will return the elements of the list which correspond to the given list
of numbers. These two functions can thus be combined to locate, and then
grab, multiple elements of a list.
 
The MATCHALL() function can be used in conjunction with WORDS() to
determine how many times a given word appears in a list, via
"words(matchall(list, word))" -- MATCHALL() returns the list of
element numbers which match, and the WORDS() counts them up.
 
&6.2
6.2   Non-standard attributes and attribute flags
Non-standard attributes act much like V-attributes, except that they
may be arbitrarily named, as long as the names do not conflict with the names
of any existing attribute. Objects can have an unlimited number of attributes,
thus freeing the programmer from the necessity of creating multiple objects
to handle extremely complex programs.  Non-standard attributes are set using
one of two methods:
  &<attribute name> <object>=<whatever>
  @set <object>=<attribute name>:<whatever>
1.50 also allows:  @_<attribute name> <object>=<whatever>
 
These attributes may be accessed via the get() and v-functions,
%-substitutions of the form %attrib do not work for user-named attributes,
as they do with @va-@vz. In all other respects, however, user-named attributes
behave like @va-@vz.
 
* * * * *
 
(Continued in 'man 6.2.2'.)
 
&6.2.2
Non-standard attributes may be locked (prevented from being changed
by anyone other than the person doing the locking, or a wizard), or
chowned separately of the object. The syntax for doing this is
"@lock <object>/<attribute>"; "@unlock <object>/<attribute>" unlocks
the attribute.
 
Attributes can also have flags. These are set via the command
"@set <object>/<attribute> = [!]<flag name>".  There are three flags
which may be set. The VISUAL flag makes an attribute public; anyone
can read it via the GET() function. The NO_COMMAND flag prevents an
attribute from being checked for $-commands and ^-listens. The
NO_INHERIT flag prevents an attribute from being inherited by the
children of the object.
 
When you examine something, a locked attribute will have a "+"
sign next to it. Attributes such as LAST are owned and locked to God;
mortals may not change them. VISUAL attributes will be marked with "v",
NO_COMMAND attributes will be marked with "$", and NO_INHERIT attributes
will be marked with "i".
 
(Continued in 'man 6.2.3'.)
 
&6.2.3
Certain 1.50 configurations always give the dbref of an attribute's
owner next to the attribute name; other configurations, and 2.0, only
show the attribute owner's dbref is it's different from the object's owner.
 
In 1.50, the ANSI_DISPLAY flag, when set on a player, will cause
attribute names to be highlighted in boldface (if the player's terminal
supports ANSI control sequences). This is useful if you are examining a
very large object, and need to be able to quickly and easily see where
the breaks between attributes are.
 
* * * * *
 
Non-standard attributes can make MUSH code much easier to read; it
is also good practice to do a &purpose or &program register on the object
which explains a little bit of the programming, for future reference.
 
(Continued in 'man 6.2.4'.)
 
&6.2.4
One useful thing about non-standard attributes is that they are very
useful when programming objects which contain numbered registers - mail
objects, bulletin boards, etc. Instead of going through the clumsy method
of putting get(me/va) get(me/vb) get(me/vc) etc. in a register and using
extract() to force an evaluation, you can directly set registers, like:
@va object=$foo *=*:&r%0 me=%1
@vb object=$bar *:@pemit %N=get(me/r%0)
Note the use of the brackets within the get() to force register evaluation
early. The two statements above allow you to set and retrieve numbered
non-standard attributes.
 
&6.3
6.3   Introduction to @dolist
One very useful command is @dolist <list>=<action>. It performs
<action> for every item in the list, replacing the symbol "##" with a
word from the list. For example, @dolist [lexits(here)]="[name(##)]
will make you say the names of all exits in the room you are in.
It can be used to multi-page: @dolist Culyn RosaLil Jellan = page ## = Hello!
 
@dolist evaluates its arguments in order. So, for example,
"@dolist Culyn RosaLil Jellan = page ## = Hello!"  would page Culyn,
then RosaLil, then Jellan.
 
@dolist can also become rather confused by @switch statements and
semi-colons. It is best to enclose the entire <action> section of the
@dolist with braces - @dolist <list> = { <action> }
This will prevent most errors.
 
@dolist should replace most list-based loops. In the past, the
following was an efficient implementation of the problem listed above:
 
(Continued in 'man 6.3.2'.)
 
&6.3.2
VA: $name-exits: @tr me/vb=[extract(lexits(here), 1, 1)], 1
VB: @switch %1=>[words(lexits(here)],{},{"[name(%0)];
     @tr me/vb=[extract(lexits(here), add(%1,1), 1)], [add(%1,1)]}
(It might be more efficient, if there are a lot of exits, to set
 @vc me=lexits(here) in the VA, but this is a small point).
 
Now, all that's needed is:  VA: $name-exits: @dolist [lexits(here)]="[name(##)]
 
Not only is this much cleaner, but it's considerably faster than
the old method. Triggers take up quite a bit of time to execute, and
@dolist is vastly more efficient.
 
&6.4
6.4   Time synchronization
Semaphores are a very flexible tool for the synchronization of
objects. In practical terms, they make sure things occur in a specified
order, and prevent simultaneous actions from conflicting with each other.
The name "semaphore" comes from the name for signal flags used on ships;
in modern computer systems, semaphores are used to prevent sections of
memory from being concurrently read from or written to by different
processes. Indeed, one of the main purposes of semaphores in MUSH is
preventing two things from attempting to change the same attribute at
the same time. More generally, in MUSH, semaphores are good for two
major things: preventing an already triggered object from being used again
until it has finished the action list associated with that trigger, and
preventing a command from being run until a certain other command has
executed. It is, fortunately, not necessary to completely understand how
semaphores work in order to use them.
 
(Continued in 'man 6.4.2'.)
 
&6.4.2
"Synchronized" actions are those which are correctly performed in
some specified order. Semaphores effectively delay the execution of
commands by queueing them up in the correct order, and preventing the
execution of the next command before the previous command has finished,
thus synchronizing the objects and actions. Every semaphore is associated
with a number, called the "semaphore count", which is the number of actions
(or in the case of MUSH, action lists) it is trying to synchronizing.
Such actions are also referred to as "pending", "blocking", or "waiting" on
the semaphore.
 
* * * * *
 
In MUSH, this semaphore count is stored in the SEMAPHORE attribute.
A semaphore which has no commands pending will have a count of 0. If
the semaphore count is positive, the semaphore has that many actions
waiting on it. A negative semaphore count indicates that actions will not
block on it; for example, a count of -3 indicates that the next three
actions to wait on the semaphore will be immediately executed.
(Computer science types: please note that this is the REVERSE of the
convention generally used in operating systems theory!)
 
(Continued in 'man 6.4.3'.)
 
&6.4.3
Two operations are used to control a semaphore: wait, and notify.
"Waiting" an action list on a semaphore puts those actions at the end
of that semaphore's queue. Each time a semaphore is notified, the first
action list on its queue is executed. Thus, an action which waits on
a semaphore is delayed until the semaphore is notified. A command which
is waiting for its associated semaphore to be notified is referred to
as "blocked"; when its semaphore allows it to be executed, the command
is then "unblocked."
 
Eexecuting a wait on a semaphore increases its semaphore count by
one, and executing a notify on a semaphore decreases the count by one. To
execute a wait on a semaphore, use "@wait <semaphore>=<action>"; if
<action> is a list of commands, it must be enclosed in curly braces.
To notify a semaphore, use "@notify <semaphore>". Please note that the
object that does the waiting executes the action; the semaphore is
simply a timing device. Thus, in MUSH, you can use objects you do not
own as semaphores, if they are LINK_OK.
 
(Continued in 'man 6.4.4'.)
 
&6.4.4
Objects waiting on a semaphore run their actions on a first-come,
first-served basis, If #2, #3, and #4 execute waits, in that order, on
semaphore object #5, the first notify the semaphore receives will begin
#2's action list. The next notify will execute #3's action list, and so
on. In other words, notification of a semaphore just releases the FIRST
object which waited on it.
 
It is possible to notify a semaphore repeatedly, by providing a
numeric argument to @notify: "@notify <semaphore>=<times to notify>"
If the number of times is not specified, the semaphore will be notified
once. The semaphore executes the first <times> commands that were @waiting
on it. As a reminder, if the semaphore is notified more times than it has
commands queued, the semaphore count will become negative and further
@waits dependent on that semaphore will be immediately executed, until the
semaphore count is zero. This normal @notify is shorthand for the default
switch, "@notify/first".
 
(Continued in 'man 6.4.5'.)
 
&6.4.5
If you want all waits pending on the semaphore to execute, use
"@notify/all <semaphore>". This will cause all the actions waiting on
the semaphore to be executed, and resets the semaphore count to 0.
The other method of clearing a semaphore is "@drain <semaphore>". This
will reset the semaphore count to 0. Actions waiting on the semaphore
are simply discarded. In 1.50, destroying an object automatically
executes a @drain on it.
 
MUSH also allows for semaphore waits to have a timeout expiration.
An object can use "@wait <semaphore>/<time in seconds>=<action>".
If <semaphore> is notified before <time> passes, the action is executed
and the semaphore count decreases by one, just as if a regular semaphore
wait were done. If <time> passes, and the action is still blocked pending
semaphore notification, it is executed anyway, and the semaphore count
on the <semaphore> is decremented by one.
 
* * * * *
 
(Continued in 'man 6.4.6'.)
 
&6.4.6
Most MUSH programmers will never use semaphores for anything more
than basic synchronization. The most common form of this is preventing
an action list associated with a trigger from being run while the action
list from a prior trigger is still executing. This is especially
important for vending machine objects that need to work on a single
item at a time. One way of preventing this is to use an attribute BUSY;
a @switch at the beginning of trigger checking for this attribute will
tell you if the object is already trying to execute something. This,
however, can force the player to make repeated attempts to trigger the
object. A better way to do this is to associate the entire action list
of the trigger with a semaphore.
 
Triggers for action lists are generally @a-actions like @apay,
or user-defined commands, like $buy. We thus set up our wait in one
of the following two forms:
 
 @apayment object = @wait me={ @@ list of actions @@; @notify me}
 &DO_COMMAND object =$command: @wait me={ @@ list of actions @@; @notify
 me}
 
(Continued in 'man 6.4.7'.)
 
&6.4.7
We also need to initialize the semaphore state; this is best done
by "@startup object = @drain me; @notify me".  The @drain makes sure that
we start with a clear semaphore. We need the @notify in the startup because
we don't want the first action we trigger on the object to block. The
semaphore state of the object should thus begin at -1. (When programming
your object, please remember that the very first time you use it, you will
have to @notify it.)
 
In the above example, if someone tries to trigger the object before
a prior trigger has completed, the action list will block. The last command
in the prior action list is "@notify me"; this will clear the block, and
allow the next action list to begin immediate execution. This simple
technique is extremely useful for avoiding the headaches associated with
preventing concurrent attribute updates.
 
&6.5
6.5   Security problems in programming
Although, in MUSH 1.50 and 2.0, any object that you own cannot force
you, care should still be taken to make sure that objects are reasonable
secure. Be extremely careful not to leave control objects lying around.
_Always_ lock them to yourself, since possessive get works in 2.0 code.
get <person>'s <object> will enable someone to take any unlocked object that
you are carrying. One simple check you can make is to put a @switch in all
commands that checks to see that the triggering object is its owner:
@switch %#=<Your dbref>,{action list},{@pemit %#=You're not my owner!}
Another secure way of doing this is to use "@lock/use" to prevent anyone
but those who pass the lock from triggering $-commands on the object.
 
One common problem is carelessness with semi-colons. Unless enclosed by
curly braces { }, commands like %0 can be extremely hazardous. For
example, take the object Foo, with a @va of $foo *:@emit %0
Type "foo bar" will force the object to emit bar.
 
(Continued in 'man 6.5.2'.)
 
&6.5.2
Under old parsers, there's a nasty trick that can be done:
"foo bar;@destroy me" (or, for that matter, any other command). Foo will
emit bar, and then happily blow itself up. This, obviously, is a Bad Thing.
The @va should be $foo *:@emit {%0}   This safely traps any semi-colons.
Although this kind of trick shouldn't be (easily) possible to do under the
new parser, it should still be something to keep in mind and avoid if possible.
 
* * * * *
 
Other problems involve registers that are directly set to whatever
someone types in; if this is a force, triggering the register will execute
the command. There are many variations on this; the most common is the
bulletin board-type object which has a command like "post <subject>=<message>"
and sets attributes to the subject and message, perhaps like this:
$post *=*: &SUBJ_[secs()] me={From %N: %0}; &MSG_[secs()] me={%1}
 
(Continued in 'man 6.5.3'.)
 
&6.5.3
Here, the SUBJ attribute is safe, since the "From" component
prevents the placement of a $command into the attribute. The MSG, however,
is subject to something like this: "post Problem=$foo: @emit Gotcha!"
This would set something like MSG_746606174 to "$foo: @emit Gotcha!"
thus allowing any player to type "foo" and force the bulletin board
to @emit Gotcha!  This is, obviously, dangerous. This problem can
be gotten around by setting MSG to "XX %1" or something similar, and
using REST() to retrieve the message when it is needed. Never allow a
player to directly set an attribute in such a manner, even for a moment!
To do so is to invite trouble.
 
                        ----------
 
A great many problems can be taken care of under INHERIT. Only objects
set INHERIT may force their owner. Objects that aren't INHERIT may not force
objects that are. If a player is set INHERIT, all of his objects are
considered to be INHERIT. This flag is reset in a @chown.
 
(Continued in 'man 6.5.4'.)
 
&6.5.4
In 2.0, INHERIT objects owned by wizards have wizard powers. Any object
with wizard powers may force anything else, regardless of its status. This
flag is most useful for wizards and people who own large, complex, publicly
used systems, such as mail.
 
Sometimes it's useful to be able to have a non-INHERIT object force
one that is, for a single command or group of commands. Since the most common
use of this is for say/pose/emit output, in 2.0, the commands @fsay, @femit,
and @fpose have been provided. These do the obvious. The only thing to note is
that @fpose has a switch, @fpose/nospace, which does eliminates the space
between the name of the object and its pose (making it equivalent to
player ";").
 
* * * * *
 
(Continued in 'man 6.5.5'.)
 
&6.5.5
There are two other notable techniques for getting around INHERIT
restrictions. Frequently, you are going to want to have a non-INHERIT
object trigger one that is; this is especially true if you are a wizard
on a 2.0 MUSH and should not, for security reasons, set objects INHERIT
unless they absolutely have to be. You can use LINK_OK as a "@trigger-ok"
flag in 1.50, but this is not possible under 2.0. Therefore, there must
be a kind of "message passing" used.
 
The first method is to uselock the object you want triggered (the
"victim") to an auxiliary object inside it, and then have the non-INHERIT
triggering object (the "actor") trigger the auxiliary, which then does
something which matches a $command on the victim. In the following example,
#88 is the auxiliary object.
 
 &DO_ACTION actor=$test *: @trigger #88/PROPAGATE=%0
 &PROPAGATE #88=do_it %0
 &ACTION victim=$do_it *: @dolist %0={@set ##=dark}
 @tel #88=victim
 @lock/use victim=#88
 
(Continued in 'man 6.5.6'.)
 
&6.5.6
* * * * *
 
Unfortunately, the $command method is not very fast. A better
method is to use ^-patterns, and uselock the victim to the actor to
prevent spoofing. The victim should also be kept in a secure location
where it's not going to "hear" anything accidentally. The actor
@pemit's an action pattern to the victim, which acts on it.
In the following example, #90 is the victim.
 
 &DO_ACTION actor=$test *:@pemit #90=TEST_PCODE %0
 &TEST_PCODE_LISTEN #90=^TEST_PCODE *: @dolist %0={@set ##=dark}
 @set #90=LISTENER  (or MONITOR, in 2.0)
 @lock/use #90=actor
 
As long as you are careful to make sure that the victim doesn't hear
anything other than the actor, and then only when appropriate, this
is the best method for getting around INHERIT.
 

* * * * *
 
(Continued in 'man 6.5.7'.)
 
&6.5.7
The SECURE() function returns a string with all semi-colons and
braces {}  converted to spaces. This is useful if you want to prevent
people from abusing your stuff via triggers and the like.
 
The ESCAPE() function inserts the escape "\" character before
all [ ], preventing the expression within from being evaluated - the string
is returned exactly as typed. An escape character is also inserted before
the first character of the string. The parser's handling of the escape
character is reliable and consistent; another less reliable character
which can act as an escape is the percent "%" character.
 
&6.7
6.7   Debugging
One of the things that is sadly lacking from MUSH is an easy way
to debug objects. One is often reduced to having an object say registers
out loud, or setting the object PUPPET.
 
If the object is PUPPET, you will see all the output from the commands
it executes, such as "Set."  Unfortunately, in TinyMUSH 2.0, "Set." is
used to acknowledge setting attributes, flags, and miscellaneous other
things. Thus, puppet output can be rather useless (although an "I don't
see that here." or "Huh?" or similar messages can be useful in notifying
you of a typo).  1.50's output is a bit more informative; it will tell
you which object is getting set, and differentiate between attribute
sets and flag sets, enabling the PUPPET flag to be fairly useful for
debugging purposes.
 
* * * * *
 
The VERBOSE flag has been provided for debugging purposes. It
displays the commands getting executed, which is useful for checking
evaluation order and the like.
 
(Continued in 'man 6.7.2'.)
 
&6.7.2
In 2.0, it displays all commands executed by the object to the
object's owner, in the format <object name>] <command>. The output can be
slightly messy, especially if @switches are involved. When it goes to
evaluate the switch, it will display the entire switch statement; it will
then show the entire branch of commands and then go to execute them.
 
In 1.50, the VERBOSE flag displays all commands executed by the
object to the object's owner, in the format <object dbref>] <command>.
As with the 2.0 version of this flag, this is the command _before_ it has
been interpreted by the parser. Placing a @force before the command
_might_ be useful for _debugging purposes only_, since this will parse
all the arguments, resulting in VERBOSE output which shows the final
form of the arguments to the command.
 
* * * * *
 
(Continued in 'man 6.7.3'.)
 
&6.7.3
In 1.50, there is a flag called DEBUG. Objects set DEBUG cause their
owner to be notified of the results every call to the parser that that object
makes. If used in conjunction with the VERBOSE flag, it can pinpoint
precisely which expression is being evaluated to an undesirable quantity. The
output is in the format <object dbref>! <unparsed string> => <parsed string>
 
A similar flag, called TRACE, exists in 2.0. Its output, however, is in
the format "<object name>(<dbref>)} '<unparsed string> -> '<parsed string>'
 
* * * * *
 
One interesting thing to note about @dolist is that it evaluates
all switches on one "level" of command before executing the results of
those switches.
 
This is a quirk which is only affects the output of @dolist; in
terms of execution order, @dolist simply repeats its command sequence on
each item in the list, completing the command sequence for each item before
beginning on the next.
 
&6.8
6.8   On the New Programming Style
The power of MUSH has increased dramatically in the past six months.
Things that used to be difficult or slow are now fairly easy to do, mostly
through the addition of new commands and functions.
 
The biggest advances are in MUSH's treat of list processing. It
is now quite simple to take a list and perform a series of functions on
it, via the function ITER() or the  1.50 command @map. These functions
"map" another function onto each element of a list, returning a list.
(The terminology comes from the LISP programming language).
 
ITER() and @dolist both use the "##" token to signify replacement,
so it is fairly difficult to easily combine the two.
 
1.50's @map command maps a function onto a list, placing the
new list into the MAPLIST attribute on the object executing the @map.
This makes the parser somewhat more forgiving. @map can be thought of
as a command version of the ITER() function provided by both MUSH
versions. This command, however, is rather redundant and is likely to
go away in future versions of 1.50; new programs should avoid its use.
 
(Continued in 'man 6.8.2'.)
 
&6.8.2
* * * * *
 
Among the more useful complex list processing functions are
SETUNION, SETINTER, and SETDIFF. These three functions return a sorted
list from two lists. SETUNION concatenates two lists, removing duplicates.
SETINTER returns the elements that the two lists have in common. SETDIFF
returns the elements of the first list which are not in the second.
 
The SWITCH() function also enables one to do the equivalent of
@switch on a pattern, but instead of triggering an action, the SWITCH()
function returns a string.
 
(Continued in 'man 6.8.3'.)
 
&6.8.3
The final major improvement is the U() function in 2.0 (also called
UFUN() in 1.50. In 1.50, UFUN() also has a close relative, ZFUN()). This
is a "user-defined function", which generally consists of a bunch of
functions in an attribute. The uses of U() are beyond the scope of
this section; suffice to say that it allows one to pass arguments into
a function of one's own devising, and get a string back in return.
It is most often  used to break up complex evaluations into something more
readable, or to make a commonly used sequence of functions easily accessable.
This function is described in detail later in this manual.
 
* * * * *
 
The increasingly popular "switchless style" of programming
eschews the actual @switch command in favor of using function evaluations
to generate a word. The object is then @forced to execute the attribute
named that word, via the V() function.
 
Concatenation is merely a matter of leaving out things such as square
brackets [] in the appropriate places. Under 1.50, the STRCAT() function can
also be used to explicitly concatenate strings.
 
(Continued in 'man 6.8.4'.)
 
&6.8.4
A very simple example of "standard" style vs. switchless coding
follows. Let's suppose we want an object to respond with one of three
different, randomly selected, messages, when someone types something.
 
Switchless style:
 &FOOBASE object=$foo: @emit [v(FOO[rand(3)])]
 &FOO0 object=Zero!
 &FOO1 object=One!
 &FOO2 object=Two!
 
[ or, alternatively, you could put the @emit in each statement and leave
  it out in the main one, if you wanted to execute more complex commands. ]
 

A slightly more interesting example, although not one that is
really any more complicated -- there is a "cat" object upon which you
wish to place a "pet cat" command which will get the cat to respond
with a random action:
 
(Continued in 'man 6.8.5'.)
 
&6.8.5
Standard style:
 &PET_CAT cat=$pet cat:@switch [rand(3)]=
 
        0,@emit The cat purrs when %N pets her.,
              1,@emit The kitty blinks at %N.,
              2,@emit The cat arches her back and hisses at %N.
 
Switchless style:
 &PET_CAT cat=$pet cat:@emit [s(v(PETMSG[rand(3)]))]
 &PETMSG0 cat=The cat purrs when %N pets her.
 &PETMSG1 cat=The kitty blinks at %N.
 &PETMSSG2 cat=The cat arches her back and hisses at %N.
 

In this particular example, the "switchless" style is wasteful;
it is more efficient (as well as simpler) to use a @switch.
The switchless style is useful when you have a very complex function with
many possible outcomes, or need to run one huge batch of commands at a time,
and want to avoid use of multiple @triggers.
 
(Continued in 'man 6.8.6'.)
 
&6.8.6
The switchless style for objects like this, however, does make it
quite easy to expand upon the basic object. For example, to add more
responses to the cat, one merey has to change the "rand(3)" to, say,
"rand(10)", and then add new PETMSG attributes. It is much more difficult
to edit switches (plus, the switchless style is easier to read).
 
Some caution should be exercised when programming complex objects in
the switchless style. Because "switchless" programs often involve extremely
large, complicated function, they can take quite a long time to evaluate.
Normally, in MUSH, commands are queued, so that no one object consumes a
large chunk of time all at once. The switchless style more or less defeats
that, forcing the game to focus all its time on evaluating that one
monster function. This can contribute to server lag. One should thus
save switchless programming for those objects that really require the
speed provided by the switchless style.
 
(Continued in 'man 6.8.7'.)
 
&6.8.7
Do note that it is presently trendy to brag that a given program uses
no @switches (or SWITCH()es, or whatever the unpopular function of the
week happens to be). One should be careful to always choose the method
which is actually faster, rather than the method which seems the most
impressive. Incomprehensible MUSHcode is poorly-written MUSHcode, usually.
 
* * * * *
 
Further notes on the parser:  while it is quite consistent in
evaluation, many programmers continue to question exactly what is needed
to accomplish certain types of evaluations.
 
The '\' character is an escape character. When placed in front of
a "special" character (like brackets or percent signs), it prevents them
from being evaluated. Each escape character delays evaluation for one
pass through the parser.
 
The '%' character is most often used for "percent substitutions":
%N, %r, %va, etc.  When it is not being used for that purpose, though,
it, too, acts like an escape character.
 
(Continued in 'man 6.8.8'.)
 
&6.8.8
The curly braces {}  are used to group commands. Also, in "weird"
functions which cause a second pass through the parser (such as ITER())
the curly braces are used to delimit functions that should not be
evaluated on the first pass through the interpreter.
 
The square brackets [] signal the start and end of a function
evaluation group. They can be nested, and for the purposes of concatenation
show where "normal" text ends and substitutions begin.  Square brackets
say, "Evaluate me now."  If you put square brackets into something like
a call to ITER(), you will need to escape them out.
 
Note that functions such as ITER() and U() are _exceptions_ to
the parser rules; because they call the interpreter again, the behavior
of the special characters sometimes seems strange. Successfully getting
ITER() to return the correct value depends on careful use of curly braces
and escape characters.
 
For further details on complex programming in this style, as well
as notes on efficiency and further parser details, consult the final
sections of this manual.
 
&6.9
6.9   Hints and tips
This is by no means a complete guide to MUSH. The code is constantly
changing, and new features are constantly being implemented. There are far
more commands and functions available than can be covered in a manual like
this one. If you are interested in MUSH programming, you should read through
all the help files, on @-commands, functions, and flags.
 
The best way to learn how to program MUSH is to do it! Find some sort
of project and work at it. If you come up with something really neat, I'd
love to hear about it - I'm especially interested in unique applications of
non-standard attributes. Besides, I like getting mail.
 
The non-standard attributes available in TinyMUSH make
certain ways of doing things obsolete. Most notable is the use of extract()
and member() combined with a list containing va-vz to access the va-vz
attributes in numerical order; attributes can now be numbered a1-a10, for
example. Also, worrying about running out of registers is now a thing of
the past.
 
Corrections, complaints, or congratulations are always welcome;
I can be found as Amberyl on most MU*s, or emailed at lwl@godlike.com
 
&7
7.    QuickStart Guide
 
&7.1
7.1   Basic Syntax
This section is really separate from the rest of the manual. It
assumes that the reader is familiar with some other programming language,
and simply wishes to learn how to get started in MUSH as quickly as
possible. Such users will still benefit from reading the rest of the
manual, since there are many programming applications in MUSH that don't
really match anything one would do in another language; this brief section
is simply intended to explain concepts in a slightly more compact,
"traditional" computer-science fashion.
 
Like most programming languages, MUSH has variables. There are
temporary and permanent variables. Temporary variables are transitory,
and are not saved in the database. They include the stack variables
%0-%9, the enactor %# and related variables (the enactor name, %N, and
the associated pronouns, %s, %o, and %p), the local registers r(0) - r(9),
and so forth. Permanent variables are stored in attributes, and can be
referenced by various functions which fetch variables. The most common
of these are the V() function, which fetches an attribute off the current
object, and GET(), which fetches an attribute off an arbitrary object.
 
(Continued in 'man 7.1.2'.)
 
&7.1.2
Attributes are divided into two categories, normally called
"built-in" and "user-defined". Built-in attributes are set with the
command "@<attribute name> <object>=<text>". User-defined attributes
are set with the command "&<attribute name> <object>=<text>". You can
set a built-in attribute using the user-defined syntax, but convention
normally dictates the use of '@' for built-ins.
 
The majority of built-in commands also being with '@', although
some, such as "page", do not. Conventionally, MUSHcoded global commands
begin with '+'. All commands are interpreted at runtime. Normally, the
'=' sign is used to separate the main two arguments to a command. If
there are multiple components to the second argument, these components
are separated by commas. Curly braces are used to indicate groupings,
and prevent interpretation of special characters enclosed within. The
escape character '\' can also be used to protect special characters.
 
(Continued in 'man 7.1.3'.)
 
&7.1.3
 MUSH is a scripting language, essentially. Most MUSH objects'
"programs" either output text or change the database in some way. The
generally accepted way to handle complex tasks is by manipulating lists
or strings in some manner. Everything in MUSH is eventually treated as
a string, and there is no system of types. Functional programming is
at the heart of most complex MUSH items; MUSH inherits a few LISP
constructs such as FOLD and SETQ.
 
&7.2
7.2    Conditional and Loop Constructs
There is no IF-THEN-ELSE construct in MUSH. Instead, there is
a command called @switch, which takes the format:
 
@switch <variable>=<condition1>,<action1>,
                   <condition2>,<action2>, ...
                   <conditionN>,<actionN>, <default>
 
This is equivalent to the SWITCH-CASE construct in languages such as C
and Pascal. Wildcard patterns are allowed in both the variable and the
conditions, thus making this a fairly powerful construct.
 
MUSH also lacks an equivalent of the FOR and WHILE constructs.
Unfortunately, this type of structure is much more difficult to duplicate
in MUSH. The closest is equivalent is the command @dolist, with syntax
@dolist <list>=<action>, which performs an action repeatedly, substituting
an element of <list> for the token '##' within <action>, each time.
Thus, if you wanted to @create five items named 1, 2, 3, 4, and 5, you
would try: @dolist 1 2 3 4 5 = @create ##
(Continued in 'man 7.2.2'.)
 
&7.2.2
FOR constructs in most programming languages typically perform
a sequence of commands for some list of numbers, which might or might not
be sequentially, but are mathematically related in some relatively simple
fashion. The MUSH function LNUM() generates a list of numbers 0 to N.
This list can then be manipulated via a function called ITER().
 
It is important to remember that because the language is list-oriented,
manipulating lists generally turns out to be the most efficient way of coding
something. Good MUSHcode generally puts a minimal number of actual action
commands on the queue. Trying to write MUSH with the same type of logic
you would use in C or a similar procedural language is generally a mistake.
 
&7.3
7.3     Functions
There are many, many functions in MUSH. Numeric manipulation, string
manipulation, list manipulation, and functions to extract information from
the database form the heart of the MUSH programming language. The important
thing to remember here is that data in MUSH is untyped, and therefore,
functions may be used to perform transformations on data types that one
would normally not think of as useful for a particular type of data.
Truncating a floating-point number, for example, can be as simple as
taking X characters after the '.' of the number (which is simply a string).
There are, however, MUSH functions to perform a variety of complex tasks;
the above task can be done with TRUNC() or ROUND(), for example.
 
Functions take a fairly traditional parameter-format, with the
syntax: FUNCTION-NAME(<arg 1>, <arg 2>, <arg 3>, <arg N>)
Parameters are normally evaluated left to right, before the relevant
outer function is called; in general, the innermost functions are the
first to be evaluated.
 
&index3
INDEX OF SECTION III EXAMPLES:
 
5.1  Wagon
5.3  Wagon controller
 
&IV
MUSH Manual Version 2.008:
   Copyright 1993, 1994, 1995, Lydia Leong (lwl@godlike.com / Amberyl)
   Last revised 5/22/95.
 
Section IV: Wizard's supplement
 
8. Owning and seeing everything
  8.1  Special privileges, ROYALTY, and Powers
  8.2  Attribute ownership - @atrchown and @atrlock
  8.3  Object ownership - @chown and @chownall
  8.4  The queue - @ps and @allhalt
  8.5  The database - @entrances, @find, @search, and @stats
  8.6  A note about security and privacy
  8.7  The Master Room and command processing
9. Wiz-specific commands
  9.1  Talking to other wizards: @wizwall and @wizemit
  9.2  Messages: @wall, @listmotd, @motd, and @wizmotd
  9.3  Locking out players: @login and @rejectmotd
  9.4  Dealing with players: @newpassword, @pcreate, @boot, @toad, and @destroy
  9.5  Dumping the database: @dump and @shutdown
 
(Continued in 'man IV1'.)
 
&IV1
10. Database control
  10.1 Quota system: limited object creation - @allquota, @quota, and @squota
  10.2 Money control: give and @poor
  10.3 Consistency checking: @dbck and @purge, @dump/paranoid, @cut, @fixdb
11. Zones
  11.1 Object zones
  11.2 Parent room zones
  11.3 ZoneMaster players
  11.4 Some notes on local wizard control
12. The Fundamental Laws of Wizarding
  12.1 Wizard Etiquette
  12.2 The Five-Step Method of player management
        warning - nasty warning - gag - boot - newpassword
  12.3 Wizard commands and when they ought to be used
 
(Continued in 'man IV2'.)
 
&IV2
This section was written with the 1.50 wizard in mind. If something is
mentioned that doesn't exist in 2.0, and you're only interested in 2.0,
ignore it.  If you're going to play with the 2.0 wizard commands that
aren't covered in this section, you probably know what you're doing and
therefore don't really need those commands covered in this manual anyway.
All wizards, however, will probably find something useful in section 12,
which provides general rules for wizarding. Mortals may find it interesting
reading.
 
&8
8.  Owning and seeing everything
 
&8.1
8.1     Special Privileges, ROYALTY, and Powers
A wizard, by definition, owns and controls everything except for God.
A wizard may manipulate any object by using its dbref number, or by using
*player. Remote get, look, and examine work, and a wizard may bypass the HAVEN
flag by using "w *<player>=<message>" to whisper a message.
 
A wizard may look at anything by looking at the dbref number, or by
looking at *player. Warning: in 2.0 this triggers the odesc and adesc messages.
The format of "look" for wizards is somewhat different: the object's name
and dbref number is displayed on the line above the description. When looking
at exits, the full exit name - including aliases - is displayed.
 
Wizards can teleport to anywhere. In 1.50, the NO_TEL flag and
teleport locks do not have any effect at all on wizards; in 2.0, however,
wizards ARE affected by teleport locks. In 2.2, this is configurable.
 
The UNFINDABLE flag does not prevent wizards from locating a player.
A wizard can also obtain a player's location by using loc(*player), and get
any attribute. There is _nothing_ in the database that a wizard cannot see,
except for things like the password attribute and other "internal"
dark-to-all attributes.
 
(Continued in 'man 8.1.2'.)
 
&8.1.2
The LWHO() function allows wizards to obtain a list of dbrefs
of connected players. Also, in 1.50, wizards may watch connects and
disconnects by setting the MONITOR flag on themselves, or grant the
ability to do the same to another player. (NOTE: the 1.50 MONITOR flag
is NOT like 2.0 MONITOR; the equivalent of 2.0 MONITOR is 1.50 LISTENER.
2.0 has no equivalent of 1.50 MONITOR). In both 1.50 and 2.0, WHO for
wizards shows an extended listing with connect sites and other special
information; to see the listing that mortals get, use the command DOING
instead.
 
* * * * *
 
Pern version 1.14 introduced a ROYALTY flag (which can optionally be
turned off at compile-time). This flag is settable by wizards. Objects
ROYALTY can examine and teleport like wizards, but have no other wizard
powers; all of the statements about wizards above also apply to ROYALTY.
This flag does not exist in 2.0.
 
(Continued in 'man 8.1.3'.)
 
&8.1.3
PennMUSH 1.50 patchlevel 7 introduced a powers system. This
enables wizards to grant specific objects, including players, the power
to accomplish certain tasks that previous were restricted to wizards.
Also, since the BUILDER and IMMORTAL flags from previous patchlevels
are, intuitively, powers rather than real flag toggles, they were changed
to powers in patchlevel 7.
 
The powers include "teleport anywhere", "teleport anything", "examine
anything", "boot", and most of the other useful wizard powers, save
the ability to @force/control anything. Players who receive such
powers should exercise them with the same caution a wizard should use,
and they should not be given out lightly. A player granted all the
powers has all the abilities of a ROYALTY, and more, except for the
@rwall command.  Therefore, prudence should be exercised in granting
special powers.
 
&8.2
8.2     Attribute ownership - @atrchown and @atrlock
Attributes may be owned independently of objects. An unlocked
attribute can be changed by the owner of the object. A locked attribute
may only be changed by the owner of that attribute. Locked and unlocked
attributes are, for the purpose of triggers and similar evaluation,
exactly the same.
 
Only wizards may set attributes on things that they do not own. The
most recent player to change an attribute is its owner. Please note that it
does not do any harm for someone else to own one of your attributes. If the
attribute is locked, however, you will not be able to remove it _even if you
are a wizard. A wizard may, however, unlock the attribute and then remove it.
 
In 1.50, two commands are used to handle attributes. @atrchown
changes the ownership. The syntax is @atrchown <object>/<attribute>=<new owner>
@atrlock governs attribute locks: @atrlock <object>/<attribute>=<on or off>
@atrlock <object>/<attribute> by itself returns the status of the lock.
The 2.0 syntax (which also works in 1.50) is "@lock <object>/<attribute>",
"@unlock <object>/<attribute>", and "@chown <object>/<attribute>=<player>".
A normal "examine" shows the owner and lock status of attributes.
 
&8.3
8.3     Object ownership - @chown and @chownall
The @chown command is somewhat different for wizards. A wizard may
@chown any object he is carrying, or any object by dbref number. The syntax
is @chown <object>=<player>. Not that *<player> is _not_ used in @chown.
 
@chownall transfers the ownership of everything a player owns to
another player. @chownall <player> transfers ownership to the wizard who
executes this command. @chownall <player>=*<new owner> transfers ownership
to another player. Note the use of the pointer. A @chownall should NEVER be
done without the consent of both parties involved, since it is usually
difficult to reverse, especially if the recipient owns a lot of objects
himself.
 
&8.4
8.4     The queue - @ps and @allhalt
Wizards can use @ps all to see the contents of the entire queue, or
@ps *<player> to see the queue for one specific player.
 
When the queue is very full, or a machine is looping so badly or
triggering so many objects that simply halting it is not feasible, the
command @allhalt can be executed. This clears out the entire queue - player,
object, and wait, and displays to all connected players the message, "Your
objects have been globally halted by <Wizard>."  @allhalt should be used
sparingly; if the server is slow, the queue may be full, but it may not
necessitate an @allhalt. In 2.0, this is "@halt/all" rather than "@allhalt".
 
&8.5
8.5      The database - @entrances, @find, @search, and @stats
@entrances will work on "here" or on any room number, for a wizard.
@stats can be broken down by player, using "@stats <player>"  Note the
absence of a pointer.
 
Wizards need to be careful with @find, since @find with no arguments
outputs the list of all objects that the wizard controls - i.e., the entire
database. @search with no arguments, however, only does a @search on the
wizard, printing out all the objects he owns. @search with any arguments,
however, looks through the entire database, not just the wizard's objects.
If you are looking for something, always try to do a @search instead of a
@find, especially if you are on a 2.0 MUSH. @search which is restricted
to a player is _considerably_ faster than @find.
 
&8.6
8.6      A note about security and privacy. DARK.
Wizards have enormous power. No notes on a MUSH are private; a
wizard can examine them. Wizards can set themselves DARK, disappearing from
the WHO list. In 1.50, any actions taken by a dark wizard show up as
"Someone" rather than the wizard's name, if the game is so configured.
Wizards cannot listen to whispers or pages, and always show up on a @sweep,
whether or not they are dark. A wizard owns everything; he can change,
destroy, or force it to do whatever he wants (unless it is God).
 
Because of this, wizards must be VERY careful to make sure that
there are no programming loopholes in their objects which would enable the
objects to @force them to perform certain actions.
 
Wizards should also be careful to announce their presence, if they
are entering a room and are DARK. There is virtually no justification for
spying on a private conversation (the exception may be listening to two
players plotting how to crash the mud, or something similar).
 
(Continued in 'man 8.6.2'.)
 
&8.6.2
A wizard should _always_ check the location of a player before he
teleports to that player. Being paged by a player does NOT mean that the
player presently wishes for company. In general, the wizard should also ask
permission to enter the room. A wizard should also never teleport a player
anywhere without asking permission first - this is extremely rude.
Occasionally, one tends to act before thinking, but a wizard should try to
act with courtesy.
 
Also, remember that in 2.0, wizards who exceed the idle time normally
granted to mortals before an inactivity-timeout boot are set DARK.
Wizards are also booted for inactivity, but can set their @timeout
attribute to an arbitrarily high value; they will not be booted until
that @timeout has expired. Wizards who are DARK from inactivity have a
"d" next to their time instead of a "D", in the WHO list.
 
In 1.50, wizards are never booted for inactivity. They are, however,
set DARK at the mortal inactivity limit, if they are already set UNFINDABLE.
 
(Continued in 'man 8.6.3'.)
 
&8.6.3
If you are the sort of person who tends to forget that he is set DARK,
you might want an automatic reminder given to you when you move. The
following is useful for this:
 
@move me=[switch(hasflag(%!,Dark),1,WARNING: You are set DARK.)]
 
&8.7
8.7      The Master Room and Command Processing
In both 1.50 and 2.0, the command parser goes through the steps
shown here looking for a match on the command.  If it finds one at a
particular step, it stops and performs it.  If more than one match
(say, multiple south exits from a room), one is picked at random.
$-commands are an exception to this rule, in that ALL $-commands that match
are executed, except that the master room is only checked for $-commands
if none are matched in the check around the player.
 
The 2.0 evaluation order:
 
- Uppercase commands (WHO, QUIT, etc) if typed at a terminal.
- Prefix-character commands (", :, ;, etc)
- The 'home' command.
- Exits in the current room.
- Exits in the master room
- Internal commands.
 
(Continued in 'man 8.7.2'.)
 
&8.7.2
- $-commands in the following places, all checked in parallel:
   - Objects in your inventory.
   - Objects in your current location.
   - Your location (the room itself)
   - You (optionally)
- $-commands in the ZONE chain of the player's location
- $-commands in the ZONE chain of the player himself
- $-commands in the following places, all checked in parallel:
   - Objects in the master room.
   - The master room itself.
 
The 1.50 evaluation order:
 
- Uppercase commands (WHO, QUIT, etc) if typed at a terminal.
- The 'home' command.
- Prefix-character commands (", :, ;, etc)
- Exits in the current room.
- Internal commands.
- Enter aliases on objects in the current room.
 
(Continued in 'man 8.7.3'.)
 
&8.7.3
- Leave aliases on the object you are in, if applicable.
- $-commands in the following places, all checked in parallel:
   - Objects in your current location.
   - Your location (the room itself)
   - Objects in your inventory.
- If nothing has been matched:
   - If the zone of the player's location is a parent room,
- Parent room exits
        - All $-commands on objects in the parent room
   - Else,
        - All $-commands on the zone object of the player's location
- If still nothing has been matched:
   - All $-commands on the player's personal zone
- As a last resort, when matching still fails,
   - Global exits (Master Room exits)
   - All global $-commands ($-commands on objects in the Master Room)
 
(Continued in 'man 8.7.4'.)
 
&8.7.4
In both 1.50 and 2.0, the Master Room contains exits and commands
which are global to the entire MUSH. This should be used with caution,
as having a lot of global commands slow down the MUSH. Make sure
something is really necessary before adding it to the Master Room. If
it's only useful in some specific area of building, consider using a
Zone instead (see the later section of this manual).
 
Also, because it is necessary to check every attribute on every object
in the Master Room for commands which don't match anything, the number
of attributes on objects in the Master Room should be kept to an
absolute minimum.  It is also a good idea to keep the number of
objects in the Master Room down, since every object represents an
additional UseLock which must be checked.  As a general rule of thumb,
if an attribute doesn't contain a $command, it shouldn't be on a
Master Room object. For convenience, some data attributes can be kept
on Master Room objects, but this should be avoided whenever possible,
even if the data attributes are set No_Command.
 
(Continued in 'man 8.7.5'.)
 
&8.7.5
Note that the parents of objects in the Master Room, and, in 2.2,
parents of objects which are contained by a ZONE chain, are not
checked for $commands. This allows you to place data attributes on
the parent, for easy reference, thus leaving you with little excuse
for ever having non-essential attributes on the object itself.
 
&9
9.  Wiz-specific commands
 
&9.1
9.1      Talking with other wizards
MUSH code provides the commands @wizwall, @wizpose, and @wizemit.
(In 2.0, these are @wall/wiz, @wall/wiz/pose, and @wall/wiz/emit). Note
that none of these use an = sign. @wizwall and @wizpose are really the same
command;  "@wizwall :<pose>" is equivalent to "@wizpose <pose>"  In the
case of @wizwall <message>, it is  "Broadcast: <Wizard> says, "<message>""
In the case of @wizwall :<pose> or @wizpose <pose>, the format is,
"Broadcast: <Wizard> <pose>". @wizemit <message> shows the other wizards
"Broadcast [<Wizard>]: <message>"
 
1.50 provides @rwall, @rwallpose, and @rwallemit. They work
identically to the @wiz variants, except they send messages to both
royalty and wizards, prefixed with "Admin:" instead of "Broadcast:".
 
Only connected players may hear these messages.
 
&9.2
9.2      Public messages
Wizards can shout using @wall <message>. There is no way of blocking
out shouts; therefore, this should be used sparingly. It sends the
message to every connected player.
 
Wizards can set the Message of the Day using @motd <message>. The
message stays up until another wizard resets it, or the MUSH goes down. The
MOTD is shown to players when they connect, and when they use @listmotd.
Wizards also have a @wizmotd, which is shown to all connecting wizards.
For wizards, @listmotd displays all MOTD messages.
 
2.0 refers to these commands as @motd, @motd/wizard, and @motd/list.
 
&9.3
9.3      Locking out players
In certain situations, there may be a need to disable all non-wizard
logins. 1.50 code provides the @login <on or off> command. When @login is
off, all player connections will be refused - after the welcome screen, the
message set by using @rejectmotd <message> is displayed and the player is
disconnected.
 
In 2.0, the command to use is "@enable logins" or "@disable logins".
The @enable and @disable commands may be used to tweak other things as
well; this is probably the most commonly used of the options. The message
displayed to players who cannot connect may be set using @motd/down.
 
&9.4
9.4      Dealing with players
There is no easy way to retrieve the lost password of a player.
Therefore, it is simpler to simply use @newpassword <player>=<new password>.
The player is informed that the wizard has changed his password. The player
should then log in and change his password to something else that the wizard
doesn't know. Never @newpassword a player without his knowledge, unless
it's an emergency.
 
@pcreate is a command which only works if the MUSH is compiled under
registration. @preate <player>=<password>  creates a player with the name and
password. You may not create two players with the same name.
 
* * * * *
 
@boot *<player> can be used to force a player to disconnect from the
MUSH. This is the general punishment for being obnoxious, or for idling for
too long. If you are @booting someone for idling, you should, in general,
page them with a warning five minutes before doing the @boot.
 
(Continued in 'man 9.4.2'.)
 
&9.4.2
@boot has another use -- killing off sessions of players who
are unable to disconnect, due to network problems. Generally, in this
case it is best to use "@boot/port", which allows you to boot a specific
question. In 1.50, the wizard WHO shows descriptor numbers; in 2.0, you
must use the SESSION command to get the descriptor number of a connection.
"@boot/port <descriptor number>" then closes that specific connection.
Players will often request to have "frozen", dead, connections @booted.
 
In 1.50, players will be booted with a message notifying them that
they have been booted off the game. In 2.0, players will also be told who
booted them off, unless "@boot/quiet" is used, in which case the player
will simply be abruptly disconnected without any kind of notification.
 
* * * * *
 
@toad turns a player into an ordinary object, called "A wart toad
named <player>" (1.50), or "A slimy toad named <player>" (2.0) and @chowns
all his objects to the wizard doing the @toad. The player will be booted off
the game, prior to being turned into an object.
 
(Continued in 'man 9.4.3'.)
 
&9.4.3
@toad is actually somewhat redundant. @dest *player will @boot the
player, @chown all his objects to the executing wizard, and @destroy the
player itself. If possible, use this instead of @toad (TIM code and MUSE,
however, may be somewhat different.)
 
Be careful with @destroy #<dbref>. There is no check to see who the
object belongs to or what it is - be _very_ certain that you have the right
object number, or you may end up irretrievably blowing up an object which
represents hours of programming. There is no way to retrieve @destroyed
objects other than rooms (which may be set !GOING). 1.50 prevents this
somewhat by forcing wizards to use @nuke to destroy objects which do not
belong to them; please don't use @nuke as your standard command for
destruction, or you'll defeat the purpose of this safeguard!
 
The wizard command "slay" is a "kill" which always works. There's
generally no reason to use it, unless programming a puzzle or something
similar; all it does is give the player some money and send him home.
 
&9.5
9.5      Dumping the database
The command @dump writes the database to disk. In 1.50, this can
take anywhere from a minute or two to half an hour - make sure not to do
overlapping @dumps. Overlapping dumps can cause crashes, incomplete database
writes, and other assorted undesired effects.
 
In 2.0, you don't generally need to worry about doing dumps, as the
disk database is saved fairly often and loss from crashes tends to be
minimal.
 
The command "@shutdown" shuts down the MUSH. It first does a @dump,
gives all connected players the name of the wizard who did the
@shutdown, and the message "Going down - Bye", then drops all
connections. Don't do this without a very good reason.
 
(Continued in 'man 9.5.2'.)
 
&9.5.2
Note: if you have database damage and are shutting down because the
game will crash or doing something else equally nasty in a few
moments, DON'T! The straight @shutdown will save the database and your
damage will be permanent. In such a dire situation, you have two options:
find the God (or other person with direct access to the MUSH account) and
have him "kill -9" the process, or do a "@shutdown/abort". This will cause
the MUSH to dump core and die, allowing for the damage to be assessed later
by someone skliled with a debugger.
 
& 10
10.      Database control
 
& 10.1
10.1     Quotas - limited object creation
If quotas are turned on, the command @allquota <limit> displays the
current quotas and objects owned by all players, and then resets their quotas
to the new limit minus the number of objects they currently own.
 
@quota <player> reports the number of objects a player owns, and
his quota still available. @squota <player>=<limit> reports the number of
objects the player owns and his remaining quota, and then sets his quota to
<limit> minus the current number of objects he owns. If the limit is 0, then
@squota works identically to @quota.
 
& 10.2
10.2     Money control
Wizards have unlimited money, and can freely give out money to
players using give *player=<money>. Wizards can also take away money from
players by giving them negative money. It is generally not a good idea to
give players vast amounts of money. The command @poor <money> resets the
money of every player on the MUSH to <money>. This command should be used
sparingly, if at all.
 
& 10.3
10.3     Consistency checking
The commands @purge and @dbck will probably not be used by most
wizards. They check the database for corruption: @purge checks the destroyed
object list and makes sure that all the objects on that list are really
there; @dbck forces the database to run an internal cleanup and consistency
check every ten minutes. @dbck automatically executes @purge.
 
In 1.50, if, for some reason, your database is corrupted but the
game is still up (usually through a bug in the internal compression routines),
you will find that an attempt to dump the database will cause a segmentation
fault and core dump (i.e. a nasty crash).  You can generally get a clean
database write by using the "@dump/paranoid" command, which very thoroughly
scans the database before writing it to disk, checking for non-printable
characters and the like. Someone with access to the game's account should
then log in, back up the paranoid dump, and then kill off the game process
in some manner.
 
(Continued in 'man 10.3.2'.)
 
& 10.3.2
2.0 provides the ability to do some database repair within the
game. The first of the db repair commands is "@cut"; this cuts off the
object or exit chain at the wizard's location by setting the "next" field
of the object to NOTHING. The objects or exits beyond the cut retain
their location, but are not accessible except via dbref number.
They can be pasted back into their proper places via the @fixdb command.
This command allows you to more or less arbitrarily set the fields of
an object -- the contents, exits, location, and next pointers, as well
as the owner, value, and name. These commands are NOT to be used unless
you are CERTAIN you know what you are doing, as it is possible (and indeed
rather easy) to produce database inconsistencies/loops which can hang
or crash the server.
 
& 11
11.      Zones
 
This section only applies to PennMUSH 1.50.  Please see a later section
of this manual for a description of Zones in TinyMUSH 2.2.
 
& 11.1
11.1     Object zones
A Zone Object (or, alternatively, ZMO - Zone Master Object) is
simply an object that other objects have their zones set to. Objects
that have their zone field set to a ZMO are referred to as being in that
ZMO's zone. There's nothing at all special about a zone object, aside from
that property.
 
Anyone who passes the enter lock of a ZMO has control over objects
in that zone. Someone who has control of an object via passing the enter
lock on the ZMO can do many things that the object's real owner can do,
including examining the object, changing its attributes, and setting flags
on it. Two notable exceptions are the @chown and @destroy commands, which
are reserved to the object's real owner. Also, players NEVER control other
players.
 
This control property of zones makes it possible for two or more
people to work on a project together. A wizard is needed to @chzone a player
to a zone; henceforth, everything that player builds is automatically part
of that zone. The wizard-only @chzoneall command changes the zone of
everything a player owns. Wizards should not change the zone of a player
without first obtaining the approval of all other players in that zone.
 
(Continued in 'man 11.1.2'.)
 
& 11.1.2
For example, if I, Amberyl, wished to work on a project together
with Annalyn and Tavella, I would @create an object (let's call it MyZone),
and then "@elock MyZone=*Amberyl|*Annalyn|*Tavella". This would allow
myself, Annalyn, and Tavella to control all objects in the zone.
(PLEASE NOTE: wizards should never be in a zone with anyone! It's far too
easy for a regular player to abuse an item belonging to that wizard).
 
Players may @chzone their own objects to a ZMO that they own,
or are in the enter lock of. It isn't necessary to be personally zoned
to a ZMO in order to be able to control objects in it (the only criterion
is the enter lock of the ZMO); it is perfectly possible to be zoned to
something else (or Nothing), and @chzone the stuff you build to the
desired zone.
 
(Continued in 'man 11.1.3'.)
 
& 11.1.3
Zones have several other nifty features. First of all, $-commands
on the ZMO are "global" to rooms that are part of that ZMO, and to things
which are personally part of that ZMO. Also, objects can perform a
"@zemit <zone> = <message>" to emit a message to all rooms in that
zone. This command is computationally expensive and costs 100 coins, but
it can be very useful if you have, for example, a space station which
uses an intercom system for announcements.
 
& 11.2
11.2     Parent room zones
Parent rooms are a slightly more complex version of zones.
The main difference is that, instead of the ZMO being a thing, the
ZMO is a room. All information above about object zones also applies
to parent rooms.
 
Parent rooms have several more useful properties. First,
a parent room is a bit like the Master Room. It is treated as "global"
by objects which are zoned to it. If you are in a room zoned to a
parent room, you can use exits in that parent room. You can also
use $-commands defined on objects placed in the parent room.
 
This essentially allows you to create small areas on the MUSH
with their own local "global" commands and exits, without cluttering
up the Master Room. Since local commands take precedence over global
ones, you don't have to worry about global commands interfering with
your local parent room ones.
 
Unless you want to use parent room exits, you should use
object zones. Object zones are faster, and cause less overhead for the
server to worry about; this is an important consideration if the
MUSH is big.
 
& 11.3
11.3      ZoneMaster players
One final type of zone control is possible, using a player with
the ZONE flag set. Such players, called ZoneMasters, behave like ordinary
players, but any object that they own is controlled by whomever passes
the ZoneMaster's enter lock. For convenience, objects which pass the
ZoneMaster's enter lock are referred to here as "zone controllers".
 
Zone controllers are able to @chown objects to the ZoneMaster.
However, such objects count against the original owner's quota, and the
object's creation cost remains charged to the original owner, not to the
ZoneMaster. This enables quotas to be set on individual players, while
still allowing a "builder character" to own all the objects.
 

The ZoneMaster is more secure than a ZMO, since INHERIT objects
may be placed within the zone without any abnormal danger; since all
objects within the zone have the same owner, there is no danger of having
one's unzoned objects @forced through a security hole. Unlike a standard
ZMO, however, the ZoneMaster does not act as a master object; $commands
are not inherited off it.
 
(Continued in 'man 11.3.2'.)
 
& 11.3.2
Note that this is different from standard zoning in that the
"zoned" objects are actually owned by the ZoneMaster; thus, it is possible
to use @chzone to place the object in yet another zone, for the purpose
of inherit $commands, and so forth.
 
& 11.4
11.4      Local wizard control
It is possible, through use of zones, to have "local wizards".
This is accomplished by @chzone'ing all players that you want the
local wiz to control, to a ZMO (or parent room; ZMO will be used in
this discussion to refer to both). This ZMO should be @elock'ed to
just that local wiz. That player will then have control over all objects
created by players in that zone. Unlike a real wizard, however, he may
not @force players.
 
This may or may not be desirable, depending on your philosophy
of administration (assuming you are a god). Local wizards have almost
all the powers of normal wizards, without the accountability and expected
responsibility of full wizards. Although certain systems, such as MUSE,
have used player ranks in a way similar to local wizards, they do not
give such complete control to non-wizard (or wizard-equivalent) players.
 
It is the recommendation of this writer that local wizard
control only be used if the MUSH is extremely large, and organized into
big, but mostly self-contained, groups which require an administrator who
must be able to control the objects of his underlings.
 
& 12
12.       The Fundamental Laws of Wizarding
 

The section below comes from a "lecture" that I've given new
wizards on MUSHes that I'm a "senior" wizard on. I've had several requests
for it in printed form, so it appears here, as kind of a summary to this
section of the manual. It summarizes rules for wizard conduct, and gives
a nutshell guide to wizard commands. The full lecture is available via
ftp from the same site where you obtained this manual; it will probably
be called "wiz-ethics" or something similar. All administrators are highly
encouraged to read the full lecture; this manual only hits the highlights.
 
& 12.1
12.1      Wizard Etiquette
 
There are three things that players REALLY hate, and which
generally constitute abuse of wizard powers. The first is @forcing a player
to do something. There's really never a reason to do this. You can almost
always duplicate the effect of a command that a player issues by just
doing it yourself. Forcing a player to say or pose something is obviously
unethical. Forcing a player's objects is also generally a bad idea.
 
Always ask permission before @teleporting a player, or teleporting to
a non-public location, even if the location is JUMP_OK. The first is
just courtesy; the only reason to ever teleport a player is if he
refuses to come of his own free will. It has the potential to mess up
some command the player is trying to execute; waiting a moment or two
for the player to come on his own isn't going to kill you. Following
the second rule will prevent you from teleporting into potentially
embarrassing situations. Just because someone is paging you doesn't
mean that he necessarily wants to talk to you in person.
 
(Continued in 'man 12.1.1'.)
 
& 12.1.1
Don't wander around DARK. If you're going to hang around dark because
you don't want people bothering you, stay in one of your rooms.  If
you encounter another player, announce your presence. The same thing
applies to puppets who are DARK. Some people believe that the best way
to handle player discipline is to teleport to their location, DARK,
and spy on them. This is a breach of ethics, in most cases. Unless you
believe that players are deliberately conspiring to destroy the MUSH,
do not use DARK for anything other than hanging around without getting
bothered by player pages.
 
Two other brief points: don't examine private objects unless you need
to, and ESPECIALLY, do not use wizard powers to take code or code
segments without permission. In addition, never, ever, wiz while
intoxicated!  Your judgement isn't steady, and you are also very
likely to accidentally mistype a command and cause some sort of minor
(or major) disaster.
 
& 12.2
12.2       The Five-Step Method of Player Management
 
If a player is behaving inappropriately, start with warnings and move
up to more direct action. The exception are spammers and those who are
being destructive towards the database; @boot and/or @destroy those
players immediately.
 
For players who are simply being obnoxious, breaking some of the MUSH
rules, etc., page them and politely tell them that their behavior is
unacceptable. If they don't respond to this "nice" warning within five
or ten minutes, page them again with a more strongly worded warning.
If they continue to misbehave, try a threat: "Do that one more time
and you're going to be @booted."  The next thing to try, if the twink
is being stubborn, is setting the twink GAG. Most people will
disconnect of their own accord if they're gagged. For really
obnoxious, stubborn people, you can then resort to @boot. If the twink
returns, do a @newpassword. Note that if you are planning on doing a
@newpassword to lock out a twink, you should @newpassword _before_ you
@boot, since otherwise, the player can log right back in before you
have a chance to type the @newpassword command.
 
(Continued in 'man 12.2.1'.)
 
& 12.2.1
The reason for using @newpassword instead of @toad or @destroy is that
@newpassword is reversible. You should never use @toad or @destroy on
a player who owns stuff; that is a decision for God to make. Just do a
@newpassword and send mail to the other wizards.
 
   Summary:
      1. Nice warning
      2. Not nice warning / threat
      3. Gag
      4. Boot
      5. Newpassword
 
& 12.3
12.3       When to use wiz commands
 
@allhalt:  This is an emergency-only command. It will halt all commands on
           all objects, and clears out the wait queue. If there are any
           objects which need to run continuously, this command should be
           used as a last resort. Try to be considerate and retrigger objects
           that need to run continuously, if you do an allhalt.
@boot:     Never @boot without a good reason. If a player is on twice and
           he can't kill one of his connections, he will generally page you
           and ask for a @boot; don't do one unless he gives you permission.
           The other use for @boot is detailed in the previous section.
@chownall: Never, ever, do one of these without the explicit permissions of
           both of the parties involved. It's not a bad idea to send mail
           to God (or at least make sure he knows) if you do one of these.
@dbck:     The @dbck command is used to force a database consistency check.
           All GOING objects get recycled. Unless you know what you're
           doing, there's no real point to doing one.
@purge:    This checks the destroyed object list for corruption. It's
           normally done as part of a @dbck.
 
(Continued in 'man 12.3.1'.)
 
& 12.3.1
@dump:     In 1.x, you don't want to do overlapping dumps. If you don't
           have FORK enabled, you want to shout before doing one, because
           it will probably cause quite a bit of lag. Otherwise, @wizwall
           that you're doing a dump, so the other wizards know not to do
           one right after you do.
@login:    You can turn MUSH logins on and off with this command. Unless
           you've got some kind of emergency which necessitates locking out
           all players, don't use this. More importantly, don't forget to
           turn logins back on after the emergency is over.
@daytime:  This turns on or off computationally expensive commands. God
           generally makes the decision when these commands should be
           enabled. Turning them off when they should be turned on probably
           won't hurt anything, but turning them on when they need to be
           off has the potential to get God very upset with you.
           Only 1.50 has this command.
 
(Continued in 'man 12.3.2'.)
 
& 12.3.2
@shutdown: In general, only wizards with access to the MUSH account should
           do @shutdowns, so they can bring the MUSH back up afterwards.
           The exception is if the MUSH is not autorestarted, and needs to
           be taken down for a machine reboot or something similar.
           If the database has somehow been corrupted, a @shutdown may or
           may not be a good idea -- this command automatically does a
           @dump, and you might be making your problem semi-permanent.
           When in doubt, contact God; to shut down the game without doing
           a @dump, use @shutdown/abort.
 

The most important thing to remember: USE COMMON SENSE.
 
------
 
That's it for wizard commands and advice.
Comments, corrections, and suggestions should be emailed to Amberyl,
at lwl@godlike.com
 

 

&V
MUSH Manual Version 2.008:
   Copyright 1993, 1994, 1995, Lydia Leong (lwl@godlike.com / Amberyl)
   Last revised 5/22/95.
 
Section V: The Art of Psychocoding
 
13. Basic Concepts
  13.1  Attribute naming and coding style
  13.2  String concatenation and the switchless style
  13.3  What the parser really does
  13.4  Zones in TinyMUSH 2.2
14. Tricks of the Trade
  14.1  Adding to, removing from, and comparing lists
  14.2  Function building blocks: U() and SWITCH(), DEFAULT(), @function
  14.3  Formatting strings: SPACE(), REPEAT(), LJUST(), and RJUST()
  14.4  Lists instead of @dolists: ITER() and FILTER()
  14.5  Recursion: theory and practice, FOLD()
15. Efficiency
  15.1  Parameter passing: U(), ULOCAL(), local registers, SETQ(), and R()
 
(Continued in 'man V1'.)
 
&V1
  15.2  How the queue works
  15.3  Pipelining
  15.4  Queue cycles vs. CPU cycles
 

Unlike the rest of this MUSH manual, this section is intended for
the programmer who already has some experience coding MUSH. Nonetheless,
newcomers to MUSH might find it helpful to scan through this section,
especially the "Basic Concepts". Familiarity with MUSH terminology,
major commands, and important functions is assumed.
 
It is suggested that the reader be on-line while reading this manual,
with access to the help text for the various functions and the ability
to test out anything which doesn't seem clear. Some of the functions
(Continued in 'man V2'.)
 
&V2
are not explained in gory syntactic detail, since the help text does
exactly that; the purpose of this manual is to provide information
that is not found in the help, and, thus, concentrates on style,
techniques, and quirks that are not immediately obvious.
 

---------------------------------------------------------------------------
 
& 13
13. Basic Concepts
 
& 13.1
13.1    Attribute naming and coding style
 
A user of MUSH once complained that most MUSH code "looks like
line noise".  It's quite possible to write totally unreadable MUSH code;
even with the introduction of the "@@" comment, almost nobody ever comments
their MUSH code, either via "@@" or via attributes which explain what the
object is supposed to do and how it does it. Code that is already difficult
to fathom is made even more incomprehensible by semi-random naming of
attributes and lack of whitespace.
 
* * * * *
 
Attributes should be named intelligently and consistently. One
useful naming convention is to call any attribute which contains a $command
DO_<name of command>; for example, an attribute with a "scan" command
might be called DO_SCAN. Any attributes triggered by that command
would be called SCAN1, SCAN2, etc.  Some people may prefer to place
the $command in SCAN0; this makes it simple to see everything $scan
related by doing an "examine object/SCAN*".
 
(Continued in 'man 13.1.1'.)
 
& 13.1.1
User-defined functions used by the $scan command might be named
as SCAN_<descriptive name>_FN, such as "SCAN_FLAGS_FN".  Temporary
registers set by $scan might be called SCAN_<descriptive name>_TEMP.
The general description of how $scan works could be called SCAN_COMMENT,
and the "help" for it would logically be named SCAN_HELP.
 
A recommended naming scheme for constants is to make their names
based on what the attributes contain; a DBREF suffix indicates a dbref
number, a NAME suffix indicates a name, and a NUM prefix indicates a
counter of some sort.
 
* * * * *
 
Liberal use of whitespace is also encouraged. Whenever possible,
leave spaces; a space should be left before the opening brace of an action
list associated with a @switch, after the ':' separating a $command from
its associated action list, after the commas in arguments to functions,
around the '=' sign between command arguments, and every other place spaces
can be left without affecting command evaluation.
 
(Continued in 'man 13.1.2'.)
 
& 13.1.2
Practicing a good coding style also helps. Actions associated with
a @switch should be enclosed in curly braces, as should each group of
parameters passed to a @trigger. Action lists for @dolist, @wait, and other
similar commands should also be enclosed in curly braces. Even if there is
only a single action, the braces make it very clear what commands or
parameters are associated with each other.
 
* * * * *
 
Certain small things speed up evaluation. For example, whenever
possible, use '%0', '%N', and other percent substitutions instead of
'[v(0)]', '[v(N)]' and similar v-function equivalents. The percent
evaluations are faster; the only time when the v-function equivalents are
needed is when explicit string concatenation is required. Similarly,
the percent-substitution '%b' is much faster than '[space(1)]'.
 
(Continued in 'man 13.1.3'.)
 
& 13.1.3
When possible, use "%#" instead of "%N" or "*%N". This removes
one layer of name-matching when hunting for the object you are trying
to reference, and also guarantees that you will get the enactor, and not
merely something with the same name as it. Also, in 2.0, and, to a lesser
extent, in 1.50, objects do not check the name of their container when
trying to name-match. Furthermore, for objects holding global commands,
a match on a name %N will fail if the enactor is not nearby. The match
for the dbref %#, on the other hand, will always work, no matter where
the enactor is located.
 
Avoid excessive use of the [] bracket grouping with functions.
Unless you are forcing immediate evaluation of an expression for the
purposes of string concatenation, only one set of brackets is needed
around the entire function. If the function is the only argument to a
command, the brackets are not even needed - "@pemit %#=[v(string)]" is
the equivalent to "@pemit %#=v(string)". In the interests of readability,
however, it is advisable to use the bracket delimiters around groups
of functions within a large, complex function call; this is especially
true within lengthy SWITCH() or ITER() evaluations.
 
& 13.2
13.2    String concatenation and the switchless style
 
The increasingly popular "switchless style" of programming eschews
the actual @switch command in favor of using function evaluations to
generate a word. The object is then @forced to execute the contents of
the attribute named by that word. A broader definition of the switchless
style includes the entire concept of using complex function evaluations to
replace nested @switches and similar control structures. This cuts down
on the total number of queue cycles needed to execute a complex program.
 
The switchless style relies very heavily on string concatenation.
This can be accomplished by using the square brackets to force immediate
evaluation of the expression within the brackets. 1.50 also provides the
STRCAT() function, which explicitly concatenates strings.
 
* * * * *
 
(Continued in 'man 13.2.1'.)
 
& 13.2.1
For example, suppose we create a "cat" object. We want to define
a $command, "pet cat", on it, which causes the cat to give the person one
of several random messages. This is quite simple to code in the standard
style:
 
 &DO_PET_CAT cat = $pet cat: @switch rand(3)=
               0, {@emit The cat purrs when %N pets her.},
               1, {@emit The kitty blinks at %N.},
               2, {@emit The cat arches her back and hisses at %N.}
 
The switchless style method would be:
 
 &DO_PET_CAT cat=$pet cat: @emit [s(v(PETMSG[rand(3)]))]
 &PETMSG0 cat=The cat purrs when %N pets her.
 &PETMSG1 cat=The kitty blinks at %N.
 &PETMSSG2 cat=The cat arches her back and hisses at %N.
 
The brackets around the 'rand(3)' forces that evaluation to be done
immediately; the result is then concatenated with PETMSG. Thus, if
rand(3) is 1, we evaluate "[s(v(PETMSG1))]".
 
(Continued in 'man 13.2.2'.)
 
& 13.2.2
This method of picking a message is very useful. If we decide
we want ten messages instead of three, we merely use @edit on the
DO_PET_CAT attribute, and change 3 to 10. Then, we can add seven more
PETMSG attributes.
 
* * * * *
 
The switchless style generally works by selecting among attributes.
Attributes used for switchless programming frequently have names ending
in a number, since it's generally easier to use MUSH to generate a number
than a name. Frequently the number will be 0 or 1, since boolean functions
like AND(), OR(), and NOT() evaluate to 0 or 1.
 
A broader definition of "switchless" programming is discussed
later in this manual, in the section concerning SWITCH(). Note that it
is difficult to program "truly" switchless objects; generally, it is
neither convenient nor desirable to do so. Instead, the aim of switchless
programming is to reduce the number of queue cycles needed through
indirect selection on a string.
 
(Continued in 'man 13.2.3'.)
 
& 13.2.3
Note that because the switchless style makes heavy use of functions,
it may use a large amount of CPU time without using many queue cycles. The
queue cycles-CPU time tradeoff will be discussed later in this manual.
 
& 13.3
13.3    What the parser really does
 
Many MUSH programmers are curious about exactly what the parser does.
A large number of programmers who are not familiar with MUSH internals like
to say, "The parser is consistent."  Throw away that notion. It's wrong.
The parser is far from consistent. Various commands have their own little
quirky ways of being parsed. Even certain functions handle their arguments
differently. To the user, however, it should _appear_ that all things are
parsed the same way.
 
Most MUSH commands take one of three forms:
 
1. <command> <argument>
2. <command> <argument 1> = <argument 2>
3. <command> <argument> = <argv 1>, <argv 2>, <argv 3>, ...
 
(Continued in 'man 13.3.1'.)
 
& 13.3.1
In most cases, the MUSH figures out what command you want, and
then figures out how to parse the rest of the string you typed. Most
of the time, arguments are run directly through the parser and the
results handed to the command handler. There are several major exceptions
to this. The most notable of these are @switch and @dolist. In @switch,
he first argument (the variable to switch on) is evaluated; the comma-
separated arguments are not. @switch evaluates these arguments as needed.
For the @dolist command, the first argument (the list to use) is evaluated
immediately. Then, a find-and-replace is done on the second argument,
sequentially replacing the "##" token with elements of the list. The final
result of such substitutions is then passed to the evaluator.
 
* * * * *
 
The MUSH parser evaluates expressions recursively. The main
server routine to do this is called 'exec'; from this point on, the
expression "the string is exec'ed" will be used to refer to the
evaluation of the string by the parser.
 
(Continued in 'man 13.3.2'.)
 
& 13.3.2
Most uses of square brackets force another call to exec.
Also, every argument to a function is passed through exec, as are the
arguments of most commands.
 
Let's take a look at our cat example above. If we type "pet cat",
the object attempts to execute "@emit [s(v(PETMSG[rand(3)]))]".
The server goes through the following:
 
1. It looks up "@emit" in the command table. The server discovers that
   this command takes one argument, which is evaluated. It thus
   passes "[s(v(PETMSG[rand(3)]))]" to exec.
2. exec attempts to evaluate that string. It sees the brackets, and
   invokes exec a second time, with the brackets stripped, so we
   are now evaluating "s(v(PETMSG[rand(3)]))"
3. s() is a function, so exec is called yet another time to evaluate
   the argument to s(). We now need to evaluate "v(PETMSG[rand(3)])"
4. v() is also a function, so we call exec on its argument. We are
   thus left with "PETMSG[rand(3)]"
(Continued in 'man 13.3.3'.)
 
& 13.3.3
5. exec scans that string until it sees the pair of brackets. It then
   invokes yet another exec call to evaluate the contents of the
   brackets. We now evaluate "rand(3)".
6. Because rand() is a function, we once more invoke exec, on "3".
7. "3" is just a string literal, so exec returns "3".
8. Having figured out the arguments to rand(), we evaluate it.
   Let's say "rand(3)" is equal to "0".
9. This expression is then concatenated with "PETMSG", giving us
   the string "PETMSG0". This is our argument to v(). Now that we
   have our argument, we evaluate "v(PETMSG0)", giving us,
   "The cat purrs when %N pets her."
10. We now pass this to s(). "s(The cat purrs when %N pets her.)"
    evaluates to "The cat purrs when Amberyl pets her."  (assuming
    Amberyl is the enactor). Note that because we used '%N' rather
    than '[v(N)]', no additional execs are required to get the
    name of the enactor. (If we used '[v(N)]', two additional exec
    calls would be required: one to strip the brackets, and one to
    evaluate the argument to V(). Thus, you can see that it's quite
    a bit more efficient to use '%N'.)
 
(Continued in 'man 13.3.4'.)
 
& 13.3.4
11. This string is passed to the command handler for @emit, which
    shows it to the appropriate people.
 
Notice how many evaluations such a simple string can need!
When coding, it is important to think not just about how many
queue cycles something uses; most functions must evaluate all their
arguments, and the computation time taken to do this eventually
adds up. Although this is usually on the order of milliseconds,
the actual cumulative delay, on a MUSH running on a busy machine,
can add up to a significant amount of time.
 
* * * * *
 
One important effect of functions evaluating their arguments first
before executing the function is that attempts to turn space-separated
lists into comma-separated lists for functions frequently fail. For
example, MAX(v(LIST), 25), where LIST is "1, 10, 83, 4"  causes the
game to find the MAX of "1, 10, 83, 4" (which the string-to-integer
conversion functions trims simply to "1") and "25", thus causing the
function to return "25", rather than "83", which is what one might
have expected it to return.
 
(Continued in 'man 13.3.5'.)
 
& 13.3.5
Similarly, using a LIST of "1 10 83 4" and then evaluating an
expression such as "MAX([iter(v(LIST),{##,})] 25)" doesn't work.  The
ITER() generates the list "1, 10, 83, 4," but this is NOT equivalent
to "MAX(1, 10, 83, 4, 25)"; the erroneous use of ITER() instead causes
MAX() to look for the maximum of "1, 10, 83, 4," (which turns into "1")
and "25". There are several ways of getting around this; see the
discussions on ITER() and FOLD() for examples.
 
* * * * *
 
Two important functions do not immediately evaluate their arguments.
ITER() and SWITCH() only evaluate their arguments when the arguments
are needed. ITER() does a brute force find-and-replace for "##" on its
second argument, much like @dolist does; to avoid needing odd
combinations of escapes in the second argument, none of the arguments
are evaluated until the ITER() function actually uses them. Because
SWITCH() calls can be massive, only those arguments which must be
evaluated will be evaluated. This is important to keep in mind if you
are using functions with side-effects, such as 1.50's create().
 
(Continued in 'man 13.3.6'.)
 
& 13.3.6
Note that if you are making multiple identical calls to functions,
all the calls are evaluated _separately_; the MUSH does _not_ know that
it has evaluated that expression before. This is definitely something to
remember, if you use functions like U() to evaluate huge complex expressions.
By the same logic, "@pemit me=add(rand(3),rand(3))" does NOT return the same
value for those two rand() calls. Ways of avoiding multiple identical
function calls will be discussed later in this manual.
 
Finally, note that the UNIX random-number generator is very poor, and
for small values of N, often returns the same value several times in a
row, even if the overall distribution over, for example, 1000 trials,
is evenly apportioned. If, for some reason, it is important that your
numbers be "more random", you may want to try a method such as using
a very large value of N, and then using a MOD() call to bring it into
the appropriate range. For example, to generate a number from 0 to 9,
one can use "rand(10)"; however, one will get a better random distribution
via "mod(rand(1000),10)".
 
& 13.4
13.4    Zones in TinyMUSH 2.2
 
Zones in TinyMUSH 2.2 are somewhat different from PennMUSH 1.50 Zones,
and therefore deserve a separate explanation. This section only applies
if Zones are permitted by the MUSH's configuration.
 
If you are standing in a room, type a command which is not matched by
an exit, or locally, or internally, and the parent of your current
room is set ZONE, all objects inside that parent will be checked for
$commands, just as if that parent object were the Global Master Room.
 
If there are no command matches, then if the parent of that parent is
also ZONE, objects in it will be checked. This goes on until something
is matched, or the parent is no longer set ZONE.
 
If there are still no matches, the same process is repeated, starting
from your own parent object, if it's ZONE.
 
If still nothing is matched, command checking proceeds to the Global
Master room.
 
(Continued in 'man 13.4.1'.)
 
& 13.4.1
* * * * *
 
Essentially, what this means is that the ZONE chain creates a chain of
Local Master Rooms. They provides a great deal of power and
flexibility that normal parent rooms don't provide; they confer all
the benefits of normal parenting, in addition to this specialized form
of command-checking.
 
Commands matched via zone checks are executed by the objects which
contain the commands, NOT by the room or player itself. Therefore,
this method is extremely useful for permitting players other than
the Builder Character (or generic area owner) to execute commands for
a given area. It also alleviates the necessity of setting all rooms
in the area INHERIT, if a certain local command requires INHERIT.
 
(Continued in 'man 13.4.2'.)
 
& 13.4.2
Because the ZONE chain is essentially a chain of Master Rooms, the
same caveats which apply to Master Room programming apply to objects
in these chains. Objects in the rooms should have a minimal number of
attributes on them. Because the parents of objects in the rooms are not
checked for $commands, @parent'ing such objects to a data object will
reduce the checks needed without significantly altering the programming
style for such an object.
 
Security, of course, is important -- ZONE chains should be isolated,
and unauthorized players should be prevented from gaining access to
them.
 

---------------------------------------------------------------------------
 
& 14
14.     Tricks of the Trade
 
& 14.1
14.1    Adding to, removing from, and comparing lists
 
Lists are the heart and soul of MUSH. Earlier in this manual,
ways of finding certain items within a list, adding to lists, and removing
from lists were discussed.
 
The standard list-operation functions fare poorly when there are
items in the list which are identical. In particular, we often want to
avoid adding items to a list which are already in it, get the result of
merging two lists, and remove items from a list without destroying the
spacing of the list.
 
The REMOVE() function generally leaves an extra space in the list.  We
can get around this problem by passing the results of a REMOVE() call
to S(); indeed, this method of forcing another round of pronoun
substitution is useful for compressing undesired spaces. The SQUISH()
function removes extra spaces, and is useful when a second round of
evaluation is not desirable. Thus, REMOVE() is adequate for most of
the times we wish to remove an item from a list.
 
(Continued in 'man 14.1.1'.)
 
& 14.1.1
* * * * *
 
The SETDIFF() function provides a better way to remove items from
a list. SETDIFF(<list 1>,<list 2>) removes from <list 1> all items that are
in <list 2>. It can also be thought of as returning all the elements of
<list 1> that aren't in <list 2>. This is useful when you want to guarantee
that you have removed every occurrence of an item; objects like communicator
systems are best programmed like this.
 
The SETUNION() function is useful for adding an element (or elements)
to a list. It merges two lists, removing duplicates. Like SETDIFF(), this
function is useful when you want to guarantee that you have no duplicates;
in a communicator system, this is especially important.
 
The SETINTER() function returns the elements that are in both lists.
This is also for use in merging lists; elements that are only in one list
get eliminated. This is also useful for telling if all elements of one
list are in another; evaluate the SETINTER() of the two lists, and COMP()
it to the list you are interested in.
 
(Continued in 'man 14.1.2'.)
 
& 14.1.2
* * * * *
 
One interesting example problem in list manipulation is the removal of
a specific element by its position. This is a problem encountered when
it is not possible to use REMOVE(), which removes the first instance of
an elements by name, or SETDIFF(), which removes all occurrences of the
elements, also by name. For example, if we keep two attributes on an
object, one with the names of dragons, and the other with the colors of
those dragons, and we want to remove one of the dragons from both lists,
we encounter this problem; while names in the first list should be unique,
many of the words in the second list will not be (we will probably have
many Blue dragons, for example.)
 
If our list of dragon names is in the attribute NAMES and the
corresponding colors list is in the attribute COLORS, we can delete,
given a dragon name, its corresponding color from the colors list by
using EXTRACT() to return all words before that position, and all
words after that position. We determine the position using the MEMBER
function, as per the standard list-matching routine described earlier
in this manual. The code is thus:
(Continued in 'man 14.1.3'.)
 
& 14.1.3
 &COLORS object=[extract(v(colors), 1, sub(member(v(names),%0),1))]
         [extract(v(colors), add(member(v(names),%0),1), words(v(colors)))]
 
Once we've deleted the color from the colors list, we can safely use REMOVE()
or SETDIFF() to remove the dragon name from the names list.
 
* * * * *
 
The above problem can be more easily solved by the judicious application
of a built-in function callled LDELETE(), which deletes an element from
from a list, given the element position to delete.
 
LDELETE() has two brethren functions, called INSERT() and REPLACE(),
which take the arguments <list>, <pos>, <word>. The first function
inserts <word> into <pos> of <list>, and the second function replaces
<pos> element of <list> with <word>.
 
All three of these functions should be used instead of clumsy EXTRACT()
manipulations of the type described above.
 
& 14.2
14.2    Function building blocks
 
Two functions form the core of switchless programming: U()
and SWITCH(). The first (also known as UFUN() in 1.50) allows the
MUSH programmer to define, in a limited sense, his own functions,
while the latter pattern-matches a string against a list of other
strings, and, instead of triggering an action, as does @switch
command, the SWITCH() function simply returns a string.
 
U() takes up to ten arguments. The first argument is an
attribute, which specifies where to look for the function definition.
This argument can be a name, or it can be an object/attribute pair.
The remaining arguments to U() are parameters to be passed on the
stack (i.e. as %0 - %9). Thus, stack parameters to a U() evaluation
are purely local - they are not at all related to the value of the
"global" stack. A evaluation like "u(FOO_FN, bunch, of, words)" would
pass "bunch" as %0, "of" as %1, and "words" as %2. Then, the contents
of FOO_FN would be evaluated with those values. For example:
(Continued in 'man 14.2.1'.)
 
& 14.2.1
> &TEST me=%0 has [strlen(%0)] characters and [words(%0)] words. %1!
> "[u(TEST, Test string, Neat)]
You say, "Test string has 11 characters and 2 words. Neat!"
 
In this example, %0 is "Test string", and %1 is "Neat". Note that
those values are only true within TEST, though. For example, values
passed by @trigger are unchanged:
 
> &TEST me=%0 has [words(%0)] words.
> &ACT me=say %0 %1 %2 - [u(TEST,%1)] - %0
> @trigger me/act={a 1}, {b 2 3}, {c 4 5 6}
You say, "a 1 b 2 3 c 4 5 6 - b 2 3 has 3 words - a 1
 
>From the @trigger, %0 is "a 1", %1 is "b 2 3", and %2 is "c 4 5 6".
In the TEST evaluation, %0 is "b 2 3", since that was the parameter
passed to it. But when we return to evaluating the output of the
@trigger, %0 is still "a 1"; the value of %0 in the U() evaluation
of TEST does not change the real value of %0.
 
(Continued in 'man 14.2.2'.)
 
& 14.2.2
* * * * *
 
1.50 and 2.0 handle U() evaluation differently; 1.50's GET_EVAL() is
basically identical to its U(). For the differences between 2.0's
GET_EVAL() and U(), see the earlier section of the manual on GET().
 
The only other difference between 1.50 and 2.0's U() is that
1.50 does not force immediate evaluation of a U() unless it is surrounded
by square brackets. In other words, in 1.50, "&FOO_FN object=strlen(%0)"
and "&FOO_FN object=[strlen(%0)]" are handled differently - without the
brackets, the game does a local evaluation and substitution, and pastes
that in, instead of forcing an immediate evaluation. For example:
 
> &TEST1 me=strlen(%0)
> &TEST2 me=[strlen(%0)]
> "Test1: -[u(TEST1,foo)]- Test2: -[u(TEST2,foo)]
You say, "Test1 -strlen(foo)- Test2: -3-"
(Continued in 'man 14.2.3'.)
 
& 14.2.3
The programmer is allowed slightly more flexibility when immediate
evaluation is not forced. In general, it is good programming practice
to put square brackets around the functions contained in an attribute
called by U().
 
* * * * *
 
The U() function is usually used to clean up code which would
otherwise be horrendously complicated and unclear. Also, because the
parameters passed to U() are only evaluated once, if you need to evaluate
an expression which utilizes a complex expression several times, you
can simply make that complex expression a parameter to U(). This method
of using U() is detailed later in the manual, in the section dealing
with efficiency.
 
(Continued in 'man 14.2.4'.)
 
& 14.2.4
A general rule of thumb of putting an expression in a U() is,
"If you use it more than once, and it contains more than two or three
nested functions, or it is more than 70 characters (one line) long,
make it a U()."   The 70-character rule has its exceptions, but
anything you can't type without using emacs or some other kind of
parentheses/brackets-matcher is Too Long and should go into a U()
attribute by itself.
 
* * * * *
 
U() is often used for permission checks on objects. For example,
a bulletin board might only permit the original poster of a message to
delete it. In the future, however, you might wish to allow wizards to
also delete messages. Rather than having to scan through all the bulletin
board code, it'd be simpler just to change a single U() function. Thus,
when writing the board code, it'd be good to call something like
OK_TO_DELETE_FN, even if the check for permission to delete is simple.
As long as you keep the parameter list the same, you shouldn't have any
trouble swapping in a new OK_TO_DELETE_FN should you ever change your
mind about who is allowed to delete messages.
 
(Continued in 'man 14.2.5'.)
 
& 14.2.5
* * * * *
 
"Switchless programming" is a bit of a misnomer; this style
frequently involves the SWITCH() function, although it generally
avoids the @switch command. The SWITCH() function is quite similar
in format to @switch, but instead of performing a command list based
on matching a string pattern, it returns another string. It is as
flexible of a pattern-matcher as @switch, taking the '*' and '?'
wildcard characters. The obvious use for this function is turning
one string into another string; if there is more than one match
possible, SWITCH() returns the first one. SWITCH() does not evaluate
its arguments until it needs to; therefore, if you have side-effect
functions within a SWITCH(), such as 1.50's CREATE(), remember that
they will not get evaluated unless the corresponding pattern is
matched.
 
(Continued in 'man 14.2.6'.)
 
& 14.2.6
When combined with U(), SWITCH() is an extremely powerful
tool. One common application of this combination is to return boolean
values (0 or 1) based on some string. The most frequently used
example of this is HASATTRIB - the determination of whether or not
an attribute exists on a certain object. If the attribute exists,
it evaluates to 1; if not, it evaluates to 0. The code for this is
simple:  &HASATTRIB_FN object=[switch(get(%0/%1),,0,1)]
It is then called via [u(HASATTRIB,object,attribute)]. If the
GET() returns nothing, then there's no such attribute, and the
evaluation is 0. Otherwise, it's 1.
 
Boolean returns can be extraordinarily useful in conjunction with
SETQ() and R(). For example, if you want to print out a '+' for
every time a function returns 1, and a '-' when the function returns
0, you can do a '[setq(0,-)][setq(1,+)]' and then print out
'[r(u(COMPLEX_FUNCTION))]' instead of continually SWITCH()ing
for the string to print.
 
(Continued in 'man 14.2.7'.)
 
& 14.2.7
* * * * *
 
Note that one common use of SWITCH() -- returning a value if a
certain attribute does not exist -- is made unnecessary by the
addition of the functions DEFAULT(), EDEFAULT(), and UDEFAULT(),
in TinyMUSH 2.2. These functions take the basic syntax:
function([<object>/]<attribute>, <default>[,<parameters for U()>])
 
Instead of writing the following:
 
[switch(v(TEST),,No test string.,v(TEST))]
[switch(get(#10/TEST),,No test string.,get_eval(#10/TEST))]
[switch(v(TEST),,No test string.,u(TEST,%#))]
 
one could write, respectively:
 
[default(TEST,No test string.)]
[edefault(#10/TEST,No test string.)]
[udefault(TEST,No test string.,%#)]
 
(Continued in 'man 14.2.8'.)
 
& 14.2.8
This elimination of the extra attribute retrieval is valuable, and
the lack of a SWITCH() removes the need to do any sort of wildcard
pattern match.
 
                        ----------
 
SWITCH() can be used to entirely eliminate a @switch. For
example, here's a typical lengthy @switch construction:
 
@switch v(num)=0,@emit [v(apple)],1,@emit [v(apple)],2,@emit [v(apple)],
        3,@emit [v(apple)],4,@emit [v(apple)],5,@emit [v(pear)],6,
        @emit [v(orange)],7,@emit [v(orange)],@emit [v(cherry)]
 
This can be reduced to:
 
@emit [v([switch([and(gte(v(num),0),lte(v(num),4))],1,apple,
        [switch(v(num),5,pear,6,orange,7,orange,cherry)])])]
 
(Continued in 'man 14.2.9'.)
 
& 14.2.9
This has the advantage of reducing the extra queue cycle involved in
the @switch. It isn't quite as easy to read as the @switch statement,
initially, but with practice, switchless-style coding becomes just as
simple to follow. (Note that extra brackets have been added in the
example above in order to make it easier to read.)
 
The repeated calls of 'v(num)' are inefficient. A better method follows
below; this time, the extra brackets have been left out.
 
@emit [setq(0,v(num))][v(switch(and(gte(%q0,0),lte(%q0,4)),1,apple,
        switch(%q0,5,pear,6,orange,7,orange,cherry)))]
 
This can be even further compressed by a technique which will be described
in another section; it combines several switch patterns into one.
 
@emit [setq(0,v(num))][v(switch([and(gte(%q0,0),lte(%q0,4))]:%q0,1:*,apple,
        *:5,pear,*:6,orange,*:7,orange,cherry))]
 
* * * * *
 
(Continued in 'man 14.2.10'.)
 
& 14.2.10
There are also variations on this theme, which don't necessarily
eliminate the @switch. For example, if instead of the simple @emit example
above, there were different action lists associated with each value of
the NUM attribute, it would be impossible to eliminate the @switch
efficiently. It would be possible to generate, as a string, the action
list to be run, and then @force the object to do it, but that wouldn't
be any timed gained. Here is a more complex example of a @switch for
which this is true:
 
@switch v(num)=0, {@pemit %#=Success.}, 1, {@pemit %#=Success.},
        2, {@pemit %#=Success.}, 3, {@emit Disaster!}, 4, {@emit Disaster!},
        5, {@tel %#=#100; &victim me=[v(victim)] %#}, {@pemit %#=Failure.}
 
The best approach to something like this is to generate a "code string"
via the SWITCH() function, and then @switch on that code. Usually, this
looks best if done in combination with a U(), but for this example, we'll
simply write it out; just realize that the left hand side of the '=' sign
would probably be best put in a U().
 
(Continued in 'man 14.2.11'.)
 
& 14.2.11
@switch switch([and(gte(v(num),0),lte(v(num),2))],1,OKAY,
                [switch(v(num),3,BAD,4,BAD,5,OTHER)]) =
        OKAY, {@pemit %#=Success.},
        BAD, {@emit Disaster!},
        OTHER, {@tel %#=#100; &victim me=[v(victim)] %#},
        {@pemit %#=Failure.}
 
In this particular case, the switchless code is not an improvement
over the original @switch. However, if we ever want to change what constitues
"okay", "bad", "other", or failure, all we have to change is the expression
on the left hand side of the '='; we don't have to rewrite the entire
command. If it's put in an attribute as a U() instead, this becomes
even easier; we simply need to change that attribute.
 
* * * * *
 
(Continued in 'man 14.2.12'.)
 
& 14.2.12
Here is a variant of the "code string" procedure which does not
use SWITCH(). Instead, it generates several words based on the values
we are interested in switching on, and takes advantage of wildcards.
In this case, the first number generated tests for 0 <= num <= 2,
the second number for num = 3 or num = 4, and for convenience, the value
of num itself as the third word.
 
@switch [and(gte(v(num),0),lte(v(num),2))] [or(eq(v(num),3),eq(v(num),4))]
                [v(num)]=
        1 * *, {@pemit %#=Success.},
        0 1 *, {@emit Disaster!},
        0 0 5, {@tel %#=#100; &victim me=[v(victim)] %#},
        {@pemit %#=Failure.}
 
When using this kind of switch, it is usually safer to use "@switch/first"
(also called "@select") to ensure that we only match the first case that
applies.
 
(Continued in 'man 14.2.13'.)
 
& 14.2.13
The multiple-code-words method is most efficient when used to
eliminate multiple @switch statements. For example, consider the case
of checking valid input for a command which takes the format
"test <four letter word> <player name>". We want to display an
appropriate error message. The simplest way to code this up is:
 
$test * *: @switch [eq(strlen(%0),4)]=0, {@pemit %#=Invalid word.},
        {@switch [num(*%1)]=#-1, {@pemit %#=Invalid player.},
        {@trigger *%1/TEST_ATTRIB}}
 
This costs us extra queue cycles, though, and also doesn't catch the
case of both arguments being incorrect. Using code words, we can fix that:
 
$test * *: @switch/first [eq(strlen(%0),4)] [num(*%1)]=
        0 #-1, {@pemit %#=Invalid word and player.},
        0 *, {@pemit %#=Invalid word.},
        * #-1, {@pemit %#=Invalid player.},
        {@trigger *%1/TEST_ATTRIB}
 
(Continued in 'man 14.2.14'.)
 
& 14.2.14
Note that because we use patterns which are not mutually exclusive
("0 #-1" also matches "0 *" and "* #-1"), we must use @switch/first.
 
* * * * *
 
Other interesting tricks can be done with @trigger and SWITCH().  For
example, in cases where we want to pass a number of complex function
evaluations to a later evaluation, we might want to use a @trigger
instead; if we eliminate the @switch in the process, this turns out to
be the same number of queue cycles, and syntatically neater.
 
Take the following example, based on the notes above. This time,
however, instead of sending the message to %#, we want to send the
message to something defined by the complex black-box user-defined
function called with u(BIG_FN,%#,revwords(%0)) -- too much to type
repeatedly. Thus, we end up with something like:
 
$test *: @trigger me/[u(FOOBLE_FN,%0)]_TRIG=u(BIG_FN,%#,revwords(%0))
 
(Continued in 'man 14.2.15'.)
 
& 14.2.15
We use FOOBLE_FN (whatever that happens to be) to generate the name
of the attribute to trigger, and now we end up writing that parameter
out only once. This technique is particularly useful in extremely
large switch statements which have many cases and long action lists.
 
                        ----------
 
The major reason to write code using U() and SWITCH() isn't
speed, for large projects. It's modularity. If you define some kind
of U() to check permissions to run a command, for example, if you ever
want to change the criteria, all you need to do is to change the
definition of that U(). SWITCH() is also particularly good at reducing
complex expressions that might otherwise require several @switches
by means of the "code strings" method; it's easy to jam multiple
@switch clauses into a single @switch by providing a complicated
SWITCH() to generate a word that can be @switch-cased on. One
should, however, be wary of trying to reduce all code down to the
minimum number of queue cycles; some amount of readability is also
important, as is the amount of "real CPU time" needed to execute
a given MUSH program. This trade-off is discussed in detail later
in this manual.
 
(Continued in 'man 14.2.16'.)
 
& 14.2.16
There are certain functions whose functionality is frequently needed,
but simple enough to code in MUSH that they are not worth hardcoding
into the server. To provide some kind of standardization for these
functions, and to get around the occasionally clumsy U() calling
convention, MUSH provides a mechanism called "@function". It enables
the global definition of a U() as an imitation "real" function. A
Wizard (or, in 1.50, someone with the Functions power) can specify a
name for the function and the place where it can be found, and then
anybody on the MUSH can use it as if it were a built-in function.  The
syntax is: @function <function name>=<object>,<attribute> <function
name> is the name used for the function, and <object> and <attribute>
specify the name of the attribute and the object on which it can be
found. The parameters passed to an invocation of a function defined in
this way are passed as %0 - %9. Therefore, any function normally
called via U() can be defined globally simply by adding it to the
"local global" function table via @function. For example, in 1.50:
 
> &HASATTRIB_FN #10=[switch(get(%0/%1),,0,1)]
> @function hasattrib=#10,hasattrib_fn
(Continued in 'man 14.2.17'.)
 
& 14.2.17
tells the game to add HASATTRIB to the functions table, and to use
the attribute HASATTRIB_FN on object #10 when evaluating that. Then
one could simply do:
  
> @desc me=The writer of the MUSH manual.
> say [hasattrib(me,desc)]
You say, "1"
 
This would be equivalent to "say [u(#10/HASATTRIB_FN,me,desc)]", but is
syntactically much neater, as well as faster. Also, because of the @function,
any player on the MUSH can use HASATTRIB(), even if he can't directly read
the attribute. Thus, players do not have to see the code in order to use
it. If the function were a simple U(), another player would have to be
able to read the attribute - it would either have to be public, set public
via the VISUAL attribute flag, or visible because the object it was on (#10)
was set VISUAL.
 
(Continued in 'man 14.2.18'.)
 
& 14.2.18
Note that the syntax in 2.2 is "@function <function>=<object>/<attribute>".
2.2 also takes the switch "/privileged"; if this is given, the function
is evaluated as if it was performed by the object on which it was stored
(giving players access to information which, for example, might only be
accessible to Wizards under normal circumstances). Otherwise, the function
is evaluated as if it were stored on the invoker.  (Also note that the
above example is somewhat irrelevant in 2.2 -- the HASATTR() function
performs that functionality.)
 
& 14.3
14.3    Formatting Strings
 
A lot of "MUSHtoys" involve the "pretty-printing" of output;
frequently, this means listing output in neat columns. To do this,
one must calculate the number of spaces needed to get to the place where
the next "real" string should start. This can be accomplished in one
of two ways.
 
The most efficient way to do this is to use the RJUST() and LJUST()
functions, which right- and left-justify a string, respectively.  The
first argument to these functions is the string to print, and the
second argument specifies the field width. Strings that are too long
do not get truncated. Both of these functions take an optional third
argument, which specifies the fill character to use; if no third
argument is given, a space is used. Thus, if you want to %0 to start
at column 1, %1 to start at column 20, and %2 to start at column 45,
the expression "[ljust(%0,19)][ljust(%1,24)]%2" will work.
 
(Continued in 'man 14.3.1'.)
 
& 14.3.2
* * * * *
 
In old versions of 2.0, a slightly clumsier method must be used. The SPACE()
function is used to print spaces; you must calculate the number of spaces
to print based on the length of the string you are printing. For the
case above, the equivalent expression, using the SPACE() function, is
"%0[space(sub(19,strlen(%0)))]%1[space(sub(24,strlen(%1)))]%2"
The major problem with printing something in this way concerns recalculation
of the same string. If, for example, you had, instead of %0, %1, and %2,
three large, complex functions, you would have to evaluate those functions
twice, once to actually print it, and once to calculate the length of
the string. For extremely complicated functions, the doubling of this
work may cause a significant loss of speed when the object is used. This
can be avoided by defining RJUST and LJUST as U() functions:
 
 &LJUST_FN object=%0[space(sub(%1,strlen(%0)))]
 &RJUST_FN object=[space(sub(%1,strlen(%0)))]%0
 
The extra overhead of invoking another U() function generally is less
than that of computing a large function evaluation.
 
(Continued in 'man 14.3.3'.)
 
& 14.3.3
Related to the SPACE() function is the REPEAT() function,
which repeats an arbitrary string a given number of times. The
strings are concatenated with each other, without spaces separating
each repetition. It can be used to fake the three-argument version of
LJUST() and RJUST():
 
 &LJUST3_FN object=%0[repeat(%2,sub(%1,strlen(%0)))]
 &RJUST3_FN object=[repeat(%2,sub(%1,strlen(%0)))]%0
 
Generally, though, this function is used for generating long lines of
asterisks, dashes, and other symbols used for ASCII graphics or division
of output into fields.
 
* * * * *
 
One common formatting task is the formatting of poses, says, and the like,
for arbitrary commands. Suppose, for example, that you have a chat system,
which takes a command of the format, "$chat *". You want the following:
(Continued in 'man 14.3.4'.)
 
& 14.3.4
chat Hi!          ==>  Fire says "Hi!"
chat :waves.      ==>  Fire waves.
chat ;'s idling.  ==>  Fire's idling.
 
Assuming that the * is going to end up as %0, and the chatting person's
going to be the enactor, the following works:
 
[switch(%0,:*,%N [delete(%0,0,1)],;*,%N[delete(%0,0,1)],%N says "%0")]
 
Note that we use DELETE() here to remove the first character of the
string, if necessary, instead of using MID() to get everything after
the first character; deleting one character is a lot faster.
 
& 14.4
14.4    Lists instead of @dolists
 
The most powerful list-creation facility available in MUSH is
the ITER() function. ITER() takes two arguments, a space-separated list
of words, and a format string of some sort (which can contain other
functions). The format string is evaluated for each element of the list,
with the "##" token being replaced by the list element. The result is
also a list, with each element separated by a space. The simplest
example of an ITER() is something of the form "[iter(%0,##)]", which
just returns back %0. The most common use of ITER(), however, is turning
a list of dbrefs into a list of names: "[iter(lcon(here),name(##))]"
returns a list of names of the objects in a room.
 
(Continued in 'man 14.4.1'.)
 
& 14.4.1
The mundane uses of ITER() are fairly obvious; it's used to
transform one list into another list. A more sophisticated use of
ITER() is using the function to replace a @dolist-@pemit combination
with a single @pemit and ITER(). This is useful for bulletin board
objects, mailer objects, WHO list formatters, and other mass-output
devices. Because ITER() places a space between each element of the
list returned, to correctly format such a list so that the elements
are returned one per line, a "%r" should be placed at the beginning
of the format string. For example, to return the list of contents
in a room, by name, one to a line, use "[iter(lcon(here),%r[name(##)])]"
The "%r" must come first, not last; otherwise, the output would be
indented by one space.
 
Using @dolist: @pemit %#=You see:; @dolist lcon(here)={@pemit %#=name(##)}
Using ITER():  @pemit %#=You see:[iter(lcon(here),%r[name(##)])]
 
* * * * *
 
(Continued in 'man 14.4.2'.)
 
& 14.4.2
One is frequently interested in obtaining only those members
of a list for which a certain expression is true. For example, the
construction "[iter(v(list),switch(u(FILTER_FN,##),1,##,))]" is quite
common. It means "return all those elements of the list contained in
the attribute LIST, for which FILTER_FN evaluates to 1."
Because this construction is very frequently used, 1.50 provides a
more efficient short form, via the FILTER() function. The first
argument to FILTER() is an attribute or object/attribute pair (just
like U()'s first argument), and the second argument is a list. FILTER()
returns all elements of the list for which the first argument evalutes
to 1. Thus, the equivalent to the expression above would be simply
"[filter(FILTER_FN,v(list))]".
 
* * * * *
 
(Continued in 'man 14.4.3'.)
 
& 14.4.3
ITER() can also be used to solve the MAX() problem from earlier
in this manual -- taking a space-separated list and passing it to a
function as a comma-separated list. The MUSH parser, when it sees a
function evaluation, attempts to evaluate each argument to the function,
using the comma to separate each argument. The problem encountered with
turning the space-separated list to the comma-separated list was that
the comma-separated list was generated _after_ the parser had already
determined where the argument began and ended. Thus, we must delay the
evaluation.
 
We do this by causing the escaping the function, without escaping
its arguments, so that the arguments are evaluated (using ITER() to turn
the space-separated list into a comma-separated list), and then running
the entire thing through the S() function, which causes a second parser
pass. Presuming that the space-separated numeric list is in the LIST
attribute on the object -- LIST was "1 10 83 4" in the earlier example --
and we want to also compare it to the number 25, we end up with the
following:  s(\[MAX([iter(v(LIST),{##,})] 25)\])
 
(Continued in 'man 14.4.4'.)
 
& 14.4.4
The parser reacts in the following manner:  it sees the S()
function, and goes to evaluate the argument inside. The argument inside
evalutes to [MAX(1, 10, 83, 4, 25)] -- the ITER() generates the string
"1, 10, 83, 4, " and concatenated with the 25, generates the above string.
Because of the '\' escapes, MAX is considered a string and not a function;
the '[]'s around the ITER() force that evaluation to complete. Now, the
S() function evaluates [MAX(1, 10, 83, 4, 25)], which is 83, our desired
result.
 
This technique works, in general, for converting any space-separated
list to a comma-separated list to be passed to a function which requires
comma-separated arguments.
 
& 14.5
14.5    Recursion
 
"Recursion" is a difficult term to define; it can be loosely
described as a process by which an expression uses itself to determine
its value. A "recursive function" calls itself, stopping when it reaches
a "base case". This can probably be best illustrative via an example.
 
The mathematical expression "n!" ("n factorial") means the
product of all whole numbers between 1 and n, or, since formal sigma
(summation) notation is difficult to write in pure ASCII, informally
expressed by the formula:    n! = (n)(n - 1)(n - 2)(n - 3)...(1)
For example, 4! = (4)(3)(2)(1) = 24.  One quickly notes, however, that
this is equal to (4)(3!) = (4)(3)(2!) = (4)(3)(2)(1)
Therefore, we can write:   n! = (n)((n - 1)!)
Because the factorial expression is used to determine a factorial,
we can say that the factorial function is recursive.
 
(Continued in 'man 14.5.1'.)
 
& 14.5.1
All recursive expressions must have some kind of base case;
otherwise, the function will continue to evaluate itself forever.
For the factorial function, the base case occurs when n = 1; the
function simply returns 1.
 
* * * * *
 
Recursion can be done quite simply in MUSH, although the built-in
function evaluation limit prevents the "stack" of functions from
growing too large. We can write a U() function to evaluate factorials,
using a SWITCH() to check for the base case:
 
 &FACTORIAL_FN object=[switch(%0,1,1,mul(%0,u(FACTORIAL_FN,sub(%0,1))))]
 
The expression "[u(object/FACTORIAL_FN,4)]" will return "24".
Note that this is a literal translation of the mathematics involved. "If 1,
return 1. Else, multiply our current number by the factorial of our current
number minus 1."  One of the beauties of recursion is that it usually
follows quite naturally from the verbal description of the algorithm.
 
(Continued in 'man 14.5.2'.)
 
& 14.5.2
* * * * *
 
There is a built-in function called FOLD() which is intended for
use in recursion. The first argument to FOLD() is the name of an attribute
which is to be treated as a U(), and the second argument is a list whose
members will be passed one at a time as %1 to the U() evaluation. (Note
that the U() function is not directly involved in the FOLD() operation,
but the attribute is evaluated like a U(), so for convenience's sake, we'll
call it a U() evaluation). If there is no third argument, which could be
called a base case, the first element passed for the first time is given
as %0. Normally, the result of the previous evaluation is passed as %0.
 
To translate our factorial function into FOLD()'s syntax, we need
to generate a list. The obvious method is to generate a list of all numbers
between 1 and n, and multiply them all together. The LNUM() function will
generate all numbers between 0 and n-1, so to get all numbers between
0 and n, we must use LNUM(add(%0,1)). To eliminate that 0, we use the
REST() function.
 
(Continued in 'man 14.5.3'.)
 
& 14.5.3
 &FACTORIAL_FN obj=[fold(FACT_AUX_FN,rest(lnum(add(%0,1))),1)]
 &FACT_AUX_FN obj=[mul(%0,%1)]
 
This is considerably faster than the "pure" recursive method, and has
the additional advantage of not running us up against the function
recursion limit. Under a normal recursion limit, our first try at
writing the factorial function fails when n is greater than 9; using
FOLD(), we don't hit the recursion limit at all, since the nesting
is never more than 3 functions deep (1 is the U() call to FACTORIAL_FN,
2 is the call to FOLD(), and 3 is the call to MUL()).
 
* * * * *
 
(Continued in 'man 14.5.4'.)
 
& 14.5.4
Most people probably don't compute factorials in their daily
MUSHing. A more practical application of recursive technique is the
"pretty printing" of output into columns. If, for example, we wish to
print a list in three columns, we should check to see if our current
list has 3 words or less, and, if so, print them; otherwise, we should
print the first three words, a newline, and then call our column function
again on the remainder of the words in the list (i.e. word #4 on).
This can be written as:
 
 &COLUMN_FN object=[switch(gt(words(%0),3),
    0,[u(FORMAT_FN,%0)],
    [u(FORMAT_FN,extract(%0,1,3))]%r[u(COLUMN_FN,extract(%0,4,words(%0)))])]
 
 &FORMAT_FN object=[first(%0)]%t[first(rest(%0))]%t[rest(rest(%0))]
 
Thus, the expression "[u(COLUMN_FN,lnum(8))]" gives us
 
0       1       2
3       4       5
6       7
(Continued in 'man 14.5.5'.)
 
& 14.5.5
By changing FORMAT_FN, we can do other interesting things with our words;
the example above is not necessarily the optimal way to pass arguments
to FORMAT_FN, if the expression is very complex; it might be better to
pass FORMAT_FN three arguments, doing the FIRST()/REST() extractions
before calling FORMAT_FN.
 
This is another case where FOLD() is useful. Because we can only
grab one item off our list at a time when using FOLD(), we need to have
some other way of determining when to insert a carriage return. For
three-column output, we want to insert a carriage return every three
words; therefore, if the number of words in the string is divisible by 3,
we add a newline, otherwise, we add a tab. The code is then quite simple:
 
 &COLUMN_FN object=[fold(FORMAT_FN,%0)]
 &FORMAT_FN object=%0[switch(mod(words(%0),3),0,%r,%t)]%1
 
* * * * *
 
(Continued in 'man 14.5.6'.)
 
& 14.5.6
FOLD() can also be used to randomize a list under 2.0 (there is a
built-in function, SHUFFLE(), in 1.50 and 2.2, which randomizes
lists).  The list cannot be too large, or the function invocation
limit will cause an error, but using FOLD() is still more reasonable
than most other list randomization methods.
 
What we want to do is to take the elements of the list one at a time
and randomly put them into positions of another list. This can be
done, fairly effectively, by doing the following:
 
1. Start with a blank new list.
2. Take an element of the original list. Put it in the new list.
3. Take the next element of the original list. Put it either before or
   after the element of the new list.
4. Take the third element of the original list. Insert it into the new
   list at a random position.
 
We can use FOLD() to accomplish this, with %0 as the new list,
and %1 as an element, using the following code:
(Continued in 'man 14.5.7'.)
 
& 14.5.7
 &SHUFFLE_FN object=[fold(SHUFFLE_LIST_FN,%0)]
 &SHUFFLE_LIST_FN object=[insert(%0,add(rand(words(%0)),1),%1)]
 
* * * * *
 
Finally, FOLD() is very good for dealing with space-separated
lists that need to be passed to functions which require comma-separated
arguments, such as the example of MAX() used earlier in this manual
section. Given an attribute LIST, containing something like "1 10 83 4",
one can find the maximum of the numbers in it using this code:
 
 &MAXLIST_FN object=[fold(MAXTWO_FN,rest(v(list)),first(v(list)))]
 &MAXTWO_FN object=[max(%0,%1)]
 
* * * * *
 
(Continued in 'man 14.5.8'.)
 
& 14.5.9
Recursion is a very natural technique for generating output
which follows a clearly defined pattern. Unfortunately, due to the
function recursion and invocation limits, it is frequently not a
usable for large values (or long lists, etc.), unless you are using
FOLD() or some other technique for reducing the number of functions
on the stack at a given time. Nonetheless, it can be the fastest
and cleanest way to accomplish a task, and it is not a technique
which should be overlooked.
 

---------------------------------------------------------------------------
 
& 15
15. Efficiency
 
& 15.1
15.1    Parameter Passing
 
MUSH evaluates every single expression it receives; it has no
memory of what has already been evaluated. Thus, if you write something
like "[extract(get(#100/list),2,1)] [extract(get(#100/list),5,1)]",
the "get(#100/list)" is evaluated twice. This isn't disastrous, but
if instead of "get(#100/list)", you had something like
"iter(setinter(lattr(#100/DATA_*),lattr(#100/NUM_*)),mid(##,rand(5),rand(2)))"
(probably expressed as a U() function), repeating the same thing twice
would be extremely inefficient.
 
The best way to avoid evaluating complex expressions multiple times
is to pass them as arguments to a U(). Because having extra function calls
generates more overhead, this is a technique which should be restricted
to those instances where the expressions are either very complex, use
computationally expensive operations (such as SETINTER() and other sorting
functions, ITER(), and large SWITCH() expressions), or are used three or
more times.
 
(Continued in 'man 15.1.1'.)
 
& 15.1.1
The second example above is an excellent candidate for such
reduction. The best way to write it would be something of the form:
 
 &EXPR_FN object=[u(AUX_FN,iter(setinter(lattr(#100/DATA_*),lattr(#100/NUM_*)),
        mid(##, rand(5), rand(2))), 2, 5)]
 
 &AUX_FN object=[extract(%0,%1,1)] [extract(%0,%2,1)]
 
This might be further improved by putting the ITER() in an expression by
itself; it's still of bearable length, but if that particular ITER()
is used another time in the same MUSH program, it should definitely go
into a U().
 
                        ----------
 
(Continued in 'man 15.1.2'.)
 
& 15.1.2
One alternative to using U() parameters to avoid evaluating an
expression twice is the SETQ()/R() function combination. There are ten
"registers", 0 through 9, which can be used for temporary storage.
The registers are local to a command list -- that is, they persist
through more than one queue cycle, within the direct chain of
evaluation, as triggered by a $command, attribute/oattribute/attribute,
or the like.  They are set via the function evaluation
"[setq(<register number>,<expression>)]".  This expression evaluates
to a null string, and therefore can be inserted into a string without
affecting its value. The R() function is used to retrieve the
appropriate register; the %q percent-substitution is equivalent
to this function.
 
(Continued in 'man 15.1.3'.)
 
& 15.1.3
The order of parser evaluation definitely makes a difference
when using SETQ(). It is advisable to put all SETQ() functions at
the beginning of any function evaluation; expressions are evaluated
left to right, outside to inside, and you can check whether or not
values are being set in the order you think they are via use of the
DEBUG flag, but for clarity, SETQ() expressions should be placed
at the beginning of the string. Also, you should make sure that
nested U() functions don't attempt to use the same registers; remember
that registers are local to a command evaluation, _not_ to a function
evaluation.
 
If you need to have nested U() functions that re-use registers (for
example, you have some extremely complex computations that require
large numbers of temporary variables), you may wish to consider use
of the ULOCAL() function instead. This function is identical to U(),
save that R() registers within it are considered "local variables".
That is, the original values of the registers are restored when the
inner function exits, and the original values _are_ passed into the
inner function. In this respect, they are somewhat like VAL parameters
in Pascal, or like ordinary function parameters in C.
 
(Continued in 'man 15.1.4'.)
 
& 15.1.4
You should, however, avoid the unnecessary use of ULOCAL(). While
syntatically cleaner than U(), the copying of variables which is
necessary to preserve the old values also increases the computational
cost of the function. Do, however, note that any use of SETQ() within
a global-defined @function should ALWAYS be done within ULOCAL() unless
you deliberately intend to change the value of the register for the
remainder of the associated command list; otherwise, you might
inadvertently change a value that the calling user is attempting
to preserve.
 
* * * * *
 
Please note that SETQ() is a FUNCTION, not a command. It should thus
be nested within a command, NOT placed on its own. In other words:
 
RIGHT: $test *: @pemit %#=[setq(0,revwords(%0))][u(A_FN,%q0)]--[u(B_FN,%q0)]
WRONG: $test *: [setq(0,revwords(%0))]; @pemit %#=[u(A_FN,%q0)]--[u(B_FN,%q0)]
 
(Continued in 'man 15.1.5'.)
 
& 15.1.5
The most obvious use for SETQ() is to cut down the number of
times a complex expression is evaluated; all that is needed is a single
evaluation as part of a SETQ(). A secondary use is as temporary storage
for some variable needed by FOLD(), FILTER(), or similar functions that
take a limited number of parameters. For example, it is frequently
desirable for a FILTER() to know the dbref of the enactor. But
because the U()-type function called by FILTER() only knows about
the one element of the list being evaluated, it can't get the enactor
unless that information is stored someplace else. In that case, simply
setting '%#' into an R()-register solves the problem.
 
* * * * *
 
Related to intelligent parameter-passing is U()'s usefulness
as a tool for hiding details of implementation. For example, there are
many different ways to count the number of times a word occurs in a list.
If a U() called COUNT_FN is used, instead of writing out the expression
every time, by simply changing the COUNT_FN attribute, different methods
can be tried. For example, any of the following would work, if %0 is the
list and %1 is the word:
(Continued in 'man 15.1.6'.)
 
& 15.1.6
 &COUNT_FN object=[sub(words(%0),words(edit(%b%0%b,%b%1%b,%b)))]
 
 &COUNT_FN object=[words(iter(%0,switch(%0,%1,%0)))]
 
 &COUNT_FN object=[setq(0,%1)][filter(AUX_FN,%0)]
 &AUX_FN object=[eq(comp(%0,%q0),0)]
 
 &COUNT_FN object=[setq(0,%1)][fold(AUX_FN,%0,0)]
 &AUX_FN object=[add(%0,eq(comp(%0,%q0),0))]
 
* * * * *
 
Sometimes, you will want to use the same complex function evaluation
across several commands. In this case, if you have something sufficiently
large and don't mind the extra queue cycle needed, you can use @trigger
to pass that function evaluation as a parameter. @trigger is extremely
useful for parameter manipulation; this is one of the few ways that the
stack variables %0 through %9 can be directly manipulated. Do not ignore
its use as a method for reducing the number of complicated functions that
need to be evaluated.
 
& 15.2
15.2    How the Queue Works
 
The "queue" is the place where all commands are placed before
being run. A queue is exactly what it sounds like; the first command
to be put on the queue is the first command to be executed (the queue
is executed from "head" to "tail"). New commands are always put at
the tail end of the queue.
 
The mysterious MUSH queue is actually three separate queues.
They are referred to as the "Player", "Object", and "Wait" queues.
The first queue is the where commands that are going to be immediately
executed are placed. This includes anything directly typed by a connected
player, plus the first X commands from the object queue (where X is usually
between 0 and 50. It is 3 by default.)  The second queue is where anything
done by an object is placed; when the commands are due to be executed, they
are placed on the player queue. The third queue is where all objects waiting
for some event to occur are placed; when its wait expires, an action in the
wait queue is moved onto the command queue.
 
(Continued in 'man 15.2.1'.)
 
& 15.2.1
The MUSH executes a loop which can be simplified down to:
 
1. Check to see if any waits have expired. If so, put those commands
   in the command queue.
2. Check to see if anybody typed anything, and if so, put those commands
   in the player queue.
3. Put X commands from the command queue into the player queue.
4. Execute the player queue. This may cause more commands to be put
   at the end of the command queue.
5. Go to 1.
 
We can think of the player and command queues as simply being a
single queue, as long as we  keep in mind that something typed from the
keyboard frequently executes before a command issued by an object.
 
Every command in MUSH is a single item on the queue. For the
purposes of this discussion, we will call a "queue cycle" one such
command (rather than referring to a queue cycle as one iteration of
the loop given above, since that's a purely internal measure). Every
command that an object gives is put on the end of the queue.
 
(Continued in 'man 15.2.3'.)
 
& 15.2.3
* * * * *
 
Certain commands "nest" other commands. For example, the @switch command
frequently takes the format:
 
@switch %0=foo, {@pemit %#=Got it.}, {@pemit %#=Failed.}
 
The game does not queue up the @switch and the @pemit one after another.
Instead, it executes the @switch, then puts the correct action at the
end of the queue. Thus, several other commands may occur between the
@switch and the @pemit.
 
This is further complicated by the way action lists (commands
of the format "@@ action 1; @@ action 2; @@ action 3") are handled.
Given that expression, those three actions are queued one after another.
However, nested action lists are considered part of command they are
part of, and are not queued up until that command is executed. For
example: "@emit 0; @switch %0=foo, {@emit yes; @emit YES},
{@emit no; @emit NO}; @emit 1" is queued as the following:
(Continued in 'man 15.2.4'.)
 
& 15.2.4
@emit 0
@switch %0=foo, {@emit yes; @emit YES}, {@emit no; @emit NO}
@emit 1
 
The first command is executed as you would expect, and the output is "0".
Next, the @switch is executed. The resulting actions are put at the tail
of the queue, so the queue becomes (assuming %0 is foo):
 
@emit 1
@emit yes
@emit YES
 
Note that the "@emit 1" executes BEFORE the @emits associated with the
@switch, despite the fact that when the code is typed, the "@emit 1"
comes after the @switch.
 
This behavior also applies to @dolist, @force, @wait, @trigger,
and all other commands which execute other commands. This can be acutely
obvious when you have a construction like:
(Continued in 'man 15.2.5'.)
 
& 15.2.5
@emit Begin; @dolist a b c=@emit ##; @emit End
 
This produces:
 
   Begin
   End
   a
   b
   c
 
That behavior is extremely important when you have commands which must
execute only _after_ all commands in a @dolist has finished executing;
in that type of case, a @wait, either timed or semaphore, is usually
the best solution.
 
& 15.3
15.3    Pipelining
 
"Pipelining" is a term borrowed from the jargon of microprocessors. In
that field, it refers to the practice of feeding the next instruction
to the CPU, before the previous instruction has completed. The
"pipeline" ensures that there will always be an instruction waiting
for the CPU.  If the previous instruction was a branch and the
processor predicts the incorrect next instruction, the processor must
then go fetch the correct next instruction; nonetheless, this is not a
loss, since, had there not been a previous fetch, there would have
been a delay anyway while the processor went hunting for the
instruction.
 
A similar principle can be applied to MUSH programming. Simply put,
there are many MUSH commands which do something along the lines of
the following:
 
$test *: @switch/first num(*%0)=#-1, {@pemit %#=No such player.},
         {&TEST_OWNER %#=owner(*%0); @pemit %#=Owner test set.}
 
(Continued in 'man 15.3.1'.)
 
& 15.3.1
Note that no matter what happens, you will always have at least two
commands to queue: the @switch, and the @pemit. In the case of correct
syntax, there'll be three commands: the @switch, the @pemit, and the
attribute set.
 
This doesn't make sense, from the viewpoint of efficiency. Since the
correct case is going to be the one encountered the most frequently,
it shouldn't, ideally, be any slower than the error case.
 
You can usually save yourself a queue cycle by doing the following:
 
$test *: @pemit %#=switch(num(*%0),#-1,No such player.,Owner test set.);
         &TEST_OWNER [switch(num(*%0),#-1,#-1,%#)]=owner(*%0)
 
(Continued in 'man 15.3.2'.)
 
& 15.3.2
Basically, we "assume" that the set is going to succeed, most of the time,
and go ahead and do it anyway; to avoid accidentally scribbling on the
attribute if we've encountered an error, we SWITCH() to make the object
try to set TEST_OWNER on a non-existent object in the case of an error.
We have, granted, added extra wildcard matches by the use of two
SWITCH() statements where before there was a single @switch, but we've
saved on a queue cycle, so we've probably won, overall -- this varies
on a case-by-case basis, of course.
 
We can do this sort of "pipelining" for @trigger, @dolist, and similar
things. It's no longer more efficient when there are more than two queue
cycles involved, but since many MUSH situations do reduce down to something
of this format, this "pipelining" technique proves extremely useful.
 
& 15.4
15.4    Queue Cycles vs. CPU Cycles
 
One of the major drawbacks to the "switchless" coding style is
that it tends to reduce the queue cycles needed to perform an action
at the expense of short evaluation times for a command. While the action
may take less time to execute, because other objects' queued commands are
not getting executed between each stage of the action, the overall
computation time ("CPU cycles") needed by that action group may not be
significantly reduced, or, indeed, may actually be increased.
 
Switchless coding tends to eliminate @switch and @trigger, two
commands which force a "delay", due to the property of these two commands
described in the earlier section on the workings of the queue. In doing
so, however, the programmer frequently uses complex function evaluations
which take a long time to evaluate, and, worse still, may evaluate the
same expression repeatedly.
 
One simple example of such a tradeoff is the following:
(Continued in 'man 15.4.1'.)
 
& 15.4.1
@va object=$test *: @pemit %#=[extract(v(colors),match(v(list),%0),1)]
        [extract(v(sizes),match(v(list),%0),1)] [match(v(list),%0,1)]
 
  vs.
 
@va object=$test *: @trigger me/vb=%#,[match(v(list),%0)]
@vb object=@pemit %0=[extract(v(colors),%1,1)] [extract(v(sizes),%1,1)] %1
 
The second way is slower, since it takes two commands instead of one,
but it's also more efficient. The best way to do the above would be
 
@va object=$test *: @pemit %#=
        [setq(0,match(v(list),%0))][extract(v(colors),r(0),1)]
        [extract(v(sizes),r(0),1)] [r(0)]
 
(Continued in 'man 15.4.2'.)
 
& 15.4.2
One must also remember that even if the total time to evaluate
a switchless and non-switchless version of the same action is the same,
other players are forced to wait longer for their commands to execute
under the switchless, because the game is running the big complex
evaluation all at once. While the _total_ time spent waiting remains
constant, the time-between-each command is increased.
 
Therefore, considerate programmers don't program gigantic
expressions which hog the server for several seconds at a time. Good
programmers find better ways to split up the evaluation, so that it
doesn't take several seconds to evaluate. If you write something which
lags a MUSH running at an ordinary speed, you haven't programmed it well.
 
(Continued in 'man 15.4.3'.)
 
& 15.4.3
As more programmers code switchless style, the amount of time
between each command increases. On a fast MUSH, the difference is not
generally noticeable, but if you really want to know if your code is
any good, try running it on a slow machine (NOT a slow network -- you
should victimize a MicroVAX or something similar). The switchless style
when used intelligently shouldn't slow down the game, but it's far too
easy to abuse. Function invocations should be kept to a minimum.
In general, if an attribute containing a command list exceeds about 12
lines of text, it is Too Large.
 
Intelligent use of switchless programming usually generates strings to
be outputted. Using massive nested switch() constructs usually implies
that something is not as efficient as it could be; the same is true
with iter(). The way a list is stored is frequently more important
than the way it is accessed; by storing data differently, it's often
possible to cut down on the complexity of retrieval.  The switchless
style is best when it eliminates large numbers of nested @switch's;
other uses, especially those involving recursion, should be carefully
considered before being used.
 
(Continued in 'man 15.3.3'.)
 
& 15.3.3
----------
 
That's the end of this manual; I hope it's been helpful. Please remember
that this is copyrighted material; I've put a lot of work into this and
am not likely to be pleased by others stealing my work. Please see the
first section of this manual for the terms of the copyright and other
information.
 
Comments, corrections, and suggestions should be emailed to Amberyl,
at lwl@godlike.com
 
&wiz-ethics
                            Godlike Technologies
 
                          Amberyl's Wizard Ethics
 
     This is an expansion of the section of the MUSH manual called "The
    Fundamental Laws of Wizarding". Questions and comments should go to
   lwl@godlike.com. The content of the lecture has been unmodified since
                                 10/23/94.
     _________________________________________________________________
 
     Administrators on a MUSH have a considerable amount of power. With
   that power comes the responsibility to use it wisely, for the actions
   of an administrator reflect not only on himself, but on the MUSH as a
    whole. Because an admin is in a position of power, he should attempt
     to set a positive example in all dealings, whether in-character or
   out-of-character, Common sense will usually suggest a decent solution
     to a given problem; there are, however, some situations where the
       ethical and "correct" thing to do is not immediately obvious.
     _________________________________________________________________
(Continued in 'man wizeth1'.)
 
&wizeth1
     Players are frequently paranoid about privacy. This is one "right"
   that you should _always_ attempt to respect; thus, this lecture begins
      with a discussion of the DARK flag. When you are DARK in a room,
    players who do a 'look' cannot see you, and you do not appear on the
   WHO list, but a @sweep of the room _does_ show that you are listening
   and connected. Therefore, there is a chance that you will be noticed,
     and, if you are "illegally" in the room DARK, it is almost certain
             that the players in the room will be quite upset.
 
   The reason why players don't like DARK wizards wandering around should
    be obvious -- they're afraid of private conversations being snooped
    on. Therefore, whenever you go _anyplace_ DARK, the first thing you
         should type upon entering the room is a "hello" or similar
       announcement of your presence. Make this a habit! If you do it
    regularly, even when the players in the room know you'll be entering
   DARK, there's less of a chance you will forget at some crucial moment.
    If you plan to be DARK, and wandering around, for an extended period
    of time, in order to arbitrate an RPG conflict or similar event, the
   players involved should, if possible, know of your presence, and if a
(Continued in 'man wizeth2'.)
 
&wizeth2
     private conversation begins, it is your ethical responsibility to
    inform the players of your presence immediately, _even if_ this lets
   players know that they are being judged. Your personal responsibility
              to promote privacy overrides any RPG mechanics.
 
   Some MUSH gods may allow their wizards to go DARK in order to observe
      players whom are suspected of trying to harm the game, either by
   harming the database or crashing the server; some other gods may also
   allow wizards to go DARK to observe the actions of a player harassing
     other players. In the latter case, the wizard should indicate his
     presence to the players in the room who are not "under suspicion".
 
    I cannot emphasize enough how important it is to obey the protocols
   for using the DARK flag. This is one of the greatest sources of player
   distrust in wizards, because it is so _easy_ to abuse. Players should
    be able to have private conversations without doing a @sweep all the
   time. While privacy on a MUD is never, ever, guaranteed, you should do
                    your best to contribute towards it.
     _________________________________________________________________
(Continued in 'man wizeth3'.)
 
&wizeth3
   The second of the frequently-abused wizard powers is @teleport. There
   are a number of rules that should be observed when @teleporting. First
       of all, never teleport a player without warning him first. If
    possible, the player should page you with an acknowledgement before
      you do the actual @tel. This prevents, for example, an untimely
    @teleport wrecking someone's set of a @desc on a room. No one enjoys
   suddenly being yanked to another room, and it doesn't hurt you to page
                             the player first.
 
   Never teleport to a room with players without asking the permission of
   the players there first. The exception to this are public hangouts. A
   room which is merely JUMP_OK is not necessarily a public hangout; use
      some judgement when determining whether or not rooms are public.
    Unless the room is clearly public, ask first; it doesn't hurt you to
                                 be polite.
 
(Continued in 'man wizeth4'.)
 
&wizeth4
   If permission is not likely to be granted, then notify all players in
   the room (@remit works well for this) that you are going to be coming
   in, before entering the room. You should wait a moment between the of
      the announcement and the teleport; this should prevent you from
                   hearing something that you shouldn't.
 
   Never make assumptions about whether or not it's okay to teleport into
   a situation. For example, just because a player is paging you for help
    with coding some complex object _doesn't_ mean that he wants you to
    teleport into his room and help him out. I know this from experience
   -- as a new wizard, I once struggled to help someone, remotely, with a
      complex MUSHcoded object, and, finally, after fifteen minutes of
   fruitless pages, I finally decided to teleport in and see what errors
    the object was outputting. Unfortunately, I bamf'ed myself straight
    into the middle of a hot 'n steamy tinysex session. Since then, I've
              made it a rule to always ask before teleporting.
     _________________________________________________________________
(Continued in 'man wizeth5'.)
 
&wizeth5
     Don't abuse "examine" or the power to see private information like
    sites. The rules for examining private objects will vary from God to
   God. On a MUSH where a strict theme is enforced, wizards will probably
        be permitted to examine anything in order to check for theme
   consistency. You should never share or show any object, or part of an
      object, that is not yours to another player, without getting the
      permission of the owner. Also, don't steal code. "Stealing code"
     includes @decompiling/logging/cloning without permission, even if
      you're just using the code for your own personal edification or
         enjoyment. If it's that important to you, ask permission.
 
    Sitenames should never be given out. If a player is Unfindable, you
   shouldn't give out his location. Some people MUD to escape people they
      know in Real Life; some players carry vendettas cross-MUD. Other
   people simply prefer not to let others know where they are, VR or RL.
                      You should respect this desire.
     _________________________________________________________________
(Continued in 'man wizeth6'.)
 
&wizeth6
    You should generally avoid modifying other people's objects, even if
    you're fixing code problems or typos. The only exception to this is
     publicly owned building owned by a wizard-played builder character
     (the core landscape for the MUSH, the downtown area, etc.) If you
   encounter an object which is inefficiently programmed or looping, and
    thus slowing down the game for everyone else, simply set it HALT and
                   mail the owner; don't fix the problem.
 
   Also, don't @destroy anything of anyone else's unless they explicitly
     ask you to. If it's an item which is illegal in some way, send the
    owner a warning, and give him a certain period of time (a few days,
    usually, depending on how often the player logs in) in which to get
     rid of it. If it's not gone by the end of the period, then you can
     destruct it. If the illegal item is sitting in a public place, you
             should feel free to teleport it back to its owner.
     _________________________________________________________________
(Continued in 'man wizeth7'.)
 
&wizeth7
    Never, ever, @force a player, unless it is absolutely necessary. For
    the same reasons, don't use @trigger and similar commands to make a
        player do something against his will. Also, don't change the
      attributes on a player; for example, it is generally considered
    unethical to change a player's description to something humiliating.
    Wizards might occassional get into practical joke wars, but mortals
     shouldn't become involved. If you need to change an attribute on a
   player, make sure you copy the old attribute to a backup attribute on
         the player, so that they can recover it later, if need be.
     _________________________________________________________________
 
   Wizards can pile huge numbers of things on the queue, and make use of
       computationally expensive commands like @find and @search with
   impunity. If you need to do something that will severely lag the game,
    do it when there aren't many players on. Also, note that very large
    @dolists cause the MUSH process size to grow, and should be avoided
                             whenever possible.
     _________________________________________________________________
(Continued in 'man wizeth8'.)
 
&wizeth8
   Wizards should be uselocked at all times. Private wiztoys should also
       be uselocked. Any item with wizard powers MUST be checked for
   security; if you are not a competent enough MUSH programmer to be able
    to do this yourself, you should show the item to a wizard who is. In
    addition, administrators and objects owned by administrators should
           never be zoned to a Zone to which mortals have access.
 
    Never give a wiz-power item to a mortal. If a mortal absolutely MUST
   have a wizard-power item to do what he wants, consider @chown'ing that
      particular system to a wizard. If this isn't possible, then make
   absolutely certain that the mortal is trustworthy. Every administrator
     on the game should be aware of all wiz-power items in the hands of
                                  mortals.
     _________________________________________________________________
(Continued in 'man wizeth9'.)
 
&wizeth9
     Avoid annoying players with shouts. @wall cannot be blocked, and,
        therefore, you should make sure that everything you shout is
   informative and necessary. On a very small, friendly MUSH, it might be
     considered acceptable to @wall hello and goodbye; on most MUSHes,
       though, especially RPG ones where "mood" and "atmosphere" are
   important, @walls of that sort should be avoided. Shouting to announce
    a @shutdown in five minutes is acceptable; shouting to announce game
   problems is acceptable. Shouting to announce that you've had a bad day
    and shouldn't be paged should probably be avoided. First of all, it
    makes you sound like a twit; second, it accomplishes nothing useful
   and implies, "stay out of my way or something bad will happen to you."
   If you really want to avoid player pages, go DARK and set a pagelock.
    Players shouldn't be afraid of you on a "professional" wizard level,
    and you should try to avoid actions which cause players to fear you.
     _________________________________________________________________
(Continued in 'man wizeth10'.)
 
&wizeth10
    Wizards should be thoroughly familiar with MUSH. While "psychocoder"
     status is not necessary, a good understanding of MUSH mechanics is
   necessary. Never type a command as a wizard without understanding what
      it does. You should have read the MUSH manual; even if you don't
      understand all of it, you should read and understand the wizard
                                  section.
 
    Every object in the Master Room should have a specific purpose. ONLY
   objects used for global commands should be in the Master Room. As few
     total attributes should be on Master Room objects as possible; any
   data objects should be contained on separate objects NOT in the master
    room, and the Master Room objects should NOT be parented to the data
       objects. Every attribute in the Master Room represents another
      attribute that must be checked for $commands when a player types
   something; thus, having unnecessary objects and attributes in the room
   will slow the game down. If you need a place to store objects used as
    global parents and whatnot, use a room _other_ than the Master Room.
      Master Room code should, obviously, be as efficient as possible.
     _________________________________________________________________
(Continued in 'man wizeth11'.)
 
&wizeth11
    There should be at least one wizard on the game who is familiar with
   the technical aspects of the server. Also, backups should be done on a
   weekly basis, or more often, if possible. This will save you a lot of
     grief should your database get eaten by a bug or other problem. If
        your currently-running game begins to show signs of database
   corruption, it is probably a good idea NOT to @shutdown; instead, log
   into the game account and 'kill -9' the MUSH process. It's also a good
   idea for wizards to know the phone number of the God / codehack / site
                          admin, for emergencies.
 
       If you have the necessary technical background, you are highly
    encourage to at least take a glance at the server code. Knowledge of
    the server workings helps your MUSH programming ability, and enables
    you to make intelligent decisions that involve disk, memory, and CPU
      usage. Also, get to know wizards on other MUSHes; this gives you
     people to go to for help should something unfortunate befall your
                                   MUSH.
     _________________________________________________________________
(Continued in 'man wizeth12'.)
 
&wizeth12
   Never MUSH while intoxicated or otherwise not fully in control of your
     actions. If you observe another wizard who is MUSHing drunk, @boot
    them. The other wizard will probably be annoyed, but this is better
   than having damage inadvertently caused by someone who isn't thinking
                                  clearly.
 
     Know when to log off or back out of a situation. If you feel like
   you're about to explode, get up, walk around for a bit, get a drink of
        water, and come back when you feel like you're ready to cope
        rationally with the situation. If possible, call in another
     administrator to handle the situation. Never, ever, perform wizard
    actions out of anger; it is likely that you will regret them later.
 
    A wizard's ability to deal with players is usually the final test of
    his skills. Troublemaking players are quick to find wizards who are
     easily provoked, and frequently enjoy pushing all the buttons they
    can. When you page a player, no matter how annoyed you might be, you
      should try to remain calm and polite. Don't swear at players, or
    behave in a manner that would allow the player to focus a discussion
             away from his wrongdoing to a mistake _you_ made.
 
(Continued in 'man wizeth13'.)
 
&wizeth13
     Players who are spamming or exhibiting behavior detrimental to the
       server or database should be @booted; if it's a one-time-deal
   character like "You_Suck", a @destroy is also in order. Other players
         should receive warnings before any direct action is taken.
 
    If a player is being obnoxious or breaking MUSH rules, page them and
     politely let them know that their behavior is unacceptable. If the
     player is not idle, and does not respond to your page within a few
      minutes, repeat your page. If the player simply ignores you, or
     refuses to change his behavior, page with a stronger warning, but
    continue to remain polite. If this doesn't work, tell them, "If you
                 don't stop that, I'm going to @boot you."
(Continued in 'man wizeth14'.)
 
&wizeth14
    This will normally at least open a dialogue between yourself and the
     player in question. If the player isn't willing to discuss it, and
   continues the obnoxious behavior, set them GAG. Most players will quit
     voluntarily. For really stubborn players, @boot will work. If they
     come back and continue to be annoying, then @newpassword them. You
   should NOT @destroy a player who isn't a one-shot annoyance. @destroy
     is not reversible, but a player can be re-@newpassworded should he
                 decide to come back and play by the rules.
 
      When talking to a player, you should attempt to remain calm and
   polite, no matter how much the player is trying to provoke you. Ignore
   personal insults, obscenities, and the like, if some useful discussion
   is occurring. If the player is just continuing to be annoying, end the
    discussion and simply tell them, "Do this again and I'll @boot you."
                You're not required to be a saint or martyr.
 
(Continued in 'man wizeth15'.)
 
&wizeth15
   Whenever you enter a major conflict with a player, you should log the
   situation, if possible. You should send the other wizards, via email,
     a summary of the situation, and, if necessary, the log. This will
    prevent the player from accusing you of saying or doing things that
   you did not, and will give you a "record" of the player's behavior, in
   case the player claims that he didn't do what you claimed he did. The
    SUSPECT flag and @comment attribute are also good for letting other
                   wizards know about suspicious players.
     _________________________________________________________________
 
      These guidelines aren't here to make the task of wizarding more
     difficult for you. They exist to provide some basic guidelines of
   ethical behavior; in general, if you follow these guidelines, players
   will find it quite difficult to accuse you of abusing your wizpowers.
    They thus work for your protection, as well as the players'. Players
     frequently take wizard mistakes personally and seriously, and may
     decide, "because wizard X did this, all other wizards probably do,
   too." Players who are paranoid tend to be more difficult to deal with;
    thus, for the sake of your sanity and that of every other wizard who
(Continued in 'man wizeth16'.)
 
&wizeth16
   ever has to deal with that player, try to avoid giving the a reason to
   be paranoid. If you consistently have personal problems with a player,
    you should also avoid wizard dealings with that player; have another
                    wizard handle the situation instead.
 
   In all things, use common sense, and try to remain calm and impartial.
                       When all else fails, log off.
     _________________________________________________________________
 
       Based on a lecture first given on TinyKrynn, 2/92, by Amberyl.
 
&README
READ THIS NOTICE FIRST
 
This notice should be located in a directory titled something like
"mushman-2.008", which contains the files "man2x0" through "man2x5".
(The files might have been renamed, but the content should be as
described below.)
 
These files constitute a document entitled, "Amberyl's MUSH Manual",
sometimes referred to as, "The TinyMUSH Manual", or, simply, "The
MUSH Manual".
 
This material is COPYRIGHTED by the author, Lydia Leong (lwl@godlike.com),
sometimes known on the Net as "Amberyl". All rights and privileges of
reproduction are hers, in accordance with United States or International
Copyright Laws. As of the date of this manual's release (May 22nd, 1995),
there is a United States copyright application being filed for this
document, though even prior to this official record of copyright, this
document is still subject to the conditions outlined below, and protected
by US and international copyright law.
 
(Continued in 'man README1'.)
 
&README1
Users are granted to print and reproduce this manual in its UNMODIFIED
entirety, as long as the copyright notices are retained and due credit
is given. This manual may be quoted in a publication -- electronic or
otherwise -- within the normal academic protocol of appropriate lengths
of quotations and due credit.
 
This manual may NOT be used within another major document (such as another
manual), nor published in print form (whether or not the publisher makes
a profit from such publication), nor may it be hypertextified or otherwise
changed in format, without the explicit permission of the author.
 
This notice must be retained together with any electronically-retrievable
version of this manual.
 
(Continued in 'man README2'.)
 
&README2
I apologize for needing to spell these terms out in such an explicit
manner, but there are certain creatures on the Net who have happily
taken advantage of my generosity in making this manual freely
available, and decided to make a buck off it themselves. To protect
myself from further incidences of such theft (and to avoid further
lining the pockets of my lawyer), to keep track of the uses of this
manual, and to ensure that no unknown "splinter" versions of this
manual arise, I'm explicitly stating the terms under which this manual
is distributed -- you can use it for your own education and enjoyment,
or print it out to line your bird cage, but please, if you're going
to change it or reprint it, please contact me first.
 
This manual is now shareware. If you found it useful, please consider
sending $10 to the address obtainable by fingering 'lwl@godlike.com'
At the very least, it'll help pay back legal expenses incurred from
protecting the copyright on this manual (and thus your privilege of
getting it free from the Net).
 
(Continued in 'man README3'.)
 
& README3
(No, I'm not giving out details on the legal tangle, until it's
settled. I'll post an explanation when it's all over.)
 
Thanks. I hope you find this manual useful. Comments and corrections
are always appreciated.
 
        -- Lydia Leong (lwl@godlike.com)
           May 22nd, 1995