LambdaCore Database Programmer's Manual

For LambdaMOO version 1.3

July 1991

Mike Prudence (blip)
Simon Hunt (Ezeke)
Floyd Moore (Phantom)
Kelly Larson (Zaphod)
Al Harringtom (Geezer)


Copyright (C) 1991 Mike Prudence, Simon Hunt, Floyd Moore, Kelly Larson, Al Harrington.

Copies of the electronic source for this document can be obtained using anonymous FTP on the Internet. At the site belch.berkeley.edu the files are pub/moo/LambdaMOO/LambdaCoreProgMan.*; several different file formats are provided, including Texinfo, plain text, and Postscript.

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the author.

Introduction

The LambdaCore database provides the facilities needed to make a LambdaMOO server useful for Multi User Adventuring. If you compare the LambdaMOO server to a piece of computer hardware, then LambdaCore is the operating system needed to allow the user to do useful work.

This document gives a rundown on the elements of the LambdaCore database, and provides details of each of the verbs used by the database. It also provides source for some of the verbs, to aid understanding and provide extra information.

The user is assumed to have read the two companion manuals to this one, The LambdaMOO Programmer's Manual and The LambdaCore User's Manual. An understanding of MOO concepts, the MOO language and the facilities provided by the LambdaCore database is needed to follow the explanations given in this document.

The LambdaCore Classes

The LambdaCore database provides several basic classes that are used to define the virtual world. It is these classes that provide the core of any MOO database built on the LambdaCore database. As well as defining obvious things like players, rooms and exits, the classes also provide all the commands used to interact with the database, and several utility functions for use by the MOO programmer writing his or her own verbs.

The LambdaCore classes can be divided into two categories:

The sections that follow describe the LambdaCore classes in detail, providing insight into what each verb and property is used for, and some idea of how they should be used in your own MOO programs.

The LambdaCore Generic Classes

The following generic classes are available in the LambdaCore database:

The Root Class ($root_class)
This is the basic class from which everything else in the database is descended. It defines basic operations and properties on an object.
The Generic Room ($room)
This class is the parent for all the rooms in the database.
The Mail Distribution Center ($mail_room)
This is a special class used to define a room for dealing with MOO mail. It is a child of the generic Room class.
The Generic Mail Recipient
To be written.
The Generic Editor's Office ($editor)
This is a special class used to define a room used for program editing. It is a child of the generic Room class.
System Object (#0)
This is the keystone object for the database. It holds various important system properties, as well as pointers to the various other classes and objects that are system-wide.
The Generic Thing ($thing)
This class defines a TinyMUD style object, that is, something that can be picked up and put down. It defines various messages related to taking and dropping the object.
The Generic Container ($container)
This is a child class of the Thing class. A container is an object that can have other objects placed within it.
The Generic Note ($note)
A note is a child class of the Thing class. It is used to store text messages, which may be encrypted. A note can only be recycled by the owner.
The Generic Letter ($letter)
A letter is a child class of the Note class. It provides the same facilities, but also has a burn verb which the recipient can use to recycle the letter.
The Generic Player ($player)
This is the class from which all players are descended.
The Generic Programmer ($prog)
This is a child of the Player class used for players that are MOO programmers. It defines a set of verbs that are useful for programming activities.
The Generic Wizard ($wiz)
This is a child of the generic programmer class, used for wizards.
The Generic Exit. ($exit)
This class defines a generic exit used to link one object of class Room to another object of class Room. It defines a number of messages that may be generated when an exit is used.

The Root Class

The root class is the base class from which all objects are descended. It is the keystone of the database and defines fundamental verbs and properties common to every object. If you are a programmer (ie, you have a player object with the programmer bit set) you can examine the properties and verbs of the root class using the command

@show $root_class

You can examine the code for a verb on the class by using, for example, the following command.

@list $root_class:description

This lists the program definition for the verb $root_class:description. An interesting point to note is that this code can be changed by the owner - in this case the Wizard - to provide any functionality desired. This configurability of the basis of the whole LambdaCore database allows a large degree of flexibility in the way the LambdaMOO server is used. It also allows for very subtle and perplexing problems. Care must be taken when editing definitions on any of the fundamental classes, the $root_class in particular. However, as the base classes of the LambdaCore database have been thoroughly tested and debugged, there should be very little need for any changes by the average database administrator.

The following section lists the verb and property definitions for the $root_class. For each verb, a description of it's function is given, along with any interesting points. The intent is to present each verb in such a way that it is possible to grasp the whole picture, rather than just looking at the individual brushstrokes.

Verb: string description ()
The :description verb on any object is supposed to return a string or list of strings describing the object in the detail someone would notice if they were specifically looking at it.

The default implementation of the "look" command (defined on the $room class), prints this description using the :look_self verb on the object. :look_self uses :description to obtain the text to display.

Verb: none describe (value)
The :describe verb is used to set the description property of an object. This is only allowed if we have permission, determined using the $perm_utils:controls() verb. By overriding this verb and the :description verb, it is possible to completely change the representation of an object description. This is done invisibly to anyone outside the object, as long as you adhere to the same interface to :description and :describe.

Verb: none look_self ()
The :look_self verb on any object is used to :tell another object what this object looks like, in detail. This verb makes use of the :description verb on the object to obtain a string or list of strings to print. It would be possible to override this verb to produce a special description for an object. However, any other verbs that use the :description verb of the object will not see the extra information added by the overriding function. The $room class overrides this verb with code to print the room name and a list of objects that are in the room.

Verb: none tell (string strings, ...)
This verb is used to send a message from one object to another. The $root_class definition of this verb tests to see if the object is a player, and if it is, uses the notify primitive to print the argument list on the player's screen, if they are connected. However, this verb can be overridden to allow arbitrary objects to pass messages between each other, or to augment the way the message is handled.

One simple example is that of an object that listens to everything that happens in a room. Every verb that needs to send text to players uses the :tell verb. If an object has it's own :tell verb, it too will be able to act upon the messages sent between objects in a room.

The $player class overrides this verb to filter messages in two different ways, as show below:

if (typeof(this.gaglist) != LIST || !(player in this.gaglist))
  if (player != this && this.paranoid == 1)
    pass("<", player.name, "(", player, ")> ", @args);
  else
    pass(@args);
  endif
endif

Firstly, if the message comes from a player that we don't want to listen to - the player has been gagged - then the message is thrown away. Secondly, if the player is being paranoid, and the message is not from ourselves, it is prefaced with the name of the originating object. The pass primitive is used to allow the :tell verb of the parent class to send the message after it has been modified.

Verb: none moveto (obj where)
This verb is used to change the location of an object to be where. The built-in function move() is used by this verb. Any error codes generated by it are returned by this function. This verb is intended to be used by any other verbs that must move an object to another location.

One important point to note is that this uses the set_task_perms() primitive to set the task permissions to those of the thing that is being moved.

Again, by overriding the verb definition on an object, it is possible to augment or change the way an object is moved. For example, you could keep a list of places visited by simply recording the where objects in a list every time this function is called.

Verb: num accept (obj thing)
This verb is used to control what objects are permitted to be placed inside other objects. If this verb returns `0', then the object where cannot be moved into this object. Conversely, if the verb returns a non-zero value, the object is allowed to be placed inside this object. The verb is called by the server when it executes a move() primitive.

The $root_class definition returns a zero value. In this case, no objects are allowed inside any objects that are children of the $root_class. The $room class definition provides for a flexible scheme using various different criteria, as shown in the following code :

what = args[1];
return this:is_unlocked_for(what) && 
       (this.free_entry || 
       what.owner == this.owner || 
       (typeof(this.residents) == LIST && what in this.residents));

Starting at the top of the conditional expression, we see the locking condition being checked. If the room lock forbids this object to enter the room, then the :accept verb returns zero.

If this is not the case, then we consider the value of the free_entry property. If this is set to a non-zero value, then the object is allowed to enter the room.

If the owner of an object is the owner of a room, the object is allowed to enter.

Finally, if a residents list is defined in the room, and the object is in the list, then it is allowed to enter.

This complex set of conditions shows how an arbitrary set of criteria can be applied to the movement of objects into other objects.

Verb: obj match (string name)
This verb is used to find things that are located within this object. It tries to match name to something in the contents list of this object, using object names and object aliases. This verb uses the $string_utils:match() verb to do the actual searching. If a match is found, the object that matched is returned. If more than one object matches, then $ambiguous_match is returned. If no match is found, then $failed_match is returned.

Verb: none exam*ine ()
This prints out some useful information about the object to the player. It is provided as a player command, to allow every player to determine basic information about any other objects they come across. For example,
>exam #0
The System Object (#0) is owned by Wizard (#2).
Aliases:  The, Known, and Universe
(No description set.)

The idea is to allow every player to discover the owner, full name, description and aliases of any object.

If you control the object, the lock for the object is shown. If the object has other objects inside it, then the contents list is printed out, too. If the object has verbs defined on it, then these verbs are listed, provided they are readable, and have not been hidden by setting the argument specifiers to the triplet `this', `none' `this'.

Verb: none tell_lines (list strings)
This outputs out the list of strings strings to the object, using the tell verb for this object. Each string in strings is output on a separate line.

Verb: num set_name (string value)
This verb sets the name of the object to value. It returns `1' if the name was set to the value successfully, otherwise it returns `0'. This verb, and the :title verb are used to control access to the name property of an object.

Verb: num is_unlocked_for (obj thing)
Returns `1' if the object is unlocked for the argument. If the value of this.key is zero, the object is unlocked. If this is not the case. the verb $lock_utils:eval_key() is used to determine the result.

Verb: string title ().
This verb is used to get the name property of this object.

One example where it might be useful to redefine this verb is if you want to add an honorific or descriptive phrase to the end of your name. By overriding the :title verb, you can append anything you like to the :name property of the object.

Verb: none recycle ()
This verb contains no code for the $root class. It is called by the recycle() primitive just before an object is recycled. This is useful to make sure that recycling objects does not leave the database in a strange state. For example, the $exit class uses the :recycle verb to remove the exit from the the entrance and exit lists of its destination and source rooms.

Verb: string titlec ()
This verb performs the same function as the title verb, but returns a capitalised version of the name property of the object, using the $string_utils:cap_property verb.

Verb: none eject ()
This verb is used to remove something from the contents of an object. The owner of an object, or a wizard, can use this verb to eject a victim from inside the object. The victim is sent to $nothing, for most objects, or to $player_start if the victim is a player.

The root class defines a few basic properties that every object has. The verbs discussed above make reference to these properties - as well as the built in properties name, owner, location, contents, programmer, wizard, r and w. The following properties are defined for the root class:

Property: key
This is used to determine what, if anything, an item is locked to.

Property: aliases
This gives a list of the alternative names that can be used to refer to an object. The value of this property should be a list of strings, the various alternatives for naming the object. Note that the name of the object in question should be included in this list, because the built in name matcher uses only the aliases property when searching for matches.

Property: description
This is a string or list of strings giving the description of the object - what we see when we look at the object.

The Room Class

The Room Class is the basic class from which all the rooms in the virtual world are descended. It is one of the very basic classes essential to constructing a virtual world; an exit is the other essential class.

A room can be thought of as a container for players and objects. It can have a number of exits that connect it to other rooms. These exits are directed; they lead from one room to another room. For a two way passage to exist, two exits are needed, going in opposite directions.

The room class defines a lot of verbs, which are used to provide an interface to the properties of the room.

One special point is worth noting about rooms and exits. An exit can have an arbitrary name - indeed, this is the usual case. In order for the room to recognise the exit name, and match it up with an exit that exists in the room, some form of catchall mechanism is used. If a player types a sentence that the parser cannot match with anything, it executes a verb called :huh in the current room, if one exists.

When this happens, the :huh verb is free to take the player's sentence, search for a valid exit, and act accordingly. This mechanism provides a very flexible arrangement for dealing with exits, and also allows a degree of player help to be added. If a close match to a command is found, the huh verb could detect this and provide a useful response that would help the player construct the correct sentence.

The following section lists the verbs defined for the $room class. Those verbs which are more properly described as player commands are detailed in a preceding section.

Verb: none confunc ()
This verb is called by the LambdaMOO server when a player connects in a room. The action coded into the $room class simply shows the player what the room looks like (using the :look_self verb of the room) and tells everyone else in the room that the player has connected.

Verb: none disfunc ()
This verb is called by the LambdaMOO server when a player disconnects from the game. The $room class definition of this verb moves the player home if s/he is not already there, using the :moveto verb on the player. One possible enhancement of this verb, already implemented in some MOOs, is to include a time delay between disconnection and movement of the player to his/her home. This would allow some tolerance of disconnection due to network problems.

Verb: none say (string message)
This verb provides one of the basic ways in which players communicate. The action of the :say verb is very simple: it :tells the player what s/he has just said, and tells everyone else what the player said. The text spoken is passed to all the objects in a room, not just the players, through the :tell verbs on the objects in the room.

By overriding this verb, it is possible to provide all sorts of effects that work on everything said in the room. For example, you could redirect messages to other rooms, or repeat messages to provide cavernous echoes.

Verb: none emote (string message)
This verb is used for the pose type of interaction with other players. It functions in a similar way to the :say verb, but instead places the player's name at the front of the text. The actual output is done in two stages. The :emote verb is responsible for telling the player the action s/he has just performed. The emote1 verb is then called to tell the other objects in the room of the pose action. This provides a two stage mechanism; either or both of the verbs can be overridden to provide special effects.

Verb: none emote1 (string message)
This verb is invoked by the emote verb to send the emote text to the other objectss in the room. By overriding this verb, it is possible to create special effects for emote actions that are only seen by the other people in a room. :emote1 uses $room:announce to send it's message.

Verb: none announce (string message)
This verb is a general purpose verb used to send a message to every object in the room except the player that invoked it. This is intended to be the way other verbs pass messages to objects in a room. For example, when an exit is activated, it uses :announce to inform the other players in the room of what has happened.

Verb: none announce_all_but (list @args)
This general purpose verb is used to send a message to everyone in the room except a particular object. This can be used in situations where we wish to present one view to the world in general, and another view to a particular object, normally a player. Another common usage is to prevent robots that trigger actions based on a redefined :tell() verb on themselves from recursing, using something like
place:announce_all_but(this, "message");

Verb: none huh (string sentence)
This verb is a stub used to call the huh2 verb. It is called by the LambdaMOO server when it can't match a sentence given to it by a player. The server calls :huh with verb equal to the actual verb in the erroneous command line. This means it is not possible to use pass() if you override :huh in a room; it would pass control up to a verb on the parent named verb, i.e., whatever the verb was on the command line. This, by definition, doesn't exist. To get around this, and allow you to use pass() to get the default :huh behaviour, :huh calls :huh2. You should override :huh2 if you wish to be able to use pass() to get the default :huh behaviour.

Verb: obj match_exit (string exit)
This verb is used to determine if exit is the name of an exit leading out of the room. It performs a simple string match on the names and aliases of the objects in the exits list stored as a property of the room. The intent here is to allow for more sophisticated matching algorithms to be implemented. One might even go so far as implementing a fuzzy matching scheme, to allow for player misspellings. If a successful match is made, this signifies that an exit with the name exit leads from this room. It's object number is returned. If more than one match is found the value $ambiguous_match is returned. If no match is found, the value $failed_match is returned.

Verb: num add_exit (obj exit)
This verb is used to add exit to the list of exits leading out of the room. This verb, and the :match_exit verb provide the interface to the room exits list. The way in which exits are stored, removed and matched has been separated from the interface so that different implementations of the exits concept can be used in different sub classes of the $room class.

If it is not possible to add exit to the room's exit list (normally because the object that invoked the verb does not have the required permission) then the verb returns `0'. Otherwise, a successful addition returns `1'.

Verb: none tell_contents ()
This verb tells us what things are visible in the room. It goes through the contents list of the room, and if it is not dark, prints the name of the object in a nicely formatted way. Three different formats are available depending on the value of the ctype property of the room. These are best illustrated by example.

Consider the a room in the LambdaCore database. With a ctype value of three (the default), the tell_contents verb produces the following output:

You see a newspaper and a fruitbat zapper here.
Wizard is here.

This format provides the separation of player objects from other objects, and provides the list in a way that fits in with the idea of a virtual reality. It is easy to read, and looks natural.

If the ctype value is changed to 2, the following is printed:

You see Wizard, a newspaper, and a fruitbat zapper here.

This format treats players and objects the same, and is useful if you wish to hide the fact that an object is not a player, or vice versa.

With a ctype value of one, the following is seen:

Wizard is here.
You see a newspaper here.
You see a fruitbat zapper here.

This format provides the advantage of having each item on a separate line, although it does mean that rooms with a large number of objects in might have excessively long contents lists.

Finally, with a ctype of zero, the following is seen:

Contents:
  Wizard
  a newspaper
  a fruitbat zapper

This is the sort of listing obtained in traditional TinyMU* games. It benefits from clarity, but is not as natural as any of the other forms.

If a value of ctype is set that is outside of the range zero thru three, then no contents list is printed. This can be useful if you want to handle the room contents listing as part of the description of the room. Also, if the dark property of a room is set to a non-zero value, then no contents list is printed.

As usual, this verb can be overridden to provide special effects. For example, you could apply a filter so that certain objects do not appear in the printed contents of a room, even if they appear in the contents list. This can be use to hide objects, for example, as part of a puzzle, or to vary how objects are seen, for example if you are looking through water at something.

Verb: obj match_object (string name)
This is the verb used to search the player's locale for an object that has the name or pseudonym name. This verb handles mapping of me to the player object, here to the player's location as well as the use of #<number> to refer to a particular object. If none of these cases match, the verb searches the room contents and the players contents (or possessions) for a match. If a match is found, then the unique object number is returned. If name matches more than one object, then $ambiguous_match is returned. If no match is found, then $failed_match is returned.

The verb :match_object is the one to use to map names of objects to object numbers, when referring to objects that the player is able to see in his current location. This includes objects that the player might be carrying, but does not include objects that are contained in other objects.

Verb: none @exits ()
This verb is a player command used to print a list of the exits in a room. It can only be used by the owner of the room. The verb simply runs through the list of defined exits, stored in the property exits, and prints the exit name, object reference number, destination name, and exit aliases.

Verb: none look_self ()
This verb overrides the $root_class definition of the verb :look_self in order to provide a fuller description of a room than the description property gives. This verb prints the room name, followed by the room's description property, and then the list of contents of the room, using the room's :tell_contents verb. This is what the player would see if he was looking at the room.

The description property of the room is actually printed by using the pass() primitive to invoke the parent verb :look_self). Changes in the way an object's description is stored by the root class are invisible to this verb, because of the way pass is used.

Verb: num accept (object thing)
This verb overrides the $root_class definition. The $room_class definition provides for a flexible scheme using various different criteria. The idea is to allow the builder flexibility in preventing objects from moving into the room. The following code shows how the $room:accept verb decides whether to allow thing to enter the room or not.
what = args[1];
return this:is_unlocked_for(what) && 
       (this.free_entry || 
       (what==this.blessed_object&&task_id()==this.blessed_task) ||
       what.owner == this.owner || 
       (typeof(this.residents) == LIST && what in this.residents));

