~name{~enUS{room library,room lib,ROOM}}
~keywords{admin}
~desc{
  ~enUS{

The room library is inherited by all "rooms".  This includes not only 
rooms in the traditional sense, but also portables, user and npc 
bodies, etc.  In general when you create a new room, however, you do 
not need to create a new room LPC file (contrary to most MUDs), you 
use the existing OnLine Creation (OLC) tools and/or hand edit the 
roomfile.unq file.  

If however you need to create a new kind of room (for example one 
where the ceiling slowly falls down), you need to create a new LPC 
program derived from ROOM, and set up the UNQ parser to recognize 
your new room type.  You do this as follows:

1) Create a new LPC file, which inherits ROOM and UNQABLE.  (ROOM 
being a constant which is the filename of the room library, probably 
/usr/common/lib/room)

2) Override the create(), upgraded(), destructed(), to_unq_text()
and from_dtd_unq() member functions.  These functions should look
approximately as follows (taken from simple_room.c):

static void create(varargs int clone) \{
  room::create(clone);
  unq::create(clone);
  if(clone) \{
    bdesc = PHR("a room");
    gdesc = PHR("a room");
    ldesc = PHR("You see a room here.");
    edesc = nil;

    MAPD->add_room_object(this_object());
  \}
\}

void destructed(int clone) \{
  room::destructed(clone);
  unq::destructed(clone);
  if(clone) \{
    MAPD->remove_room_object(this_object());
  \}
\}

void upgraded(varargs int clone) \{
  room::upgraded(clone);
  unq::upgraded(clone);
\}
 
/* Prevent anyone from getting a room */
string can_get(object mover, object new_env) \{
  return "You can't move a room!";
\}
 
string to_unq_text(void) \{
  return "\~my_room\{\\n" + to_unq_flags() + "\}\\n";
\}
 
void from_dtd_unq(mixed* unq) \{
  int ctr;
 
  if(unq[0] != "my_room")
    error("Doesn't look like room data!");
 
  for (ctr = 0; ctr < sizeof(unq[1]); ctr++) \{
    from_dtd_tag(unq[1][ctr][0], unq[1][ctr][1]);
  \}
\}

Where "my_room" is a name for your room -- it must be unique, and
cannot be the name of any room parameters -- like location, bdesc,
parent, etc.  (ie it can't be any of the types already listed in
room.dtd).

3) Now you have to add a dtd definition for your room to room.dtd.  
The simplest definiton is just "\~my_room:obj\{\}".  (my_room must
be the same as the my_room above.  If you want any
extra parameters stored for your room, you need to add these into
room.dtd too.  (Of course you also have to be prepared to process
them in your room LPC file).  Look at simple_portable.c for an example
of how this works.

4) Next you need to bind your LPC file to the dtd you have just
finished creating.  To do this edit room_binder.unq and add some unq
such as the following:

\~bind\{
  \~tag\{my_room\}
  \~code\{/usr/common/obj/my_room\}
\}

where my_room is the name of the dtd tag you just finished creating
and /usr/common/obj/my_room is the name of the LPC file containing
your program (excluding the .c).  

That's it.  However, you can't use the OLC to create objects of the
type of your file (at least not yet.  If you want to implement this
feature go ahead).  Instead you need to edit roomfile.unq manually.

FUNCTIONS:

Now, to implement your neato features for this room, there are a few
functions in the ROOM library that you can override to give your room
custom behaviours.  Some of these functions state that you should
call the base class function; you should really call all the base
class functions for all functions, since even if a base class
function doesn't do anything now, it may do something in the future.
The hook functions are as follows:

Movement controlling functions:

string can_enter(object enter_object, int dir)
     Called before a mobile's body enters a room.  enter_object is
the body of the mobile who is trying to enter, dir is the direction
they are entering from.  Return nil to let the mobile enter the room
or a string containing the reason why they can't enter the room
to prevent them from entering.

void enter(object enter_object, int dir)
     Called when a mobile's body enters a room.  enter_object is the
body of the mobile who just entered, dir is the direction they
entered from.  The default implementation of this function of this
function causes all other mobiles in this room to be notified
of the newcomer's arrival, so please call the base class function
unless you don't want other mobiles in the room to be notified when
another person enters the room.  NB: can_enter() will _usually_ be
called before enter() but not always!  For example, an admin
using the @goto command _will not_ cause can_enter to be called.

string can_leave(object leave_object, int dir)
     Called before a mobile's body leaves a room.  leav_object is
the body of the mobile who is trying to leave, dir is the direction
they are leaving to.  Return nil to let the mobile enter the room
or a string containing the reason why they can't leave the room
to prevent them from leaving.

void leave(object leave_object, int dir)
     Called when a mobile's body leaves a room.  leave_object is the
body of the mobile who just left, dir is the direction they
left.  The default implementation of this function of this
function causes all other mobiles in this room to be notified
of the person who left's departure, so please call the base class 
function unless you don't want other mobiles in the room to be 
notified when someone leaves the room.  NB: can_leave() will 
_usually_ be called before leave() but not always!  For example, an 
admin using the @goto command _will not_ cause can_leave() to be 
called.

Picking up/dropping/etc functions:

string can_remove(object mover, object movee, object new_env)
     Called before an object is moved from this room through a
