diff -ruN ../nakedmudv3.1/src/Makefile src/Makefile
--- ../nakedmudv3.1/src/Makefile	Sun Dec  4 20:18:15 2005
+++ src/Makefile	Sat Jul  1 20:11:53 2006
@@ -38,11 +38,9 @@
 LIBS    := -lz -lpthread -lcrypt
 
 # each module will add to this from its module.mk file
-SRC     := gameloop.c mud.c utils.c interpret.c handler.c inform.c movement.c \
+SRC     := gameloop.c mud.c utils.c interpret.c handler.c inform.c \
 	   action.c mccp.c save.c socket.c io.c strings.c event.c \
 	   \
-	   cmd_comm.c cmd_manip.c cmd_misc.c cmd_admin.c cmd_builder.c \
-	   \
 	   races.c \
 	   \
 	   log.c auxiliary.c account_handler.c char_gen.c \
@@ -53,6 +51,7 @@
 	   list.c property_table.c hashtable.c map.c storage.c set.c \
 	   buffer.c bitvector.c numbers.c prototype.c hooks.c parse.c \
 	   near_map.c command.c
+
 
 
 # include the description for each module. These will add to SRC
diff -ruN ../nakedmudv3.1/src/account_handler.c src/account_handler.c
--- ../nakedmudv3.1/src/account_handler.c	Sun Dec  4 20:03:08 2005
+++ src/account_handler.c	Sat Jul  1 20:06:58 2006
@@ -191,7 +191,8 @@
     // is already created, we're just editing the password. So save changes.
     if(!account_exists(accountGetName(socketGetAccount(sock)))) {
       // run hooks for creating our account for the first time
-      hookRun("create_account", socketGetAccount(sock));
+      hookRun("create_account", 
+	      hookBuildInfo("str", accountGetName(socketGetAccount(sock))));
       register_account(socketGetAccount(sock));
     }
     else
@@ -261,7 +262,7 @@
 	look_at_room(ch, charGetRoom(ch));
 
 	// run entrance hooks
-	hookRun("enter", ch, charGetRoom(ch));
+	hookRun("enter", hookBuildInfo("ch rm", ch, charGetRoom(ch)));
       }
       else {
 	text_to_buffer(sock, "There was a problem entering the game. Try again later!\r\n");
diff -ruN ../nakedmudv3.1/src/action.c src/action.c
--- ../nakedmudv3.1/src/action.c	Sun Dec  4 20:03:08 2005
+++ src/action.c	Sat Jul  1 20:06:58 2006
@@ -112,6 +112,13 @@
 #endif
 }
 
+// allows stop_all_actions to run as a hook
+void stop_actions_hook(const char *info) {
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &ch);
+  stop_all_actions(ch);
+}
+
 
 
 //*****************************************************************************
@@ -126,7 +133,7 @@
 	  "admin", TRUE, FALSE);
 
   // make sure the character does not continue actions after being extracted
-  hookAdd("char_from_game", stop_all_actions);
+  hookAdd("char_from_game", stop_actions_hook);
 }
 
 bool is_acting(void *ch, bitvector_t where) {
diff -ruN ../nakedmudv3.1/src/char_gen.c src/char_gen.c
--- ../nakedmudv3.1/src/char_gen.c	Sun Dec  4 20:03:07 2005
+++ src/char_gen.c	Sat Jul  1 20:06:58 2006
@@ -169,7 +169,7 @@
     look_at_room(socketGetChar(sock), charGetRoom(socketGetChar(sock)));
 
     // run any hooks for creating the player for the first time
-    hookRun("create_player", socketGetChar(sock));
+    hookRun("create_player", hookBuildInfo("ch", socketGetChar(sock)));
     
     // and register him as a valid player
     register_player(socketGetChar(sock));
@@ -183,7 +183,7 @@
 
     // run entrance hooks
     ROOM_DATA      *room = charGetRoom(socketGetChar(sock));
-    hookRun("enter", socketGetChar(sock), room);
+    hookRun("enter", hookBuildInfo("ch rm", socketGetChar(sock), room));
   }
 }
 
diff -ruN ../nakedmudv3.1/src/character.c src/character.c
--- ../nakedmudv3.1/src/character.c	Sun Dec  4 20:03:07 2005
+++ src/character.c	Sat Jul  1 20:06:58 2006
@@ -103,6 +103,7 @@
   ROOM_DATA            * last_room;
   OBJ_DATA             * furniture;
   BUFFER               * desc;
+  BUFFER               * look_buf;
   char                 * name;
   int                    sex;
   int                    position;
@@ -133,6 +134,7 @@
   ch->furniture     = NULL;
   ch->socket        = NULL;
   ch->desc          = newBuffer(1);
+  ch->look_buf      = newBuffer(1);
   ch->name          = strdup("");
   ch->sex           = SEX_NEUTRAL;
   ch->position      = POS_STANDING;
@@ -228,6 +230,10 @@
   return ch->desc;
 }
 
+BUFFER      *charGetLookBuffer( CHAR_DATA *ch) {
+  return ch->look_buf;
+}
+
 const char  *charGetRdesc     ( CHAR_DATA *ch) {
   return ch->rdesc;
 }
@@ -377,6 +383,7 @@
   if(mob->prototypes)  free(mob->prototypes);
   if(mob->name)        free(mob->name);
   if(mob->desc)        deleteBuffer(mob->desc);
+  if(mob->look_buf)    deleteBuffer(mob->look_buf);
   if(mob->rdesc)       free(mob->rdesc);
   if(mob->multi_rdesc) free(mob->multi_rdesc);
   if(mob->multi_name)  free(mob->multi_name);
diff -ruN ../nakedmudv3.1/src/character.h src/character.h
--- ../nakedmudv3.1/src/character.h	Sun Dec  4 20:03:07 2005
+++ src/character.h	Sat Jul  1 20:06:58 2006
@@ -82,6 +82,7 @@
 int          charGetSex       (CHAR_DATA *ch);
 // for editing with the text editor
 BUFFER      *charGetDescBuffer(CHAR_DATA *ch);
+BUFFER      *charGetLookBuffer(CHAR_DATA *ch);
 LIST        *charGetInventory (CHAR_DATA *ch);
 BODY_DATA   *charGetBody      (CHAR_DATA *ch);
 const char  *charGetRace      (CHAR_DATA *ch);
diff -ruN ../nakedmudv3.1/src/cmd_admin.c src/cmd_admin.c
--- ../nakedmudv3.1/src/cmd_admin.c	Sun Dec  4 20:03:07 2005
+++ src/cmd_admin.c	Wed Dec 31 17:00:00 1969
@@ -1,303 +0,0 @@
-//*****************************************************************************
-//
-// cmd_admin.c
-//
-// commands and procedures available only to admins.
-//
-//*****************************************************************************
-
-#include "mud.h"
-#include "world.h"
-#include "inform.h"
-#include "character.h"
-#include "room.h"
-#include "handler.h"
-#include "utils.h"
-#include "socket.h"
-#include "save.h"
-#include "storage.h"
-
-
-
-//*****************************************************************************
-// commands in cmd_admin.c
-//*****************************************************************************
-
-//
-// Locks the game for anyone not a member of one of the user groups we specify.
-COMMAND(cmd_lockdown) {
-  // no argument - check the current lockdown status
-  if(!*arg) {
-    if(!*mudsettingGetString("lockdown"))
-      send_to_char(ch, "Lockdown is currently turned off.\r\n");
-    else {
-      send_to_char(ch, "Current lockdown is to members not of: %s\r\n",
-		   mudsettingGetString("lockdown"));
-      send_to_char(ch, "To turn off lockdown, use {clockdown off{n\r\n");
-    }
-  }
-
-  // turn lockdown off
-  else if(!strcasecmp(arg, "off")) {
-    send_to_char(ch, "Lockdown disabled.\r\n");
-    mudsettingSetString("lockdown", "");
-  }
-
-  // make sure we're not locking ourself out
-  else if(!bitIsSet(charGetUserGroups(ch), arg))
-    send_to_char(ch, "You cannot lock yourself out!\r\n");
-
-  // lock out anyone not in the groups we specify
-  else {
-    send_to_char(ch, "MUD locked down to everyone not in groups: %s\r\n", arg);
-    mudsettingSetString("lockdown", arg);
-
-    // kick out everyone who we've just locked out
-    LIST_ITERATOR *ch_i = newListIterator(mobile_list);
-    ITERATE_LIST(ch, ch_i) {
-      if(!charIsNPC(ch) && !bitIsSet(charGetUserGroups(ch), arg)) {
-	send_to_char(ch, "The mud has just been locked down to you.\r\n");
-	save_player(ch);
-
-	// and close the socket if we have one
-	if(charGetSocket(ch)) {
-	  SOCKET_DATA *sock = charGetSocket(ch);
-	  charSetSocket(ch, NULL);
-	  socketSetChar(sock, NULL);
-	  close_socket(sock, FALSE);
-	}
-
-	// do the extraction
-	extract_mobile(ch);
-      }
-    } deleteListIterator(ch_i);
-  }
-}
-
-
-//
-// changes the number of pulses the mud experiences each second
-COMMAND(cmd_pulserate) {
-  if(!*arg)
-    send_to_char(ch,"The mud currently has %d pulses per second.\r\n", 
-		 PULSES_PER_SECOND);
-  else {
-    int pulserate = atoi(arg);
-    if(pulserate == 0 || 1000 % pulserate != 0)
-      send_to_char(ch, "The number of pulses per second must divide 1000.\r\n");
-    else {
-      mudsettingSetInt("pulses_per_second", pulserate);
-      send_to_char(ch, "The mud's new pulse rate is %d pulses per second.\r\n",
-		   PULSES_PER_SECOND);
-    }
-  }
-}
-
-
-//
-// BOOM! Shut down the MUD
-COMMAND(cmd_shutdown) {
-  shut_down = TRUE;
-}
-
-
-//
-// Perform a command multiple times
-COMMAND(cmd_repeat) {
-  int    repeats = 0;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "int string", &repeats, &arg))
-    return;
-
-  // make sure the integer is a valid number
-  if(repeats < 1)
-    send_to_char(ch, "Commands can only be repeated a positive number of time.\r\n");
-  else {
-    int i;
-    // now, do the repeating
-    for(i = 0; i < repeats; i++)
-      do_cmd(ch, arg, TRUE);
-  }
-}
-
-
-//
-// tries to force the person to do something
-void try_force(CHAR_DATA *ch, CHAR_DATA *vict, char *cmd) {
-  if(ch == vict)
-    send_to_char(ch, "Why don't you just try doing it?\r\n");
-  else if(!charHasMoreUserGroups(ch, vict))
-    send_to_char(ch, "But %s has just as many priviledges as you!\r\n",
-		 charGetName(vict));
-  else {
-    send_to_char(ch,   "You force %s to '%s'\r\n", charGetName(vict), cmd);
-    send_to_char(vict, "%s forces you to '%s'\r\n",
-		 see_char_as(vict, ch), cmd);
-    do_cmd(vict, cmd, TRUE);
-  }
-}
-
-
-//
-// force someone to execute a command
-COMMAND(cmd_force) {
-  void    *found = NULL;
-  bool  multiple = FALSE; 
-
-  if(!parse_args(ch, TRUE, cmd, arg, "ch.world.noself.multiple string",
-		 &found, &multiple, &arg))
-    return;
-
-  // did we find a single character, or a list of characters?
-  if(multiple == FALSE)
-    try_force(ch, found, arg);
-  else {
-    LIST_ITERATOR *ch_i = newListIterator(found);
-    CHAR_DATA   *one_ch = NULL;
-    ITERATE_LIST(one_ch, ch_i) {
-      try_force(ch, one_ch, arg);
-    } deleteListIterator(ch_i);
-    deleteList(found);
-  }
-}
-
-
-//
-// Perform a command at another room or person
-COMMAND(cmd_at) {
-  ROOM_DATA *room = NULL;
-  void     *found = NULL;
-  int  found_type = PARSE_NONE;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "{ room ch.world.noself } string",
-		 &found, &found_type, &arg))
-    return;
-
-  // figure out what room we're doing the command at
-  if(found_type == PARSE_ROOM)
-    room = found;
-  else // found_type == PARSE_CHAR
-    room = charGetRoom(found);
-
-  // transfer us over to the new room, do the command, then transfer back
-  ROOM_DATA *old_room = charGetRoom(ch);
-  char_from_room(ch);
-  char_to_room(ch, room);
-  do_cmd(ch, arg, TRUE);
-  char_from_room(ch);
-  char_to_room(ch, old_room);
-}
-
-
-//
-// Go to a specific room, object, or character in the game. Rooms are referenced
-// by vnum. Everything else is referenced by name.
-//   usage: goto <thing>
-//
-//   examples:
-//     goto 100             go to room number 100
-//     goto jim             go to an object/person named jim
-COMMAND(cmd_goto) {
-  ROOM_DATA *room = NULL;
-  void     *found = NULL;
-  int  found_type = PARSE_NONE;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "{ room ch.world.noself }", 
-		 &found, &found_type))
-    return;
-
-  // what did we find?
-  if(found_type == PARSE_ROOM)
-    room = found;
-  else // found_type == PARSE_CHAR
-    room = charGetRoom(found);
-
-  message(ch, NULL, NULL, NULL, TRUE, TO_ROOM,
-	  "$n disappears in a puff of smoke.");
-  char_from_room(ch);
-  char_to_room(ch, room);
-  look_at_room(ch, room);
-  message(ch, NULL, NULL, NULL, TRUE, TO_ROOM,
-	  "$n arrives in a puff of smoke.");
-}
-
-
-//
-// ch transfers tgt to dest
-void do_transfer(CHAR_DATA *ch, CHAR_DATA *tgt, ROOM_DATA *dest) {
-  if(dest == charGetRoom(tgt))
-    send_to_char(ch, "%s is already %s.\r\n", charGetName(tgt),
-		 (charGetRoom(ch) == dest ? "here" : "there"));
-  else {
-    send_to_char(tgt, "%s has transferred you to %s!\r\n",
-		 see_char_as(tgt, ch), roomGetName(dest));
-    message(tgt, NULL, NULL, NULL, TRUE, TO_ROOM,
-	    "$n disappears in a puff of smoke.");
-    char_from_room(tgt);
-    char_to_room(tgt, dest);
-    look_at_room(tgt, dest);
-    message(tgt, NULL, NULL, NULL, TRUE, TO_ROOM,
-	    "$n arrives in a puff of smoke.");
-  }
-}
-
-
-//
-// The opposite of goto. Instead of moving to a specified location, it
-// takes the target to the user.
-//   usage: transfer <player> [[to] room]
-COMMAND(cmd_transfer) {
-  void     *found = NULL;
-  bool   multiple = FALSE;
-  ROOM_DATA *dest = NULL;
-
-  // if our arguments don't parse properly, 
-  // parse_args will tell the person what is wrong
-  if(parse_args(ch, TRUE, cmd, arg,
-		"ch.world.multiple.noself | [to] room",
-		&found, &multiple, &dest)) {
-    // if we didn't supply a destination, use our current room
-    if(dest == NULL)
-      dest = charGetRoom(ch);
-
-    // if we have multiple people, we'll have to transfer them one by one
-    if(multiple == FALSE)
-      do_transfer(ch, found, dest);
-    else {
-      LIST_ITERATOR *tgt_i = newListIterator(found);
-      CHAR_DATA       *tgt = NULL;
-      ITERATE_LIST(tgt, tgt_i) {
-	do_transfer(ch, found, dest);
-      } deleteListIterator(tgt_i);
-
-      // we also have to delete the list that we were given
-      deleteList(found);
-    }
-  }
-}
-
-
-//
-// Perform a copyover
-COMMAND(cmd_copyover) { 
-  do_copyover(ch);
-}
-
-
-//
-// show a list of all the PCs who are linkdead
-COMMAND(cmd_linkdead) {
-  LIST_ITERATOR *ch_i = newListIterator(mobile_list);
-  CHAR_DATA   *one_ch = NULL;
-  bool          found = FALSE;
-
-  ITERATE_LIST(one_ch, ch_i) {
-    if (!(charIsNPC(one_ch) || charGetSocket(one_ch))) {
-      send_to_char(ch, "%s is linkdead.\r\n", charGetName(one_ch));
-      found = TRUE;
-    }
-  } deleteListIterator(ch_i);
-
-  if (!found)
-    send_to_char(ch, "Noone is currently linkdead.\r\n");
-}
diff -ruN ../nakedmudv3.1/src/cmd_builder.c src/cmd_builder.c
--- ../nakedmudv3.1/src/cmd_builder.c	Sun Dec  4 20:03:07 2005
+++ src/cmd_builder.c	Wed Dec 31 17:00:00 1969
@@ -1,328 +0,0 @@
-//*****************************************************************************
-//
-// cmd_builder.c
-//
-// various utilities (non-OLC) for builders, such as digging/filling exits, 
-// listing zone scripts/rooms/etc, and utilities for loading/purging mobs and
-// objects.
-//
-//*****************************************************************************
-
-#include "mud.h"
-#include "world.h"
-#include "zone.h"
-#include "room.h"
-#include "room_reset.h"
-#include "character.h"
-#include "object.h"
-#include "handler.h"
-#include "inform.h"
-#include "utils.h"
-#include "prototype.h"
-
-
-
-//*****************************************************************************
-// mandatory modules
-//*****************************************************************************
-#include "items/items.h"
-
-
-
-//
-// Load a copy of a specific mob/object
-// usage: load <mob | obj> <vnum>
-COMMAND(cmd_load) {
-  if(!arg || !*arg)
-    send_to_char(ch, "What did you want to load?\r\n");
-  else {
-    char   type[SMALL_BUFFER];
-    char   name[SMALL_BUFFER];
-    char locale[SMALL_BUFFER];
-    char    key[SMALL_BUFFER];
-    arg = one_arg(arg, type);
-    if(!parse_worldkey_relative(ch, arg, name, locale)) {
-      send_to_char(ch, "What did you want to load?\r\n");
-      return;
-    }
-
-    sprintf(key, "%s@%s", name, locale);
-    if(!strncasecmp("mobile", type, strlen(type))) {
-      PROTO_DATA *proto = worldGetType(gameworld, "mproto", key);
-      if(proto == NULL)
-	send_to_char(ch, "No mobile prototype exists with that key.\r\n");
-      else if(protoIsAbstract(proto))
-	send_to_char(ch, "That prototype is abstract.\r\n");
-      else {
-	CHAR_DATA *mob = protoMobRun(proto);
-	if(mob == NULL)
-	  send_to_char(ch, "There was an error running the prototype.\r\n");
-	else {
-	  send_to_char(ch, "You create %s.\r\n", charGetName(mob));
-	  char_to_room(mob, charGetRoom(ch));
-	}
-      }
-    }
-
-    else if(!strncasecmp("object", type, strlen(type))) {
-      PROTO_DATA *proto = worldGetType(gameworld, "oproto", key);
-      if(proto == NULL)
-	send_to_char(ch, "No object prototype exists with that key.\r\n");
-      else if(protoIsAbstract(proto))
-	send_to_char(ch, "That prototype is abstract.\r\n");
-      else {
-	OBJ_DATA *obj = protoObjRun(proto);
-	if(obj == NULL)
-	  send_to_char(ch, "There was an error running the prototype.\r\n");
-	else {
-	  send_to_char(ch, "You create %s.\r\n", objGetName(obj));
-	  obj_to_char(obj, ch);
-	}
-      }
-    }
-
-    // type not found
-    else 
-      send_to_char(ch, "What type of thing did you want to load?\r\n");
-  }
-}
-
-
-//
-// remove an object or player from the game. If no argument is supplied, all
-// objects and non-player characters are removed from the current room.
-//   usage: purge <target>
-COMMAND(cmd_purge) {
-  void    *found = NULL;
-  int found_type = PARSE_NONE;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "| { ch.room.noself obj.room }",
-		 &found, &found_type))
-    return;
-
-  // purge everything in the current room
-  if(found == NULL) {
-    LIST_ITERATOR *list_i = newListIterator(roomGetContents(charGetRoom(ch)));
-    OBJ_DATA *obj;
-    CHAR_DATA *vict;
-
-    send_to_char(ch, "You purge the room.\r\n");
-    message(ch, NULL, NULL, NULL, FALSE, TO_ROOM,
-	    "$n raises $s arms, and white flames engulf the entire room.");
-
-    // purge all the objects. 
-    ITERATE_LIST(obj, list_i)
-      extract_obj(obj);
-    deleteListIterator(list_i);
-
-    // and now all of the non-characters
-    list_i = newListIterator(roomGetCharacters(charGetRoom(ch)));
-    ITERATE_LIST(vict, list_i) {
-      if(vict == ch || !charIsNPC(vict)) 
-	continue;
-      extract_mobile(vict);
-    }
-    deleteListIterator(list_i);
-  }
-
-  // purge characters
-  else if(found_type == PARSE_CHAR) {
-    // we can only purge him if we have all the same groups as him, and more
-    if(!charHasMoreUserGroups(ch, found))
-      send_to_char(ch, "Erm, you better not try that on %s. %s has "
-		   "just as much priviledges as you.\r\n", 
-		   HIMHER(found), HESHE(found));
-    else {
-      send_to_char(ch, "You purge %s.\r\n", charGetName(found));
-      message(ch, found, NULL, NULL, FALSE, TO_ROOM,
-	      "$n raises $s arms, and white flames engulf $N.");
-      extract_mobile(found);
-    }
-  }
-
-  // purge objects
-  else if(found_type == PARSE_OBJ) {
-    send_to_char(ch, "You purge %s.\r\n", objGetName(found));
-    message(ch, NULL, found, NULL, FALSE, TO_ROOM,
-	    "$n raises $s arms, and white flames engulf $o.");
-    obj_from_room(found);
-    extract_obj(found);
-  }
-}
-
-
-//
-// reruns the room's load script, and replaces the old version of the room with
-// the new one.
-COMMAND(cmd_rreload) {
-  PROTO_DATA   *proto = NULL;
-  ROOM_DATA *old_room = NULL;
-  ROOM_DATA *new_room = NULL;
-  ZONE_DATA     *zone = NULL;
-  const char     *key = roomGetClass(charGetRoom(ch));
-
-  // unless an arg is supplied, we're working on the current room.
-  if(arg && *arg)
-    key = get_fullkey_relative(arg, get_key_locale(key));
-
-  // make sure all of our requirements are met
-  if( (zone = worldGetZone(gameworld, get_key_locale(key))) == NULL)
-    send_to_char(ch, "That zone does not exist!\r\n");
-  else if(!canEditZone(zone, ch))
-    send_to_char(ch, "You are not authorized to edit that zone.\r\n");
-  else if( (proto = worldGetType(gameworld, "rproto", key)) == NULL)
-    send_to_char(ch, "No prototype for that room exists.\r\n");
-  else if(!worldRoomLoaded(gameworld, key))
-    send_to_char(ch, "No room with that key is currently loaded.\r\n");
-  else {
-    // try running the proto to get our new room...
-    old_room = worldGetRoom(gameworld, key);
-    new_room = protoRoomRun(proto);
-    if(new_room == NULL)
-      send_to_char(ch, "There was an error reloading the room.\r\n");
-    else {
-      do_mass_transfer(old_room, new_room, TRUE, TRUE, TRUE);
-      extract_room(old_room);
-      worldPutRoom(gameworld, key, new_room);
-      send_to_char(ch, "Room reloaded.\r\n");
-    }
-  }
-}
-
-
-//
-// trigger all of a specified zone's reset scripts and such. If no vnum is
-// supplied, the zone the user is currently in is reset.
-//   usage: zreset <zone vnum>
-COMMAND(cmd_zreset) {
-  ZONE_DATA *zone = NULL;
-
-  if(!arg || !*arg)
-    zone= worldGetZone(gameworld,get_key_locale(roomGetClass(charGetRoom(ch))));
-  else
-    zone= worldGetZone(gameworld, arg);
-
-  if(zone == NULL)
-    send_to_char(ch, "Which zone did you want to reset?\r\n");
-  else if(!canEditZone(zone, ch))
-    send_to_char(ch, "You are not authorized to edit that zone.\r\n");
-  else {
-    send_to_char(ch, "%s has been reset.\r\n", zoneGetName(zone));
-    zoneForceReset(zone);
-  }
-}
-
-
-
-//*****************************************************************************
-// Functions for deleting different prototype
-//*****************************************************************************
-COMMAND(cmd_rdelete) {
-  char *name = NULL;
-  if(!parse_args(ch, TRUE, cmd, arg, "word", &name))
-    return;
-  if(do_delete(ch, "rproto", deleteProto, name)) {
-    do_delete(ch, "reset", deleteResetList, name);
-    send_to_char(ch, "If the room has already been used, do not forget to "
-		 "also purge the current instance of it.\r\n");
-  }
-}
-
-COMMAND(cmd_mdelete) {
-  char *name = NULL;
-  if(!parse_args(ch, TRUE, cmd, arg, "word", &name))
-    return;
-  do_delete(ch, "mproto", deleteProto, name);
-}
-
-COMMAND(cmd_odelete) {
-  char *name = NULL;
-  if(!parse_args(ch, TRUE, cmd, arg, "word", &name))
-    return;
-  do_delete(ch, "oproto", deleteProto, name);
-}
-
-
-
-//*****************************************************************************
-// Functions for listing different types of data (zones, mobs, objs, etc...)
-//*****************************************************************************
-//
-// returns yes/no if the prototype is abstract or not
-const char *prototype_list_info(PROTO_DATA *data) {
-  static char buf[SMALL_BUFFER];
-  sprintf(buf, "%-50s %3s", 
-	  (*protoGetParents(data) ? protoGetParents(data) : "-------"),
-	  (protoIsAbstract(data)  ? "yes" : "no"));
-  return buf;
-}
-
-// this is used for the header when printing out zone proto info
-#define PROTO_LIST_HEADER \
-"Parents                                       Abstract"
-
-
-COMMAND(cmd_rlist) {
-  do_list(ch, (arg&&*arg?arg:get_key_locale(roomGetClass(charGetRoom(ch)))),
-	  "rproto", PROTO_LIST_HEADER, prototype_list_info);
-}
-
-COMMAND(cmd_mlist) {
-  do_list(ch, (arg&&*arg?arg:get_key_locale(roomGetClass(charGetRoom(ch)))),
-	  "mproto", PROTO_LIST_HEADER, prototype_list_info);
-}
-
-COMMAND(cmd_olist) {
-  do_list(ch, (arg&&*arg?arg:get_key_locale(roomGetClass(charGetRoom(ch)))),
-	  "oproto", PROTO_LIST_HEADER, prototype_list_info);
-}
-
-COMMAND(cmd_mrename) {
-  char *from = NULL, *to = NULL;
-  if(!parse_args(ch, TRUE, cmd, arg, "word word", &from, &to))
-    return;
-  do_rename(ch, "mproto", from, to);
-}
-
-COMMAND(cmd_rrename) {
-  char *from = NULL, *to = NULL;
-  if(!parse_args(ch, TRUE, cmd, arg, "word word", &from, &to))
-    return;
-  if(do_rename(ch, "rproto", from, to)) {
-    do_rename(ch, "reset", from, to);
-    send_to_char(ch, "No not forget to purge any instances of %s already "
-		 "loaded.\r\n", from); 
-  }
-}
-
-COMMAND(cmd_orename) {
-  char *from = NULL, *to = NULL;
-  if(!parse_args(ch, TRUE, cmd, arg, "word word", &from, &to))
-    return;
-  do_rename(ch, "oproto", from, to);
-}
-
-COMMAND(cmd_zlist) {
-  LIST *keys = worldGetZoneKeys(gameworld);
-
-  // first, order all the zones
-  listSortWith(keys, strcasecmp);
-
-  // now, iterate across them all and show them
-  LIST_ITERATOR *zone_i = newListIterator(keys);
-  ZONE_DATA       *zone = NULL;
-  char             *key = NULL;
-
-  send_to_char(ch,
-" {wKey            Name                                             Editors  Timer\r\n"
-"{b--------------------------------------------------------------------------------\r\n{n");
-
-  ITERATE_LIST(key, zone_i) {
-    if( (zone = worldGetZone(gameworld, key)) != NULL) {
-      send_to_char(ch, " {c%-14s %-30s %25s  {w%5d\r\n", key, zoneGetName(zone),
-		   zoneGetEditors(zone), zoneGetPulseTimer(zone));
-    }
-  } deleteListIterator(zone_i);
-  deleteListWith(keys, free);
-  send_to_char(ch, "{g");
-}
diff -ruN ../nakedmudv3.1/src/cmd_comm.c src/cmd_comm.c
--- ../nakedmudv3.1/src/cmd_comm.c	Sun Dec  4 20:03:07 2005
+++ src/cmd_comm.c	Wed Dec 31 17:00:00 1969
@@ -1,170 +0,0 @@
-//*****************************************************************************
-//
-// cmd_comm.c
-//
-// Various commands used in NakedMud(tm) for communicating with other
-// characters, and NPCs.
-//
-//*****************************************************************************
-
-#include "mud.h"
-#include "utils.h"
-#include "inform.h"
-#include "character.h"
-#include "world.h"
-#include "hooks.h"
-
-
-
-//
-// cmd_ask is used to pose a question to another character. Mostly, this is
-// intended to be used to carry on dialogs with NPCs. Ask has a local range
-// (i.e. you can only ask people in the same room as you questions)
-//   usage: ask <person> [about] <question>
-//
-//   examples:
-//     ask bob about cats           ask bob about the topic, "cats"
-//     ask jim can I have a salad?  ask jim if you can have a salad
-COMMAND(cmd_ask) {
-  CHAR_DATA *tgt = NULL;
-  char *question = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "ch.room.noself [about] string", 
-		 &tgt, &question))
-    return;
-
-  mssgprintf(ch, tgt, NULL, NULL, FALSE, TO_VICT, 
-	     "{w$n asks you, '%s'{n", question);
-  mssgprintf(ch, tgt, NULL, NULL, FALSE, TO_CHAR,
-	     "{wYou ask $N, '%s'{n", question);
-  hookRun("ask", ch, tgt, arg);
-}
-
-
-//
-// cmd_tell sends a message to another character. Primarily intended for
-// player-player communication. Players can tell other players things even
-// if they are not in the same room.
-//   usage: tell <person> <mesage>
-//
-//   examples:
-//     tell luke I am your father
-COMMAND(cmd_tell) {
-  CHAR_DATA *tgt = NULL;
-  char     *mssg = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "ch.world.noself string", &tgt, &mssg))
-    return;
-
-  mssgprintf(ch, tgt, NULL, NULL, FALSE, TO_CHAR,
-	     "{rYou tell $N, '%s'{n", mssg);
-  mssgprintf(ch, tgt, NULL, NULL, FALSE, TO_VICT, 
-	     "{r$n tells you, '%s'{n", mssg);
-}
-
-
-//
-// cmd_chat sends a global message to all of the players currently logged on.
-//   usage: chat <message>
-//
-//   example:
-//     chat hello, world!
-COMMAND(cmd_chat) {
-  if (!arg || !*arg)
-    send_to_char(ch, "Chat what?\n\r");
-  else
-    communicate(ch, arg, COMM_GLOBAL);
-}
-
-
-//
-// cmd_say sends a message to everyone in the same room as you. Say, like ask,
-// can trigger NPC dialogs.
-//   usage: say <message>
-//
-//   example:
-//     say hello, room!
-COMMAND(cmd_say) {
-  if (!*arg)
-    send_to_char(ch, "Say what?\n\r");
-  else {
-    communicate(ch, arg, COMM_LOCAL);
-    hookRun("say", ch, arg);
-  }
-}
-
-
-//
-// NPCs with dialogs will often have something to say when you greet/approach
-// then. cmd_greet is a way to get them talking.
-//   usage: greet <person>
-//
-//   examples:
-//     greet mayor
-COMMAND(cmd_greet) {
-  CHAR_DATA *tgt = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "ch.room.noself", &tgt))
-    return;
-
-  message(ch, tgt, NULL, NULL, FALSE, TO_CHAR, "You greet $N.");
-  message(ch, tgt, NULL, NULL, FALSE, TO_VICT, "$n greets you.");
-  message(ch, tgt, NULL, NULL, FALSE, TO_ROOM, "$n greets $N.");
-  hookRun("greet", ch, tgt);
-}
-
-
-//
-// Send a special text message to the room you are in. The message is preceded
-// by your name, unless you put a $n somewhere in the text, in which case the
-// $n is replaced by your name.
-//   usage: emote <message>
-//
-//   examples:
-//     emote does a little dance.
-//     emote A gunshot sounds, and $n is laying on the ground, dead.
-COMMAND(cmd_emote) {
-  if(!arg || !*arg)
-    send_to_char(ch, "Emote we must, but emote what?\r\n");
-  else {
-    char buf[MAX_BUFFER];
-
-    // see if a $n is within the argument ... if there is, let the
-    // person put his or her name were it's wanted. Otherwise, tag
-    // it onto the front of the message
-    if(strfind(arg, "$n"))
-      strcpy(buf, arg);
-    else
-      sprintf(buf, "$n %s", arg);
-
-    message(ch, NULL, NULL, NULL, FALSE, TO_ROOM | TO_CHAR, buf);
-  }
-}
-
-
-//
-// cmd_gemote is similar to emote, but it sends a global message
-COMMAND(cmd_gemote) {
-  if(!arg || !*arg)
-    send_to_char(ch, "Gemote we must, but gemote what?\r\n");
-  else if(strfind(arg, "$n"))
-    mssgprintf(ch, NULL, NULL, NULL, FALSE, TO_WORLD | TO_CHAR,
-	       "{bGLOBAL:{c %s{n", arg);
-  else 
-    mssgprintf(ch, NULL, NULL, NULL, FALSE, TO_WORLD | TO_CHAR,
-	       "{bGLOBAL:{c $n %s{n", arg);
-}
-
-
-//
-// Send a message to another character, and also make it beep
-COMMAND(cmd_page) {
-  CHAR_DATA *tgt = NULL;
-  char     *mssg = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "ch.world.noself string", &tgt, &mssg))
-    return;
-
-  send_to_char(ch,  "\007\007You page %s.\r\n", see_char_as(ch, tgt));
-  send_to_char(tgt, "\007\007*%s* %s\r\n", see_char_as(tgt, ch), mssg);
-}
diff -ruN ../nakedmudv3.1/src/cmd_manip.c src/cmd_manip.c
--- ../nakedmudv3.1/src/cmd_manip.c	Sun Dec  4 20:03:07 2005
+++ src/cmd_manip.c	Wed Dec 31 17:00:00 1969
@@ -1,571 +0,0 @@
-//*****************************************************************************
-//
-// cmd_manip.c
-//
-// a set of commands that NakedMud(tm) comes with that allows characters to
-// manipulate various things. These commands are mostly directed towards
-// manipulating objects (e.g. get, put, drop, etc...) but can also affect other
-// things like exits (e.g. open, close)
-//
-//*****************************************************************************
-#include "mud.h"
-#include "utils.h"
-#include "handler.h"
-#include "inform.h"
-#include "character.h"
-#include "exit.h"
-#include "world.h"
-#include "room.h"
-#include "object.h"
-#include "hooks.h"
-
-
-
-//*****************************************************************************
-// mandatory modules
-//*****************************************************************************
-#include "items/items.h"
-#include "items/container.h"
-
-
-
-//*****************************************************************************
-// local functions
-//*****************************************************************************
-
-//
-// used by open, close, lock, and unlock. When an exit is manipulated on one
-// side, it is the case that we'll want to do an identical manipulation on the
-// other side. That's what we do here. Note: Can only do close OR lock with
-// one call to this function. Cannot handle both at the same time!
-void try_manip_other_exit(ROOM_DATA *room, EXIT_DATA *exit,
-			  bool closed, bool locked) {
-  // see if there's a room on the other side
-  ROOM_DATA         *to = worldGetRoom(gameworld, exitGetTo(exit));
-  EXIT_DATA *other_exit = NULL;
-  const char   *opp_dir = NULL;
-  if(to == NULL)
-    return;
-
-  // check to see if we can figure out a return direction
-  if(*exitGetOpposite(exit))
-    opp_dir = exitGetOpposite(exit);
-  else {
-    int opp_num = dirGetNum(roomGetExitDir(room, exit));
-    if(opp_num != DIR_NONE)
-      opp_dir = dirGetName(dirGetOpposite(opp_num));
-  }
-
-  // do we have an opposite direction to manipulate?
-  if(opp_dir == NULL)
-    return;
-
-  // do we have an opposite exit to manipulate?
-  if( (other_exit = roomGetExit(to, opp_dir)) != NULL) {
-    // are we changing the close state, and the exit's not locked?
-    if(exitIsClosed(other_exit) != closed && !exitIsLocked(other_exit)) {
-      exitSetClosed(other_exit, closed);
-      send_to_list(roomGetCharacters(to),
-		   "%s %s from the other side.\r\n",
-		   (*exitGetName(other_exit)?exitGetName(other_exit):
-		    "An exit"),
-		   (closed ? "closes" : "opens"));
-    }
-
-    // are we changing the lock state, and the exit is closed?
-    if(exitIsLocked(other_exit) != locked && exitIsClosed(other_exit)) {
-      exitSetLocked(other_exit, locked);
-      send_to_list(roomGetCharacters(to),
-		   "%s %s from the other side.\r\n",
-		   (*exitGetName(other_exit)?exitGetName(other_exit):
-		    "An exit"),
-		   (locked ? "locks" : "unlocks"));
-    }
-  }
-}
-
-
-
-//*****************************************************************************
-// player commands
-//*****************************************************************************
-
-
-//
-// try to lock an exit or container. The container can be anything in our
-// immediate visible range (room, inventory, body). do_lock automatically
-// checks if we have the key on us.
-//
-//  examples:
-//    lock door                lock a door in the room
-//    lock south               lock the south exit
-//    lock 2.chest             lock the 2nd chest in our visible range
-COMMAND(cmd_lock) {
-  int found_type = PARSE_NONE;
-  void    *found = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "[the] { obj.room.inv.eq exit }", 
-		 &found, &found_type))
-    return;
-
-  // did we find an exit or an object?
-  if(found_type == PARSE_EXIT) {
-    if(!exitIsClosed(found))
-      send_to_char(ch, "%s must be closed first.\r\n", exitGetName(found));
-    else if(exitIsLocked(found))
-      send_to_char(ch, "%s is already locked.\r\n", exitGetName(found));
-    else if(!*exitGetKey(found))
-      send_to_char(ch, "You cannot figure out how %s would be locked.\r\n",
-		   exitGetName(found));
-    else if(!has_obj(ch, get_fullkey_relative(exitGetKey(found), 
-			     get_key_locale(roomGetClass(charGetRoom(ch))))))
-      send_to_char(ch, "You cannot seem to find the key.\r\n");
-    else {
-      send_to_char(ch, "You lock %s.\r\n", exitGetName(found));
-      send_around_char(ch, TRUE, "%s locks %s.\r\n", 
-		       charGetName(ch), exitGetName(found));
-      exitSetLocked(found, TRUE);
-
-      // and try the other side
-      try_manip_other_exit(charGetRoom(ch), found, exitIsClosed(found), TRUE);
-    }
-  }
-
-  // object found
-  else { // if(found_type == PARSE_OBJ) {
-    if(!objIsType(found, "container"))
-      send_to_char(ch, "%s is not a container.\r\n", objGetName(found));
-    else if(!containerIsClosed(found))
-      send_to_char(ch, "%s must be closed first.\r\n", objGetName(found));
-    else if(containerIsLocked(found))
-      send_to_char(ch, "%s is already locked.\r\n", objGetName(found));
-    else if(!*containerGetKey(found))
-      send_to_char(ch, "You cannot figure out how %s would be locked.\r\n",
-		   objGetName(found));
-    else if(!has_obj(ch, get_fullkey_relative(containerGetKey(found),
-				     get_key_locale(objGetClass(found)))))
-      send_to_char(ch, "You cannot seem to find the key.\r\n");
-    else {
-      send_to_char(ch, "You lock %s.\r\n", objGetName(found));
-      message(ch, NULL, found, NULL, TRUE, TO_ROOM, "$n locks $o.");
-      containerSetLocked(found, TRUE);
-    }
-  }
-}
-
-
-//
-// the opposite of lock
-COMMAND(cmd_unlock) {
-  int found_type = PARSE_NONE;
-  void    *found = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "[the] { obj.room.inv exit }", 
-		 &found, &found_type))
-    return;
-
-  // did we find something?
-  if(found_type == PARSE_EXIT) {
-    if(!exitIsLocked(found))
-      send_to_char(ch, "%s is not locked.\r\n", exitGetName(found));
-    else if(!*exitGetKey(found))
-      send_to_char(ch, "You cannot figure out how %s would be unlocked.\r\n",
-		   exitGetName(found));
-    else if(!has_obj(ch, get_fullkey_relative(exitGetKey(found), 
-			     get_key_locale(roomGetClass(charGetRoom(ch))))))
-      send_to_char(ch, "You cannot seem to find the key.\r\n");
-    else {
-      send_to_char(ch, "You unlock %s.\r\n", exitGetName(found));
-      send_around_char(ch, TRUE, "%s unlocks %s.\r\n", 
-		       charGetName(ch), exitGetName(found));
-      exitSetLocked(found, FALSE);
-
-      // and try the other side
-      try_manip_other_exit(charGetRoom(ch), found, exitIsClosed(found), FALSE);
-    }
-  }
-
-  else { // if(found_type == PARSE_OBJ) {
-    if(!objIsType(found, "container"))
-      send_to_char(ch, "%s is not a container.\r\n", objGetName(found));
-    else if(!containerIsLocked(found))
-      send_to_char(ch, "%s is not locked.\r\n", objGetName(found));
-    else if(!*containerGetKey(found))
-      send_to_char(ch, "You cannot figure out how %s would be unlocked.\r\n",
-		   objGetName(found));
-    else if(!has_obj(ch, get_fullkey_relative(containerGetKey(found), 
-				     get_key_locale(objGetClass(found)))))
-      send_to_char(ch, "You cannot seem to find the key.\r\n");
-    else {
-      send_to_char(ch, "You unlock %s.\r\n", objGetName(found));
-      message(ch, NULL, found, NULL, TRUE, TO_ROOM, "$n unlocks $o.");
-      containerSetLocked(found, FALSE);
-    }
-  }
-}
-
-
-//
-//  put one thing into another. The thing you wish to put must be in
-//  your inventory. The container must be in your immediate visible range
-//  (room, inventory, body)
-//
-//  usage: put [the] <thing> [in the] <container>
-//
-//  examples:
-//    put coin bag             put a coin into the bag
-//    put all.shirt closet     put all of the shirts in the closet
-COMMAND(cmd_put) {
-  void    *found = NULL;
-  bool  multiple = FALSE;
-  OBJ_DATA *cont = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, 
-		 "[the] obj.inv.multiple [in the] obj.room.inv",
-		 &found, &multiple, &cont))
-    return;
-  
-  // make sure we have a container
-  if(!objIsType(cont, "container"))
-    send_to_char(ch, "%s is not a container.\r\n", objGetName(cont));
-
-  // did we find a list of things or a single item?
-  else if(multiple == FALSE)
-    do_put(ch, found, cont);
-
-  // we have to move a bunch of things
-  else {
-    OBJ_DATA *obj = NULL;
-    while( (obj = listPop(found)) != NULL)
-      do_put(ch, obj, cont);
-    deleteList(found);
-  }
-}
-
-
-//
-//  attempt to open a door or container. The container must be in our immediate
-//  visible range (room, inventory, body).
-//
-//  usage: open [the] <thing>
-//
-//  examples:
-//    open door               open a door
-//    open 2.bag              open your second bag
-//    open east               open the east exit
-//    open backpack on self   open a backpack you are wearing
-COMMAND(cmd_open) {
-  void    *found = NULL;
-  int found_type = PARSE_NONE;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "{ obj.room.inv.eq exit }",
-		 &found, &found_type))
-    return;
-
-  // open an exit
-  if(found_type == PARSE_EXIT) {
-    if(!exitIsClosable(found))
-      send_to_char(ch, "But %s cannot be opened!\r\n",
-		   (*exitGetName(found) ? exitGetName(found) : "it"));
-    else if(!exitIsClosed(found))
-      send_to_char(ch, "It is it easy to open something when someone "
-		   "has already done it for you!\r\n");
-    else if(exitIsLocked(found))
-      send_to_char(ch, "%s appears to be locked.\r\n",
-		   (*exitGetName(found) ? exitGetName(found) : "It"));
-    else {
-      mssgprintf(ch, NULL, NULL, NULL, FALSE, TO_ROOM, "$n opens %s.", 
-		 (*exitGetName(found) ? exitGetName(found) : "an exit"));
-      send_to_char(ch, "You open %s.\r\n",
-		   (*exitGetName(found) ? exitGetName(found) : "the exit"));
-      exitSetClosed(found, FALSE);
-
-      // try opening the other side
-      try_manip_other_exit(charGetRoom(ch), found, FALSE, exitIsLocked(found));
-      hookRun("open_door", ch, found);
-    }
-  }
-
-  // open a container
-  else { // if(found_type == FOUND_OBJ) {
-    // make sure it's a container and it can be opened
-    if(!objIsType(found, "container") || !containerIsClosable(found))
-      send_to_char(ch, "But it cannot be opened!\r\n");
-    else if(!containerIsClosed(found))
-      send_to_char(ch, "It is already opened.\r\n");
-    else if(containerIsLocked(found))
-      send_to_char(ch, "It appears to be locked.\r\n");
-    else {
-      send_to_char(ch, "You open %s.\r\n", objGetName(found));
-      message(ch, NULL, found, NULL, FALSE, TO_ROOM, "$n opens $o.");
-      containerSetClosed(found, FALSE);
-      hookRun("open_obj", ch, found);
-    }
-  }
-}
-
-
-//
-// cmd_close is used to close containers and exits.
-//   usage: open <thing>
-//
-//   examples:
-//     close door               close a door
-//     close 2.bag              close your second bag
-//     close east               close the east exit
-//     close backpack on self   close a backpack you are wearing
-COMMAND(cmd_close) {
-  void    *found = NULL;
-  int found_type = PARSE_NONE;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "{ obj.room.eq.inv exit }",
-		 &found, &found_type))
-    return;
-
-  // close an exit
-  if(found_type == PARSE_EXIT) {
-    if(!exitIsClosable(found))
-      send_to_char(ch, "But %s cannot be closed!\r\n",
-		   (*exitGetName(found) ? exitGetName(found) : "it"));
-    else if(exitIsClosed(found))
-      send_to_char(ch, "It is easy to close something when someone "
-		   "has already done it for you!\r\n");
-    else {
-      char other_buf[SMALL_BUFFER];
-      sprintf(other_buf, "$n closes %s.", (*exitGetName(found) ?
-					   exitGetName(found) : "an exit"));
-      message(ch, NULL, NULL, NULL, FALSE, TO_ROOM, other_buf);
-      send_to_char(ch, "You close %s.\r\n",
-		   (*exitGetName(found) ? exitGetName(found) : "the exit"));
-      exitSetClosed(found, TRUE);
-
-      // try opening the other side
-      try_manip_other_exit(charGetRoom(ch), found, TRUE, exitIsLocked(found));
-    }
-  }
-
-  // close a container
-  else { // if(found_type == PARSE_OBJ) {
-    // make sure it's a container and it can be closed
-    if(!objIsType(found, "container") || !containerIsClosable(found))
-      send_to_char(ch, "But it cannot even be closed!\r\n");
-    else if(containerIsClosed(found))
-      send_to_char(ch, "It is already closed.\r\n");
-    else {
-      send_to_char(ch, "You close %s.\r\n", objGetName(found));
-      message(ch, NULL, found, NULL, FALSE, TO_ROOM, "$n closes $o.");
-      containerSetClosed(found, TRUE);
-    }
-  }
-}
-
-
-//
-// cmd_get is used to move objects from containers or the room to your inventory
-//   usage: get <object> <from>
-//
-//   examples:
-//     get sword            get a sword from the room
-//     get 2.cupcake bag    get the second cupcake from your bag
-//     get all.coin         get all of the coins on the ground
-COMMAND(cmd_get) {
-  if(!arg || !*arg) {
-    send_to_char(ch, "What did you want to get?\r\n");
-    return;
-  }
-
-  // the name of what we're trying to get
-  char name[SMALL_BUFFER];
-  arg = one_arg(arg, name);
-
-  // first check to see if we're trying to get from a container
-  OBJ_DATA *cont = NULL;
-  if(*arg) {
-    cont = generic_find(ch, arg, FIND_TYPE_OBJ, FIND_SCOPE_IMMEDIATE,
-			FALSE, NULL);
-    // were we trying to get something from a container 
-    // but couldn't find the container?
-    if(cont == NULL) {
-      send_to_char(ch, "Get what from what?\r\n");
-      return;
-    }
-    else if(!objIsType(cont, "container")) {
-      send_to_char(ch, "%s is not a container.\r\n", objGetName(cont));
-      return;
-    }
-    else if(containerIsClosed(cont)) {
-      send_to_char(ch, "%s is closed. Try opening it first.\r\n", 
-		   objGetName(cont));
-      return;
-    }
-  }
-
-  int found_type = FOUND_NONE;
-  void    *found = NULL;
-
-  // if we have a container, just search the container for things
-  if(cont != NULL) {
-    // oi... this is going to get messy. We have to do some stuff
-    // that the generic_find will usually do for us - i.e. checking
-    // to see if we need to get a list of items or a single item
-    // we should really add a new function in the handler for doing this
-    int count = 1;
-    get_count(name, name, &count);
-    if(count == COUNT_ALL) {
-      found_type = FOUND_LIST;
-      found      = find_all_objs(ch, objGetContents(cont), name, NULL, TRUE);
-    }
-    else {
-      found_type = FOUND_OBJ;
-      found      = find_obj(ch, objGetContents(cont), count, name, NULL, TRUE);
-    }
-  }
-  // otherwise, search the room for visible things
-  else
-    found = generic_find(ch, name, 
-			 FIND_TYPE_OBJ, 
-			 FIND_SCOPE_ROOM | FIND_SCOPE_VISIBLE, 
-			 TRUE, &found_type);
-
-
-  if(found && found_type == FOUND_OBJ)
-    do_get(ch, found, cont);
-  else if(found && found_type == FOUND_LIST) {
-    OBJ_DATA *obj = NULL;
-    while( (obj = listPop(found)) != NULL)
-      do_get(ch, obj, cont);
-    deleteList(found);
-  }
-  else
-    send_to_char(ch, "You can't find what you're looking for.\r\n");
-}
-
-
-//
-// cmd_give is used to transfer an object in your possession to 
-// another character
-//   usage: give [the] <object> [to] <person>
-//
-//   examples:
-//     give doll girl           give a doll in your inventory to a girl
-//     give all.coin robber     give all of your money to the robber
-//
-COMMAND(cmd_give) {
-  CHAR_DATA *recv = NULL;  // the person we're giving stuff to
-  void   *to_give = NULL;  // may be a list or a single item
-  bool   multiple = FALSE; // are we giving one or multiple items?
-
-  // try to give objects from our inventory. We can give multiple items. Give
-  // them to a person in the room who is not ourself. The fact we can see the
-  // receiver is implied. If we fail to find our items or receiver, parse_args
-  // will tell the character what he did wrong, and we will halt the command
-  if(!parse_args(ch,TRUE,cmd,arg, "[the] obj.inv.multiple [to] ch.room.noself",
-		 &to_give, &multiple, &recv))
-    return;
-
-  // just a single item to give...
-  if(multiple == FALSE)
-    do_give(ch, recv, to_give);
-  // we have a list of items to give
-  else {
-    LIST_ITERATOR *obj_i = newListIterator(to_give);
-    OBJ_DATA        *obj = NULL;
-    ITERATE_LIST(obj, obj_i) {
-      do_give(ch, recv, obj);
-    } deleteListIterator(obj_i);
-
-    // we also have to delete the list that parse_args sent us
-    deleteList(to_give);
-  }
-}
-
-
-//
-// cmd_drop is used to transfer an object in your inventory to the ground
-//   usage: drop <item>
-//
-//   examples:
-//     drop bag          drop a bag you have
-//     drop all.bread    drop all of the bread you are carrying
-//     drop 2.cupcake    drop the second cupcake in your posession
-COMMAND(cmd_drop) {
-  void   *found = NULL;
-  bool multiple = FALSE;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "[the] obj.inv.multiple",&found,&multiple))
-    return;
-
-  // are we dropping a list of things, or just one?
-  if(multiple == FALSE)
-    do_drop(ch, found);
-
-  // we got a list of things... drop 'em all
-  else {
-    OBJ_DATA *obj = NULL;
-    while( (obj = listPop(found)) != NULL)
-      do_drop(ch, obj);
-    deleteList(found);
-  }
-}
-
-
-//
-// cmd_wear is used to equip wearable items in your inventory to your body
-//   usage: wear [object] [where]
-//
-//   examples:
-//     wear shirt                            equip a shirt
-//     wear all.ring                         wear all of the rings in your 
-//                                           inventory
-//     wear gloves left hand, right hand     wear the gloves on your left and
-//                                           right hands
-COMMAND(cmd_wear) {
-  void   *found = NULL;
-  bool multiple = FALSE;
-  char   *where = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "[the] obj.inv.multiple | [on] string", 
-		 &found, &multiple, &where))
-    return;
-
-  // are we wearing one thing, or multiple things?
-  if(multiple == FALSE)
-    do_wear(ch, found, where);
-
-  // we're trying to wear multiple items
-  else {
-    OBJ_DATA *obj = NULL;
-    while( (obj = listPop(found)) != NULL)
-      do_wear(ch, obj, where);
-    deleteList(found);
-  }
-}
-
-
-//
-// cmd_remove is used to unequip items on your body to your inventory
-//   usage: remove <item>
-//
-//   examples:
-//     remove mask             remove the mask you are wearing
-//     remove all.ring         remove all the rings you have on
-//     remove 2.ring           remove the 2nd ring you have equipped
-COMMAND(cmd_remove) {
-  void   *found = NULL;
-  bool multiple = FALSE;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "obj.eq.multiple", &found, &multiple))
-    return;
-
-  // are we trying to remove one thing, or multiple things?
-  if(multiple == FALSE)
-    do_remove(ch, found);
-
-  // removing multiple things...
-  else {
-    OBJ_DATA *obj = NULL;
-    while( (obj = listPop(found)) != NULL)
-      do_remove(ch, obj);
-    deleteList(found);
-  }
-}
diff -ruN ../nakedmudv3.1/src/cmd_misc.c src/cmd_misc.c
--- ../nakedmudv3.1/src/cmd_misc.c	Sun Dec  4 20:03:07 2005
+++ src/cmd_misc.c	Wed Dec 31 17:00:00 1969
@@ -1,102 +0,0 @@
-//*****************************************************************************
-//
-// cmd_misc.c
-//
-// a collection of miscellaneous commands that come with NakedMud(tm)
-//
-//*****************************************************************************
-#include "mud.h"
-#include "utils.h"
-#include "character.h"
-#include "socket.h"
-#include "save.h"
-#include "event.h"
-#include "action.h"
-
-
-
-//
-// stop performing the character's current action
-COMMAND(cmd_stop) {
-#ifdef MODULE_FACULTY
-  if(!is_acting(ch, FACULTY_ALL))
-    send_to_char(ch, "But you're not currently performing an action!\r\n");
-  else
-    interrupt_action(ch, FACULTY_ALL);
-#else
-  if(!is_acting(ch, 1))
-    send_to_char(ch, "But you're not currently performing an action!\r\n");
-  else
-    interrupt_action(ch, 1);
-#endif
-}
-
-
-//
-// clear the screen
-COMMAND(cmd_clear) {
-  send_to_char(ch, "\033[H\033[J");
-}
-
-
-//
-// quit the game
-COMMAND(cmd_quit) {
-  // log the attempt
-  log_string("%s has left the game.", charGetName(ch));
-  save_player(ch);
-
-  // 
-  // gotta make sure we have a socket. Who knows...
-  // a mobile might be trying to quit
-  if(charGetSocket(ch)) {
-    SOCKET_DATA *sock = charGetSocket(ch);
-    charSetSocket(ch, NULL);
-    socketSetChar(sock, NULL);
-    socketPopInputHandler(sock);
-  }
-
-  extract_mobile(ch);
-}
-
-
-//
-// save the character
-COMMAND(cmd_save) {
-  save_player(ch);
-  text_to_char(ch, "Saved.\r\n");
-}
-
-
-//
-// the function for executing a delayed command
-void event_delayed_cmd(CHAR_DATA *ch, void *data, char *cmd) {
-  do_cmd(ch, cmd, TRUE);
-}
-
-
-//
-// Perform a command, but delay its execution by a couple seconds
-COMMAND(cmd_delay) {
-  int       secs = 0;
-  char *to_delay = NULL;
-
-  if(!parse_args(ch, TRUE, cmd, arg, "int string", &secs, &to_delay))
-    return;
-
-  if(secs < 1)
-    send_to_char(ch, "You can only delay commands for positive amounts of time.\r\n");
-  else {
-    send_to_char(ch, "You delay '%s' for %d seconds.\r\n", to_delay, secs);
-    start_event(ch, secs SECONDS, event_delayed_cmd, NULL, NULL, to_delay);
-  }
-}
-
-//
-// Displays the MOTD to the character
-COMMAND(cmd_motd) {
-  // only bother sending it if we have a socket. And then page it, incase
-  // the motd is especially long.
-  if(charGetSocket(ch))
-    page_string(charGetSocket(ch), bufferString(motd));
-}
diff -ruN ../nakedmudv3.1/src/commands.h src/commands.h
--- ../nakedmudv3.1/src/commands.h	Sun Dec  4 20:03:07 2005
+++ src/commands.h	Sat Jul  1 20:06:58 2006
@@ -4,91 +4,16 @@
 //
 // commands.h
 //