Starting at the top of the conditional expression, we see the locking condition being checked. If the room lock forbids this object to enter the room, then the :accept verb returns zero.

If this is not the case, then we consider the value of the free_entry property. If this is set to a non-zero value, then the object is allowed to enter the room. This is used to provide public places, where anything and everything is allowed to enter. The default value of this property is 1.

If the object has been blessed for entry into this room, and the task that is moving the object is the same as the task that requested the blessing, then the object is allowed to enter. Refer to the :bless_for_entry verb for further details on the concept of blessed objects.

If the owner of an object is the owner of a room, the object is allowed to enter. This is a general rule used as a catch-all case. It can be overridden by specifically locking against an object, but as a rule, it is desirable for objects owned by the room owner to be allowed to enter.

Finally, if a residents list is defined in the room, and the object is in the list, then it is allowed to enter. This concept can be used to define a set of objects that are allowed to enter the room without specifying a long and complex locking condition.

Verb: num add_entrance (obj entrance)
This verb functions similarly to the :add_exit verb, but applies to $exit objects that lead into the room. If we imagine an $exit object as a flexible tube connecting two rooms, then the concept of specifying both ends of the tube seems natural. It is not usual to search the entrance list for a match, as you would with the exit list, but the concept of an entrance is included to cover unexpected cases.