get command or something similar.  mover is the object that is
trying to move the object around, movee is the object which is being
moved, and new_env is the room that the object is being moved to.  
Return the reason (as a string) why the object can't be removed to 
prevent the object from being removed, or nil to allow the object to
be removed.  NB: new_env will always be either the parent or a child
of the current room, and movee will always be a child of this room, 
however mover doesn't necessarily have any relation to this room.

void remove(object mover, object movee, object new_env)
     Called when an object is being moved from this room through a
get command or something similar.  mover is the object that is
moving the object around, movee is the object which is being
moved, and new_env is the room that the object is being moved to.  
NB: new_env will always be either the parent or a child
of the current room, and movee will always be a child of this room, 
however mover doesn't necessarily have any relation to this room.

string can_put(object mover, object movee, object old_env)
     Called before an object is moved into this room through a
get command or something similar.  mover is the object that is
trying to move the object around, movee is the object which is being
moved, and old_env is the room that the object is being moved from.  
Return the reason (as a string) why the object can't be moved to 
prevent the object from being moved, or nil to allow the object to
be moved.  NB: old_env will always be either the parent or a child
of the current room, and movee will always be a child of old_env, 
however mover doesn't necessarily have any relation to this room.

string put(object mover, object movee, object old_env)
     Called when an object is moved into this room through a
get command or something similar.  mover is the object that is
moving the object around, movee is the object which is being
moved, and old_env is the room that the object is being moved from.  
NB: old_env will always be either the parent or a child
of the current room, however mover doesn't necessarily have any 
relation to this room.

string can_get(object mover, object new_env)
     Called when someone is trying to move this object around
through a get command or something similar.  mover is the object
that is trying to move this object around, and new_env is the room
this object is being moved into.  Return the reason (as a string)
why this object can't be moved around, or nil to allow the move.
NB: By default this function checks to see if this object is
no_desc, and prevents the move if it is.  Unless you don't want
this behaviour, please call the base class.

void get(object mover, object new_env)
     Called when someone is moving this object around
through a get command or something similar.  mover is the object
that is trying to move this object around, and new_env is the room
this object is being moved into.  

}}

~name{~enUS{mobile library,mobile lib,MOBILE,mob lib,mob library}}
~keywords{admin}
~desc{
  ~enUS{

Mobiles are the LPC code which serves as a go between between the 
user object and (will) control NPCs.  All sentient objects have a 
mobile, and all mobiles will normally have a body.  To create a NPC, 
you will derive an object form MOBILE.  Since no NPCs have ever been 
created yet, exactly how this will work is somewhat unclear, however 
the MOBILE library is at a state where it _should_be possible to
create a working NPC by deriving a new LPC program from MOBILE.
There are no cookbook answers here, however so you'll need to do
a little experimentation, and really understand some fundementals of
Phantasmal by the time you finish -- you'll probably also need to
modify some other files too.  If you still want to do this,
check out user_mobile.c, for an example of how to create a mobile
based on the MOBILE library (user_mobile.c is the mobile object
for a user).

When NPCs actually work, these are the functions you'll use to
control them:

void say(string msg)
     Say msg to everyone in the current room.

void emote(string msg)
     Emote something, which will be picked up by everyone in the
current room.

int whisper(object to, string str)
     Whisper "str" to "to".  "to" must be the body of a mobile in
the current room.  When something is whispered, only the person who 
is being whispered to will be able to tell what you said, however 
everyone in the same room as you will be able to tell that you 
whispered something to them.  Returns 1 if the whisper suceeded, 0 
if it failed.

int ask(object to, string str)
     Ask "to" "str".  "to" must be the body of a mobile in the
current room.  "to" can be nil, in which case the question will be
asked of everyone in the room.  Although a question can be directed
at a specific person, everyone in the room will be able to hear it.

string place(object obj, object to)
     Moves the object "obj" from its current location into "to".
Both obj and to must be descendents of your location.  String will
be a string explaining why the move failed, or nil if it succeeded.

string move(int dir)
     Moves in the direction "dir".  If the move succeeds, this 
function returns nil, otherwise it returns a string indicating
why it failed.

string teleport(object loc, int force)
     Teleports into the room "loc".  If force is 1, the teleport will
always succeed.  NB:  force will be made priviledged, and the entire
function may be made privileged, as it is a very dangerous function,
with much potential for being abused.

Here are the functions which will allow you to respond to events in
your NPCs:

void hook_say(mixed *args)
     Someone in the current room said something.  args[0] is the body
of the person who said it, and args[1] is what they said.

void hook_whisper(mixed *args)
     Someone in the current room whispered something to this mobile.
args[0] is the person who did the whispering, and args[1] is what 
they whispered.

void hook_whisper_other(mixed *args)
     Someone in the current room whispered something to someone
else in the room.  args[0] is the person who whispered, args[1] is
the person they whispered to.

void hook_ask(mixed *args)
     Someone in the current room asked you something.  args[0] is
the person who asked, and args[1] is what they asked.

void hook_ask_other(mixed *args)
     Someone in the current room asked someone in the room something.
args[0] is the person who asked, args[1] is the person they asked
(which may be nil for a general ask), and args[2] is what they asked.

void hook_leave(mixed *args)
     Someone just left this room.  args[0] is the person who left,
args[1] is the direction in which they left.

void hook_enter(mixed *args)
     Someone just entered this room.  args[0] is the person who
entered, args[1] is the direction they entered from.

}}