-// contains a list of all commands available on the MUD.
+// contains a list of all commands available on the MUD. This is rather skimpy
+// since so many things were rewritten in Python.
 //
 //*****************************************************************************
 
-/* cmd_admin.c */
-COMMAND(cmd_goto);
-COMMAND(cmd_transfer);
-COMMAND(cmd_copyover);
-COMMAND(cmd_shutdown);
-COMMAND(cmd_linkdead);
-COMMAND(cmd_repeat);
-COMMAND(cmd_at);
-COMMAND(cmd_lockdown);
-COMMAND(cmd_force);
-COMMAND(cmd_pulserate);
-
-
-/* cmd_builder.c */
-COMMAND(cmd_load);
-COMMAND(cmd_purge);
-COMMAND(cmd_zreset);
-COMMAND(cmd_rlist);
-COMMAND(cmd_mlist);
-COMMAND(cmd_olist);
-COMMAND(cmd_zlist);
-COMMAND(cmd_rdelete);
-COMMAND(cmd_mdelete);
-COMMAND(cmd_odelete);
-COMMAND(cmd_mrename);
-COMMAND(cmd_rrename);
-COMMAND(cmd_orename);
-COMMAND(cmd_rreload);
-
-
-/* cmd_manip.c */
-COMMAND(cmd_unlock);
-COMMAND(cmd_lock);
-COMMAND(cmd_put);
-COMMAND(cmd_get);
-COMMAND(cmd_drop);
-COMMAND(cmd_wear);
-COMMAND(cmd_remove);
-COMMAND(cmd_give);
-COMMAND(cmd_close);
-COMMAND(cmd_open);
-
-
-/* cmd_comm.c */
-COMMAND(cmd_ask);
-COMMAND(cmd_tell);
-COMMAND(cmd_greet);
-COMMAND(cmd_say);
-COMMAND(cmd_chat);
-COMMAND(cmd_emote);
-COMMAND(cmd_gemote);
-COMMAND(cmd_page);
-
-
-/* cmd_misc.c */
-COMMAND(cmd_delay);
-COMMAND(cmd_clear);
-COMMAND(cmd_quit);
-COMMAND(cmd_save);
 COMMAND(cmd_commands);
 COMMAND(cmd_compress);
-COMMAND(cmd_motd);
-
-
-/* inform.c */
-COMMAND(cmd_who);
 COMMAND(cmd_look);
-COMMAND(cmd_inventory);
-COMMAND(cmd_equipment);
 COMMAND(cmd_groupcmds);
 COMMAND(cmd_more);
 COMMAND(cmd_back);
-COMMAND(cmd_stop);
-
-
-/* movement.c */
-COMMAND(cmd_move);
-COMMAND(cmd_sit);
-COMMAND(cmd_stand);
-COMMAND(cmd_wake);
-COMMAND(cmd_sleep);
-COMMAND(cmd_enter);
 
 #endif // __COMMAND_H
diff -ruN ../nakedmudv3.1/src/event.c src/event.c
--- ../nakedmudv3.1/src/event.c	Sun Dec  4 20:03:07 2005
+++ src/event.c	Sat Jul  1 20:06:58 2006
@@ -96,6 +96,24 @@
     event->on_complete(event->owner, event->data, event->arg);
 }
 
+void interrupt_events_obj_hook(const char *info) {
+  OBJ_DATA *obj = NULL;
+  hookParseInfo(info, &obj);
+  interrupt_events_involving(obj);
+}
+
+void interrupt_events_char_hook(const char *info) {
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &ch);
+  interrupt_events_involving(ch);
+}
+
+void interrupt_events_room_hook(const char *info) {
+  ROOM_DATA *room = NULL;
+  hookParseInfo(info, &room);
+  interrupt_events_involving(room);
+}
+
 
 
 //*****************************************************************************
@@ -110,9 +128,9 @@
 
   // make sure all events involving the object/char are cancelled when
   // either is extracted from the game