If it is not possible to add entrance to the room's entrance list (normally because the object that invoked the verb does not have the required permission) then the verb returns `0'. Otherwise, a successful addition returns `1'.

Verb: none bless_for_entry (obj thing)
This verb is called by an exit to allow an object special permission to enter a room. Two properties on the room store thing and the task_id of the calling task. The idea behind blessed objects is to allow an object temporary permission to enter. The permission is only granted if the request is made by an object that is an entrance into the room.

The idea here is that a normally inaccessible room can be entered providing you use an exit that leads into the room. In addition, the task ID of the task that asked for the blessing is stored, so that there is no way an object can become blessed, and then later gain entry to the room. The object being blessed is only allowed to enter once per blessing. Once the object has moved into the room, it's blessed status is removed by resetting the blessed_object property in the room to $nothing.

Verb: none @entrances
This verb is a player command used to list the entrances to the player's current location. Only the owner of a room may list it's entrances. For every object kept in the room's entrances list, the exit name, object reference number and aliases are displayed to the player.

Verb: none go (list args)
The verb is a player command used to move from one room to another. One special feature of this command is that it allows the player to string together a number of different movement commands into one use of the `go' command. This can save typing when we know where we want to go. The code for this verb is shown below:
for dir in (args)
  exit = player.location:match_exit(dir);
  if (exit < #0)
    player:tell("Go where?");
  else
    exit:invoke();
  endif
endfor

This simply moves through the list of exits given in args, matching the exit name in the current room, and invoking the exit if a valid match is found.

Verb: none look ()
This verb is a player command used to look at various things in the player's current location. It can be used meaningfully in other verbs, however, if the verb is called with no arguments. In this case, it calls the :look_self on the room which the verb was invoked on. You could use this verb to print the description of a room you are not in, but it is stylistically better to use the :look_self() verb of the room.

If a preposition is supplied, via this verb being invoked as a command, and the preposition is not `on' or `in', then the verb attempts to match the direct object with something in the room. If the match succeeds, the :look_self verb of the matched object is called to tell the player what the object looks like.

If the preposition is `on' or `in', then the player wishes to look inside a container of some sort, be it a member of the $container class, or in a player's inventory, for example. An attempt is made to match the indirect object with something in the room. If it succeeds, then an attempt is made to match the direct object with something inside the container previously matched. If this final match is made, the :look_self verb of the matched object is invoked to print it's description.

If the direct object is the empty string, `""', then the container's :look_self verb is called to print it's description.

Any ambiguous or failed matches produce suitable error messages.

Verb: none announce_all (list @args)
This verb is another general purpose verb used to send a message to every object in the room. It is used for messages that we wish everyone to see, with no exceptions.

Verb: none enterfunc (obj thing)
This verb is invoked by the LambdaMOO server when an object moves into a room, as part of action of the move primitive. The actions taken for a room are very straightforward. If thing is a player object, then we tell the player where s/he has moved into using the $room:look_self verb on the room. If the object is the blessed_object for this room, then the blessed_object property for the room is reset to $nothing. For further details on blessed objects, refer to the description of $room:bless_for_entry.

Verb: none exitfunc (obj thing)
This verb is invoked by the LambdaMOO server when an object is moved out of a room, as part of the action of the move primitive. The action defined for the $room class is to do nothing.

This verb, and the :enterfunc verb, can be used for a variety of effects that need to take note of objects moving in and out of rooms. For example, consider a torch object that casts light on it's surroundings. When the torch is moved out of a room, the light that is casts moves with it. This can be tackled using the room's exitfunc, which could check if the object leaving is a torch, and if it is, the room could become dark. Similarly, when the torch enters a room, the enterfunc can be used to detect this, and brighten the room accordingly.

Verb: num remove_exit (obj exit)
This verb performs the opposite function to the :add_exit verb. It removes exit from the room's list of exits. If it is not possible to remove exit from the room's exit list (normally because the object that invoked the verb does not have the required permission) then the verb returns `0'. Otherwise, a successful addition returns `1'.

Verb: num remove_entrance (obj entrance)
This verb performs the opposite function to the :add_entrance verb. It removes entrance from the room's list of entrances. If it is not possible to remove entrance from the room's entrance list (normally because the object that invoked the verb does not have the required permission) then the verb returns `0'. Otherwise, a successful addition returns `1'.

Verb: none @add-exit
This is a player command used to add an exit to the current room. This is normally used when someone else has created an exit they want to lead out of a room you own. The verb matches the direct object string with an object in the room to get the object reference number for the exit. If the object found is not a descendant of the $exit object, the verb is aborted with an error.

Otherwise, if the destination of the exit is readable and leads to a valid room, an attempt is made to add the exit using the room's :add_exit verb. If this fails, a suitable error message is sent to the user.

Verb: none @add-entrance
This is a player command used to add an entrance to the current room. This follows much the same sequence as for the `@add-exit'. An attempt is made to match the direct object supplied with an object in the room. If this fails, the verb is aborted with a suitable error message.

Otherwise, if the object found is a descendant of the $exit class, then the exit is checked to make sure it goes to this room. If this is the case, then the exit is added as an entrance using the room's :add-entrance verb.

Verb: none recycle ()
This verb is called by the LambdaMOO server when a room is recycled. When a room is recycled, something has to be done with the room's contents, both players and objects, to stop them ending up in $nothing. This is done by trying to move everything home. The code to do this is shown below:
for x in (this.contents)
  if (is_player(x))
    if (typeof(x.home) == OBJ && valid(x.home))
      x:moveto(x.home);
    endif
    if (x.location == this)
      move(x, $player_start);
    endif
  elseif (valid(x.owner))
    x:moveto(x.owner);
  endif
endfor

The main loop goes through the complete contents list of the room. If the object is a player, then it is moved home, using it's :moveto verb, or to the $player_start room, using the move() primitive. All other objects are moved to the inventories of their owners.

Note that if the attempt to move an object fails, then no action is taken. The server will place all objects still in the room into $nothing when the room is recycled.

Verb: none @lastlog ()
Commabd: none @lastlog (player)
This verb is a player command used to list the times that players last connected to the MOO. If player is supplied, by invoking the verb as a command, only the last connect time for that player is shown.

If no argument is supplied, the verb uses the players() primitive to return a list of all players in the database. It then looks at each players last_connect_time property, and places a particular list, depending on whether the player conncted within the last day, week or month or longer.

When all players have been placed in one or other of the lists, they are printed out, along with the exact connect time as found in the player's last_connect_time property.

Verb: none n*orth/e*east/w*west/s*south ()
Verb: none northwest/northeast/southwest/southeast ()
Verb: none up/down ()
In general, when a player wants to move out of a room using an exit, the recognition of the exit name is done by the :huh and :huh2 verbs for the room. However, to cope with the most common cases, verbs are defined for each of the compass directions and up and down. The code for these verbs is the same, and is shown below as an example:
exit = this:match_exit(verb);
if (valid(exit))
  exit:invoke();
elseif (exit == $failed_match)
  player:tell("You can't go that way.");
else
  player:tell("I don't know which '", verb, "' you mean.");
endif

What this does is check to see if the exit is defined for the room. If it is, then the exit is :invoked. If not, a suitable message is sent to the player.

This case is included simply to speed up processing for certain common cases.

Verb: none explain_syntax (string verb)
This verb is used to provide helpful information to the player should s/he fail to enter a command correctly. It is called by the :huh2 verb as a last resort to process the player command. The verb follows the parser's search path for verbs looking for a match with verb. If one is found, this means that the parser rejected the match because the argument's did not match.

Having established this, :explain_syntax compares the user input to the verb argument definition, and prints some explanatory text to try and help the player enter a correct command. This verb usually catches mistakes such as entering the wrong preposition, or forgetting to use an indirect object. It is provided as part of the $room class to allow other room subclasses to provide more specific help for certain verbs defined in their rooms, if the user should make an error trying to use one of them.

Verb: none huh2 (list args)
This verb is called by the huh verb to handle commands that the parser couldn't sensibly pass to another object. In the case of a room, the verb covers a number of different possibilities. First, the sentence is checked to see if it matches any of the exits that lead out of the room. This is done using the match_exit verb. If a matching exit is found then the :invoke verb for the exit is called, which causes it to be activated. This provides for a flexible approach to handling exits.

If this does not produce a sensible match, then the verb is treated in one of two ways. If it starts with an `at' (@) character, then we attempt to match the remainder of the verb in the sentence with a message field on the direct object. A message field is a property whose name ends in "_msg". If a match is found, then this is treated as a field setting command. This approach is used to avoid having to define a verb for every message field that can exist on an object. It also allows players to add extra message fields to objects simply by ending the name of the property with "_msg". For example, if you define a message on an object called foobar_msg then you can set the message with the command

@foobar <object> is <message text>

If the verb does not start with an `at' (@) character, then we call the :explain_syntax verb. This tries to match the verb with a verb defined on the player, room, direct object (if any) and indirect object (if any). If a match is found, the syntax of the verb (ie, number and type of arguments and prepositions) is checked, and a useful message sent to the player.

This approach is taken to provide flexibility. By not placing this sort of code within the server, the LambdaMOO administrator has the choice of changing the way erroneous commands are handled. One application could be an augmentation of the basic huh action to log failed commands in a list somewhere. This mechanism, long used in other MUDs, can provide a builder with an idea of what other players have tried (and failed) to do in his or her areas.

Verb: none @eject object
This verb is a player command used to remove unwanted objects from places that you own. It can be used to remove objects, which are sent to $nothing and players, which are sent to $player_start.

The verb first matches the supplied object with something in the room. If a match is found, and the player controls the current room, then the ejection messages are printed, and the victim's :eject verb is invoked to actually remove the object.

Verb: string ejection_msg ()
Verb: string oejection_msg ()
Verb: string victim_ejection_msg ()
These three verbs return the messages used by the @eject mechanism. The code for the verb is shown below, as it illustrates how to deal with multiple messages with a single verb:
set_task_perms(caller_perms());
return $string_utils:pronoun_sub(this.(verb));

Note the permission setting at the start of the verb. This is necessary because the verb is owned by the Wizard, and hence would have permission to read the ejection messages on any object. By restricting the permissions of the verb to those of the verb that called it, this verb restricts who may access the ejection messages on objects.

The following properties are defined for the $room class:

Property: victim_ejection_msg
This is a string containing the message sent to objects that are ejected from a room by the owner. It is sent to the victim by the room's :@eject verb.

Property: ejection_msg
This is a string containing the message sent to the owner when they eject an object from the room. It is printed by the room's :@eject verb.

Property: oejection_msg
This is a string containing the message sent to everyone else in a room when the owner ejects an object. It is printed by the room's :@eject verb.

Property: residents
This is a simple list of objects that have their homes in this room. It is examined by the :accept verb on the $room class as one of the criteria used to determine whether an object is allowed to enter the room or not. The @sethome verb could be enhanced to include players as residents when their home is set to be a particular room.

Property: free_entry
If this is set to a non-zero value, then the room is considered public and any object is allowed to move in to the room. Setting the value to zero will stop objects that do not meet any of the other acceptance criteria from entering. Refer to the $room:accept verb for further details on these criteria.

Property: entrances
This is a simple list of the exits that lead into this room. It is manipulated by the $room:add_entrance and $room:remove_entrance.

Property: blessed_object
This contains the object number of the object that has been blessed for entry into this room.

Property: blessed_task
This contains the task ID of the task that requested an object be blessed for entry into the room.

Property: exits
This is a simple list of the exit objects that lead out of this room. It is manipulated by the $room:add_exit, $room:remove_exit and $room:match_exit verbs.

Property: dark
If set to a non-zero value, then this property inhibits display of the contents of a room when the $room:look_self verb is invoked. It can be used, for example, in rooms where a large number of objects are likely to be located, that you do not wish to see (for instance, a limbo type room, where sleeping players and lost objects reside.). If the dark is set to zero, then the contents of a room are displayed when $room:look_self is invoked.

Property: ctype
This property determines the format of the room contents list, as printed by the verb $room:look_self. It can take a value between `0' and `3'. An example for each of the contents formats is given below.
0: Traditional TinyMU* format.
Contents: Wizard a newspaper a fruitbat zapper
1: Enhanced TinyMU* format.
Wizard is here. You see a newspaper here. You see a fruitbat zapper here.
2: "All-in-one" format.
You see Wizard, a newspaper, and a fruitbat zapper here.
3: The default, objects and player descriptive format.
You see a newspaper and a fruitbat zapper here. Wizard is here.

The Thing Class

The $thing defines verbs and properties for objects that exist in the virtual world. This class includes everything that is not a player, room or exit. For example, the classes $container and $note are descended from the $thing class. The two basic operations that can be performed on a thing are picking it up and putting it down. Two verbs are defined for the $thing class to implement this idea. Configurable messages are used, so that someone using an object of this class can set the text printed when an attempt is made to take an object. No messages are available for the case of dropping an object.

Verb: none g*et ()
Verb: none t*ake ()
One or the other of these verbs is invoked when a player tries to take possession of an object i.e., pick it up. The code involved is fairly straightforward. It checks to see if the player already has the object, and prints a suitable message if this is the case. If not, then the :moveto verb on the object is invoked. If this results in the object moving into the player's inventory, then the take_succeeded messages defined on the object are printed. If the :moveto failed, then the take_failed messages for the object are printed.

This scheme allows you to add extra conditions to restrict whether a player can take an object or not. For example, you may place a notion of strength onto a player, and add weight to objects. If an object is too heavy for a player to lift, then the object cannot be taken by the player. This sort of condition should be added to the :take verb for the object.

Verb: none d*rop ()
Verb: none th*row ()
One or the other of these verbs is invoked when a player tries to place an object in the room s/he is currently located, i.e., when the player tries to drop the object. Again, the code is fairly straightforward. If the object is not located on the player, then a suitable message is sent to the player telling him/her to check his/her pockets. If the player does possess the object, and the current location :accept verb indicates that the room will allow the object to be dropped, the object :moveto verb is invoked to move the object from the player's inventory to the contents list of the player's location. Suitable messages are printed to inform the player that the action succeeded, and to tell other people in the room that the object has just been dropped.
Verb: none moveto (obj where)
This verb should be used to move an $thing object from one location to another. It checks to see that where is a valid object, and that the lock on wher permits the object to enter. If this is the case, then the $root_class:moveto verb is invoked to actually move the object, using pass(where).
Verb: string take_failed_msg ()
Verb: string take_succeeded_msg ()
Verb: string otake_failed_msg ()
Verb: string otake_succeeded_msg ()
Verb: string drop_failed_msg ()
Verb: string drop_succeeded_msg ()
Verb: string odrop_failed_msg ()
Verb: string odrop_succeeded_msg ()
These eight verbs are used to access the message fields used by a $thing object. In each case, the value returned by the verb is a a version of the corresponding "_msg" property of the object, with standard pronoun substitutions performed. This allows the messages to be more flexible than simple constant text strings. If extra complexity were to be added to the messages, then these verbs should be overridden.

The default values of these strings are shown below:

drop_failed_msg
"You can't seem to drop %t here."
drop_succeeded_msg
"You drop %t."
odrop_failed_msg
"tries to drop %t but fails!"
odrop_succeeded_msg
"drops %t."
otake_succeeded_msg
"picks up %t."
otake_failed_msg
""
take_succeeded_msg
"You take %t."
take_failed_msg
"You can't pick that up."

The following properties are defined for the $thing class. They are the messages used by the $thing:take and $thing:drop verbs in various situations. All of these message can use standard pronoun substitutions.

Property: otake_succeeded_msg
This message is the text sent to other people in the thing's location when the thing is taken by another object. The default value of this string is `picks up %t.'

Property: otake_failed_msg
This message is the text sent to other people in the thing's location when an attempt by another object to take the thing fails. The default value of this string is `'

Property: take_succeeded_msg
When an object successfully takes a thing, this message is sent to inform the object of success. The default value of this string is `You take %t.'

Property: take_failed_msg
When an object unsuccessfully tries to take a thing, this message is sent to tell the object that the attempt failed. The default value of this string is `You can't pick that up.'

Property: odrop_succeeded_msg
This message is the text sent to other people in the thing's location when the thing is dropped by another object. The default value of this string is `drops %t.'

Property: odrop_failed_msg
This message is the text sent to other people in the thing's location when an attempt by another object to drop the thing fails. The default value of this string is `tries to drop %t but fails!'

Property: drop_succeeded_msg
When an object successfully drops a thing, this message is sent to inform the object of success. The default value of this message is `You drop %t.'

Property: drop_failed_msg
When an object unsuccessfully tries to drop a thing, this message is sent to tell the object that the attempt failed. The default value of this string is `You can't seem to drop %t here.'

The Exit Class

The $exit class is the other type of object used to construct the fabric of the virtual world. You can imagine an exit to be a flexible tube connecting two $room objects. Each $exit object goes in one direction only. It leads from a source object to a destination object. Note that it takes no virtual time to traverse an exit. When an object moves through an exit, it moves from one room to another instantaneously.

The verbs defined for the $exit class are fairly simple and obvious. Several messages are defined as properties on an exit. These are pronoun substituted and printed when the exit is invoked, under various conditions.

Verb: none invoke ()
This verb is used to trigger an exit. In the $room class, when a player elects to move through an exit, this verb is called to move the player through the exit. The code for this verb is very simple. It calls the exit's :move verb, with the player object as an argument.

This is the verb to use for moving players through exits. It does not allow objects to be moved. For that, a direct call to the exit's :move verb is needed, with the object you wish to move through the exit as an argument.

Verb: none move (obj thing)
This verb is used to move thing through the exit. It provides a general mechanism for moving any sort of object through the exit, not necessarily just players. The code for this verb performs a number of actions. First, the lock on the exit is checked to see if thing is allowed to use the exit. If this is not the case, the nogo_msg and onogo_msg text is sent to thing and everyone else in thing's location, respectively.

If the object is allowed to use the exit, it is blessed for entry to the destination room. This is done to ensure that the object will be accepted by the destination room. It provides a way to stop objects moving into a room by any means other than an exit leading into the room. By simply prohibiting all objects from entering the room, the only way in is then to use an exit that leads into that room.

If the object is accepted by the room, determined using the $room:accept verb, then the leave messages are printed to thing and the other people in the room. Then thing:moveto is invoked to move the object from the current room to the destination of the exit. Once this has been done, the arrive messages for the exit are printed out to thing and the destination room's occupants.

Verb: none recycle ()
This verb is defined to allow an exit to be tidily removed from the database. The exit is removed from the entrance and exit lists of the destination and source rooms respectively, if the caller of this verb has permission to do so. This is done using the $room:remove{entrance|exit} verbs.

Verb: none leave_msg ()
Verb: none oleave_msg ()
Verb: none arrive_msg ()
Verb: none oarrive_msg ()
Verb: none nogo_msg ()
Verb: none onogo_msg
These verbs return a pronoun substituted version of the corresponding properties stored on the exit object. They are used by $exit:move.

The following properties are defined for the $exit class. Most of them are messages used when the exit is invoked.

Property: source
This is the object that the exit leads out of. If the exit has been created using the correct verbs, the exit object should be in the exits list of the source room object.

Property: dest
This is the object that the exit leads to. If the exit has been created using the correct verbs, the exit object should be in the entrances list of the dest room object.

Property: nogo_msg
This is the message printed to an object if it is unable to move through the exit.

Property: onogo_msg
This is the message printed to everyone in an object's location if it is unable to move through the exit.

Property: arrive_msg
This is the message printed to an object using an exit when it arrives in the destination room.

Property: oarrive_msg
This is the message printed in the destination room of the exit when something is moved through it.

Property: oleave_msg
This is the message printed in the exit's source room when an object moves through the exit.

Property: leave_msg
This is the message printed to an object using the exit as it leaves the source room.

The Player Class

The player class is the one of the basic classes of the virtual world. A player object is the same as any other object, except that has it's player bit set. This allows the server to connect a user to that object. A number of player commands are defined as verbs of the $player class, as well as other useful functions.

Verb: none g*et ()
Verb: none take ()
This verb is called in the situation when another object tries to get or take a player. Given that this is a fairly nonsensical thing to do, it is not allowed. Suitable messages are sent to the object that invoked the action, and the player object.

Verb: none i*nventory ()
This verb is used to tell a player what s/he has in his/her pockets. The code for the verb provides the best documentation, so it is printed below. Note the use of the thing:title verb to get the name of an object.
if (length(player.contents))
  player:tell("You are carrying:");
  for thing in (player.contents)
    player:tell(thing:title());
  endfor
else
  player:tell("You are empty-handed.");
endif

Verb: none wh*isper ()
This verb is used to send secret messages between two players, as if they were whispering to each other. The way this works is slightly the reverse of what might be expected, because the :whisper verb on the person being whispered to is the one that is invoked. The message, referred to by the dobjstr, is printed to the recipient, with suitable text surrounding it to indicate that is it a whisper.

Verb: none look_self ()
This verb overrides the $root_class definition to provide an indication to other players of whether this player is currently active or not. It uses pass() to allow the parent class to print a description, and then looks at the connected_players() list to determine if this player is currently connected. If not, then the text
He is sleeping

is printed. If the player is connected, and has been idle for less than 60 seconds, then the string

He is awake and looks alert

is printed. If the player is connected, but has been inactive for more than 60 seconds, the string

He is awake, but has been staring off into space for X

is printed, where X is an indication of the time the player has been inactive. The gender pronoun inserted is taken from the pronoun list for the player. This means it can vary with the gender of the player object.

If the player is carrying any objects, a simple list of these is printed.

Verb: none @gag (args)
The concept of gagging is fairly simple to understand. If there is a player or object you do not wish to see any output from, then you can place the player or object into your gag list. If any output is sent to you from that object, using it's :tell verb, then it is ignored, and not printed on your terminal screen.

Two gaglists are maintained: one for players, in the property gaglist and one for objects, in the property object_gaglist.

Three verbs are used to maintain and observe the list of objects that are in the gag lists. The @gag verb is used as a player command to add objects to the gag lists. The code for this is fairly straightforward, and is included below:

if (player != this)
  player:tell("Permission denied.");
  return;
endif
victims = $string_utils:match_player(args);
if (!victims)
  player:tell("Usage:  @gag <player or object> 
                    [<player or object>...]");
  return;
endif
gagplayers = gagobjs = {};
for i in [1..length(args)]
  if (valid(victims[i]))
    gagplayers = {victims[i], @gagplayers};
  elseif (valid(o = player.location:match(args[i])))
    gagobjs = {o, @gagobjs};
  elseif (tonum(o = toobj(args[i])) && valid(o))
    gagobjs = {o, @gagobjs};
  else
    player:tell("Could not find ", args[i], " as either a player or an object.");
  endif
endfor
changed = 0;
for p in (gagplayers)
  if (p in player.gaglist)
    player:tell("You are already gagging ", p.name, ".");
  else
    changed = 1;
    player.gaglist = setadd(this.gaglist, p);
  endif
endfor
for o in (gagobjs)
  if (o in player.object_gaglist)
    player:tell("You are already gagging ", o.name, ".");
  else
    changed = 1;
    player.object_gaglist = setadd(this.object_gaglist, o);
  endif
endfor
if (changed)
  fork (0)
    this:("@listgag")();
  endfork
endif

Note that you can only manipulate your own gag list. Other objects cannot change your gag list. Another interesting point is the call to @listgag, after the new objects have been added to the gag list, to print the current gag list.

The code first tries to match the argument list against the players in the database, using $string_utils:match_player(). Then, for each argument given, if a match was not found using that method, a match for an object in the room is tried, using the utility routine $string_utils:match_object(). If this fails, the argument is rejected.

This results in a list of objects to be added to the player's gag lists. Any objects already in the player's gag lists are removed from the to do list. If this yields an empty to do list, the command is aborted. Any objects that are not already in the gag list are added to it.

Finally, this:@listgag is called to print the list, if it has changed.

Verb: none @listgag ()
This verb is used as a player command to list the objects in the player's gag lists. If the gag lists are not empty, a list of the names of the players in the gaglist property on the player, and the objects in the object_gaglist property are produced.

The verb uses a test based on the callers() primitive, to determine if it is being called by another verb, or invoked by a player as a command. If callers() returns a null list (and hence is not TRUE, then the verb is being invoked as a player command. This affects the text printed by the verb.

In addition, the verb checks through the gag lists of all the player's in the database, to see if the player who invoked the command is listed in anyone else's gag list. If this is the case, a list of the people doing the gagging is printed.

Verb: none @ungag (args)
This verb is used as a player command to remove an object from one of the player's gag lists, if it is a member. The dobjstr is used as the name of the thing to remove from the gag list.

If this name is `everyone' then the player gag and object gag lists are reset to the empty list. Otherwise, if a valid direct object has been referred to, by checking dobj, that is used as the object to gag. Otherwise, an attempt is made to match the dobjstr with something in the player gag list. If no match is found, it is retried with the object gag list. If this fails, the command is aborted with an error message.

If a valid match is found, it is removed from the relevant list, and the player informed. @listgag is used to print the list after the operation has been completed.

Verb: none news ()
This is a very simple verb used as a player command to print out the current MOO news. It makes a simple call to the verb $news:read to actually perform the reading task.

Verb: none @gripe (args)
A gripe is a player complaint or observation that is sent, using MOO mail, to all the administrators in the game. It is intended to provide a way to report problems with the MOO in a high-priority way that will attract the attention of the people who can do something about it. A good example of the use of a gripe is to complain about a bug in one of the core classes, or maybe even a request for something to be added.

The implementation of the gripe concept involves a property on the System Object called $gripe_recipients. This is a list of all the players who will be mailed the @gripe message. When a player types in @gripe they are taken to the mail room to enter their message. Any text entered on the line with the @gripe command is taken to be the subject of the gripe message. When the message is finished and sent, it is received by all the people on the $gripe_recipients list.

Verb: none gi*ve ()
Verb: none ha*nd ()
This verb is a player command used to exchange objects between players. It performs a :moveto on the direct object to the inventory of the indirect object. If, after the move, the object is still in the possession of the donor, then it is obvious that the recipient has rejected the gift. If this is the case, a suitable message is printed to the doner.

Verb: none ? help info*rmation ()
This verb is a player command used to activate the help system. It is described more fully in the section on the help system.

Verb: none @password ()
This verb is a player command used to change a player's password. A player's password is stored in a property on the player called, surprisingly enough, password. The crypt() primitive is used to store the password in encrypted form, using the standard UN*X encryption algorithm. Note that you need to know your old password in order to change it, unless a password has not been previously set for this player.

Verb: none @gender (string gender)
This verb is used to set the gender of a player object. Without any arguments, it prints the player's gender, currently set pronouns and the available genders stored on $gender_utils.genders.

If a gender is given as the argument, gender, then the $gender_utils:set verb is called to actually change the player's gender pronouns. If this verb does not return an error, then the gender of the player is set to the full gender name which is returned. $gender_utils:set takes care of setting the correct pronouns.

If an error is returned when trying to set the player's gender, this could indicate that permission to change the pronouns was denied, or some other problem existed. If a value of E_NONE is returned by $gender_utils:set then the gender of the player is set, but the pronouns are left unchanged.

The gender of a player is used in the string_utils:pronoun_sub verb to insert the appropriate pronouns in places where `%' substitutions have been used. When the gender of a player is changed, it results in a set of 8 properties being assigned on the player, one for every type of possible pronoun substitution. A further property, containing the gender of the player, is also set, for example, to either "male", "female", or "neuter", depending on the argument given to the @gender command.

Verb: none page (list args)
This verb is a player command used to send messages between players who are not physically located in the same room in the virtual world. You can imagine a page to be a worldwide form of whispering. Without an argument, a message like
You sense that blip is looking for you in The Venue Hallway.

is sent to the recipient of the page. If an argument is given, it is treated as a message to send to the other player. This results in the recipient getting a message like

You sense that blip is looking for you in Hallway.
He pages, "Hello - are you busy ?"

Paging is used primarily to attract the attention of a player, or to pass short messages between players in different locations. It is not intended to be used for conversation.

If a player name has been given as an argument, the :page verb first tries to match the first argument with a player name, using $string_utils:match_player. If a match is found, then there are two possibilities. Firstly, if the player is not connected, a pronoun substituted version of the string returned by that player's :page_absent_msg verb is printed to the sender, and the verb is aborted.

Otherwise, if the recipient is connected, we send him/her the string returned by the sender's :page_origin_msg. We then check to see if, optonally, `with' followed by a message is part of the argument list for the verb. If so, then the message is extracted from the argument list and sent to the recipient, suitably pronoun substituted. The string returned by the recipient's :page_echo_msg verb is printed to the sending player.

An interesting piece of coding is used to stop the line containing the message from duplicating the sender's name if it has already been sent as part of the :page_origin_msg. For example, if blip page's Ezeke, Ezeke might see the following:

You sense that blip is looking for you in The Venue Hallway
He pages, "Hello"

which would be better than something like

You sense that blip is looking for you in The Venue Hallway
blip pages, "Hello"

The code in question is shown below:

who:tell($string_utils:index_delimited(pagemsg, player.name) ? 
           player.psc | player.name, " pages, \"", msg, "\"");

Here, the $string_utils:index_delimited() verb is used to check if the player's name occurs in the string we sent to the recipient as pagemsg. If it does, then we print the player's subjective pronoun, capitalised. If it doesn't, we print the player's name.

Verb: none @rename ()
This verb is a player command used to change the name and aliases of an object or verb. It first tries to parse the supplied direct object as a verb reference. If this succeeds, then it tries to match the object, and then the verb name. If both are found, the indirect object string is used to set verb name.

If the direct object string cannot be parsed as a verb, then a match is attempted using the string as an object name. If this succeeds, then $building_utils:set_names() is used to set the name and aliases of the matched object.

Any permission errors, ambiguous object specifications or syntax errors are flagged appropriately.

Verb: num accept (obj thing)
This verb is used to determine if a player will allow thing to be moved into his/her inventory. The verb defined for the $player class allows anything that is not a player to be moved into the player's possession. You could override this verb to restrict the sorts of things you would want other people to be able to place on your person.

Verb: none tell ()
This verb should be used to send a message to a player. The $player:tell filters messages in two different ways, as show below. Remember that the player referred to in the code is the player sending the message. this refers to the player receiving the message.
if (!this:gag_p())
  if (this.paranoid == 2)
    z = this:whodunnit(listappend(callers(), {player, "", player}), 
               {this}, {})[3];
    pass("(", z.name, " ", z, ") ", @args);
  else
    pass(@args);
    if (this.paranoid == 1)
      this.responsible = listappend(this.responsible, 
          {listappend(callers(), {player, "<cmd-line>", 
	                            player}), args});
      while (length(this.responsible) > this.lines)
        this.responsible = listdelete(this.responsible, 1);
      endwhile
    else
      this.responsible = {};
    endif
  endif
endif

The verb $player:gag_p returns true if the player sending the message is in the recipient's gag list. For this verb, the output from any gagged player is ignored, and not printed to the recipient's terminal.

If the paranoid level of the recipient is `2', this means that they wish to see who has sent them a message. The $player:whodunnit verb returns the object reference of the player that sent the message. This is prepended to the message text, which is then printed to the player.

If the paranoid level of the recipient is `1', then the message and it's originator are stored in the property list responsible on the player. The list is kept to player.lines length, at most. This option is used for later processing by the @check command.

Verb: list whodunnit (list callers, list trust, list mistrust)
This verb runs through the list of callers until it finds an object reference that is not a wizard, is not in the list trust, or is in the list mistrust. The verb is used by $player:tell to locate the originator of a message. It returns a list of three elements, in the same format as that returned by the callers() primitive:
{this, verb-name, programmer}

where this is the initial value of the variable this in that verb, verb-name is the name used to invoke the chosen verb, and programmer is the player with whose permissions that verb is running.

Verb: num gag_p ()
This verb returns `TRUE' if the current value of the player variable is in the gag list of the object indicated by the variable this, or if a non-player object mentioned in the gag list if the first elements of the verbs callers() list.

Verb: none home ()
This verb is normally invoked by the player as a command. The home of a player is the room where s/he goes to when they disconnect. Unlike some flavours of MUD, MOO does not cause you to lose all your possessions if you go home.

The :home verb performs a simple sequence. It first checks whether the player is already at home, and tells him/her so if this is the case. Secondly, a check is made that the player's home (stored in the home property on the player, is a valid object. If this is not the case, the verb sets the home to the default, $player_start, and stops with a suitable message.

Having decided that the player has a valid home s/he is not already in, the verb uses $player:moveto to send the player to the home location. If this doesn't work - checked by comparing the player's home with the player's location after the move - then for some reason the player's home location has not allowed him/her to enter. A suitable message is printed, and no further action is taken.

Verb: none @sethome ()
This verb is a player command used to set the player's home to be the his/her current location. You can only set your home to a room if the room will accept you, determined by checking the room's :accept verb.. This allows builders to restrict which rooms may be used by players as their homes. If the room does not allow the player to set it as his/her home, a suitable message is printed to inform the user of this fact. Otherwise, the player's home property is set to the player's current location.

Verb: none confunc ()
This verb is called when the player connects to the LambdaMOO server. It can be used to perform actions that should be done every time the player logs in to the MUD. This is much the same idea as having a ~/.cshrc or ~/.kshrc file that is activated when you log into a UN*X account. The verb defined for the player class is listed below:
$news:check(this);
for x in (this.messages)
  if (x[1] > this.current_message)
    this:tell("You have new mail.  Type 'help mail' for 
                                          info on reading it.");
    return;
  endif
endfor

This performs a couple of actions. First it calls $news:check to see whether the news has been updated since this player last looked at it. Then it checks through the MOO Mail list on the player to see if any mail has arrived since they were last connected.

You could place a variety of actions into this verb. For example, you may wish to tell your friends when you log in, by sending a suitable message to them if they are connected. Similarly, you may wish to produce a special message in the room you are in when you connect.

Verb: none disfunc ()
This verb is invoked when the player disconnects from the LambdaMOO server. The verb defined for the $player class does nothing. You might choose to override this verb to print a special message when you log out, or perhaps to retrieve some of your possessions.

Verb: none whereis (args)
Verb: none @whereis (args)
This verb is a player command used to locate a player in the virtual world. The code, shown below, allows any player to locate any other player. If no argument is given, a list of the locations of all the currently connected players is printed.
if (!args)
  them = connected_players();
else
  who = $command_utils:player_match_result(
                     $string_utils:match_player(args), args);
  if (length(who) <= 1)
    if (!who[1])
      player:tell("Where is who?");
    endif
    return;
  elseif (who[1])
    player:tell("");
  endif
  them = listdelete(who, 1);
endif
lmax = rmax = 0;
for p in (them)
  player:tell(p:whereis_location_msg());
endfor

If an argument is given, the verb attempts to match with one or more player names. If no valid matches are found, a suitable error message is printed by invoking the verb $command_utils:player_match_result. That verb returns a list. The first element indicates whether any of the elements of the argument list didn't match. The rest of the list contains the objects references that did match.

The verb runs through the list of object references, and reports the string returned by each player's whereis_location_msg verb.

Verb: none @mail ()
Verb: none @rmm*ail ()
Verb: none @send ()
Verb: none @read ()
Verb: none @answer ()
Verb: none @reply ()
Verb: none @renumber ()
Verb: none receive_message ()
Verb: none fix_current_message ()
Verb: none @next ()
Verb: none @prev ()
These functions are player commands used to access the MOO Mail system. They are fully described in the section on the MOO mail system.

Verb: none @quota ()
This verb is a player command used to print a player's current building quota. This is a numerical value of the number of objects that the player may create without recycling anything. Quotas are used to limit the number of objects that can be created, in principle to allow the game administrators to quality control the things that are placed in the database.

With no argument, the player's quota is displayed, taken from the property ownership quota. If an argument is given in the dobjst, it is taken as a player name, and matched to find a player object reference. If one is found, and the user is a wizard, then the value of that player's ownership_quota is returned. Otherwise, a `permission denied' message is returned.

Verb: none @realm (args)
This is a player command used to examine the object hierarchy. The arguments can specify the players whose objects are to be shown, the root object number to start from, and a list of objects to miss from the tree search.

Firstly, the verb parses the arguments, to determine the root to start from, the players whose objects we are intersted in, and any objects that are to be ignored. Any ancestors of the root are printed by a short loop, with the owner appended in square brackets. The verb this:realm2 is called to produce the hierarchical list of objects to printed. A summary of the number of objects in the list, and how many are owned by the player, is printed at the end.

Verb: list realm2 (obj root, list owners, string space, list missing)
This verb puts toegther a number of lines of text indicating the object hierarchy from the root object downwards. Only objects owned by people in the owners list are included. Objects in the missing list are excluded. The verb is called recursively to evaluate the descendants of each node in the tree of objects. The string space is the visual indentation factor used to represent different levels in the hierarchy.

Verb: none @count ()
This verb is a player command used to print the number of objects owned by a particular player. If no player name is given in the dobjstr, then the number of objects owned by the player invoking the verb is printed. In both cases, the verb this:count_2 is called to do the actual counting and displaying.

Verb: none count_2 (num count, num start)
This verb is called to count the number of objects owned by the player indicated by dobj. The verb first checks the current remaining time available for it to execute in. If it is in danger of running out of time, it forks another :count_2 verb to carry on from where it left off. This enables the verb to count lots of objects in a large database.

Foe each object, if it is valid, and the owner is the same as dobj, then the count is incremented. This is performed for every object in the database, from start to the last item.

When all the objects in the database have been looked at, the total is printed.

Verb: num set_name ()
This verb is used to set the name of the player object. It overrides the verb $root_class:set_name to provide some extra checking needed for player objects. This checking basically stops you changing your name to be the same as another player. Note also that spaces are not allowed in player names. If the extra checks are passed, the parent set_name verb is called to actually set the name.

Verb: none @memory ()
This is a player command used to return memory usage statistics for the LambdaMOO server. It uses the memory_usage() primitive to gather usage information, which is then printed in a nicely formatted fashion.

Verb: none announce (args)
Verb: none announce_all_but (args)
This verb is used to call the :announce and :announce_all_but verbs in the player's location, if those verbs are defined, and the player is in a valid location. It is used by noisy objects in player's inventories that wish to broadcast messages to both the player, and others in the surrounding room.

Verb: none @notedit (args)
This is a simple verb used as a player command to invoke the note editor on the argument.

Verb: none @who (list names)
This verb is a player command used to determine who is currently connected to the MOO. If names is given, it is a list of player names to display in the who list. In both cases, the list is sorted, using $list_utils:sort_alist and displayed. Player names, connection times, idle times and locations are displayed. Player name is determined by getting the value of the name property on the player. Connection time is determined by using the connected seconds() primitive. Idle time is determined using the idle_seconds() primitive. The location is determined by the return value of a player's :who_location_msg verb.

A summary of player activity is attached to the end of the list.

Verb: none @typo (args)
Verb: none @bug (args)
Verb: none @suggest*ion (args)
Verb: none @idea (args)
These commands are used register a typo/bug/suggestion/idea with the person who owns the room the player is currently in. If args is given, this is used as the text of the message, and is delivered straightaway to the room owner.

If no argument is given, the player is taken to the mail room to compose a full message. However, if the room the player is in does not have it's free_entry property set, then the verb doesn't move the player to the mail room, as s/he may not be able to reenter the current room after the message has been completed. Similarly, if the $generic editor is a parent of the current room, then the move is not performed. Generally speaking is is not a good idea to be taken to the mail room from within another editor.

Verb: none @quit ()
This verb is a player command used to exit in an orderly fashion from the MOO server. It simply calls the boot_player primitive to disconnect the player.

Verb: none @audit ()
This verb is a player command used to print the objects owned by this or another player. If a direct object is given, this is taken as a player name to audit, otherwise the current value of player is used. In both cases, the this:audit_2 verb is called to do the actual counting and displaying of objects.

Verb: none audit_2 (num count, num start)
This verb is called by the @audit command to print the objects owned by player given in dobj. In a similar way to @count, the verb first checks how much time it has left. If it might run out, then it forks another occurrence of itself to carry on auditing where it left off.

A loop is entered, running from start to the last item in the database. Each object in the database is looked at. If it is valid, and the owner matches the dobj, then the object name and reference number are printed, and the count is incremented.

When all the objects in the database have been covered, the total count is printed out.

Verb: none @eject ()
This verb is a player command used to remove objects from rooms or the player's inventory. The indirect object is used to specify what the direct object is to be ejected from. The special cases of `me' and `here' are caught and handled. Similarly, the case where the direct object is `me' is also handled.

If neither of the special cases match, the direct and indirect object are matched on, to give an object reference to use. Suitable error messages are printed if a match is not found. If matches are found, then a sequence of message printing is started. The indirect object's :victim_ejection_msg verb is invoked, and the returned result printed to the victim. The string returned by the indirect object's :ejection_msg is printed to the player doing the ejecting. The result returned by the indirect object's oejection_msg verb is printed to everyone else in the room.

Finally, the indirect object's :eject verb is called to remove the victim.

Verb: none QUIT ()
This player command used to be the way to disconnect from the MOO. It has been replaced with the `@quit' command. Some rooms, for example editors, define the `QUIT' command. If the room the player is in has a :QUIT verb, it is called. Otherwise, the verb prints a message telling the player to use the `@quit' command.

Verb: none @unlock ()
This verb is a player command used to unlock an object. The direct object string, dobjstr is matched to try and find an object to unlock. If a match is found, the key property is reset to `0'. Any errors are reported to the invoking player.

Verb: none @lock ()
This verb is a player command used to lock an object with a specified key. It first matches the direct object, dobj to get an object reference number. If that succeeds, the $lock_utils:parse_keyexp() verb is called to parse the key expression given for thelock. If that fails, a suitable error message is printed. Othwerwise, the key property of the object being locked is set to the returned value from the parsing verb. Again, any errors are reported to the invoking player.

Verb: none @version ()
This is a player command used to print the current server version number, using the server_version() primitive.

Verb: none @mess*ages ()
This is a player command used to list the possible message properties (those that end in `_msg') on the dobjstr supplied. The names of the messages, along with their current values, are displayed.

Verb: none @sw*eep ()
This is a player command used to list the objects that are capable of receiving any messages sent out from the player in the current room. It gathers a list of the objects in the current room, from the contents property of the player's location. In any element in the list is a connected player, the message
blip (#42) is listening.

is printed, for example.

If an element has a sweep_msg verb defined, the returned string from this verb is printed, prepended by the object's name.

If an element has a tell verb defined, and the owner is not the invoking player or a wizard, then this object is a potential snooper, and is reported by a phrase such as:

The Fruitbat (#999) has been taught to listen by blip (#42).

The verbs `announce', `announce_all', `announce_all_but', `say', `emote', `huh', `huh2' and `whisper' are checked to see if the current room has a definition not owned by the invoking player or a wizard. If any of these are found, a message such as:

The Venue Hallway (#1234) may have been bugged by blip.

if the player's location was the Venue hallway.

If no potential bugs are found, the the message `Communications are secure.' is printed, and the player can breath easily (ish).

Verb: none @che*ck (list args)
This is a player command used to check the origin of the last few messages received by the player. The args list can contain the number of lines to print as the first element, followed by a list of player names. Each player name in the list is a person to be trusted, unless the name is prefixed by an exclamation point, `!', in which case the person is not to be trusted.

The verb starts by building up a list of trusted and mistrusted individuals based on the names given on the command line. Then it runs through last n messages in the player's responsible property list, checking the origin of the messages using the this:whodunnit verb with the trust and mistrust lists.

Any dubious messages found are printed, along with details of who sent them.

Verb: none @move ()
This is a player command used to move objects from one location to another. The direct and indirect object strings are used to match an object and location to move to. The :moveto verb on the dobj is invoked to move it to the iobj location. If the location changes, and the object is a player, then the message
blip disappears suddenly for parts unknown.

is displayed in the player's location before the move took place. Similarly, at the new location, the message

blip materializes out of thin air.

is printed to the objects in the destination room. No messages are printed if an object is moved. If a permission problem is found, it is reported to the player who typed the command.

Verb: none @par*anoid ()
This verb is used to set the player's paranoid level, as stored in the .paranoid property. Three different levels are available :

Verb: none @s*how ()
This is a player command used to examine other objects in detail. It returns details of an object's owner, location, parent, and all the verbs and properties defined for the object, along with their values, if permissions allow.

Verb: none @desc*ribe ()
This is a player command used to set the description of an object. It takes the dobjstr and tries to match it with an object. If a match is found, then the object's :describe verb is invoked, with the dobjstr as an argument.

Verb: none @create (args)
This verb is a player command used to create an instance of an object or class. It parses the arguments to extract the parent object we wish to create an instance of, along with the name we wish to give to the created object. The create() primitive is called, with the derived parent as an argument. The resulting object is moved to the player's inventory, using the move() primitive, and it's names and aliases set using $building_utils:set_names.

Verb: none @recycle ()
This is a player command used to recycle an object. This simply matches the dobjstr with an object, and calls the recycle() primitive to recycle the object. The returned value, in the case of an error, is printed to the player. Otherwise, a suitable success message is sent.

Verb: none @dig ()
This is a player command used to create a room or exit, (that is, instances of the class $room or `$exit'. The verb parses the arguments to determine the type and number of objects that are to be created. It uses the create() primitive, with $room as a parent to create a room. Note that you can only use the @dig command to dig an exit from within a room. The building_utils:make_exit verb is called to dig an exit.

Verb: none @cl*asses ()
This is a player command used to list the publicly available classes in the database. The public classes are divided into different sections, as defined by the property $class_registry. This contains a list of entries, in the following form:
{ {name, description, members}, ... }

where name is the name of the superclass of objects, description is a short, one line description of the superclass, and members is a list of object references that are in the superclass.

If no argument is given to the `@classes' command, it runs through the entries in the $class_registry and prints out the name and description.

If an argument is given, it is taken as one or more names of an entries in the $class_registry. The names of the members of the requested classes are printed, in this case, using this:classes_2.

Verb: none classes_2 (obj root, indent, list members, list printed)
This verb is called by `@classes' to print the members of the classes given in members. It is called recursively to list all the children of every class in members. If root is in the list of members then it is printed as the class root name. Otherwise, it is printed as a member of the class. For every child of the root, if it is in the set printed, this:classes_2 is called, to print any descendants.

Verb: str who_location_msg ()
Verb: str whereis_location_msg ()
Verb: str page_origin_msg ()
Verb: str page_echo_msg ()
Verb: str page_absent_msg ()
These verbs return the value of the corresponding property on the player after pronoun substitution. They are provided to allow the player to override the verbs for more distinctive and complex messages.

The following properties are defined for the $player class.

Property: current_message
This property contains an integer index into the list of MOO Mail messages currently stored in the messages property. It is used by the mail handler to determine which message the player is currently looking at.

Property: messages
This property contains a list of mail messages. Each mail message is a list in the following format:
{num, {line-1, line-2, ..., line-n}}

num gives the message number used in the various MOO mail commands. The list of strings contains the text of the message, one line per string.

Property: last_connect_time
This property is an integer, holding the time that this player last connected to the MUD. The integer is in the format returned by the time() primitive, i.e., the number of seconds elasped since 1 January 1970, GMT.

Property: ownership_quota
This property stores the current quota for the player. It is not accessible by the player, to prevent you increasing your building quota arbitrarily. This field can be only changed by a wizard.

Property: gender
This property is used to hold a string representing the gender of the player. In the normal case, this is one of `male', `female', `neuter'. This property is affected by the `@gender' command.

Property: ps
This property is used to hold the subjective pronoun, set to either "he", "she" or "it" as appropriate. string_utils:pronoun_sub replaces the string "%s" with the value of this property.

Property: po
This property is used to hold the objective pronoun, set to either "him", "her" or "it" as appropriate. string_utils:pronoun_sub replaces the string "%o" with the value of this property.

Property: pp
This property is used to hold the possessive pronoun, set to either "his", "her" or "its" as appropriate. string_utils:pronoun_sub replaces the string "%p" with the value of this property.

Property: pr
This property is used to hold the reflexive pronoun, set to either "himself", "herself" or "itself" as appropriate. string_utils:pronoun_sub replaces the string "%r" with the value of this property.

Property: pq
This property is used to hold the possessive pronoun in it's noun form, set to either "his", "hers" or "its" as appropriate. string_utils:pronoun_sub replaces the string "%q" with the value of this property.

Property: psc
This property is used to hold the subjective pronoun, set to either "He", "She" or "It" as appropriate. string_utils:pronoun_sub replaces the string "%S" with the value of this property.

Property: poc
This property is used to hold the objective pronoun, set to either "Him", "Her" or "It" as appropriate. string_utils:pronoun_sub replaces the string "%O" with the value of this property.

Property: ppc
This property is used to hold the possessive pronoun, set to either "His", "Her" or "Its" as appropriate. string_utils:pronoun_sub replaces the string "%P" with the value of this property.

Property: prc
This property is used to hold the reflexive pronoun, set to either "Himself", "Herself" or "Itself" as appropriate. string_utils:pronoun_sub replaces the string "%R" with the value of this property.

Property: pqc
This property is used to hold the possessive pronoun in it's noun form, set to either "His", "Hers" or "Its" as appropriate. string_utils:pronoun_sub replaces the string "%Q" with the value of this property.

Property: home
This property stores the object number of the player's home. This is the place that the player is taken to when s/he types in `home'. The home room is normally either a general sleeping area, or the player's hotel room or apartment.

Property: password
This property stores the encrypted password used to connect to the LambdaMOO server as this player. It is changed by using the `@password' command, and is checked by the server upon login.

Property: gaglist
This property stores a list of object numbers. Any output received, using $player:tell from any of the objects in the list is filtered out of the text sent to the player's terminal screen. Items are added and deleted to this list using the `@gag' and `@ungag' commands.

Property: paranoid
This property is an integer, representing the paranoid level of the player. If set to `2', any output received by the player, via $player:tell is prefixed with the name of the object that originated the message. This is used to that a player can detect spoof output from other players or objects.

If set to `1', any messages sent using $player:tell are stored in a small cache in the property responsible, along with details of where the message came from. This can be used for later checking with the `@check' command.

If set to `0', no spoof checking is performed. This is the normal case.

Property: responsible
This property stores a list in the following format:
{callers, text}

The callers part is in the same format returned by the callers() primitive, and lists the verb stack at the time that the message stored in text was sent.

This property is set by $player:tell and looked at by $player:@check. It contains a maximum number of entries, as determined by the value of the lines property on the player.

Property: lines
This property stores the number of lines kept in the property responsible for anti-spoof checking.

Property: object_gaglist
This property holds a list of objects that are in the player's gaglist. Any output from these objects is ignored by the player's :tell verb.

Property: page_absent_msg
This property holds the message sent to someone when they try to page the player while s/he is not connected. It may contain the usual pronoun substitutions. The default value is `%n is not currently logged in.'

Property: page_origin_msg
This property holds the message sent to a player you page, telling them where you are. The default message is `You sense that %n is looking for you in %l.'

Property: page_echo_msg
This property holds the message sent to a player that pages you when you are logged in. The default message is `Your message has been sent.'

Property: whereis_location_msg
This property holds the message sent when someone locates you through the `@whereis' command. The default message is `%N (%#) is in %l (%[#l]).' This might expand out to something like
Blip (#35) is in The Toilet (#96).

Property: who_location_msg
This property holds the message printed in a who list to inform other player's of your location. The default value is `%l', which returns your current location.

Property: mail_notify
Property: mail_options
Property: mail_forward
These properties define your MOO mail environment. They are discussed in more detail in the section on the MOO Mail system.

Property: edit_options
This property defines your MOO editor environment. It is discussed in more detail in the section on the MOO editor.

The Mail Room Class

*** To be updated for MOO 1.3 ***

This class provides the mail facility used within LambdaMOO. Some would say that to provide an electronic mail facility within a game is slightly insane, but it is very useful for passing around game related messages. Coupled with the use of a suitable client program, for example the excellent mud.el with MOO Mail extensions, sending MOO mail can be easy and efficient. It also allows players to separate their MOO based mail from other, more important mail.

LambdaMOO does not yet provide any facility for reading input from a player. For this reason, programs such as the mail room use a pseudo-room to catch player input. For example, when you start to compose a mail message, you are transported to the mail pseudo-room. Once there, anything you enter is trapped by various verbs in the room, and stored in the message you are entering.

This method means that commands used in the mail composition environment are actually verbs on the mail pseudo-room.

Mail messages are actually stored on the player object, in a property list called messages. Each message occupies one entry, called a mail record, in the following format:

{num, {date, from, to, subject, line1, ..., lineN} }

Apart from the num field, these are all strings. The num field stores the message number for each message. When a new piece of mail arrives, it is allocated a message number 1 greater than the last message in the player's mailbox. If the mailbox is empty, the message is numbered `1'. Each message retains it's unique message number until it is deleted using `@rmmail'.

The number of messages in the mailbox is given by the length of the messages list. A current message pointer is maintained in the property $player.current_message. This is used to determine which message to print when the `@read' command is used.

The MOO Mail system is implemented by four separate objects, and some verbs on the $player class:

The sections that follow detail the verbs in each of the classes, along with any relevant properties.

Mail Commands and Properties on The Player Class

A number of verbs are defined in the $player class to provide access to the mail system. These verbs are detailed below:

Verb: none @mail (args)
This command is used to list the messages currently stored in the player's mailbox. Mail messages are stored in the property list messages on the player. This is a list of complete messages, stored one per list item, in the format shown above.

The `@mail' command first checks the current message number still exists, using the verb this:fix_current_message. It then attempts to parse the arguments given to it, to get a set of message numbers that the user wishes to have displayed. The possible arguments are as follows :-

cur
- the current message
new
- all messages after the current message
num
- (where num is a number) the message numbered num if there is one.
num1-num2
- all messages in the given range, if any.
last:num
- the last num messages
-num
- the last num messages

These may be combined on the `@mail' command line. When a list of messages to display has been gathered in the variable msglist, the following code is used to display the list to the user:

for x in (msglist)
  msg_num = x[1];
  player:tell(this.current_message == msg_num ? "-> " | "   ", 
              $string_utils:right(msg_num, 2), ":  ", 
	      $mail_recipient:summary_line(x[2]));
endfor

For example,

You have 3 messages:
    1:  May 30 12:18   Ezeke (#57)   Classes Documentation
    2:  Jun  4 19:35   Ezeke (#57)   Room contents using title()
->  3:  Jun  5 10:23   Ezeke (#57)   Potential problems

The pointer, `->' indicates the current message. The date, subject and sender of each message, along with the message number, is taken from the relevant mail record stored in the player's messages property.

Verb: none @rmm*ail (args)
This command is used to delete mail from the player's mailbox property, messages. The verb takes each message number given as an argument, and searches for the message in the player's mailbox. If an argument is the string `cur', then this is taken as the number of the current message.

If a match is found, by checking the first entry in each mail record, the message is removed from the messages property list. If a message is not found, the player is informed with a suitable message.