Cheezmud:  a cheesy little mud in Objective C (GNU dialect)
    Copyright (C) 1995  David Flater.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


These are notes that I have made regarding things that are complicated
or non-intuitive.  They are not promised to be accurate in any way,
and they certainly do not constitute complete documentation.


How to Avoid Breaking the Mud
-----------------------------

1.  Don't use really long names.  Everywhere I use little 80-character
    buffers for constructing output.  If you start using long names, the
    mud will self-destruct.

2.  Be extremely careful with libobjects.  If you ask it to do something
    tricky it will screw up the pointers and make cheezmud die mysteriously.

3.  Never call free directly.  Send the logout message instead.  #2 explains
    why.

4.  Don't delete or rename things without checking to see what the consequences
    might be.  For example, the denizens of the Imperial Headquarters rely
    on the room names to decide how to move about.  There are several
    other rooms that are referenced by name in the code, and if you do
    something to them, the mud will break.


Types of Mud Objects
--------------------

Players
Monsters
Rooms
Do-Something Objects (Weapons, Magic Items, Containers, Tools)
Do-Nothing Objects
Money (Gold, Silver, Copper, Precious Stones, ...) NOT IMPLEMENTED YET


How Actions Work
----------------

An action is a method that supplies an action to a player or other "active"
object.  Methods like describe and mudname are not actions.  I just call them
methods.

When a player takes an action, a message must be sent to some object to cause
the action to happen.  Which object receives the message is determined by the
priority system.  For example, the "kill" action of a weapon has higher
priority than the inherent "kill" action of the player (hand-to-hand combat).
Both of these actions might in turn be overridden by a very high priority
"kill" action provided by the room that prevents any killing from going on.
Usually a mud has certain places where all fighting is forbidden, and this is
how it is supported in cheezmud.

This priority system is particularly useful in the case where a player picks up
two items with conflicting goals -- for example, night vision goggles and a
cursed object that makes you blind.  Both of these affect the "look" action,
but we probably don't want a blinded player to be able to see again simply by
picking up the night vision goggles, so the cursed object gets higher priority.
A more powerful magic that bestows super-vision might have higher priority than
the cursed object.

To support this priority system, each mud object must provide a method

- (float) priority: (char *) action: (int) numargs;

When this method is invoked, the return value is the priority of that action in
the object (>= 0), or a negative number if that action is not supported by that
object.  Numerically higher priority values correspond to higher priority,
unlike process priorities in Unix.

The objects that are queried for potential player actions are the player, all
objects directly in the player's inventory (not in a container), and the room
the player is in.  The same sort of resolution occurs for other nonrooms that
call do, except that they might not be in a room -- they could be in somebody's
inventory, in which case they can invoke the player's actions like room
actions.  (I don't recommend using this "feature".)

In general, the priority of the "kill" action of a weapon should
correspond to its deadliness, so that the most deadly weapon will
always be used automatically if several weapons are being carried.
The generic Weapon.m contains a heuristic to estimate a priority based
on speed and damage, so if you don't tamper with the default methods
it will set the priority for you.  If you like, you can code the
priority method to return a differet value for kill depending on the
circumstances.  A weapon that is special against a particular type of
monster could sense the presence of that monster and increase its own
priority.  Hopefully it won't confuse players too much.

The Sack class shows a cool use of variable priority.  The bag action has
priority based on how full the sack is, so that stuff will be distributed
evenly among several sacks that are being carried.

Not all commands are actions.  Look at the ohce methods in Player.m and
Mudadmin.m to see which ones are special.  The mudadmin also has a special
doadmin function that does not allow actions to be overridden and which does
global object resolution instead of just the room and inventory.


The Kill Action
---------------

- kill: who: dobj;
Kill dobj.  This message is sent each heartbeat.  It is the responsibility of
the *weapon* to ignore 3 out of 4 to get a 1-second turnaround.  This is so
that some weapons can be faster than others.  If you want to have a monster
that has superhuman speed with an ordinary weapon, give it a high-priority kill
method that is just like the weapon's kill method but faster.  Then when
somebody plunders the weapon it will still be an ordinary weapon.


Some Special Methods
--------------------

- (float) priority: (char *) action: (int) numargs;
Return priority of an action.  Actions take either one arg (who) or two args
(who and dobj).  Mud admin actions omit the who parameter.

- describe: (char *) newname: (char *) newindef: (char *) newdef:
  (char *) newlongdesc;
- setmudname: (char *) newname;
- setindef: (char *) newdesc;
- setdef: (char *) newdesc;
- setlongdesc: (char *) newdesc;
- (char *) mudname;
- (char *) indef;
- (char *) def;
- (char *) longdesc;
Methods to change or get the name and descriptions.  Indef is the short
description for a context wanting an indefinite article; def is the same thing
for a definite context.  Do not capitalize the first word unless it should
always be capitalized -- Cheezmud will capitalize it if context dictates that
it should be capitalized.  The mudname is the keyword that must be used to
refer to the object in commands.  The long description is just that, with
carriage returns hard-coded for an 80-column screen.  Here are some examples of
how to use mudname, indef, and def:

  mudname         indef                      def
  ----------------------------------------------------------------
  sword           a sword                    the sword
  cord            an honor cord              the honor cord
  Frank           Frank                      Frank
  sword           the Sword of Shannara      the Sword of Shannara

Room names and player names should be unique to avoid dire consequences,
like torching the wrong player.

- (void) heartbeat;
Every object receives this message four times per second.  Inert objects ignore
it.  Most ert objects ignore it except once per second.  The fast heartbeat is
provided in case something really needs to move fast.  The heartbeat will
stabilize itself if the system clock takes a flying leap, but it will not
attempt to "catch up" when it falls behind -- it will slow down gracefully.
Catching up would be unfair to the players since they might get slaughtered
without getting a chance to run when the heartbeat hurries up.

- echo: (char *) text;
The provided text is sent to a player's terminal or processed as needed by some
other object.  If an echo is sent to a room, the room sends the echo to every
object in the room.

- emote: emoter: (char *) verb_you: (char *) verb_he: (char *) emotion;
- emote: emoter: (char *) verb_you: (char *) verb_he: dobj: (char *) emotion;
Emote is similar to echo except that it handles 2nd vs. 3rd person description.
It says "You look around" and "Name looks around" as appropriate.  Emotes in a
room are visible to everyone in the room.  Emotes by objects in a player's
inventory are only visible to that player.  Emotes by objects inside of
containers are not visible at all.

- getlocation;
- setlocation: whereto;
- teleport: whereto;
(Nonrooms)  Getlocation can be used to find out where the object is.
Setlocation silently changes that location.  Teleport calls setlocation but
also generates echoes indicating that the object has been magically moved.

- (int) act: (char *) someaction;
(Nonrooms)  Perform an action.  1 is returned on success or if a diagnostic
has been printed.  0 is returned on total failure.  This method handles
actions of both the 1 and 2 arg varieties.  It resolves direct objects
against the inventory and the room, except for get, drop, bag, and unbag
which are special.

- logout;
This is the way of getting rid of something.  Never call free directly.

- hit: fromwho: (float) damage;
Fromwho has hit you for that much damage.

- clue: dontkillme;
You are supposed to stop trying to kill the specified object.

- (int) isdead;
Things that are "dead" will shortly be deleted.

- (float) health;
- (float) stamina;
Health is stamina over maxstamina.  Stamina is just stamina.