-  hookAdd("obj_from_game",  interrupt_events_involving);
-  hookAdd("char_from_game", interrupt_events_involving);
-  hookAdd("room_from_game", interrupt_events_involving);
+  hookAdd("obj_from_game",  interrupt_events_obj_hook);
+  hookAdd("char_from_game", interrupt_events_char_hook);
+  hookAdd("room_from_game", interrupt_events_room_hook);
 }
 
 void interrupt_event(EVENT_DATA *event) {
diff -ruN ../nakedmudv3.1/src/gameloop.c src/gameloop.c
--- ../nakedmudv3.1/src/gameloop.c	Sun Dec  4 20:03:07 2005
+++ src/gameloop.c	Sat Jul  1 20:06:58 2006
@@ -303,7 +303,7 @@
   game_loop(control);
 
   // run our finalize hooks
-  hookRun("shutdown");
+  hookRun("shutdown", "");
 
   // close down the socket
   close(control);
diff -ruN ../nakedmudv3.1/src/handler.c src/handler.c
--- ../nakedmudv3.1/src/handler.c	Sun Dec  4 20:03:07 2005
+++ src/handler.c	Sat Jul  1 20:06:58 2006
@@ -29,6 +29,8 @@
 #include "items/items.h"
 #include "items/container.h"
 #include "items/worn.h"
+#include "scripts/scripts.h"
+#include "scripts/pymud.h"
 
 
 
@@ -44,7 +46,7 @@
   propertyTablePut(obj_table, obj);
 
   // execute all of our to_game hooks
-  hookRun("obj_to_game", obj);
+  hookRun("obj_to_game", hookBuildInfo("obj", obj));
 
   // also add all contents
   if(listSize(objGetContents(obj)) > 0) {
@@ -61,7 +63,7 @@
   propertyTablePut(room_table, room);
 
   // execute all of our to_game hooks
-  hookRun("room_to_game", room);
+  hookRun("room_to_game", hookBuildInfo("rm", room));
 
   // add contents
   if(listSize(roomGetContents(room)) > 0) {
@@ -87,9 +89,9 @@
   char           *dir = NULL;
   ITERATE_LIST(dir, ex_i) {
     exit_to_game(roomGetExit(room, dir));
-    if(dirGetNum(dir) == DIR_NONE)
+    if(get_cmd_move() != NULL && dirGetNum(dir) == DIR_NONE)
       nearMapPut(roomGetCmdTable(room), dir, NULL,
-		 newCmd(dir, cmd_move, POS_STANDING, POS_FLYING,
+		 newPyCmd(dir, get_cmd_move(), POS_STANDING, POS_FLYING,
 			"player", TRUE, TRUE));
   } deleteListIterator(ex_i);
   deleteListWith(ex_list, free);
@@ -100,7 +102,7 @@
   propertyTablePut(mob_table, ch);
 
   // execute all of our to_game hooks
-  hookRun("char_to_game", ch);
+  hookRun("char_to_game", hookBuildInfo("ch", ch));
 
   // also add inventory
   if(listSize(charGetInventory(ch)) > 0) {
@@ -128,12 +130,12 @@
 }
 
 void obj_from_game(OBJ_DATA *obj) {
+  // go through all of our fromgame hooks
+  hookRun("obj_from_game", hookBuildInfo("obj", obj));
+
   listRemove(object_list, obj);
   propertyTableRemove(obj_table, objGetUID(obj));
 
-  // go through all of our fromgame hooks
-  hookRun("obj_from_game", obj);
-
   // also remove everything that is contained within the object
   if(listSize(objGetContents(obj)) > 0) {
     LIST_ITERATOR *cont_i = newListIterator(objGetContents(obj));
@@ -145,12 +147,12 @@
 }
 
 void room_from_game(ROOM_DATA *room) {
+  // go through all of our fromgame hooks
+  hookRun("room_from_game", hookBuildInfo("rm", room));
+
   listRemove(room_list, room);
   propertyTableRemove(room_table, roomGetUID(room));
 
-  // go through all of our fromgame hooks
-  hookRun("room_from_game", room);
-
   // also remove all the objects contained within the room
   if(listSize(roomGetContents(room)) > 0) {
     LIST_ITERATOR *cont_i = newListIterator(roomGetContents(room));
@@ -180,12 +182,12 @@
 }
 
 void char_from_game(CHAR_DATA *ch) {
+  // go through all of our fromgame hooks
+  hookRun("char_from_game", hookBuildInfo("ch", ch));
+
   listRemove(mobile_list, ch);
   propertyTableRemove(mob_table, charGetUID(ch));
 
-  // go through all of our fromgame hooks
-  hookRun("char_from_game", ch);
-
   // also remove inventory
   if(listSize(charGetInventory(ch)) > 0) {
     LIST_ITERATOR *inv_i = newListIterator(charGetInventory(ch));
@@ -273,106 +275,6 @@
 
 
 //*****************************************************************************
-// do_get/give/drop/etc...
-//*****************************************************************************
-void do_get(CHAR_DATA *ch, OBJ_DATA *obj, OBJ_DATA *container) {
-  if(bitIsOneSet(objGetBits(obj), "notake"))
-    send_to_char(ch, "You cannot take %s.\r\n", objGetName(obj));
-  else if(container) {
-    send_to_char(ch, "You get %s from %s.\r\n", 
-		 objGetName(obj), objGetName(container));
-    message(ch, NULL, obj, container, TRUE, TO_ROOM,
-	    "$n gets $o from $O.");
-    obj_from_obj(obj);
-    obj_to_char(obj, ch);
-  }
-  else {
-    send_to_char(ch, "You get %s.\r\n", objGetName(obj));
-    message(ch, NULL, obj, NULL, TRUE, TO_ROOM,
-	    "$n gets $o.");
-    obj_from_room(obj);
-    obj_to_char(obj, ch);
-    hookRun("get", ch, obj);
-  }
-}
-
-void do_put(CHAR_DATA *ch, OBJ_DATA *obj, OBJ_DATA *container) {
-  if(containerIsClosed(container))
-    send_to_char(ch, "%s is closed. Open it first.\r\n", 
-		 see_obj_as(ch, container));
-  else if(obj == container)
-    send_to_char(ch, "You cannot put %s into itself.\r\n", objGetName(obj));
-  // make sure we have enough room
-  else if(objGetWeight(obj) > 
-	  (containerGetCapacity(container) - 
-	   objGetWeight(container) + objGetWeightRaw(container)))
-    send_to_char(ch, "There is not enough room in %s for %s.\r\n", 
-		 see_obj_as(ch, container), see_obj_as(ch, obj));
-  // do the move
-  else {
-    obj_from_char(obj);
-    obj_to_obj(obj, container);
-    send_to_char(ch, "You put %s into %s.\r\n", 
-		 see_obj_as(ch, obj), see_obj_as(ch, container));
-    message(ch, NULL, obj, container, TRUE, TO_ROOM,
-	    "$n puts $o into $O.");
-  }
-}
-
-
-void do_give(CHAR_DATA *ch, CHAR_DATA *recv, OBJ_DATA *obj) {
-  message(ch, recv, obj, NULL, TRUE, TO_ROOM, "$n gives $o to $N.");
-  message(ch, recv, obj, NULL, TRUE, TO_VICT, "$n gives $o to you.");
-  message(ch, recv, obj, NULL, TRUE, TO_CHAR, "You give $o to $N.");
-  obj_from_char(obj);
-  obj_to_char(obj, recv);
-
-  // run all of our give/receive hooks
-  hookRun("give", ch, recv, obj);
-}
-
-
-void do_drop(CHAR_DATA *ch, OBJ_DATA *obj) {
-  send_to_char(ch, "You drop %s.\r\n", objGetName(obj));
-  message(ch, NULL, obj, NULL, TRUE, TO_ROOM, "$n drops $o.");
-  obj_from_char(obj);
-  obj_to_room(obj, charGetRoom(ch));
-
-  // run all of our drop hooks
-  hookRun("drop", ch, obj);
-}
-
-
-void do_wear(CHAR_DATA *ch, OBJ_DATA *obj, const char *where) {
-  if(!objIsType(obj, "worn"))
-    send_to_char(ch, "You cannot wear %s!\r\n", objGetName(obj));
-  else {
-    obj_from_char(obj);
-    if(try_equip(ch, obj, where, wornGetPositions(obj))) {
-      message(ch, NULL, obj, NULL, TRUE, TO_CHAR, "You equip $o.");
-      message(ch, NULL, obj, NULL, TRUE, TO_ROOM, "$n equips $o.");
-    }
-    else {
-      send_to_char(ch, "You could not equip %s.\r\n", objGetName(obj));
-      obj_to_char(obj, ch);
-    }
-  }
-}
-
-
-void do_remove(CHAR_DATA *ch, OBJ_DATA *obj) {
-  if(try_unequip(ch, obj)) {
-    message(ch, NULL, obj, NULL, TRUE, TO_CHAR, "You remove $o.");
-    message(ch, NULL, obj, NULL, TRUE, TO_ROOM, "$n removes $o.");
-    obj_to_char(obj, ch);
-  }
-  else
-    send_to_char(ch, "You were unable to remove %s.\r\n", objGetName(obj));
-}
-
-
-
-//*****************************************************************************
 // functions related to equipping and unequipping items
 //*****************************************************************************
 bool try_equip(CHAR_DATA *ch, OBJ_DATA *obj, const char *wanted_pos,
@@ -428,17 +330,14 @@
       success = bodyEquipPosnames(charGetBody(ch), obj, wanted_pos);
   }
 
-  if(success == TRUE) {
+  if(success == TRUE)
     objSetWearer(obj, ch);
-    hookRun("wear", ch, obj);
-  }
   return success;
 }
 
 bool try_unequip(CHAR_DATA *ch, OBJ_DATA *obj) {
   if(bodyUnequip(charGetBody(ch), obj)) {
     objSetWearer(obj, NULL);
-    hookRun("remove", ch, obj);
     return TRUE;
   }
   return FALSE;
@@ -453,7 +352,6 @@
   while( (obj = listPop(eq)) != NULL) {
     if(bodyUnequip(charGetBody(ch), obj)) {
       objSetWearer(obj, NULL);
-      hookRun("remove", ch, obj);
       obj_to_char(obj, ch);
     }
   } deleteList(eq);
diff -ruN ../nakedmudv3.1/src/help/help.c src/help/help.c
--- ../nakedmudv3.1/src/help/help.c	Sun Dec  4 20:03:07 2005
+++ src/help/help.c	Sat Jul  1 20:06:58 2006
@@ -39,18 +39,22 @@
   char *info;       // the information in the helpfile
   char *editor;     // who edited the helpfile?
   char *timestamp;  // when was it last edited?
+  // user_group is currently unused
+  char *user_group; // the user group the helpfile belongs to, if any
   LIST *backups;    // a chronologically sorted list of backup helps
 } HELP_DATA;
 
 
-HELP_DATA *newHelp(const char *editor, const char *timestamp,
-		   const char *keywords, const char *info) {
-  HELP_DATA *data = malloc(sizeof(HELP_DATA));
-  data->keywords  = strdupsafe(keywords);
-  data->editor    = strdupsafe(editor);
-  data->info      = strdupsafe(info);
-  data->timestamp = strdupsafe(timestamp);
-  data->backups   = newList();
+HELP_DATA *newHelp(const char *editor, const char *timestamp, 
+		   const char *keywords, const char *user_group, 
+		   const char *info) {
+  HELP_DATA *data   = malloc(sizeof(HELP_DATA));
+  data->keywords    = strdupsafe(keywords);
+  data->editor      = strdupsafe(editor);
+  data->info        = strdupsafe(info);
+  data->timestamp   = strdupsafe(timestamp);
+  data->user_group  = strdupsafe(user_group);
+  data->backups     = newList();
   return data;
 }
 
@@ -59,6 +63,7 @@
   if(data->keywords)  free(data->keywords);
   if(data->editor)    free(data->editor);
   if(data->timestamp) free(data->timestamp);
+  if(data->user_group)free(data->user_group);
   if(data->info)      free(data->info);
   free(data);
 }
@@ -67,6 +72,7 @@
   HELP_DATA *data = newHelp(read_string(set, "editor"),
 			    read_string(set, "timestamp"),
 			    read_string(set, "keywords"),
+			    read_string(set, "user_group"),
 			    read_string(set, "info"));
   deleteList(data->backups);
   data->backups = gen_read_list(read_list(set, "backups"), helpRead);
@@ -78,6 +84,7 @@
   store_string(set, "keywords",  help->keywords);
   store_string(set, "editor",    help->editor);
   store_string(set, "timestamp", help->timestamp);
+  store_string(set, "user_group",help->user_group);
   store_string(set, "info",      help->info);
   store_list  (set, "backups",   gen_store_list(help->backups, helpStore));
   return set;
@@ -238,6 +245,15 @@
 //   help <topic>
 //
 COMMAND(cmd_help) {
+  // make sure we can view it, first
+  HELP_DATA *help = get_help_data(arg, TRUE);
+  if(help != NULL && *help->user_group) {
+    if(!bitIsSet(charGetUserGroups(ch), help->user_group)) {
+      send_to_char(ch, "You may not view that help file.\r\n");
+      return;
+    }
+  }
+
   BUFFER *buf = build_help(arg);
   if(buf == NULL)
     send_to_char(ch, "No help exists on that topic.\r\n");
@@ -486,7 +502,7 @@
 
   if(data != NULL) {
     HELP_DATA *help_old = newHelp(data->editor, data->timestamp, data->keywords,
-				  data->info);
+				  "", data->info);
     if(data->editor)    free(data->editor);
     if(data->timestamp) free(data->timestamp);
     if(data->info)      free(data->info);
@@ -498,7 +514,7 @@
     listPut(data->backups, help_old);
   }
   else
-    add_help(newHelp(editor, get_time(), keyword, info));
+    add_help(newHelp(editor, get_time(), keyword, "", info));
 
   save_help();
 }
diff -ruN ../nakedmudv3.1/src/hooks.c src/hooks.c
--- ../nakedmudv3.1/src/hooks.c	Sun Dec  4 20:03:07 2005
+++ src/hooks.c	Sat Jul  1 20:06:58 2006
@@ -19,6 +19,11 @@
 //*****************************************************************************
 #include "mud.h"
 #include "utils.h"
+#include "character.h"
+#include "object.h"
+#include "room.h"
+#include "exit.h"
+#include "account.h"
 #include "hooks.h"
 
 
@@ -28,10 +33,13 @@
 //*****************************************************************************
 
 // the table of all our installed hooks
-HASHTABLE *hook_table = NULL;
+HASHTABLE *hook_table   = NULL;
 
-// a table of all our handlers for running hooks
-HASHTABLE *hook_handler_table = NULL;
+// the list of functions called whenever a hook is run
+LIST *monitors = NULL;
+
+// a buffer for building hook info on
+BUFFER      *info_buf = NULL;
 
 
 
@@ -39,141 +47,181 @@
 // implementation of hooks.h
 //*****************************************************************************
 void init_hooks(void) {
-  // make our required tables
-  hook_handler_table = newHashtable();
-  hook_table         = newHashtable();
-
-  // set up our basic types of hooks
-  hook_add_handler("shutdown",             hook_handler_0_args);
-  hook_add_handler("create_account",       hook_handler_1_arg);
-  hook_add_handler("create_player",        hook_handler_1_arg);
-  hook_add_handler("enter",                hook_handler_2_args);
-  hook_add_handler("exit",                 hook_handler_3_args);
-  hook_add_handler("ask",                  hook_handler_3_args);
-  hook_add_handler("say",                  hook_handler_2_args);
-  hook_add_handler("greet",                hook_handler_2_args);
-  hook_add_handler("obj_to_game",          hook_handler_1_arg);
-  hook_add_handler("char_to_game",         hook_handler_1_arg);
-  hook_add_handler("room_to_game",         hook_handler_1_arg);
-  hook_add_handler("obj_from_game",        hook_handler_1_arg);
-  hook_add_handler("char_from_game",       hook_handler_1_arg);
-  hook_add_handler("room_from_game",       hook_handler_1_arg);
-  hook_add_handler("get",                  hook_handler_2_args);
-  hook_add_handler("give",                 hook_handler_3_args);
-  hook_add_handler("drop",                 hook_handler_2_args);
-  hook_add_handler("wear",                 hook_handler_2_args);
-  hook_add_handler("remove",               hook_handler_2_args);
-  hook_add_handler("reset",                hook_handler_1_arg);
-  hook_add_handler("open_door",            hook_handler_2_args);
-  hook_add_handler("open_obj",             hook_handler_2_args);
-  hook_add_handler("close_door",           hook_handler_2_args);
-  hook_add_handler("close_obj",            hook_handler_2_args);
-}
-
-void hook_add_handler(const char *type, 
-		      void (* handler)(LIST *hooks, va_list args)) {
-  hashPut(hook_handler_table, type, handler);
+  // make our required variables
+  hook_table = newHashtable();
+  info_buf   = newBuffer(1);
+  monitors   = newList();
 }
 
-void hookAdd(const char *type, void *hook) {
+void hookRemove(const char *type, void (* func)(const char *)) {
+  LIST *list = hashGet(hook_table, type);
+  if(list != NULL) listRemove(list, func);
+}
+
+void hookAdd(const char *type, void (* func)(const char *)) {
   LIST *list = hashGet(hook_table, type);
   if(list == NULL) {
     list = newList();
     hashPut(hook_table, type, list);
   }
-  listQueue(list, hook);
+  listQueue(list, func);
 }
 
-void hookRun(const char *type, ...) {
-  LIST *list = hashGet(hook_table, type);
-  void (* handler)(LIST *hooks, va_list args) = 
-    hashGet(hook_handler_table, type);
-  if(list != NULL && handler != NULL) {
-    va_list args;
-    va_start(args, type);
-    handler(list, args);
-    va_end(args);
-  }
+void hookAddMonitor(void (* func)(const char *, const char *)) {
+  listQueue(monitors, func);
 }
 
-void hookRemove(const char *type, void *hook) {
+void hookRun(const char *type, const char *info) {
   LIST *list = hashGet(hook_table, type);
-  if(list != NULL) listRemove(list, hook);
+  if(list != NULL) {
+    char *info_dup = strdup(info);
+    LIST_ITERATOR *list_i = newListIterator(list);
+    void (* func)(const char *) = NULL;
+    ITERATE_LIST(func, list_i) {
+      func(info_dup);
+    } deleteListIterator(list_i);
+    free(info_dup);
+  }
+
+  // run our monitors
+  LIST_ITERATOR *mon_i = newListIterator(monitors);
+  void (* mon)(const char *, const char *) = NULL;
+  ITERATE_LIST(mon, mon_i) {
+    mon(type, info);
+  } deleteListIterator(mon_i);
+}
+
+const char *hookBuildInfo(const char *format, ...) {
+  // clear our workspace
+  bufferClear(info_buf);
+
+  // parse out all of our tokens
+  LIST *tokens           = parse_strings(format, ' ');
+  LIST_ITERATOR *token_i = newListIterator(tokens);
+  char *token            = NULL;
+  int   len              = listSize(tokens);
+  int   count            = 0;
+
+  // go through all of our tokens
+  va_list vargs;
+  va_start(vargs, format);
+  ITERATE_LIST(token, token_i) {
+    if(!strcasecmp(token, "ch"))
+      bprintf(info_buf, "ch.%d", charGetUID(va_arg(vargs, CHAR_DATA *)));
+    else if(!strcasecmp(token, "obj"))
+      bprintf(info_buf, "obj.%d", objGetUID(va_arg(vargs, OBJ_DATA *)));
+    else if(!strcasecmp(token, "rm") || !strcasecmp(token, "room"))
+      bprintf(info_buf, "rm.%d", roomGetUID(va_arg(vargs, ROOM_DATA *)));
+    else if(!strcasecmp(token, "ex") || !strcasecmp(token, "exit"))
+      bprintf(info_buf, "ex.%d", exitGetUID(va_arg(vargs, EXIT_DATA *)));
+    else if(!strcasecmp(token, "str"))
+      bprintf(info_buf, "%c%s%c", HOOK_STR_MARKER, va_arg(vargs, char *), HOOK_STR_MARKER);
+    else if(!strcasecmp(token, "int"))
+      bprintf(info_buf, "%d", va_arg(vargs, int));
+    else if(!strcasecmp(token, "dbl"))
+      bprintf(info_buf, "%lf", va_arg(vargs, double));
+    // unknown type -- abort!
+    else
+      break;
+
+    // add a space for the next token to be printed
+    if(count < len - 1)
+      bprintf(info_buf, " ");
+    count++;
+  } deleteListIterator(token_i);
+  deleteListWith(tokens, free);
+  va_end(vargs);
+  return bufferString(info_buf);
+}
+
+//
+// parses up info tokens
+LIST *parse_hook_info_tokens(const char *info) {
+  LIST *tokens = newList();
+  BUFFER  *buf = newBuffer(1);
+  while(*info) {
+    // skip leading spaces
+    while(isspace(*info))
+      info++;
+
+    char marker = ' ';
+    bufferClear(buf);
+    
+    // are we parsing a string or something else?
+    if(*info == HOOK_STR_MARKER) {
+      marker = HOOK_STR_MARKER;
+      bprintf(buf, "%c", HOOK_STR_MARKER);
+      info++;
+    }
+
+    // fill up to the end marker
+    for(;*info && *info != marker; info++)
+      bprintf(buf, "%c", *info);
+
+    // were we parsing a string?
+    if(marker == HOOK_STR_MARKER)
+      bprintf(buf, "%c", HOOK_STR_MARKER);
+
+    // skip past our marker
+    if(*info) info++;
+    
+    // append our token
+    listQueue(tokens, strdup(bufferString(buf)));
+  }
+  deleteBuffer(buf);
+  return tokens;
 }
 
-void hook_handler_0_args(LIST *hooks, va_list args) {
-  LIST_ITERATOR *hook_i = newListIterator(hooks);
-  void   (* hook)(void) = NULL;
-  ITERATE_LIST(hook, hook_i) {
-    hook();
-  } deleteListIterator(hook_i);
-}
-
-void hook_handler_1_arg(LIST *hooks, va_list args) {
-  LIST_ITERATOR *hook_i = newListIterator(hooks);
-  void *arg1 = va_arg(args, void *);
-  void (* hook)(void *) = NULL;
-  ITERATE_LIST(hook, hook_i) {
-    hook(arg1);
-  } deleteListIterator(hook_i);
-}
-
-void hook_handler_2_args(LIST *hooks, va_list args) {
-  LIST_ITERATOR *hook_i = newListIterator(hooks);
-  void *arg1 = va_arg(args, void *);
-  void *arg2 = va_arg(args, void *);
-  void (* hook)(void *, void *) = NULL;
-  ITERATE_LIST(hook, hook_i) {
-    hook(arg1, arg2);
-  } deleteListIterator(hook_i);
-}
-
-void hook_handler_3_args(LIST *hooks, va_list args) {
-  LIST_ITERATOR *hook_i = newListIterator(hooks);
-  void *arg1 = va_arg(args, void *);
-  void *arg2 = va_arg(args, void *);
-  void *arg3 = va_arg(args, void *);
-  void (* hook)(void *, void *, void *) = NULL;
-  ITERATE_LIST(hook, hook_i) {
-    hook(arg1, arg2, arg3);
-  } deleteListIterator(hook_i);
-}
-
-void hook_handler_4_args(LIST *hooks, va_list args) {
-  LIST_ITERATOR *hook_i = newListIterator(hooks);
-  void *arg1 = va_arg(args, void *);
-  void *arg2 = va_arg(args, void *);
-  void *arg3 = va_arg(args, void *);
-  void *arg4 = va_arg(args, void *);
-  void (* hook)(void *, void *, void *, void *) = NULL;
-  ITERATE_LIST(hook, hook_i) {
-    hook(arg1, arg2, arg3, arg4);
-  } deleteListIterator(hook_i);
-}
-
-void hook_handler_5_args(LIST *hooks, va_list args) {
-  LIST_ITERATOR *hook_i = newListIterator(hooks);
-  void *arg1 = va_arg(args, void *);
-  void *arg2 = va_arg(args, void *);
-  void *arg3 = va_arg(args, void *);
-  void *arg4 = va_arg(args, void *);
-  void *arg5 = va_arg(args, void *);
-  void (* hook)(void *, void *, void *, void *, void *) = NULL;
-  ITERATE_LIST(hook, hook_i) {
-    hook(arg1, arg2, arg3, arg4, arg5);
-  } deleteListIterator(hook_i);
-}
-
-void hook_handler_6_args(LIST *hooks, va_list args) {
-  LIST_ITERATOR *hook_i = newListIterator(hooks);
-  void *arg1 = va_arg(args, void *);
-  void *arg2 = va_arg(args, void *);
-  void *arg3 = va_arg(args, void *);
-  void *arg4 = va_arg(args, void *);
-  void *arg5 = va_arg(args, void *);
-  void *arg6 = va_arg(args, void *);
-  void (* hook)(void *, void *, void *, void *, void *, void *) = NULL;
-  ITERATE_LIST(hook, hook_i) {
-    hook(arg1, arg2, arg3, arg4, arg5, arg6);
-  } deleteListIterator(hook_i);
+void hookParseInfo(const char *info, ...) {
+  // parse out all of our tokens
+  LIST *tokens           = parse_hook_info_tokens(info);
+  LIST_ITERATOR *token_i = newListIterator(tokens);
+  char *token            = NULL;
+
+  // id number we'll need for parsing some values
+  int id = 0;
+
+  // go through all of our tokens
+  va_list vargs;
+  va_start(vargs, info);
+  ITERATE_LIST(token, token_i) {
+    if(startswith(token, "ch")) {
+      sscanf(token, "ch.%d", &id);
+      *va_arg(vargs, CHAR_DATA **) = propertyTableGet(mob_table, id);
+    }
+    else if(startswith(token, "obj")) {
+      sscanf(token, "obj.%d", &id);
+      *va_arg(vargs, OBJ_DATA **) = propertyTableGet(obj_table, id);
+    }
+    else if(startswith(token, "rm")) {
+      sscanf(token, "rm.%d", &id);
+      *va_arg(vargs, ROOM_DATA **) = propertyTableGet(room_table, id);
+    }
+    else if(startswith(token, "room")) {
+      sscanf(token, "room.%d", &id);
+      *va_arg(vargs, ROOM_DATA **) = propertyTableGet(room_table, id);
+    }
+    else if(startswith(token, "ex")) {
+      sscanf(token, "ex.%d", &id);
+      *va_arg(vargs, EXIT_DATA **) = propertyTableGet(exit_table, id);
+    }
+    else if(startswith(token, "exit")) {
+      sscanf(token, "exit.%d", &id);
+      *va_arg(vargs, EXIT_DATA **) = propertyTableGet(exit_table, id);
+    }
+    else if(*token == HOOK_STR_MARKER) {
+      char *str = strdup(token + 1);
+      str[strlen(str)-1] = '\0';
+      *va_arg(vargs, char **) = str;
+    }
+    else if(isdigit(*token)) {
+      // integer or double?
+      if(next_letter_in(token, '.') > -1)
+	*va_arg(vargs, double *) = atof(token);
+      else
+	*va_arg(vargs, int *) = atoi(token);
+    }
+  } deleteListIterator(token_i);
+  deleteListWith(tokens, free);
+  va_end(vargs);
 }
diff -ruN ../nakedmudv3.1/src/hooks.h src/hooks.h
--- ../nakedmudv3.1/src/hooks.h	Sun Dec  4 20:03:07 2005
+++ src/hooks.h	Sat Jul  1 20:06:58 2006
@@ -21,46 +21,19 @@
 //*****************************************************************************
 
 //
-// prepare hooks for use
-void init_hooks(void);
-
-//
-// creates a "middle-man" between hooks and the variables passed in when 
-// hookRun is called. The supplied function should take a LIST of hooks to
-// be run, and a VA_LIST of arguments. It should parse the arguments out of
-// VA_LIST and call each hook in the LIST with the arguments found in VA_LIST.
-void hook_add_handler(const char *type, 
-		      void(* handler)(LIST *hooks, va_list args));
-
-//
-// some handlers for use by outside modules not wanting to write their own hook
-// handlers. Each assumes a specific number of (void *) pointer arguments, and
-// no return value. If you want to support arguments of other sizes (like ints,
-// bools, etc) or would like your hooks to be able to return values, you will
-// have to write your own handler.
-void hook_handler_0_args(LIST *hooks, va_list args);
-void  hook_handler_1_arg(LIST *hooks, va_list args);
-void hook_handler_2_args(LIST *hooks, va_list args);
-void hook_handler_3_args(LIST *hooks, va_list args);
-void hook_handler_4_args(LIST *hooks, va_list args);
-void hook_handler_5_args(LIST *hooks, va_list args);
-void hook_handler_6_args(LIST *hooks, va_list args);
+// random character we use for denoting the beginning/end of a string
+#define HOOK_STR_MARKER '\033'
 
 //
-// This function attaches a hook to the game. It will run whenever a signal is
-// sent that a hook of "type" should run. A hook is a function. The number and
-// types of arguments that the function should take, as well as the type of 
-// return value the hook should supply depends on the type of hook it's added as
-void hookAdd(const char *type, void *hook);
-
-//
-// executes all of the hooks of the given type, with the given arguments. This
-// is sort of a sloppy way to provide hooks with arguments, but it's the best
-// I've come up with so far.
-void hookRun(const char *type, ...);
+// prepare hooks for use
+void init_hooks(void);
 
-//
-// remove the given hook
-void hookRemove(const char *type, void *hook);
+void hookRun(const char *type, const char *info);
+void hookAdd(const char *type, void (* func)(const char *));
+void hookAddMonitor(void (* func)(const char *, const char *));
+void hookRemove(const char *type, void (* func)(const char *));
+void hookParseInfo(const char *info, ...);
+const char *hookBuildInfo(const char *format, ...);
+LIST *parse_hook_info_tokens(const char *info);
 
 #endif // HOOKS_H
diff -ruN ../nakedmudv3.1/src/inform.c src/inform.c
--- ../nakedmudv3.1/src/inform.c	Sun Dec  4 20:03:07 2005
+++ src/inform.c	Sat Jul  1 20:06:58 2006
@@ -130,58 +130,56 @@
 //*****************************************************************************
 void look_at_obj(CHAR_DATA *ch, OBJ_DATA *obj) {
   // make our working copy of the description
-  BUFFER *new_desc = bufferCopy(objGetDescBuffer(obj));
+  bufferClear(charGetLookBuffer(ch));
+  bufferCat(charGetLookBuffer(ch), objGetDesc(obj));
 
   // do all of the preprocessing on the new descriptions
-  hookRun("preprocess_obj_desc", new_desc, obj, ch);
+  hookRun("preprocess_obj_desc", hookBuildInfo("obj ch", obj, ch));
 
   // append anything that might also go onto it
-  hookRun("append_obj_desc", new_desc, obj, ch);
+  hookRun("append_obj_desc", hookBuildInfo("obj ch", obj, ch));
 
   // colorize all of the edescs
-  edescTagDesc(new_desc, objGetEdescs(obj), "{c", "{g");
+  edescTagDesc(charGetLookBuffer(ch), objGetEdescs(obj), "{c", "{g");
 
   // format the desc, and send it
-  bufferFormat(new_desc, SCREEN_WIDTH, PARA_INDENT);
+  bufferFormat(charGetLookBuffer(ch), SCREEN_WIDTH, PARA_INDENT);
 
-  if(bufferLength(new_desc) == 0)
+  if(bufferLength(charGetLookBuffer(ch)) == 0)
     send_to_char(ch, "{g%s\r\n", NOTHING_SPECIAL);
   else
-    send_to_char(ch, "{g%s", bufferString(new_desc));
+    send_to_char(ch, "{g%s", bufferString(charGetLookBuffer(ch)));
 
-  // free up our mess
-  deleteBuffer(new_desc);
-
-  hookRun("look_at_obj", obj, ch);
+  hookRun("look_at_obj", hookBuildInfo("obj ch", obj, ch));
   send_to_char(ch, "{n");
 }
 
 
 void look_at_exit(CHAR_DATA *ch, EXIT_DATA *exit) {
   // make the working copy of the description, and fill it up with info
-  BUFFER *desc = bufferCopy(exitGetDescBuffer(exit));
+  bufferClear(charGetLookBuffer(ch));
+  bufferCat(charGetLookBuffer(ch), exitGetDesc(exit));
 
   // do all of our preprocessing of the description before we show it
-  hookRun("preprocess_exit_desc", desc, exit, ch);
+  hookRun("preprocess_exit_desc", hookBuildInfo("ex ch", exit, ch));
 
   // append anything that might also go onto it
-  hookRun("append_exit_desc", desc, exit, ch);
+  hookRun("append_exit_desc", hookBuildInfo("ex ch", exit, ch));
 
   // colorize all of the edescs
-  edescTagDesc(desc, roomGetEdescs(exitGetRoom(exit)), "{c", "{g");
+  edescTagDesc(charGetLookBuffer(ch), roomGetEdescs(exitGetRoom(exit)), 
+	       "{c", "{g");
 
   // format our description
-  bufferFormat(desc, SCREEN_WIDTH, PARA_INDENT);
+  bufferFormat(charGetLookBuffer(ch), SCREEN_WIDTH, PARA_INDENT);
 
   // if the buffer has nothing in it, send a "nothing special" message
-  if(bufferLength(desc) == 0)
+  if(bufferLength(charGetLookBuffer(ch)) == 0)
     send_to_char(ch, "{g%s\r\n", NOTHING_SPECIAL);
   else
-    send_to_char(ch, "{g%s", bufferString(desc));
-
-  deleteBuffer(desc);
+    send_to_char(ch, "{g%s", bufferString(charGetLookBuffer(ch)));
 
-  hookRun("look_at_exit", exit, ch);
+  hookRun("look_at_exit", hookBuildInfo("ex ch", exit, ch));
   send_to_char(ch, "{n");
 }
 
@@ -239,44 +237,25 @@
 }
 
 
-void show_body(CHAR_DATA *ch, BODY_DATA *body) {
-  int i, num_bodyparts;
-  const char **bodyparts = bodyGetParts(body, TRUE, &num_bodyparts);
-  OBJ_DATA    *equipment = NULL;
-  char posbuf[SMALL_BUFFER];
-  for(i = 0; i < num_bodyparts; i++) {
-    equipment = bodyGetEquipment(body, bodyparts[i]);
-    if(!equipment || !can_see_obj(ch, equipment))
-      continue;
-    sprintf(posbuf, "{c<{C%s{c>{n", bodyparts[i]);
-    send_to_char(ch, "%-30s %s\r\n", 
-		 posbuf, objGetName(equipment));
-  }
-  if(bodyparts) 
-    free(bodyparts);
-}
-
-
 void look_at_char(CHAR_DATA *ch, CHAR_DATA *vict) {
-  BUFFER *new_desc = bufferCopy(charGetDescBuffer(vict));
+  bufferClear(charGetLookBuffer(ch));
+  bufferCat(charGetLookBuffer(ch), charGetDesc(vict));
 
   // preprocess our desc before it it sent to the person
-  hookRun("preprocess_char_desc", new_desc, vict, ch);
+  hookRun("preprocess_char_desc", hookBuildInfo("ch ch", vict, ch));
 
   // append anything that might also go onto it
-  hookRun("append_char_desc", new_desc, vict, ch);
-    
+  hookRun("append_char_desc", hookBuildInfo("ch ch", vict, ch));
+
   // format and send it
-  bufferFormat(new_desc, SCREEN_WIDTH, PARA_INDENT);
+  bufferFormat(charGetLookBuffer(ch), SCREEN_WIDTH, PARA_INDENT);
 
-  if(bufferLength(new_desc) == 0)
+  if(bufferLength(charGetLookBuffer(ch)) == 0)
     send_to_char(ch, "{g%s\r\n", NOTHING_SPECIAL);
   else
-    send_to_char(ch, "{g%s{n", bufferString(new_desc));
+    send_to_char(ch, "{g%s{n", bufferString(charGetLookBuffer(ch)));
   
-  // clean up our mess
-  deleteBuffer(new_desc);
-  hookRun("look_at_char", vict, ch);
+  hookRun("look_at_char", hookBuildInfo("ch ch", vict, ch));
 }
 
 
@@ -288,27 +267,26 @@
   send_to_char(ch, "{c%s\r\n", roomGetName(room));
 
   // make the working copy of the description, and fill it up with info
-  BUFFER *desc = bufferCopy(roomGetDescBuffer(room));
-
+  bufferClear(charGetLookBuffer(ch));
+  bufferCat(charGetLookBuffer(ch), roomGetDesc(room));
   // do all of our preprocessing of the description before we show it
-  hookRun("preprocess_room_desc", desc, room, ch);
+  hookRun("preprocess_room_desc", hookBuildInfo("rm ch", room, ch));
 
   // append anything that might also go onto it
-  hookRun("append_room_desc", desc, room, ch);
+  hookRun("append_room_desc", hookBuildInfo("rm ch", room, ch));
 
   // colorize all of the edescs
-  edescTagDesc(desc, roomGetEdescs(room), "{c", "{g");
+  edescTagDesc(charGetLookBuffer(ch), roomGetEdescs(room), "{c", "{g");
 
   // format our description
-  bufferFormat(desc, SCREEN_WIDTH, PARA_INDENT);
+  bufferFormat(charGetLookBuffer(ch), SCREEN_WIDTH, PARA_INDENT);
 
-  if(bufferLength(desc) == 0)
+  if(bufferLength(charGetLookBuffer(ch)) == 0)
     send_to_char(ch, "{g%s\r\n", NOTHING_SPECIAL);
   else
-    send_to_char(ch, "{g%s", bufferString(desc));
+    send_to_char(ch, "{g%s", bufferString(charGetLookBuffer(ch)));
 
-  deleteBuffer(desc);
-  hookRun("look_at_room", room, ch);
+  hookRun("look_at_room", hookBuildInfo("rm ch", room, ch));
   send_to_char(ch, "{n");
 }
 
@@ -522,77 +500,14 @@
 
 
 //
-// list all of the equipment a character is wearing to him or herself
-COMMAND(cmd_equipment) {
-  send_to_char(ch, "You are wearing:\r\n");
-  show_body(ch, charGetBody(ch));
-}
-
-
-//
-// list a character's inventory to him or herself
-COMMAND(cmd_inventory) {
-  if(listSize(charGetInventory(ch)) == 0)
-    send_to_char(ch, "You aren't carrying anything.\r\n");
-  else {
-    send_to_char(ch, "{gYou are carrying:\r\n");
-    LIST *vis_objs = find_all_objs(ch, charGetInventory(ch), "", NULL, TRUE);
-    show_list(ch, vis_objs, objGetName, objGetMultiName);
-    deleteList(vis_objs);
-  }
-}
-
-
-//
 // show a list of all commands available to the character
 COMMAND(cmd_commands) {
-  show_commands(ch, bitvectorGetBits(charGetUserGroups(ch)));
-}
-
-
-//
-// builds a buffer that lists all of the people online. 
-// Buffer must be deleted after it is used
-BUFFER *build_who(void) {
-  CHAR_DATA *plr;
-  SOCKET_DATA *dsock;
-  BUFFER *buf = newBuffer(MAX_BUFFER);
-  LIST_ITERATOR *sock_i = newListIterator(socket_list);
-  int socket_count = 0, playing_count = 0;
-
-  bprintf(buf, 
-	  "{cPlayers Online:\r\n"
-	  "{gStatus   Race )\r\n"
-	  );
-
-  // build our list of people online
-  ITERATE_LIST(dsock, sock_i) {
-    socket_count++;
-    if ((plr = socketGetChar(dsock)) == NULL) continue;
-    playing_count++;
-    bprintf(buf, "{y%-8s %-3s  {g)  {c%-12s {b%26s\r\n",
-	    (bitIsSet(charGetUserGroups(plr), "admin") ? "admin" :
-	     (bitIsSet(charGetUserGroups(plr), "scripter") ? "scripter" :
-	      (bitIsSet(charGetUserGroups(plr), "builder") ? "builder"  :
-	       (bitIsSet(charGetUserGroups(plr), "player") ? "player" : 
-		"noone!")))),
-	    raceGetAbbrev(charGetRace(plr)),
-	    charGetName(plr), socketGetHostname(dsock));
-  } deleteListIterator(sock_i);
-
-  // send out info about the number of sockets and players logged on
-  bprintf(buf, "\r\n{g%d socket%s connected. %d playing.\r\n",
-	  socket_count, (socket_count == 1 ? "" : "s"), playing_count);
-  return buf;
-}
-
-
-//
-// show the player all of the people who are currently playing
-COMMAND(cmd_who) {
-  BUFFER *buf = build_who();
-  page_string(charGetSocket(ch), bufferString(buf));
-  deleteBuffer(buf);
+  if(!*arg)
+    show_commands(ch, bitvectorGetBits(charGetUserGroups(ch)));
+  else if(!bitIsAllSet(charGetUserGroups(ch), arg))
+    send_to_char(ch, "You are not a member of all user groups: %s.\r\n", arg);
+  else
+    show_commands(ch, arg);
 }
 
 
@@ -849,8 +764,13 @@
   deleteListWith(exnames, free);
 }
 
-void exit_append_hook(BUFFER *buf, EXIT_DATA *exit, CHAR_DATA *ch) {
+void exit_append_hook(const char *info) {
   // before anything, figure out some basic information like our dir and dest
+  EXIT_DATA     *exit = NULL;
+  CHAR_DATA       *ch = NULL;
+  hookParseInfo(info, &exit, &ch);
+
+  BUFFER         *buf = charGetLookBuffer(ch);
   ROOM_DATA     *room = exitGetRoom(exit);
   ROOM_DATA     *dest = worldGetRoom(gameworld, exitGetTo(exit));
   LIST       *exnames = roomGetExitNames(room);
@@ -888,7 +808,10 @@
   if(dir) free(dir);
 }
 
-void exit_look_hook(EXIT_DATA *exit, CHAR_DATA *ch) {
+void exit_look_hook(const char *info) {
+  EXIT_DATA *exit = NULL;
+  CHAR_DATA   *ch = NULL;
+  hookParseInfo(info, &exit, &ch);
   // the door is not closed, list off the people we can see as well
   if(!exitIsClosed(exit)) {
     ROOM_DATA *room = worldGetRoom(gameworld, exitGetTo(exit));
@@ -897,14 +820,10 @@
   }
 }
 
-void body_look_hook(CHAR_DATA *vict, CHAR_DATA *ch) {
-  send_to_char(ch, "\r\n{g%s %s wearing:\r\n", 
-	       (ch == vict ? "You" : HESHE(vict)),
-	       (ch == vict ? "are" : "is"));
-  show_body(ch, charGetBody(vict));
-}
-
-void room_look_hook(ROOM_DATA *room, CHAR_DATA *ch) {
+void room_look_hook(const char *info) {
+  ROOM_DATA *room = NULL;
+  CHAR_DATA   *ch = NULL;
+  hookParseInfo(info, &room, &ch);
   list_room_exits(ch, room);
   list_room_contents(ch, room);
 }
@@ -915,25 +834,10 @@
 // initialization of inform.h
 //*****************************************************************************
 void init_inform(void) {
-  // add all of our hook types
-  hook_add_handler("preprocess_room_desc", hook_handler_3_args);
-  hook_add_handler("preprocess_obj_desc",  hook_handler_3_args);
-  hook_add_handler("preprocess_char_desc", hook_handler_3_args);
-  hook_add_handler("preprocess_exit_desc", hook_handler_3_args);
-  hook_add_handler("append_room_desc",     hook_handler_3_args);
-  hook_add_handler("append_obj_desc",      hook_handler_3_args);
-  hook_add_handler("append_char_desc",     hook_handler_3_args);
-  hook_add_handler("append_exit_desc",     hook_handler_3_args);
-  hook_add_handler("look_at_room",         hook_handler_2_args);
-  hook_add_handler("look_at_obj",          hook_handler_2_args);
-  hook_add_handler("look_at_char",         hook_handler_2_args);
-  hook_add_handler("look_at_exit",         hook_handler_2_args);
-
   // attach hooks
   hookAdd("append_exit_desc", exit_append_hook);
   // enable if you want exits to append to the end of room descs
   //  hookAdd("append_room_desc", exit_append_room_hook);
-  hookAdd("look_at_exit",     exit_look_hook);
-  hookAdd("look_at_char",     body_look_hook);
-  hookAdd("look_at_room",     room_look_hook);
+  hookAdd("look_at_exit", exit_look_hook);
+  hookAdd("look_at_room", room_look_hook);
 }
diff -ruN ../nakedmudv3.1/src/inform.h src/inform.h
--- ../nakedmudv3.1/src/inform.h	Sun Dec  4 20:03:07 2005
+++ src/inform.h	Sat Jul  1 20:06:58 2006
@@ -150,11 +150,4 @@
 //
 void show_body(CHAR_DATA *ch, BODY_DATA *body);
 
-
-//
-// builds a buffer that lists all of the people online. 
-// Buffer must be deleted after it is used
-BUFFER *build_who(void);
-
-
 #endif // __INFORM_H
diff -ruN ../nakedmudv3.1/src/interpret.c src/interpret.c
--- ../nakedmudv3.1/src/interpret.c	Sun Dec  4 20:03:07 2005
+++ src/interpret.c	Sat Jul  1 20:06:58 2006
@@ -10,7 +10,6 @@
 #include "character.h"
 #include "socket.h"
 #include "room.h"
-#include "movement.h"    // for try_move_special
 #include "commands.h"
 #include "action.h"
 
@@ -49,210 +48,18 @@
   // functions to the MUD, they should be added in the init_xxx() function
   // associated with your module.
   //***************************************************************************
-  add_cmd("north", "n", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("east",  "e", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("south", "s", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("west",  "w", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("up",    "u", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("down",  "d", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("northeast", "na", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("southeast", "sa",  cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("southwest", "sb", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("northwest", "nb", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("ne",        "ne", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("se",        "se", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("sw",        "sw", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("nw",        "nw", cmd_move, POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-
-  // A
-  add_cmd("approach",   NULL, cmd_greet,    POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("ask",        NULL, cmd_ask,      POS_SITTING,  POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("at",         NULL, cmd_at,       POS_UNCONCIOUS, POS_FLYING,
-	  "builder", TRUE, FALSE);
-
-  // B
   add_cmd("back",       NULL, cmd_back,     POS_UNCONCIOUS, POS_FLYING,
 	  "player", TRUE, FALSE);
-
-  // C
-  add_cmd("chat",       NULL, cmd_chat,     POS_UNCONCIOUS, POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("clear",      NULL, cmd_clear,    POS_UNCONCIOUS, POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("close",      NULL, cmd_close,    POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
   add_cmd("commands",   NULL, cmd_commands, POS_UNCONCIOUS, POS_FLYING,
 	  "player", TRUE, FALSE);
   add_cmd("compress",   NULL, cmd_compress, POS_UNCONCIOUS, POS_FLYING,
 	  "player", FALSE, FALSE);
-  add_cmd("copyover",   NULL, cmd_copyover, POS_UNCONCIOUS, POS_FLYING,
-	  "admin",  FALSE, TRUE);
-
-  // D
-  add_cmd("delay",      NULL, cmd_delay,    POS_SLEEPING, POS_FLYING,
-	  "player", TRUE,  FALSE);
-  add_cmd("drop",       NULL, cmd_drop,     POS_SITTING,  POS_FLYING,
-	  "player", TRUE, TRUE );
-
-  // E
-  add_cmd("emote",      NULL, cmd_emote,    POS_SITTING,  POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd(":",          NULL, cmd_emote,    POS_SITTING,  POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("equipment",  NULL, cmd_equipment,POS_SITTING,  POS_FLYING,
-	  "player", TRUE, FALSE);
-
-  // F
-  add_cmd("force",      NULL, cmd_force,    POS_STANDING, POS_FLYING,
-	  "admin",   FALSE, FALSE);
-
-  // G
-  add_cmd("gemote",     NULL, cmd_gemote,   POS_UNCONCIOUS, POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("give",       NULL, cmd_give,     POS_SITTING,  POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("gossip",     NULL, cmd_chat,     POS_UNCONCIOUS, POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("\"",         NULL, cmd_chat,     POS_UNCONCIOUS, POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("greet",      NULL, cmd_greet,    POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("get",        NULL, cmd_get,      POS_SITTING,  POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("goto",       NULL, cmd_goto,     POS_STANDING, POS_FLYING,
-	  "builder", FALSE, TRUE );
   add_cmd("groupcmds",  NULL, cmd_groupcmds,POS_UNCONCIOUS, POS_FLYING,
 	  "player", FALSE, FALSE);
-
-  // I
-  add_cmd("inventory",  NULL, cmd_inventory,POS_SITTING,  POS_FLYING,
-	  "player", TRUE, FALSE);
-
-  // L
   add_cmd("look",       "l",  cmd_look,     POS_SITTING,  POS_FLYING,
 	  "player", TRUE, FALSE);
-  add_cmd("lock",       NULL,  cmd_lock,    POS_STANDING,  POS_FLYING,
-	  "player", TRUE, TRUE);
-  add_cmd("land",       NULL, cmd_stand,    POS_FLYING,   POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("load",       NULL, cmd_load,     POS_SITTING,  POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("linkdead",   NULL, cmd_linkdead, POS_UNCONCIOUS, POS_FLYING,
-	  "admin", FALSE, FALSE);
-  add_cmd("lockdown",   NULL, cmd_lockdown, POS_UNCONCIOUS, POS_FLYING,
-	  "admin", FALSE, FALSE);
-
-  // M
-  add_cmd("mlist",      NULL, cmd_mlist,    POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("mdelete",    NULL, cmd_mdelete,  POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("mrename",    NULL, cmd_mrename,  POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
   add_cmd("more",       NULL, cmd_more,     POS_UNCONCIOUS, POS_FLYING,
 	  "player", TRUE, FALSE);
-  add_cmd("motd",       NULL, cmd_motd,     POS_UNCONCIOUS, POS_FLYING,
-	  "player", TRUE, FALSE);
-
-  // O
-  add_cmd("olist",      NULL, cmd_olist,    POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("odelete",    NULL, cmd_odelete,  POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("orename",    NULL, cmd_orename,  POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("open",       NULL, cmd_open,     POS_STANDING, POS_FLYING,
-	  "player", TRUE, TRUE );
-
-  // P
-  add_cmd("put",        "p", cmd_put,       POS_SITTING,  POS_FLYING,
-	  "player", TRUE,  TRUE );
-  add_cmd("page",       NULL, cmd_page,     POS_SITTING,  POS_FLYING,
-	  "builder", TRUE, FALSE);
-  add_cmd("purge",      NULL, cmd_purge,    POS_SITTING,  POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("pulserate",  NULL, cmd_pulserate,POS_UNCONCIOUS, POS_FLYING,
-	  "admin", FALSE, FALSE);
-  
-  // Q
-  add_cmd("quit",       NULL, cmd_quit,     POS_SLEEPING, POS_FLYING,
-	  "player", FALSE, TRUE );
-
-  // R
-  add_cmd("rreload",    NULL, cmd_rreload,  POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("remove",     NULL, cmd_remove,   POS_SITTING, POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("repeat",     NULL, cmd_repeat,   POS_UNCONCIOUS, POS_FLYING,
-	  "admin", FALSE, FALSE);
-  add_cmd("rlist",      NULL, cmd_rlist,    POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("rdelete",    NULL, cmd_rdelete,  POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-  add_cmd("rrename",    NULL, cmd_rrename,  POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
-
-  // S
-  add_cmd("say",        NULL, cmd_say,      POS_SITTING,  POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("'",          NULL, cmd_say,      POS_SITTING,  POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("save",       NULL, cmd_save,     POS_SLEEPING, POS_FLYING,
-	  "player", FALSE, FALSE);
-  add_cmd("shutdown",   NULL, cmd_shutdown, POS_UNCONCIOUS, POS_FLYING,
-	  "admin", FALSE, TRUE );
-  add_cmd("sit",        NULL, cmd_sit,      POS_SITTING,  POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("sleep",      NULL, cmd_sleep,    POS_SITTING,  POS_STANDING,
-	  "player", TRUE, FALSE);
-  add_cmd("stand",      NULL, cmd_stand,    POS_SITTING,  POS_STANDING,
-	  "player", TRUE, TRUE );
-  add_cmd("stop",       NULL, cmd_stop,     POS_SITTING, POS_FLYING,
-	  "player", TRUE, FALSE);
-
-  // T
-  add_cmd("take",       NULL, cmd_get,      POS_SITTING,  POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("tell",       NULL, cmd_tell,     POS_SLEEPING, POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("transfer",   NULL, cmd_transfer, POS_STANDING, POS_FLYING,
-	  "builder", FALSE, TRUE);
-
-  // U
-  add_cmd("unlock",       NULL,  cmd_unlock,    POS_STANDING,  POS_FLYING,
-	  "player", TRUE, TRUE);
-
-  // W
-  add_cmd("wake",       NULL, cmd_wake,     POS_SLEEPING,  POS_SLEEPING,
-	  "player", TRUE, TRUE );
-  add_cmd("wear",       NULL, cmd_wear,     POS_SITTING,  POS_FLYING,
-	  "player", TRUE, TRUE );
-  add_cmd("who",        NULL, cmd_who,      POS_UNCONCIOUS, POS_FLYING,
-	  "player", TRUE, FALSE);
-  add_cmd("worn",       NULL, cmd_equipment,POS_SITTING,  POS_FLYING,
-	  "player", TRUE, FALSE);
-
-  // Z
-  add_cmd("zlist",      NULL, cmd_zlist,    POS_SITTING,  POS_FLYING,
-	  "builder", FALSE, TRUE);
-  add_cmd("zreset",     NULL, cmd_zreset,   POS_UNCONCIOUS, POS_FLYING,
-	  "builder", FALSE, FALSE);
 }
 
 
diff -ruN ../nakedmudv3.1/src/items/container.c src/items/container.c
--- ../nakedmudv3.1/src/items/container.c	Sun Dec  4 20:03:07 2005
+++ src/items/container.c	Sat Jul  1 20:06:58 2006
@@ -10,6 +10,7 @@
 #include "../mud.h"
 #include "../storage.h"
 #include "../object.h"
+#include "../character.h"
 #include "../world.h"
 #include "../socket.h"
 #include "../utils.h"
@@ -499,14 +500,23 @@
 //*****************************************************************************
 // hooks
 //*****************************************************************************
-void container_append_hook(BUFFER *desc, OBJ_DATA *obj, CHAR_DATA *ch) {
+void container_append_hook(const char *info) {
+  OBJ_DATA *obj = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &obj, &ch);
+
   if(objIsType(obj, "container")) {
-    bprintf(desc, " It is %s%s.", (containerIsClosed(obj) ? "closed":"open"),
+    bprintf(charGetLookBuffer(ch), " It is %s%s.", 
+	    (containerIsClosed(obj) ? "closed":"open"),
 	    (containerIsLocked(obj) ? " and locked" : ""));
   }
 }
 
-void container_look_hook(OBJ_DATA *obj, CHAR_DATA *ch) {
+void container_look_hook(const char *info) {
+  OBJ_DATA *obj = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &obj, &ch);
+
   if(objIsType(obj, "container") && !containerIsClosed(obj)) {
     LIST *vis_contents = find_all_objs(ch, objGetContents(obj), "", 
 				       NULL, TRUE);
diff -ruN ../nakedmudv3.1/src/items/furniture.c src/items/furniture.c
--- ../nakedmudv3.1/src/items/furniture.c	Sun Dec  4 20:03:07 2005
+++ src/items/furniture.c	Sat Jul  1 20:06:58 2006
@@ -275,15 +275,20 @@
 //*****************************************************************************
 // hooks
 //*****************************************************************************
-void furniture_append_hook(BUFFER *buf, OBJ_DATA *obj, CHAR_DATA *ch) {
+void furniture_append_hook(const char *info) {
+  OBJ_DATA *obj = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &obj, &ch);
+
   if(objIsType(obj, "furniture")) {
     int num_sitters = listSize(objGetUsers(obj));
 
     // print out how much room there is left on the furniture
     int seats_left = (furnitureGetCapacity(obj) - num_sitters);
     if(seats_left > 0)
-      bprintf(buf, " It looks like it could fit %d more %s.\r\n",
-		   seats_left, (seats_left == 1 ? "person" : "people"));
+      bprintf(charGetLookBuffer(ch), 
+	      " It looks like it could fit %d more %s.\r\n",
+	      seats_left, (seats_left == 1 ? "person" : "people"));
 
     // print character names
     if(num_sitters > 0) {
@@ -291,7 +296,7 @@
       listRemove(can_see, ch);
 
       char *chars = print_list(can_see, charGetName, charGetMultiName);
-      if(*chars) bprintf(buf, "%s %s %s %s%s.\r\n",
+      if(*chars) bprintf(charGetLookBuffer(ch), "%s %s %s %s%s.\r\n",
 			 chars, (listSize(can_see) == 1 ? "is" : "are"),
 			 (furnitureGetType(obj) == FURNITURE_AT ? "at":"on"),
 			 see_obj_as(ch, obj),
diff -ruN ../nakedmudv3.1/src/items/portal.c src/items/portal.c
--- ../nakedmudv3.1/src/items/portal.c	Sun Dec  4 20:03:07 2005
+++ src/items/portal.c	Sat Jul  1 20:06:58 2006
@@ -15,7 +15,6 @@
 #include "../socket.h"
 #include "../room.h"
 #include "../world.h"
-#include "../movement.h"
 #include "../inform.h"
 #include "../handler.h"
 #include "../hooks.h"
@@ -138,41 +137,34 @@
 //   examples:
 //     enter portal         enter the thing called "portal" in your room
 COMMAND(cmd_enter) {
-  void    *found = NULL;
-  int found_type = PARSE_NONE;
+  void *obj = NULL;
 
-  if(!parse_args(ch, TRUE, cmd, arg, "{ obj.room exit }", &found, &found_type))
+  if(!parse_args(ch, TRUE, cmd, arg, "obj.room", &obj))
     return;
 
-  // we're trying to enter an exit
-  if(found_type == PARSE_EXIT)
-    try_move_mssg(ch, roomGetExitDir(charGetRoom(ch), found));
-
   // we're trying to enter a portal
+  if(!objIsType(obj, "portal"))
+    send_to_char(ch, "You cannot seem to find an enterance.\r\n");
   else {
-    if(!objIsType(found, "portal"))
-      send_to_char(ch, "You cannot seem to find an enterance.\r\n");
+    ROOM_DATA *dest = worldGetRoom(gameworld, portalGetDest(obj));
+    if(dest == NULL)
+      send_to_char(ch, "There is nothing on the other side...\r\n");
     else {
-      ROOM_DATA *dest = worldGetRoom(gameworld, portalGetDest(found));
-      if(dest == NULL)
-	send_to_char(ch, "There is nothing on the other side...\r\n");
-      else {
-	if(*portalGetLeaveMssg(found))
-	  message(ch, NULL, found,NULL,TRUE,TO_ROOM, portalGetLeaveMssg(found));
-	else
-	  message(ch, NULL, found, NULL, TRUE, TO_ROOM, "$n steps into $o.");
-
-	// transfer our character and look
-	char_from_room(ch);
-	char_to_room(ch, dest);
-	look_at_room(ch, dest);
-
-	if(*portalGetEnterMssg(found))
-	  message(ch, NULL, found,NULL,TRUE,TO_ROOM, portalGetEnterMssg(found));
-	else
-	  message(ch, NULL, found, NULL, TRUE, TO_ROOM,
-		  "$n arrives after travelling through $o.");
-      }
+      if(*portalGetLeaveMssg(obj))
+	message(ch, NULL, obj,NULL,TRUE,TO_ROOM, portalGetLeaveMssg(obj));
+      else
+	message(ch, NULL, obj, NULL, TRUE, TO_ROOM, "$n steps into $o.");
+      
+      // transfer our character and look
+      char_from_room(ch);
+      char_to_room(ch, dest);
+      look_at_room(ch, dest);
+      
+      if(*portalGetEnterMssg(obj))
+	message(ch, NULL, obj,NULL,TRUE,TO_ROOM, portalGetEnterMssg(obj));
+      else
+	message(ch, NULL, obj, NULL, TRUE, TO_ROOM,
+		"$n arrives after travelling through $o.");
     }
   }
 }
@@ -390,7 +382,11 @@
 //*****************************************************************************
 // add our hookds
 //*****************************************************************************
-void portal_look_hook(OBJ_DATA *obj, CHAR_DATA *ch) {
+void portal_look_hook(const char *info) {
+  OBJ_DATA *obj = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &obj, &ch);
+
   if(objIsType(obj, "portal")) {
     ROOM_DATA *dest = worldGetRoom(gameworld, portalGetDest(obj));
     if(dest != NULL) {
diff -ruN ../nakedmudv3.1/src/items/worn.c src/items/worn.c
--- ../nakedmudv3.1/src/items/worn.c	Sun Dec  4 20:03:07 2005
+++ src/items/worn.c	Sat Jul  1 20:06:58 2006
@@ -76,9 +76,13 @@
 
 //
 // append information about where the item can be worn
-void append_worn_hook(BUFFER *desc, OBJ_DATA *obj, CHAR_DATA *ch) {
+void append_worn_hook(const char *info) {
+  OBJ_DATA *obj = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &obj, &ch);
+
   if(objIsType(obj, "worn")) {
-    bprintf(desc, "When worn, this item covers bodyparts: %s.", 
+    bprintf(charGetLookBuffer(ch),"When worn, this item covers bodyparts: %s.",
 	    wornGetPositions(obj));
   }
 }
diff -ruN ../nakedmudv3.1/src/movement.c src/movement.c
--- ../nakedmudv3.1/src/movement.c	Sun Dec  4 20:03:08 2005
+++ src/movement.c	Wed Dec 31 17:00:00 1969
@@ -1,224 +0,0 @@
-//*****************************************************************************
-//
-// movement.c
-//
-// all of the functions assocciated with moving (chars and objects)
-//
-//*****************************************************************************
-
-#include "mud.h"
-#include "utils.h"
-#include "character.h"
-#include "world.h"
-#include "zone.h"
-#include "room.h"
-#include "exit.h"
-#include "handler.h"
-#include "inform.h"
-#include "object.h"
-#include "movement.h"
-#include "hooks.h"
-
-
-
-//*****************************************************************************
-// mandatory modules
-//*****************************************************************************
-#include "items/items.h"
-#include "items/furniture.h"
-
-
-
-//*****************************************************************************
-// implementation of movement.h
-//*****************************************************************************
-EXIT_DATA *try_move_mssg(CHAR_DATA *ch, const char *dir) {
-  ROOM_DATA *old_room = charGetRoom(ch);
-  EXIT_DATA     *exit = try_move(ch, dir);
-  
-  // did we successfully move?
-  if(exit != NULL) {
-    ROOM_DATA *new_room = charGetRoom(ch);
-    int          dirnum = dirGetNum(dir);
-    // are we using an abbreviated direction name?
-    if(dirnum == DIR_NONE && !roomGetExit(old_room, dir))
-      dirnum = dirGetAbbrevNum(dir);
-
-    // now, we have to temporarily go back to the old room so we can do
-    // leave messages. Then we come back to the new room and do enter messages
-    char_from_room(ch);
-    char_to_room(ch, old_room);
-    if(*exitGetSpecLeave(exit))
-      message(ch, NULL, NULL, NULL, TRUE, TO_ROOM, exitGetSpecLeave(exit));
-    else if(dirnum == DIR_NONE)
-      send_around_char(ch, TRUE, "%s leaves.\r\n", charGetName(ch));
-    else
-      send_around_char(ch, TRUE, "%s leaves %s.\r\n", charGetName(ch), 
-		       dirGetName(dirnum));
-    char_from_room(ch);
-    char_to_room(ch, new_room);
-    
-    // do we have a special enter message? If so, use them
-    if(*exitGetSpecEnter(exit))
-      message(ch, NULL, NULL, NULL, FALSE, TO_ROOM, exitGetSpecEnter(exit));
-    else if(dirnum == DIR_NONE)
-      send_around_char(ch, TRUE, "%s has arrived.\r\n", charGetName(ch));
-    else
-      send_around_char(ch, TRUE, "%s arrives from the %s.\r\n",
-		       charGetName(ch), dirGetName(dirGetOpposite(dirnum)));
-  }
-  return exit;
-}
-
-EXIT_DATA *try_move(CHAR_DATA *ch, const char *dir) {
-  EXIT_DATA *exit = roomGetExit(charGetRoom(ch), dir);
-  ROOM_DATA   *to = NULL;
-
-  // are we using an abbreviated direction name?
-  if(exit == NULL && dirGetAbbrevNum(dir) != DIR_NONE) {
-    dir  = dirGetName(dirGetAbbrevNum(dir));
-    exit = roomGetExit(charGetRoom(ch), dir);
-  }
-
-  // did we find an exit?
-  if(exit == NULL || !can_see_exit(ch, exit))
-    send_to_char(ch, "{gAlas, there is no exit in that direction.\r\n");
-  else if(exitIsClosed(exit))
-    send_to_char(ch, "You will have to open %s first.\r\n",
-		 (*exitGetName(exit) ? exitGetName(exit) : "it"));
-  else if((to = worldGetRoom(gameworld, exitGetTo(exit))) == NULL)
-    send_to_char(ch, "It doesn't look like %s leads anywhere!", 
-		 (*exitGetName(exit) ? exitGetName(exit) : "it"));
-  else {
-    ROOM_DATA  *old_room = charGetRoom(ch);
-
-    // try all of our exit hooks
-    hookRun("exit", ch, old_room, exit);
-
-    char_from_room(ch);
-    char_to_room(ch, to);
-    look_at_room(ch, charGetRoom(ch));
-
-    // now try all of our entrance hooks
-    hookRun("enter", ch, to);
-
-    return exit;
-  }
-
-  // our exit failed
-  return NULL;
-}
-
-//
-// cmd_move is the basic entry into all of the movement utilities. See
-// try_move() in movement.h
-COMMAND(cmd_move) {
-  try_move_mssg(ch, cmd);
-}
-
-
-
-//*****************************************************************************
-// Functions and commands for changing position (sleeping, standing, etc)
-//*****************************************************************************
-bool try_change_pos(CHAR_DATA *ch, int pos) {
-  if(charGetPos(ch) == pos) {
-    send_to_char(ch, "You are already %s.\r\n", posGetName(pos));
-    return FALSE;
-  }
-  else {
-    send_to_char(ch, "You %s.\r\n", posGetActionSelf(pos));
-    send_around_char(ch, TRUE, "%s %s.\r\n", 
-		     charGetName(ch), posGetActionOther(pos));
-    charSetPos(ch, pos);
-    return TRUE;
-  }
-}
-
-bool try_use_furniture(CHAR_DATA *ch, char *arg, int pos) {
-  // strip out "at" and "on". People might be 
-  // trying "sit at table" or "sleep on bed"
-  strip_word(arg, "at");
-  strip_word(arg, "on");
-
-  OBJ_DATA *furniture = generic_find(ch, arg,
-				     FIND_TYPE_OBJ, 
-				     FIND_SCOPE_ROOM | FIND_SCOPE_VISIBLE,
-				     FALSE, NULL);
-  
-  if(furniture == NULL)
-    send_to_char(ch, "Where did you want to %s?\r\n", posGetActionSelf(pos));
-  else if(!objIsType(furniture, "furniture"))
-    send_to_char(ch, "But that's not furniture!\r\n");
-  // make sure we found something we might be able to sit on
-  else if(charGetFurniture(ch) == furniture)
-    send_to_char(ch, "You're already %s %s.\r\n",
-		 (furnitureGetType(furniture) == FURNITURE_ON ? "on" : "at"),
-		 objGetName(furniture));
-
-  else if(furnitureGetCapacity(furniture) <= listSize(objGetUsers(furniture)))
-    send_to_char(ch, "There isn't any room left.\r\n");
-  
-  else {
-    // if we're already sitting on something, get up first
-    if(charGetFurniture(ch)) {
-      send_to_char(ch, "You stand up from %s.\r\n", 
-		   objGetName(charGetFurniture(ch)));
-      message(ch, NULL, charGetFurniture(ch), NULL,TRUE, TO_ROOM,
-	      "$n stands up from $o.");
-      char_from_furniture(ch);
-    }
-
-    // send out messages
-    char other_buf[SMALL_BUFFER];
-    sprintf(other_buf, "$n %s %s $o.",	
-	    posGetActionOther(pos),
-	    (furnitureGetType(furniture) == FURNITURE_ON ? "on" : "at"));
-    message(ch, NULL, furniture, NULL, TRUE, TO_ROOM, other_buf);
-
-    send_to_char(ch, "You %s %s %s.\r\n",
-		 posGetActionSelf(pos),
-		 (furnitureGetType(furniture) == FURNITURE_ON ? "on" : "at"),
-		 objGetName(furniture));
-
-    // now sit down on the new thing
-    char_to_furniture(ch, furniture);
-    charSetPos(ch, pos);
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-COMMAND(cmd_sit) {
-  if(!arg || !*arg)
-    try_change_pos(ch, POS_SITTING);
-  else
-    try_use_furniture(ch, arg, POS_SITTING);
-}
-
-COMMAND(cmd_sleep) {
-  if(!arg || !*arg)
-    try_change_pos(ch, POS_SLEEPING);
-  else
-    try_use_furniture(ch, arg, POS_SLEEPING);
-}
-
-COMMAND(cmd_stand) {
-  if(charGetPos(ch) == POS_FLYING) {
-    send_to_char(ch, "You stop flying.\r\n");
-    send_around_char(ch, TRUE, "%s stops flying.\r\n", charGetName(ch));
-    charSetPos(ch, POS_STANDING);
-  }
-  else {
-    if(try_change_pos(ch, POS_STANDING) && charGetFurniture(ch))
-      char_from_furniture(ch);
-  }
-}
-
-COMMAND(cmd_wake) {
-  send_to_char(ch, "You stop sleeping and sit up.\r\n");
-  send_around_char(ch, TRUE, "%s stops sleeping and sits up.\r\n",
-		   charGetName(ch));
-  charSetPos(ch, POS_SITTING);
-}
diff -ruN ../nakedmudv3.1/src/movement.h src/movement.h
--- ../nakedmudv3.1/src/movement.h	Sun Dec  4 20:03:08 2005
+++ src/movement.h	Wed Dec 31 17:00:00 1969
@@ -1,27 +0,0 @@
-#ifndef MOVEMENT_H
-#define MOVEMENT_H
-//*****************************************************************************
-//
-// movement.h
-//
-// all of the functions assocciated with moving (chars and objects)
-//
-//*****************************************************************************
-
-//
-// Try to move in a specified direction. Returns the exit that was gone through
-// if successful. A move might be false if a) there is a no (noticable) opened
-// exit in the direction, the character is busy with some activity
-// (.e.g fighting) that will not let him move, or his position is not one that
-// is easily movable in (e.g. sleeping, resting, dead). The direction can be
-// anything. Abbreviations of the normal directions (n, s, e, w) are handled
-// properly by this function. Does not send messages to the rooms saying the
-// person has entered/exited.
-EXIT_DATA *try_move(CHAR_DATA *ch, const char *dir);
-
-//
-// Exactly the same as try_move, except this also sends messages saying the
-// person has entered/exited.
-EXIT_DATA *try_move_mssg(CHAR_DATA *ch, const char *dir);
-
-#endif // MOVEMENT_H
diff -ruN ../nakedmudv3.1/src/olc2/olc.c src/olc2/olc.c
--- ../nakedmudv3.1/src/olc2/olc.c	Sun Dec  4 20:03:07 2005
+++ src/olc2/olc.c	Sat Jul  1 20:06:58 2006
@@ -17,6 +17,13 @@
 #include "../world.h"
 #include "../character.h"  // for POS_XXX <-- we should change the place of this
 #include "../auxiliary.h"
+#include "../prototype.h"
+#include "../zone.h"
+#include "../room_reset.h"
+#include "../room.h"
+#include "../handler.h"
+#include "../object.h"
+#include "../inform.h"
 #include "olc.h"
 
 
@@ -247,11 +254,307 @@
 
 
 //*****************************************************************************
+// builder commands
+//*****************************************************************************
+
 //
-// implementation of olc.h
+// Load a copy of a specific mob/object
+// usage: load <mob | obj> <vnum>
+COMMAND(cmd_load) {
+  if(!arg || !*arg)
+    send_to_char(ch, "What did you want to load?\r\n");
+  else {
+    char   type[SMALL_BUFFER];
+    char   name[SMALL_BUFFER];
+    char locale[SMALL_BUFFER];
+    char    key[SMALL_BUFFER];
+    arg = one_arg(arg, type);
+    if(!parse_worldkey_relative(ch, arg, name, locale)) {
+      send_to_char(ch, "What did you want to load?\r\n");
+      return;
+    }
+
+    sprintf(key, "%s@%s", name, locale);
+    if(!strncasecmp("mobile", type, strlen(type))) {
+      PROTO_DATA *proto = worldGetType(gameworld, "mproto", key);
+      if(proto == NULL)
+	send_to_char(ch, "No mobile prototype exists with that key.\r\n");
+      else if(protoIsAbstract(proto))
+	send_to_char(ch, "That prototype is abstract.\r\n");
+      else {
+	CHAR_DATA *mob = protoMobRun(proto);
+	if(mob == NULL)
+	  send_to_char(ch, "There was an error running the prototype.\r\n");
+	else {
+	  send_to_char(ch, "You create %s.\r\n", charGetName(mob));
+	  char_to_room(mob, charGetRoom(ch));
+	}
+      }
+    }
+
+    else if(!strncasecmp("object", type, strlen(type))) {
+      PROTO_DATA *proto = worldGetType(gameworld, "oproto", key);
+      if(proto == NULL)
+	send_to_char(ch, "No object prototype exists with that key.\r\n");
+      else if(protoIsAbstract(proto))
+	send_to_char(ch, "That prototype is abstract.\r\n");
+      else {
+	OBJ_DATA *obj = protoObjRun(proto);
+	if(obj == NULL)
+	  send_to_char(ch, "There was an error running the prototype.\r\n");
+	else {
+	  send_to_char(ch, "You create %s.\r\n", objGetName(obj));
+	  obj_to_char(obj, ch);
+	}
+      }
+    }
+
+    // type not found
+    else 
+      send_to_char(ch, "What type of thing did you want to load?\r\n");
+  }
+}
+
+
+//
+// remove an object or player from the game. If no argument is supplied, all
+// objects and non-player characters are removed from the current room.
+//   usage: purge <target>
+COMMAND(cmd_purge) {
+  void    *found = NULL;
+  int found_type = PARSE_NONE;
+
+  if(!parse_args(ch, TRUE, cmd, arg, "| { ch.room.noself obj.room }",
+		 &found, &found_type))
+    return;
+
+  // purge everything in the current room
+  if(found == NULL) {
+    LIST_ITERATOR *list_i = newListIterator(roomGetContents(charGetRoom(ch)));
+    OBJ_DATA *obj;
+    CHAR_DATA *vict;
+
+    send_to_char(ch, "You purge the room.\r\n");
+    message(ch, NULL, NULL, NULL, FALSE, TO_ROOM,
+	    "$n raises $s arms, and white flames engulf the entire room.");
+
+    // purge all the objects. 
+    ITERATE_LIST(obj, list_i)
+      extract_obj(obj);
+    deleteListIterator(list_i);
+
+    // and now all of the non-characters
+    list_i = newListIterator(roomGetCharacters(charGetRoom(ch)));
+    ITERATE_LIST(vict, list_i) {
+      if(vict == ch || !charIsNPC(vict)) 
+	continue;
+      extract_mobile(vict);
+    }
+    deleteListIterator(list_i);
+  }
+
+  // purge characters
+  else if(found_type == PARSE_CHAR) {
+    // we can only purge him if we have all the same groups as him, and more
+    if(!charHasMoreUserGroups(ch, found))
+      send_to_char(ch, "Erm, you better not try that on %s. %s has "
+		   "just as much priviledges as you.\r\n", 
+		   HIMHER(found), HESHE(found));
+    else {
+      send_to_char(ch, "You purge %s.\r\n", charGetName(found));
+      message(ch, found, NULL, NULL, FALSE, TO_ROOM,
+	      "$n raises $s arms, and white flames engulf $N.");
+      extract_mobile(found);
+    }
+  }
+
+  // purge objects
+  else if(found_type == PARSE_OBJ) {
+    send_to_char(ch, "You purge %s.\r\n", objGetName(found));
+    message(ch, NULL, found, NULL, FALSE, TO_ROOM,
+	    "$n raises $s arms, and white flames engulf $o.");
+    obj_from_room(found);
+    extract_obj(found);
+  }
+}
+
+
 //
+// reruns the room's load script, and replaces the old version of the room with
+// the new one.
+COMMAND(cmd_rreload) {
+  PROTO_DATA   *proto = NULL;
+  ROOM_DATA *old_room = NULL;
+  ROOM_DATA *new_room = NULL;
+  ZONE_DATA     *zone = NULL;
+  const char     *key = roomGetClass(charGetRoom(ch));
+
+  // unless an arg is supplied, we're working on the current room.
+  if(arg && *arg)
+    key = get_fullkey_relative(arg, get_key_locale(key));
+
+  // make sure all of our requirements are met
+  if( (zone = worldGetZone(gameworld, get_key_locale(key))) == NULL)
+    send_to_char(ch, "That zone does not exist!\r\n");
+  else if(!canEditZone(zone, ch))
+    send_to_char(ch, "You are not authorized to edit that zone.\r\n");
+  else if( (proto = worldGetType(gameworld, "rproto", key)) == NULL)
+    send_to_char(ch, "No prototype for that room exists.\r\n");
+  else if(!worldRoomLoaded(gameworld, key))
+    send_to_char(ch, "No room with that key is currently loaded.\r\n");
+  else {
+    // try running the proto to get our new room...
+    old_room = worldGetRoom(gameworld, key);
+    new_room = protoRoomRun(proto);
+    if(new_room == NULL)
+      send_to_char(ch, "There was an error reloading the room.\r\n");
+    else {
+      do_mass_transfer(old_room, new_room, TRUE, TRUE, TRUE);
+      extract_room(old_room);
+      worldPutRoom(gameworld, key, new_room);
+      send_to_char(ch, "Room reloaded.\r\n");
+    }
+  }
+}
+
+
+//
+// trigger all of a specified zone's reset scripts and such. If no vnum is
+// supplied, the zone the user is currently in is reset.
+//   usage: zreset <zone vnum>
+COMMAND(cmd_zreset) {
+  ZONE_DATA *zone = NULL;
+
+  if(!arg || !*arg)
+    zone= worldGetZone(gameworld,get_key_locale(roomGetClass(charGetRoom(ch))));
+  else
+    zone= worldGetZone(gameworld, arg);
+
+  if(zone == NULL)
+    send_to_char(ch, "Which zone did you want to reset?\r\n");
+  else if(!canEditZone(zone, ch))
+    send_to_char(ch, "You are not authorized to edit that zone.\r\n");
+  else {
+    send_to_char(ch, "%s has been reset.\r\n", zoneGetName(zone));
+    zoneForceReset(zone);
+  }
+}
+
+COMMAND(cmd_rdelete) {
+  char *name = NULL;
+  if(!parse_args(ch, TRUE, cmd, arg, "word", &name))
+    return;
+  if(do_delete(ch, "rproto", deleteProto, name)) {
+    do_delete(ch, "reset", deleteResetList, name);
+    send_to_char(ch, "If the room has already been used, do not forget to "
+		 "also purge the current instance of it.\r\n");
+  }
+}
+
+COMMAND(cmd_mdelete) {
+  char *name = NULL;
+  if(!parse_args(ch, TRUE, cmd, arg, "word", &name))
+    return;
+  do_delete(ch, "mproto", deleteProto, name);
+}
+
+COMMAND(cmd_odelete) {
+  char *name = NULL;
+  if(!parse_args(ch, TRUE, cmd, arg, "word", &name))
+    return;
+  do_delete(ch, "oproto", deleteProto, name);
+}
+
+
+
+//*****************************************************************************
+// Functions for listing different types of data (zones, mobs, objs, etc...)
 //*****************************************************************************
+//
+// returns yes/no if the prototype is abstract or not
+const char *prototype_list_info(PROTO_DATA *data) {
+  static char buf[SMALL_BUFFER];
+  sprintf(buf, "%-50s %3s", 
+	  (*protoGetParents(data) ? protoGetParents(data) : "-------"),
+	  (protoIsAbstract(data)  ? "yes" : "no"));
+  return buf;
+}
+
+// this is used for the header when printing out zone proto info
+#define PROTO_LIST_HEADER \
+"Parents                                       Abstract"
+
+
+COMMAND(cmd_rlist) {
+  do_list(ch, (arg&&*arg?arg:get_key_locale(roomGetClass(charGetRoom(ch)))),
+	  "rproto", PROTO_LIST_HEADER, prototype_list_info);
+}
+
+COMMAND(cmd_mlist) {
+  do_list(ch, (arg&&*arg?arg:get_key_locale(roomGetClass(charGetRoom(ch)))),
+	  "mproto", PROTO_LIST_HEADER, prototype_list_info);
+}
+
+COMMAND(cmd_olist) {
+  do_list(ch, (arg&&*arg?arg:get_key_locale(roomGetClass(charGetRoom(ch)))),
+	  "oproto", PROTO_LIST_HEADER, prototype_list_info);
+}
+
+COMMAND(cmd_mrename) {
+  char *from = NULL, *to = NULL;
+  if(!parse_args(ch, TRUE, cmd, arg, "word word", &from, &to))
+    return;
+  do_rename(ch, "mproto", from, to);
+}
+
+COMMAND(cmd_rrename) {
+  char *from = NULL, *to = NULL;
+  if(!parse_args(ch, TRUE, cmd, arg, "word word", &from, &to))
+    return;
+  if(do_rename(ch, "rproto", from, to)) {
+    do_rename(ch, "reset", from, to);
+    send_to_char(ch, "No not forget to purge any instances of %s already "
+		 "loaded.\r\n", from); 
+  }
+}
+
+COMMAND(cmd_orename) {
+  char *from = NULL, *to = NULL;
+  if(!parse_args(ch, TRUE, cmd, arg, "word word", &from, &to))
+    return;
+  do_rename(ch, "oproto", from, to);
+}
+
+COMMAND(cmd_zlist) {
+  LIST *keys = worldGetZoneKeys(gameworld);
+
+  // first, order all the zones
+  listSortWith(keys, strcasecmp);
+
+  // now, iterate across them all and show them
+  LIST_ITERATOR *zone_i = newListIterator(keys);
+  ZONE_DATA       *zone = NULL;
+  char             *key = NULL;
+
+  send_to_char(ch,
+" {wKey            Name                                             Editors  Timer\r\n"
+"{b--------------------------------------------------------------------------------\r\n{n");
+
+  ITERATE_LIST(key, zone_i) {
+    if( (zone = worldGetZone(gameworld, key)) != NULL) {
+      send_to_char(ch, " {c%-14s %-30s %25s  {w%5d\r\n", key, zoneGetName(zone),
+		   zoneGetEditors(zone), zoneGetPulseTimer(zone));
+    }
+  } deleteListIterator(zone_i);
+  deleteListWith(keys, free);
+  send_to_char(ch, "{g");
+}
+
+
 
+//*****************************************************************************
+// implementation of olc.h
+//*****************************************************************************
 void init_olc2() {
   // install our auxiliary data on the socket so 
   // we can keep track of our olc data
@@ -272,6 +575,9 @@
   extern COMMAND(cmd_mpedit);
   extern COMMAND(cmd_opedit);
   extern COMMAND(cmd_rpedit);
+  extern COMMAND(cmd_dig);
+  extern COMMAND(cmd_fill);
+  extern COMMAND(cmd_instantiate);
   add_cmd("zedit", NULL, cmd_zedit, POS_UNCONCIOUS, POS_FLYING,
 	  "builder", FALSE, TRUE);
   add_cmd("redit", NULL, cmd_redit, POS_UNCONCIOUS, POS_FLYING,
@@ -292,6 +598,44 @@
 	  "scripter", FALSE, TRUE);
   add_cmd("rpedit", NULL, cmd_rpedit, POS_UNCONCIOUS, POS_FLYING,
 	  "scripter", FALSE, TRUE);
+
+  add_cmd("dig", NULL, cmd_dig, POS_STANDING, POS_FLYING,
+	  "builder", FALSE, TRUE);
+  add_cmd("fill", NULL, cmd_fill, POS_STANDING, POS_FLYING,
+	  "builder", FALSE, TRUE);
+  add_cmd("instantiate", NULL, cmd_instantiate, POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, TRUE);
+  add_cmd("purge",      NULL, cmd_purge,    POS_SITTING,  POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("load",       NULL, cmd_load,     POS_SITTING,  POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("rcopy", NULL, cmd_instantiate,   POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, TRUE);
+
+  add_cmd("mlist",      NULL, cmd_mlist,    POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("mdelete",    NULL, cmd_mdelete,  POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("mrename",    NULL, cmd_mrename,  POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("olist",      NULL, cmd_olist,    POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("odelete",    NULL, cmd_odelete,  POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("orename",    NULL, cmd_orename,  POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("rreload",    NULL, cmd_rreload,  POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("rlist",      NULL, cmd_rlist,    POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("rdelete",    NULL, cmd_rdelete,  POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("rrename",    NULL, cmd_rrename,  POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
+  add_cmd("zlist",      NULL, cmd_zlist,    POS_SITTING,  POS_FLYING,
+	  "builder", FALSE, TRUE);
+  add_cmd("zreset",     NULL, cmd_zreset,   POS_UNCONCIOUS, POS_FLYING,
+	  "builder", FALSE, FALSE);
 }
 
 void do_olc(SOCKET_DATA *sock,
diff -ruN ../nakedmudv3.1/src/olc2/redit.c src/olc2/redit.c
--- ../nakedmudv3.1/src/olc2/redit.c	Sun Dec  4 20:03:07 2005
+++ src/olc2/redit.c	Sat Jul  1 20:06:58 2006
@@ -1320,6 +1320,283 @@
 }
 
 
+COMMAND(cmd_dig) {
+  ROOM_DATA      *dest = NULL;
+  char     *parsed_dir = NULL;
+  char *parsed_ret_dir = NULL;
+  char        *ret_dir = NULL;
+  char            *dir = NULL;
+  
+  // parse our arguments
+  if(!parse_args(ch, TRUE, cmd, arg, "room word | word",
+		 &dest, &parsed_dir, &parsed_ret_dir))
+    return;
+
+  // figure out our direction
+  if(dirGetAbbrevNum(parsed_dir) != DIR_NONE)
+    dir = strdup(dirGetName(dirGetAbbrevNum(parsed_dir)));
+  // special exit
+  else
+    dir = strdup(parsed_dir);
+
+  // figure out our return direction. First case == special exit
+  if(parsed_ret_dir != NULL)
+    ret_dir = strdup(parsed_ret_dir);
+  else if(dirGetNum(dir) != DIR_NONE)
+    ret_dir = strdup(dirGetName(dirGetOpposite(dirGetNum(dir))));
+  else if(dirGetAbbrevNum(dir) != DIR_NONE)
+    ret_dir = strdup(dirGetName(dirGetOpposite(dirGetAbbrevNum(dir))));
+
+  // make sure we have a return direction
+  if(ret_dir == NULL)
+    send_to_char(ch, "A return direction for the dig could not be found.\r\n");
+
+  // make sure we don't have an exit in the specified direction
+  else if(roomGetExit(charGetRoom(ch), dir) != NULL)
+    send_to_char(ch, "An exit already exists %s -- fill it first!\r\n",
+		 dir);
+
+  // make sure we don't have an exit in the return direction
+  else if(roomGetExit(dest, ret_dir) != NULL)
+    send_to_char(ch, "An exit already exists in the return direction -- fill it first!\r\n");
+
+  // make sure we have edit priviledges
+  else if(!canEditZone(worldGetZone(gameworld, get_key_locale(roomGetClass(charGetRoom(ch)))), ch))
+    send_to_char(ch, "You are not authorized to edit this zone.\r\n");
+
+  // make sure we have edit priviledges for the destination
+  else if(!canEditZone(worldGetZone(gameworld, get_key_locale(roomGetClass(dest))), ch))
+    send_to_char(ch,"You are not authorized to edit the destination zone.\r\n");
+
+  // do the digging
+  else {
+    // get the prototype for our current room and destination
+    PROTO_DATA  *proto_here = 
+      worldGetType(gameworld, "rproto", roomGetClass(charGetRoom(ch)));
+    PROTO_DATA *proto_there = 
+      worldGetType(gameworld, "rproto", roomGetClass(dest));
+
+    // parse a ROOM_OLC out of them both
+    ROOM_OLC  *olc_here = roomOLCFromProto(proto_here);
+    ROOM_OLC *olc_there = roomOLCFromProto(proto_there);
+
+    // make our exits
+    EXIT_DATA  *exit_here = newExit();
+    EXIT_DATA *exit_there = newExit();
+    exitSetTo(exit_here, roomGetClass(dest));
+    exitSetTo(exit_there, roomGetClass(charGetRoom(ch)));
+
+    // link our rooms
+    roomSetExit(roomOLCGetRoom(olc_here), dir, exit_here);
+    roomSetExit(roomOLCGetRoom(olc_there), ret_dir, exit_there);
+
+    // save our changes and reload the rooms
+    save_room_olc(olc_here);
+    save_room_olc(olc_there);
+
+    // garbage collection
+    deleteRoomOLC(olc_here);
+    deleteRoomOLC(olc_there);
+
+    // inform the builder
+    send_to_char(ch, "You link %s [%s] to %s [%s].\r\n",
+		 roomGetClass(charGetRoom(ch)), dir,
+		 roomGetClass(dest), ret_dir);
+  }
+
+  // garbage collection
+  free(dir);
+  free(ret_dir);
+}
+
+COMMAND(cmd_fill) {
+  ROOM_DATA      *dest = NULL;
+  char     *parsed_dir = NULL;
+  char *parsed_ret_dir = NULL;
+  char        *ret_dir = NULL;
+  char            *dir = NULL;
+  
+  // parse our arguments
+  if(!parse_args(ch, TRUE, cmd, arg, "word | word",
+		 &parsed_dir, &parsed_ret_dir))
+    return;
+
+  // figure out our direction
+  if(dirGetAbbrevNum(parsed_dir) != DIR_NONE)
+    dir = strdup(dirGetName(dirGetAbbrevNum(parsed_dir)));
+  // special exit
+  else
+    dir = strdup(parsed_dir);
+
+  // figure out our return direction. First case == special exit
+  if(parsed_ret_dir != NULL)
+    ret_dir = strdup(parsed_ret_dir);
+  else if(dirGetNum(dir) != DIR_NONE)
+    ret_dir = strdup(dirGetName(dirGetOpposite(dirGetNum(dir))));
+  else if(dirGetAbbrevNum(dir) != DIR_NONE)
+    ret_dir = strdup(dirGetName(dirGetOpposite(dirGetAbbrevNum(dir))));
+
+  // make sure we have a return direction
+  if(ret_dir == NULL)
+    send_to_char(ch, "A return direction for fill could not be found.\r\n");
+  // make sure we have the exit
+  else if(!roomGetExit(charGetRoom(ch), dir))
+    send_to_char(ch, "No exit exists %s!\r\n", dir);
+  // make sure the destination exists
+  else if((dest = worldGetRoom(gameworld,exitGetTo(roomGetExit(charGetRoom(ch),
+							       dir)))) == NULL)
+    send_to_char(ch, "No destination exists %s!\r\n", dir);
+  // make sure we have edit priviledges
+  else if(!canEditZone(worldGetZone(gameworld, get_key_locale(roomGetClass(charGetRoom(ch)))), ch))
+    send_to_char(ch, "You are not authorized to edit this zone.\r\n");
+  // make sure we have edit priviledges for the destination
+  else if(!canEditZone(worldGetZone(gameworld, get_key_locale(roomGetClass(dest))), ch))
+    send_to_char(ch,"You are not authorized to edit the destination zone.\r\n");
+
+  // do the digging
+  else {
+    // get the prototype for our current room and destination
+    PROTO_DATA  *proto_here = 
+      worldGetType(gameworld, "rproto", roomGetClass(charGetRoom(ch)));
+    PROTO_DATA *proto_there = 
+      worldGetType(gameworld, "rproto", roomGetClass(dest));
+
+    // parse a ROOM_OLC out of them both
+    ROOM_OLC  *olc_here = roomOLCFromProto(proto_here);
+    ROOM_OLC *olc_there = roomOLCFromProto(proto_there);
+
+    // delete our exits
+    roomRemoveExit(roomOLCGetRoom(olc_here), dir);
+    roomRemoveExit(roomOLCGetRoom(olc_there), ret_dir);
+
+    // save our changes and reload the rooms
+    save_room_olc(olc_here);
+    save_room_olc(olc_there);
+
+    // garbage collection
+    deleteRoomOLC(olc_here);
+    deleteRoomOLC(olc_there);
+
+    // inform the builder
+    send_to_char(ch, "You unlink %s [%s] and %s [%s].\r\n",
+		 roomGetClass(charGetRoom(ch)), dir,
+		 roomGetClass(dest), ret_dir);
+  }
+
+  // garbage collection
+  free(dir);
+  free(ret_dir);
+}
+
+
+//
+// builds a list of all the instantiations in the range provided
+LIST *list_instantiations(const char *name, const char *locale, int times) {
+  LIST         *list = newList();
+  int      i, base_i = 1;
+  char *working_name = strdup(name);
+
+  // see if we have a start number provided
+  //***********
+  // FINISH ME
+  //***********
+
+  // generate our keys
+  for(i = base_i; i < times + base_i; i++) {
+    char fullkey[SMALL_BUFFER];
+    sprintf(fullkey, "%s%s%d@%s", working_name, (i < 10 ? "0" : ""), i, locale);
+    listQueue(list, strdup(fullkey));
+  }
+
+  // garbage collection
+  free(working_name);
+  return list;
+}
+
+
+//
+// checks to see if any of the rooms are already cloned
+bool check_for_instantiations(CHAR_DATA *ch, const char *name, const char *locale, int times) {
+  LIST           *keys = list_instantiations(name, locale, times);
+  LIST_ITERATOR *key_i = newListIterator(keys);
+  char            *key = NULL;
+  bool         success = TRUE;  
+
+  ITERATE_LIST(key, key_i) {
+    // check for the existance
+    if(worldGetType(gameworld, "rproto", key) != NULL) {
+      send_to_char(ch, "A prototype with key %s already exists.", key);
+      success = FALSE;
+      break;
+    }
+  } deleteListIterator(key_i);
+  deleteListWith(keys, free);
+
+  return success;
+}
+
+COMMAND(cmd_instantiate) {
+  ZONE_DATA  *dest_zone = NULL;
+  ZONE_DATA   *src_zone = NULL; 
+  char            *dest = NULL;
+  char             *src = NULL;
+  char dest_locale[SMALL_BUFFER];
+  char   dest_name[SMALL_BUFFER];
+  char  src_locale[SMALL_BUFFER];
+  char    src_name[SMALL_BUFFER];
+  int             times = 1;
+
+  // rcopy <source> <dest> [times]
+  if(!parse_args(ch, TRUE, cmd, arg, "word word | int", &src, &dest, &times))
+    return;
+  // get our locale and name for the source
+  else if(!parse_worldkey_relative(ch, src, src_name, src_locale))
+    send_to_char(ch, "What is the key of the source room?\r\n");
+  // get our locale and name for the dest
+  else if(!parse_worldkey_relative(ch, dest, dest_name, dest_locale))
+    send_to_char(ch, "What is the key of the destination room?\r\n");
+  // make sure the destination zone is editable
+  else if((dest_zone = worldGetZone(gameworld, dest_locale)) == NULL)
+    send_to_char(ch, "No such destination zone exists.\r\n");
+  else if((src_zone = worldGetZone(gameworld, src_locale)) == NULL)
+    send_to_char(ch, "No such source zone exists.\r\n");
+  // make sure we have editing priviledges
+  else if(!canEditZone(dest_zone, ch))
+    send_to_char(ch,"You are not authorized to edit the destination zone.\r\n");
+  // make sure none of the prototypes we'll be making are instantiated
+  else if(!check_for_instantiations(ch, src_name, src_locale, times)) 
+    return;
+  else {
+    // generate our list of keys
+    LIST           *keys = list_instantiations(dest_name, dest_locale, times);
+    LIST_ITERATOR *key_i = newListIterator(keys);
+    char            *key = NULL;
+    bool      resettable = FALSE;
+
+    // check to see if the source room is resettable
+    if(listGetWith(zoneGetResettable(src_zone),
+		   get_key_name(get_fullkey(src_name, src_locale)),
+		   strcasecmp) != NULL)
+      resettable = TRUE;
+
+    // create each of the rooms to be cloned
+    ITERATE_LIST(key, key_i) {
+      ROOM_OLC *data = newRoomOLC();
+      roomOLCSetKey(data, key);
+      resetListSetKey(roomOLCGetResets(data), key);
+      roomOLCSetAbstract(data, FALSE);
+      roomOLCSetResettable(data, resettable);
+      roomOLCSetParents(data, get_fullkey(src_name, src_locale));
+      save_room_olc(data);
+      deleteRoomOLC(data);
+    } deleteListIterator(key_i);
+    deleteListWith(keys, free);
+
+    send_to_char(ch, "You create %d new instantion%s of %s@%s.\r\n",
+		 times, (times == 1 ? "":"s"), src_name, src_locale);
+  }
+}
+
 COMMAND(cmd_redit) {
   ZONE_DATA    *zone = NULL;
   PROTO_DATA  *proto = NULL;
diff -ruN ../nakedmudv3.1/src/parse.c src/parse.c
--- ../nakedmudv3.1/src/parse.c	Sun Dec  4 20:03:08 2005
+++ src/parse.c	Sat Jul  1 20:06:58 2006
@@ -15,6 +15,10 @@
 #include "inform.h"
 #include "parse.h"
 
+// mandatory modules
+#include "scripts/scripts.h"
+#include "scripts/pyexit.h"
+
 
 
 //*****************************************************************************
@@ -36,7 +40,11 @@
 #define PARSE_VAR_BOOL         0
 #define PARSE_VAR_INT          1
 #define PARSE_VAR_DOUBLE       2
-#define PARSE_VAR_POINTER      4
+#define PARSE_VAR_CHAR         4
+#define PARSE_VAR_OBJ          5
+#define PARSE_VAR_ROOM         6
+#define PARSE_VAR_EXIT         7
+#define PARSE_VAR_STRING       8
 
 
 
@@ -575,7 +583,7 @@
   if(found == NULL)
     return NULL;
   else {
-    PARSE_VAR *var = newParseVar(PARSE_VAR_POINTER);
+    PARSE_VAR *var = newParseVar(PARSE_VAR_CHAR);
 
     // if multiple vals were possible, flag it
     var->multiple_possible = tok->all_ok;
@@ -632,7 +640,7 @@
   if(found == NULL)
     return NULL;
   else {
-    PARSE_VAR *var = newParseVar(PARSE_VAR_POINTER);
+    PARSE_VAR *var = newParseVar(PARSE_VAR_OBJ);
 
     // if multiple vals were possible, flag it
     var->multiple_possible = tok->all_ok;
@@ -682,7 +690,7 @@
   if(found == NULL)
     return NULL;
   else {
-    PARSE_VAR *var = newParseVar(PARSE_VAR_POINTER);
+    PARSE_VAR *var = newParseVar(PARSE_VAR_EXIT);
 
     // if multiple vals were possible, flag it
     var->multiple_possible = tok->all_ok;
@@ -731,7 +739,7 @@
   if(room == NULL)
     return NULL;
   else {
-    PARSE_VAR *var = newParseVar(PARSE_VAR_POINTER);
+    PARSE_VAR *var = newParseVar(PARSE_VAR_ROOM);
     var->ptr_val   = room;
     return var;
   }
@@ -885,7 +893,7 @@
 
     // parse out a single word
   case PARSE_TOKEN_WORD: {
-    var = newParseVar(PARSE_VAR_POINTER);
+    var = newParseVar(PARSE_VAR_STRING);
     var->ptr_val    = arg;
     bool multi_word = FALSE;
 
@@ -909,7 +917,7 @@
 
     // copies whatever is left
   case PARSE_TOKEN_STRING:
-    var = newParseVar(PARSE_VAR_POINTER);
+    var = newParseVar(PARSE_VAR_STRING);
     var->ptr_val = arg;
     // skip up the place of the arg...
     while(*arg != '\0')
@@ -1083,7 +1091,11 @@
     case PARSE_VAR_DOUBLE:
       *va_arg(vargs, double *) = one_var->dbl_val;
       break;
-    case PARSE_VAR_POINTER:
+    case PARSE_VAR_STRING:
+    case PARSE_VAR_OBJ:
+    case PARSE_VAR_CHAR:
+    case PARSE_VAR_EXIT:
+    case PARSE_VAR_ROOM:
       *va_arg(vargs, void **) = one_var->ptr_val;
       break;
     // this should never happen...
@@ -1102,10 +1114,171 @@
 }
 
 
+//
+// Goes through the list of variables and make a python list with them
+PyObject *parse_create_py_vars(LIST *variables) {
+  LIST_ITERATOR *var_i = newListIterator(variables);
+  PARSE_VAR   *one_var = NULL;
+  PyObject       *list = PyList_New(0);
+  PyObject      *pyval = NULL;
+
+  // go through each variable and assign to vargs as needed
+  ITERATE_LIST(one_var, var_i) {
+    // first, do our basic type
+    switch(one_var->type) {
+    case PARSE_VAR_BOOL:
+      pyval = Py_BuildValue("b", one_var->bool_val);
+      PyList_Append(list, pyval);
+      Py_DECREF(pyval);
+      break;
+    case PARSE_VAR_INT:
+      pyval = Py_BuildValue("i", one_var->int_val);
+      PyList_Append(list, pyval);
+      Py_DECREF(pyval);
+      break;
+    case PARSE_VAR_DOUBLE:
+      pyval = Py_BuildValue("f", one_var->dbl_val);
+      PyList_Append(list, pyval);
+      Py_DECREF(pyval);
+      break;
+    case PARSE_VAR_STRING:
+      pyval = Py_BuildValue("s", one_var->ptr_val);
+      PyList_Append(list, pyval);
+      Py_DECREF(pyval);
+      break;
+    case PARSE_VAR_OBJ:
+      if(one_var->multiple == FALSE)
+	PyList_Append(list, objGetPyFormBorrowed(one_var->ptr_val));
+      else {
+	pyval = PyList_fromList(one_var->ptr_val, objGetPyForm);
+	PyList_Append(list, pyval);
+	Py_DECREF(pyval);
+      }
+      break;
+    case PARSE_VAR_CHAR:
+      if(one_var->multiple == FALSE)
+	PyList_Append(list, charGetPyFormBorrowed(one_var->ptr_val));
+      else {
+	pyval = PyList_fromList(one_var->ptr_val, charGetPyForm);
+	PyList_Append(list, pyval);
+	Py_DECREF(pyval);
+      }
+      break;
+    case PARSE_VAR_EXIT:
+      pyval = newPyExit(one_var->ptr_val);
+      PyList_Append(list, pyval);
+      Py_DECREF(pyval);
+      break;
+    case PARSE_VAR_ROOM:
+      PyList_Append(list, roomGetPyFormBorrowed(one_var->ptr_val));
+      break;
+    // this should never happen...
+    default:
+      break;
+    }
+    
+    // now see if we have a multi_type
+    if(one_var->disambiguated_type != PARSE_NONE) {
+      pyval = 
+	Py_BuildValue("s", (one_var->disambiguated_type==PARSE_CHAR?"char":
+			    (one_var->disambiguated_type==PARSE_ROOM?"room":
+			     (one_var->disambiguated_type==PARSE_OBJ?"obj":
+			      (one_var->disambiguated_type==PARSE_EXIT?"exit":
+			       NULL)))));
+      PyList_Append(list, pyval);
+      Py_DECREF(pyval);
+    }
+
+    // and if we parsed multiple occurences
+    if(one_var->multiple_possible == TRUE) {
+      pyval = Py_BuildValue("b", one_var->multiple);
+      PyList_Append(list, pyval);
+      Py_DECREF(pyval);
+    }
+  } deleteListIterator(var_i);
+
+  return list;
+}
+
+
 
 //*****************************************************************************
 // implementation of parse.h
 //*****************************************************************************
+int parse_expected_py_args(const char *syntax) {
+  LIST *tokens = NULL;
+  if((tokens = decompose_parse_format(syntax)) == NULL)
+    return -1;
+  int count = 0;
+  LIST_ITERATOR *token_i = newListIterator(tokens);
+  PARSE_TOKEN     *token = NULL;
+  ITERATE_LIST(token, token_i) {
+    if(token->type == PARSE_TOKEN_FLAVOR || token->type == PARSE_TOKEN_OPTIONAL)
+      continue;
+
+    // one for a returnable type
+    count++;
+
+    // one to denote what kind in an ambiguous case
+    if(token->type == PARSE_TOKEN_MULTI)
+      count++;
+
+    // one to denote if we had multiples
+    if(token->all_ok)
+      count++;
+  } deleteListIterator(token_i);
+  deleteListWith(tokens, deleteParseToken);
+
+  return count;
+}
+
+void *Py_parse_args(CHAR_DATA *looker, bool show_errors, const char *cmd, 
+		    char *args, const char *syntax) {
+  char err_buf[SMALL_BUFFER] = "";
+  bool       parse_ok = TRUE;
+  LIST        *tokens = NULL;
+  LIST     *variables = NULL;
+  PyObject      *list = NULL;
+
+  // get our list of tokens
+  if((tokens = decompose_parse_format(syntax)) == NULL) {
+    log_string("Command '%s', format error in argument parsing: %s",cmd,syntax);
+    parse_ok = FALSE;
+  }
+  // try to use our tokens to compose a variable list
+  else if((variables = compose_variable_list(looker, tokens, args, err_buf))
+	  == NULL)
+    parse_ok = FALSE;
+  else {
+    // go through all of our vars and make python forms for them
+    list = parse_create_py_vars(variables);
+
+    // fill up optional spots at the end we didn't parse args for
+    int expected = parse_expected_py_args(syntax);
+    while(PyList_Size(list) < expected)
+      PyList_Append(list, Py_None);
+  }
+
+  // did we encounter an error with the arguments and need to mssg someone?
+  if(tokens != NULL && !parse_ok && show_errors) {
+    // do we have a specific error message?
+    if(*err_buf)
+      send_to_char(looker, "%s\r\n", err_buf);
+    // assume a syntax error
+    else
+      show_parse_syntax_error(looker, cmd, tokens);
+  }
+
+  // clean up our mess
+  if(tokens != NULL)
+    deleteListWith(tokens, deleteParseToken);
+  if(variables != NULL)
+    deleteListWith(variables, deleteParseVar);
+
+  // return our parse status
+  return list;
+}
+
 bool parse_args(CHAR_DATA *looker, bool show_errors, const char *cmd,
 		char *args, const char *syntax, ...) {
   char err_buf[SMALL_BUFFER] = "";
diff -ruN ../nakedmudv3.1/src/parse.h src/parse.h
--- ../nakedmudv3.1/src/parse.h	Sun Dec  4 20:03:08 2005
+++ src/parse.h	Sat Jul  1 20:06:58 2006
@@ -113,4 +113,9 @@
 bool parse_args(CHAR_DATA *looker, bool show_errors, const char *cmd, 
 		char *args, const char *syntax, ...);
 
+//
+// the same as above, but returns a Python list version of the arguments
+void *Py_parse_args(CHAR_DATA *looker, bool show_errors, const char *cmd, 
+		    char *args, const char *syntax);
+
 #endif // PARSE_H
diff -ruN ../nakedmudv3.1/src/room_reset.c src/room_reset.c
--- ../nakedmudv3.1/src/room_reset.c	Sun Dec  4 20:03:08 2005
+++ src/room_reset.c	Sat Jul  1 20:06:58 2006
@@ -713,18 +713,31 @@
 
 //
 // room reset hook. Whenever a room is reset, apply all of its reset rules
-void room_reset_hook(ZONE_DATA *zone) {
+void room_reset_hook(const char *info) {
+  char  *zone_key = NULL;
+  hookParseInfo(info, &zone_key);
+  ZONE_DATA *zone = worldGetZone(gameworld, zone_key);
+  free(zone_key);
+
   LIST_ITERATOR *res_i = newListIterator(zoneGetResettable(zone));
   char           *name = NULL;
   const char   *locale = zoneGetKey(zone);
   RESET_LIST     *list = NULL;
   ROOM_DATA      *room = NULL;
   ITERATE_LIST(name, res_i) {
-    room = worldGetRoom(gameworld, get_fullkey(name, locale));
-    list = worldGetType(gameworld, "reset", get_fullkey(name, locale));
-    // do we have resets? If so, apply them...
-    if(room != NULL && list != NULL)
-      resetRunOn(resetListGetResets(list), room, INITIATOR_ROOM, locale);
+    if((room = worldGetRoom(gameworld, get_fullkey(name, locale))) != NULL) {
+      // first apply all of our prototype resets
+      LIST            *protos = parse_keywords(roomGetPrototypes(room));
+      LIST_ITERATOR  *proto_i = newListIterator(protos);
+      char             *proto = NULL;
+
+      // try to run each parent reset, and finally our own
+      ITERATE_LIST(proto, proto_i) {
+	if((list = worldGetType(gameworld, "reset", proto)) != NULL)
+	  resetRunOn(resetListGetResets(list), room, INITIATOR_ROOM, locale);
+      } deleteListIterator(proto_i);
+      deleteListWith(protos, free);
+    }
   } deleteListIterator(res_i);
 }
 
diff -ruN ../nakedmudv3.1/src/scripts/module.mk src/scripts/module.mk
--- ../nakedmudv3.1/src/scripts/module.mk	Sun Dec  4 20:18:43 2005
+++ src/scripts/module.mk	Sat Jul  1 20:12:13 2006
@@ -101,6 +101,8 @@
 	scripts/pychar.c        \
 	scripts/pyobj.c         \
 	scripts/pymud.c         \
+	scripts/pymudsys.c      \
+	scripts/pyhooks.c       \
 	scripts/pyroom.c        \
 	scripts/pyexit.c        \
 	scripts/script_editor.c \
diff -ruN ../nakedmudv3.1/src/scripts/pychar.c src/scripts/pychar.c
--- ../nakedmudv3.1/src/scripts/pychar.c	Sun Dec  4 20:03:07 2005
+++ src/scripts/pychar.c	Sat Jul  1 20:06:58 2006
@@ -22,12 +22,14 @@
 #include "../action.h"
 #include "../socket.h"
 #include "../prototype.h"
+#include "../save.h"
 
 #include "pyplugs.h"
 #include "scripts.h"
 #include "pychar.h"
 #include "pyroom.h"
 #include "pyobj.h"
+#include "pyexit.h"
 #include "pyauxiliary.h"
 
 
@@ -132,6 +134,12 @@
   else           return NULL;
 }
 
+PyObject *PyChar_getlookbuf(PyChar *self, void *closure) {
+  CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
+  if(ch != NULL) return Py_BuildValue("s", bufferString(charGetLookBuffer(ch)));
+  else           return NULL;
+}  
+
 PyObject *PyChar_getrdesc(PyChar *self, void *closure) {
   CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
   if(ch != NULL) return Py_BuildValue("s", charGetRdesc(ch));
@@ -266,6 +274,31 @@
   return retval;
 }
 
+PyObject *PyChar_getbodyparts(PyChar *self, PyObject *args) {
+  CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
+  if(ch == NULL) 
+    return NULL;
+
+  PyObject *list = PyList_New(0);
+  int i, num_bodyparts;
+  const char **bodyparts = bodyGetParts(charGetBody(ch), TRUE, &num_bodyparts);
+  for(i = 0; i < num_bodyparts; i++) {
+    PyObject *str = Py_BuildValue("s", bodyparts[i]);
+    PyList_Append(list, str);
+    Py_DECREF(str);
+  }
+  free(bodyparts);
+  return list;
+}
+
+
+PyObject *PyChar_getusergroups(PyChar *self, void *closure) {
+  CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
+  if(ch != NULL) 
+    return Py_BuildValue("s", bitvectorGetBits(charGetUserGroups(ch)));
+  else           
+    return NULL;
+}
 
 //
 // Standard check to make sure the character exists when
@@ -348,6 +381,24 @@
   return 0;
 }
 
+int PyChar_setlookbuf(PyChar *self, PyObject *value, void *closure) {
+  if (value == NULL) {
+    PyErr_Format(PyExc_TypeError, "Cannot delete character's look buffer");
+    return -1;
+  }
+  
+  if (!PyString_Check(value)) {
+    PyErr_Format(PyExc_TypeError, "Look bufers must be strings");
+    return -1;
+  }
+
+  CHAR_DATA *ch;
+  PYCHAR_CHECK_CHAR_EXISTS(self->uid, ch);
+  bufferClear(charGetLookBuffer(ch));
+  bufferCat(charGetLookBuffer(ch), PyString_AsString(value));
+  return 0;
+}
+
 int PyChar_setrdesc(PyChar *self, PyObject *value, void *closure) {
   if (value == NULL) {
     PyErr_Format(PyExc_TypeError, "Cannot delete character's rdesc");
@@ -619,8 +670,9 @@
 //
 // make the character perform an action
 PyObject *PyChar_act(PyChar *self, PyObject *value) {
-  char *act          = NULL;
-  if (!PyArg_ParseTuple(value, "s", &act)) {
+  char     *act = NULL;
+  bool alias_ok = FALSE; 
+  if (!PyArg_ParseTuple(value, "s|b", &act, &alias_ok)) {
     PyErr_Format(PyExc_TypeError, "Characters actions must be strings.");
     return NULL;
   }
@@ -629,7 +681,7 @@
   if(ch) {
     // do not send the actual act - if we edit it, things go awry
     char *working_act = strdupsafe(act);
-    do_cmd(ch, working_act, FALSE);
+    do_cmd(ch, working_act, alias_ok);
     free(working_act);
     return Py_BuildValue("i", 1);
   }
@@ -648,7 +700,7 @@
   PyObject *py_tgt = NULL;
 
   if(!PyArg_ParseTuple(arg, "O", &py_tgt)) {
-    PyErr_Format(PyExc_TypeError, "Must supply obj or mob for cansee");
+    PyErr_Format(PyExc_TypeError, "Must supply obj, mob, or exit for cansee");
     return NULL;
   }
 
@@ -661,13 +713,16 @@
   else {
     OBJ_DATA    *obj = NULL;
     CHAR_DATA  *pers = NULL;
+    EXIT_DATA    *ex = NULL;
 
     if(PyChar_Check(py_tgt))
       pers = PyChar_AsChar(py_tgt);
     else if(PyObj_Check(py_tgt))
       obj  = PyObj_AsObj(py_tgt);
+    else if(PyExit_Check(py_tgt))
+      ex   = PyExit_AsExit(py_tgt);
     else {
-      PyErr_Format(PyExc_TypeError, "Must supply obj or mob to cansee");
+      PyErr_Format(PyExc_TypeError, "Must supply obj, mob, or exit to cansee");
       return NULL;
     }
 
@@ -675,6 +730,8 @@
       return Py_BuildValue("b", can_see_obj(ch, obj));
     else if(pers != NULL)
       return Py_BuildValue("b", can_see_char(ch, pers));
+    else if(ex != NULL)
+      return Py_BuildValue("b", can_see_exit(ch, ex));
     else {
       PyErr_Format(PyExc_StandardError, "Target of cansee did not exist!");
       return NULL;
@@ -810,7 +867,7 @@
   ROOM_DATA    *old_room = NULL;
   OBJ_DATA     *old_cont = NULL;
 
-  if (!PyArg_ParseTuple(args, "O|s", &pobj, &pos)) {
+  if (!PyArg_ParseTuple(args, "O|z", &pobj, &pos)) {
     PyErr_Format(PyExc_TypeError, 
 		 "Character equip must be supplied with an item to equip!");
     return NULL;
@@ -858,9 +915,10 @@
       obj_to_char(obj, old_carrier);
     else if(old_wearer != NULL)
       try_equip(ch, obj, old_pos, NULL);
-    PyErr_Format(PyExc_StandardError,
-		 "Character is already equipped in all possible positions!");
-    return NULL;
+    return Py_BuildValue("i", 0);
+    //    PyErr_Format(PyExc_StandardError,
+    //		 "Character is already equipped in all possible positions!");
+    //    return NULL;
   }
   // success
   else 
@@ -868,6 +926,28 @@
 }
 
 
+PyObject *PyChar_getequip(PyChar *self, PyObject *args) {  
+  CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
+  OBJ_DATA *obj = NULL;
+  char     *pos = NULL;
+  if(ch == NULL) {
+    PyErr_Format(PyExc_StandardError, "Nonexistant character");
+    return NULL;
+  }
+
+  if(!PyArg_ParseTuple(args, "s", &pos)) {
+    PyErr_Format(PyExc_TypeError, "A position name must be supplied.");
+    return NULL;
+  }
+  
+  obj = bodyGetEquipment(charGetBody(ch), pos);
+  if(obj == NULL)
+    return Py_None;
+  else
+    return Py_BuildValue("O", objGetPyFormBorrowed(obj));
+}
+
+
 PyObject *PyChar_attach(PyChar *self, PyObject *args) {  
   char *key = NULL;
 
@@ -1074,7 +1154,7 @@
     data = Py_None;
   }
   PyObject *retval = Py_BuildValue("O", data);
-  Py_DECREF(data);
+  //  Py_DECREF(data);
   return retval;
 }
 
@@ -1102,6 +1182,28 @@
   }
 }
 
+//
+// returns whether or not the character belongs to one of the specified groups
+PyObject *PyChar_is_in_groups(PyChar *self, PyObject *args) {  
+  char *groups = NULL;
+
+  // make sure we're getting passed the right type of data
+  if (!PyArg_ParseTuple(args, "s", &groups)) {
+    PyErr_Format(PyExc_TypeError, "is_in_groups only accepts strings.");
+    return NULL;
+  }
+
+  // pull out the object and check the type
+  CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
+  if(ch != NULL)
+    return Py_BuildValue("i", bitIsSet(charGetUserGroups(ch), groups));
+  else {
+    PyErr_Format(PyExc_StandardError, 
+		 "Tried to check user groups of nonexistent char, %d.", self->uid);
+    return NULL;
+  }
+}
+
 
 
 //*****************************************************************************
@@ -1442,12 +1544,16 @@
 		      "returns a list of objects in the char's inventory");
   PyChar_addGetSetter("eq",   PyChar_geteq,  NULL,
 		      "returns a list of the character's equipment");
+  PyChar_addGetSetter("bodyparts", PyChar_getbodyparts, NULL,
+		      "Returns a list of the character's bodyparts");
   PyChar_addGetSetter("name", PyChar_getname, PyChar_setname,
 		      "handle the character's name");
   PyChar_addGetSetter("mname", PyChar_getmname, PyChar_setmname,
 		      "handle the character's multi-name");
   PyChar_addGetSetter("desc", PyChar_getdesc, PyChar_setdesc,
 		      "handle the character's description");
+  PyChar_addGetSetter("look_buf", PyChar_getlookbuf, PyChar_setlookbuf,
+		      "handle the character's look buffer");
   PyChar_addGetSetter("rdesc", PyChar_getrdesc, PyChar_setrdesc,
 		      "handle the character's room description");
   PyChar_addGetSetter("mdesc", PyChar_getmdesc, PyChar_setmdesc,
@@ -1483,12 +1589,14 @@
   PyChar_addGetSetter("hisher", PyChar_gethisher, NULL,
 		      "Returns 'his' if the char is male, 'her' if female, and "
 		      "'its' for neuters");
-  PyChar_addGetSetter("himher", PyChar_gethisher, NULL,
+  PyChar_addGetSetter("himher", PyChar_gethimher, NULL,
 		      "Returns 'him' if the char is male, 'her' if female, and "
 		      "'it' for neuters");
-  PyChar_addGetSetter("heshe", PyChar_gethisher, NULL,
+  PyChar_addGetSetter("heshe", PyChar_getheshe, NULL,
 		      "Returns 'he' if the char is male, 'she' if female, and "
 		      "'it' for neuters");
+  PyChar_addGetSetter("user_groups", PyChar_getusergroups, NULL,
+		      "Returns the character's user groups");
 
   // add in all of our methods for the Char class
   PyChar_addMethod("attach", PyChar_attach, METH_VARARGS,
@@ -1514,6 +1622,8 @@
   PyChar_addMethod("equip", PyChar_equip, METH_VARARGS,
 		   "equips a character with the given item. Removes the item "
 		   "from whatever it is currently in/on.");
+  PyChar_addMethod("get_equip", PyChar_getequip, METH_VARARGS,
+		   "Returns the person's equipment in the specified slot.");
   PyChar_addMethod("isActing", PyChar_is_acting, METH_VARARGS,
 		   "Returns True if the character is currently taking an "
 		   "action, and False otherwise.");
@@ -1529,6 +1639,8 @@
 		   "page a bunch of text to the character.");
   PyChar_addMethod("isinstance", PyChar_isinstance, METH_VARARGS,
 		   "returns whether or not the char inherits from the proto");
+  PyChar_addMethod("isInGroup", PyChar_is_in_groups, METH_VARARGS,
+		   "returns whether or not the character belongs to one of the groups");
 
   // add in all the getsetters and methods
   makePyType(&PyChar_Type, pychar_getsetters, pychar_methods);
diff -ruN ../nakedmudv3.1/src/scripts/pyhooks.c src/scripts/pyhooks.c
--- ../nakedmudv3.1/src/scripts/pyhooks.c	Wed Dec 31 17:00:00 1969
+++ src/scripts/pyhooks.c	Sat Jul  1 20:06:58 2006
@@ -0,0 +1,336 @@
+//*****************************************************************************
+//
+// pyhooks.c
+//
+// The wrapper around hooks for Python to interact with them.
+//
+//*****************************************************************************
+
+#include "../mud.h"
+#include "../utils.h"
+#include "../hooks.h"
+
+#include "scripts.h"
+#include "pyroom.h"
+#include "pychar.h"
+#include "pyobj.h"
+#include "pyexit.h"
+#include "pyplugs.h"
+#include "pyhooks.h"
+
+
+
+//*****************************************************************************
+// local variables and functions
+//*****************************************************************************
+
+// a list of methods to add to the hooks module
+LIST *pyhooks_methods = NULL;
+
+// a table of python hooks we have installed
+HASHTABLE *pyhook_table = NULL;
+
+
+
+//*****************************************************************************
+// local methods
+//*****************************************************************************
+PyObject *PyHooks_BuildInfo(PyObject *self, PyObject *args) {
+  // parse out our variables
+  char           *format = NULL;
+  PyObject         *vars = NULL;
+  if(!PyArg_ParseTuple(args, "sO", &format, &vars)) {
+    PyErr_Format(PyExc_TypeError,"PyHook_BuildInfo requies format and tuple.");
+    return NULL;
+  }
+
+  // make sure we have a tuple
+  if(!PyTuple_Check(vars)) {
+    PyErr_Format(PyExc_TypeError, "Second argument to PyHooks_buildInfo must "
+		 "be a tuple.");
+    return NULL;
+  }
+
+  LIST *tokens = parse_strings(format, ' ');
+  // make sure our tuple and tokens are of the same length
+  if(listSize(tokens) != PyTuple_Size(vars)) {
+    PyErr_Format(PyExc_TypeError, "unequal number of tokens and values.");
+    deleteListWith(tokens, free);
+    return NULL;
+  }
+
+  // build each of our tokens into the info
+  BUFFER            *buf = newBuffer(1);
+  LIST_ITERATOR *token_i = newListIterator(tokens);
+  char            *token = NULL;
+  int                  i = 0;
+  PyObject          *var = NULL;
+  ITERATE_LIST(token, token_i) {
+    if(!strcasecmp(token, "ch")) {
+      var = PyTuple_GetItem(vars, i);
+      if(!PyChar_Check(var)) {
+	PyErr_Format(PyExc_TypeError, "arg %d was not Char", i);
+	break;
+      }
+      bprintf(buf, "ch.%d", PyChar_AsUid(var));
+    }
+    else if(!strcasecmp(token, "obj")) {
+      var = PyTuple_GetItem(vars, i);
+      if(!PyObj_Check(var)) {
+	PyErr_Format(PyExc_TypeError, "arg %d was not Obj", i);
+	break;
+      }
+      bprintf(buf, "obj.%d", PyObj_AsUid(var));
+    }
+    else if(!strcasecmp(token, "rm") || !strcasecmp(token, "room")) {
+      var = PyTuple_GetItem(vars, i);
+      if(!PyRoom_Check(var)) {
+	PyErr_Format(PyExc_TypeError, "arg %d was not Room", i);
+	break;
+      }
+      bprintf(buf, "rm.%d", PyRoom_AsUid(var));
+    }
+    else if(!strcasecmp(token, "ex") || !strcasecmp(token, "exit")) {
+      var = PyTuple_GetItem(vars, i);
+      if(!PyExit_Check(var)) {
+	PyErr_Format(PyExc_TypeError, "arg %d was not Exit", i);
+	break;
+      }
+      bprintf(buf, "ex.%d", PyExit_AsUid(var));
+    }
+    else if(!strcasecmp(token, "str")) {
+      var = PyTuple_GetItem(vars, i);
+      if(!PyString_Check(var)) {
+	PyErr_Format(PyExc_TypeError, "arg %d was not String", i);
+	break;
+      }
+      bprintf(buf, "%c%s%c", HOOK_STR_MARKER, PyString_AsString(var),
+	      HOOK_STR_MARKER);
+    }
+    else if(!strcasecmp(token, "int")) {
+      var = PyTuple_GetItem(vars, i);
+      if(!PyInt_Check(var)) {
+	PyErr_Format(PyExc_TypeError, "arg %d was not Integer", i);
+	break;
+      }
+      bprintf(buf, "%ld", PyInt_AsLong(var));
+    }
+    else if(!strcasecmp(token, "dbl")) {
+      var = PyTuple_GetItem(vars, i);
+      if(!PyFloat_Check(var)) {
+	PyErr_Format(PyExc_TypeError, "arg %d was not Float", i);
+	break;
+      }
+      bprintf(buf, "%lf", PyFloat_AsDouble(var));
+    }
+
+    // put a space in for our next variable if needed
+    if(i < listSize(tokens) - 1)
+      bprintf(buf, " ");
+    i++;
+  } deleteListIterator(token_i);
+  deleteListWith(tokens, free);
+
+  // did we manage to go through all of our tokens or not?
+  if(i != PyTuple_Size(vars)) {
+    deleteBuffer(buf);
+    return NULL;
+  }
+  else {
+    PyObject *retval = Py_BuildValue("s", bufferString(buf));
+    deleteBuffer(buf);
+    return retval;
+  }
+}
+
+
+PyObject *PyHooks_ParseInfo(PyObject *self, PyObject *args) {
+  // parse out our info
+  char             *info = NULL;
+  if(!PyArg_ParseTuple(args, "s", &info)) {
+    PyErr_Format(PyExc_TypeError, "PyHook_ParseInfo must be supplied a string");
+    return NULL;
+  }
+
+  // parse out all of our tokens
+  LIST           *tokens = parse_hook_info_tokens(info);
+  LIST_ITERATOR *token_i = newListIterator(tokens);
+  char            *token = NULL;
+  PyObject         *list = PyTuple_New(listSize(tokens));
+  int                  i = 0;
+
+  // id number we'll need for parsing some values
+  int id = 0;
+
+  // we need to crash-proof this function still
+  //***********
+  // FINISH ME
+  //***********
+
+  // go through all of our tokens
+  ITERATE_LIST(token, token_i) {
+    if(startswith(token, "ch")) {
+      sscanf(token, "ch.%d", &id);
+      PyTuple_SetItem(list, i, charGetPyForm(propertyTableGet(mob_table,id)));
+    }
+    else if(startswith(token, "obj")) {
+      sscanf(token, "obj.%d", &id);
+      PyTuple_SetItem(list, i, objGetPyForm(propertyTableGet(obj_table,id)));
+    }
+    else if(startswith(token, "rm")) {
+      sscanf(token, "rm.%d", &id);
+      PyTuple_SetItem(list, i, roomGetPyForm(propertyTableGet(room_table,id)));
+    }
+    else if(startswith(token, "room")) {
+      sscanf(token, "room.%d", &id);
+      PyTuple_SetItem(list, i, roomGetPyForm(propertyTableGet(room_table,id)));
+    }
+    else if(startswith(token, "ex")) {
+      sscanf(token, "ex.%d", &id);
+      PyTuple_SetItem(list, i, newPyExit(propertyTableGet(exit_table, id)));
+    }
+    else if(startswith(token, "exit")) {
+      sscanf(token, "exit.%d", &id);
+      PyTuple_SetItem(list,i, newPyExit(propertyTableGet(exit_table, id)));
+    }
+    else if(*token == HOOK_STR_MARKER) {
+      char *str = strdup(token + 1);
+      str[strlen(str)-1] = '\0';
+      PyTuple_SetItem(list,i, Py_BuildValue("s", str));
+      free(str);
+    }
+    else if(isdigit(*token)) {
+      // integer or double?
+      if(next_letter_in(token, '.') > -1)
+	PyTuple_SetItem(list, i, Py_BuildValue("d", atof(token)));
+      else
+	PyTuple_SetItem(list,i, Py_BuildValue("i", atoi(token)));
+    }
+    i++;
+  } deleteListIterator(token_i);
+  deleteListWith(tokens, free);
+
+  return list;
+}
+
+
+PyObject *PyHooks_Run(PyObject *self, PyObject *args) {
+  char *type = NULL;
+  char *info = NULL;
+  if(!PyArg_ParseTuple(args, "ss", &type, &info)) {
+    PyErr_Format(PyExc_TypeError, "A string type and info must be supplied");
+    return NULL;
+  }
+
+  // run the hook
+  hookRun(type, info);
+  return Py_BuildValue("i", 1);
+}
+
+
+PyObject *PyHooks_Add(PyObject *self, PyObject *args) {
+  char     *type = NULL;
+  PyObject *hook = NULL;
+  if(!PyArg_ParseTuple(args, "sO", &type, &hook)) {
+    PyErr_Format(PyExc_TypeError, "Must supply with a type and function");
+    return NULL;
+  }
+
+  if(!PyFunction_Check(hook)) {
+    PyErr_Format(PyExc_TypeError, "Only functions may be supplied as hooks.");
+    return NULL;
+  }
+
+  Py_INCREF(hook);
+  LIST *list = hashGet(pyhook_table, type);
+  if(list == NULL) {
+    list = newList();
+    hashPut(pyhook_table, type, list);
+  }
+  listQueue(list, hook);  
+  return Py_BuildValue("i", 1);
+}
+
+
+PyObject *PyHooks_Remove(PyObject *self, PyObject *args) {
+  char     *type = NULL;
+  PyObject *hook = NULL;
+  if(!PyArg_ParseTuple(args, "sO", &type, &hook)) {
+    PyErr_Format(PyExc_TypeError, "Must supply with a type and function");
+    return NULL;
+  }
+
+  LIST *list = hashGet(pyhook_table, type);
+  if(list != NULL && listRemove(list, hook)) {
+    Py_DECREF(hook);
+  }
+  return Py_BuildValue("i", 1);
+}
+
+
+//
+// monitors hook activity, and handles the ones on the Python end
+void PyHooks_Monitor(const char *type, const char *info) {
+  LIST *list = hashGet(pyhook_table, type);
+  if(list != NULL) {
+    char *info_dup = strdup(info);
+    LIST_ITERATOR *list_i = newListIterator(list);
+    PyObject *func = NULL;
+    ITERATE_LIST(func, list_i) {
+      PyObject *arglist = Py_BuildValue("(s)", info);
+      PyObject *retval  = PyEval_CallObject(func, arglist);
+      // check for an error:
+      if(retval == NULL) {
+	char *tb = getPythonTraceback();
+	if(tb != NULL) {
+	  log_string("Error running python hook:\r\n%s\r\n", tb);
+	  free(tb);
+	}
+      }
+
+      // garbage collection
+      Py_XDECREF(retval);
+      Py_XDECREF(arglist);
+    } deleteListIterator(list_i);
+    free(info_dup);
+  }
+}
+
+
+
+//*****************************************************************************
+// Hooks module
+//*****************************************************************************
+PyMODINIT_FUNC
+init_PyHooks(void) {
+  PyHooks_addMethod("parse_info", PyHooks_ParseInfo, METH_VARARGS,
+		    "parses a hook info string into a tuple.");
+  PyHooks_addMethod("build_info", PyHooks_BuildInfo, METH_VARARGS,
+		    "builds a hook info string out of a tuple and format.");
+  PyHooks_addMethod("run", PyHooks_Run, METH_VARARGS,
+		    "runs a hook.");
+  PyHooks_addMethod("add", PyHooks_Add, METH_VARARGS,
+		    "adds a hook.");
+  PyHooks_addMethod("remove", PyHooks_Remove, METH_VARARGS,
+		    "removes a hook");
+
+  Py_InitModule3("hooks", makePyMethods(pyhooks_methods),
+		 "The hooks module.");
+
+  // set up our hook monitor
+  pyhook_table = newHashtable();
+  hookAddMonitor(PyHooks_Monitor);
+}
+
+void PyHooks_addMethod(const char *name, void *f, int flags, const char *doc) {
+  // make sure our list of methods is created
+  if(pyhooks_methods == NULL) pyhooks_methods = newList();
+
+  // make the Method def
+  PyMethodDef *def = calloc(1, sizeof(PyMethodDef));
+  def->ml_name     = strdup(name);
+  def->ml_meth     = (PyCFunction)f;
+  def->ml_flags    = flags;
+  def->ml_doc      = (doc ? strdup(doc) : NULL);
+  listPut(pyhooks_methods, def);
+}
diff -ruN ../nakedmudv3.1/src/scripts/pyhooks.h src/scripts/pyhooks.h
--- ../nakedmudv3.1/src/scripts/pyhooks.h	Wed Dec 31 17:00:00 1969
+++ src/scripts/pyhooks.h	Sat Jul  1 20:06:58 2006
@@ -0,0 +1,23 @@
+#ifndef PYHOOKS_H
+#define PYHOOKS_H
+//*****************************************************************************
+//
+// pyhooks.h
+//
+// The wrapper around hooks for Python to interact with them.
+//
+//*****************************************************************************
+
+/* initialize mud module for use */
+PyMODINIT_FUNC
+init_PyHooks(void);
+
+//
+// Adds a new method function (i.e. void *f) to the hooks module. Name is the 
+// name of the function, f is the PyCFunction implementing the new method, 
+// flags is the type of method beings used (almost always METH_VARARGS), and 
+// doc is an (optional) description of what the method does. For examples on 
+// how to add new methods, see pyhooks.c
+void PyHooks_addMethod(const char *name, void *f, int flags, const char *doc);
+
+#endif // PYHOOKS_H
diff -ruN ../nakedmudv3.1/src/scripts/pymud.c src/scripts/pymud.c
--- ../nakedmudv3.1/src/scripts/pymud.c	Sun Dec  4 20:03:07 2005
+++ src/scripts/pymud.c	Sat Jul  1 20:06:58 2006
@@ -19,12 +19,14 @@
 #include "../character.h"
 #include "../inform.h"
 #include "../handler.h"
+#include "../parse.h"
 
 #include "scripts.h"
 #include "pyroom.h"
 #include "pychar.h"
 #include "pyobj.h"
 #include "pyplugs.h"
+#include "pyexit.h"
 
 
 
@@ -37,6 +39,9 @@
 // a list of methods to add to the mud module
 LIST *pymud_methods = NULL;
 
+// a placeholder of the movement command, as set by one of our modules
+PyObject *py_cmd_move = NULL;
+
 
 
 //*****************************************************************************
@@ -98,42 +103,6 @@
 
 
 //
-// add a new command to the mud, via a python script or module. Takes in a
-// command name, a sort_by command, the function, a minimum and maximum 
-// position in the form of strings, a level, and boolean values for whether the
-// command can be performed by mobiles, and whether it interrupts actions.
-PyObject *mud_add_cmd(PyObject *self, PyObject *args) {
-  PyObject *func = NULL;
-  char *name  = NULL, *sort_by = NULL, *min_pos = NULL, *max_pos = NULL,
-       *group = NULL;
-  bool mob_ok = FALSE, interrupts = FALSE;
-  int min_pos_num, max_pos_num;
-
-  // parse all of the values
-  if (!PyArg_ParseTuple(args, "szOsssbb", &name, &sort_by, &func,
-  			&min_pos, &max_pos, &group, &mob_ok, &interrupts)) {
-    PyErr_Format(PyExc_TypeError, 
-		 "Could not add new command. Improper arguments supplied");
-    return NULL;
-  }
-
-  // get our positions
-  min_pos_num = posGetNum(min_pos);
-  max_pos_num = posGetNum(max_pos);
-  if(min_pos_num == POS_NONE || max_pos_num == POS_NONE) {
-    PyErr_Format(PyExc_TypeError, 
-		 "Could not add new command. Invalid position names.");
-    return NULL;
-  }
-
-  // add the command to the game
-  add_py_cmd(name, sort_by, func, min_pos_num, max_pos_num,
-	     group, mob_ok, interrupts);
-  return Py_None;
-}
-
-
-//
 // format a string to be into a typical description style
 PyObject *mud_format_string(PyObject *self, PyObject *args) {
   char *string = NULL;
@@ -154,6 +123,42 @@
   return ret;
 }
 
+
+//
+// parses arguments for character commands
+PyObject *mud_parse_args(PyObject *self, PyObject *args) {
+  PyObject   *pych = NULL;
+  bool show_errors = FALSE;
+  char        *cmd = NULL;
+  char     *pyargs = NULL;
+  char     *syntax = NULL;
+  char *parse_args = NULL;
+  CHAR_DATA    *ch = NULL;
+
+  // parse our arguments
+  if(!PyArg_ParseTuple(args, "Obsss", &pych, &show_errors, 
+		       &cmd, &pyargs, &syntax)) {
+    PyErr_Format(PyExc_TypeError, "Invalid arguments to parse_args");
+    return NULL;
+  }
+
+  // convert the character
+  if(!PyChar_Check(pych) || (ch = PyChar_AsChar(pych)) == NULL) {
+      PyErr_Format(PyExc_TypeError, 
+		   "First argument must be an existent character!");
+      return NULL;
+  }
+
+  // strdup our py args; they might be edited in the parse function
+  parse_args = strdup(pyargs);
+
+  // finish up and garbage collections
+  PyObject *retval = Py_parse_args(ch, show_errors, cmd, parse_args, syntax);
+  free(parse_args);
+  return retval;
+}
+
+
 //
 // a wrapper around NakedMud's generic_find() function
 PyObject *mud_generic_find(PyObject *self, PyObject *args) {
@@ -201,8 +206,13 @@
     SET_BIT(type, FIND_TYPE_OBJ);
   if(is_keyword(type_str, "char", FALSE))
     SET_BIT(type, FIND_TYPE_CHAR);
+  if(is_keyword(type_str, "exit", FALSE))
+    SET_BIT(type, FIND_TYPE_EXIT);
   if(is_keyword(type_str, "in", FALSE))
     SET_BIT(type, FIND_TYPE_IN_OBJ);
+  if(is_keyword(type_str, "all", FALSE))
+    SET_BIT(type,FIND_TYPE_OBJ  | FIND_TYPE_CHAR | 
+	         FIND_TYPE_EXIT | FIND_TYPE_IN_OBJ);
 
   // do the search
   int found_type = FOUND_NONE;
@@ -215,6 +225,17 @@
     else
       return Py_BuildValue("Os", charGetPyFormBorrowed(found), "char");
   }
+  else if(found_type == FOUND_EXIT) {
+    // were we searching for one type, or multiple types?
+    PyObject   *exit = newPyExit(found);
+    PyObject *retval = NULL;
+    if(!strcasecmp("exit", type_str))
+      retval = Py_BuildValue("O", exit);
+    else
+      retval = Py_BuildValue("Os", exit, "obj");
+    Py_DECREF(exit);
+    return retval;
+  }
   else if(found_type == FOUND_OBJ) {
     // were we searching for one type, or multiple types?
     if(!strcasecmp("obj", type_str))
@@ -316,6 +337,8 @@
     SET_BIT(range, TO_VICT);
   if(is_keyword(pyrange, "to_room", FALSE))
     SET_BIT(range, TO_ROOM);
+  if(is_keyword(pyrange, "to_world", FALSE))
+    SET_BIT(range, TO_WORLD);
 
   // finally, send out the message
   message(ch, vict, obj, vobj, hide_nosee, range, mssg);
@@ -400,6 +423,46 @@
   return Py_BuildValue("i", ok);
 }
 
+//
+// returns the mud's message of the day
+PyObject *mud_get_motd(PyObject *self, PyObject *args) {
+  return Py_BuildValue("s", bufferString(motd));
+}
+
+PyObject *mud_log_string(PyObject *self, PyObject *args) {
+  char *mssg = NULL;
+  if(!PyArg_ParseTuple(args, "s", &mssg)) {
+    PyErr_Format(PyExc_TypeError, "a message must be supplied to log_string");
+    return NULL;
+  }
+
+  // we have to strip all %'s out of this message
+  BUFFER *buf = newBuffer(1);
+  bufferCat(buf, mssg);
+  bufferReplace(buf, "%", "%%", TRUE);
+  log_string(bufferString(buf));
+  deleteBuffer(buf);
+  return Py_BuildValue("i", 1);
+}
+
+PyObject *mud_set_cmd_move(PyObject *self, PyObject *args) {
+  PyObject *cmd = NULL;
+  if(!PyArg_ParseTuple(args, "O", &cmd)) {
+    PyErr_Format(PyExc_TypeError, "a command must be suppled");
+    return NULL;
+  }
+
+  // make sure it's a function
+  if(!PyFunction_Check(cmd)) {
+    PyErr_Format(PyExc_TypeError, "a command must be suppled");
+    return NULL;
+  }
+
+  Py_XDECREF(py_cmd_move);
+  py_cmd_move = cmd;
+  return Py_BuildValue("i", 1);
+}
+
 
 
 //*****************************************************************************
@@ -428,8 +491,6 @@
 		  "Set the value of a global variable.");
   PyMud_addMethod("erase_global",  mud_erase_global, METH_VARARGS,
 		  "Erase the value of a global variable.");
-  PyMud_addMethod("add_cmd", mud_add_cmd, METH_VARARGS,
-		  "Add a new command to the game.");
   PyMud_addMethod("message", mud_message, METH_VARARGS,
 		  "plugs into the message() function from inform.h");
   PyMud_addMethod("format_string", mud_format_string, METH_VARARGS,
@@ -446,10 +507,22 @@
 		  "arguments (condition, if action) and an optional third "
 		  "(else action). If no else action is specified and the "
 		  "condition is false, None is returned.");
+  PyMud_addMethod("parse_args", mud_parse_args, METH_VARARGS,
+		  "equivalent to parse_args written in C");
+  PyMud_addMethod("get_motd", mud_get_motd, METH_VARARGS,
+		  "returns the mud's message of the day");
+  PyMud_addMethod("log_string", mud_log_string, METH_VARARGS,
+		  "adds a string to the mudlog");
+  PyMud_addMethod("set_cmd_move", mud_set_cmd_move, METH_VARARGS,
+		  "sets the movement command");
 
   Py_InitModule3("mud", makePyMethods(pymud_methods),
 		 "The mud module, for all MUD misc mud utils.");
 
   globals = PyDict_New();
   Py_INCREF(globals);
+}
+
+void *get_cmd_move(void) {
+  return py_cmd_move;
 }
diff -ruN ../nakedmudv3.1/src/scripts/pymud.h src/scripts/pymud.h
--- ../nakedmudv3.1/src/scripts/pymud.h	Sun Dec  4 20:03:07 2005
+++ src/scripts/pymud.h	Sat Jul  1 20:06:58 2006
@@ -22,4 +22,8 @@
 // new methods, see pymud.c
 void PyMud_addMethod(const char *name, void *f, int flags, const char *doc);
 
+//
+// returns the current defined cmd_move
+void *get_cmd_move(void);
+
 #endif //__PYMUD_H
diff -ruN ../nakedmudv3.1/src/scripts/pymudsys.c src/scripts/pymudsys.c
--- ../nakedmudv3.1/src/scripts/pymudsys.c	Wed Dec 31 17:00:00 1969
+++ src/scripts/pymudsys.c	Sat Jul  1 20:06:58 2006
@@ -0,0 +1,254 @@
+//*****************************************************************************
+//
+// pymudsys.c
+//
+// A set of system level commands and variables that may be needed by python,
+// but which are not neccessarily needed by scripts.
+//
+//*****************************************************************************
+#include <Python.h>
+#include <structmember.h>
+
+#include "../mud.h"
+#include "../utils.h"
+#include "../character.h"
+#include "../socket.h"
+#include "../save.h"
+
+#include "pymudsys.h"
+#include "scripts.h"
+#include "pyplugs.h"
+#include "pychar.h"
+
+
+
+//*****************************************************************************
+// local variables and functions
+//*****************************************************************************
+// a list of methods to add to the mudsys module
+LIST *pymudsys_methods = NULL;
+
+
+
+//*****************************************************************************
+// mudsys methods
+//*****************************************************************************
+PyObject *mudsys_set_sys_val(PyObject *self, PyObject *args) {
+  char *key, *val;
+  if(!PyArg_ParseTuple(args, "ss", &key, &val)) {
+    PyErr_Format(PyExc_TypeError, "Provide a string key and value");
+    return NULL;
+  }
+
+  mudsettingSetString(key, val);
+  return Py_BuildValue("i", 1);
+}
+
+PyObject *mudsys_get_sys_val(PyObject *self, PyObject *args) {
+  char *key;
+  if(!PyArg_ParseTuple(args, "s", &key)) {
+    PyErr_Format(PyExc_TypeError, "Provide a string key");
+    return NULL;
+  }
+
+  return Py_BuildValue("s", mudsettingGetString(key));
+}
+
+PyObject *mudsys_shutdown(PyObject *self, PyObject *args) {
+  shut_down = TRUE;
+  return Py_BuildValue("i", 1);
+}
+
+PyObject *mudsys_copyover(PyObject *self, PyObject *args) {
+  do_copyover();
+  return Py_BuildValue("i", 1);
+}
+
+//
+// saves a player to disk
+PyObject *mudsys_do_save(PyObject *self, PyObject *args) {
+  PyObject *pych = NULL;
+  CHAR_DATA  *ch = NULL;
+
+  if(!PyArg_ParseTuple(args, "O", &pych)) {
+    PyErr_Format(PyExc_TypeError, "A character to be saved must be supplied.");
+    return NULL;
+  }
+
+  if(!PyChar_Check(pych)) {
+    PyErr_Format(PyExc_TypeError, "Only characters may be saved.");
+    return NULL;
+  }
+
+  if( (ch = PyChar_AsChar(pych)) == NULL) {
+    PyErr_Format(PyExc_StandardError,
+		 "Tried to save nonexistant character, %d.",PyChar_AsUid(pych));
+    return NULL;
+  }
+
+  if(!charIsNPC(ch))
+    save_player(ch);
+  return Py_BuildValue("i", 1);
+}
+
+
+//
+// quits a character from the game
+PyObject *mudsys_do_quit(PyObject *self, PyObject *args) {
+  PyObject *pych = NULL;
+  CHAR_DATA  *ch = NULL;
+
+  if(!PyArg_ParseTuple(args, "O", &pych)) {
+    PyErr_Format(PyExc_TypeError,"A character to be quitted must be supplied.");
+    return NULL;
+  }
+
+  if(!PyChar_Check(pych)) {
+    PyErr_Format(PyExc_TypeError, "Only characters may be quitted.");
+    return NULL;
+  }
+
+  if( (ch = PyChar_AsChar(pych)) == NULL) {
+    PyErr_Format(PyExc_StandardError,
+		 "Tried to quit nonexistant character, %d.",PyChar_AsUid(pych));
+    return NULL;
+  }
+
+  if(!charIsNPC(ch) && charGetSocket(ch)) {
+    SOCKET_DATA *sock = charGetSocket(ch);
+    charSetSocket(ch, NULL);
+    socketSetChar(sock, NULL);
+    socketPopInputHandler(sock);
+    extract_mobile(ch);
+  }
+
+  return Py_BuildValue("i", 1);
+}
+
+
+//
+// disconnects a character from its socket
+PyObject *mudsys_do_disconnect(PyObject *self, PyObject *args) {
+  PyObject *pych = NULL;
+  CHAR_DATA  *ch = NULL;
+
+  if(!PyArg_ParseTuple(args, "O", &pych)) {
+    PyErr_Format(PyExc_TypeError,"A character to be dc'd must be supplied.");
+    return NULL;
+  }
+
+  if(!PyChar_Check(pych)) {
+    PyErr_Format(PyExc_TypeError, "Only characters may be dc'd.");
+    return NULL;
+  }
+
+  if( (ch = PyChar_AsChar(pych)) == NULL) {
+    PyErr_Format(PyExc_StandardError,
+		 "Tried to dc nonexistant character, %d.",PyChar_AsUid(pych));
+    return NULL;
+  }
+
+  if(charGetSocket(ch)) {
+    SOCKET_DATA *sock = charGetSocket(ch);
+    charSetSocket(ch, NULL);
+    socketSetChar(sock, NULL);
+    close_socket(sock, FALSE);
+  }
+
+  return Py_BuildValue("i", 1);
+}
+
+
+//
+// add a new command to the mud, via a python script or module. Takes in a
+// command name, a sort_by command, the function, a minimum and maximum 
+// position in the form of strings, a level, and boolean values for whether the
+// command can be performed by mobiles, and whether it interrupts actions.
+PyObject *mudsys_add_cmd(PyObject *self, PyObject *args) {
+  PyObject *func = NULL;
+  char *name  = NULL, *sort_by = NULL, *min_pos = NULL, *max_pos = NULL,
+       *group = NULL;
+  bool mob_ok = FALSE, interrupts = FALSE;
+  int min_pos_num, max_pos_num;
+
+  // parse all of the values
+  if (!PyArg_ParseTuple(args, "szOsssbb", &name, &sort_by, &func,
+  			&min_pos, &max_pos, &group, &mob_ok, &interrupts)) {
+    PyErr_Format(PyExc_TypeError, 
+		 "Could not add new command. Improper arguments supplied");
+    return NULL;
+  }
+
+  // get our positions
+  min_pos_num = posGetNum(min_pos);
+  max_pos_num = posGetNum(max_pos);
+  if(min_pos_num == POS_NONE || max_pos_num == POS_NONE) {
+    PyErr_Format(PyExc_TypeError, 
+		 "Could not add new command. Invalid position names.");
+    return NULL;
+  }
+
+  // add the command to the game
+  add_py_cmd(name, sort_by, func, min_pos_num, max_pos_num,
+	     group, mob_ok, interrupts);
+  return Py_None;
+}
+
+
+//
+// removes a command from the game
+PyObject *mudsys_remove_cmd(PyObject *self, PyObject *args) {
+  char *name = NULL;
+  // parse all of the values
+  if (!PyArg_ParseTuple(args, "s", &name)) {
+    PyErr_Format(PyExc_TypeError, "function requires string argument.");
+    return NULL;
+  }
+  remove_cmd(name);
+  return Py_None;
+}
+
+
+
+//*****************************************************************************
+// MudSys module
+//*****************************************************************************
+void PyMudSys_addMethod(const char *name, void *f, int flags, const char *doc) {
+  // make sure our list of methods is created
+  if(pymudsys_methods == NULL) pymudsys_methods = newList();
+
+  // make the Method def
+  PyMethodDef *def = calloc(1, sizeof(PyMethodDef));
+  def->ml_name     = strdup(name);
+  def->ml_meth     = (PyCFunction)f;
+  def->ml_flags    = flags;
+  def->ml_doc      = (doc ? strdup(doc) : NULL);
+  listPut(pymudsys_methods, def);
+}
+
+
+PyMODINIT_FUNC
+init_PyMudSys(void) {
+  // add all of our methods
+  PyMudSys_addMethod("do_shutdown", mudsys_shutdown, METH_VARARGS,
+		     "shuts the mud down.");
+  PyMudSys_addMethod("do_copyover", mudsys_copyover, METH_VARARGS,
+		     "performs a copyover on the mud.");
+  PyMudSys_addMethod("sys_setval", mudsys_set_sys_val, METH_VARARGS,
+		     "sets a system value on the mud.");
+  PyMudSys_addMethod("sys_getval", mudsys_get_sys_val, METH_VARARGS,
+		     "returns a system value on the mud.");
+  PyMudSys_addMethod("do_save", mudsys_do_save, METH_VARARGS,
+		     "save a character to disk");
+  PyMudSys_addMethod("do_quit", mudsys_do_quit, METH_VARARGS,
+		     "quit a character from game");
+  PyMudSys_addMethod("do_disconnect", mudsys_do_disconnect, METH_VARARGS,
+		     "disconnects a character from its socket");
+  PyMudSys_addMethod("add_cmd", mudsys_add_cmd, METH_VARARGS,
+		     "Add a new command to the game.");
+  PyMudSys_addMethod("remove_cmd", mudsys_remove_cmd, METH_VARARGS,
+		     "Removes a command from the game.");
+
+  Py_InitModule3("mudsys", makePyMethods(pymudsys_methods),
+		 "The mudsys module, for all MUD system utils.");
+}
diff -ruN ../nakedmudv3.1/src/scripts/pymudsys.h src/scripts/pymudsys.h
--- ../nakedmudv3.1/src/scripts/pymudsys.h	Wed Dec 31 17:00:00 1969
+++ src/scripts/pymudsys.h	Sat Jul  1 20:06:58 2006
@@ -0,0 +1,24 @@
+#ifndef __PYMUDSYS_H
+#define __PYMUDSYS_H
+//*****************************************************************************
+//
+// pymudsys.h
+//
+// A set of system level commands and variables that may be needed by python,
+// but which are not neccessarily needed by scripts.
+//
+//*****************************************************************************
+
+/* initialize mud sys module for use */
+PyMODINIT_FUNC
+init_PyMudSys(void);
+
+//
+// Adds a new method function (i.e. void *f) to the sys module. Name is the name
+// of the function, f is the PyCFunction implementing the new method, flags is
+// the type of method beings used (almost always METH_VARARGS), and doc is an
+// (optional) description of what the method does. For examples on how to add
+// new methods, see pymud.c
+void PyMudSys_addMethod(const char *name, void *f, int flags, const char *doc);
+
+#endif //__PYMUD_H
diff -ruN ../nakedmudv3.1/src/scripts/pyobj.c src/scripts/pyobj.c
--- ../nakedmudv3.1/src/scripts/pyobj.c	Sun Dec  4 20:03:07 2005
+++ src/scripts/pyobj.c	Sat Jul  1 20:06:58 2006
@@ -162,6 +162,13 @@
   else            return NULL;
 }
 
+
+PyObject *PyObj_get_weight_raw(PyObj *self, void *closure) {
+  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
+  if(obj != NULL) return Py_BuildValue("d", objGetWeightRaw(obj));
+  else            return NULL;
+}
+
 PyObject *PyObj_getcontents(PyObj *self, PyObject *args) {
   OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
   if(obj == NULL) 
@@ -564,9 +571,19 @@
 
   // pull out the object and check the type
   OBJ_DATA    *obj = PyObj_AsObj((PyObject *)self);
-  if(obj != NULL)
-    return Py_BuildValue("i", 
-        objIsInstance(obj, get_fullkey_relative(type, get_script_locale())));
+  if(obj != NULL) {
+    PyObject *retval = NULL;
+    char     *locale = NULL;
+    if(get_script_locale())
+      locale = strdup(get_script_locale());
+    else
+      locale = strdup(get_key_locale(objGetClass(obj)));
+
+    retval = 
+      Py_BuildValue("i", objIsInstance(obj, get_fullkey_relative(type,locale)));
+    free(locale);
+    return retval;
+  }
   else {
     PyErr_Format(PyExc_StandardError, 
 		 "Tried to check instances of nonexistent object, %d.", self->uid);
@@ -1006,6 +1023,8 @@
     PyObj_addGetSetter("keywords", PyObj_getkeywords, PyObj_setkeywords,
 		       "the object's keywords");
     PyObj_addGetSetter("weight", PyObj_getweight, PyObj_setweight,
+		       "the object's weight (plus contents)");
+    PyObj_addGetSetter("weight_raw", PyObj_get_weight_raw, NULL,
 		       "the object's weight (minus contents)");
     PyObj_addGetSetter("uid", PyObj_getuid, NULL,
 		       "the object's unique identification number");
diff -ruN ../nakedmudv3.1/src/scripts/pyplugs.c src/scripts/pyplugs.c
--- ../nakedmudv3.1/src/scripts/pyplugs.c	Sun Dec  4 20:03:07 2005
+++ src/scripts/pyplugs.c	Sat Jul  1 20:06:58 2006
@@ -65,6 +65,27 @@
   }
   // no errors occured... load the module into our package
   else {
+    // we need to run an unload function if the module has been loaded before
+    PyObject *old_mod = PyImport_ImportModule(mname);
+    if(old_mod != NULL) {
+      PyObject *dict = PyModule_GetDict(old_mod);
+      
+      // if the module has an __unload__ function, call it
+      if(PyDict_GetItemString(dict, "__unload__") != NULL) {
+	PyObject *tbList = PyObject_CallMethod(old_mod, "__unload__", "");
+
+	// encountered an error with the unload function
+	if(tbList == NULL) {
+	  char *tb = getPythonTraceback();
+	  log_string("Encountered error in %s.__unload__():\r\n"
+		     "\r\nTraceback is:\r\n%s\r\n", mname, tb);
+	  free(tb);
+	}
+	Py_XDECREF(tbList);
+      }
+      Py_XDECREF(old_mod);
+    }
+
     PyObject *module = PyImport_ExecCodeModule(mname, code);
     if(module == NULL) {
       char *tb = getPythonTraceback();
diff -ruN ../nakedmudv3.1/src/scripts/pyroom.c src/scripts/pyroom.c
--- ../nakedmudv3.1/src/scripts/pyroom.c	Sun Dec  4 20:03:07 2005
+++ src/scripts/pyroom.c	Sat Jul  1 20:06:58 2006
@@ -28,6 +28,7 @@
 #include "pyobj.h"
 #include "pyexit.h"
 #include "pyroom.h"
+#include "pymud.h"
 
 
 
@@ -368,6 +369,42 @@
 
 
 //
+// Returns the direction of the exit
+PyObject *PyRoom_get_exit_dir(PyObject *self, PyObject *args) {
+  ROOM_DATA *room = NULL;
+  EXIT_DATA *exit = NULL;
+  PyObject  *pyex = NULL;
+
+  if (!PyArg_ParseTuple(args, "O", &pyex)) {
+    PyErr_Format(PyExc_TypeError, "Exit must be supplied.");
+    return NULL;
+  }
+
+  if((room = PyRoom_AsRoom((PyObject *)self)) == NULL) {
+    PyErr_Format(PyExc_TypeError, "Tried to get exit dir of nonexistent room"
+		 ", %d.", PyRoom_AsUid(self));
+    return NULL;
+  }
+
+  // get the exit
+  if(!PyExit_Check(pyex)) {
+    PyErr_Format(PyExc_TypeError, "an exit must be supplied to exdir");
+    return NULL;
+  }
+
+  // make sure the exit exists
+  exit = PyExit_AsExit(pyex);
+  if(exit == NULL) {
+    PyErr_Format(PyExc_StandardError, "Tried to get direction of nonexistant "
+		 "exit, %d.", PyExit_AsUid(pyex));
+    return NULL;
+  }
+
+  return Py_BuildValue("s", roomGetExitDir(room, exit));
+}
+
+
+//
 // Fills an exit in the given direction
 PyObject *PyRoom_fill(PyRoom *self, PyObject *value) {
   ROOM_DATA *room = NULL;
@@ -425,7 +462,7 @@
 
   // make sure we have a valid destination
   if(PyString_Check(py_dest))
-    dest = get_fullkey(PyString_AsString(py_dest), get_script_locale());
+    dest = get_fullkey_relative(PyString_AsString(py_dest),get_script_locale());
   else if(PyRoom_Check(py_dest)) {
     ROOM_DATA *to_room = PyRoom_AsRoom(py_dest);
     if(to_room != NULL)
@@ -463,9 +500,9 @@
     roomSetExit(room, cdir, exit);
 
     // if we're digging a special exit, add a cmd for it to the room cmd table
-    if(dir_num == DIR_NONE && dir_abbrev_num == DIR_NONE)
+    if(get_cmd_move() && dir_num == DIR_NONE && dir_abbrev_num == DIR_NONE)
       nearMapPut(roomGetCmdTable(room), cdir, NULL,
-		 newCmd(cdir, cmd_move, POS_STANDING, POS_FLYING, 
+		 newPyCmd(cdir, get_cmd_move(), POS_STANDING, POS_FLYING, 
 			"player", TRUE, TRUE));
   }
 
@@ -721,6 +758,8 @@
 		     "fills in direction for the room.");
     PyRoom_addMethod("exit", PyRoom_get_exit, METH_VARARGS,
 		     "gets an exit in the room with the given direction name.");
+    PyRoom_addMethod("exdir", PyRoom_get_exit_dir, METH_VARARGS,
+		     "returns the direction of the exit.");
     PyRoom_addMethod("send", PyRoom_send, METH_VARARGS,
 		     "send a message to everyone in the room.");
     PyRoom_addMethod("edesc", PyRoom_edesc, METH_VARARGS,
diff -ruN ../nakedmudv3.1/src/scripts/scripts.c src/scripts/scripts.c
--- ../nakedmudv3.1/src/scripts/scripts.c	Sun Dec  4 20:39:05 2005
+++ src/scripts/scripts.c	Sat Jul  1 20:06:58 2006
@@ -31,6 +31,8 @@
 #include "pyexit.h"
 #include "pyobj.h"
 #include "pymud.h"
+#include "pymudsys.h"
+#include "pyhooks.h"
 #include "pyevent.h"
 #include "pystorage.h"
 #include "pyauxiliary.h"
@@ -125,39 +127,55 @@
 // a local variable used for storing whether or not the last script ran fine
 bool script_ok = TRUE;
 
-void expand_char_dynamic_descs(BUFFER *desc, CHAR_DATA *me, CHAR_DATA *ch) {
+void expand_char_dynamic_descs(const char *info) {
+  CHAR_DATA *me = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &me, &ch);
+
   // if we're an NPC, do some special work for displaying us. We don't do 
   // dynamic descs for PCs because they will probably be describing themselves,
   // and we don't want to give them access to the scripting language.
   if(charIsNPC(me)) {
     PyObject *pyme = charGetPyForm(me);
     char   *locale = strdup(get_key_locale(charGetClass(me))); 
-    expand_dynamic_descs(desc, pyme, ch, locale);
+    expand_dynamic_descs(charGetLookBuffer(ch), pyme, ch, locale);
     Py_DECREF(pyme);
     free(locale);
   }
 }
 
-void  expand_obj_dynamic_descs(BUFFER *desc, OBJ_DATA *me, CHAR_DATA *ch) {
+void  expand_obj_dynamic_descs(const char *info) {
+  OBJ_DATA  *me = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &me, &ch);
+
   PyObject *pyme = objGetPyForm(me);
   char   *locale = strdup(get_key_locale(objGetClass(me))); 
-  expand_dynamic_descs(desc, pyme, ch, locale);
+  expand_dynamic_descs(charGetLookBuffer(ch), pyme, ch, locale);
   Py_DECREF(pyme);
   free(locale);
 }
 
-void expand_room_dynamic_descs(BUFFER *desc, ROOM_DATA *me, CHAR_DATA *ch) {
+void expand_room_dynamic_descs(const char *info) {
+  ROOM_DATA *me = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &me, &ch);
+
   PyObject *pyme = roomGetPyForm(me);
   char   *locale = strdup(get_key_locale(roomGetClass(me))); 
-  expand_dynamic_descs(desc, pyme, ch, locale);
+  expand_dynamic_descs(charGetLookBuffer(ch), pyme, ch, locale);
   Py_DECREF(pyme);
   free(locale);
 }
 
-void expand_exit_dynamic_descs(BUFFER *desc, EXIT_DATA *me, CHAR_DATA *ch) {
+void expand_exit_dynamic_descs(const char *info) {
+  EXIT_DATA *me = NULL;
+  CHAR_DATA *ch = NULL;
+  hookParseInfo(info, &me, &ch);
+
   PyObject *pyme = newPyExit(me);
   char   *locale = strdup(get_key_locale(roomGetClass(exitGetRoom(me)))); 
-  expand_dynamic_descs(desc, pyme, ch, locale);
+  expand_dynamic_descs(charGetLookBuffer(ch), pyme, ch, locale);
   Py_DECREF(pyme);
   free(locale);
 }
@@ -166,6 +184,10 @@
   Py_Finalize();
 }
 
+void finalize_scripts_hook(const char *info) {
+  finalize_scripts();
+}
+
 
 
 //*****************************************************************************
@@ -312,6 +334,7 @@
   Py_Initialize();
 
   // initialize all of our modules written in C
+  init_PyMudSys();
   init_PyAuxiliary();
   init_PyEvent();
   init_PyStorage();
@@ -320,6 +343,7 @@
   init_PyExit();
   init_PyObj();
   init_PyMud();
+  init_PyHooks();
 
   // initialize all of our modules written in Python
   init_pyplugs();
@@ -345,7 +369,7 @@
   hookAdd("preprocess_char_desc", expand_char_dynamic_descs);
   hookAdd("preprocess_obj_desc",  expand_obj_dynamic_descs);
   hookAdd("preprocess_exit_desc", expand_exit_dynamic_descs);
-  hookAdd("shutdown",             finalize_scripts);
+  hookAdd("shutdown", finalize_scripts_hook);
 
   /*
   // add new player commands
@@ -769,6 +793,19 @@
   PyObject *pyform = roomGetPyFormBorrowed(room);
   Py_INCREF(pyform);
   return pyform;
+}
+
+PyObject *PyList_fromList(LIST *list, void *convertor) {
+  PyObject *pylist = PyList_New(0);
+  PyObject *(*conv_func)(void *) = convertor; 
+  LIST_ITERATOR *list_i = newListIterator(list);
+  void            *elem = NULL;
+  ITERATE_LIST(elem, list_i) {
+    PyObject *pyelem = conv_func(elem);
+    PyList_Append(pylist, pyelem);
+    Py_DECREF(pyelem);
+  } deleteListIterator(list_i);
+  return pylist;
 }
 
 void triggerListAdd(LIST *list, const char *trigger) {
diff -ruN ../nakedmudv3.1/src/scripts/scripts.h src/scripts/scripts.h
--- ../nakedmudv3.1/src/scripts/scripts.h	Sun Dec  4 20:39:05 2005
+++ src/scripts/scripts.h	Sat Jul  1 20:06:58 2006
@@ -97,6 +97,10 @@
 PyObject  *objGetPyFormBorrowed(OBJ_DATA  *obj);
 
 //
+// returns a Python form of the given list
+PyObject *PyList_fromList(LIST *list, void *convertor);
+
+//
 // adds a trigger to the trigger list. Makes sure it's not a duplicate copy
 void triggerListAdd(LIST *list, const char *trigger);
 
diff -ruN ../nakedmudv3.1/src/scripts/trighooks.c src/scripts/trighooks.c
--- ../nakedmudv3.1/src/scripts/trighooks.c	Sun Dec  4 20:03:07 2005
+++ src/scripts/trighooks.c	Sat Jul  1 20:06:58 2006
@@ -285,23 +285,40 @@
 //*****************************************************************************
 // trighooks
 //*****************************************************************************
-void do_give_trighooks(CHAR_DATA *ch, CHAR_DATA *recv, OBJ_DATA *obj) {
+void do_give_trighooks(const char *info) {
+  CHAR_DATA   *ch = NULL;
+  CHAR_DATA *recv = NULL;
+  OBJ_DATA   *obj = NULL;
+  hookParseInfo(info, &ch, &recv, &obj);
+
   do_char_trigs(ch,   "give",    recv, obj);
   do_char_trigs(recv, "receive", ch,   obj);
   do_obj_trigs (obj,  "give",    ch,  recv);
 }
 
-void do_get_trighooks(CHAR_DATA *ch, OBJ_DATA *obj) {
+void do_get_trighooks(const char *info) {
+  CHAR_DATA *ch = NULL;
+  OBJ_DATA *obj = NULL;
+  hookParseInfo(info, &ch, &obj);
+
   do_obj_trigs (obj,             "get", ch, NULL);
   do_room_trigs(charGetRoom(ch), "get", ch, obj);
 }
 
-void do_drop_trighooks(CHAR_DATA *ch, OBJ_DATA *obj) {
+void do_drop_trighooks(const char *info) {
+  CHAR_DATA *ch = NULL;
+  OBJ_DATA *obj = NULL;
+  hookParseInfo(info, &ch, &obj);
+
   do_obj_trigs (obj,             "drop", ch, NULL);
   do_room_trigs(charGetRoom(ch), "drop", ch,  obj);
 }
 
-void do_enter_trighooks(CHAR_DATA *ch, ROOM_DATA *room) {
+void do_enter_trighooks(const char *info) {
+  CHAR_DATA   *ch = NULL;
+  ROOM_DATA *room = NULL;
+  hookParseInfo(info, &ch, &room);
+
   LIST_ITERATOR *mob_i = newListIterator(roomGetCharacters(room));
   CHAR_DATA       *mob = NULL;
   ITERATE_LIST(mob, mob_i) {
@@ -311,7 +328,12 @@
   do_room_trigs(room, "enter", ch, NULL);
 }
 
-void do_exit_trighooks(CHAR_DATA *ch, ROOM_DATA *room, EXIT_DATA *exit) {
+void do_exit_trighooks(const char *info) {
+  CHAR_DATA   *ch = NULL;
+  ROOM_DATA *room = NULL;
+  EXIT_DATA *exit = NULL;
+  hookParseInfo(info, &ch, &room, &exit);
+
   LIST_ITERATOR *mob_i = newListIterator(roomGetCharacters(room));
   CHAR_DATA       *mob = NULL;
   ITERATE_LIST(mob, mob_i) {
@@ -322,11 +344,20 @@
   do_char_trigs(ch,   "move", exit, NULL);
 }
 
-void do_ask_trighooks(CHAR_DATA *ch, CHAR_DATA *listener, char *speech) {
+void do_ask_trighooks(const char *info) {
+  CHAR_DATA       *ch = NULL;
+  CHAR_DATA *listener = NULL;
+  char        *speech = NULL;
+  hookParseInfo(info, &ch, &listener, &speech);
   do_char_trigs(listener, "speech", ch, speech);
+  if(speech) free(speech);
 }
 
-void do_say_trighooks(CHAR_DATA *ch, char *speech) {
+void do_say_trighooks(const char *info) {
+  CHAR_DATA *ch = NULL;
+  char  *speech = NULL;
+  hookParseInfo(info, &ch, &speech);
+
   LIST_ITERATOR *mob_i = newListIterator(roomGetCharacters(charGetRoom(ch)));
   CHAR_DATA       *mob = NULL;
   ITERATE_LIST(mob, mob_i) {
@@ -334,23 +365,41 @@
       do_char_trigs(mob, "speech", ch, speech);
   } deleteListIterator(mob_i);
   do_room_trigs(charGetRoom(ch), "speech", ch, speech);
+  if(speech) free(speech);
 }
 
-void do_greet_trighooks(CHAR_DATA *ch, CHAR_DATA *greeted) {
+void do_greet_trighooks(const char *info) {
+  CHAR_DATA      *ch = NULL;
+  CHAR_DATA *greeted = NULL;
+  hookParseInfo(info, &ch, &greeted);
   do_char_trigs(greeted, "greet", ch, NULL);
 }
 
-void do_wear_trighooks(CHAR_DATA *ch, OBJ_DATA *obj) {
+void do_wear_trighooks(const char *info) {
+  CHAR_DATA *ch = NULL;
+  OBJ_DATA *obj = NULL;
+  hookParseInfo(info, &ch, &obj);
+  printf("%s\r\n", info);
+  printf("%s %s\r\n", charGetName(ch), objGetName(obj));
+
   do_char_trigs(ch,  "wear", obj, NULL);
   do_obj_trigs (obj, "wear", ch,  NULL);
 }
 
-void do_remove_trighooks(CHAR_DATA *ch, OBJ_DATA *obj) {
+void do_remove_trighooks(const char *info) {
+  CHAR_DATA *ch = NULL;
+  OBJ_DATA *obj = NULL;
+  hookParseInfo(info, &ch, &obj);
   do_char_trigs(ch,  "remove", obj, NULL);
   do_obj_trigs (obj, "remove", ch,  NULL);
 }
 
-void do_reset_trighooks(ZONE_DATA *zone) {
+void do_reset_trighooks(const char *info) {
+  char  *zone_key = NULL;
+  hookParseInfo(info, &zone_key);
+  ZONE_DATA *zone = worldGetZone(gameworld, zone_key);
+  free(zone_key);
+
   LIST_ITERATOR *res_i = newListIterator(zoneGetResettable(zone));
   char           *name = NULL;
   const char   *locale = zoneGetKey(zone);
@@ -361,11 +410,17 @@
   } deleteListIterator(res_i);
 }
 
-void do_open_door_trighooks(CHAR_DATA *ch, EXIT_DATA *ex) {
+void do_open_door_trighooks(const char *info) {
+  CHAR_DATA *ch = NULL;
+  EXIT_DATA *ex = NULL;
+  hookParseInfo(info, &ch, &ex);
   do_room_trigs(charGetRoom(ch), "open", ch, ex);
 }
 
-void do_open_obj_trighooks(CHAR_DATA *ch, OBJ_DATA *obj) {
+void do_open_obj_trighooks(const char *info) {
+  CHAR_DATA *ch = NULL;
+  OBJ_DATA *obj = NULL;
+  hookParseInfo(info, &ch, &obj);
   do_obj_trigs(obj, "open", ch, NULL);
 }
 
diff -ruN ../nakedmudv3.1/src/socket.c src/socket.c
--- ../nakedmudv3.1/src/socket.c	Sun Dec  4 20:03:08 2005
+++ src/socket.c	Sat Jul  1 20:06:58 2006
@@ -1114,7 +1114,7 @@
 }
 
 
-void do_copyover(CHAR_DATA *ch) {
+void do_copyover(void) {
   LIST_ITERATOR *sock_i = newListIterator(socket_list);
   SOCKET_DATA     *sock = NULL;
   FILE *fp;
@@ -1122,16 +1122,11 @@
   char control_buf[20];
   char port_buf[20];
 
-  if ((fp = fopen(COPYOVER_FILE, "w+")) == NULL) {
-    text_to_char(ch, "Copyover file not writeable, aborted.\n\r");
+  if ((fp = fopen(COPYOVER_FILE, "w+")) == NULL)
     return;
-  }
 
   sprintf(buf, "\n\r <*>            The world starts spinning             <*>\n\r");
 
-  // execute our shutdown hooks
-  hookRun("shutdown");
-
   // For each playing descriptor, save its character and account
   ITERATE_LIST(sock, sock_i) {
     compressEnd(sock, sock->compressing, FALSE);
@@ -1158,13 +1153,15 @@
   // close any pending sockets
   recycle_sockets();
 
+#ifdef MODULE_WEBSERVER
+  // if we have a webserver set up, finalize that
+  finalize_webserver();
+#endif
+  
   // exec - descriptors are inherited
   sprintf(control_buf, "%d", control);
   sprintf(port_buf, "%d", mudport);
   execl(EXE_FILE, "NakedMud", "-copyover", control_buf, port_buf, NULL);
-
-  // Failed - sucessful exec will not return
-  text_to_char(ch, "Copyover FAILED!\n\r");
 }
 
 
diff -ruN ../nakedmudv3.1/src/socket.h src/socket.h
--- ../nakedmudv3.1/src/socket.h	Sun Dec  4 20:03:08 2005
+++ src/socket.h	Sat Jul  1 20:06:58 2006
@@ -12,7 +12,7 @@
 bool  read_from_socket      ( SOCKET_DATA *dsock );
 void  socket_handler        ( void );
 void  copyover_recover      ( void );
-void  do_copyover           ( CHAR_DATA *ch);
+void  do_copyover           ( void );
 
 /* sends the output directly */
 bool  text_to_socket        ( SOCKET_DATA *dsock, const char *txt );
diff -ruN ../nakedmudv3.1/src/time/time.c src/time/time.c
--- ../nakedmudv3.1/src/time/time.c	Sun Dec  4 20:03:07 2005
+++ src/time/time.c	Sat Jul  1 20:06:58 2006
@@ -222,12 +222,16 @@
 
 //
 // If it's in the night, swap out our desc for the room's night desc
-void room_nightdesc_hook(BUFFER *desc, ROOM_DATA *room, CHAR_DATA *looker) {
+void room_nightdesc_hook(const char *info) {
+  ROOM_DATA   *room = NULL;
+  CHAR_DATA *looker = NULL;
+  hookParseInfo(info, &room, &looker);
+
   if((is_evening() || is_night()) && *roomGetNightDesc(room)) {
     // if it's the room desc and not an edesc, cat the night desc...
-    if(!strcasecmp(bufferString(desc), roomGetDesc(room))) {
-      bufferClear(desc);
-      bufferCat(desc, roomGetNightDesc(room));
+    if(!strcasecmp(bufferString(charGetLookBuffer(looker)),roomGetDesc(room))) {
+      bufferClear(charGetLookBuffer(looker));
+      bufferCat(charGetLookBuffer(looker), roomGetNightDesc(room));
     }
   }
 }
diff -ruN ../nakedmudv3.1/src/utils.c src/utils.c
--- ../nakedmudv3.1/src/utils.c	Sun Dec  4 20:03:08 2005
+++ src/utils.c	Sat Jul  1 20:06:58 2006
@@ -1220,6 +1220,16 @@
   return data;
 }
 
+LIST *reverse_list(LIST *list) {
+  LIST         *newlist = newList();
+  LIST_ITERATOR *list_i = newListIterator(list);
+  void            *elem = NULL;
+  ITERATE_LIST(elem, list_i) {
+    listPut(newlist, elem);
+  } deleteListIterator(list_i);
+  return newlist;
+}
+
 bool parse_worldkey(const char *key, char *name, char *locale) {
   *name = *locale = '\0';
   int pos = next_letter_in(key, '@');
diff -ruN ../nakedmudv3.1/src/utils.h src/utils.h
--- ../nakedmudv3.1/src/utils.h	Sun Dec  4 20:03:08 2005
+++ src/utils.h	Sat Jul  1 20:06:58 2006
@@ -219,6 +219,10 @@
 void *identity_func(void *data);
 
 //
+// returns a copy of the list with everything in reverse order
+LIST *reverse_list(LIST *list);
+
+//
 // checks to see if a file or directory exists
 bool file_exists(const char *fname);
 bool dir_exists (const char *dname);
diff -ruN ../nakedmudv3.1/src/zone.c src/zone.c
--- ../nakedmudv3.1/src/zone.c	Sun Dec  4 20:03:08 2005
+++ src/zone.c	Sat Jul  1 20:06:58 2006
@@ -124,7 +124,7 @@
   zone->pulse--;
   if(zone->pulse == 0) {
     zone->pulse = zone->pulse_timer;
-    hookRun("reset", zone);
+    hookRun("reset", hookBuildInfo("str", zoneGetKey(zone)));
   }
 }
 
diff -ruN ../nakedmudv3.1/lib/pymodules/cmd_admin.py lib/pymodules/cmd_admin.py
--- ../nakedmudv3.1/lib/pymodules/cmd_admin.py	Wed Dec 31 17:00:00 1969
+++ lib/pymodules/cmd_admin.py	Sat Jul  1 20:07:04 2006
@@ -0,0 +1,215 @@
+################################################################################
+#
+# cmd_admin.py
+#
+# commands available only to admins.
+#
+################################################################################
+from mud import *
+from mudsys import add_cmd
+import mudsys, inform, char
+
+
+
+def cmd_shutdown(ch, cmd, arg):
+    '''boom! shut the mud down'''
+    mudsys.do_shutdown()
+
+def cmd_shutdown_net(ch, cmd, arg):
+    '''a trap to make sure we spell shutdown out completely'''
+    ch.send("You must spell out shutdown completely!")
+
+def cmd_copyover(ch, cmd, arg):
+    '''restart the mud, but keep all sockets attached'''
+    mudsys.do_copyover()
+
+def cmd_copyover_net(ch, cmd, arg):
+    '''a trap to make sure we spell copyover out completely'''
+    ch.send("You must spell out copyover completely!")
+
+def cmd_repeat(ch, cmd, arg):
+    '''performs the same command multiple times'''
+    try:
+        times, arg = parse_args(ch, True, cmd, arg, "int string")
+    except: return
+
+    if times < 1:
+        ch.send("Commands may only be repeated a positive number of times.")
+    else:
+        for i in range(times):
+            ch.act(arg, True)
+
+def cmd_pulserate(ch, cmd, arg):
+    '''changes the number of pulses the mud experiences each second'''
+    if arg == '':
+        ch.send("The mud currently has "+mudsys.sys_getval("pulses_per_second")+
+                "pulses per second.")
+    else:
+        pulserate = atoi(arg)
+        if pulserate == 0 or 1000 % pulse != 0:
+            ch.send("The number of pulses per second must divide 1000.")
+        else:
+            mudsys.sys_setval("pulses_per_second", str(pulserate))
+            ch.send("The mud's new pulse rate is %d pulses per second." %
+                    pulserate)
+
+def cmd_lockdown(ch, cmd, arg):
+    '''Locks the game for anyone not a member of one of the user groups
+       we specify.'''
+    if arg == '':
+        lockdown = mudsys.sys_getval("lockdown")
+        if lockdown == '':
+            ch.send("Lockdown is currently off.")
+        else:
+            ch.send("Lockdown is currently to members not of: " + lockdown)
+            ch.send("To turn off lockdown, use {clockdown off{n")
+
+    elif arg.lower() == "off":
+        ch.send("Lockdown disabled.")
+        mudsys.sys_setval("lockdown", "")
+
+    # make sure we're not locking ourself out
+    elif not ch.isInGroup(arg):
+        ch.send("You cannot lock yourself out!")
+
+    else:
+        ch.send("MUD locked down to everyone not in groups: " + arg)
+        mudsys.sys_setval("lockdown", arg)
+
+        # kick out everyone who we've just locked out
+        for ch in Char.char_list():
+            if ch.is_pc and not ch.isInGroup(arg):
+                ch.send("The mud has just been locked down to you.")
+                mudsys.do_save(ch)
+                mudsys.do_disconnect(ch)
+                extract_mob(ch)
+
+def cmd_at(ch, cmd, arg):
+    '''Perform a command at another room or person'''
+    try:
+        found, type, arg = parse_args(ch, True, cmd, arg,
+                                      "{ room ch.world.noself } string")
+    except: return
+
+    # figure out what room we're doing the command at
+    if type == "char":
+        room = found.room
+    else:
+        room = found
+
+    # transfer us over to the new room, do the command, then transfer back
+    old_room = ch.room
+    ch.room  = room
+    ch.act(arg, True)
+    ch.room  = old_room
+
+def try_force(ch, vict, cmd):
+    '''tries to force a person to do something'''
+    if ch == vict:
+        ch.send("Why don't you just try doing it?")
+    elif vict.isInGroup("admin"):
+        ch.send("But " + vict.name + " has just as many priviledges as you!")
+    else:
+        ch.send("You force " + vict.name + " to '" + cmd + "'")
+        vict.send(inform.see_char_as(vict, ch) + " forces you to '" + cmd + "'")
+        vict.act(cmd, False)
+
+def cmd_force(ch, cmd, arg):
+    '''force someone to execute a command'''
+    try:
+        found, multi, arg = parse_args(ch, True, cmd, arg,
+                                       "ch.world.noself.multiple string")
+    except: return
+
+    if multi == False:
+        try_force(ch, found, arg)
+    else:
+        for vict in found:
+            try_force(ch, vict, arg)
+
+def cmd_goto(ch, cmd, arg):
+    '''Go to a specific room, object, or character in the game. Rooms are
+       referenced by vnum. Everything else is referenced by name.
+       usage: goto <thing>
+       
+       examples:
+         goto room@zone       go to room in zone
+         goto jim             go to an object/person named jim'''
+    try:
+        found, type = parse_args(ch, True, cmd, arg, "{ room ch.world.noself }")
+    except: return
+
+    # what did we find?
+    if type == "char":
+        dest = found.room
+    else:
+        dest = found
+
+    message(ch, None, None, None, True, "to_room",
+            "$n disappears in a puff of smoke.")
+    ch.room = dest
+    ch.act("look")
+    message(ch, None, None, None, True, "to_room",
+            "$n appears in a puff of smoke.")
+
+def do_transfer(ch, tgt, dest):
+    '''ch transfers tgt to dest'''
+    if tgt.room == dest:
+        ch.send(tgt.name + " is already there")
+    else:
+        tgt.send(inform.see_char_as(tgt, ch) + " has transferred you to " +
+                 dest.name)
+        message(tgt, None, None, None, True, "to_room",
+                "$n disappears in a puff of smoke.")
+        tgt.room = dest
+        tgt.act("look", False)
+        message(tgt, None, None, None, True, "to_room",
+                "$n arrives in a puff of smoke.")
+
+def cmd_transfer(ch, cmd, arg):
+    '''The opposite of goto. Instead of moving to a specified location, it
+       takes the target to the user.
+       usage: transfer <player> [[to] room]'''
+    try:
+        found, multi, dest = parse_args(ch, True, cmd, arg,
+                                        "ch.world.multiple.noself | [to] room")
+    except: return
+
+    # if we didn't supply a room, use our own
+    if dest == None:
+        dest = ch.room
+
+    # do our transfers
+    if multi == False:
+        do_transfer(ch, found, dest)
+    else:
+        for tgt in found:
+            do_transfer(ch, tgt, dest)
+
+
+
+################################################################################
+# add our commands
+################################################################################
+add_cmd("shutdow", None, cmd_shutdown_net, "unconcious", "flying", "admin",
+        False, False)
+add_cmd("shutdown", None, cmd_shutdown, "unconcious", "flying", "admin",
+        False, False)
+add_cmd("copyove", None, cmd_copyover_net, "unconcious", "flying", "admin",
+        False, False)
+add_cmd("copyover", None, cmd_copyover, "unconcious", "flying", "admin",
+        False, False)
+add_cmd("at", None, cmd_at, "unconcious", "flying", "admin",
+        False, False)
+add_cmd("lockdown", None, cmd_lockdown, "unconcious", "flying", "admin",
+        False, False)
+add_cmd("pulserate", None, cmd_pulserate, "unconcious", "flying", "admin",
+        False, False)
+add_cmd("repeat", None, cmd_repeat, "unconcious", "flying", "admin",
+        False, False)
+add_cmd("force", None, cmd_force, "sitting", "flying", "admin",
+        False, False)
+add_cmd("goto", None, cmd_goto, "sitting", "flying", "admin",
+        False, False)
+add_cmd("transfer", None, cmd_transfer, "sitting", "flying", "admin",
+        False, False)
diff -ruN ../nakedmudv3.1/lib/pymodules/cmd_comm.py lib/pymodules/cmd_comm.py
--- ../nakedmudv3.1/lib/pymodules/cmd_comm.py	Wed Dec 31 17:00:00 1969
+++ lib/pymodules/cmd_comm.py	Sat Jul  1 20:07:04 2006
@@ -0,0 +1,163 @@
+################################################################################
+#
+# cmd_comm.c
+#
+# Various commands used in NakedMud(tm) for communicating with other
+# characters, and NPCs.
+#
+################################################################################
+from mud import *
+from mudsys import add_cmd
+import inform, hooks
+
+
+
+def cmd_ask(ch, cmd, arg):
+    '''cmd_ask is used to pose a question to another character. Mostly, this is
+       intended to be used to carry on dialogs with NPCs. Ask has a local range
+       (i.e. you can only ask people in the same room as you questions)
+       usage: ask <person> [about] <question>
+
+       examples:
+         ask bob about cats           ask bob about the topic, "cats"
+         ask jim can I have a salad?  ask jim if you can have a salad'''
+    try:
+        tgt, question = parse_args(ch, True, cmd, arg,
+                                   "ch.room.noself [about] string")
+    except: return
+
+    question = question.replace("$", "$$")
+    message(ch, tgt, None, None, False, "to_vict",
+            "{w$n asks you, '" + question + "'{n")
+    message(ch, tgt, None, None, False, "to_char",
+            "{wYou ask $N, '" + question + "'{n")
+
+    # run our ask hooks
+    hooks.run("ask", hooks.build_info("ch ch str", (ch, tgt, question)))
+
+def cmd_tell(ch, cmd, arg):
+    '''cmd_tell sends a message to another character. Primarily intended for
+       player-player communication. Players can tell other players things even
+       if they are not in the same room.
+       usage: tell <person> <mesage>
+       
+       examples:
+         tell luke I am your father'''
+    try:
+        tgt, mssg = parse_args(ch, True, cmd, arg, "ch.world.noself string")
+    except: return
+
+    mssg = mssg.replace("$", "$$")
+    message(ch, tgt, None, None, False, "to_vict",
+            "{r$n tells you, '" + mssg + "'{n")
+    message(ch, tgt, None, None, False, "to_char",
+            "{rYou tell $N, '" + mssg + "'{n")
+
+def cmd_chat(ch, cmd, arg):
+    '''cmd_chat sends a message to all of the players currently logged on.
+       usage: chat <message>
+
+       example:
+         chat hello, world!'''
+    if arg == '':
+        ch.send("Chat what?")
+    else:
+        arg = arg.replace("$", "$$")
+        message(ch, None, None, None, False, "to_world",
+                "{y$n chats, '" + arg + "'{n")
+        message(ch, None, None, None, False, "to_char",
+                "{yyou chat, '" + arg + "'{n")
+
+def cmd_say(ch, cmd, arg):
+    '''cmd_say sends a message to everyone in the same room as you. Say, like
+       ask, can trigger NPC dialogs.
+       usage: say <message>
+
+       example:
+         say hello, room!'''
+    if arg == '':
+        send_to_char(ch, "Say what?")
+    else:
+        arg = arg.replace("$", "$$")
+        message(ch, None, None, None, False, "to_room",
+                "{y$n says, '" + arg + "'{n")
+        message(ch, None, None, None, False, "to_char",
+                "{yyou say, '" + arg + "'{n")        
+
+        # run say hooks
+        hooks.run("say", hooks.build_info("ch str", (ch, arg)))
+
+def cmd_greet(ch, cmd, arg):
+    '''NPCs with dialogs will often have something to say when you
+       greet/approach then. cmd_greet is a way to get them talking.
+       usage: greet <person>
+
+       examples:
+         greet mayor'''
+    try:
+        tgt, = parse_args(ch, True, cmd, arg, "ch.room.noself")
+    except: return
+
+    message(ch, tgt, None, None, False, "to_char", "You greet $N.")
+    message(ch, tgt, None, None, False, "to_vict", "$n greets you.")
+    message(ch, tgt, None, None, False, "to_room", "$n greets $N.")
+
+    # run greet hooks
+    hooks.run("greet", hooks.build_info("ch ch", (ch, tgt)))
+
+def cmd_emote(ch, cmd, arg):
+    '''Send a special text message to the room you are in. The message is
+       preceded by your name, unless you put a $n somewhere in the text, in
+       which case the $n is replaced by your name.
+       usage: emote <message>
+
+       examples:
+         emote does a little dance.
+         emote A gunshot sounds, and $n is laying on the ground, dead.'''
+    if arg == '':
+        send_to_char(ch, "Emote we must, but emote what?")
+    else:
+        # see if a $n is within the argument ... if there is, let the person
+        # put his or her name where it's wanted. Otherwise, tag it onto the
+        # front of the message
+        if arg.find("$n") == -1:
+            arg = "$n " + arg
+        message(ch, None, None, None, False, "to_room, to_char", arg)
+
+def cmd_gemote(ch, cmd, arg):
+    '''cmd_gemote is similar to emote, but it sends a global message'''
+    if arg == '':
+        send_to_char(ch, "Gemote we must, but gemote what?")
+    else:
+        # same as emote, but global
+        if arg.find("$n") == -1:
+            arg = "$n " + arg
+        message(ch, None, None, None, False, "to_world, to_char",
+                "{bGLOBAL:{c " + arg + "{n")
+
+def cmd_page(ch, cmd, arg):
+    '''Send a message to another character, and also make it beep'''
+    try:
+        tgt, mssg = parse_args(ch, True, cmd, arg, "ch.world.noself string")
+    except: return
+    ch.send("\007\007You page " + inform.see_char_as(ch, tgt))
+    tgt.send("\007\007*" + inform.see_char_as(tgt, ch) + "* " + mssg)
+
+
+
+################################################################################
+# add our commands
+################################################################################
+add_cmd("ask",     None, cmd_ask,   "sitting", "flying", "player", False, False)
+add_cmd("say",     None, cmd_say,   "sitting", "flying", "player", False, False)
+add_cmd("'",       None, cmd_say,   "sitting", "flying", "player", False, False)
+add_cmd("tell",    None, cmd_tell,  "sitting", "flying", "player", False, False)
+add_cmd("chat",    None, cmd_chat,  "sitting", "flying", "player", False, False)
+add_cmd("gossip",  None, cmd_chat,  "sitting", "flying", "player", False, False)
+add_cmd("\"",      None, cmd_chat,  "sitting", "flying", "player", False, False)
+add_cmd("page",    None, cmd_page,  "sitting", "flying", "player", False, False)
+add_cmd("greet",   None, cmd_greet, "sitting", "flying", "player", False, False)
+add_cmd("approach",None, cmd_greet, "sitting", "flying", "player", False, False)
+add_cmd("emote",   None, cmd_emote, "sitting", "flying", "player", False, False)
+add_cmd("gemote",  None, cmd_gemote,"sitting", "flying", "player", False, False)
+add_cmd(":",       None, cmd_emote, "sitting", "flying", "player", False, False)
diff -ruN ../nakedmudv3.1/lib/pymodules/cmd_inform.py lib/pymodules/cmd_inform.py
--- ../nakedmudv3.1/lib/pymodules/cmd_inform.py	Wed Dec 31 17:00:00 1969
+++ lib/pymodules/cmd_inform.py	Sat Jul  1 20:07:04 2006
@@ -0,0 +1,77 @@
+################################################################################
+#
+# cmd_inform.py
+#
+# Contains various commands that are informative in nature. For instance, look,
+# equipment, inventory, etc...
+#
+################################################################################
+from mud import *
+from inform import *
+from mudsys import add_cmd
+import utils
+
+
+
+################################################################################
+# utility functions
+################################################################################
+def cmd_inventory(ch, cmd, arg):
+    '''displays the character inventory to himself'''
+    if len(ch.inv) == 0:
+        ch.send("You are not carrying anything.")
+    else:
+        ch.send("{gYou are carrying:")
+        visible = utils.find_all_objs(ch, ch.inv, "", None, True)
+        utils.show_list(ch, visible, lambda(x): x.name, lambda(x): x.mname)
+
+
+def cmd_equipment(ch, cmd, arg):
+    '''displays a character\'s equipment to himself'''
+    ch.send("You are wearing:")
+    show_equipment(ch, ch)
+
+def cmd_who(ch, cmd, arg):
+    '''lists who is all online to the character'''
+    ch.page(build_who())
+    
+def cmd_look(ch, cmd, arg):
+    '''allows players to examine just about anything in the game'''
+    if arg == '':
+        inform.look_at_room(ch, ch.room)
+    else:
+        found, type = generic_find(ch, arg, "all", "immediate", False)
+
+        # what did we find?
+        if found == None:
+            ch.send("What did you want to look at?")
+        elif type == "obj" or type == "in":
+            inform.look_at_obj(ch, found)
+        elif type == "char":
+            inform.look_at_char(ch, found)
+        elif type == "exit":
+            inform.look_at_exit(ch, found)
+
+        # extra descriptions as well
+        ############
+        # FINISH ME
+        ############
+
+
+
+################################################################################
+# add our commands
+################################################################################
+add_cmd("inventory", "inv", cmd_inventory, "sitting", "flying",
+        "player", True, False)
+add_cmd("equipment", "eq",  cmd_equipment, "sitting", "flying",
+        "player", True, False)
+add_cmd("worn",      None,  cmd_equipment, "sitting", "flying",
+        "player", True, False)
+add_cmd("who",       None,  cmd_who,       "sitting", "flying",
+        "player", True, False)
+
+'''
+add_cmd("look",      "l",   cmd_look,      "sitting", "flying",
+        "player", True, False)
+'''
diff -ruN ../nakedmudv3.1/lib/pymodules/cmd_manip.py lib/pymodules/cmd_manip.py
--- ../nakedmudv3.1/lib/pymodules/cmd_manip.py	Wed Dec 31 17:00:00 1969
+++ lib/pymodules/cmd_manip.py	Sat Jul  1 20:07:04 2006
@@ -0,0 +1,496 @@
+################################################################################
+#
+# cmd_manip.py
+#
+# a set of commands that NakedMud(tm) comes with that allows characters to
+# manipulate various things. These commands are mostly directed towards
+# manipulating objects (e.g. get, put, drop, etc...) but can also affect other
+# things like exits (e.g. open, close)
+#
+################################################################################
+from mud import *
+from utils import *
+from inform import *
+from mudsys import add_cmd
+import movement, hooks
+
+
+
+def do_give(ch, recv, obj):
+    '''does the handling of the give command'''
+    message(ch, recv, obj, None, True, "to_room",
+            "$n gives $o to $N.")
+    message(ch, recv, obj, None, True, "to_vict",
+            "$n gives $o to you.")
+    message(ch, recv, obj, None, True, "to_char",
+            "You give $o to $N.")
+    obj.carrier = recv
+
+    # run our give hook
+    hooks.run("give", hooks.build_info("ch ch obj", (ch, recv, obj)))
+
+def cmd_give(ch, cmd, arg):
+    '''the give command'''
+    try:
+        to_give, multi, recv = parse_args(ch, True, cmd, arg,
+                                          "[the] obj.inv.multiple " +
+                                          "[to] ch.room.noself")
+    except: return
+
+    if multi == False:
+        do_give(ch, recv, to_give)
+    else:
+        for obj in to_give:
+            do_give(ch, recv, obj)
+
+def do_get(ch, obj, cont):
+    '''transfers an item from the ground to the character'''
+    if is_keyword(obj.bits, "notake"):
+        ch.send("You cannot take " + see_obj_as(ch, obj) + ".")
+    elif cont != None:
+        message(ch, None, obj, cont, True, "to_char", "You get $o from $O.")
+        message(ch, None, obj, cont, True, "to_room", "$n gets $o from $O.")
+        obj.carrier = ch
+    else:
+        message(ch, None, obj, None, True, "to_char", "You get $o.")
+        message(ch, None, obj, None, True, "to_room", "$n gets $o.")
+        obj.carrier = ch
+
+        # run get hooks
+        hooks.run("get", hooks.build_info("ch obj", (ch, obj)))
+
+def try_get_from(ch, cont, arg):
+    '''tries to get one item from inside another'''
+    if not cont.istype("container"):
+        message(ch, None, cont, None, True, "to_char", "$o is not a container.")
+    elif cont.container_is_closed:
+        message(ch, None, cont, None, True, "to_char", "$o is closed.")
+    else:
+        # find our count and name
+        num, name = get_count(arg)
+
+        # multi or single?
+        if num == "all":
+            list = find_all_objs(ch, cont.objs, name)
+            for obj in list:
+                do_get(ch, obj, cont)
+        else:
+            obj = find_obj(ch, cont.objs, num, name)
+            if obj != None:
+                do_get(ch, obj, cont)
+
+def cmd_get(ch, cmd, arg):
+    '''cmd_get is used to move objects from containers or the room to your
+       inventory.
+       usage: get <object> <from>
+
+       examples:
+         get sword            get a sword from the room
+         get 2.cupcake bag    get the second cupcake from your bag
+         get all.coin         get all of the coins on the ground'''
+    try:
+        arg, cont = parse_args(ch, True, cmd, arg,
+                               "[the] word | [from] obj.room.inv.eq")
+    except: return
+    
+    # are we doing get, or get-from?
+    if cont != None:
+        try_get_from(ch, cont, arg)
+    else:
+        # try to find the object in the room
+        try:
+            found, multi = parse_args(ch, True, cmd, arg, "obj.room.multiple")
+        except: return
+
+        # pick up all the items we want
+        if multi == False:
+            do_get(ch, found, None)
+        else:
+            for obj in found:
+                do_get(ch, obj, None)
+
+def do_drop(ch, obj):
+    '''handles object dropping'''
+    message(ch, None, obj, None, True, "to_char", "You drop $o.")
+    message(ch, None, obj, None, True, "to_room", "$n drops $o.")
+    obj.room = ch.room
+
+    # run our drop hook
+    hooks.run("drop", hooks.build_info("ch obj", (ch, obj)))
+
+def cmd_drop(ch, cmd, arg):
+    '''cmd_drop is used to transfer an object in your inventory to the ground
+       usage: drop <item>
+   
+       examples:
+         drop bag          drop a bag you have
+         drop all.bread    drop all of the bread you are carrying
+         drop 2.cupcake    drop the second cupcake in your posession'''
+    try:
+        found, multi = parse_args(ch, True, cmd, arg, "[the] obj.inv.multiple")
+    except: return
+
+    # are we dropping a list of things, or just one?
+    if multi == False:
+        do_drop(ch, found)
+    else:
+        for obj in found:
+            do_drop(ch, obj)
+
+def do_remove(ch, obj):
+    '''handles equipment removing'''
+    # try to put it to our inventory
+    obj.carrier = ch
+
+    # make sure it succeeded
+    if obj.carrier != ch:
+        ch.send("You were unable to remove " + see_obj_as(ch, obj) + ".")
+    else:
+        message(ch, None, obj, None, True, "to_char", "You remove $o.")
+        message(ch, None, obj, None, True, "to_room", "$n removes $o.")
+
+        # run our hooks
+        hooks.run("remove", hooks.build_info("ch obj", (ch, obj)))
+
+def cmd_remove(ch, cmd, arg):
+    '''cmd_remove is used to unequip items on your body to your inventory
+       usage: remove <item>
+
+       examples:
+         remove mask             remove the mask you are wearing
+         remove all.ring         remove all the rings you have on
+         remove 2.ring           remove the 2nd ring you have equipped'''
+    try:
+        found, multi = parse_args(ch, True, cmd, arg, "[the] obj.eq.multiple")
+    except: return
+
+    # are we removing one thing, or multiple things?
+    if multi == False:
+        do_remove(ch, found)
+    else:
+        for obj in found:
+            do_remove(ch, obj)
+
+def do_wear(ch, obj, where):
+    '''handles object wearing'''
+    if not obj.istype("worn"):
+        ch.send("But " + see_obj_as(ch, obj) + " is not wearable.")
+    elif ch.equip(obj, where):
+        message(ch, None, obj, None, True, "to_char", "You wear $o.")
+        message(ch, None, obj, None, True, "to_room", "$n wears $o.")
+        # equip hooks are done in the C code
+    else:
+        message(ch, None, obj, None, True, "to_char", "You could not equip $o.")
+
+def cmd_wear(ch, cmd, arg):
+    '''cmd_wear is used to equip wearable items in your inventory to your body
+       usage: wear [object] [where]
+
+       examples:
+         wear shirt                            equip a shirt
+         wear all.ring                         wear all of the rings in your 
+                                               inventory
+         wear gloves left hand, right hand     wear the gloves on your left and
+                                               right hands'''
+    try:
+        found, multi, where = parse_args(ch, True, cmd, arg,
+                                         "[the] obj.inv.multiple | [on] string")
+    except: return
+
+    # are we wearing one thing, or multiple things?
+    if multi == False:
+        do_wear(ch, found, where)
+    else:
+        for obj in found:
+            do_wear(ch, obj, where)
+
+def do_put(ch, obj, cont):
+    '''handles the putting of objects'''
+    if obj == cont:
+        ch.send("You cannot put " + see_obj_as(ch, obj) + " into itself.")
+    # make sure we have enough room 
+    elif obj.weight > cont.container_capacity - cont.weight + cont.weight_raw:
+        ch.send("There is not enough room in " + see_obj_as(ch, cont) +
+                " for " + see_obj_as(ch, obj) + ".")
+    # do the move
+    else:
+        obj.container = cont
+        message(ch, None, obj, cont, True, "to_char", "You put $o in $O.")
+        message(ch, None, obj, cont, True, "to_room", "$n puts $o in $O.")
+
+def cmd_put(ch, cmd, arg):
+    '''put one thing into another. The thing you wish to put must be in
+       your inventory. The container must be in your immediate visible range
+       (room, inventory, body)
+
+       usage: put [the] <thing> [in the] <container>
+
+       examples:
+         put coin bag             put a coin into the bag
+         put all.shirt closet     put all of the shirts in the closet'''
+    try:
+        found, multi, cont = parse_args(ch, True, cmd, arg,
+                                        "[the] obj.inv.multiple " +
+                                        "[in the] obj.room.inv")
+    except: return
+
+    # make sure we have a container
+    if not cont.istype("container"):
+        ch.send(see_obj_as(ch, cont) + " is not a container.")
+    elif cont.container_is_closed:
+        ch.send(see_obj_as(ch, cont) + " is currently closed.")
+    # do we have one or multiple items?
+    elif multi == False:
+        do_put(ch, found, cont)
+    else:
+        for obj in found:
+            do_put(ch, obj, cont)
+
+def try_manip_other_exit(room, ex, closed, locked):
+    '''used by open, close, lock, and unlock. When an exit is manipulated on one
+       side, it is the case that we'll want to do an identical manipulation on
+       the other side. That's what we do here. Note: Can only do close OR lock
+       with one call to this function. Cannot handle both at the same time!'''
+    opp_dir = None
+    if ex.dest == None:
+        return
+
+    # see if we can figure out the opposite direction
+    if ex.opposite != '':
+        opp_dir = ex.opposite
+    else:
+        # figure out the direction of the exit, and its opposite
+        dirnum = movement.dir_index(room.exdir(ex))
+        if dirnum != -1:
+            opp_dir = movement.dir_name[movement.dir_opp[dirnum]]
+
+    # do we have an opposite direction to manipulate?
+    if opp_dir == None:
+        return
+
+    # do we have an opposite exit to manipulate?
+    opp_ex = ex.dest.exit(opp_dir)
+    if opp_ex != None:
+        # figure out our name
+        name = "an exit"
+        if opp_ex.name != '':
+            name = opp_ex.name
+
+        # try to manipulate the exit
+        if closed and not opp_ex.is_closed:
+            opp_ex.close()
+            ex.dest.send(name + " closes from the other side.")
+        elif locked and opp_ex.is_closed and not opp_ex.is_locked:
+            opp_ex.lock()
+            ex.dest.send(name + " locks from the other side.")
+        elif not closed and opp_ex.is_closed and not opp_ex.is_locked:
+            opp_ex.open()
+            ex.dest.send(name + " opens from the other side.")
+        elif not locked and opp_ex.is_locked:
+            opp_ex.unlock()
+            ex.dest.send(name + " unlocks from the other side.")
+
+def cmd_lock(ch, cmd, arg):
+    '''try to lock an exit or container. The container can be anything in our
+       immediate visible range (room, inventory, body). do_lock automatically
+       checks if we have the key on us.
+
+       examples:
+         lock door                lock a door in the room
+         lock south               lock the south exit
+         lock 2.chest             lock the 2nd chest in our visible range'''
+    try:
+        found, type = parse_args(ch, True, cmd, arg,
+                                 "[the] {obj.room.inv.eq exit }")
+    except: return
+
+    # what did we find?
+    if type == "exit":
+        ex = found
+        if not ex.is_closed:
+            ch.send(ex.name + " must be closed first.")
+        elif ex.is_locked:
+            ch.send(ex.name + " is already locked.")
+        elif ex.key == '':
+            ch.send("You cannot figure out how " + ex.name +" would be locked.")
+        elif not has_proto(ch, ex.key):
+            ch.send("You cannot seem to find the key.")
+        else:
+            message(ch, None, None, None, True, "to_char",
+                    "You lock " + ex.name + ".")
+            message(ch, None, None, None, True, "to_room",
+                    "$n locks " + ex.name + ".")
+            ex.lock()
+            try_manip_other_exit(ch.room, ex, ex.is_closed, True)
+
+    # type must be object
+    else:
+        obj = found
+        if not obj.istype("container"):
+            ch.send(see_obj_as(ch, obj) + " is not a container.")
+        elif not obj.container_is_closed:
+            ch.send(see_obj_as(ch, obj) + " is not closed.")
+        elif obj.container_is_locked:
+            ch.send(see_obj_as(ch, obj) + " is already locked.")
+        elif obj.container_key == '':
+            ch.send("You cannot figure out how to lock " + see_obj_as(ch, obj))
+        elif not has_proto(ch, obj.container_key):
+            ch.send("You cannot seem to find the key.")
+        else:
+            message(ch, None, obj, None, True, "to_char", "You lock $o.")
+            message(ch, None, obj, None, True, "to_room", "$n locks $o.")
+            obj.container_is_locked = True
+
+def cmd_unlock(ch, cmd, arg):
+    '''the opposite of lock'''
+    try:
+        found, type = parse_args(ch, True,cmd,arg, "[the] {obj.room.inv exit }")
+    except: return
+
+    # what did we find?
+    if type == "exit":
+        ex = found
+        if not ex.is_closed:
+            ch.send(ex.name + " is already open.")
+        elif not ex.is_locked:
+            ch.send(ex.name + " is already unlocked.")
+        elif ex.key == '':
+            ch.send("You cannot figure out how " + ex.name +
+                    " would be unlocked.")
+        elif not has_proto(ch, ex.key):
+            ch.send("You cannot seem to find the key.")
+        else:
+            message(ch, None, None, None, True, "to_char",
+                    "You unlock " + ex.name + ".")
+            message(ch, None, None, None, True, "to_room",
+                    "$n unlocks " + ex.name + ".")
+            ex.unlock()
+            try_manip_other_exit(ch.room, ex, ex.is_closed, False)
+
+    # must be an object
+    else:
+        obj = found
+        if not obj.istype("container"):
+            ch.send(see_obj_as(ch, obj) + " is not a container.")
+        elif not obj.container_is_closed:
+            ch.send(see_obj_as(ch, obj) + " is already open.")
+        elif not obj.container_is_locked:
+            ch.send(see_obj_as(ch, obj) + " is already unlocked.")
+        elif obj.container_key == '':
+            ch.send("You cannot figure out how to unlock "+see_obj_as(ch, obj))
+        elif not has_proto(ch, obj.container_key):
+            ch.send("You cannot seem to find the key.")
+        else:
+            message(ch, None, obj, None, True, "to_char", "You unlock $o.")
+            message(ch, None, obj, None, True, "to_room", "$n unlocks $o.")
+            obj.container_is_locked = False
+
+def cmd_open(ch, cmd, arg):
+    '''attempt to open a door or container. The container must be in our
+       immediate visible range (room, inventory, body).
+
+       usage: open [the] <thing>
+
+       examples:
+         open door               open a door
+         open 2.bag              open your second bag
+         open east               open the east exit
+         open backpack on self   open a backpack you are wearing'''
+    try:
+        found, type = parse_args(ch, True,cmd,arg, "[the] {obj.room.inv exit }")
+    except: return
+
+    # is it an exit?
+    if type == "exit":
+        ex = found
+        if not ex.is_closed:
+            ch.send(ex.name + " is already open.")
+        elif ex.is_locked:
+            ch.send(ex.name + " must be unlocked first.")
+        elif not ex.is_closable:
+            ch.send(ex.name + " cannot be opened.")
+        else:
+            message(ch, None, None, None, True, "to_char",
+                    "You open " + ex.name + ".")
+            message(ch, None, None, None, True, "to_room",
+                    "$n opens " + ex.name + ".")
+            ex.open()
+            try_manip_other_exit(ch.room, ex, False, ex.is_locked)
+            hooks.run("open_door", hooks.build_info("ch ex", (ch, ex)))
+
+    # must be an object
+    else:
+        obj = found
+        if not obj.istype("container"):
+            ch.send(see_obj_as(ch, obj) + " is not a container.")
+        elif not obj.container_is_closed:
+            ch.send(see_obj_as(ch, obj) + " is already open.")
+        elif obj.container_is_locked:
+            ch.send(see_obj_as(ch, obj) + " must be unlocked first.")
+        elif not obj.container_is_closable:
+            ch.send(see_obj_as(ch, obj) + " cannot be opened.")
+        else:
+            message(ch, None, obj, None, True, "to_char", "You open $o.")
+            message(ch, None, obj, None, True, "to_room", "$n opens $o.")
+            obj.container_is_closed = False
+            hooks.run("open_obj", hooks.build_info("ch obj", (ch, obj)))
+
+def cmd_close(ch, cmd, arg):
+    '''cmd_close is used to close containers and exits.
+       usage: open <thing>
+
+       examples:
+         close door               close a door
+         close 2.bag              close your second bag
+         close east               close the east exit
+         close backpack on self   close a backpack you are wearing'''
+    try:
+        found, type = parse_args(ch, True,cmd,arg, "[the] {obj.room.inv exit }")
+    except: return
+
+    # is it an exit?
+    if type == "exit":
+        ex = found
+        if ex.is_closed:
+            ch.send(ex.name + " is already closed.")
+        elif ex.is_locked:
+            ch.send(ex.name + " must be unlocked first.")
+        elif not ex.is_closable:
+            ch.send(ex.name + " cannot be closed.")
+        else:
+            message(ch, None, None, None, True, "to_char",
+                    "You close " + ex.name + ".")
+            message(ch, None, None, None, True, "to_room",
+                    "$n closes " + ex.name + ".")
+            ex.close()
+            try_manip_other_exit(ch.room, ex, True, ex.is_locked) 
+
+    # must be an object
+    else:
+        obj = found
+        if not obj.istype("container"):
+            ch.send(see_obj_as(ch, obj) + " is not a container.")
+        elif obj.container_is_closed:
+            ch.send(see_obj_as(ch, obj) + " is already closed.")
+        elif not obj.container_is_closable:
+            ch.send(see_obj_as(ch, obj) + " cannot be closed.")
+        else:
+            message(ch, None, obj, None, True, "to_char", "You close $o.")
+            message(ch, None, obj, None, True, "to_room", "$n closes $o.")
+            obj.container_is_closed = True
+
+
+
+################################################################################
+# load all of our commands
+################################################################################
+add_cmd("give",   None, cmd_give,   "sitting", "flying", "player", True, True)
+add_cmd("get",    None, cmd_get,    "sitting", "flying", "player", True, True)
+add_cmd("drop",   None, cmd_drop,   "sitting", "flying", "player", True, True)
+add_cmd("remove", None, cmd_remove, "sitting", "flying", "player", True, True)
+add_cmd("wear",   None, cmd_wear,   "sitting", "flying", "player", True, True)
+add_cmd("put",    None, cmd_put,    "sitting", "flying", "player", True, True)
+add_cmd("open",   None, cmd_open,   "sitting", "flying", "player", True, True)
+add_cmd("close",  None, cmd_close,  "sitting", "flying", "player", True, True)
+add_cmd("lock",   None, cmd_lock,   "sitting", "flying", "player", True, True)
+add_cmd("unlock", None, cmd_unlock, "sitting", "flying", "player", True, True)
diff -ruN ../nakedmudv3.1/lib/pymodules/cmd_misc.py lib/pymodules/cmd_misc.py
--- ../nakedmudv3.1/lib/pymodules/cmd_misc.py	Wed Dec 31 17:00:00 1969
+++ lib/pymodules/cmd_misc.py	Sat Jul  1 20:07:04 2006
@@ -0,0 +1,66 @@
+################################################################################
+#
+# cmd_misc.c
+#
+# a collection of miscellaneous commands that come with NakedMud(tm)
+#
+################################################################################
+from mud import *
+from hooks import *
+from mudsys import add_cmd
+import event, mudsys
+
+
+def cmd_stop(ch, cmd, arg):
+    '''stop performing the character\'s current action'''
+    if not ch.isActing():
+        ch.send("But you're not currently performing an action!\r\n")
+    else:
+        ch.interrupt()
+
+def cmd_clear(ch, cmd, arg):
+    '''clear the screen'''
+    ch.send("\033[H\033[J")
+
+def event_delayed_cmd(ch, filler, cmd):
+    '''used to perform delayed commands'''
+    ch.act(cmd, True)
+
+def cmd_delay(ch, cmd, arg):
+    '''Perform a command, but delay its execution by a couple seconds'''
+    try:
+        secs, to_delay = parse_args(ch, True, cmd, arg, "int string")
+    except: return
+
+    if secs < 1:
+        ch.send("You can only delay commands for positive amounts of time.")
+    else:
+        ch.send("You delay '%s' for %d seconds" % (to_delay, secs))
+        event.start_event(ch, secs, event_delayed_cmd, None, to_delay)
+
+def cmd_motd(ch, cmd, arg):
+    '''Displays the MOTD to the character'''
+    ch.page(get_motd())
+
+def cmd_save(ch, cmd, arg):
+    '''save the character'''
+    mudsys.do_save(ch)
+    ch.send("Saved.")
+
+def cmd_quit(ch, cmd, arg):
+    '''quit the game'''
+    log_string(ch.name + " has left the game.")
+    mudsys.do_save(ch)
+    mudsys.do_quit(ch)
+
+
+
+################################################################################
+# add our commands
+################################################################################
+add_cmd("stop",  None, cmd_stop,    "sitting", "flying", "player", True,  False)
+add_cmd("clear", None, cmd_clear,"unconcious", "flying", "player", True,  False)
+add_cmd("delay", None, cmd_delay,  "sleeping", "flying", "player", True,  False)
+add_cmd("motd",  None, cmd_motd, "unconcious", "flying", "player", False, False)
+add_cmd("save",  None, cmd_save,   "sleeping", "flying", "player", False, False)
+add_cmd("quit",  None, cmd_quit,   "sleeping", "flying", "player", False, True)
diff -ruN ../nakedmudv3.1/lib/pymodules/demo.py lib/pymodules/demo.py
--- ../nakedmudv3.1/lib/pymodules/demo.py	Sun Dec  4 20:03:26 2005
+++ lib/pymodules/demo.py	Wed Dec 31 17:00:00 1969
@@ -1,46 +0,0 @@
-################################################################################
-#
-# demo.py
-#
-# This is a demo module that gives the basics on how to extend the mud via
-# Python modules. Python is primarily used for scripting in NakedMud, but it is
-# only a couple small steps to integrate python and the mud enough to let Python
-# add commands, events, actions, and entirely new systems like combat and magic.
-# 
-# There are pros and cons that come with extending the mud with Python, and
-# extending the mud with C. Python is a much easier language to program in than
-# C, especially when it comes to prototyping new ideas; programming an idea in
-# Python will often take much less time than it will in C. Python code also
-# tends to be much shorter than C code, and is thus easier to maintain. Another
-# beautiful feature of the way Python is integrated into the MUD is that
-# problems in the code will rarely crash the mud. Rather, they'll just throw
-# an error that we can display, and continue working fine.
-#
-# The downside is that Python has extremely limited access to the C code that
-# serves as the foundation for NakedMud. Python can't  call any player commands
-# that are written in C (yet), Python can't add auxiliary data to the different
-# types of data in the mud (yet), and Python doesn't have the capabilities to
-# interact with some of the important C modules and systems (e.g. set_val, 
-# olc, races, bodyparts, character generation, storage sets). These are all 
-# things that will come in time, but at the moment, extending the mud in Python
-# means giving away the ability to do many things that will eventually be 
-# important.
-#
-# You won't be able to do everything with python modules, but you WILL be able
-# to do a hell of a lot... 
-#
-################################################################################
-from mud import add_cmd
-
-#
-# Our first character command added with Python! Like a normal MUD command,
-# this command takes in 4 arguments: the character who performed it, the command
-# name, a subcommand value, and the argument supplied to the command. ch is
-# a Character, cmd is a string, subcmd is an int, and arg is a string
-def cmd_pycmd(ch, cmd, arg):
-    ch.send("Hello, " + ch.name + ". This is a demo Python command!")
-
-# let the MUD know it should add a command. This works exactly like add_cmd in 
-# the C source. Good examples of how to use it can be found in interpret.c
-add_cmd('pycmd', None, cmd_pycmd, 'unconcious', 'flying', 'admin', 
-	False, False)
diff -ruN ../nakedmudv3.1/lib/pymodules/inform.py lib/pymodules/inform.py
--- ../nakedmudv3.1/lib/pymodules/inform.py	Wed Dec 31 17:00:00 1969
+++ lib/pymodules/inform.py	Sat Jul  1 20:07:04 2006
@@ -0,0 +1,126 @@
+################################################################################
+#
+# inform.py
+#
+# Python's mirror of C's inform.c -- contains various functions that perform
+# informative duties. Examining places/things, displaying proper names, etc...
+#
+################################################################################
+from mud import *
+import utils, char, hooks
+
+
+
+################################################################################
+# utility functions
+################################################################################
+def see_char_as(ch, tgt):
+    '''returns the proper name one character sees another by'''
+    if ch.cansee(tgt):
+        return tgt.name
+    else:
+        return "someone"
+
+def see_obj_as(ch, obj):
+    '''returns the proper name a character sees an object by'''
+    if ch.cansee(obj):
+        return obj.name
+    else:
+        return "something"
+
+def see_exit_as(ch, ex):
+    '''returns the proper name a character sees an exit by'''
+    if ch.cansee(ex):
+        return ex.name
+    else:
+        return "something"
+
+def look_at_obj(ch, obj):
+    '''displays the object info the the character'''
+    ############
+    # FINISH ME
+    ############
+    return
+
+def look_at_char(ch, tgt):
+    '''displays the other character\'s info the the character'''
+    ############
+    # FINISH ME
+    ############
+    return
+
+def look_at_exit(ch, exit):
+    '''displays the exit info the the character'''
+    ############
+    # FINISH ME
+    ############
+    return
+
+def look_at_room(ch, room):
+    '''displays the room info the the character'''
+    ############
+    # FINISH ME
+    ############
+    return
+
+def show_equipment(ch, tgt):
+    '''shows ch tgt\'s equipment'''
+    for part in tgt.bodyparts:
+        obj = tgt.get_equip(part)
+
+        # if it's not there, or on someone else and we can't see it, skip it
+        if obj == None or (ch != tgt and not ch.cansee(obj)):
+            continue
+
+        ch.send("%-30s %s" % ("{c<{C" + part + "{c>{n", see_obj_as(ch, obj)))
+
+def build_who():
+    '''returns a formatted list of all the people currently online'''
+    buf = "--------------------------------------------------------------------------------\r\n"
+
+    # build character info
+    count = len(char.socket_list())
+    for ch in char.socket_list():
+        buf = buf+(" %-16s %-15s %45s "%(ch.name,ch.race,ch.user_groups))+"\r\n"
+
+    conn_end = "s"
+    if count == 1: conn_end = ""
+
+    # build our footer
+    buf = buf + "--------------------------------------------------------------------------------\r\n" + (" %d player" % count)  + conn_end + " currently logged in.\r\n" + "--------------------------------------------------------------------------------\r\n"
+    
+    return buf
+
+
+
+################################################################################
+# hooks
+################################################################################
+def equipment_look_hook(info):
+    tgt, ch = hooks.parse_info(info)
+
+    if ch != tgt:
+        gndr = tgt.heshe
+        act  = "is"
+    else:
+        gndr = "You"
+        act  = "are"
+
+    ch.send("\n" + gndr + " " + act + " wearing:")
+    show_equipment(ch, tgt)
+
+
+
+################################################################################
+# add our hooks
+################################################################################
+hooks.add("look_at_char", equipment_look_hook)
+
+
+
+################################################################################
+# unload procedure
+################################################################################
+def __unload__():
+    '''things that need to be detached when the module is un/reloaded'''
+    hooks.remove("look_at_char", equipment_look_hook)
diff -ruN ../nakedmudv3.1/lib/pymodules/movement.py lib/pymodules/movement.py
--- ../nakedmudv3.1/lib/pymodules/movement.py	Wed Dec 31 17:00:00 1969
+++ lib/pymodules/movement.py	Sat Jul  1 20:07:04 2006
@@ -0,0 +1,216 @@
+################################################################################
+#
+# movement.py
+#
+# all of the functions concerned with movement and position change
+#
+################################################################################
+from mud import *
+from mudsys import add_cmd
+import inform, hooks
+
+
+
+# a ranking of positions
+positions     = ["unconcious", "sleeping", "sitting", "standing", "flying"]
+pos_act       = ["collapse",   "sleep",    "sit",     "stand",    "fly"]
+
+# stuff for handling movement
+dir_name = ["north", "east", "south", "west", "northeast", "northwest",
+                 "southwest", "southeast", "up", "down"]
+dir_abbr = ["n", "e", "s", "w", "ne", "nw", "sw", "se", "u", "d"]
+dir_opp  = [  2,   3,   0,   1,   6,     7,    4,    5,   9,   8]
+
+
+
+def try_use_furniture(ch, obj, pos):
+    '''attempts to resituate a person on the piece of furniture'''
+    # are we already on it?
+    if ch.on == obj:
+        ch.send("You are already " +ch.on.furniture_type+ " " +ch.on.name+ ".")
+    # make sure we have room
+    elif obj.furniture_capacity <= len(obj.chars):
+        ch.send("There isn't any room left.")
+    else:
+        # are we already on something? get up first
+        if ch.on:
+            message(ch,None,ch.on,None,True,"to_char","You stand up from $o.")
+            message(ch,None,ch.on,None,True,"to_room","$n stands up from $o.")
+            ch.on = None
+
+        # send our messages for sitting down
+        act = pos_act[positions.index(pos)]
+        message(ch, None, obj, None, True,
+                "to_char", "You " + act + " " + obj.furniture_type + " $o.")
+        message(ch, None, obj, None, True,
+                "to_room", "$n " + act + " " + obj.furniture_type + " $o.")
+
+        # place ourselves down on our new furniture
+        ch.on  = obj
+        ch.pos = pos
+        return True
+
+    # we didn't manage to get on the furniture
+    return False
+
+def try_change_pos(ch, pos):
+    '''this function attempts to change the position of the person'''
+    if ch.pos == pos:
+        ch.send("You are already " + pos + ".")
+        return False
+    else:
+        if ch.pos == "flying":
+            message(ch, None, None, None, True, "to_char", "You stop flying.")
+            message(ch, None, None, None, True, "to_room", "$n stops flying.")
+
+        act = pos_act[positions.index(pos)]
+        message(ch, None, None, None, True, "to_char", "You " + act + ".")
+        message(ch, None, None, None, True, "to_room", "$n "  + act + "s.")
+        ch.pos = pos
+        return True
+
+def cmd_sit(ch, cmd, arg):
+    '''attempts to sit'''
+    try:
+        obj, = parse_args(ch, True, cmd, arg, "| [on] obj.room")
+    except: return
+
+    if obj == None:
+        try_change_pos(ch, "sitting")
+    elif obj.istype("furniture"):
+        try_use_furniture(ch, obj, "sitting")
+    else:
+        ch.send("You cannot sit on " + inform.see_obj_as(ch, obj) + ".")
+
+def cmd_sleep(ch, cmd, arg):
+    '''attempts to sleep'''
+    try:
+        obj, = parse_args(ch, True, cmd, arg, "| [on] obj.room")
+    except: return
+
+    if obj == None:
+        try_change_pos(ch, "sleeping")
+    elif obj.istype("furniture"):
+        try_use_furniture(ch, obj, "sleeping")
+    else:
+        ch.send("You cannot sleep on " + inform.see_obj_as(ch, obj) + ".")
+
+def cmd_stand(ch, cmd, arg):
+    '''attempts to stand'''
+    try_change_pos(ch, "standing")
+
+def cmd_wake(ch, cmd, arg):
+    '''attempts to wake up'''
+    message(ch,None,None,None,True, "to_char", "You stop sleeping and sit up.")
+    message(ch,None,None,None,True, "to_room", "$n stops sleeping and sits up.")
+    ch.pos = "sitting"
+
+def dir_index(dir):
+    '''returns the index of the direction name'''
+    try:
+        return dir_name.index(dir)
+    except: pass
+    try:
+        return dir_abbr.index(dir)
+    except: pass
+    return -1
+
+def try_move_mssg(ch, dir):
+    '''Handles all moving of characters from one room to another, through
+       commands. Attempts a move. If succcessful, returns the exit left through.
+       Informs people of our moving'''
+    old_room = ch.room
+    ex       = try_move(ch, dir)
+    dirnum   = dir_index(dir)
+
+    # did we successfully move?
+    if ex != None:
+        new_room = ch.room
+        ch.room  = old_room
+
+        # send out our leave messages as needed
+        if ex.leave_mssg != '':
+            message(ch, None, None, None, True, "to_room", ex.leave_mssg)
+        elif dirnum == -1:
+            message(ch, None, None, None, True, "to_room", "$n leaves.")
+        else:
+            message(ch, None, None, None, True, "to_room",
+                    "$n leaves " + dir_name[dirnum] + ".")
+
+        # send out our enter messages as needed
+        ch.room = new_room
+        if ex.enter_mssg != '':
+            message(ch, None, None, None, True, "to_room", ex.enter_mssg)
+        elif dirnum == None:
+            message(ch, None, None, None, True, "to_room", "$n has arrived.")
+        else:
+            message(ch, None, None, None, True, "to_room",
+                    "$n arrives from the " + dir_name[dir_opp[dirnum]] + ".")
+
+    # return our exit, whether it existed or not
+    return ex
+
+def try_move(ch, dir):
+    '''Handles all moving of characters from one room to another, through
+       commands. Attempts a move. If succcessful, returns the exit left
+       through.'''
+    ex = ch.room.exit(dir)
+
+    # did we find an exit?
+    if ex == None or not ch.cansee(ex):
+        ch.send("Alas, there is no exit in that direction.")
+    elif ex.is_closed:
+        exname = ex.name
+        if exname == '':
+            exname = "it"
+        ch.send("You will have to open " + exname + " first.")
+    elif ex.dest == None:
+        ch.send("It doesn't look like " + exname + " leads anywhere!")
+    else:
+        old_room = ch.room
+
+        # run our leave hooks
+        hooks.run("exit", hooks.build_info("ch rm ex", (ch, ch.room, ex)))
+
+        ch.room = ex.dest
+        ch.act("look")
+
+        # run our enter hooks
+        hooks.run("enter", hooks.build_info("ch rm", (ch, ch.room)))
+
+    # return the exit we found (if we found any)
+    return ex
+
+def cmd_move(ch, cmd, arg):
+    '''cmd_move is the basic entry to all of the movement utilities. See
+       try_move() in movement.py'''
+    try_move_mssg(ch, cmd)
+
+
+
+################################################################################
+# mud commands
+################################################################################
+add_cmd("north",     "n",  cmd_move, "standing", "flying", "player", True, True)
+add_cmd("west",      "w",  cmd_move, "standing", "flying", "player", True, True)
+add_cmd("east",      "e",  cmd_move, "standing", "flying", "player", True, True)
+add_cmd("south",     "s",  cmd_move, "standing", "flying", "player", True, True)
+add_cmd("up",        "u",  cmd_move, "standing", "flying", "player", True, True)
+add_cmd("down",      "d",  cmd_move, "standing", "flying", "player", True, True)
+add_cmd("northwest", None, cmd_move, "standing", "flying", "player", True, True)
+add_cmd("northeast", None, cmd_move, "standing", "flying", "player", True, True)
+add_cmd("southwest", None, cmd_move, "standing", "flying", "player", True, True)
+add_cmd("southeast", None, cmd_move, "standing", "flying", "player", True, True)
+add_cmd("nw",        None, cmd_move, "standing", "flying", "player", True, True)
+add_cmd("ne",        None, cmd_move, "standing", "flying", "player", True, True)
+add_cmd("sw",        None, cmd_move, "standing", "flying", "player", True, True)
+add_cmd("se",        None, cmd_move, "standing", "flying", "player", True, True)
+
+add_cmd("wake",      None, cmd_wake,"sleeping","sleeping", "player", True, True)
+add_cmd("sleep",     None, cmd_sleep,"sitting", "flying",  "player", True, True)
+add_cmd("stand",     None, cmd_stand,"sitting", "flying",  "player", True, True)
+add_cmd("land",      None, cmd_stand, "flying", "flying",  "player", True, True)
+add_cmd("sit",       None, cmd_sit, "standing", "flying",  "player", True, True)
+
+# The mud needs to know our command for movement as well
+set_cmd_move(cmd_move)
diff -ruN ../nakedmudv3.1/lib/pymodules/utils.py lib/pymodules/utils.py
--- ../nakedmudv3.1/lib/pymodules/utils.py	Wed Dec 31 17:00:00 1969
+++ lib/pymodules/utils.py	Sat Jul  1 20:07:04 2006
@@ -0,0 +1,114 @@
+################################################################################
+#
+# utils.py
+#
+# Various utility functions used by other Python modules.
+#
+################################################################################
+
+def parse_keywords(kw):
+    '''turns a comma-separated list of strings to a list of keywords'''
+    list = kw.lower().split(",")
+    for i in range(len(list)):
+        list[i] = list[i].strip()
+    return list
+
+def is_one_keyword(kw, word, abbrev_ok = False):
+    '''returns whether or not the single word is a keyword in the list'''
+    for one_kw in kw:
+        if word == one_kw:
+            return True
+        elif abbrev_ok and len(one_kw)>len(word) and one_kw[0:len(word)]==word:
+            return True
+    return False
+            
+def is_keyword(kw, word, abbrev_ok = False):
+    '''returns whether or not the word (or list of words) is a keyword'''
+    kw   = parse_keywords(kw)
+    word = parse_keywords(word)
+
+    for one_word in word:
+        if is_one_keyword(kw, one_word, abbrev_ok):
+            return True
+    return False
+
+def has_proto(ch, proto):
+    '''returns whether or not the character has on his or her person an object
+       that inherits from the given prototype'''
+    for obj in ch.inv + ch.eq:
+        if obj.isinstance(proto):
+            return True
+    return False
+
+def find_all_objs(looker, list, name, proto = None, must_see = True):
+    '''returns a list of all the objects that match the supplied constraints'''
+    found = []
+    for obj in list:
+        if must_see and not looker.cansee(obj):
+            continue
+        elif name != None and is_keyword(obj.keywords, name, True):
+            found.append(obj)
+        elif proto != None and obj.isinstance(proto):
+            found.append(obj)
+    return found
+
+def find_obj(looker, list, num, name, proto = None, must_see = True):
+    '''returns the numth object to match the supplied constraints'''
+    count = 0
+    for obj in list:
+        if must_see and not looker.cansee(obj):
+            continue
+        elif name != None and is_keyword(obj.keywords, name, True):
+            count = count + 1
+        elif proto != None and obj.isinstance(proto):
+            count = count + 1
+        if count == num:
+            return obj
+    return None
+
+def get_count(str):
+    '''separates a name and a count, and returns the two'''
+    parts = str.lower().split(".", 1)
+
+    # did we get two, or one?
+    if len(parts) == 1 and parts[0] == "all":
+        return "all", ""
+    elif len(parts) == 1:
+        return 1, str
+
+    if parts[0] == "all":
+        return "all", parts[1]
+    try:
+        return int(parts[0]), parts[1]
+    except:
+        return 1, str
+
+def show_list(ch, list, s_func, m_func = None):
+    '''shows a list of things to the character. s_func is the description if
+       there is only a single item of the type. m_func is the description if
+       there are multiple occurences of the thing in the list'''
+
+    # maps descriptions to counts
+    counts = { }
+
+    # build up our counts
+    for thing in list:
+        if counts.has_key(s_func(thing)):
+            counts[s_func(thing)] = counts[s_func(thing)] + 1
+        else:
+            counts[s_func(thing)] = 1
+
+    # print out our counts
+    for thing in list:
+        # only display > 0 counts. Otherwise it has been displayed
+        if counts.has_key(s_func(thing)):
+            count = counts.pop(s_func(thing))
+
+            # display our item(s)
+            if count == 1:
+                ch.send(s_func(thing))
+            elif m_func == None:
+                ch.send("(" + str(count) + ") " + s_func(thing))
+            else:
+                ch.send(m_func(thing) % count)
+        else: pass
