diff -ruN ../nakedmudv3.7.9/src/alias/alias.c src/alias/alias.c
--- ../nakedmudv3.7.9/src/alias/alias.c	2009-03-02 01:00:31.000000000 -0500
+++ src/alias/alias.c	2009-04-04 20:51:16.000000000 -0400
@@ -378,9 +378,16 @@
   add_cmd("alias", NULL, cmd_alias, "player", TRUE);
 
   // Python extensions
-  PyChar_addMethod("get_alias", PyChar_GetAlias,   METH_VARARGS, NULL);
-  PyChar_addMethod("set_alias", PyChar_SetAlias,   METH_VARARGS, NULL);
-  PyChar_addGetSetter("aliases",PyChar_GetAliases, NULL,         NULL);
+  PyChar_addMethod("get_alias", PyChar_GetAlias,   METH_VARARGS, 
+    "get_alias(name)\n"
+    "\n"
+    "Return character's alias by the specified name, or None.");
+  PyChar_addMethod("set_alias", PyChar_SetAlias,   METH_VARARGS, 
+    "set_alias(name, value)\n"
+    "\n"
+    "Set a character's alias. Value must be a string.");
+  PyChar_addGetSetter("aliases",PyChar_GetAliases, NULL, 
+    "A list of all aliases the character currently has defined. Immutable.");
 }
 
 
diff -ruN ../nakedmudv3.7.9/src/buffer.c src/buffer.c
--- ../nakedmudv3.7.9/src/buffer.c	2009-03-02 01:00:31.000000000 -0500
+++ src/buffer.c	2009-03-16 03:18:44.000000000 -0400
@@ -56,6 +56,12 @@
   buf->len += txtlen;
 }
 
+void        bufferCatCh (BUFFER *buf, const char ch) {
+  static char tmp[2];
+  tmp[0] = ch; tmp[1] = '\0';
+  bufferCat(buf, tmp);
+}
+
 void        bufferClear (BUFFER *buf) {
   *buf->data = '\0';
   buf->len = 0;
diff -ruN ../nakedmudv3.7.9/src/buffer.h src/buffer.h
--- ../nakedmudv3.7.9/src/buffer.h	2009-03-02 01:00:31.000000000 -0500
+++ src/buffer.h	2009-03-16 03:18:44.000000000 -0400
@@ -18,6 +18,7 @@
 
 // concatinate the text to the end of the buffer
 void        bufferCat   (BUFFER *buf, const char *txt);
+void        bufferCatCh (BUFFER *buf, const char ch);
 
 // clear the buffer's contents
 void bufferClear(BUFFER *buf);
diff -ruN ../nakedmudv3.7.9/src/event.h src/event.h
--- ../nakedmudv3.7.9/src/event.h	2006-07-08 21:51:45.000000000 -0400
+++ src/event.h	2009-03-17 17:07:14.000000000 -0400
@@ -49,8 +49,7 @@
 // check_involvement must be a function that takes the thing to check
 // the involvement of as the first argument, and the data to check in
 // as its second argument. It must return TRUE if the data contains
-// a pointer to the thing, and FALSE otherwise. See admin.c (cmd_devent)
-// for an example of how this works. 
+// a pointer to the thing, and FALSE otherwise.
 //
 void start_event(void *owner, 
 		 int   delay,
diff -ruN ../nakedmudv3.7.9/src/handler.c src/handler.c
--- ../nakedmudv3.7.9/src/handler.c	2009-03-02 01:00:32.000000000 -0500
+++ src/handler.c	2009-03-21 02:12:00.000000000 -0400
@@ -489,17 +489,30 @@
 //*****************************************************************************
 // functions related to equipping and unequipping items
 //*****************************************************************************
+
+//
+// if we're equipping by the specific name of positions, by_name should be TRUE.
+// If instead we are equipping by the TYPE of position, by_name should be FALSE
+bool do_equip(CHAR_DATA *ch, OBJ_DATA *obj, const char *pos, bool by_name) {
+  if((by_name  && bodyEquipPosnames(charGetBody(ch), obj, pos)) ||
+     (!by_name && bodyEquipPostypes(charGetBody(ch), obj, pos))) {
+    objSetWearer(obj, ch);
+    return TRUE;
+  }
+  return FALSE;
+}
+
 bool try_equip(CHAR_DATA *ch, OBJ_DATA *obj, const char *wanted_pos,
 	       const char *required_pos) {
   bool success = FALSE;
 
   // if we don't need any specific places, try equipping to our wanted spots
   if(!required_pos || !*required_pos)
-    success = bodyEquipPosnames(charGetBody(ch), obj, wanted_pos);
+    success = do_equip(ch, obj, wanted_pos, TRUE);
 
   // if we don't want any specific places, equip to whatever is open
   else if(!wanted_pos || !*wanted_pos)
-    success = bodyEquipPostypes(charGetBody(ch), obj, required_pos);
+    success = do_equip(ch, obj, required_pos, FALSE);
 
   // otherwise, see if the places we want to equip to match what we need,
   // and also make sure we're not trying to equip the same position twice
@@ -539,15 +552,16 @@
 
     // if we didn't run into problems, try equipping
     if(match == TRUE)
-      success = bodyEquipPosnames(charGetBody(ch), obj, wanted_pos);
+      success = do_equip(ch, obj, wanted_pos, TRUE);
   }
 
   if(success == TRUE)
-    objSetWearer(obj, ch);
+    hookRun("equip", hookBuildInfo("ch obj", ch, obj));
+
   return success;
 }
 
-bool try_unequip(CHAR_DATA *ch, OBJ_DATA *obj) {
+bool do_unequip(CHAR_DATA *ch, OBJ_DATA *obj) {
   if(bodyUnequip(charGetBody(ch), obj)) {
     objSetWearer(obj, NULL);
     return TRUE;
@@ -555,6 +569,22 @@
   return FALSE;
 }
 
+bool try_unequip(CHAR_DATA *ch, OBJ_DATA *obj) {
+  if(objGetWearer(obj) == ch) {
+    hookRun("pre_unequip", hookBuildInfo("ch obj", ch, obj));
+
+    // if wearer == ch, this should never fail
+    bool success = do_unequip(ch, obj);
+
+    if(success == TRUE)
+      hookRun("unequip", hookBuildInfo("ch obj", ch, obj));
+    else
+      log_string("ERROR: failed to unequip obj when wearer == ch");
+    return success;
+  }
+  return FALSE;
+}
+
 //
 // unequip everything the character is wearing, and put it to his or her inv
 //
@@ -562,10 +592,8 @@
   LIST      *eq = bodyGetAllEq(charGetBody(ch));
   OBJ_DATA *obj = NULL;
   while( (obj = listPop(eq)) != NULL) {
-    if(bodyUnequip(charGetBody(ch), obj)) {
-      objSetWearer(obj, NULL);
+    if(do_unequip(ch, obj))
       obj_to_char(obj, ch);
-    }
   } deleteList(eq);
 }
 
diff -ruN ../nakedmudv3.7.9/src/handler.h src/handler.h
--- ../nakedmudv3.7.9/src/handler.h	2008-12-03 15:19:26.000000000 -0500
+++ src/handler.h	2009-03-21 02:12:56.000000000 -0400
@@ -69,9 +69,12 @@
 void      char_from_furniture (CHAR_DATA *ch);
 void      char_to_furniture   (CHAR_DATA *ch, OBJ_DATA *furniture);
 
+bool      do_equip          (CHAR_DATA *ch, OBJ_DATA *obj, const char *pos, 
+			     bool by_name);
 bool      try_equip         (CHAR_DATA *ch, OBJ_DATA *obj, 
 			     const char *wanted_pos, const char *required_pos);
 bool      try_unequip       (CHAR_DATA *ch, OBJ_DATA *obj);
+bool      do_unequip        (CHAR_DATA *ch, OBJ_DATA *obj);
 void      unequip_all       (CHAR_DATA *ch);
 
 
diff -ruN ../nakedmudv3.7.9/src/help2/help.c src/help2/help.c
--- ../nakedmudv3.7.9/src/help2/help.c	2009-03-02 01:00:32.000000000 -0500
+++ src/help2/help.c	2009-04-05 15:46:23.000000000 -0400
@@ -227,9 +227,10 @@
   char            *kwd = NULL;
   ITERATE_LIST(kwd, kwd_i) {
     // remove any old copy we might of had
-    HELP_DATA *old = nearMapRemove(help_table, kwd);
-    if(old != NULL)
-      deleteHelp(old);
+    // HELP_DATA *old = nearMapRemove(help_table, kwd);
+    // if(old != NULL)
+    //   deleteHelp(old);
+    nearMapRemove(help_table, kwd);
     
     // put our new entry
     nearMapPut(help_table, kwd, NULL, data);
@@ -453,9 +454,14 @@
 
   // add all of our Python hooks
   PyMudSys_addMethod("add_help", PyMudSys_add_help, METH_VARARGS, 
-		     "allows Python modules to add non-persistent helpfiles.");
-  PyMudSys_addMethod("get_help", PyMudSys_get_help, METH_VARARGS, 
-		     "returns info for the help file.");
+    "add_help(keywords, info, user_groups='', related='')\n\n"
+    "Add a new, non-persistent helpfile to the mud's help database.");
+  PyMudSys_addMethod("get_help", PyMudSys_get_help, METH_VARARGS,
+    "get_help(keyword)\n\n"
+    "Returns a tuple of a helpfile's keywords, info, user_groups, and related\n"
+    "or None if the helpfile does not exist.");
   PyMudSys_addMethod("list_help", PyMudSys_list_help, METH_VARARGS,
-		     "Returns all help topics. If a partial keyword is supplied, only return partial matches.");
+    "list_help(keyword='')\n\n"
+    "Returns a list of helpfiles that match the specified keyword. If no\n"
+    "keywordi s supplied, return all helpfiles.");
 }
diff -ruN ../nakedmudv3.7.9/src/inform.h src/inform.h
--- ../nakedmudv3.7.9/src/inform.h	2006-07-08 21:51:45.000000000 -0400
+++ src/inform.h	2009-03-14 21:18:38.000000000 -0400
@@ -29,8 +29,8 @@
 // Send a message out
 //
 // Converts the following symbols:
-//  $c = ch name
-//  $C = vict name
+//  $n = ch name
+//  $N = vict name
 //  $m = him/her of char
 //  $M = him/her of vict
 //  $s = his/hers of char
diff -ruN ../nakedmudv3.7.9/src/items/container.c src/items/container.c
--- ../nakedmudv3.7.9/src/items/container.c	2008-12-03 04:15:08.000000000 -0500
+++ src/items/container.c	2009-04-04 22:42:26.000000000 -0400
@@ -523,22 +523,24 @@
   // set up the container OLC too
   item_add_olc("container", iedit_container_menu, iedit_container_chooser, 
   	       iedit_container_parser, NULL, container_to_proto);
+
+  // set up our Python extensions
   PyObj_addGetSetter("container_capacity",
-		     PyObj_getcontainercapacity, PyObj_setcontainercapacity,
-		     "Sets the maximum amount of weight the container holds.");
+    PyObj_getcontainercapacity, PyObj_setcontainercapacity,
+    "The maximum amount of weight c container can hold.");
   PyObj_addGetSetter("container_key", 
-		     PyObj_getcontainerkey, PyObj_setcontainerkey,
-		     "The key that opens the container.");
+    PyObj_getcontainerkey, PyObj_setcontainerkey,
+    "An object prototype that acts as a key for this container.");
   PyObj_addGetSetter("container_pick_diff",
-		     PyObj_getcontainerpickdiff, PyObj_setcontainerpickdiff,
-		     "The picking difficulty of the container,");
+    PyObj_getcontainerpickdiff, PyObj_setcontainerpickdiff,
+    "An integer representing how difficult a container's lock is to pick.");
   PyObj_addGetSetter("container_is_closable", 
-		     PyObj_getcontainerclosable, PyObj_setcontainerclosable,
-		     "true or false if the container can be closed.");
+    PyObj_getcontainerclosable, PyObj_setcontainerclosable,
+    "True or False if the container can be closed.");
   PyObj_addGetSetter("container_is_closed", 
-		     PyObj_getcontainerclosed, PyObj_setcontainerclosed,
-		      "true or false if the container is closed.");
+    PyObj_getcontainerclosed, PyObj_setcontainerclosed,
+    "True or False if the container is closed.");
   PyObj_addGetSetter("container_is_locked", 
-		     PyObj_getcontainerlocked, PyObj_setcontainerlocked,
-		      "true or false if the container is locked.");
+    PyObj_getcontainerlocked, PyObj_setcontainerlocked,
+    "True or False if the container is locked.");
 }
diff -ruN ../nakedmudv3.7.9/src/items/furniture.c src/items/furniture.c
--- ../nakedmudv3.7.9/src/items/furniture.c	2008-12-03 04:15:37.000000000 -0500
+++ src/items/furniture.c	2009-04-04 22:46:03.000000000 -0400
@@ -312,8 +312,8 @@
 
   // add our getters and setters for furniture
   PyObj_addGetSetter("furniture_capacity", 
-		     PyObj_getfurncapacity, PyObj_setfurncapacity,
-		     "The capacity of a furniture object.");
+    PyObj_getfurncapacity, PyObj_setfurncapacity,
+    "The number of characters a furniture object can accomodate.");
   PyObj_addGetSetter("furniture_type", PyObj_getfurntype, PyObj_setfurntype,
-		     "The type of furniture this is: 'at' or 'on'.");
+    "The type of furniture this is: 'at' or 'on' like e.g., tables vs. couches.");
 }
diff -ruN ../nakedmudv3.7.9/src/items/items.c src/items/items.c
--- ../nakedmudv3.7.9/src/items/items.c	2009-03-02 01:00:38.000000000 -0500
+++ src/items/items.c	2009-04-04 22:37:51.000000000 -0400
@@ -341,11 +341,20 @@
     return NULL;
   }
 
+  // make sure the object exists
+  if(obj == NULL) {
+    PyErr_Format(PyExc_TypeError, "Tried to get type data for non-existent object.");
+    return NULL;
+  }
+
   // make sure it's Python data
   fdata = hashGet(type_table, type);
   if(fdata == NULL || fdata->type == ITYPE_C)
-    return Py_BuildValue("O", Py_None);
-  return Py_BuildValue("O", objGetTypeData(obj, type));
+    return Py_BuildValue("");
+  
+  // make sure this item actually has the relevant type data
+  PyObject *tdata = objGetTypeData(obj, type);
+  return Py_BuildValue("O", (tdata == NULL ? Py_None : tdata));
 }
 
 PyObject *PyObj_istype(PyObject *self, PyObject *args) {  
@@ -420,17 +429,27 @@
 
   // initialize Python mudsys methods
   PyMudSys_addMethod("item_add_type", PyMudSys_ItemAddType, METH_VARARGS,
-		     "add a new type of item to the game");
+		     "item_add_type(name, type_data)\n"
+		     "\n"
+		     "Register a new item type and its data.");
 
   // initialize Python pyobj methods
   PyObj_addMethod("get_type_data", PyObj_GetTypeData, METH_VARARGS,
-		  "Returns the Python data associated with the item type.");
+    "get_type_data(item_type)\n"
+    "\n"
+    "Returns Python item type data if it exists, or None.");
   PyObj_addMethod("istype", PyObj_istype, METH_VARARGS,
-		  "checks to see if the object is of the specified type");
+    "istype(item_type)\n"
+    "\n"
+    "Returns True or False if the object is of the specified item type.");
   PyObj_addMethod("settype", PyObj_settype, METH_VARARGS,
-		  "the object will become of the specified type");
+    "settype(item_type)\n"
+    "\n"
+    "Make an object be the specified item type.");
   PyObj_addMethod("get_types", PyObj_get_types, METH_NOARGS,
-		  "returns a list of the types this object is");
+    "get_types()\n"
+    "\n"
+    "Returns a comma-separated list of item types this object has.");
   // do we need a deltype as well?
   //***********
   // FINISH ME
diff -ruN ../nakedmudv3.7.9/src/items/portal.c src/items/portal.c
--- ../nakedmudv3.7.9/src/items/portal.c	2009-03-02 01:00:38.000000000 -0500
+++ src/items/portal.c	2009-04-04 22:44:46.000000000 -0400
@@ -399,13 +399,14 @@
 
   // make it so we can set portal destinations in scripts
   PyObj_addGetSetter("portal_dest", PyObj_getportaldest, PyObj_setportaldest,
-		     "the database key of the room we're going to.");
+    "A string key specifying the destination of the portal. Can be set by\n"
+    "a string or the actual room.");
   PyObj_addGetSetter("portal_enter_mssg", 
-		     PyObj_getportalentermssg, PyObj_setportalentermssg,
-		     "The message shown when user enters a new room.");
+    PyObj_getportalentermssg, PyObj_setportalentermssg,
+    "The message shown to the desination room when a character enters portal.");
   PyObj_addGetSetter("portal_leave_mssg", 
-		     PyObj_getportalleavemssg, PyObj_setportalleavemssg,
-		     "The message shown when user leaves a room.");
+    PyObj_getportalleavemssg, PyObj_setportalleavemssg,
+    "The message shown to a room after a character leaves it via a portal.");
 
   add_cmd("enter", NULL, cmd_enter, "player", TRUE);
   add_cmd_check("enter", chk_can_move);
diff -ruN ../nakedmudv3.7.9/src/items/worn.c src/items/worn.c
--- ../nakedmudv3.7.9/src/items/worn.c	2009-03-02 12:39:03.000000000 -0500
+++ src/items/worn.c	2009-04-04 22:48:45.000000000 -0400
@@ -330,11 +330,15 @@
 
   // add our new python get/setters
   PyObj_addGetSetter("worn_locs", PyObj_getwornlocs, NULL,
-		     "The positions this item must be equipped to.");
+    "The position names this worn type must be equipped to. Immutable.");
   PyObj_addGetSetter("worn_type", PyObj_getworntype, PyObj_setworntype,
-		     "The type of clothing this wearable item is.");
+    "The type of worn item this is.");
   PyMudSys_addMethod("add_worn_type", PyMudSys_AddWornType, METH_VARARGS,
-		     "Adds a new worn type to the game.");
+    "add_worn_type(type, postypes)\n"
+    "\n"
+    "Register a new type of worn item. Postypes is a comma-separated list of\n"
+    "body position types this object must be equipped to e.g., \n"
+    "shirt : torso, arm, arm.");
   
   // add in our basic worn types
   worn_add_type("shirt",              "torso, arm, arm");
diff -ruN ../nakedmudv3.7.9/src/olc2/redit.c src/olc2/redit.c
--- ../nakedmudv3.7.9/src/olc2/redit.c	2009-03-02 01:00:38.000000000 -0500
+++ src/olc2/redit.c	2009-03-03 17:26:20.000000000 -0500
@@ -301,10 +301,10 @@
     text_to_buffer(sock, "What is the success chance of the reset: ");
     return RESEDIT_CHANCE;
   case '4':
-    text_to_buffer(sock, "What is the max that can exit in game (0 = no limit): ");
+    text_to_buffer(sock, "What is the max that can exist in game (0 = no limit): ");
     return RESEDIT_MAX;
   case '5':
-    text_to_buffer(sock, "What is the max that can exit in room (0 = no limit): ");
+    text_to_buffer(sock, "What is the max that can exist in room (0 = no limit): ");
     return RESEDIT_ROOM_MAX;
   case '6':
     if(resetGetType(data->reset) == RESET_SCRIPT) {
@@ -560,7 +560,7 @@
     text_to_buffer(sock, "Enter a new leave message: ");
     return EXEDIT_LEAVE;
   case '4':
-    text_to_buffer(sock, "Enter a new enterance message: ");
+    text_to_buffer(sock, "Enter a new entrance message: ");
     return EXEDIT_ENTER;
   case '5':
     socketStartEditor(sock, text_editor, exitGetDescBuffer(exit));
diff -ruN ../nakedmudv3.7.9/src/olc2/zedit.c src/olc2/zedit.c
--- ../nakedmudv3.7.9/src/olc2/zedit.c	2009-03-02 01:00:38.000000000 -0500
+++ src/olc2/zedit.c	2009-03-04 22:32:24.000000000 -0500
@@ -168,6 +168,8 @@
 
     if(locale_malformed(key))
       send_to_char(ch, "The zone name you entered was malformed.");
+    else if(!strcasecmp(arg, "new"))
+      send_to_char(ch, "'new' is not a valid zone name.");
     else if(worldGetZone(gameworld, key))
       send_to_char(ch, "A zone already exists with that key.\r\n");
     else {
diff -ruN ../nakedmudv3.7.9/src/save.c src/save.c
--- ../nakedmudv3.7.9/src/save.c	2009-03-02 01:00:39.000000000 -0500
+++ src/save.c	2009-03-21 02:09:10.000000000 -0400
@@ -163,7 +163,7 @@
   while( (obj_set = storage_list_next(list)) != NULL) {
     if(storage_contains(obj_set, "object")) {
       obj = objRead(read_set(obj_set, "object"));
-      if(!try_equip(ch, obj, read_string(obj_set, "equipped"), NULL))
+      if(!do_equip(ch, obj, read_string(obj_set, "equipped"), TRUE))
 	obj_to_char(obj, ch);
     }
   }
diff -ruN ../nakedmudv3.7.9/src/scripts/pyaccount.c src/scripts/pyaccount.c
--- ../nakedmudv3.7.9/src/scripts/pyaccount.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pyaccount.c	2009-04-05 12:41:52.000000000 -0400
@@ -280,17 +280,21 @@
 
     // add all of the basic getsetters
     PyAccount_addGetSetter("name", PyAccount_getname, NULL, 
-			   "the account's name.");
+			   "The account's name. Immutable.");
 
     // add all of the basic methods
     PyAccount_addMethod("add_char", PyAccount_add_char, METH_VARARGS,
-			"adds a character to the account.");
+      "add_char(name_or_char)\n\n"
+      "Adds a new character to an account's list of registered characters.");
     PyAccount_addMethod("characters", PyAccount_characters, METH_VARARGS,
-			"lists names of all characters tied to the account.");
+      "characters()\n\n"
+      "Returns a list of names for characters registered to the account.");
     PyAccount_addMethod("getAuxiliary", PyAccount_get_auxiliary, METH_VARARGS,
-			"gets the account auxiliary data with given key.");
+      "getAuxiliary(name)\n"
+      "\n"
+      "Returns account's auxiliary data of the specified name.");
     PyAccount_addMethod("aux", PyAccount_get_auxiliary, METH_VARARGS,
-			"gets the account auxiliary data with given key.");
+      "Alias for account.Account.getAuxiliary.");
 
     // add in all the getsetters and methods
     makePyType(&PyAccount_Type, pyaccount_getsetters, pyaccount_methods);
@@ -303,8 +307,7 @@
 
     // initialize the module
     module = Py_InitModule3("account", account_module_methods,
-			    "The account module, for all MUD account-related "
-			    "stuff.");
+			    "Contains the Python wrapper for accounts.");
 
     // make sure the module parsed OK
     if (module == NULL)
diff -ruN ../nakedmudv3.7.9/src/scripts/pyauxiliary.c src/scripts/pyauxiliary.c
--- ../nakedmudv3.7.9/src/scripts/pyauxiliary.c	2008-12-19 15:55:12.000000000 -0500
+++ src/scripts/pyauxiliary.c	2009-04-05 00:41:50.000000000 -0400
@@ -136,14 +136,20 @@
   }
 
   // parse the data types that this auxiliary data installs to
-  if(is_keyword(installs_on, "character", FALSE))
+  if(is_keyword(installs_on, "character", FALSE) ||
+     is_keyword(installs_on, "char",      FALSE))
     SET_BIT(type, AUXILIARY_TYPE_CHAR);
   if(is_keyword(installs_on, "room",      FALSE))
     SET_BIT(type, AUXILIARY_TYPE_ROOM);
-  if(is_keyword(installs_on, "object",    FALSE))
+  if(is_keyword(installs_on, "object",    FALSE) ||
+     is_keyword(installs_on, "obj",       FALSE))
     SET_BIT(type, AUXILIARY_TYPE_OBJ);
-  if(is_keyword(installs_on, "account",   FALSE))
+  if(is_keyword(installs_on, "account",   FALSE) ||
+     is_keyword(installs_on, "acct",      FALSE))
     SET_BIT(type, AUXILIARY_TYPE_ACCOUNT);
+  if(is_keyword(installs_on, "socket",    FALSE) ||
+     is_keyword(installs_on, "sock",      FALSE))
+    SET_BIT(type, AUXILIARY_TYPE_SOCKET);
   // more types to come soon!!
   //***********
   // FINISH ME
@@ -164,10 +170,23 @@
 
 PyMethodDef pyauxiliary_module_methods[] = {
   { "install", PyAuxiliary_install, METH_VARARGS,
-    "installs new python auxiliary data into the mud. Auxiliary Data must "
-    "take the form of an uninstanced class that has a ClassXXX(set = None) "
-    "init function, a copy() function, a copyTo(to) function, and a store() "
-    "function" },
+    "install(name, AuxClass, installs_on)\n\n"
+    "Register new auxiliary data to the given name. Auxiliary data can be\n"
+    "installed on: character, object, room, account, socket. Auxiliary data\n"
+    "must be a class object of the following form:\n\n"
+    "  class ClassName:\n"
+    "    def __init__(self, storage_set = None)\n"
+    "      ...\n\n"
+    "    def copy(self)\n"
+    "      ...\n\n"
+    "    def copyTo(self, to)\n"
+    "      ...\n\n"
+    "    def store(self)\n"    
+    "      ...\n\n"
+    "The Store method returns a storage set representation of the data. If\n"
+    "the auxiliary data is not persistent, an empty storage set can be\n"
+    "returned. The class's init function must be able to handle reading in\n"
+    "data from a storage set, or creating a fresh instance if set = None.\n" },
   {NULL, NULL, 0, NULL}  /* Sentinel */
 };
 
diff -ruN ../nakedmudv3.7.9/src/scripts/pychar.c src/scripts/pychar.c
--- ../nakedmudv3.7.9/src/scripts/pychar.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pychar.c	2009-04-05 16:39:24.000000000 -0400
@@ -33,6 +33,7 @@
 #include "pyexit.h"
 #include "pyaccount.h"
 #include "pyauxiliary.h"
+#include "pystorage.h"
 
 
 
@@ -479,6 +480,8 @@
     charSetWeight(ch, 0.0);
   else if(PyFloat_Check(value))
     charSetWeight(ch, PyFloat_AsDouble(value));
+  else if(PyInt_Check(value))
+    charSetWeight(ch, PyInt_AsLong(value));
   else {
     PyErr_Format(PyExc_TypeError,
 		"Tried to change char %d's weight to an invalid type.",
@@ -734,7 +737,7 @@
 
   CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
   if(ch) {
-    send_to_char(ch, "%s", mssg);
+    text_to_char(ch, mssg);
     return Py_BuildValue("i", 1);
   }
   else {
@@ -746,22 +749,71 @@
 }
 
 //
-// sends a newline-tagged message to the character
-PyObject *PyChar_send(PyChar *self, PyObject *value) {
-  PyObject *retval = PyChar_send_raw(self, value);
-  if(retval == NULL)
+// Send a message with Python statements potentially embedded in it. For 
+//evaluating 
+PyObject *PyChar_send(PyObject *self, PyObject *args, PyObject *kwds) {
+  static char *kwlist[] = { "mssg", "dict", "newline", NULL };
+  CHAR_DATA  *me = NULL;
+  char     *text = NULL;
+  PyObject *dict = NULL;
+  bool   newline = TRUE;
+
+  if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|Ob", kwlist, 
+				  &text, &dict, &newline)) {
+    PyErr_Format(PyExc_TypeError, "Char.send takes a message, a dictionary, and possibly a newline option.");
     return NULL;
-  CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
-  send_to_char(ch, "\r\n");
-  Py_DECREF(retval);
-  return Py_BuildValue("i", 1);
+  }
+
+  // make sure the dictionary is a dictionary
+  if(dict != NULL && !(PyDict_Check(dict) || dict == Py_None)) {
+    PyErr_Format(PyExc_TypeError, "char.send expects second argument to be a dict object.");
+    return NULL;
+  }
+  
+  // make sure we exist
+  if( (me = PyChar_AsChar(self)) == NULL) {
+    PyErr_Format(PyExc_TypeError, "Tried to send nonexistant character.");
+    return NULL;
+  }
+
+  // the text we are sending
+  BUFFER *buf = newBuffer(1);
+  bprintf(buf, "%s%s", text, (newline ? "\r\n" : ""));
+  
+  // are we sending as-is, or expanding embedded statements?
+  if(dict != NULL) {
+    // build the script dictionary
+    PyObject *script_dict = restricted_script_dict();
+    if(dict != Py_None)
+      PyDict_Update(script_dict, dict);
+    PyDict_SetItemString(script_dict, "me", self);
+
+    // do the expansion
+    expand_dynamic_descs_dict(buf, script_dict, get_script_locale());
+
+    // garbage collection and end
+    Py_XDECREF(script_dict);
+  }
+
+  // send the message
+  text_to_char(me, bufferString(buf));
+
+  // build the return value
+  PyObject *ret = Py_BuildValue("s", bufferString(buf));
+
+  // garbage collection
+  deleteBuffer(buf);
+
+  // return the value
+  return ret;
 }
 
 //
 // Send a newline-tagged message to everyone around the character
 PyObject *PyChar_sendaround(PyChar *self, PyObject *value) {
-  char *mssg = NULL;
-  if (!PyArg_ParseTuple(value, "s", &mssg)) {
+  char   *mssg = NULL;
+  bool newline = TRUE;
+  if (!PyArg_ParseTuple(value, "s|b", &mssg, &newline)) {
     PyErr_Format(PyExc_TypeError, 
                     "Characters may only be sent strings");
     return NULL;
@@ -769,7 +821,7 @@
 
   CHAR_DATA *ch = PyChar_AsChar((PyObject *)self);
   if(ch) {
-    send_around_char(ch, FALSE, "%s\r\n", mssg);
+    send_around_char(ch, FALSE, "%s%s", mssg, (newline ? "\r\n" : ""));
     return Py_BuildValue("i", 1);
   }
   else {
@@ -1519,6 +1571,30 @@
   }
 }
 
+PyObject *PyChar_store(PyObject *self, void *closure) {
+  CHAR_DATA *ch = PyChar_AsChar(self);
+  if(ch == NULL) {
+    PyErr_Format(PyExc_TypeError, "failed to store nonexistent character.");
+    return NULL;
+  }
+  return newPyStorageSet(charStore(ch));
+}
+
+PyObject *PyChar_copy(PyObject *self, void *closure) {
+  CHAR_DATA *ch = PyChar_AsChar(self);
+  if(ch == NULL) {
+    PyErr_Format(PyExc_TypeError, "failed to copy nonexistent character.");
+    return NULL;
+  }
+  CHAR_DATA *newch = charCopy(ch);
+
+  // we have to put the object in the global tables and list, 
+  // or else Python will not be able to access it
+  char_to_game(newch);
+
+  return charGetPyForm(newch);
+}
+
 
 
 //*****************************************************************************
@@ -1783,6 +1859,22 @@
   return list;
 }
 
+PyObject *PyChar_read(PyObject *self, PyObject *args) {
+  PyObject *pyset = NULL;
+  if(!PyArg_ParseTuple(args, "O", &pyset)) {
+    PyErr_Format(PyExc_TypeError, "failed to read character from storage set.");
+    return NULL;
+  }
+  else if(!PyStorageSet_Check(pyset)) {
+    PyErr_Format(PyExc_TypeError, "storage set must be supplied to read.");
+    return NULL;
+  }
+
+  CHAR_DATA *ch = charRead(PyStorageSet_AsSet(pyset));
+  char_to_game(ch);
+  return Py_BuildValue("O", charGetPyFormBorrowed(ch));
+}
+
 PyObject *PyChar_is_abstract(PyObject *self, PyObject *args) {
   char     *mob_key = NULL;
   if (!PyArg_ParseTuple(args, "s", &mob_key)) {
@@ -1800,18 +1892,33 @@
 }
 
 PyMethodDef char_module_methods[] = {
+  { "read",     PyChar_read, METH_VARARGS,
+    "read(storage_set)\n"
+    "\n"
+    "Read and return a character from a storage set." },
   { "char_list", (PyCFunction)PyChar_all_chars, METH_NOARGS,
-    "Return a python list containing an entry for every character in game." },
+    "char_list()\n"
+    "\n"
+    "Return a list of every character in game." },
   { "load_mob", PyChar_load_mob, METH_VARARGS,
-    "load a mobile with the specified prototype to a room." },
+    "load_mob(proto, room, pos = 'standing')\n"
+    "\n"
+    "Generate a new mobile from the specified prototype. Add it to the\n"
+    "given room. Return the created mobile." },
   { "count_mobs", PyChar_count_mobs, METH_VARARGS,
-    "count how many occurances of a mobile there are in the specified scope. "
-    "prototype or name can be used." },
+    "count_mobs(keyword, loc = None)\n"
+    "\n"
+    "count how many occurences of a mobile with the specified keyword, uid,\n"
+    "or prototype exist at a location. If loc is None, search the entire mud.\n"
+    "Loc can be a room, room prototype, or furniture object." },
   { "find_char_key", PyChar_find_char_key, METH_VARARGS,
-    "finds a character (or group of chars) by their prototype. Finding by "
-    "keywords is done with generic_find()" },
+    "Function has been deprecated. Entrypoint for generic_find()\n"
+    "Use mud.parse_args instead."  },
   { "is_abstract",   PyChar_is_abstract, METH_VARARGS,
-    "Returns whether a mob with the specified prototype is abstract." },
+    "is_abstract(proto)\n"
+    "\n"
+    "Returns whether a specified mob prototype is abstract. Also return True\n"
+    "if the prototype does not exist." },
   {NULL, NULL, 0, NULL}  /* Sentinel */
 };
 
@@ -1854,141 +1961,231 @@
 
   // add in our setters and getters for the char class
   PyChar_addGetSetter("inv", PyChar_getinv, NULL,
-		      "returns a list of objects in the char's inventory");
+    "An immutable list of objects in the character's inventory.\n"
+    "See obj.Obj.carrier for altering an item's carrier.");
   PyChar_addGetSetter("objs", PyChar_getinv, NULL,
-		      "returns a list of objects in the char's inventory");
+    "An alias for inv to be consistent with how room and object contents are\n"
+    "accessed.");
   PyChar_addGetSetter("eq",   PyChar_geteq,  NULL,
-		      "returns a list of the character's equipment.");
+    "An immutable list of the character's worn equipment.\n"
+    "See equip() and unequip() for altering a characters worn items.");
   PyChar_addGetSetter("bodyparts", PyChar_getbodyparts, NULL,
-		      "Returns a list of the character's bodyparts");
+    "An immutable list naming all of the character's bodyparts.");
   PyChar_addGetSetter("name", PyChar_getname, PyChar_setname,
-		      "handle the character's name");
+    "The characer's name, e.g., Grunald the Baker.");
   PyChar_addGetSetter("mname", PyChar_getmname, PyChar_setmname,
-		      "handle the character's multi-name");
+    "The character's name for describing packs, e.g.,\n"
+    "a horde of 9001 mosquitos. The number should be replaced by %d, or not\n"
+    "included.");
   PyChar_addGetSetter("desc", PyChar_getdesc, PyChar_setdesc,
-		      "handle the character's description");
+    "A character's verbose description for e.g., when they are looked at.");
   PyChar_addGetSetter("look_buf", PyChar_getlookbuf, PyChar_setlookbuf,
-		      "handle the character's look buffer");
+    "When characters look at something, the thing's description is copied to\n"
+    "the character's look buffer for processing before being sent.");
   PyChar_addGetSetter("rdesc", PyChar_getrdesc, PyChar_setrdesc,
-		      "handle the character's room description");
+    "The character's description when seen in a room, e.g., \n"
+    "Bob is here, baking a cake.");
   PyChar_addGetSetter("mdesc", PyChar_getmdesc, PyChar_setmdesc,
-		      "handle the character's multi room description");
+    "The equivalent of mname, for room descriptions.");
   PyChar_addGetSetter("keywords", PyChar_getkeywords, PyChar_setkeywords,
-		      "comma-separated list of the character's keywords.");
+    "A comma-separated list of the keywords for referencing the character.");
   PyChar_addGetSetter("sex", PyChar_getsex, PyChar_setsex,
-		      "handle the character's gender");
+    "The character's sex. Can be male, female, or neutral.");
   PyChar_addGetSetter("gender", PyChar_getsex, PyChar_setsex,
-		      "handle the character's gender");
+    "Alias for char.Char.sex");
   PyChar_addGetSetter("race", PyChar_getrace, PyChar_setrace,
-		      "handle the character's race");
+    "The character's race.");
   PyChar_addGetSetter("pos", PyChar_getposition, PyChar_setposition,
-		      "handle the character's position");
+    "Alias for char.Char.position.");
   PyChar_addGetSetter("position", PyChar_getposition, PyChar_setposition,
-		      "handle the character's position");
+    "The character's current position (e.g., standing, sleeping, sitting).");
   PyChar_addGetSetter("room", PyChar_getroom, PyChar_setroom,
-		      "handle the character's room");
+    "The current room a character is in. Can be set by room or room key.");
   PyChar_addGetSetter("last_room", PyChar_getlastroom, NULL,
-		      "the last room the character was in");
+    "The last room a character was in. Immutable. Value is None if character\n"
+    "was not previously in a room.");
   PyChar_addGetSetter("on", PyChar_geton, PyChar_seton,
-   "The furniture the character is sitting on/at. If the character is not "
-   "on furniture, None is returned. To remove a character from furniture, "
-  "then use None");
+   "The furniture the character is sitting on/at. Value is None if character\n"
+   "is not currently on furniture. Set value to None to remove a character\n"
+   "from their furniture.");
   PyChar_addGetSetter("uid", PyChar_getuid, NULL,
-		      "the character's unique identification number");
+    "The character's unique identification number. Immutable.");
   PyChar_addGetSetter("prototypes", PyChar_getprototypes, NULL,
-		      "The prototypes for a mobile");
+   "A comma-separated list of prototypes the mobile inherits from. Immutable.");
   PyChar_addGetSetter("mob_class", PyChar_getclass, NULL,
-		      "The main prototype of the mobile.");
+    "The main prototype the mobile inherits from. Immutable.");
   PyChar_addGetSetter("is_npc", PyChar_getisnpc, NULL,
-		      "Returns 1 if the char is an NPC, and 0 otherwise.");
+    "Value is True if character is an NPC, and False otherwise. Immutable.");
   PyChar_addGetSetter("is_pc", PyChar_getispc, NULL,
-		      "Returns 1 if the char is a PC, and 0 otherwise.");
+    "Value is negation of char.Char.is_npc");
   PyChar_addGetSetter("hisher", PyChar_gethisher, NULL,
-		      "Returns 'his' if the char is male, 'her' if female, and "
-		      "'its' for neuters");
+    "Value is 'his', 'her', or 'its'. Immutable.");
   PyChar_addGetSetter("himher", PyChar_gethimher, NULL,
-		      "Returns 'him' if the char is male, 'her' if female, and "
-		      "'it' for neuters");
+    "Value is 'him', 'her', or 'it'. Immutable.");
   PyChar_addGetSetter("heshe", PyChar_getheshe, NULL,
-		      "Returns 'he' if the char is male, 'she' if female, and "
-		      "'it' for neuters");
+    "Value is 'he', 'she', or 'it'. Immutable.");
   PyChar_addGetSetter("user_groups", PyChar_getusergroups, NULL,
-		      "Returns the character's user groups");
+    "A comma-separated list of user groups the character belongs to.\n"
+    "Use char.Char.isInGroup(group) to check for a specific group. Immutable.");
   PyChar_addGetSetter("socket", PyChar_getsocket, NULL,
-		      "Returns the character's socket if it exists.");
+    "The current socket this character is attached to. Value is None if \n"
+    "socket does not exist. Immutable. Use mudsys.attach_char_socket to \n"
+    "attach a character and socket to each other.");
   PyChar_addGetSetter("sock",   PyChar_getsocket, NULL,
-		      "Returns the character's socket if it exists.");
+    "Alias for char.Char.socket");
   PyChar_addGetSetter("hidden", PyChar_gethidden, PyChar_sethidden,
-		      "integer value representing how hidden the char is.");
+    "Integer value representing how hidden the character is. Default is 0.");
   PyChar_addGetSetter("weight", PyChar_getweight, PyChar_setweight,
-		      "double value representing how heavy we are.");
+    "Floating point value representing how heavy the character is.");
   PyChar_addGetSetter("age", PyChar_getage, NULL,
-		      "how old, in seconds, are we");
+    "Value is the difference between the character's creation time and the\n"
+    "current system time. Immutable.");
   PyChar_addGetSetter("birth", PyChar_getbirth, NULL,
-		      "when were we created");
+    "Value is the character's creation time (system time). Immutable.");
 
   // add in all of our methods for the Char class
   PyChar_addMethod("attach", PyChar_attach, METH_VARARGS,
-		   "attach a new script to the character.");
+    "attach(trigger)\n"
+    "\n"
+    "Attach a trigger to the character by key name.");
   PyChar_addMethod("detach", PyChar_detach, METH_VARARGS,
-		   "detach an old script from the character.");
-  PyChar_addMethod("send", PyChar_send, METH_VARARGS,
-		   "send a message to the character with appended newline.");
+    "detach(trigger)\n"
+    "\n"
+    "Detach a trigger from the character by key name.");
+  PyChar_addMethod("send", PyChar_send, METH_KEYWORDS,
+    "send(mssg, script_dict = None, newline = True)\n"
+    "\n"
+    "Sends message to the character. Messages can have scripts embedded in\n" 
+    "them, using [ and ]. If so, a variable dictionary must be provided. By\n"
+    "default, 'me' references the character being sent the message.");
   PyChar_addMethod("send_raw", PyChar_send_raw, METH_VARARGS,
-		   "send a message to the character.");
+    "send_raw(mssg)\n"
+    "\n"
+    "Sends message to the character with no newline appended.");
   PyChar_addMethod("sendaround", PyChar_sendaround, METH_VARARGS,
-		   "send a message to everyone around the character.");
+    "sendaround(mssg, newline=True)\n"
+    "\n"
+    "Sends message to everyone else in the same room as the character.");
   PyChar_addMethod("act", PyChar_act, METH_VARARGS,
-		   "make the character perform an action.");
+    "act(command)\n"
+    "\n"
+    "Simulate a character typing in a command.");
   PyChar_addMethod("getvar", PyChar_getvar, METH_VARARGS,
-		   "get the value of a special variable the character has.");
+    "getvar(name)\n"
+    "\n"
+    "Return value of a special variable. Return 0 if no value has been set.");
   PyChar_addMethod("setvar", PyChar_setvar, METH_VARARGS,
-		   "set the value of a special variable the character has.");
+    "setvar(name, val)\n"
+    "\n"
+    "Set value of a special variable for the character. Values must be\n"
+    "strings or numbers. This function is intended to allow scripts and\n"
+    "triggers to open-endedly add variables to characters.");
   PyChar_addMethod("hasvar", PyChar_hasvar, METH_VARARGS,
-		   "return whether or not the character has a given variable.");
+    "hasvar(name)\n"
+    "\n"
+    "Return True if a character has the given special variable. False otherwise.");
   PyChar_addMethod("deletevar", PyChar_deletevar, METH_VARARGS,
-		   "delete a variable from the character's variable table.");
+    "deletevar(name)\n"
+    "\n"
+    "Deletes a special variable from a character if they have one by the\n"
+    "given name.");
   PyChar_addMethod("delvar", PyChar_deletevar, METH_VARARGS,
-		   "delete a variable from the character's variable table.");
+    "Alias for char.Char.deletevar(name)");
   PyChar_addMethod("equip", PyChar_equip, METH_VARARGS,
-		   "equips a character with the given item. Removes the item "
-		   "from whatever it is currently in/on.");
+    "equip(obj, positions=None, forced=False)\n"
+    "\n"
+    "Attempts to equip an object to the character's body. Positions can be a\n"
+    "comma-separated list of position names or position types. If positions\n"
+    "is None and object is of type 'worn', attempt to equip the object to\n"
+    "its default positions. Setting forced to True allows non-worn objects\n"
+    "to be equipped, or worn objects to be equipped to their non-default\n"
+    "positions. Returns success of attempt.");
   PyChar_addMethod("get_equip", PyChar_getequip, METH_VARARGS,
-		   "Returns the person's equipment in the specified slot.");
+    "get_equip(bodypart)\n"
+    "\n"
+    "Returns object currently equipped to the character's bodypart, or None.");
   PyChar_addMethod("get_slots", PyChar_getslots, METH_VARARGS,
-		   "Returns the slots occupied by the piece of equipment.");
+    "get_slots(obj)\n"
+    "\n"
+    "Returns a comma-separated list of bodypart names currently occupied by\n"
+    "the object.");
   PyChar_addMethod("get_slot_types", PyChar_getslottypes, METH_VARARGS,
-		   "Returns the slot types occupied by the equipment.");
+    "get_slot_types(obj)\n"
+    "\n"
+    "Returns a list of the bodypart types currently occupied by the object.\n"
+    "Returns an empty list of the object is not equipped to this character.");
   PyChar_addMethod("get_bodypct", PyChar_getbodypct, METH_VARARGS,
-		   "Returns the percent mass of the character's body taken up "
-		   "by the specified parts.");
+    "get_bodypct(posnames)\n"
+    "\n"
+    "Returns the percent mass of the character's body taken up by the\n"
+    "specified parts. Bodyparts must be a comma-separated list.");
   PyChar_addMethod("isActing", PyChar_is_acting, METH_NOARGS,
-		   "Returns True if the character is currently taking an "
-		   "action, and False otherwise.");
+    "isActing()\n"
+    "\n"
+    "Returns True if the character is currently taking an action, and False\n"
+    "otherwise.");
   PyChar_addMethod("startAction", PyChar_start_action, METH_VARARGS,
-		   "Begins the character starting a new action");
+    "startAction(delay, on_complete, on_interrupt=None, data=None, arg='')\n"
+    "\n"
+    "Begins a new delayed action for the character. Delay is in seconds.\n"
+    "on_complete is a function taking three arguments: the character, the\n"
+    "data, and the argument. Argument must be a string, data can be anything.\n"
+    "on_interrupt takes the same arguments as on_complete, but is instead\n"
+    "called if the character's action is interrupted.");
   PyChar_addMethod("interrupt", PyChar_interrupt_action, METH_NOARGS,
-		   "Interrupts the character's current action.");
+    "interrupt()\n"
+    "\n"
+    "Cancel any action the character is currently taking.");
   PyChar_addMethod("getAuxiliary", PyChar_get_auxiliary, METH_VARARGS,
-		   "get's the specified piece of aux data from the char");
+    "getAuxiliary(name)\n"
+    "\n"
+    "Returns character's auxiliary data of the specified name.");
   PyChar_addMethod("aux", PyChar_get_auxiliary, METH_VARARGS,
-		   "get's the specified piece of aux data from the char");
+    "Alias for char.Char.getAuxiliary(name)");
   PyChar_addMethod("cansee", PyChar_cansee, METH_VARARGS,
-		   "returns whether or not a char can see an obj or mob.");
+    "cansee(thing)\n"
+    "\n"
+    "Returns whether a character can see the specified object, exit, or other\n"
+    "character.");
   PyChar_addMethod("see_as", PyChar_see_as, METH_VARARGS,
-		   "returns what the character sees the thing as.");
+    "see_as(thing)\n"
+    "\n"
+    "Returns the name by which a character sees a specified object, exit, or\n"
+    "other character.");
   PyChar_addMethod("page", PyChar_page, METH_VARARGS,
-		   "page a bunch of text to the character.");
+    "page(text)\n"
+    "\n"
+    "Send text to the character in paginated form e.g., for helpfiles and\n."
+    "other large blocks of text.");
   PyChar_addMethod("isinstance", PyChar_isinstance, METH_VARARGS,
-		   "returns whether or not the char inherits from the proto");
+    "isinstance(prototype)\n"
+    "\n"
+    "returns whether the character inherits from a specified mob prototype.");
   PyChar_addMethod("isInGroup", PyChar_is_in_groups, METH_VARARGS,
-		   "returns whether or not the character belongs to one of the groups");
+    "isInGroup(usergroup)\n"
+    "\n"
+    "Returns whether a character belongs to a specified user group.");
   PyChar_addMethod("hasPrefs", PyChar_hasPreferences, METH_VARARGS,
-		   "Return if the character has the specified preference.");
+    "hasPrefs(char_prefs)\n"
+    "\n"
+    "Return whether character has any of the specified character preferences.\n"
+    "Multiples can be specified as a comma-separated string.");
   PyChar_addMethod("append_look", PyChar_append_look, METH_VARARGS,
-		   "Append text to the character's look buffer.");
+    "append_look(text)\n"
+    "\n"
+    "Adds text to the character's current look buffer.");
   PyChar_addMethod("clear_look",  PyChar_clear_look, METH_VARARGS,
-		   "Clear the character's look buffer.");
+    "clear_look()\n"
+    "\n"
+    "Clear the character's current look buffer.");
+  PyChar_addMethod("store", PyChar_store, METH_NOARGS,
+    "store()\n"
+    "\n"
+    "Return a storage set representing the character.");
+  PyChar_addMethod("copy", PyChar_copy, METH_NOARGS,
+    "copy()\n"
+    "\n"
+    "Returns a copy of the character.");
 
   // add in all the getsetters and methods
   makePyType(&PyChar_Type, pychar_getsetters, pychar_methods);
@@ -2001,7 +2198,8 @@
 
   // load the module
   m = Py_InitModule3("char", char_module_methods,
-		     "The char module, for all char/mob-related MUD stuff.");
+    "Contains the Python wrapper for characters, and utilities for searching,\n"
+    "storing, and generating NPCs from mob prototypes.");
   
   // make sure it loaded OK
   if (m == NULL)
diff -ruN ../nakedmudv3.7.9/src/scripts/pyevent.c src/scripts/pyevent.c
--- ../nakedmudv3.7.9/src/scripts/pyevent.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pyevent.c	2009-04-05 13:00:58.000000000 -0400
@@ -170,12 +170,19 @@
 // the all methods that are contained within the event module
 PyMethodDef event_module_methods[] = {
   {"start_event",  PyEvent_start_event, METH_VARARGS,
-   "Add a new python event to the event queue."},
+   "start_event(owner, delay, event_func, data=None, arg='')\n\n"
+   "Queue a new delayed event, to go off after delay seconds. Events are\n"
+   "cancelled when their owner is extracted. Owners can be characters, \n"
+   "objects, rooms, or None. The event function should take three arguments:\n"
+   "the event owner, the event data, and the string argument. Data is an\n"
+   "optional argument that can be of any type. Arg is an optional argument\n"
+   "that must be a string." },
   {"start_update",  PyEvent_start_update, METH_VARARGS,
-   "Add a new python update to the event queue. Like an event, but readds "
-   "itself to the event queue after completion."},
+   "Deprecated. For repeating events, use events that manually re-queue\n"
+   "their selves." },
   {"interrupt_events_involving",  PyEvent_interrupt_event, METH_VARARGS,
-   "Interrupt all of the events involving the given object, room, or char."},
+   "interrupt_events_involving(thing)\n\n"
+   "Interrupt all events involving a given object, room, or character."},
   {NULL, NULL, 0, NULL}  /* Sentinel */
 };
 
@@ -185,5 +192,6 @@
 // implementation of pyevent.h
 //*****************************************************************************
 PyMODINIT_FUNC init_PyEvent(void) {
-  Py_InitModule3("event", event_module_methods, "The mud's event handler.");
+  Py_InitModule3("event", event_module_methods, 
+    "The event module handles delayed function calls.");
 }
diff -ruN ../nakedmudv3.7.9/src/scripts/pyexit.c src/scripts/pyexit.c
--- ../nakedmudv3.7.9/src/scripts/pyexit.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pyexit.c	2009-04-04 23:47:36.000000000 -0400
@@ -658,55 +658,62 @@
 
     // add all of the basic getsetters
     PyExit_addGetSetter("uid", PyExit_getuid, NULL,
-			"returns the exit's universal ID nubmer");
+      "The exit's universal identification nubmer. Immutable.");
     PyExit_addGetSetter("spot_diff", PyExit_getspotdiff, PyExit_setspotdiff,
-			"integer value representing how hidden the exit is.");
+      "Integer value representing how hard to see the exit is.");
     PyExit_addGetSetter("hidden", PyExit_getspotdiff, PyExit_setspotdiff,
-			"integer value representing how hidden the exit is.");
+      "Alias for exit.Exit.spot_diff");
     PyExit_addGetSetter("pick_diff", PyExit_getpickdiff, PyExit_setpickdiff,
-			"integer value representing how hard lock is to pick.");
+      "Integer value representing how hard the exit's lock is to pick.");
     PyExit_addGetSetter("key", PyExit_getkey, PyExit_setkey,
-			"String or Obj value for obj class that unlocks exit.");
+      "An object prototype name that can be used to unlock this exit. Can be\n"
+      "set either by assigning a prototype name, or an actual object.");
     PyExit_addGetSetter("dest", PyExit_getdest, PyExit_setdest,
-			"String or Room value for room this exit leads to.");
+      "The room that this exit leads to. Can be set either by assigning a\n"
+      "world room key, or an actual room.");
     PyExit_addGetSetter("destproto", PyExit_getdestproto, NULL,
-			"return the class name of our our destiantion.");
+      "The world room key of our destination. Immutable.");
     PyExit_addGetSetter("name", PyExit_getname, PyExit_setname,
-			"The name of the door on the exit.");
+      "The name of the door for this exit, if any.");
     PyExit_addGetSetter("keywords", PyExit_getkeywords, PyExit_setkeywords,
-			"comma-separated string of the door's keywords.");
+      "A comma-separated string of the door's keywords.");
     PyExit_addGetSetter("opposite", PyExit_getopposite, PyExit_setopposite,
-			"if the exit is special, a dir name for the exit that "
-			"leads back to this exit's room.");
+      "if the exit is special, a dir name for the exit that leads back to\n"
+      "this exit's room.");
     PyExit_addGetSetter("desc", PyExit_getdesc, PyExit_setdesc,
-			"the long description of the exit when looked at.");
+      "The verbose description of the exit when, e.g., it is looked at.");
     PyExit_addGetSetter("leave_mssg", PyExit_getleavemssg, PyExit_setleavemssg,
-			"the special message sent when a char exits the room.");
+      "A message for when a character leaves a room via this exit.");
     PyExit_addGetSetter("enter_mssg", PyExit_getentermssg, PyExit_setentermssg, 
-		       "the special message sent when a char enters the room.");
+      "A message for when a char enters the room via this exit.");
     PyExit_addGetSetter("is_closable", PyExit_getclosable, NULL,
-			"true or false if the exit can be closed.");
+      "True or False if an exit can be closed. Immutable.");
     PyExit_addGetSetter("is_closed", PyExit_getclosed, NULL,
-			"true or false if the exit is closed.");
+      "True or False if an exit is closed. Immutable.");
     PyExit_addGetSetter("is_locked", PyExit_getlocked, NULL,
-			"true or false if the exit is locked.");
+      "True or False if an exit is locked.");
     PyExit_addGetSetter("room", PyExit_getroom, NULL,
-			"the room we are attached to.");
+      "The room we this exit is attached to. Immutable.");
 
     // add all of the basic methods
     PyExit_addMethod("makedoor", PyExit_makedoor, METH_VARARGS,
-		     "Make a door on the exit. Takes name, keywords, and "
-		     "optionally opposite, closed, locked, and key.");
+      "makedoor(name=None, keywords=None, opposite=None, closed=False, locked=False)\n\n"
+      "Create a door for the exit.");
     PyExit_addMethod("filldoor", PyExit_filldoor, METH_NOARGS,
-		     "remove a door that was made on the exit.");
-    PyExit_addMethod("open", PyExit_open, METH_VARARGS,
-		     "Opens the exit if there's a door. Also unlocks.");
-    PyExit_addMethod("close", PyExit_close, METH_VARARGS,
-		     "Close the exit's door if one exists.");
-    PyExit_addMethod("lock", PyExit_lock, METH_VARARGS,
-		     "Locks the exit if there's a door. Also closes.");
-    PyExit_addMethod("unlock", PyExit_unlock, METH_VARARGS,
-		     "Unlocks the exit's door if one exists.");
+      "filldoor()\n\n"
+      "Erase a door that was on the exit.");
+    PyExit_addMethod("open", PyExit_open, METH_NOARGS,
+      "open()\n\n"
+      "Opens the exit's door if it exists. Also unlocks.");
+    PyExit_addMethod("close", PyExit_close, METH_NOARGS,
+      "close()\n\n"
+      "Close the exit's door if it exists.");
+    PyExit_addMethod("lock", PyExit_lock, METH_NOARGS,
+      "lock()\n\n"
+      "Locks the exit's door if it exists. Also closes.");
+    PyExit_addMethod("unlock", PyExit_unlock, METH_NOARGS,
+      "unlock()\n\n"
+      "Unlocks the exit's door if it exists.");
 
     // add in all the getsetters and methods
     makePyType(&PyExit_Type, pyexit_getsetters, pyexit_methods);
diff -ruN ../nakedmudv3.7.9/src/scripts/pyhooks.c src/scripts/pyhooks.c
--- ../nakedmudv3.7.9/src/scripts/pyhooks.c	2009-01-02 17:33:12.000000000 -0500
+++ src/scripts/pyhooks.c	2009-04-05 16:34:08.000000000 -0400
@@ -297,7 +297,7 @@
     LIST_ITERATOR *list_i = newListIterator(list);
     PyObject *func = NULL;
     ITERATE_LIST(func, list_i) {
-      PyObject *arglist = Py_BuildValue("(s)", info);
+      PyObject *arglist = Py_BuildValue("(s)", info_dup);
       PyObject *retval  = PyEval_CallObject(func, arglist);
       // check for an error:
       if(retval == NULL)
@@ -319,18 +319,26 @@
 PyMODINIT_FUNC
 init_PyHooks(void) {
   PyHooks_addMethod("parse_info", PyHooks_ParseInfo, METH_VARARGS,
-		    "parses a hook info string into a tuple.");
+    "parse_info(info)\n\n"
+    "Returns a tuple of parsed hook information.");
   PyHooks_addMethod("build_info", PyHooks_BuildInfo, METH_VARARGS,
-		    "builds a hook info string out of a tuple and format.");
+    "build_info(format, args)\n\n"
+    "Returns hook information from a string format and a tuple of values for\n"
+    "the format. Format arguments must be space-separated. They include:\n"
+    "ch, rm, obj, ex, sk, str, int, dbl.");
   PyHooks_addMethod("run", PyHooks_Run, METH_VARARGS,
-		    "runs a hook.");
+    "run(hooktypes)\n\n"
+    "Runs hooks registered to the given type.");
   PyHooks_addMethod("add", PyHooks_Add, METH_VARARGS,
-		    "adds a hook.");
+    "add(type, function)\n\n"
+    "Register a new hook function. Hook functions should take one argument:\n"
+    "an information string that can be parsed with hooks.parse_info");
   PyHooks_addMethod("remove", PyHooks_Remove, METH_VARARGS,
-		    "removes a hook");
+    "remove(type, function)\n\n"
+    "Unregister a hook function.");
 
   Py_InitModule3("hooks", makePyMethods(pyhooks_methods),
-		 "The hooks module.");
+    "The python module for registering and running hooks.");
 
   // set up our hook monitor
   pyhook_table = newHashtable();
diff -ruN ../nakedmudv3.7.9/src/scripts/pymud.c src/scripts/pymud.c
--- ../nakedmudv3.7.9/src/scripts/pymud.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pymud.c	2009-04-05 00:26:22.000000000 -0400
@@ -507,41 +507,53 @@
 init_PyMud(void) {
   // add all of our methods
   PyMud_addMethod("get_global", mud_get_global, METH_VARARGS,
-		  "Get the value of a global variable.");
+    "get_global(name)\n\n"
+    "Return a non-persistent global variable, or None.");
   PyMud_addMethod("set_global", mud_set_global, METH_VARARGS,
-		  "Set the value of a global variable.");
+    "set_global(name, val)\n\n"
+    "Sets a non-persistent global variable. Val can be any type.");
   PyMud_addMethod("erase_global",  mud_erase_global, METH_VARARGS,
-		  "Erase the value of a global variable.");
+    "erase_global(name)\n\n"
+    "Delete a value from the global variable table.");
   PyMud_addMethod("message", mud_message, METH_VARARGS,
-		  "plugs into the message() function from inform.h");
+    "message(ch, vict, obj, vobj, show_invis, range, mssg)\n\n"
+    "Send a message via the mud messaging system using $ expansions. Range\n"
+    "can be 'to_room', 'to_char', 'to_vict', or 'to_world'.");
   PyMud_addMethod("format_string", mud_format_string, METH_VARARGS,
-		  "format a string to be 80 chars wide and indented.");
+    "format_string(text, indent=True, width=80)\n\n"
+    "Format a block of text to be of the specified width, possibly indenting\n"
+    "paragraphs.");
   PyMud_addMethod("generic_find",  mud_generic_find, METH_VARARGS,
-		  "Python wrapper around the generic_find() function");
+    "Deprecated. Use mud.parse_args instead.");
   PyMud_addMethod("extract", mud_extract, METH_VARARGS,
-		  "extracts an object or character from the game.");
+    "extract(thing)\n\n"
+    "Extracts an object, character, or room from the game.");
   PyMud_addMethod("keys_equal", mud_keys_equal, METH_VARARGS,
-		  "Returns whether or not two db keys are equal, given the ."
-		  "locale that the script is running in.");
+    "keys_equal(key1, key2)\n\n"
+    "Returns whether two world database keys are equal, relative to the\n"
+    "locale (if any) that the current script is running in.");
   PyMud_addMethod("ite", mud_ite, METH_VARARGS,
-		  "A functional form of an if-then-else statement. Takes 2 "
-		  "arguments (condition, if action) and an optional third "
-		  "(else action). If no else action is specified and the "
-		  "condition is false, None is returned.");
+    "ite(logic_statement, if_statement, else_statement=None)\n\n"
+    "A functional form of if/then/else.");
   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("get_greeting", mud_get_greeting, METH_VARARGS,
-		  "returns the mud's login greeting");
+    "parse_args(ch, show_usage_errors, cmd, args, format)\n\n"
+    "equivalent to parse_args written in C. See parse.h for information.");
+  PyMud_addMethod("get_motd", mud_get_motd, METH_NOARGS,
+    "get_motd()\n\n"
+    "Returns the mud's message of the day.");
+  PyMud_addMethod("get_greeting", mud_get_greeting, METH_NOARGS,
+    "get_greeting()\n\n"
+    "returns the mud's connection greeting.");
   PyMud_addMethod("log_string", mud_log_string, METH_VARARGS,
-		  "adds a string to the mudlog");
+    "log_string(mssg)\n"
+    "Send a message to the mud's log.");
   PyMud_addMethod("is_race", mud_is_race, METH_VARARGS,
-		  "returns whether or not the string is a valid race.");
+    "is_race(name)\n\n"
+    "Returns True or False if the string is a valid race name.");
   PyMud_addMethod("list_races", mud_list_races, METH_VARARGS,
-		  "returns a list of all the races available. Can take one "
-		  "argument that specifies whether or not to list player "
-		  "races.");
+    "list_races(player_only=False)\n\n"
+    "Return a list of available races. If player_only is True, list only the\n"
+    "races that players have access to.");
 
   Py_InitModule3("mud", makePyMethods(pymud_methods),
 		 "The mud module, for all MUD misc mud utils.");
diff -ruN ../nakedmudv3.7.9/src/scripts/pymudsys.c src/scripts/pymudsys.c
--- ../nakedmudv3.7.9/src/scripts/pymudsys.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pymudsys.c	2009-04-05 16:48:16.000000000 -0400
@@ -761,7 +761,7 @@
   char       *name = NULL;
 
   if(!PyArg_ParseTuple(args, "OO", &pyname, &method)) {
-    PyErr_Format(PyExc_TypeError, "Method takes string and function argument.");
+    PyErr_Format(PyExc_TypeError, "Method takes string and function or property argument.");
     return NULL;
   }
 
@@ -770,8 +770,8 @@
     return NULL;
   }
 
-  if(!PyFunction_Check(method)) {
-    PyErr_Format(PyExc_TypeError, "Second argument not a function.");
+  if(!PyFunction_Check(method) && !PyObject_TypeCheck(method,&PyProperty_Type)){
+    PyErr_Format(PyExc_TypeError,"Second argument not a function or property.");
     return NULL;
   }
 
@@ -1023,7 +1023,7 @@
   char      *type = NULL;
   char       *key = NULL;
 
-  if(!PyArg_ParseTuple(args, "ssO", &type, &key)) {
+  if(!PyArg_ParseTuple(args, "ss", &type, &key)) {
     PyErr_Format(PyExc_TypeError, 
 		 "Error parsing type and key for world_save_type");
     return NULL;
@@ -1101,6 +1101,33 @@
   }
 }
 
+PyObject *mudsys_can_edit_zone(PyObject *self, PyObject *args) {
+  PyObject  *pych = NULL;
+  CHAR_DATA   *ch = NULL;
+  ZONE_DATA *zone = NULL;
+  char     *zname = NULL;
+
+  if(!PyArg_ParseTuple(args, "Os", &pych, &zname)) {
+    PyErr_Format(PyExc_TypeError,"can_edit_zone takes ch and zone name.");
+    return NULL;
+  }
+
+  if(!PyChar_Check(pych)) {
+    PyErr_Format(PyExc_TypeError,"Non-character supplied to can_edit_zone.");
+    return NULL;
+  }
+  else if( (ch = PyChar_AsChar(pych)) == NULL) {
+    PyErr_Format(PyExc_TypeError,"can_edit_zone supplied non-existent zone.");
+    return NULL;
+  }
+
+  // find the zone and check
+  zone = worldGetZone(gameworld, zname);
+  if(zone == NULL || !canEditZone(zone, ch))
+    return Py_BuildValue("i", 0);
+  return Py_BuildValue("i", 1);
+}
+
 
 
 //*****************************************************************************
@@ -1133,117 +1160,211 @@
 
   // add all of our methods
   PyMudSys_addMethod("do_shutdown", mudsys_shutdown, METH_VARARGS,
+		     "do_shutdown()\n\n"
 		     "shuts the mud down.");
   PyMudSys_addMethod("do_copyover", mudsys_copyover, METH_VARARGS,
+		     "do_copyover()\n\n"
 		     "performs a copyover on the mud.");
   PyMudSys_addMethod("sys_setval", mudsys_set_sys_val, METH_VARARGS,
-		     "sets a system value on the mud.");
+		     "set_sysval(name, val)\n"
+		     "\n"
+		     "sets a value registered in the system settings.");
   PyMudSys_addMethod("sys_getval", mudsys_get_sys_val, METH_VARARGS,
-		     "returns a system value on the mud.");
+		     "sys_getval(name)\n"
+		     "\n"
+		     "returns a value registered in the system settings.");
   PyMudSys_addMethod("sys_getvar", mudsys_get_sys_val, METH_VARARGS,
-		     "returns a system value on the mud.");
+		     "Alias to mudsys.sys_getval");
   PyMudSys_addMethod("sys_setvar", mudsys_set_sys_val, METH_VARARGS,
-		     "sets a system value on the mud.");
+		     "Alias to mudsys.sys_setval");
   PyMudSys_addMethod("player_exists", mudsys_player_exists, METH_VARARGS,
-		     "returns whether a player with the name exists.");
+		     "player_exists(name)\n"
+		     "\n"
+		     "Returns whether a player with the name exists.");
   PyMudSys_addMethod("account_exists", mudsys_account_exists, METH_VARARGS,
-		     "returns whether an account with the name exists.");
+		     "account_exists(name)\n"
+		     "\n"
+		     "Returns whether an account with the name exists.");
   PyMudSys_addMethod("player_creating", mudsys_player_creating, METH_VARARGS,
+		     "player_creating(name)\n"
+		     "\n"
 		     "returns whether a player with the name is creating.");
   PyMudSys_addMethod("account_creating", mudsys_account_creating, METH_VARARGS,
+		     "account_creating(name)\n"
+		     "\n"
 		     "returns whether an account with the name is creating.");
   PyMudSys_addMethod("do_register", mudsys_do_register, METH_VARARGS,
-		     "register a player to disk, and with an account.");
+		     "do_register(char_or_account)\n"
+		     "\n"
+		     "Register a PC or account for the first time. Should be called after creation.");
+  PyMudSys_addMethod("get_player", mudsys_load_char, METH_VARARGS,
+		     "get_player(name)\n"
+		     "\n"
+		     "Return a saved character of specified name, or None.");
   PyMudSys_addMethod("load_char", mudsys_load_char, METH_VARARGS,
-		     "load a characer from disk");
+		     "Alias for mudsys.get_player(name).");
   PyMudSys_addMethod("load_account", mudsys_load_account, METH_VARARGS,
-		     "load an account from disk");
+		     "load_account(name)\n"
+		     "\n"
+		     "Return a saved account of specified name, or None.");
   PyMudSys_addMethod("try_enter_game", mudsys_try_enter_game, METH_VARARGS,
-		     "Tries to put the character into the game world");
+		     "try_enter_game(ch)\n"
+		     "\n"
+		     "Tries to add a character the game world.");
   PyMudSys_addMethod("do_save", mudsys_do_save, METH_VARARGS,
-		     "save a character to disk");
+		     "do_save(char_or_account)\n"
+		     "\n"
+		     "Save a character or account's information.");
   PyMudSys_addMethod("do_quit", mudsys_do_quit, METH_VARARGS,
-		     "quit a character from game");
+		     "do_quit(ch)\n"
+		     "\n"
+		     "Extract a character from game.");
   PyMudSys_addMethod("attach_account_socket",mudsys_attach_account_socket, 
-		     METH_VARARGS, "attaches an account and socket.");
+		     METH_VARARGS, 
+		     "attach_account_socket(acct, sock)\n"
+		     "\n"
+		     "Link a loaded account to a connected socket.");
   PyMudSys_addMethod("attach_char_socket", mudsys_attach_char_socket, 
-		     METH_VARARGS, "attaches a char and socket.");
+		     METH_VARARGS,
+		     "attach_char_socket(ch, sock)\n"
+		     "\n"
+		     "Link a loaded character to a connected socket.");
   PyMudSys_addMethod("detach_char_socket", mudsys_detach_char_socket,
-		     METH_VARARGS, "detachs a char from a socket.");
+		     METH_VARARGS,
+		     "detach_char_socket(ch)\n"
+		     "\n"
+		     "Unlink a character from its attached socket.");
   PyMudSys_addMethod("do_disconnect", mudsys_do_disconnect, METH_VARARGS,
-		     "disconnects a character from its socket");
+		     "do_disconnect(ch)\n"
+		     "\n"
+		     "call detach_char_socket, then close the socket.");
   PyMudSys_addMethod("password_matches", mudsys_password_matches, METH_VARARGS,
-		     "returns whether or not the password matches the account's"
-		     " password.");
+		     "password_matches(acct, psswd)\n"
+		     "\n"
+		     "Returns True or False if the given password matches the account's password.");
   PyMudSys_addMethod("set_password", mudsys_set_password, METH_VARARGS,
-		     "sets an account's password.");
+		     "set_password(acct, passwd)\n"
+		     "\n"
+		     "Set an account's password.");
   PyMudSys_addMethod("add_cmd", mudsys_add_cmd, METH_VARARGS,
-		     "Add a new command to the game.");
+    "add_cmd(name, shorthand, cmd_func, user_group, interrupts_action)\n"
+    "\n"
+    "Add a new command to the master command table. If a preferred shorthand\n"
+    "exists, e.g., 'n' for 'north', it can be specified. Otherwise, shorthand\n"
+    "should be None. Command functions take three arguments: a character\n"
+    "issuing the command, the command name, and a string argument supplied\n"
+    "to the command. Commands must be tied to a specific user group, and they\n"
+    "can optionally interupt character actions.");
   PyMudSys_addMethod("add_cmd_check", mudsys_add_cmd_check, METH_VARARGS,
-		     "Add a new check prior to a command running.");
+    "add_cmd_check(name, check_func)\n"
+    "\n"
+    "Add a new command check to a registered command. Check functions take\n"
+    "two arguments: the character issuing the command, and the command name.\n"
+    "If a check fails, it should return False and send the character a\n"
+    "message why.");
   PyMudSys_addMethod("remove_cmd", mudsys_remove_cmd, METH_VARARGS,
-		     "Removes a command from the game.");
+    "remove_cmd(name)\n"
+    "\n"
+    "Removes a command from the master command table.");
   PyMudSys_addMethod("handle_cmd_input", mudsys_handle_cmd_input, METH_VARARGS,
-		     "the default input handler for character commands.");
+    "handle_cmd_input(sock, cmd)\n"
+    "\n"
+    "Equivalent to char.Char.act(cmd)");
   PyMudSys_addMethod("show_prompt", mudsys_show_prompt, METH_VARARGS,
-		     "the default character prompt. Can be replaced in Python "
-		     "by assigning a new prompt to the same named variable.");
+    "show_prompt(sock)\n"
+    "\n"
+    "Display the default game prompt to the socket. Can be replaced in Python\n"
+    "by assigning a new function to show_prompt.");
   PyMudSys_addMethod("create_account", mudsys_create_account, METH_VARARGS,
-		     "creates a new account by name. Must be registered "
-		     "after fully created.");
+    "create_account(acctname)\n"
+    "\n"
+    "Returns a new account by the specified name, or None if an account by.\n"
+    "the specified name is already registered or creating. After the account" 
+    "generation process is complete, mudsys.do_register(acct) must be called.");
   PyMudSys_addMethod("create_player", mudsys_create_player, METH_VARARGS,
-		     "creates a new player by name. Must be registered "
-		     "after fully created.");
+    "Same as mudsys.create_account for player characters.");
   PyMudSys_addMethod("add_sock_method", mudsys_add_sock_method, METH_VARARGS,
-		     "adds a new Python method to the Mudsock class");
+    "Same as add_acct_method for sockets.");
   PyMudSys_addMethod("add_char_method", mudsys_add_char_method, METH_VARARGS,
-		     "adds a new Python method to the Char class");
+    "Same as add_acct_method for characters.");
   PyMudSys_addMethod("add_room_method", mudsys_add_room_method, METH_VARARGS,
-		     "adds a new Python method to the Room class");
+    "Same as add_acct_method for rooms.");
   PyMudSys_addMethod("add_exit_method",  mudsys_add_exit_method, METH_VARARGS,
-		     "adds a new Python method to the Exit class");
+    "Same as add_acct_method for exits.");
   PyMudSys_addMethod("add_obj_method",  mudsys_add_obj_method, METH_VARARGS,
-		     "adds a new Python method to the Obj class");
+    "Same as add_acct_method for objects.");
   PyMudSys_addMethod("add_acct_method",  mudsys_add_acct_method, METH_VARARGS,
-		     "adds a new Python method to the Account class");
+    "add_acct_method(name, method)\n"
+    "\n"
+    "Adds a function or property to the Account class.");
   PyMudSys_addMethod("world_add_type", mudsys_world_add_type, METH_VARARGS,
-		     "adds a new type to the world. like, e.g., mob, obj, and "
-                     "room prototypes. Assumes a class with a store and "
-		     "setKey method");
+    "world_add_type(typename, class_data)\n"
+    "\n"
+    "Registers a new type to the world database. Like, e.g., mob, obj, and\n"
+    "room prototypes. Assumes class has a store and setKey method. Init\n"
+    "method should take one optional argument: a storage set to parse the\n"
+    "type data from, when loaded.");
   PyMudSys_addMethod("world_get_type", mudsys_world_get_type, METH_VARARGS,
-		     "gets a registered item from the world database. Assumes "
-		     "it is a python type, and not a C type. If no type exists "
-		     "return Py_None");
+    "world_get_type(typename, key)\n"
+    "\n"
+    "Returns registered entry of the specified type from the world database.\n"
+    "Assumes it is a python type, and not a C type. If no type exists\n"
+    "return None.");
   PyMudSys_addMethod("world_put_type", mudsys_world_put_type, METH_VARARGS,
-		     "Put a new type into thw world database.");
+    "world_put_type(typename, key, data)\n"
+    "\n"
+    "Put and save an entry of the specified type to the world database.");
   PyMudSys_addMethod("world_save_type", mudsys_world_save_type, METH_VARARGS,
-		     "Saves a world entry if it exists.");
+    "world_save_type(typename, key)\n"
+    "\n"
+    "Saves an entry in the world database if it exists.");
   PyMudSys_addMethod("world_remove_type", mudsys_world_remove_type,METH_VARARGS,
-		     "Removes a type, and returns a reference to it, or None "
-		     "if it does not exist.");
+    "world_remove_type(typename, key)\n"
+    "\n"
+    "Remove and return an entry from the world database, or None.");
   PyMudSys_addMethod("register_char_cansee", mudsys_register_char_cansee,
-		     METH_VARARGS, "Register a new check of whether one "
-		     "character can see another.");
+    METH_VARARGS,
+   "register_char_cansee(check_function(observer, observee))\n"
+   "\n"
+   "Register a new check of whether one character can see another.");
   PyMudSys_addMethod("register_obj_cansee", mudsys_register_obj_cansee,
-		     METH_VARARGS, "Register a new check of whether a "
-		     "character can see an object.");
+    METH_VARARGS, "Same as register_char_cansee for objects.");
   PyMudSys_addMethod("register_exit_cansee", mudsys_register_exit_cansee,
-		     METH_VARARGS, "Register a new check of whether a char "
-		     "can see an exit.");
+    METH_VARARGS, "Same as register_char_cansee for exits.");
   PyMudSys_addMethod("set_cmd_move", mudsys_set_cmd_move, METH_VARARGS,
-		     "sets the movement command.");
+    "set_cmd_move(cmd_func)\n"
+    "\n"
+    "Register a player command for handling all default movement commands.\n"
+    "See mudsys.add_cmd for information about commands.");
   PyMudSys_addMethod("register_dflt_move_cmd", mudsys_register_dflt_move_cmd, 
-		     METH_VARARGS, "registers a new default movement command.");
+    METH_VARARGS,
+    "register_dflt_move_cmd(cmdname)\n"
+    "\n" 
+    "registers a new default movement command, e.g., north");
   PyMudSys_addMethod("register_move_check",mudsys_register_move_check,
-		     METH_VARARGS,"register new check to perform a movement.");
+    METH_VARARGS,
+    "register_move_check(check_func)\n"
+    "\n"
+    "Register a check to perform movement commands. See mudsys.add_cmd_check\n"
+    "for information about command checks.");
   PyMudSys_addMethod("create_bitvector", mudsys_create_bitvector,
-		     METH_VARARGS,"creates a new type of bitvector."); 
+    METH_VARARGS, "Not yet implemented."); 
   PyMudSys_addMethod("create_bit", mudsys_create_bit,
-		     METH_VARARGS,"creates a new bit on the specified bitvector."); 
+    METH_VARARGS,
+    "create_bit(bitvector, bit)\n"
+    "\n"
+    "Creates a new bit on the specified bitvector."); 
   PyMudSys_addMethod("next_uid", mudsys_next_uid, METH_NOARGS,
-		     "returns the next available uid.");
+    "next_uid()\n\n"
+    "Returns the next available universal identification number.");
   PyMudSys_addMethod("list_zone_contents", mudsys_list_zone_contents, 
-		     METH_VARARGS, "returns a list of the contents of the given type, for the specified zone.");
+    METH_VARARGS,
+    "list_zone_contents(zone, type)\n\n" 
+    "Returns a list of the content keys of the given type, for the specified\n"
+    "zone.");
+  PyMudSys_addMethod("can_edit_zone", mudsys_can_edit_zone, METH_VARARGS,
+    "can_edit_zone(ch, zone)\n\n"
+    "True or False if a character has permission to edit a zone.");
 
   Py_InitModule3("mudsys", makePyMethods(pymudsys_methods),
 		 "The mudsys module, for all MUD system utils.");
diff -ruN ../nakedmudv3.7.9/src/scripts/pyobj.c src/scripts/pyobj.c
--- ../nakedmudv3.7.9/src/scripts/pyobj.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pyobj.c	2009-04-05 12:44:10.000000000 -0400
@@ -1,8 +1,8 @@
 //*****************************************************************************
 //
-// py_char.c
+// pyobj.c
 //
-// A python extention to allow python scripts to treat MUD characters as an
+// A python extention to allow python scripts to treat MUD objects as a Python
 // object within the script.
 //
 //*****************************************************************************
@@ -874,6 +874,20 @@
   return ret;
 }
 
+PyObject *PyObj_copy(PyObject *self, void *closure) {
+  OBJ_DATA *obj = PyObj_AsObj(self);
+  if(obj == NULL) {
+    PyErr_Format(PyExc_TypeError, "failed to copy nonexistent object.");
+    return NULL;
+  }
+  OBJ_DATA *newobj = objCopy(obj);
+
+  // we have to put the object in the global tables and list, 
+  // or else Python will not be able to access it
+  obj_to_game(newobj);
+
+  return objGetPyForm(newobj);
+}
 
 
 
@@ -1198,20 +1212,32 @@
 
 PyMethodDef obj_module_methods[] = {
   { "read",     PyObj_read, METH_VARARGS,
-    "read an object from a storage set." },
+    "read(storage_set)\n"
+    "\n"
+    "Read and return an object from a storage set." },
   { "obj_list", (PyCFunction)PyObj_all_objs, METH_NOARGS,
-    "Return a python list containing an entry for every object in game." },
+    "obj_list()\n"
+    "\n"
+    "Return a list containing every object in the game." },
   { "load_obj", PyObj_load_obj, METH_VARARGS,
-    "load a object with the specified oproto to a room." },
+    "load_obj(prototype, where=None, equip_to='')\n"
+    "\n"
+    "Generate a new object from the specified prototype. Add it to where.\n"
+    "Where can be a room, character, or container. If where is a character,\n"
+    "add the object to the character's inventory unless a comma-separated\n"
+    "list of bodypart name of positions is specified. Return the created object." },
   { "count_objs", PyObj_count_objs, METH_VARARGS,
-    "count how many occurances of an object there are in the specified scope. "
-    "prototype or name can be used."},
+    "count_objs(keyword, loc = None)\n"
+    "\n"
+    "count how many occurences of an object with the specified keyword, uid,\n"
+    "or prototype exist at a location. If loc is None, search the entire mud.\n"
+    "Loc can be a room, character, or container object." },
   { "find_obj", PyObj_find_obj, METH_VARARGS,
-    "Takes a string argument, and returns the object(s) in the scope that "
-    "correspond to what the string is searching for."},
+    "function has been deprecated. Entrypoint for generic_find().\n"
+    "Use mud.parse_args instead." },
   { "find_obj_key", PyObj_find_obj_key, METH_VARARGS,
-    "Takes a string argument, and returns the object(s) in the scope that "
-    "are an instance of the specified class."},
+    "function has been deprecated. Entrypoint for generic_find().\n"
+    "Use mud.parse_args instead." },
   {NULL, NULL, 0, NULL}  /* Sentinel */
 };
 
@@ -1253,77 +1279,112 @@
 
     // getters and setters
     PyObj_addGetSetter("contents", PyObj_getcontents, NULL,
-		       "the object's contents");
+      "A list of other objects contained within this one. Immutable.\n"
+      "See obj.Obj.container for changing an object's container.");
     PyObj_addGetSetter("objs", PyObj_getcontents, NULL,
-		       "the object's contents");
+      "Alias for obj.Obj.contents");
     PyObj_addGetSetter("chars", PyObj_getchars, NULL,
-		       "the characters sitting on/riding the object");
+      "A list of characters currently sitting/riding this object. Immutable.\n"
+      "See char.Char.furniture for changing a character's furniture.");
     PyObj_addGetSetter("name", PyObj_getname, PyObj_setname,
-		       "the object's name");
+      "The object's name e.g., a longsword");
     PyObj_addGetSetter("mname", PyObj_getmname, PyObj_setmname,
-		       "the object's multi-name");
+      "The object's name for describing packs, e.g.,\n"
+      "a stack of 12 linen towels. The number should be replaced by %d, or\n"
+      "not included.");
     PyObj_addGetSetter("desc", PyObj_getdesc, PyObj_setdesc,
-		       "the object's long description");
+      "An object's verbose description e.g., for when it is looked at.");
     PyObj_addGetSetter("rdesc", PyObj_getrdesc, PyObj_setrdesc,
-		       "the object's room description");
+      "The object's description when seen in a room, e.g.,\n"
+      "a longsword is here, gleaming in the sun.");
     PyObj_addGetSetter("mdesc", PyObj_getmdesc, PyObj_setmdesc,
-		       "the object's multi room description");
+      "the equivalent of mname, for room descriptions.");
     PyObj_addGetSetter("keywords", PyObj_getkeywords, PyObj_setkeywords,
-		       "the object's keywords");
+      "A comma-separated list of keywords for referencing the object.");
     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)");
+      "The object's weight (plus contents). When setting a new value, \n"
+      "sets raw weight (minus contents).");
+    PyObj_addGetSetter("weight_raw", PyObj_get_weight_raw, PyObj_setweight,
+      "The object's weight (minus contents)");
     PyObj_addGetSetter("uid", PyObj_getuid, NULL,
-		       "the object's unique identification number");
+      "The object's unique identification number. Immutable.");
     PyObj_addGetSetter("prototypes", PyObj_getprototypes, NULL,
-		       "a comma-separated list of this obj's prototypes.");
+      "A comma-separated list of prototypes this object inherits from. Immutable");
     PyObj_addGetSetter("bits", PyObj_getbits, PyObj_setbits,
-		       "the object's basic bitvector.");
+      "A comma-separated list of bits currently toggled for this object.");
     PyObj_addGetSetter("carrier", PyObj_getcarrier, PyObj_setcarrier,
-		       "the person carrying the object");
+      "The character whose inventory this object is currently in, or None.");
     PyObj_addGetSetter("wearer", PyObj_getwearer, NULL,
-		       "the person wearing this object");
+      "The character who is currently wearing this object, or None.");
     PyObj_addGetSetter("room", PyObj_getroom, PyObj_setroom,
-		       "The room this object is in. "
-		       "None if on a character or in another object");
+      "The room this object is current in, or None.");
     PyObj_addGetSetter("container", PyObj_getcontainer, PyObj_setcontainer,
-		       "The container this object is in. "
-		       "None if on a character or in a room");
+      "The container this object is currently in, or None.");
     PyObj_addGetSetter("hidden", PyObj_gethidden, PyObj_sethidden,
-		       "integer value representing how hidden the object is.");
+      "Integer value representing how hard this object is to see.");
     PyObj_addGetSetter("age", PyObj_getage, NULL,
-		       "how old, in seconds, are we");
+      "Value is the difference between the object's creation time and the\n"
+      "current system time. Immutable.");
     PyObj_addGetSetter("birth", PyObj_getbirth, NULL,
-		       "when were we created");
+      "Value is the object's creation time (system time). Immutable.");
 
     // methods
     PyObj_addMethod("attach", PyObj_attach, METH_VARARGS,
-		    "attach a new script to the object");
+      "attach(trigger)\n"
+      "\n"
+      "Attach a trigger to the object by key name.");
     PyObj_addMethod("detach", PyObj_detach, METH_VARARGS,
-		    "detach an old script from the object, by vnum");
+      "detach(trigger)\n"
+      "\n"
+      "Detach a trigger from the object by key name.");
     PyObj_addMethod("isinstance", PyObj_isinstance, METH_VARARGS,
-		    "checks to see if the object inherits from the class");
+      "isinstance(prototype)\n"
+      "\n"
+      "returns whether the object inherits from a specified obj prototype.");
     PyObj_addMethod("edesc", PyObj_edesc, METH_VARARGS,
-		    "adds an extra description to the object.");
+      "edesc(keywords, desc)\n"
+      "\n"
+      "Create an extra description for the object, accessible via a comma-\n"
+      "separated list of keywords.");
     PyObj_addMethod("getAuxiliary", PyObj_get_auxiliary, METH_VARARGS,
-		    "get's the specified piece of aux data from the obj");
+      "getAuxiliary(name)\n"
+      "\n"
+      "Returns object's auxiliary data of the specified name.");
     PyObj_addMethod("aux", PyObj_get_auxiliary, METH_VARARGS,
-		    "get's the specified piece of aux data from the obj");
+      "Alias for obj.Obj.getAuxiliary(name)");
     PyObj_addMethod("getvar", PyObj_getvar, METH_VARARGS,
-		    "get the value of a special variable the object has.");
+      "getvar(name)\n"
+      "\n"
+      "Return value of a special variable. Return 0 if no value has been set.");
     PyObj_addMethod("setvar", PyObj_setvar, METH_VARARGS,
-		    "set the value of a special variable the object has.");
+      "setvar(name, val)\n"
+      "\n"
+      "Set value of a special variable for the object. Values must be strings\n"
+      "or numbers. This function is intended to allow scripts and triggers to"
+      "open-endedly add variables to objects.");
     PyObj_addMethod("hasvar", PyObj_hasvar, METH_VARARGS,
-		    "return whether or not the object has a given variable.");
+      "hasvar(name)\n"
+      "\n"
+      "Return True if object has the given special variable. False otherwise.");
     PyObj_addMethod("deletevar", PyObj_deletevar, METH_VARARGS,
-		    "delete a variable from the object's variable table.");
+      "deletevar(name)\n"
+      "\n"
+      "Deletes a special variable from an object if they have one by the\n"
+      "given name.");
     PyObj_addMethod("delvar", PyObj_deletevar, METH_VARARGS,
-		    "delete a variable from the object's variable table.");
+      "Alias for obj.Obj.deletevar(name)");
     PyObj_addMethod("fromall", PyObj_fromall, METH_NOARGS,
-		    "remove from room, character, and containers.");
+      "fromall()\n"
+      "\n"
+      "Remove object from whichever room, character, or container it is in.");
     PyObj_addMethod("store", PyObj_store, METH_NOARGS,
-		    "return a storage set for the object.");
+      "store()\n"
+      "\n"
+      "Return a storage set representing the object.");
+    PyObj_addMethod("copy", PyObj_copy, METH_NOARGS,
+      "copy()\n"
+      "\n"
+      "Returns a copy of the object.");
 
     makePyType(&PyObj_Type, pyobj_getsetters, pyobj_methods);
     deleteListWith(pyobj_getsetters, free); pyobj_getsetters = NULL;
@@ -1335,7 +1396,8 @@
 
     // make the obj module
     m = Py_InitModule3("obj", obj_module_methods,
-                       "The object module, for all object-related MUD stuff.");
+      "Contains the Python wrapper for game objects. Also contains utilities\n"
+      "for listing, storing, and generating objects from prototypes.");
 
     // make sure the obj module parsed OK
     if (m == NULL)
diff -ruN ../nakedmudv3.7.9/src/scripts/pyolc.c src/scripts/pyolc.c
--- ../nakedmudv3.7.9/src/scripts/pyolc.c	2008-12-05 21:37:14.000000000 -0500
+++ src/scripts/pyolc.c	2009-04-05 13:07:11.000000000 -0400
@@ -369,15 +369,25 @@
 PyMODINIT_FUNC
 init_PyOLC(void) {
   // add all of our methods
-  PyOLC_addMethod("do_olc", pyolc_do_olc, METH_VARARGS,"Enter the OLC editor.");
+  PyOLC_addMethod("do_olc", pyolc_do_olc, METH_VARARGS,
+    "do_olc(sock, menu_func, chooser_func, parse_func, saver_func, data, autosave=False)\n\n"
+    "Entry point to the olc system. See olc2/olc.h for documentation.");
   PyOLC_addMethod("item_add_olc", pyolc_item_add_olc, METH_VARARGS, 
-		  "Add a new OLC for editing a Python item type.");
+    "item_add_olc(itemtype, menu_func, chooser_func, parse_func,\n"
+    "             fromproto_func, toproto_func)\n\n"
+    "Register a new olc handler for an item type. See items/iedit.h for\n"
+    "documentation.");
   PyOLC_addMethod("extend", pyolc_extend, METH_VARARGS,
-		  "Extends an already existing OLC command");
+    "extend(olc_type, optname, menu_func, chooser_func, parse_func = None,\n"
+    "       fromproto_func = None, toproto_func = None)\n\n"
+    "Register a new olc menu extender. Types are medit, redit, and oedit. See\n"
+    "olc2/olc_extender.h for documentation.");
 
   // create the module
   PyObject *m = Py_InitModule3("olc", makePyMethods(pyolc_methods),
-			       "The Python module for OLC.");
+    "This is the Python wrapper for the online creation module. Allows users\n"
+    "to set up new menus and handlers for editing data, such as characters,\n"
+    "while online.");
 
   // set some important OLC values as well
   PyObject_SetAttrString(m, "MENU_NOCHOICE", Py_BuildValue("i", MENU_NOCHOICE));
diff -ruN ../nakedmudv3.7.9/src/scripts/pyplugs.c src/scripts/pyplugs.c
--- ../nakedmudv3.7.9/src/scripts/pyplugs.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pyplugs.c	2009-03-18 18:16:56.000000000 -0400
@@ -97,6 +97,7 @@
   if(!*arg)
     send_to_char(ch, "Which module or package would you like to load?\r\n");
   else {
+    send_to_char(ch, "{rpyload is unsafe and has been deprecated.{n\r\n");
     char fname[SMALL_BUFFER];
     sprintf(fname, "%s/%s.py", PYMOD_LIB, arg);
     // make sure the file exists
diff -ruN ../nakedmudv3.7.9/src/scripts/pyroom.c src/scripts/pyroom.c
--- ../nakedmudv3.7.9/src/scripts/pyroom.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pyroom.c	2009-04-05 12:39:18.000000000 -0400
@@ -736,7 +736,7 @@
   bool interrupts = FALSE;
 
   // parse all of the values
-  if (!PyArg_ParseTuple(args, "szOsb", &name, &sort_by, &func,
+  if (!PyArg_ParseTuple(args, "szOs|b", &name, &sort_by, &func,
   			&group, &interrupts)) {
     PyErr_Format(PyExc_TypeError, 
 		 "Could not add new room command. Improper arguments supplied");
@@ -1025,7 +1025,11 @@
     0,                         /*tp_setattro*/
     0,                         /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-    "Python Room object",      /* tp_doc */
+    "__init__(self, uid_or_string_key)\n\n"
+    "Creates a new Python reference to a room, by uid. If a string database\n"
+    "key is instead supplied, first try to generate a room by an rporoto of\n"
+    "the same name. If no rproto exists, create a new blank room in the room\n"
+    "table, and assign it the given key.",
     0,		               /* tp_traverse */
     0,		               /* tp_clear */
     0,		               /* tp_richcompare */
@@ -1047,13 +1051,25 @@
 
 PyMethodDef room_module_methods[] = {
   { "get_room", (PyCFunction)PyRoom_get_room, METH_VARARGS,
-    "Takes a room key/locale and returns a pointer to that room." },
+    "get_room(key)\n"
+    "\n"
+    "Takes a room key/locale and returns the matching room, or None." },
   { "is_loaded", (PyCFunction)PyRoom_loaded, METH_VARARGS,
-    "Returns whether the given room key has been loaded to the game." },
+    "is_loaded(key)\n"
+    "\n"
+    "Returns whether a room with the given key currently exists in game." },
   { "instance",  (PyCFunction)PyRoom_instance, METH_VARARGS,
-    "Returns a new instanced room to the game." },
+    "instance(room_proto, as_key = None)\n"
+    "\n"
+    "Create an instanced copy of a room, specified by a room prototype name.\n"
+    "If as_key is None, the instanced room's key will be a derivation of\n"
+    "the original prototype name, with a uid number appended to it. Otherwise\n"
+    "as_key is used for the room's key." },
   { "is_abstract",  (PyCFunction)PyRoom_is_abstract, METH_VARARGS,
-    "Returns whether a room with the specified prototype is abstract." },
+    "is_abstract(proto)\n"
+    "\n"
+    "Returns whether a specified room prototype is abstract. Also return True\n"
+    "if the prototype does not exist." },
   {NULL, NULL, 0, NULL}  /* Sentinel */
 };
 
@@ -1097,73 +1113,122 @@
 
     // add all of the basic getsetters
     PyRoom_addGetSetter("name",    PyRoom_getname,     PyRoom_setname, 
-			"the room's name");
+      "The room's name, e.g., Town Square.");
     PyRoom_addGetSetter("desc",    PyRoom_getdesc,     PyRoom_setdesc, 
-			"the room's desc");
+      "The room's description when, e.g., looked at.");
     PyRoom_addGetSetter("proto",   PyRoom_getclass,    NULL, 
-			"The room's class");
+      "The room's unique identifier key. For non-instanced rooms, equivalent\n"
+      "to the main room prototype inherited from. Immutable.");
     PyRoom_addGetSetter("locale",  PyRoom_getlocale,   NULL, 
-			"The zone we belong to");
+      "The zone a room belongs to. Immutable.");
     PyRoom_addGetSetter("protoname",PyRoom_getprotoname,NULL, 
-			"The head of our proto");
+      "The first half of the room's unique identifier key. Immutable.");
     PyRoom_addGetSetter("protos",  PyRoom_getprotos,   NULL, 
-			"The room's prototypes");
+      "A comma-separated list of room prototypes this room inherits from. Immutable.");
     PyRoom_addGetSetter("chars",   PyRoom_getchars,    NULL, 
-			"chars in the room");
+      "A list of all characters in the room. Immutable. See char.Char.room\n"
+      "for changing the room a character is in.");
     PyRoom_addGetSetter("objs",  PyRoom_getobjs,       NULL, 
-			"objects in the room");
+      "Alias for room.Room.contents");
     PyRoom_addGetSetter("contents",PyRoom_getobjs,     NULL, 
-			"objects in the room");
+      "A list of objects in the room. Immutable. See obj.Obj.room for\n"
+      "changing the room an object is in.");
     PyRoom_addGetSetter("exnames", PyRoom_getexnames,  NULL, 
-			"the room's exits");
+      "A list of the room's exits, by direction. Immutable. See room.Room.dig\n"
+      "for creating new links between rooms.");
     PyRoom_addGetSetter("uid",     PyRoom_getuid,      NULL,
-			"the room's uid");
+      "The room's unique identification number. Immutable.");
     PyRoom_addGetSetter("terrain", PyRoom_getterrain,  PyRoom_setterrain,
-			"the room's terrain type");
+      "The current terrain type of the room.");
     PyRoom_addGetSetter("bits",    PyRoom_getbits,     PyRoom_setbits,
-			"the room's bits");
+      "A comma-separated list of setting bits currently toggled on the room.");
 
     // add all of the basic methods
     PyRoom_addMethod("attach", PyRoom_attach, METH_VARARGS,
-		     "attach a new script to the room.");
+      "attach(trigger)\n"
+      "\n"
+      "Attach a trigger to the room by key name.");
     PyRoom_addMethod("detach", PyRoom_detach, METH_VARARGS,
-		     "detach a script from the room, by vnum.");
+      "detach(trigger)\n"
+      "\n"
+      "Detach a trigger from the room by key name.");
     PyRoom_addMethod("dig", PyRoom_dig, METH_VARARGS,
-		     "digs in direction to the target room. Returns exit.");
+      "dig(dir, dest)\n"
+      "\n"
+      "Link the room to another room via the specified direction. The\n"
+      "destination room can be an actual room or a room key name. Returns\n"
+      "the created exit. If an exit already exists in the specified\n"
+      "direction, change its destination.");
     PyRoom_addMethod("fill", PyRoom_fill, METH_VARARGS,
-		     "fills in direction for the room.");
+      "fill(dir)\n"
+      "\n"
+      "Erases an exit in the specified direction.");
     PyRoom_addMethod("exit", PyRoom_get_exit, METH_VARARGS,
-		     "gets an exit in the room with the given direction name.");
+      "exit(dir)\n"
+      "\n"
+      "Returns an exit for the specified direction, or None.");
     PyRoom_addMethod("exdir", PyRoom_get_exit_dir, METH_VARARGS,
-		     "returns the direction of the exit.");
+      "exdir(exit)\n"
+      "\n"
+      "Returns the direction for a specified exit, or None.");
     PyRoom_addMethod("send", PyRoom_send, METH_VARARGS,
-		     "send a message to everyone in the room.");
+      "send(mssg)\n"
+      "\n"
+      "Send a message to all characters in the room.");
     PyRoom_addMethod("edesc", PyRoom_edesc, METH_VARARGS,
-		     "adds an extra description to the room.");
+      "edesc(keywords, desc)\n"
+      "\n"
+      "Create an extra description for the room, accessible via a comma-\n"
+      "separated list of keywords.");
     PyRoom_addMethod("add_cmd", PyRoom_add_cmd, METH_VARARGS,
-		     "adds a command to the room.");
+      "add_cmd(name, shorthand, cmd_func, user_group, interrupts = False)\n"
+      "\n"
+      "Add a new player command specific to the room. See mudsys.add_cmd for\n"
+      "documentation on commands.");
     PyRoom_addMethod("add_cmd_check", PyRoom_add_cmd_check, METH_VARARGS,
-		     "adds a pre-check to a room command.");
+      "add_cmd_check(cmd_name, check_func)\n"
+      "\n"
+      "Add a new command check function specific to the room. See \n"
+      "mudsys.add_cmd_check for documentation on command checks.");
     PyRoom_addMethod("isinstance", PyRoom_isinstance, METH_VARARGS,
-		     "returns whether or not the room inherits from the proto");
+      "isinstance(prototype)\n"
+      "\n"
+      "returns whether the room inherits from a specified room prototype.");
     PyRoom_addMethod("getAuxiliary", PyRoom_get_auxiliary, METH_VARARGS,
-		     "get's the specified piece of aux data from the room");
+      "getAuxiliary(name)\n"
+      "\n"
+      "Returns room's auxiliary data of the specified name.");
     PyRoom_addMethod("aux", PyRoom_get_auxiliary, METH_VARARGS,
-		     "get's the specified piece of aux data from the room");
+      "Alias for room.Room.getAuxiliary(name)");
     PyRoom_addMethod("getvar", PyRoom_getvar, METH_VARARGS,
-		    "get the value of a special variable the room has.");
+      "getvar(name)\n"
+      "\n"
+      "Return value of a special variable. Return 0 if no value has been set.");
     PyRoom_addMethod("setvar", PyRoom_setvar, METH_VARARGS,
-		    "set the value of a special variable the room has.");
+      "setvar(name, val)\n"
+      "\n"
+      "Set value of a special variable for the room. Values must be strings \n"
+      "or numbers. This function is intended to allow scripts and triggers to"
+      "open-endedly add variables to rooms.");
     PyRoom_addMethod("hasvar", PyRoom_hasvar, METH_VARARGS,
-		    "return whether or not the room has a given variable.");
+      "hasvar(name)\n"
+      "\n"
+      "Return True if a room has the given special variable. False otherwise.");
     PyRoom_addMethod("deletevar", PyRoom_deletevar, METH_VARARGS,
-		    "delete a variable from the room's variable table.");
+      "deletevar(name)\n"
+      "\n"
+      "Deletes a special variable from a room if they have one by the\n"
+      "given name.");
     PyRoom_addMethod("delvar", PyRoom_deletevar, METH_VARARGS,
-		    "delete a variable from the room's variable table.");
+      "Alias for room.Room.deletevar(name)");
     PyRoom_addMethod("reset", PyRoom_reset, METH_NOARGS,
-		     "run all of the room's reset commands.");
+      "reset()\n"
+      "\n"
+      "Runs a room's reset commands and reset hooks.");
     PyRoom_addMethod("hasBit", PyRoom_hasBit, METH_VARARGS,
-		     "return whether or not the room has a specified bit.");
+      "hasBit(name)\n"
+      "\n"
+      "Return whether room has a bit toggled.\n");
 
     // add in all the getsetters and methods
     makePyType(&PyRoom_Type, pyroom_getsetters, pyroom_methods);
@@ -1176,7 +1241,8 @@
 
     // initialize the module
     module = Py_InitModule3("room", room_module_methods,
-			    "The room module, for all MUD room-related stuff.");
+      "Contains the Python wrapper for rooms, and utilities for loading and\n"
+      "instancing rooms.");
 
     // make sure the module parsed OK
     if (module == NULL)
diff -ruN ../nakedmudv3.7.9/src/scripts/pysocket.c src/scripts/pysocket.c
--- ../nakedmudv3.7.9/src/scripts/pysocket.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pysocket.c	2009-04-05 12:41:04.000000000 -0400
@@ -418,6 +418,7 @@
 
 PyMethodDef socket_module_methods[] = {
   { "socket_list", (PyCFunction)PySocket_all_sockets, METH_NOARGS,
+    "socket_list()\n\n"
     "Returns a list of all sockets currently connected." },
   {NULL, NULL, 0, NULL}  /* Sentinel */
 };
@@ -461,52 +462,70 @@
 
     // add all of the basic getsetters
     PySocket_addGetSetter("uid", PySocket_getuid, NULL,
-			   "the socket's uid.");
+      "The socket's uid. Immutable.");
     PySocket_addGetSetter("account", PySocket_getaccount, NULL,
-			   "the socket's account.");
+      "The account currently attached to the socket, or None. Immutable.\n"
+      "see mudsys.attach_account_socket for connecting sockets and accounts.");
     PySocket_addGetSetter("character", PySocket_getchar, NULL,
-			   "the socket's character.");
+      "The character currently attached to the socket, on None. Immutable.\n"
+      "see mudsys.attach_char_socket for connecting characters to account.");
     PySocket_addGetSetter("char", PySocket_getchar, NULL,
-			   "the socket's character.");
+       "Alias for mudsock.Mudsock.character");
     PySocket_addGetSetter("ch",   PySocket_getchar, NULL,
-			   "the socket's character.");
+       "Alias for mudsock.Mudsock.character.");
     PySocket_addGetSetter("has_input", PySocket_getcmdread, NULL,
-			  "Have we read any input this iteration?");
+       "True or False if the socket has any input pending. Immutable.");
     PySocket_addGetSetter("outbound_text",
-			  PySocket_get_outbound_text,PySocket_set_outbound_text,
-			  "the socket's outbound text.");
-    PySocket_addGetSetter("can_use",
-			  PySocket_get_can_use, NULL,
-			  "Returns whether or not the socket is ready for use. "
-			  "Sockets become available after their dns resolves.");
+       PySocket_get_outbound_text, PySocket_set_outbound_text,
+       "The socket's outbound text.");
+    PySocket_addGetSetter("can_use", PySocket_get_can_use, NULL,
+      "True or False if the socket is ready for use. Socket becomes available\n"
+      "after its dns addresss resolves. Immutable.");
     PySocket_addGetSetter("state", PySocket_getstate, NULL,
-			  "Returns the state that the socket is in.");
+      "The state that the socket is in. Immutable. For more on states see\n"
+      "mudsock.Mudsock.push_ih");
     PySocket_addGetSetter("idle_time", PySocket_getidletime, NULL,
-			  "Returns how long (seconds) we've been idle.");
+      "How long (in seconds) the socket's input handler has been idle for. Immutable.");
     PySocket_addGetSetter("hostname", PySocket_gethostname, NULL,
-			  "return where we are connected from.");
+      "The dns address that the socket is connected from. Immutable.");
 
     // add all of the basic methods
     PySocket_addMethod("getAuxiliary", PySocket_get_auxiliary, METH_VARARGS,
-		       "gets the socket auxiliary data with given key.");
+      "getAuxiliary(name)\n\n"
+      "Returns socket's auxiliary data of the specified name.");
     PySocket_addMethod("aux", PySocket_get_auxiliary, METH_VARARGS,
-		       "gets the socket auxiliary data with given key.");
+      "Alias for mudsock.Mudsock.getAuxiliary");
     PySocket_addMethod("send", PySocket_send, METH_VARARGS,
-		       "sends text to the socket with appended newline.");
+      "send(mssg)\n\n"
+      "Sends text to the socket with appended newline.");
     PySocket_addMethod("send_raw", PySocket_send_raw, METH_VARARGS,
-		       "sends text to the socket.");
+      "send_raw(mssg)\n\n"
+      "Sends text to the socket. No appended newline.");
     PySocket_addMethod("pop_ih", PySocket_pop_ih, METH_NOARGS,
-			"Pops the socket's current input handler.");
+      "pop_ih()\n\n"
+      "Pops the socket's current input handler from its input handler stack.");
     PySocket_addMethod("push_ih", PySocket_push_ih, METH_VARARGS,
-			"pushes on a new input handler.");
+      "push_ih(handler_func, prompt_func, state=None)\n\n"
+      "Pushes a new input handler and prompt pair onto the socket's input\n"
+      "handler stack. Optionally, a (String) state value can be supplied.\n"
+      "Input handlers take two arguments: the socket and a string command.\n"
+      "Prompts take one argument: the socket. They should send the relevant\n"
+      "text for the prompt to the socket.");
     PySocket_addMethod("replace_ih", PySocket_replace_ih, METH_VARARGS,
-		       "replaces the socket's input handler.");
+      "repalce_ih(handler_func, prompt_func, state=None)\n\n"
+      "Calls pop_ih, followed by push_ih.");
     PySocket_addMethod("close", PySocket_close, METH_VARARGS,
-		       "closes the socket.");
+      "close()\n\n"
+      "Closes the socket's connection.");
     PySocket_addMethod("bust_prompt", PySocket_bust_prompt, METH_NOARGS,
-		       "busts the socket's prompt so it will be displayed.");
+      "bust_prompt()\n\n"
+      "Busts the socket's prompt so it will be displayed next pulse.");
     PySocket_addMethod("edit_text", PySocket_edit_text, METH_VARARGS, 
-		       "enter the text editor and begin editing something.");
+      "edit_text(dflt_value, on_complete, mode='text')\n\n"
+      "Enter the text editor, and set its default value. When the text editor\n"
+      "is edited, call on_complete. This function should take two arguments:\n"
+      "the socket doing the editing, and the output of the editor. Mode can\n"
+      "be 'text' or 'script'.");
 
     // add in all the getsetters and methods
     makePyType(&PySocket_Type, pysocket_getsetters, pysocket_methods);
@@ -519,8 +538,8 @@
 
     // initialize the module
     module = Py_InitModule3("mudsock", socket_module_methods,
-			    "The socket module, for all MUD socket-related "
-			    "stuff.");
+      "Contains the Python wrapper for sockets, and utilities for listing\n"
+      "currently connected sockets.");
 
     // make sure the module parsed OK
     if (module == NULL)
diff -ruN ../nakedmudv3.7.9/src/scripts/pystorage.c src/scripts/pystorage.c
--- ../nakedmudv3.7.9/src/scripts/pystorage.c	2009-03-02 01:00:40.000000000 -0500
+++ src/scripts/pystorage.c	2009-04-05 12:59:31.000000000 -0400
@@ -64,7 +64,41 @@
 //
 // initialize a new storage list
 int PyStorageList_init(PyStorageList *self, PyObject *args, PyObject *kwds) {
+  // are we building this from a Python list?
+  PyObject *pylist = NULL;
+  if(!PyArg_ParseTuple(args, "|O", &pylist)) {
+    PyErr_Format(PyExc_TypeError, "unexpected arguments passed to StorageList.");
+    return -1;
+  }
+  
+  // if we received something, make sure it's a list
+  if(pylist != NULL && !PyList_Check(pylist)) {
+    PyErr_Format(PyExc_TypeError, "StorageList expected a list argument.");
+    return -1;
+  }
+
+  // create the storage list
   self->list = new_storage_list();
+
+  // try adding contents to the storage list
+  if(pylist != NULL) {
+    int i;
+    // first, make sure they're all storage sets
+    for(i = 0; i < PyList_Size(pylist); i++) {
+      PyObject *set = PyList_GetItem(pylist, i);
+      if(!PyStorageSet_Check(set)) {
+	PyErr_Format(PyExc_TypeError, "StorageList list content to be a StorageSet.");
+	return -1;
+      }
+    }
+
+    // all good, append them
+    for(i = 0; i < PyList_Size(pylist); i++) {
+      PyObject *set = PyList_GetItem(pylist, i);
+      storage_list_put(self->list, PyStorageSet_AsSet(set));
+    }
+  }
+
   return 0;
 }
 
@@ -115,9 +149,11 @@
 //*****************************************************************************
 PyMethodDef PyStorageList_class_methods[] = {
   {"sets", PyStorageList_sets, METH_VARARGS,
-   "Returns a python list of all the sets in the storage list" },
+   "sets()\n\n"
+   "Returns a python list of all the sets in the storage list." },
   {"add",  PyStorageList_add,  METH_VARARGS,
-   "Adds a new storage set to the list" },
+   "add(storage_set)\n\n"
+   "Append a new storage set to the storage list." },
   {NULL, NULL, 0, NULL}  /* Sentinel */
 };
 
@@ -143,7 +179,9 @@
     0,                                /*tp_setattro*/
     0,                                /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-    "storage lists",                  /* tp_doc */
+    "__init__(self, list=None)\n\n"
+    "Create a new storage list. A Python list of storage sets may be\n"
+    "supplied, from which to build the storage list.",
     0,		                      /* tp_traverse */
     0,		                      /* tp_clear */
     0,		                      /* tp_richcompare */
@@ -262,8 +300,10 @@
 // read a boolean value from the storage set
 PyObject *PyStorageSet_readBool  (PyObject *self, PyObject *args) { 
   char *key = PyStorageSet_readParseKey(args);
-  if(key != NULL) 
-    return Py_BuildValue("i", read_bool(((PyStorageSet *)self)->set, key));
+  if(key != NULL) {
+    bool val = read_bool(((PyStorageSet *)self)->set, key);
+    return Py_BuildValue("O", (val ? Py_True : Py_False));
+  }
   else
     return NULL;
 }
@@ -396,42 +436,51 @@
 PyMethodDef PyStorageSet_class_methods[] = {
   // read functions
   { "readString", PyStorageSet_readString, METH_VARARGS,
-    "Read in the string value of a storage set entry, by key." },
+    "readString(name)\n\n"
+    "Read a string value from the storage set. Return empty string if the\n"
+    "storage set does not contain an entry by the given name." },
   { "readInt",    PyStorageSet_readInt,    METH_VARARGS,
-    "Read in the integer value of a storage set entry, by key." },
+    "Same as readString, for integers. Returns 0 if entry does not exist." },
   { "readDouble", PyStorageSet_readDouble, METH_VARARGS,
-    "Read in the double value of a storage set entry, by key." },
+    "Same as readString, for floating points. Returns 0 if entry does not exist.." },
   { "readBool",   PyStorageSet_readBool,   METH_VARARGS,
-    "Read in the boolean value of a storage set entry, by key." },
+    "Same as readString, for booleans. Returns False if entry does not exist."},
   { "readList",   PyStorageSet_readList,   METH_VARARGS,
-    "Read in the list value of a storage set entry, by key." },
+    "Same as readString, for storage lists. Returns an empty storage list\n"
+    "if entry does not exist." },
   { "readSet",    PyStorageSet_readSet,   METH_VARARGS,
-    "Read in the set value of a storage set entry, by key." },
+    "Same as readString, for storage sets. Returns an empty set if entry\n"
+    "does not exist." },
 
   // write store functions
   { "storeString", PyStorageSet_storeString, METH_VARARGS,
-    "Store the string value of a storage set entry, by key." },
+    "storeString(name, val)\n\n"
+    "Store a string value in the storage set." },
   { "storeInt",    PyStorageSet_storeInt,    METH_VARARGS,
-    "Store the integer value of a storage set entry, by key." },
+    "Same as storeString, for integers." },
   { "storeDouble", PyStorageSet_storeDouble, METH_VARARGS,
-    "Store the double value of a storage set entry, by key." },
+    "Same as storeString, for floating point values." },
   { "storeBool",   PyStorageSet_storeBool,   METH_VARARGS,
-    "Store the boolean value of a storage set entry, by key." },
+    "Same as storeString, for boolean values." },
   { "storeList",   PyStorageSet_storeList,   METH_VARARGS,
-    "Store the list value of a storage set entry, by key." },
+    "Same as storeString, for storage lists." },
   { "storeSet",    PyStorageSet_storeSet,    METH_VARARGS,
-    "Store the set value of a storage set entry, by key." },
+    "Same as storeString, for storage sets." },
 
   // other functions
   { "write",       PyStorageSet_write,       METH_VARARGS,
-    "Store the contents of the storage set to the specified filename" },
-  { "close",       PyStorageSet_close,       METH_VARARGS,
-    "Close a storage set. MUST be called when the storage set is done "
-    "being used. Garbage collection will not delete the set." },
+    "write(filename)\n\n"
+    "Write the contents of a storage set to the specified file name." },
+  { "close",       PyStorageSet_close,       METH_NOARGS,
+    "close()\n\n"
+    "Recursively close a storage set and all of its children sets and lists.\n"
+    "MUST be called when the storage set has finished being used. Garbage\n"
+    "collection will not delete the set." },
   { "contains",    PyStorageSet_contains,    METH_VARARGS,
-    "Returns True if the set contains the given key, and false otherwise." },
+    "contains(name)\n\n"
+    "Returns True or False if the set contains an entry by the given name." },
   { "__contains__",    PyStorageSet_contains,    METH_VARARGS,
-    "Returns True if the set contains the given key, and false otherwise." },
+    "__contains__(name) <==> name in self" },
 
   {NULL, NULL, 0, NULL}  /* Sentinel */
 };
@@ -459,7 +508,9 @@
     0,                                /*tp_setattro*/
     0,                                /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-    "storage sets",                   /* tp_doc */
+    "__init__(self, filename=None)\n\n"
+    "Create a new storage set. If a file name is supplied, read a storage set\n"
+    "in from the specified file.",
     0,		                      /* tp_traverse */
     0,		                      /* tp_clear */
     0,		                      /* tp_richcompare */
@@ -494,7 +545,11 @@
 //*****************************************************************************
 PyMODINIT_FUNC init_PyStorage(void) {
   PyObject *module = Py_InitModule3("storage", PyStorage_module_methods,
-				    "Python wrapper for storage sets.");
+    "The storage module allows users to save information to disk as key:value\n"
+    "pairs without having to interact with files directly. This module gives\n"
+    "users access to two classes: StorageSets and StorageLists. Sets match\n"
+    "keys to values. Lists hold multiple sets.");
+
   // something went wrong... abort!
   if(module == NULL)
     return;
diff -ruN ../nakedmudv3.7.9/src/scripts/trigedit.c src/scripts/trigedit.c
--- ../nakedmudv3.7.9/src/scripts/trigedit.c	2009-03-02 01:08:06.000000000 -0500
+++ src/scripts/trigedit.c	2009-04-01 14:02:18.000000000 -0400
@@ -11,6 +11,7 @@
 #include "../utils.h"
 #include "../world.h"
 #include "scripts.h"
+#include "trighooks.h"
 
 
 
@@ -84,59 +85,28 @@
 #define TEDIT_NAME       1
 #define TEDIT_TYPE       2
 
-struct trigger_type_usable_list {
-  char    *type;
-  char *used_by;
-};
-
-// a table of allowable trigger types
-struct trigger_type_usable_list trigger_types[] = {
-  { "speech",         "mob, room" },
-  { "greet",          "mob"       },
-  { "enter",          "mob, room" },
-  { "exit",           "mob, room" },
-  { "self_enter",     "mob"       },
-  { "self_exit",      "mob"       },
-  { "drop",           "obj, room" },
-  { "get",            "obj, room" },
-  { "give",           "obj, mob"  },
-  { "receive",        "mob"       },
-  { "wear",           "obj, mob"  },
-  { "remove",         "obj, mob"  },
-  { "reset",          "room"      },
-  { "look",           "obj, mob, room" },
-  { "open",           "obj, room" },
-  { "close",          "obj, room" },
-  { "to_game",        "obj, mob, room" },
-  { "", "" },
-};
-
-int num_trig_types(void) {
-  static int num = -1;
-  // we need to calculate...
-  if(num == -1)
-    do { num++; } while(*trigger_types[num].type);
-  return num;
-}
-
-// returns the trigger type name, for the given number
-const char *triggerTypeGetName(int num) {
-  return trigger_types[num].type;
-}
-
-// returns the types of things the trigger can be attached to
-const char *triggerTypeGetUsedBy(int num) {
-  return trigger_types[num].used_by;
-}
-
-// returns a buffer that contains the name and used-by list for a trigger
-const char *triggerTypeGetNameAndUsedBy(int num) {
-  static char buf[100];
-  sprintf(buf, "%-20s %s", triggerTypeGetName(num), triggerTypeGetUsedBy(num));
-  return buf;
-}
+
+
+//*****************************************************************************
+// tedit OLC functions
+//*****************************************************************************
 
 void tedit_menu(SOCKET_DATA *sock, TRIGGER_DATA *trigger) {
+  // the display line for our trigger type
+  BUFFER *ttype_line = newBuffer(1);
+  if(!*triggerGetType(trigger))
+    bufferCat(ttype_line, "<NONE>");
+  else {
+    bufferCat(ttype_line, triggerGetType(trigger));
+
+    // is it a valid type?
+    if(hashIn(get_tedit_opts(), triggerGetType(trigger)))
+      bprintf(ttype_line, "   (%s)", (char *)hashGet(get_tedit_opts(), 
+						   triggerGetType(trigger)));
+    else
+      bprintf(ttype_line, "   {r* unknown trigger type");
+  }
+
   send_to_socket(sock,
 		 "{g[{c%s{g]\r\n"
 		 "{g1) Name        : {c%s\r\n"
@@ -144,8 +114,11 @@
 		 "{g3) Script Code\r\n",
 		 triggerGetKey(trigger),
 		 triggerGetName(trigger),
-		 (*triggerGetType(trigger) ? triggerGetType(trigger):"<NONE>"));
+		 bufferString(ttype_line));
   script_display(sock, triggerGetCode(trigger), FALSE);
+
+  // garbage collection
+  deleteBuffer(ttype_line);
 }
 
 int tedit_chooser(SOCKET_DATA *sock, TRIGGER_DATA *trigger, const char *option){
@@ -154,10 +127,36 @@
     send_to_socket(sock, "Enter trigger name: ");
     return TEDIT_NAME;
   case '2':
-    send_to_socket(sock, "      {wType                 Usable By\r\n");
-    send_to_socket(sock, "      {y-----------------------------------\r\n");
-    olc_display_table(sock, triggerTypeGetNameAndUsedBy, num_trig_types(), 1);
+    send_to_socket(sock, 
+		   "{w%-18s %-20s%-18s %-22s\r\n", 
+		   "Type", "Usable By", "Type", "Usable By");
+    send_to_socket(sock, "{y------------------------------------------------------------------------------{g\r\n");
+
+    // get our keys, sort them alphabetically, and then list them all
+    HASHTABLE        *opts = get_tedit_opts();
+    LIST             *keys = hashCollect(opts);
+    listSortWith(keys, strcasecmp);
+    LIST_ITERATOR   *key_i = newListIterator(keys);
+    const char        *key = NULL;
+    int             parity = 0;
+
+    // display our keys, one at a time
+    ITERATE_LIST(key, key_i) {
+      send_to_socket(sock, "%-18s %-20s", key, (char *)hashGet(opts, key));
+      parity = (parity + 1) % 2;
+      if(parity == 0)
+	send_to_socket(sock, "\r\n");
+    } deleteListIterator(key_i);
+
+    // need a newline
+    if(parity == 1)
+      send_to_socket(sock, "\r\n");
+
     send_to_socket(sock, "\r\nEnter trigger type: ");
+
+    // garbage collection
+    deleteListWith(keys, free);
+
     return TEDIT_TYPE;
   case '3':
     socketStartEditor(sock, script_editor, triggerGetCodeBuffer(trigger));
@@ -175,6 +174,8 @@
     return TRUE;
 
   case TEDIT_TYPE: {
+    triggerSetType(trigger, arg);
+    /*
     int num = atoi(arg);
     if(num < 0 || num >= num_trig_types())
       return FALSE;
@@ -182,6 +183,8 @@
       triggerSetType(trigger, triggerTypeGetName(num));
       return TRUE;
     }
+    */
+    return TRUE;
   }
 
   default: 
diff -ruN ../nakedmudv3.7.9/src/scripts/trighooks.c src/scripts/trighooks.c
--- ../nakedmudv3.7.9/src/scripts/trighooks.c	2009-03-02 01:08:22.000000000 -0500
+++ src/scripts/trighooks.c	2009-04-01 14:02:06.000000000 -0400
@@ -23,6 +23,8 @@
 #include "pyobj.h"
 #include "pyroom.h"
 #include "pyexit.h"
+#include "pymudsys.h"
+#include "trighooks.h"
 
 
 
@@ -30,17 +32,15 @@
 // local datastructures and defines
 //*****************************************************************************
 
-// values for figuring out what "me" and optional variables are in gen_do_trig
-#define VARTYPE_CHAR      0
-#define VARTYPE_OBJ       1
-#define VARTYPE_ROOM      2
+// a table matching trigger types to what they can attach to (obj, mob, room)
+HASHTABLE *tedit_opts = NULL;
 
 // used for providing additional variables to gen_do_trig that are not standard
-typedef struct {
+struct opt_var {
   char *name;
   void *data;
   int   type;
-} OPT_VAR;
+};
 
 OPT_VAR *newOptVar(const char *name, void *data, int type) {
   OPT_VAR *var = malloc(sizeof(OPT_VAR));
@@ -55,6 +55,16 @@
   free(var);
 }
 
+HASHTABLE *get_tedit_opts(void) {
+  return tedit_opts;
+}
+
+void register_tedit_opt(const char *type, const char *desc) {
+  if(tedit_opts == NULL)
+    tedit_opts = newHashtable();
+  hashPut(tedit_opts, type, strdupsafe(desc));
+}
+
 
 
 //*****************************************************************************
@@ -114,9 +124,9 @@
   if(me) {
     PyObject *pyme = NULL;
     switch(me_type) {
-    case VARTYPE_CHAR:  pyme = charGetPyForm(me); break;
-    case VARTYPE_OBJ:   pyme = objGetPyForm(me);  break;
-    case VARTYPE_ROOM:  pyme = roomGetPyForm(me); break;
+    case TRIGVAR_CHAR:  pyme = charGetPyForm(me); break;
+    case TRIGVAR_OBJ:   pyme = objGetPyForm(me);  break;
+    case TRIGVAR_ROOM:  pyme = roomGetPyForm(me); break;
     }
     PyDict_SetItemString(dict, "me", pyme);
     listPut(varnames, strdup("me"));
@@ -131,9 +141,9 @@
     ITERATE_LIST(opt, opt_i) {
       pyopt = NULL;
       switch(opt->type) {
-      case VARTYPE_CHAR:  pyopt = charGetPyForm(opt->data); break;
-      case VARTYPE_OBJ:   pyopt = objGetPyForm(opt->data);  break;
-      case VARTYPE_ROOM:  pyopt = roomGetPyForm(opt->data); break;
+      case TRIGVAR_CHAR:  pyopt = charGetPyForm(opt->data); break;
+      case TRIGVAR_OBJ:   pyopt = objGetPyForm(opt->data);  break;
+      case TRIGVAR_ROOM:  pyopt = roomGetPyForm(opt->data); break;
       }
       PyDict_SetItemString(dict, opt->name, pyopt);
       listPut(varnames, strdup(opt->name));
@@ -157,174 +167,31 @@
   Py_XDECREF(dict);
 }
 
-
-//
-// handles all of a character's triggers
-void do_char_trigs(CHAR_DATA *ch, const char *type, void *thing, void *arg) {
-  if(ch == NULL)
-    return;
-
-  if(listSize(charGetTriggers(ch)) > 0) {
-    // first, build a list of all our triggers of this type
-    LIST           *trigs = newList();
-    LIST_ITERATOR *trig_i = newListIterator(charGetTriggers(ch));
-    const char       *key = NULL;
-    TRIGGER_DATA    *trig = NULL;
-    ITERATE_LIST(key, trig_i) {
-      if((trig = worldGetType(gameworld, "trigger", key)) != NULL &&
-	 !strcasecmp(triggerGetType(trig), type))
-	listPut(trigs, trig);
-    } deleteListIterator(trig_i);
-
-    // did we find any triggers?
-    if(listSize(trigs) > 0) {
-      trig_i = newListIterator(trigs);
-      ITERATE_LIST(trig, trig_i) {
-	if(!strcasecmp(type, "speech"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,NULL,NULL,arg,NULL);
-	else if(!strcasecmp(type, "look"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "self_exit"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,NULL,NULL,NULL,thing,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "self_enter"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "enter"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "exit"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,arg,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "greet"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "give"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,thing,arg,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "receive"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,thing,arg,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "wear"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,NULL,thing,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "remove"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,NULL,thing,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "to_game"))
-	  gen_do_trig(trig,ch,VARTYPE_CHAR,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
-	else {
-	  log_string("Unrecognized trigger type %s attached to %s, uid %d.\r\n",
-		     type, charGetClass(ch), charGetUID(ch));
-	}
-      } deleteListIterator(trig_i);
-    }
-    
-    // clean up our mess
-    deleteList(trigs);
-  }
-}
-
 //
-// handles all of an object's triggers
-void do_obj_trigs(OBJ_DATA *obj, const char *type, void *thing, void *arg) {
-  if(obj == NULL)
-    return;
-
-  if(listSize(objGetTriggers(obj)) > 0) {
-    // first, build a list of all our triggers of this type
-    LIST           *trigs = newList();
-    LIST_ITERATOR *trig_i = newListIterator(objGetTriggers(obj));
-    const char       *key = NULL;
-    TRIGGER_DATA    *trig = NULL;
-    ITERATE_LIST(key, trig_i) {
-      if((trig = worldGetType(gameworld, "trigger", key)) != NULL &&
-	 !strcasecmp(triggerGetType(trig), type))
-	listPut(trigs, trig);
-    } deleteListIterator(trig_i);
-
-    // did we find any triggers?
-    if(listSize(trigs) > 0) {
-      trig_i = newListIterator(trigs);
-      ITERATE_LIST(trig, trig_i) {
-	if(!strcasecmp(type, "give")) {
-	  // set up the optional "receiver" variable
-	  LIST *opts = newList();
-	  listPut(opts, newOptVar("recv", arg, VARTYPE_CHAR));
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,opts);
-	  deleteListWith(opts, deleteOptVar);
-	}
-	else if(!strcasecmp(type, "get"))
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "drop"))
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "wear"))
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "remove"))
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "open"))
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "close"))
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "look"))
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "to_game"))
-	  gen_do_trig(trig,obj,VARTYPE_OBJ,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
-	else {
-	  log_string("Unrecognized trigger type %s attached to %s, uid %d.\r\n",
-		     type, objGetClass(obj), objGetUID(obj));
-	}
-      } deleteListIterator(trig_i);
-    }
-
-    // clean up our mess
-    deleteList(trigs);
-  }
-}
+// generalized function for running all triggers of a specified type.
+void gen_do_trigs(void *me, int me_type, const char *type,
+		  CHAR_DATA *ch,OBJ_DATA *obj, ROOM_DATA *room, EXIT_DATA *exit,
+		  const char *command, const char *arg, LIST *optional) {
+  // find our list of triggers
+  LIST *trig_keys = NULL;
+  if(me_type == TRIGVAR_CHAR)
+    trig_keys = charGetTriggers(me);
+  else if(me_type == TRIGVAR_OBJ)
+    trig_keys = objGetTriggers(me);
+  else if(me_type == TRIGVAR_ROOM)
+    trig_keys = roomGetTriggers(me);
 
-//
-// handles all of a room's triggers
-void do_room_trigs(ROOM_DATA *rm, const char *type, void *thing, void *arg){
-  if(rm == NULL)
+  if(trig_keys == NULL || listSize(trig_keys) == 0)
     return;
-
-  if(listSize(roomGetTriggers(rm)) > 0) {
-    // first, build a list of all our triggers of this type
-    LIST           *trigs = newList();
-    LIST_ITERATOR *trig_i = newListIterator(roomGetTriggers(rm));
-    const char       *key = NULL;
-    TRIGGER_DATA    *trig = NULL;
-    ITERATE_LIST(key, trig_i) {
-      if((trig = worldGetType(gameworld, "trigger", key)) != NULL &&
-	 !strcasecmp(triggerGetType(trig), type))
-	listPut(trigs, trig);
-    } deleteListIterator(trig_i);
-
-    // did we find any triggers?
-    if(listSize(trigs) > 0) {
-      trig_i = newListIterator(trigs);
-      ITERATE_LIST(trig, trig_i) {
-	if(!strcasecmp(type, "get"))
-	  gen_do_trig(trig,rm,VARTYPE_ROOM,thing,arg,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "drop"))
-	  gen_do_trig(trig,rm,VARTYPE_ROOM,thing,arg,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "enter"))
-	  gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "exit"))
-	  gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,arg,NULL,NULL,NULL);
- 	else if(!strcasecmp(type, "look"))
- 	  gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "speech"))
-	  gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,NULL,NULL,arg,NULL);
-	else if(!strcasecmp(type, "reset"))
-	  gen_do_trig(trig,rm,VARTYPE_ROOM,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
-	else if(!strcasecmp(type, "open"))
-	  gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,arg,NULL,NULL,NULL);
- 	else if(!strcasecmp(type, "close"))
- 	  gen_do_trig(trig,rm,VARTYPE_ROOM,thing,NULL,NULL,arg,NULL,NULL,NULL);
- 	else if(!strcasecmp(type, "to_game"))
- 	  gen_do_trig(trig,rm,VARTYPE_ROOM,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
-	else {
-	  log_string("Unrecognized trigger type %s attached to %s, uid %d.\r\n",
-		     type, roomGetClass(rm), roomGetUID(rm));
-	}
-      } deleteListIterator(trig_i);
-    }
-    
-    // clean up our mess
-    deleteList(trigs);
-  }
+  
+  char        *trig_key = NULL;
+  LIST_ITERATOR *trig_i = newListIterator(trig_keys);
+  TRIGGER_DATA    *trig = NULL;
+  ITERATE_LIST(trig_key, trig_i) {
+    if((trig = worldGetType(gameworld, "trigger", trig_key)) != NULL &&
+       !strcasecmp(triggerGetType(trig), type))
+      gen_do_trig(trig,me,me_type,ch,obj,room,exit,command,arg,optional);
+  } deleteListIterator(trig_i);
 }
 
 
@@ -338,9 +205,15 @@
   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);
+  gen_do_trigs(ch,TRIGVAR_CHAR,"give",recv,obj,NULL,NULL,NULL,NULL,NULL);
+  gen_do_trigs(recv,TRIGVAR_CHAR,"receive",ch,obj,NULL,NULL,NULL,NULL,NULL);
+
+  LIST *opts = newList();
+  listPut(opts, newOptVar("vict", recv, TRIGVAR_CHAR));
+  gen_do_trigs(obj,TRIGVAR_OBJ,"give",ch,NULL,NULL,NULL,NULL,NULL,opts);
+
+  // garbage collection
+  deleteListWith(opts, deleteOptVar);
 }
 
 void do_get_trighooks(const char *info) {
@@ -348,17 +221,16 @@
   OBJ_DATA *obj = NULL;
   hookParseInfo(info, &ch, &obj);
 
-  do_obj_trigs (obj,             "get", ch, NULL);
-  do_room_trigs(charGetRoom(ch), "get", ch, obj);
+  gen_do_trigs(obj,TRIGVAR_OBJ,"get",ch,NULL,NULL,NULL,NULL,NULL,NULL);
+  gen_do_trigs(charGetRoom(ch),TRIGVAR_ROOM,"get",ch,obj,NULL,NULL,NULL,NULL,NULL);
 }
 
 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);
+  gen_do_trigs(obj,TRIGVAR_OBJ,"drop",ch,NULL,NULL,NULL,NULL,NULL,NULL);
+  gen_do_trigs(charGetRoom(ch),TRIGVAR_ROOM,"drop",ch,obj,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_enter_trighooks(const char *info) {
@@ -370,10 +242,10 @@
   CHAR_DATA       *mob = NULL;
   ITERATE_LIST(mob, mob_i) {
     if(ch != mob)
-      do_char_trigs(mob, "enter", ch, NULL);
+      gen_do_trigs(mob,TRIGVAR_CHAR,"enter",ch,NULL,NULL,NULL,NULL,NULL,NULL);
   } deleteListIterator(mob_i);
-  do_room_trigs(room, "enter", ch, NULL);
-  do_char_trigs(ch,   "self_enter", NULL, NULL);
+  gen_do_trigs(room,TRIGVAR_ROOM,"enter",ch,NULL,NULL,NULL,NULL,NULL,NULL);
+  gen_do_trigs(ch,TRIGVAR_CHAR,"self enter",NULL,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_exit_trighooks(const char *info) {
@@ -386,10 +258,10 @@
   CHAR_DATA       *mob = NULL;
   ITERATE_LIST(mob, mob_i) {
     if(ch != mob)
-      do_char_trigs(mob, "exit", ch, exit);
+      gen_do_trigs(mob,TRIGVAR_CHAR,"exit",ch,NULL,NULL,exit,NULL,NULL,NULL);
   } deleteListIterator(mob_i);
-  do_room_trigs(room, "exit", ch,   exit);
-  do_char_trigs(ch,   "self_exit", exit, NULL);
+  gen_do_trigs(room,TRIGVAR_ROOM,"exit",ch,NULL,NULL,exit,NULL,NULL,NULL);
+  gen_do_trigs(ch,TRIGVAR_CHAR,"self exit",NULL,NULL,NULL,exit,NULL,NULL,NULL);
 }
 
 void do_ask_trighooks(const char *info) {
@@ -397,8 +269,10 @@
   CHAR_DATA *listener = NULL;
   char        *speech = NULL;
   hookParseInfo(info, &ch, &listener, &speech);
-  do_char_trigs(listener, "speech", ch, speech);
-  if(speech) free(speech);
+  gen_do_trigs(listener,TRIGVAR_CHAR,"speech",ch,NULL,NULL,NULL,NULL,speech,NULL);
+
+  // garbage collection
+  free(speech);
 }
 
 void do_say_trighooks(const char *info) {
@@ -410,34 +284,35 @@
   CHAR_DATA       *mob = NULL;
   ITERATE_LIST(mob, mob_i) {
     if(ch != mob)
-      do_char_trigs(mob, "speech", ch, speech);
+     gen_do_trigs(mob,TRIGVAR_CHAR,"speech",ch,NULL,NULL,NULL,NULL,speech,NULL);
   } deleteListIterator(mob_i);
-  do_room_trigs(charGetRoom(ch), "speech", ch, speech);
-  if(speech) free(speech);
+  gen_do_trigs(charGetRoom(ch),TRIGVAR_ROOM,"speech",ch,NULL,NULL,NULL,NULL,speech,NULL);
+
+  // garbage collection
+  free(speech);
 }
 
 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);
+  gen_do_trigs(greeted,TRIGVAR_CHAR,"greet",ch,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_wear_trighooks(const char *info) {
   CHAR_DATA *ch = NULL;
   OBJ_DATA *obj = NULL;
   hookParseInfo(info, &ch, &obj);
-
-  do_char_trigs(ch,  "wear", obj, NULL);
-  do_obj_trigs (obj, "wear", ch,  NULL);
+  gen_do_trigs(ch,TRIGVAR_CHAR,"wear",NULL,obj,NULL,NULL,NULL,NULL,NULL);
+  gen_do_trigs(obj,TRIGVAR_OBJ,"wear",ch,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 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);
+  gen_do_trigs(ch,TRIGVAR_CHAR,"remove",NULL,obj,NULL,NULL,NULL,NULL,NULL);
+  gen_do_trigs(obj,TRIGVAR_OBJ,"remove",ch,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_reset_trighooks(const char *info) {
@@ -451,7 +326,8 @@
   ROOM_DATA      *room = NULL;
   ITERATE_LIST(name, res_i) {
     room = worldGetRoom(gameworld, get_fullkey(name, locale));
-    if(room != NULL) do_room_trigs(room, "reset", NULL, NULL);
+    if(room != NULL)
+     gen_do_trigs(room,TRIGVAR_ROOM,"reset",NULL,NULL,NULL,NULL,NULL,NULL,NULL);
   } deleteListIterator(res_i);
 
   // garbage collection
@@ -462,67 +338,67 @@
   CHAR_DATA *ch = NULL;
   EXIT_DATA *ex = NULL;
   hookParseInfo(info, &ch, &ex);
-  do_room_trigs(charGetRoom(ch), "open", ch, ex);
+  gen_do_trigs(charGetRoom(ch),TRIGVAR_ROOM,"open",ch,NULL,NULL,ex,NULL,NULL,NULL);
 }
 
 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);
+  gen_do_trigs(obj,TRIGVAR_OBJ,"open",ch,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_close_door_trighooks(const char *info) {
   CHAR_DATA *ch = NULL;
   EXIT_DATA *ex = NULL;
   hookParseInfo(info, &ch, &ex);
-  do_room_trigs(charGetRoom(ch), "close", ch, ex);
+  gen_do_trigs(charGetRoom(ch),TRIGVAR_ROOM,"close",ch,NULL,NULL,ex,NULL,NULL,NULL);
 }
 
 void do_close_obj_trighooks(const char *info) {
   CHAR_DATA *ch = NULL;
   OBJ_DATA *obj = NULL;
   hookParseInfo(info, &ch, &obj);
-  do_obj_trigs(obj, "close", ch, NULL);
+  gen_do_trigs(obj,TRIGVAR_OBJ,"close",ch,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_look_at_obj_trighooks(const char *info) {
   OBJ_DATA     *obj = NULL;
   CHAR_DATA *looker = NULL;
   hookParseInfo(info, &obj, &looker);
-  do_obj_trigs(obj, "look", looker, NULL);
+  gen_do_trigs(obj,TRIGVAR_OBJ,"look",looker,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_look_at_room_trighooks(const char *info) {
   ROOM_DATA   *room = NULL;
   CHAR_DATA *looker = NULL;
   hookParseInfo(info, &room, &looker);
-  do_room_trigs(room, "look", looker, NULL);
+  gen_do_trigs(room,TRIGVAR_ROOM,"look",looker,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_look_at_char_trighooks(const char *info) {
   CHAR_DATA     *ch = NULL;
   CHAR_DATA *looker = NULL;
   hookParseInfo(info, &ch, &looker);
-  do_char_trigs(ch, "look", looker, NULL);
+  gen_do_trigs(ch,TRIGVAR_CHAR,"look",looker,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_obj_to_game_trighooks(const char *info) {
   OBJ_DATA *obj = NULL;
   hookParseInfo(info, &obj);
-  do_obj_trigs(obj, "to_game", obj, NULL);
+  gen_do_trigs(obj,TRIGVAR_OBJ,"to_game",NULL,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_char_to_game_trighooks(const char *info) {
   CHAR_DATA *ch = NULL;
   hookParseInfo(info, &ch);
-  do_char_trigs(ch, "to_game", ch, NULL);
+  gen_do_trigs(ch, TRIGVAR_CHAR,"to_game",NULL,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 void do_room_to_game_trighooks(const char *info) {
   ROOM_DATA *rm = NULL;
   hookParseInfo(info, &rm);
-  do_room_trigs(rm, "to_game", rm, NULL);
+  gen_do_trigs(rm,TRIGVAR_ROOM,"to_game",NULL,NULL,NULL,NULL,NULL,NULL,NULL);
 }
 
 
@@ -553,4 +429,23 @@
   hookAdd("obj_to_game",    do_obj_to_game_trighooks);
   hookAdd("char_to_game",   do_char_to_game_trighooks);
   hookAdd("room_to_game",   do_room_to_game_trighooks);
+
+  // add our trigger displays
+  register_tedit_opt("speech",         "mob, room" );
+  register_tedit_opt("greet",          "mob"       );
+  register_tedit_opt("enter",          "mob, room" );
+  register_tedit_opt("exit",           "mob, room" );
+  register_tedit_opt("self enter",     "mob"       ),
+  register_tedit_opt("self exit",      "mob"       );
+  register_tedit_opt("drop",           "obj, room" );
+  register_tedit_opt("get",            "obj, room" );
+  register_tedit_opt("give",           "obj, mob"  );
+  register_tedit_opt("receive",        "mob"       );
+  register_tedit_opt("wear",           "obj, mob"  );
+  register_tedit_opt("remove",         "obj, mob"  );
+  register_tedit_opt("reset",          "room"      );
+  register_tedit_opt("look",           "obj, mob, room" );
+  register_tedit_opt("open",           "obj, room" );
+  register_tedit_opt("close",          "obj, room" );
+  register_tedit_opt("to_game",        "obj, mob, room" );
 }
diff -ruN ../nakedmudv3.7.9/src/scripts/trighooks.h src/scripts/trighooks.h
--- ../nakedmudv3.7.9/src/scripts/trighooks.h	2005-11-14 00:28:06.000000000 -0500
+++ src/scripts/trighooks.h	2009-04-01 14:02:06.000000000 -0400
@@ -5,8 +5,7 @@
 // trighooks.h
 //
 // Triggers attach on to rooms, objects, and mobiles as hooks. When a hook
-// event occurs, all of the triggers of the right type will run. This header is
-// just to allow scripts to initialize the hooks into the game. The init 
+// event occurs, all of the triggers of the right type will run. The init 
 // function here should not be touched by anything other than scripts.c
 //
 //*****************************************************************************
@@ -15,5 +14,41 @@
 // called when init_scripts() is run
 void init_trighooks(void);
 
-#endif // TRIGHOOKS_H
+//
+// values for figuring out what "me" and optional variables are in gen_do_trigs
+#define TRIGVAR_CHAR      0
+#define TRIGVAR_OBJ       1
+#define TRIGVAR_ROOM      2
+
+//
+// structure for defining extra variables when calling gen_do_trigs
+typedef struct opt_var OPT_VAR;
+
+//
+// create and delete optional variables for use with gen_do_trigs
+OPT_VAR *newOptVar(const char *name, void *data, int type);
+void  deleteOptVar(OPT_VAR *var);
 
+//
+// generalized function for running all triggers of a specified type. First
+// argument is the thing tirggers are being run for. Me must be a character,
+// object, or room that owns the triggers. me_type is an integer value that
+// specifies the owner. Type is the class of triggers to be run. Other variables
+// appear as the same name in the trigger. Each can be NULL. If other variables
+// are needed, a list of optionals can be provided, which must be deleted after
+// use
+void gen_do_trigs(void *me, int me_type, const char *type,
+		  CHAR_DATA *ch,OBJ_DATA *obj, ROOM_DATA *room, EXIT_DATA *exit,
+		  const char *cmd, const char *arg, LIST *optional);
+
+//
+// the trigger edit (tedit) menu displays a list of possible trigger types
+// to choose from. That list can be extended by calling this function. desc
+// should be a comma-separated list of things the trigger can be attached to
+// (obj, mob, room, in that order)
+void register_tedit_opt(const char *type, const char *desc); 
+
+// returns a table of the available tedit opts
+HASHTABLE *get_tedit_opts(void);
+
+#endif // TRIGHOOKS_H
diff -ruN ../nakedmudv3.7.9/src/socket.c src/socket.c
--- ../nakedmudv3.7.9/src/socket.c	2009-03-02 01:00:40.000000000 -0500
+++ src/socket.c	2009-03-16 03:17:41.000000000 -0400
@@ -48,7 +48,9 @@
   ACCOUNT_DATA  * account;
   char          * hostname;
   char            inbuf[MAX_INPUT_LEN];
-  char            next_command[MAX_BUFFER];
+  BUFFER        * next_command;
+  BUFFER        * iac_sequence;
+  // char            next_command[MAX_BUFFER];
   bool            cmd_read;
   bool            bust_prompt;
   bool            closed;
@@ -440,139 +442,130 @@
   bufferCat(dsock->outbuf, txt);
 }
 
+//
+// read an IAC sequence from the socket's input buffer. When we hit a
+// termination point, send a hook and clear he buffer. Return how many
+// characters to skip ahead in the input handler
+int read_iac_sequence(SOCKET_DATA *dsock, int start) {
+  // are we doing subnegotiation?
+  bool subneg = strchr(bufferString(dsock->iac_sequence), SB) != NULL;
+  int       i = start;
+  bool   done = FALSE;
+
+  for(; dsock->inbuf[i] != '\0'; i++) {
+    // are we looking for IAC?
+    if(bufferLength(dsock->iac_sequence) == 0) {
+      // Oops! Something is broken
+      if(dsock->inbuf[i] != (signed char) IAC)
+	return 0;
+      else
+	bufferCatCh(dsock->iac_sequence, IAC);
+    }
+
+    // are we looking for a command?
+    else if(bufferLength(dsock->iac_sequence) == 1) {
+      // did we find subnegotiation?
+      if(dsock->inbuf[i] == (signed char) SB) {
+	bufferCatCh(dsock->iac_sequence, dsock->inbuf[i]);
+	subneg = TRUE;
+      }
+
+      // basic three-character command
+      else if(dsock->inbuf[i] == (signed char) WILL || 
+	      dsock->inbuf[i] == (signed char) WONT || 
+	      dsock->inbuf[i] == (signed char) DO   || 
+	      dsock->inbuf[i] == (signed char) DONT)
+	bufferCatCh(dsock->iac_sequence, dsock->inbuf[i]);
+
+      // something went wrong
+      else {
+	bufferClear(dsock->iac_sequence);
+	return 2;
+      }
+    }
+    
+    // are we doing subnegotiation?
+    else if(subneg) {
+      int       last_i = bufferLength(dsock->iac_sequence) - 2;
+      signed char last = bufferString(dsock->iac_sequence)[last_i];
+      bufferCatCh(dsock->iac_sequence, dsock->inbuf[i]);
+
+      // have hit the end of the subnegotiation? Break out if so
+      if(last == (signed char) IAC && dsock->inbuf[i] == (signed char) SE) {
+	done = TRUE;
+	break;
+      }
+    }
+
+    // this is the end
+    else {
+      bufferCatCh(dsock->iac_sequence, dsock->inbuf[i]);
+      done = TRUE;
+      break;
+    }
+  }
+  
+  int len = i - start + (dsock->inbuf[i] == '\0' ? 0 : 1);
+
+  // broadcast the message we parsed, and prepare for the next sequence
+  if(done == TRUE) {
+    hookRun("receive_iac", 
+	    hookBuildInfo("sk str", dsock,bufferString(dsock->iac_sequence)));
+    bufferClear(dsock->iac_sequence);
+  }
+  return len;
+}
 
 void next_cmd_from_buffer(SOCKET_DATA *dsock) {
   // do we have stuff in our input list? If so, use that instead of inbuf
   dsock->cmd_read = FALSE;
   if(listSize(dsock->input) > 0) {
     char *cmd = listPop(dsock->input);
-    strncpy(dsock->next_command, cmd, MAX_BUFFER);
+    bufferClear(dsock->next_command);
+    bufferCat(dsock->next_command, cmd);
     dsock->cmd_read    = TRUE;
     dsock->bust_prompt = TRUE;
     free(cmd);
   }
   else {
-    int size = 0, i = 0, j = 0; //, telopt = 0;
-    static char iacopt[MAX_BUFFER];
-    bool found_iac = FALSE;
-    iacopt[0] = '\0';
-    
-    // if theres already a command ready, we return
-    if(dsock->next_command[0] != '\0')
-      return;
-    
-    // if there is nothing pending, then return
-    if(dsock->inbuf[0] == '\0')
-      return;
-
-    // check how long the next command is
-    while(dsock->inbuf[size] != '\0' && 
-	  dsock->inbuf[size] != '\n' && dsock->inbuf[size] != '\r')
-      size++;
-
-    /* we only deal with real commands */
-    // I'm not really sure what this means, or does! -- Geoff
-    if(dsock->inbuf[size] == '\0')
-      return;
-
-    // copy the next command into next_command
-    for(; i < size; i++) {
-      // we have a system command. Try to parse it out
-      if(dsock->inbuf[i] == (signed char) IAC) {
-	int iac_i       = 0;
-	iacopt[iac_i++] = (signed char) dsock->inbuf[i++];
-	
-	// IAC escape sequence: IAC IAC
-	if(dsock->inbuf[i] == (signed char) IAC)
-	  iacopt[iac_i++] = (signed char) dsock->inbuf[i];
-	
-	// subnegotiation, read until the end of the sequence
-	if(dsock->inbuf[i] == (signed char) SB) {
-	  while(dsock->inbuf[i] != (signed char) SE)
-	    iacopt[iac_i++] = (signed char) dsock->inbuf[i++];
-	  iacopt[iac_i++] = (signed char) dsock->inbuf[i];
-	}
-
-	// basic three-character command
-	else if(dsock->inbuf[i] == (signed char) WILL || 
-		dsock->inbuf[i] == (signed char) WONT || 
-		dsock->inbuf[i] == (signed char) DO   || 
-		dsock->inbuf[i] == (signed char) DONT) {
-	  iacopt[iac_i++] = (signed char) dsock->inbuf[i++];
-	  iacopt[iac_i++] = (signed char) dsock->inbuf[i];
-	}
-	
-	// not sure what happened here! Something got busted in transit
-	else {
-	  iacopt[iac_i++] = dsock->inbuf[i];
-	}
-
-	// close off the command
-	iacopt[iac_i++] = '\0';
-
-	// did we find an IAC command? Notify the world!
-	if(*iacopt) {
-	  found_iac = TRUE;
-	  hookRun("receive_iac", hookBuildInfo("sk str", dsock, iacopt));
-	  //*iacopt = '\0';
-	}
-      }
-      
-      else if(isprint(dsock->inbuf[i]) && isascii(dsock->inbuf[i])) {
-	dsock->next_command[j++] = dsock->inbuf[i];
-      }
-      else {
-	// log_string("BAD CHARACTER %d", (unsigned int)dsock->inbuf[i]); 
-      }
+    int i = 0, cmd_end = -1;
 
-      /*
-       * THE OLD HANDLER
-       *
-      if(dsock->inbuf[i] == (signed char) IAC)
-	telopt = 1;
-      else if(telopt == 1 && (dsock->inbuf[i] == (signed char) DO || 
-			      dsock->inbuf[i] == (signed char) DONT))
-	telopt = 2;
-    
-      // check for compression format
-      else if(telopt == 2) {
-	unsigned char compress_opt = dsock->inbuf[i];
-	telopt = 0;
-	
-	// check if we're using a valid compression
-	if(compress_opt == TELOPT_COMPRESS || compress_opt == TELOPT_COMPRESS2){
-	  // start compressing
-	  if(dsock->inbuf[i-1] == (signed char) DO)                  
-	    compressStart(dsock, compress_opt);
-	  // stop compressing
-	  else if(dsock->inbuf[i-1] == (signed char) DONT)
-	    compressEnd(dsock, compress_opt, FALSE);
-	}
+    // are we building an IAC command? Try to continue it
+    if(bufferLength(dsock->iac_sequence) > 0)
+      i += read_iac_sequence(dsock, 0);
+
+    // copy over characters until we hit a newline, an IAC command, or \0
+    for(; dsock->inbuf[i] != '\0' && cmd_end < 0; i++) {
+      switch(dsock->inbuf[i]) {
+      default:
+	// append us to the command
+	bufferCatCh(dsock->next_command, dsock->inbuf[i]);
+	break;
+      case '\n':
+	// command end found
+	cmd_end = ++i;
+      case '\r':
+	// ignore \r ... only pay attention to \n
+	break;
+      case (signed char) IAC:
+	i += read_iac_sequence(dsock, i) - 1;
+	break;
       }
-      else if(isprint(dsock->inbuf[i]) && isascii(dsock->inbuf[i])) {
-	dsock->next_command[j++] = dsock->inbuf[i];
-      }
-      */
+      if(cmd_end >= 0)
+	break;
     }
+
+    // move the context of inbuf down
+    int begin = 0;
+    while(dsock->inbuf[i] != '\0')
+      dsock->inbuf[begin++] = dsock->inbuf[i++];
+    dsock->inbuf[begin] = '\0';
     
-    dsock->next_command[j] = '\0';
-    
-    // skip forward to the next line
-    while(dsock->inbuf[size] == '\n' || dsock->inbuf[size] == '\r') {
+    // did we find a command?
+    if(cmd_end >= 0) {
       dsock->cmd_read    = TRUE;
       dsock->bust_prompt = TRUE;
-      size++;
-    }
-    
-    // use i as a static pointer
-    i = size;
-    
-    // move the context of inbuf down
-    while(dsock->inbuf[size] != '\0') {
-      dsock->inbuf[size - i] = dsock->inbuf[size];
-      size++;
     }
-    dsock->inbuf[size - i] = '\0';
   }
 }
 
@@ -635,6 +628,8 @@
   if(sock->page_string)   free(sock->page_string);
   if(sock->text_editor)   deleteBuffer(sock->text_editor);
   if(sock->outbuf)        deleteBuffer(sock->outbuf);
+  if(sock->next_command)  deleteBuffer(sock->next_command);
+  if(sock->iac_sequence)  deleteBuffer(sock->iac_sequence);
   if(sock->input_handlers)deleteListWith(sock->input_handlers,deleteInputHandler);
   if(sock->input)         deleteListWith(sock->input, free);
   if(sock->command_hist)  deleteListWith(sock->command_hist, free);
@@ -647,6 +642,8 @@
   if(sock_new->page_string)    free(sock_new->page_string);
   if(sock_new->text_editor)    deleteBuffer(sock_new->text_editor);
   if(sock_new->outbuf)         deleteBuffer(sock_new->outbuf);
+  if(sock_new->next_command)   deleteBuffer(sock_new->next_command);
+  if(sock_new->iac_sequence)   deleteBuffer(sock_new->iac_sequence);
   if(sock_new->input_handlers) deleteListWith(sock_new->input_handlers, deleteInputHandler);
   if(sock_new->auxiliary)      deleteAuxiliaryData(sock_new->auxiliary);
   if(sock_new->input)          deleteListWith(sock_new->input, free);
@@ -663,6 +660,8 @@
 
   sock_new->text_editor    = newBuffer(1);
   sock_new->outbuf         = newBuffer(MAX_OUTPUT);
+  sock_new->next_command   = newBuffer(1);
+  sock_new->iac_sequence   = newBuffer(1);
 }
 
 
@@ -864,11 +863,13 @@
       IH_PAIR *pair = listGet(sock->input_handlers, 0);
       if(pair->python == FALSE) {
 	void (* handler)(SOCKET_DATA *, char *) = pair->handler;
-	handler(sock, sock->next_command);
+	char *cmddup = strdup(bufferString(sock->next_command));
+	handler(sock, cmddup);
+	free(cmddup);
       }
       else {
 	PyObject *arglist = Py_BuildValue("Os", socketGetPyFormBorrowed(sock),
-					  sock->next_command);
+					  bufferString(sock->next_command));
 	PyObject *retval  = PyEval_CallObject(pair->handler, arglist);
 
 	// check for an error:
@@ -882,10 +883,10 @@
 
       // append our last command to the command history. History buffer is
       // 100 commands, so pop off the earliest command if we're going over
-      listPut(sock->command_hist, strdup(sock->next_command));
+      listPut(sock->command_hist, strdup(bufferString(sock->next_command)));
       if(listSize(sock->command_hist) > 100)
 	free(listRemoveNum(sock->command_hist, 100));
-      sock->next_command[0] = '\0';
+      bufferClear(sock->next_command);
 
       // we save whether or not we read a command until our next call to
       // input_handler(), at which time it is reset to FALSE if we didn't read
diff -ruN ../nakedmudv3.7.9/src/storage.c src/storage.c
--- ../nakedmudv3.7.9/src/storage.c	2009-03-02 01:00:41.000000000 -0500
+++ src/storage.c	2009-03-05 21:25:48.000000000 -0500
@@ -351,7 +351,7 @@
 //
 bool storage_end(FILEBUF *fb) {
   char c = fbgetc(fb);
-  if(c == SET_MARKER) {
+  if(c == SET_MARKER || c == EOF) {
     // also skip the newline that comes after us
     fbgetc(fb);
     return TRUE;
diff -ruN ../nakedmudv3.7.9/src/time/time.c src/time/time.c
--- ../nakedmudv3.7.9/src/time/time.c	2009-03-02 01:00:41.000000000 -0500
+++ src/time/time.c	2009-04-05 00:28:28.000000000 -0400
@@ -191,12 +191,20 @@
     curr_hour = curr_day_of_week = curr_day_of_month = curr_month = curr_year = 0;
 
   // add our mud methods
-  PyMud_addMethod("get_hour",     PyMud_GetHour,     METH_NOARGS, NULL);
-  PyMud_addMethod("get_time",     PyMud_GetTime,     METH_NOARGS, NULL);
-  PyMud_addMethod("is_morning",   PyMud_IsMorning,   METH_NOARGS, NULL);
-  PyMud_addMethod("is_afternoon", PyMud_IsAfternoon, METH_NOARGS, NULL);
-  PyMud_addMethod("is_evening",   PyMud_IsEvening,   METH_NOARGS, NULL);
-  PyMud_addMethod("is_night",     PyMud_IsNight,     METH_NOARGS, NULL);
+  PyMud_addMethod("get_hour",     PyMud_GetHour,     METH_NOARGS, 
+		  "get_hour()\n\n"
+		  "Return the current in-game hour of day.");
+  PyMud_addMethod("get_time",     PyMud_GetTime,     METH_NOARGS, 
+		  "get_time()\n\n"
+		  "Return time of day (morning, afternoon, evening, night).");
+  PyMud_addMethod("is_morning",   PyMud_IsMorning,   METH_NOARGS, 
+		  "True or False if it is morning.");
+  PyMud_addMethod("is_afternoon", PyMud_IsAfternoon, METH_NOARGS, 
+		  "True or False if it is afternoon.");
+  PyMud_addMethod("is_evening",   PyMud_IsEvening,   METH_NOARGS, 
+		  "True or False if it is evening.");
+  PyMud_addMethod("is_night",     PyMud_IsNight,     METH_NOARGS, 
+		  "True or False if it is night.");
 
   // add the time command
   add_cmd("time", NULL, cmd_time, "player", FALSE);
diff -ruN ../nakedmudv3.7.9/lib/pymodules/account_handler.py lib/pymodules/account_handler.py
--- ../nakedmudv3.7.9/lib/pymodules/account_handler.py	2009-03-02 12:37:00.000000000 -0500
+++ lib/pymodules/account_handler.py	2009-04-05 13:24:25.000000000 -0400
@@ -332,6 +332,9 @@
 # events for blocking action when dns lookup is in progress
 ################################################################################
 def dns_check_event(owner, void, info):
+    '''After a socket connects, monitor their hostname until dns lookup is
+       complete. Then, put the socket into the account handler.
+    '''
     sock, = hooks.parse_info(info)
     if sock != None and sock.can_use:
         sock.send(" Lookup complete.")
@@ -349,6 +352,7 @@
 # account handler hooks
 ################################################################################
 def account_handler_hook(info):
+    '''When a socket connects, put them into the account handler menu.'''
     # put a nonfunctional prompt up while waiting for the DNS to resolve
     sock, = hooks.parse_info(info)
     sock.push_ih(login_method_handler, login_method_prompt)
diff -ruN ../nakedmudv3.7.9/lib/pymodules/char_gen.py lib/pymodules/char_gen.py
--- ../nakedmudv3.7.9/lib/pymodules/char_gen.py	2009-03-02 03:10:23.000000000 -0500
+++ lib/pymodules/char_gen.py	2009-04-05 13:25:22.000000000 -0400
@@ -105,6 +105,9 @@
 # character generation hooks
 ################################################################################
 def char_gen_hook(info):
+    '''Put a socket into the character generation menu when character generation
+       hooks are called.
+    '''
     sock, = hooks.parse_info(info)
     sock.push_ih(mudsys.handle_cmd_input, mudsys.show_prompt, "playing")
     sock.push_ih(cg_finish_handler, cg_finish_prompt)
diff -ruN ../nakedmudv3.7.9/lib/pymodules/cmd_admin.py lib/pymodules/cmd_admin.py
--- ../nakedmudv3.7.9/lib/pymodules/cmd_admin.py	2009-03-02 01:43:35.000000000 -0500
+++ lib/pymodules/cmd_admin.py	2009-04-05 16:15:10.000000000 -0400
@@ -1,13 +1,9 @@
-################################################################################
-#
-# cmd_admin.py
-#
-# commands available only to admins.
-#
-################################################################################
-from mud import *
-from mudsys import add_cmd
-import mudsys, inform, string, mudsock, mud, hooks
+'''
+cmd_admin.py
+
+commands available only to admins.
+'''
+import mudsys, inform, string, mudsock, mud, hooks, display
 import room as mudroom
 import char as mudchar
 import obj  as mudobj
@@ -51,7 +47,7 @@
          > repeat 20 load obj beer@drinks
        '''
     try:
-        times, arg = parse_args(ch, True, cmd, arg, "int(times) string(command)")
+        times, arg = mud.parse_args(ch, True, cmd, arg, "int(times) string(command)")
     except: return
 
     if times < 1:
@@ -118,8 +114,8 @@
        Perform a command at another room or person while never leaving your
        current room.'''
     try:
-        found, type, arg = parse_args(ch, True, cmd, arg,
-                                      "{ room ch.world.noself } string(command)")
+        found, type, arg = mud.parse_args(ch, True, cmd, arg,
+                                          "{ room ch.world.noself } string(command)")
     except: return
 
     # figure out what room we're doing the command at
@@ -150,8 +146,8 @@
     
        Attempts to make the specified perform a command of your choosing.'''
     try:
-        found, multi, arg = parse_args(ch, True, cmd, arg,
-                                       "ch.world.noself.multiple string(command)")
+        found, multi, arg = mud.parse_args(ch, True, cmd, arg,
+                                           "ch.world.noself.multiple string(command)")
     except: return
 
     if multi == False:
@@ -167,7 +163,7 @@
        are referenced by their zone key.
        '''
     try:
-        found, type = parse_args(ch, True, cmd, arg, "{ room ch.world.noself }")
+        found, type = mud.parse_args(ch, True, cmd, arg, "{ room ch.world.noself }")
     except: return
 
     # what did we find?
@@ -176,12 +172,12 @@
     else:
         dest = found
 
-    message(ch, None, None, None, True, "to_room",
-            "$n disappears in a puff of smoke.")
+    mud.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.")
+    mud.message(ch, None, None, None, True, "to_room",
+                "$n appears in a puff of smoke.")
     hooks.run("enter", hooks.build_info("ch rm", (ch, ch.room)))
     
 def do_transfer(ch, tgt, dest):
@@ -190,12 +186,12 @@
         ch.send(ch.see_as(tgt) + " is already there")
     else:
         tgt.send(tgt.see_as(ch) + " has transferred you to " + dest.name)
-        message(tgt, None, None, None, True, "to_room",
-                "$n disappears in a puff of smoke.")
+        mud.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.")
+        mud.message(tgt, None, None, None, True, "to_room",
+                    "$n arrives in a puff of smoke.")
 
 def cmd_transfer(ch, cmd, arg):
     '''Usage: transfer <person> [[to] room]
@@ -204,8 +200,8 @@
        takes the target to the user. If an additional argument is supplied,
        instead transfers the target to the specifie room.'''
     try:
-        found, multi, dest = parse_args(ch, True, cmd, arg,
-                                        "ch.world.multiple.noself | [to] room")
+        found, multi, dest = mud.parse_args(ch, True, cmd, arg,
+                                            "ch.world.multiple.noself | [to] room")
     except: return
 
     # if we didn't supply a room, use our own
@@ -252,7 +248,7 @@
 def cmd_instance(ch, cmd, arg):
     '''Create an instanced version of the specified room'''
     try:
-        source, dest = parse_args(ch, True, cmd, arg, "word(source) [as] word(dest)")
+        source, dest = mud.parse_args(ch, True, cmd, arg, "word(source) [as] word(dest)")
     except: return
 
     room = mudroom.instance(source, dest)
@@ -299,7 +295,7 @@
             ch.send("No zones currently instanced.")
         else:
             ch.send("{w %-40s %36s " % ("Instance", "Source"))
-            ch.send("{b-------------------------------------------------------------------------------")
+            ch.send("{b" + display.seperator)
             for pair in curr_instances:
                 ch.send("{c %-40s %36s{n" % pair)
         return
@@ -322,42 +318,59 @@
 
     tosend = [ ]
 
-    fmt = " %-11s %-11s %-11s %s"
+    fmt = " %2s   %-11s %-11s %-11s %s"
 
-    tosend.append(("{w" + fmt) % ("Character", "Account", "Status", "Host"))
-    tosend.append("{b--------------------------------------------------------------------------------{c")
+    tosend.append(("{w"+fmt) % ("Id", "Character", "Account", "Status", "Host"))
+    tosend.append("{b" + display.seperator + "{c")
     for sock in mudsock.socket_list():
         chname  = "none"
         accname = "none"
         state   = sock.state
         host    = sock.hostname
+        id      = sock.uid
 
         if sock.ch != None:
             chname  = sock.ch.name
         if sock.account != None:
             accname = sock.account.name
-        tosend.append(fmt % (chname, accname, state, host))
+        tosend.append(fmt % (id, chname, accname, state, host))
     tosend.append("{n")
     ch.page("\r\n".join(tosend))
 
+def cmd_disconnect(ch, cmd, arg):
+    """Usage: disconnect <uid>
+
+       Disconnects a socket with the given uid. Use 'connections' to see
+       current connected sockets."""
+    try:
+        uid, = mud.parse_args(ch, True, cmd, arg, "int(uid)")
+    except: return
+
+    for sock in mudsock.socket_list():
+        if sock.uid == uid:
+            ch.send("You disconnect socket %d." % uid)
+            sock.close()
+            break
+
 
 
 ################################################################################
 # add our commands
 ################################################################################
-add_cmd("shutdow",     None, cmd_shutdown_net, "admin",   False)
-add_cmd("shutdown",    None, cmd_shutdown,     "admin",   False)
-add_cmd("copyove",     None, cmd_copyover_net, "admin",   False)
-add_cmd("copyover",    None, cmd_copyover,     "admin",   False)
-add_cmd("at",          None, cmd_at,           "wizard",  False)
-add_cmd("lockdown",    None, cmd_lockdown,     "admin",   False)
-add_cmd("pulserate",   None, cmd_pulserate,    "admin",   False)
-add_cmd("repeat",      None, cmd_repeat,       "wizard",  False)
-add_cmd("force",       None, cmd_force,        "wizard",  False)
-add_cmd("goto",        None, cmd_goto,         "wizard",  False)
-add_cmd("transfer",    None, cmd_transfer,     "wizard",  False)
-add_cmd("eval",        None, cmd_eval,         "admin",   False)
-add_cmd("exec",        None, cmd_exec,         "admin",   False)
-add_cmd("connections", None, cmd_connections,  "admin",   False)
-add_cmd("instance",    None, cmd_instance,     "admin",   False)
-add_cmd("zinstance",   None, cmd_zinstance,    "admin",   False)
+mudsys.add_cmd("shutdow",     None, cmd_shutdown_net, "admin",   False)
+mudsys.add_cmd("shutdown",    None, cmd_shutdown,     "admin",   False)
+mudsys.add_cmd("copyove",     None, cmd_copyover_net, "admin",   False)
+mudsys.add_cmd("copyover",    None, cmd_copyover,     "admin",   False)
+mudsys.add_cmd("at",          None, cmd_at,           "wizard",  False)
+mudsys.add_cmd("lockdown",    None, cmd_lockdown,     "admin",   False)
+mudsys.add_cmd("pulserate",   None, cmd_pulserate,    "admin",   False)
+mudsys.add_cmd("repeat",      None, cmd_repeat,       "wizard",  False)
+mudsys.add_cmd("force",       None, cmd_force,        "wizard",  False)
+mudsys.add_cmd("goto",        None, cmd_goto,         "wizard",  False)
+mudsys.add_cmd("transfer",    None, cmd_transfer,     "wizard",  False)
+mudsys.add_cmd("eval",        None, cmd_eval,         "admin",   False)
+mudsys.add_cmd("exec",        None, cmd_exec,         "admin",   False)
+mudsys.add_cmd("connections", None, cmd_connections,  "admin",   False)
+mudsys.add_cmd("disconnect",  None, cmd_disconnect,   "admin",   False)
+mudsys.add_cmd("instance",    None, cmd_instance,     "admin",   False)
+mudsys.add_cmd("zinstance",   None, cmd_zinstance,    "admin",   False)
diff -ruN ../nakedmudv3.7.9/lib/pymodules/cmd_comm.py lib/pymodules/cmd_comm.py
--- ../nakedmudv3.7.9/lib/pymodules/cmd_comm.py	2009-03-02 01:43:35.000000000 -0500
+++ lib/pymodules/cmd_comm.py	2009-04-05 16:15:06.000000000 -0400
@@ -1,14 +1,12 @@
-################################################################################
-#
-# cmd_comm.c
-#
-# Various commands used in NakedMud(tm) for communicating with other
-# characters, and NPCs.
-#
-################################################################################
+'''
+cmd_comm.c
+
+Various commands used in NakedMud(tm) for communicating with other
+characters, and NPCs.
+'''
 from mud import *
 from mudsys import add_cmd, add_cmd_check
-import inform, hooks, mudsock, history
+import mudsys, mud, inform, hooks, mudsock, history
 
 
 
@@ -21,15 +19,15 @@
        as you.
        '''
     try:
-        tgt, question = parse_args(ch, True, cmd, arg,
-                                   "ch.room.noself [about] string(question)")
+        tgt, question =mud.parse_args(ch, True, cmd, arg,
+                                      "ch.room.noself [about] string(question)")
     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")
+    mud.message(ch, tgt, None, None, False, "to_vict",
+                "{w$n asks you, '" + question + "'{n")
+    mud.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)))
@@ -43,17 +41,18 @@
 
        see also: reply'''
     try:
-        tgt, mssg = parse_args(ch, True, cmd, arg, "ch.world.noself string(message)")
+        tgt, mssg = mud.parse_args(ch, True, cmd, arg,
+                                   "ch.world.noself string(message)")
     except: return
 
     mssg   = mssg.replace("$", "$$")
     tovict = "{r$n tells you, '" + mssg + "'{n"
     toch   = "{rYou tell $N, '" + mssg + "'{n"
-    message(ch, tgt, None, None, False, "to_vict", tovict)
-    message(ch, tgt, None, None, False, "to_char", toch)
+    mud.message(ch, tgt, None, None, False, "to_vict", tovict)
+    mud.message(ch, tgt, None, None, False, "to_char", toch)
     history.add_history(ch,   "tell", "{r%-10s: %s{n" % (ch.name, mssg))
     history.add_history(tgt,  "tell", "{r%-10s: %s{n" % (ch.name, mssg))
-    hooks.run("tell", hooks.build_info("ch ch", (ch, tgt)))
+    hooks.run("tell", hooks.build_info("ch ch str", (ch, tgt, mssg)))
 
 def cmd_chat(ch, cmd, arg):
     '''Usage: chat <message>
@@ -65,8 +64,8 @@
     else:
         arg  = arg.replace("$", "$$")
         mssg = "{y$n chats, '" + arg + "'{n"
-        message(ch, None, None, None, False, "to_world", mssg)
-        message(ch, None, None, None,False,"to_char", "{yyou chat, '"+arg+"'{n")
+        mud.message(ch, None, None, None, False, "to_world", mssg)
+        mud.message(ch, None, None, None,False,"to_char", "{yyou chat, '"+arg+"'{n")
         history.add_history(ch, "chat", "{y%-10s: %s{n" % (ch.name, arg))
 
 def cmd_wiz(ch, cmd, arg):
@@ -87,10 +86,10 @@
         ch.send("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")        
+        mud.message(ch, None, None, None, False, "to_room",
+                    "{y$n says, '" + arg + "'{n")
+        mud.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)))
@@ -101,12 +100,12 @@
        NPCs with dialogs will often have something to say when you greet or
        approach then. Greeting an NPC is a way to get them talking.'''
     try:
-        tgt, = parse_args(ch, True, cmd, arg, "ch.room.noself")
+        tgt, = mud.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.")
+    mud.message(ch, tgt, None, None, False, "to_char", "You greet $N.")
+    mud.message(ch, tgt, None, None, False, "to_vict", "$n greets you.")
+    mud.message(ch, tgt, None, None, False, "to_room", "$n greets $N.")
 
     # run greet hooks
     hooks.run("greet",      hooks.build_info("ch ch", (ch, tgt)))
@@ -131,7 +130,7 @@
         # front of the message
         if arg.find("$n") == -1:
             arg = "$n " + arg
-        message(ch, None, None, None, False, "to_room, to_char", arg)
+        mud.message(ch, None, None, None, False, "to_room, to_char", arg)
 
 def cmd_gemote(ch, cmd, arg):
     '''Gemote is similar to emote, except that it sends a mud-wide message
@@ -142,8 +141,8 @@
         # 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")
+        mud.message(ch, None, None, None, False, "to_world, to_char",
+                    "{bGLOBAL:{c " + arg + "{n")
 
 def cmd_page(ch, cmd, arg):
     '''Usage: page <person> <message>
@@ -153,7 +152,8 @@
        anyone in the mud, regardless if you are in the same room as them or not.
        '''
     try:
-        tgt, mssg = parse_args(ch, True, cmd, arg, "ch.world.noself string(message)")
+        tgt, mssg = mud.parse_args(ch, True, cmd, arg,
+                                   "ch.world.noself string(message)")
     except: return
     ch.send("\007\007You page " + ch.see_as(tgt))
     tgt.send("\007\007*" + tgt.see_as(ch) + "* " + mssg)
@@ -163,20 +163,20 @@
 ################################################################################
 # add our commands
 ################################################################################
-add_cmd("ask",     None, cmd_ask,   "player", False)
-add_cmd("say",     None, cmd_say,   "player", False)
-add_cmd("'",       None, cmd_say,   "player", False)
-add_cmd("tell",    None, cmd_tell,  "player", False)
-add_cmd("chat",    None, cmd_chat,  "player", False)
-add_cmd("wizchat", "wiz",cmd_wiz,   "wizard", False)
-add_cmd("gossip",  None, cmd_chat,  "player", False)
-add_cmd("\"",      None, cmd_chat,  "player", False)
-add_cmd("page",    None, cmd_page,  "player", False)
-add_cmd("greet",   None, cmd_greet, "player", False)
-add_cmd("approach",None, cmd_greet, "player", False)
-add_cmd("emote",   None, cmd_emote, "player", False)
-add_cmd("gemote",  None, cmd_gemote,"player", False)
-add_cmd(":",       None, cmd_emote, "player", False)
+mudsys.add_cmd("ask",     None, cmd_ask,   "player", False)
+mudsys.add_cmd("say",     None, cmd_say,   "player", False)
+mudsys.add_cmd("'",       None, cmd_say,   "player", False)
+mudsys.add_cmd("tell",    None, cmd_tell,  "player", False)
+mudsys.add_cmd("chat",    None, cmd_chat,  "player", False)
+mudsys.add_cmd("wizchat", "wiz",cmd_wiz,   "wizard", False)
+mudsys.add_cmd("gossip",  None, cmd_chat,  "player", False)
+mudsys.add_cmd("\"",      None, cmd_chat,  "player", False)
+mudsys.add_cmd("page",    None, cmd_page,  "player", False)
+mudsys.add_cmd("greet",   None, cmd_greet, "player", False)
+mudsys.add_cmd("approach",None, cmd_greet, "player", False)
+mudsys.add_cmd("emote",   None, cmd_emote, "player", False)
+mudsys.add_cmd("gemote",  None, cmd_gemote,"player", False)
+mudsys.add_cmd(":",       None, cmd_emote, "player", False)
 
 def chk_room_communication(ch, cmd):
     if ch.pos in ("sleeping", "unconscious"):
@@ -184,7 +184,7 @@
         return False
 
 for cmd in ["ask", "say", "'", "greet", "approach", "emote", ":"]:
-    add_cmd_check(cmd, chk_room_communication)
+    mudsys.add_cmd_check(cmd, chk_room_communication)
 
 # register our history handling
 history.register_comm_history("chat", lambda ch: "chat")
diff -ruN ../nakedmudv3.7.9/lib/pymodules/cmd_inform.py lib/pymodules/cmd_inform.py
--- ../nakedmudv3.7.9/lib/pymodules/cmd_inform.py	2009-03-02 02:38:42.000000000 -0500
+++ lib/pymodules/cmd_inform.py	2009-04-05 13:33:04.000000000 -0400
@@ -1,15 +1,10 @@
-################################################################################
-#
-# 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
+'''
+cmd_inform.py
+
+Contains various commands that are informative in nature. For instance, look,
+equipment, inventory, etc...
+'''
+import mud, mudsys, inform, utils
 
 
 
@@ -28,18 +23,18 @@
 def cmd_equipment(ch, cmd, arg):
     '''Displays all of the equipment you are currently wearing.'''
     ch.send("You are wearing:")
-    show_equipment(ch, ch)
+    inform.show_equipment(ch, ch)
 
 def cmd_who(ch, cmd, arg):
     '''List all of the players currently online.'''
-    ch.page(build_who(ch))
+    ch.page(inform.build_who(ch))
     
 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)
+        found, type = mud.generic_find(ch, arg, "all", "immediate", False)
 
         # what did we find?
         if found == None:
@@ -61,11 +56,11 @@
 ################################################################################
 # add our commands
 ################################################################################
-add_cmd("inventory", "i",   cmd_inventory, "player", False)
-add_cmd("equipment", "eq",  cmd_equipment, "player", False)
-add_cmd("worn",      None,  cmd_equipment, "player", False)
-add_cmd("who",       None,  cmd_who,       "player", False)
+mudsys.add_cmd("inventory", "i",   cmd_inventory, "player", False)
+mudsys.add_cmd("equipment", "eq",  cmd_equipment, "player", False)
+mudsys.add_cmd("worn",      None,  cmd_equipment, "player", False)
+mudsys.add_cmd("who",       None,  cmd_who,       "player", False)
 
 '''
-add_cmd("look",      "l",   cmd_look,      "player", False)
+mudsys.add_cmd("look",      "l",   cmd_look,      "player", False)
 '''
diff -ruN ../nakedmudv3.7.9/lib/pymodules/cmd_manip.py lib/pymodules/cmd_manip.py
--- ../nakedmudv3.7.9/lib/pymodules/cmd_manip.py	2009-03-02 02:02:41.000000000 -0500
+++ lib/pymodules/cmd_manip.py	2009-04-05 14:29:14.000000000 -0400
@@ -1,29 +1,24 @@
-################################################################################
-#
-# 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, add_cmd_check
-import movement, hooks
+'''
+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)
+'''
+import mudsys, mud, inform, utils, movement, hooks
+import obj as mudobj
 
 
 
 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.")
+    mud.message(ch, recv, obj, None, True, "to_room",
+                "$n gives $o to $N.")
+    mud.message(ch, recv, obj, None, True, "to_vict",
+                "$n gives $o to you.")
+    mud.message(ch, recv, obj, None, True, "to_char",
+                "You give $o to $N.")
     obj.carrier = recv
 
     # run our give hook
@@ -45,9 +40,9 @@
 
        > give 3.cookie george'''
     try:
-        to_give, multi, recv = parse_args(ch, True, cmd, arg,
-                                          "[the] obj.inv.multiple " +
-                                          "[to] ch.room.noself")
+        to_give, multi, recv = mud.parse_args(ch, True, cmd, arg,
+                                              "[the] obj.inv.multiple " +
+                                              "[to] ch.room.noself")
     except: return
 
     if multi == False:
@@ -58,16 +53,16 @@
 
 def do_get(ch, obj, cont):
     '''transfers an item from the ground to the character'''
-    if is_keyword(obj.bits, "notake"):
+    if utils.is_keyword(obj.bits, "notake"):
         ch.send("You cannot take " + ch.see_as(obj) + ".")
     elif cont != None:
         obj.carrier = ch
-        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.")
+        mud.message(ch, None, obj, cont, True, "to_char", "You get $o from $O.")
+        mud.message(ch, None, obj, cont, True, "to_room", "$n gets $o from $O.")
     else:
         obj.carrier = ch
-        message(ch, None, obj, None, True, "to_char", "You get $o.")
-        message(ch, None, obj, None, True, "to_room", "$n gets $o.")
+        mud.message(ch, None, obj, None, True, "to_char", "You get $o.")
+        mud.message(ch, None, obj, None, True, "to_room", "$n gets $o.")
 
         # run get hooks
         hooks.run("get", hooks.build_info("ch obj", (ch, obj)))
@@ -75,16 +70,17 @@
 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.")
+        mud.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.")
+        mud.message(ch, None, cont, None, True, "to_char", "$o is closed.")
     else:
         # find our count and name
-        num, name = get_count(arg)
+        num, name = utils.get_count(arg)
 
         # multi or single?
         if num == "all":
-            list = find_all_objs(ch, cont.objs, name)
+            list = utils.find_all_objs(ch, cont.objs, name)
             for obj in list:
                 do_get(ch, obj, cont)
         else:
@@ -93,8 +89,8 @@
             if obj != None:
                 do_get(ch, obj, cont)
             else:
-                message(ch, None, cont, None, True, "to_char",
-                        "You could not find what you were looking for in $o.")
+                mud.message(ch, None, cont, None, True, "to_char",
+                            "You could not find what you were looking for in $o.")
 
 def cmd_get(ch, cmd, arg):
     '''Usage: get [the] <item> [[from] <other item>]
@@ -103,8 +99,8 @@
        addition argument is supplied, the command assumes it is a container and
        instead tries to move an object from the container to your inventory.'''
     try:
-        arg, cont = parse_args(ch, True, cmd, arg,
-                               "[the] word(object) | [from] obj.room.inv.eq")
+        arg,cont = mud.parse_args(ch, True, cmd, arg,
+                                  "[the] word(object) | [from] obj.room.inv.eq")
     except: return
     
     # are we doing get, or get-from?
@@ -113,7 +109,7 @@
     else:
         # try to find the object in the room
         try:
-            found, multi = parse_args(ch, True, cmd, arg, "obj.room.multiple")
+            found,multi= mud.parse_args(ch, True, cmd, arg, "obj.room.multiple")
         except: return
 
         # pick up all the items we want
@@ -127,8 +123,8 @@
     '''handles object dropping'''
     obj.room = ch.room
 
-    message(ch, None, obj, None, True, "to_char", "You drop $o.")
-    message(ch, None, obj, None, True, "to_room", "$n drops $o.")
+    mud.message(ch, None, obj, None, True, "to_char", "You drop $o.")
+    mud.message(ch, None, obj, None, True, "to_room", "$n drops $o.")
 
     # run our drop hook
     hooks.run("drop", hooks.build_info("ch obj", (ch, obj)))
@@ -138,7 +134,7 @@
 
        Attempts to move an object from your inventory to the ground.'''
     try:
-        found, multi = parse_args(ch, True, cmd, arg, "[the] obj.inv.multiple")
+        found,multi=mud.parse_args(ch, True, cmd, arg, "[the] obj.inv.multiple")
     except: return
 
     # are we dropping a list of things, or just one?
@@ -157,8 +153,8 @@
     if obj.carrier != ch:
         ch.send("You were unable to remove " + ch.see_as(obj) + ".")
     else:
-        message(ch, None, obj, None, True, "to_char", "You remove $o.")
-        message(ch, None, obj, None, True, "to_room", "$n removes $o.")
+        mud.message(ch, None, obj, None, True, "to_char", "You remove $o.")
+        mud.message(ch, None, obj, None, True, "to_room", "$n removes $o.")
 
         # run our hooks
         hooks.run("remove", hooks.build_info("ch obj", (ch, obj)))
@@ -181,7 +177,7 @@
 
        > remove 2.ring'''
     try:
-        found, multi = parse_args(ch, True, cmd, arg, "[the] obj.eq.multiple")
+        found,multi= mud.parse_args(ch, True, cmd, arg, "[the] obj.eq.multiple")
     except: return
 
     # are we removing one thing, or multiple things?
@@ -197,8 +193,8 @@
         ch.send("But " + ch.see_as(obj) + " is not equippable.")
         
     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.")
+        mud.message(ch, None, obj, None, True, "to_char", "You wear $o.")
+        mud.message(ch, None, obj, None, True, "to_room", "$n wears $o.")
 
         # run our wear hook
         hooks.run("wear", hooks.build_info("ch obj", (ch, obj)))
@@ -218,8 +214,8 @@
 
        > wear gloves left hand, right hand'''
     try:
-        found, multi, where = parse_args(ch, True, cmd, arg,
-                                         "[the] obj.inv.multiple | [on] string(bodyparts)")
+        found, multi, where = mud.parse_args(ch, True, cmd, arg,
+                                             "[the] obj.inv.multiple | [on] string(bodyparts)")
     except: return
 
     # Are the things we're looking for not body positions? Try to catch this!
@@ -230,7 +226,7 @@
         if not where in ch.bodyparts:
             where = None
             try:
-                found, = parse_args(ch,True,cmd,"'"+arg+"'","[the] obj.inv")
+                found, = mud.parse_args(ch,True,cmd,"'"+arg+"'","[the] obj.inv")
             except: return
 
     # are we wearing one thing, or multiple things?
@@ -251,8 +247,8 @@
     # 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.")
+        mud.message(ch, None, obj, cont, True, "to_char", "You put $o in $O.")
+        mud.message(ch, None, obj, cont, True, "to_room", "$n puts $o in $O.")
 
 def cmd_put(ch, cmd, arg):
     '''Usage: put [the] <item> [in the] <container>
@@ -261,9 +257,9 @@
        container. The container must be in the room, in your inventory, or
        worn.'''
     try:
-        found, multi, cont = parse_args(ch, True, cmd, arg,
-                                        "[the] obj.inv.multiple " +
-                                        "[in] [the] obj.room.inv")
+        found, multi, cont = mud.parse_args(ch, True, cmd, arg,
+                                            "[the] obj.inv.multiple " +
+                                            "[in] [the] obj.room.inv")
     except: return
 
     # make sure we have a container
@@ -330,8 +326,8 @@
 
        Attempts to lock a specified door, direction, or container.'''
     try:
-        found, type = parse_args(ch, True, cmd, arg,
-                                 "[the] {obj.room.inv.eq exit }")
+        found, type = mud.parse_args(ch, True, cmd, arg,
+                                     "[the] {obj.room.inv.eq exit }")
     except: return
 
     # what did we find?
@@ -350,10 +346,10 @@
         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 " + name + ".")
-            message(ch, None, None, None, True, "to_room",
-                    "$n locks " + name + ".")
+            mud.message(ch, None, None, None, True, "to_char",
+                        "You lock " + name + ".")
+            mud.message(ch, None, None, None, True, "to_room",
+                        "$n locks " + name + ".")
             ex.lock()
             # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
             try_manip_other_exit(ch.room, ex, ex.is_closed, True)
@@ -372,8 +368,8 @@
         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.")
+            mud.message(ch, None, obj, None, True, "to_char", "You lock $o.")
+            mud.message(ch, None, obj, None, True, "to_room", "$n locks $o.")
             obj.container_is_locked = True
 
 def cmd_unlock(ch, cmd, arg):
@@ -381,7 +377,7 @@
 
        Attempts to unlock the specified door, direction, or container.'''
     try:
-        found, type = parse_args(ch, True,cmd,arg, "[the] {obj.room.inv exit }")
+        found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
     except: return
 
     # what did we find?
@@ -401,10 +397,10 @@
         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 " + name + ".")
-            message(ch, None, None, None, True, "to_room",
-                    "$n unlocks " + name + ".")
+            mud.message(ch, None, None, None, True, "to_char",
+                        "You unlock " + name + ".")
+            mud.message(ch, None, None, None, True, "to_room",
+                        "$n unlocks " + name + ".")
             ex.unlock()
             # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
             try_manip_other_exit(ch.room, ex, ex.is_closed, False)
@@ -423,8 +419,8 @@
         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.")
+            mud.message(ch, None, obj, None, True, "to_char", "You unlock $o.")
+            mud.message(ch, None, obj, None, True, "to_room", "$n unlocks $o.")
             obj.container_is_locked = False
 
 def cmd_open(ch, cmd, arg):
@@ -432,7 +428,7 @@
 
        Attempts to open the speficied door, direction, or container.'''
     try:
-        found, type = parse_args(ch, True,cmd,arg, "[the] {obj.room.inv exit }")
+        found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
     except: return
 
     # is it an exit?
@@ -449,10 +445,10 @@
         elif not ex.is_closable:
             ch.send(name + " cannot be opened.")
         else:
-            message(ch, None, None, None, True, "to_char",
-                    "You open " + name + ".")
-            message(ch, None, None, None, True, "to_room",
-                    "$n opens " + name + ".")
+            mud.message(ch, None, None, None, True, "to_char",
+                        "You open " + name + ".")
+            mud.message(ch, None, None, None, True, "to_room",
+                        "$n opens " + name + ".")
             ex.open()
             # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
             try_manip_other_exit(ch.room, ex, False, ex.is_locked)
@@ -470,8 +466,8 @@
         elif not obj.container_is_closable:
             ch.send(ch.see_as(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.")
+            mud.message(ch, None, obj, None, True, "to_char", "You open $o.")
+            mud.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)))
 
@@ -480,7 +476,7 @@
 
        Attempts to close the specified door, direction, or container.'''
     try:
-        found, type = parse_args(ch, True,cmd,arg, "[the] {obj.room.inv exit }")
+        found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
     except: return
 
     # is it an exit?
@@ -497,10 +493,10 @@
         elif not ex.is_closable:
             ch.send(name + " cannot be closed.")
         else:
-            message(ch, None, None, None, True, "to_char",
-                    "You close " + name + ".")
-            message(ch, None, None, None, True, "to_room",
-                    "$n closes " + name + ".")
+            mud.message(ch, None, None, None, True, "to_char",
+                        "You close " + name + ".")
+            mud.message(ch, None, None, None, True, "to_room",
+                        "$n closes " + name + ".")
             ex.close()
             # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
             try_manip_other_exit(ch.room, ex, True, ex.is_locked) 
@@ -516,8 +512,8 @@
         elif not obj.container_is_closable:
             ch.send(ch.see_as(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.")
+            mud.message(ch, None, obj, None, True, "to_char", "You close $o.")
+            mud.message(ch, None, obj, None, True, "to_room", "$n closes $o.")
             obj.container_is_closed = True
             hooks.run("close_obj", hooks.build_info("ch obj", (ch, obj)))
 
@@ -526,16 +522,16 @@
 ################################################################################
 # load all of our commands
 ################################################################################
-add_cmd("give",   None, cmd_give,   "player", True)
-add_cmd("get",    None, cmd_get,    "player", True)
-add_cmd("drop",   None, cmd_drop,   "player", True)
-add_cmd("remove", None, cmd_remove, "player", True)
-add_cmd("wear",   None, cmd_wear,   "player", True)
-add_cmd("put",    None, cmd_put,    "player", True)
-add_cmd("open",   None, cmd_open,   "player", True)
-add_cmd("close",  None, cmd_close,  "player", True)
-add_cmd("lock",   None, cmd_lock,   "player", True)
-add_cmd("unlock", None, cmd_unlock, "player", True)
+mudsys.add_cmd("give",   None, cmd_give,   "player", True)
+mudsys.add_cmd("get",    None, cmd_get,    "player", True)
+mudsys.add_cmd("drop",   None, cmd_drop,   "player", True)
+mudsys.add_cmd("remove", None, cmd_remove, "player", True)
+mudsys.add_cmd("wear",   None, cmd_wear,   "player", True)
+mudsys.add_cmd("put",    None, cmd_put,    "player", True)
+mudsys.add_cmd("open",   None, cmd_open,   "player", True)
+mudsys.add_cmd("close",  None, cmd_close,  "player", True)
+mudsys.add_cmd("lock",   None, cmd_lock,   "player", True)
+mudsys.add_cmd("unlock", None, cmd_unlock, "player", True)
 
 def chk_can_manip(ch, cmd):
     if not ch.pos in ["sitting", "standing", "flying"]:
@@ -544,5 +540,4 @@
 
 for cmd in ["give", "get", "drop", "remove", "wear", "put", "open", "close",
             "lock", "unlock"]:
-    add_cmd_check(cmd, chk_can_manip)
-    
+    mudsys.add_cmd_check(cmd, chk_can_manip)
diff -ruN ../nakedmudv3.7.9/lib/pymodules/cmd_misc.py lib/pymodules/cmd_misc.py
--- ../nakedmudv3.7.9/lib/pymodules/cmd_misc.py	2009-03-02 01:45:15.000000000 -0500
+++ lib/pymodules/cmd_misc.py	2009-04-05 13:48:31.000000000 -0400
@@ -1,14 +1,10 @@
-################################################################################
-#
-# cmd_misc.c
-#
-# a collection of miscellaneous commands that come with NakedMud(tm)
-#
-################################################################################
-from mud import *
-from hooks import *
-from mudsys import add_cmd, add_cmd_check
-import event, mudsys
+'''
+cmd_misc.c
+
+a collection of miscellaneous commands that come with NakedMud(tm)
+'''
+import mudsys, mud, hooks, event, mudsys
+
 
 
 def cmd_stop(ch, cmd, arg):
@@ -38,7 +34,7 @@
        Will make you say \'hello, world!\' two seconds after entering the
        delayed command.'''
     try:
-        secs, to_delay = parse_args(ch, True, cmd, arg, "double string")
+        secs, to_delay = mud.parse_args(ch, True, cmd, arg, "double string")
     except: return
 
     if secs < 1:
@@ -62,7 +58,7 @@
 
 def cmd_quit(ch, cmd, arg):
     '''Attempts to save and log out of the game.'''
-    log_string(ch.name + " has left the game.")
+    mud.log_string(ch.name + " has left the game.")
     mudsys.do_save(ch)
     mudsys.do_quit(ch)
 
@@ -71,13 +67,13 @@
 ################################################################################
 # add our commands
 ################################################################################
-add_cmd("stop",  None, cmd_stop,  "player", False)
-add_cmd("clear", None, cmd_clear, "player", False)
-add_cmd("delay", None, cmd_delay, "player", False)
-add_cmd("motd",  None, cmd_motd,  "player", False)
-add_cmd("save",  None, cmd_save,  "player", False)
-add_cmd("quit",  None, cmd_quit,  "player", True)
+mudsys.add_cmd("stop",  None, cmd_stop,  "player", False)
+mudsys.add_cmd("clear", None, cmd_clear, "player", False)
+mudsys.add_cmd("delay", None, cmd_delay, "player", False)
+mudsys.add_cmd("motd",  None, cmd_motd,  "player", False)
+mudsys.add_cmd("save",  None, cmd_save,  "player", False)
+mudsys.add_cmd("quit",  None, cmd_quit,  "player", True)
 
 chk_can_save = lambda ch, cmd: not ch.is_npc
-add_cmd_check("save", chk_can_save)
-add_cmd_check("quit", chk_can_save)
+mudsys.add_cmd_check("save", chk_can_save)
+mudsys.add_cmd_check("quit", chk_can_save)
diff -ruN ../nakedmudv3.7.9/lib/pymodules/colour.py lib/pymodules/colour.py
--- ../nakedmudv3.7.9/lib/pymodules/colour.py	2009-03-02 01:45:15.000000000 -0500
+++ lib/pymodules/colour.py	2009-04-05 13:50:43.000000000 -0400
@@ -42,6 +42,8 @@
 # colour processing hooks
 ################################################################################
 def process_colour_hook(info):
+    """When outbound text is being processed, find colour codes and replace them
+       by the proper colour escape sequences."""
     sock,  = hooks.parse_info(info)
     buf    = sock.outbound_text
     newbuf = []
diff -ruN ../nakedmudv3.7.9/lib/pymodules/display.py lib/pymodules/display.py
--- ../nakedmudv3.7.9/lib/pymodules/display.py	1969-12-31 19:00:00.000000000 -0500
+++ lib/pymodules/display.py	2009-04-05 14:06:45.000000000 -0400
@@ -0,0 +1,164 @@
+'''
+display.py
+
+Various utilities for displaying information such as tables and metered values.
+'''
+import math, mud
+
+
+
+def table_row(info, align="left", caps = "|", space=" ",
+              center_filler=" ", width=79):
+    '''display a table row like this:
+       | info       |
+       '''
+    # account for color codes
+    width += info.count("{")*2
+
+    fmt = "%s%s%%-%ds%s%s" % (caps, space, width-len(caps)*2-len(space)*2,
+                              space, caps)
+    if align == "center":
+        info = info.center(width-len(caps)*2-len(space)*2, center_filler)
+    elif align == "right":
+        fmt = "%s%s%%%ds%s%s" % (caps, space, width-len(caps)*2-len(space)*2,
+                                 space, caps)
+    return fmt % info
+
+def table_splitrow(left, right, align="left", caps = "|", space=" ",
+                   center_filler=" ", width=79):
+    '''display two columns like this:
+       | left    | right    |
+       '''
+    width -= len(caps)*2 + len(space)*4
+    linfo = table_row(left,  align, "", "", center_filler, width/2)
+    rinfo = table_row(right, align, "", "", center_filler, width/2)
+    fmt = "%s%s%%s%s%s%s%%s%s%s" % (caps,space,space,caps,space,space,caps)
+    return fmt % (linfo, rinfo)
+
+def table_splitrows(left, right, align="left", caps = "|", space=" ",
+                   center_filler=" ", width=79):
+    """return a list of split rows"""
+    buf = [ ]
+    for i in range(max(len(left), len(right))):
+        lstr = ""
+        rstr = ""
+        if i < len(left):
+            lstr = left[i]
+        if i < len(right):
+            rstr = right[i]
+        buf.append(table_splitrow(lstr, rstr, align, caps, space, center_filler,
+                                  width))
+    return buf
+
+def meter(val,char="{p#",empty=" ",lcap="[",rcap="]",align="left",width=20):
+    """Return a horizontal meter representing a numeric value ranging between
+       [0,1]."""
+    width   = width-len(lcap)-len(rcap) + (lcap.count("{")+rcap.count("{"))*2
+    hatches = int(math.floor(width*abs(val)))
+    hatches = min(hatches, width)
+    left    = ""
+    right   = ""
+    
+    # are we dealing with a backwards meter?
+    left  = "".join([char for v in range(hatches)])
+    right = "".join([empty for v in range(width-hatches)])
+    if align == "right":
+        left, right = right, left
+    return lcap + "{n" + left + right + "{n" + rcap + "{n"
+
+def pagedlist(category_map, order=None, header=None, height=21):
+    """Display lists of information as flips within a book. category_map is a
+       mapping between section headers and lists of entries to display for that
+       category. If you are only displaying one category, have a map from
+       the section header, Topics, to your list of entries. If the categories
+       should be displayed in a specific (or partially specific) order, that
+       can be specified. Header is text that can appear at front of the book
+       display.
+    """
+    buf = [ ]
+    
+    # split our header into rows if we have one
+    hrows = [ ]
+    if header != None:
+        hrows = mud.format_string(header, False, 76).strip().split("\r\n")
+
+    # build our full list of orderings
+    if order == None:
+        order = [ ]
+    for category in category_map.iterkeys():
+        if not category in order:
+            order.append(category)
+
+    # build our page entries. This includes categories and category items
+    entries = [ ]
+    for category in order:
+        if not category in category_map:
+            continue
+
+        # add a space between categories
+        if len(entries) > 0:
+            entries.append("")
+        entries.append(category.capitalize())
+        for item in category_map[category]:
+            entries.append("  %s" % item)
+
+    # append our header if we have one
+    if len(hrows) > 0:
+        buf.append(table_border)
+        for hrow in hrows:
+            buf.append(table_row(hrow))
+
+    # build our page contents, one page at a time, until we are out of entries
+    pages    = [ ]
+    last_cat = None
+    while len(entries) > 0:
+        page = [ ]
+        plen = height - 2 # minus 2 for the borders
+
+        # we're still on the first flip of the book; header is displayed
+        if len(pages) <= 2:
+            plen -= len(hrows) + 1 # plus 1 for the row above it
+
+        # add items to the page until we are full
+        while len(entries) > 0 and len(page) < plen:
+            entry = entries.pop(0)
+
+            # is this a blank row, and are we at the head of the page?
+            if entry == "" and len(page) == 0:
+                continue
+            
+            # is this a category header?
+            if not entry.startswith(" "):
+                last_cat = entry
+
+            # are we continuing an old category?
+            if entry.startswith(" ") and len(page)==0 and last_cat != None:
+                page.append("%s (cont.)" % last_cat)
+            page.append(entry)
+
+        # did we have anything added to it?
+        if len(page) > 0:
+            pages.append(page)
+
+    # take our pages by twos and turn them into table rows
+    i = 0
+    while i < len(pages):
+        page1 = pages[i]
+        page2 = [ ]
+        if i+1 < len(pages):
+            page2 = pages[i+1]
+
+        # append the rows and page contents
+        buf.append(table_border)
+        buf.extend(table_splitrows(page1, page2))
+        buf.append(table_border)
+        i += 2
+    
+    buf.append("")
+    return buf
+
+# shortcut table elements
+table_border = table_row("", "center", "+", "", "-")
+table_filler = table_row("")
+seperator    = table_row("", "center", "-", "", "-")
+
diff -ruN ../nakedmudv3.7.9/lib/pymodules/doc.py lib/pymodules/doc.py
--- ../nakedmudv3.7.9/lib/pymodules/doc.py	1969-12-31 19:00:00.000000000 -0500
+++ lib/pymodules/doc.py	2009-04-05 03:09:50.000000000 -0400
@@ -0,0 +1,129 @@
+"""
+doc.py
+
+This module allows documentation for Python classes and modules to be viewed
+in-game via the 'doc' command. 
+"""
+import pydoc, os, mudsys, display
+
+
+
+################################################################################
+# local variables
+################################################################################
+
+# where do we store documentation?
+HTML_DOC_DIR = "../html/pydocs"
+
+shortcuts = { "ch"      : "char",
+              "sock"    : "mudsock",
+              }
+
+# just a list of all our builtin modules
+builtins = [
+    "char",
+    "room",
+    "obj",
+    "exit",
+    "account",
+    "mudsock",
+    "mud",
+    "mudsys",
+    "hooks",
+    "event",
+    "auxiliary",
+    "storage",
+    "olc",
+    ]
+
+# append all of our builtins to suggested reading list
+suggested_reading = [mod for mod in builtins]
+
+def register_module_doc(modname, package = None, root = "pymodules"):
+    """Add a new module name to suggested_reading. If modname is a package,
+       recursively add its packages as well
+    """
+    fname = root + "/" + modname.replace(".", "/")
+    suggested_reading.append(modname)
+    if os.path.isdir(fname):
+        for file in os.listdir(fname):
+            if (file.endswith(".py") or not "." in file) and not file[0] in "._":
+                module = modname + "." + file.split(".", 1)[0]
+                register_module_doc(module, root)
+ 
+# now, append all of our Python packages and modules
+for fname in os.listdir("pymodules/"):
+    # look for modules and packages
+    if (fname.endswith(".py") or not "." in fname) and not fname[0] in "._":
+        modname = fname.split(".", 1)[0]
+        register_module_doc(modname)
+
+
+
+################################################################################
+# player commands
+################################################################################
+def cmd_htmldoc(ch, cmd, arg):
+    """Creates html documentation for all registered modules. html files will
+       be saved to html/pydocs/
+    """
+    try:
+        os.makedirs(HTML_DOC_DIR)
+    except: pass
+    doc = pydoc.HTMLDoc()
+    for modname in suggested_reading:
+        todoc = pydoc.locate(modname)
+        if todoc != None:
+            fname = HTML_DOC_DIR + "/" + modname + ".html"
+            fl    = file(fname, "w+")
+            fl.write(doc.page(modname, doc.document(todoc)))
+            fl.close()
+
+    builtin_index = doc.multicolumn([doc.modulelink(pydoc.locate(modname)) for modname in builtins], lambda x: x)
+    
+    # build our index page. That includes things in pymodules/ and builtins
+    index_contents ="".join([doc.section("<big><strong>builtins</big></strong>",
+                                         'white', '#ee77aa', builtin_index),
+                             doc.index("../lib/pymodules/")])
+
+    # go over all of our builtins and add them to the index
+    index = file(HTML_DOC_DIR + "/index.html", "w+")
+    index.write(doc.page("index", index_contents))
+    index.close()
+    
+    ch.send("html documentation generated for all known modules.")
+
+def cmd_doc(ch, cmd, arg):
+    """Return Python documentation for the specified module, class, function,
+       etc... for example:
+       
+       > doc char.Char
+
+       Will return all available documentation for the Char class.
+    """
+    if arg == "":
+        ch.page("\r\n".join(display.pagedlist({ "Topics" : suggested_reading },
+                                              header = "Suggested doc readings include:")))
+    else:
+        # just because sometimes I forget periods
+        arg = arg.replace(" ", ".")
+
+        # are we looking for a shortcut value?
+        if arg in shortcuts:
+            arg = shortcuts[arg]
+
+        # try to find what we're documenting
+        todoc = pydoc.locate(arg)
+        if todoc == None:
+            ch.send("Could not find Python documentation on: '%s'" % arg)
+        else:
+            doc = pydoc.TextDoc()
+            ch.page(doc.document(todoc).replace("{", "{{"))
+
+
+
+################################################################################
+# initialization
+################################################################################
+mudsys.add_cmd("doc",     None, cmd_doc,     "wizard", False)
+mudsys.add_cmd("htmldoc", None, cmd_htmldoc, "admin",  False)
diff -ruN ../nakedmudv3.7.9/lib/pymodules/inform.py lib/pymodules/inform.py
--- ../nakedmudv3.7.9/lib/pymodules/inform.py	2009-03-02 02:58:42.000000000 -0500
+++ lib/pymodules/inform.py	2009-04-05 13:56:24.000000000 -0400
@@ -1,13 +1,10 @@
-################################################################################
-#
-# 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, mudsock, string
+"""
+inform.py
+
+Python's mirror of C's inform.c -- contains various functions that perform
+informative duties. Examining places/things, displaying proper names, etc...
+"""
+import utils, char, hooks, mudsock, mud, string, display
 
 
 
@@ -17,7 +14,7 @@
 def build_who(ch = None):
     '''returns a formatted list of all the people currently online'''
     buf = [ ]
-    buf.append("-------------------------------------------------------------------------------")
+    buf.append(display.seperator)
 
     # build character info
     count   = len(mudsock.socket_list())
@@ -37,9 +34,9 @@
     if playing == 1: play_end = ""
 
     # build our footer
-    buf.append("-------------------------------------------------------------------------------")
+    buf.append(display.seperator)
     buf.append((" %d socket" % count)  + conn_end + " logged in." + (" %d player" % playing) + play_end + " currently playing.")
-    buf.append("-------------------------------------------------------------------------------")
+    buf.append(display.seperator)
     buf.append("")
     return "\r\n".join(buf)
 
@@ -74,8 +71,8 @@
             if ex == None:
                 continue
             if ex.dest == None:
-                log_string("ERROR: room %s headed %s to %s, which does not exist."%\
-                           room.proto, dir, ex.destproto)
+                mud.log_string("ERROR: room %s headed %s to %s, which does not exist."%\
+                               room.proto, dir, ex.destproto)
             elif ch.cansee(ex):
                 list_one_exit(ch, ex, dir)
 
@@ -84,8 +81,8 @@
         if not dir in compass_dirs:
             ex = room.exit(dir)
             if ex.dest == None:
-                log_string("ERROR: room %s headed %s to %s, which does not exist." % \
-                           room.proto, dir, ex.destproto)
+                mud.log_string("ERROR: room %s headed %s to %s, which does not exist." % \
+                               room.proto, dir, ex.destproto)
             elif ch.cansee(ex):
                 list_one_exit(ch, ex, dir)
 
diff -ruN ../nakedmudv3.7.9/lib/pymodules/movement.py lib/pymodules/movement.py
--- ../nakedmudv3.7.9/lib/pymodules/movement.py	2009-03-02 01:45:15.000000000 -0500
+++ lib/pymodules/movement.py	2009-04-05 14:04:03.000000000 -0400
@@ -1,12 +1,8 @@
-################################################################################
-#
-# movement.py
-#
-# all of the functions concerned with movement and position change
-#
-################################################################################
-from mud import *
-from mudsys import add_cmd, add_cmd_check
+'''
+movement.py
+
+all of the functions concerned with movement and position change
+'''
 import inform, hooks, mudsys, mud
 
 
@@ -34,16 +30,18 @@
     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.")
+            mud.message(ch,None,ch.on,None,True,"to_char",
+                        "You stand up from $o.")
+            mud.message(ch,None,ch.on,None,True,"to_room",
+                        "$n stands up from $o.")
             ch.on = None
 
-        # send our messages for sitting down
+        # send our mud.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.")
+        mud.message(ch, None, obj, None, True,
+                    "to_char", "You " + act + " " + obj.furniture_type + " $o.")
+        mud.message(ch, None, obj, None, True,
+                    "to_room", "$n " + act + " " + obj.furniture_type + " $o.")
 
         # place ourselves down on our new furniture
         ch.on  = obj
@@ -60,19 +58,19 @@
         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.")
+            mud.message(ch,None,None,None,True, "to_char", "You stop flying.")
+            mud.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.")
+        mud.message(ch, None, None, None, True, "to_char", "You " + act + ".")
+        mud.message(ch, None, None, None, True, "to_room", "$n "  + act + "s.")
         ch.pos = pos
         return True
 
 def cmd_sit(ch, cmd, arg):
     '''If standing, attempts to sit on the ground.'''
     try:
-        obj, = parse_args(ch, True, cmd, arg, "| [on] obj.room")
+        obj, = mud.parse_args(ch, True, cmd, arg, "| [on] obj.room")
     except: return
 
     if obj == None:
@@ -85,7 +83,7 @@
 def cmd_sleep(ch, cmd, arg):
     '''If awake, attempts to lay down and sleep.'''
     try:
-        obj, = parse_args(ch, True, cmd, arg, "| [on] obj.room")
+        obj, = mud.parse_args(ch, True, cmd, arg, "| [on] obj.room")
     except: return
 
     if obj == None:
@@ -101,8 +99,10 @@
 
 def cmd_wake(ch, cmd, arg):
     '''If sleep, attempts to wake up and sit.'''
-    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.")
+    mud.message(ch,None,None,None,True, "to_char",
+                "You stop sleeping and sit up.")
+    mud.message(ch,None,None,None,True, "to_room",
+                "$n stops sleeping and sits up.")
     ch.pos = "sitting"
 
 def dir_opposite(dir):
@@ -150,15 +150,15 @@
         old_room = ch.room
         dirnum   = dir_index(dir)
 
-        # send out our leave messages as needed. Is anyone in the old room?
+        # send out our leave mud.messages as needed. Is anyone in the old room?
         if mssg == True:
             if ex.leave_mssg != '':
-                message(ch, None, None, None, True, "to_room", ex.leave_mssg)
+                mud.message(ch, None, None, None, True, "to_room",ex.leave_mssg)
             elif dirnum == -1:
-                message(ch, None, None, None, True, "to_room", "$n leaves.")
+                mud.message(ch, None, None, None, True, "to_room", "$n leaves.")
             else:
-                message(ch, None, None, None, True, "to_room",
-                        "$n leaves " + dir_name[dirnum] + ".")
+                mud.message(ch, None, None, None, True, "to_room",
+                            "$n leaves " + dir_name[dirnum] + ".")
 
         # run our leave hooks
         hooks.run("exit", hooks.build_info("ch rm ex", (ch, ch.room, ex)))
@@ -172,15 +172,15 @@
             
         ch.act("look")
 
-        # send out our enter messages as needed
+        # send out our enter mud.messages as needed
         if mssg == True:
             if ex.enter_mssg != '':
-                message(ch, None, None, None, True, "to_room", ex.enter_mssg)
+                mud.message(ch,None,None,None,True,"to_room",ex.enter_mssg)
             elif dirnum == -1:
-                message(ch, None, None, None, True, "to_room","$n has arrived.")
+                mud.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]] +".")
+                mud.message(ch, None, None, None, True, "to_room",
+                            "$n arrives from the "+dir_name[dir_opp[dirnum]]+".")
 
         # run our enter hooks
         hooks.run("enter", hooks.build_info("ch rm", (ch, ch.room)))
@@ -201,26 +201,26 @@
 ################################################################################
 # mud commands
 ################################################################################
-add_cmd("north",     "n",  cmd_move, "player", True)
-add_cmd("west",      "w",  cmd_move, "player", True)
-add_cmd("east",      "e",  cmd_move, "player", True)
-add_cmd("south",     "s",  cmd_move, "player", True)
-add_cmd("up",        "u",  cmd_move, "player", True)
-add_cmd("down",      "d",  cmd_move, "player", True)
-add_cmd("northwest", None, cmd_move, "player", True)
-add_cmd("northeast", None, cmd_move, "player", True)
-add_cmd("southwest", None, cmd_move, "player", True)
-add_cmd("southeast", None, cmd_move, "player", True)
-add_cmd("nw",        None, cmd_move, "player", True)
-add_cmd("ne",        None, cmd_move, "player", True)
-add_cmd("sw",        None, cmd_move, "player", True)
-add_cmd("se",        None, cmd_move, "player", True)
-
-add_cmd("wake",      None, cmd_wake, "player", True)
-add_cmd("sleep",     None, cmd_sleep,"player", True)
-add_cmd("stand",     None, cmd_stand,"player", True)
-add_cmd("land",      None, cmd_stand,"player", True)
-add_cmd("sit",       None, cmd_sit,  "player", True)
+mudsys.add_cmd("north",     "n",  cmd_move, "player", True)
+mudsys.add_cmd("west",      "w",  cmd_move, "player", True)
+mudsys.add_cmd("east",      "e",  cmd_move, "player", True)
+mudsys.add_cmd("south",     "s",  cmd_move, "player", True)
+mudsys.add_cmd("up",        "u",  cmd_move, "player", True)
+mudsys.add_cmd("down",      "d",  cmd_move, "player", True)
+mudsys.add_cmd("northwest", None, cmd_move, "player", True)
+mudsys.add_cmd("northeast", None, cmd_move, "player", True)
+mudsys.add_cmd("southwest", None, cmd_move, "player", True)
+mudsys.add_cmd("southeast", None, cmd_move, "player", True)
+mudsys.add_cmd("nw",        None, cmd_move, "player", True)
+mudsys.add_cmd("ne",        None, cmd_move, "player", True)
+mudsys.add_cmd("sw",        None, cmd_move, "player", True)
+mudsys.add_cmd("se",        None, cmd_move, "player", True)
+
+mudsys.add_cmd("wake",      None, cmd_wake, "player", True)
+mudsys.add_cmd("sleep",     None, cmd_sleep,"player", True)
+mudsys.add_cmd("stand",     None, cmd_stand,"player", True)
+mudsys.add_cmd("land",      None, cmd_stand,"player", True)
+mudsys.add_cmd("sit",       None, cmd_sit,  "player", True)
 
 # The mud needs to know our command for movement as well
 mudsys.set_cmd_move(cmd_move)
@@ -242,7 +242,7 @@
     if not ch.pos == "sleeping":
         ch.send("You must be asleep to wake up.")
         return False
-add_cmd_check("wake", chk_wake)
+mudsys.add_cmd_check("wake", chk_wake)
 
 def chk_sleep(ch, cmd):
     if ch.pos == "sleeping":
@@ -251,7 +251,7 @@
     elif ch.pos == "unconscious":
         ch.send("You cannot sleep while you are unconscious.")
         return False
-add_cmd_check("sleep", chk_sleep)
+mudsys.add_cmd_check("sleep", chk_sleep)
 
 def chk_stand(ch, cmd):
     if ch.pos == "standing":
@@ -260,7 +260,7 @@
     elif ch.pos != "sitting":
         ch.send("You cannot stand while " + ch.pos + ".")
         return False
-add_cmd_check("stand", chk_stand)
+mudsys.add_cmd_check("stand", chk_stand)
 
 def chk_land(ch, cmd):
     if ch.pos == "standing":
@@ -269,7 +269,7 @@
     elif ch.pos != "flying":
         ch.send("You cannot land if you are not flying.")
         return False
-add_cmd_check("land", chk_land)
+mudsys.add_cmd_check("land", chk_land)
 
 def chk_sit(ch, cmd):
     if ch.pos == "sitting":
@@ -278,4 +278,4 @@
     elif ch.pos != "standing":
         ch.send("You must be standing to sit.")
         return False
-add_cmd_check("sit", chk_sit)
+mudsys.add_cmd_check("sit", chk_sit)
diff -ruN ../nakedmudv3.7.9/lib/pymodules/path.py lib/pymodules/path.py
--- ../nakedmudv3.7.9/lib/pymodules/path.py	2009-03-02 01:45:15.000000000 -0500
+++ lib/pymodules/path.py	2009-04-01 13:03:01.000000000 -0400
@@ -4,8 +4,6 @@
 Plugs into the routine module to allow for the easy construction of paths and
 path following.
 '''
-from mud import *
-from mudsys import add_cmd
 import mud, mudsys, room
 
 
@@ -16,7 +14,7 @@
 def leads_to(frm, to):
     '''returns whether from leads directly to to'''
     for ex in frm.exnames:
-        if frm.exit(ex).dest is to:
+        if frm.exit(ex).dest == to:
             return True
     return False
 
@@ -24,80 +22,61 @@
                       ignore = None):
     '''calculates the shortest path, but uses a breadth first search. More
        efficient than depth-first seach for very short paths with lots of
-       branches or very large muds.'''
+       branches or very large muds.
+    '''
     if frm == to:
-        return [frm]
+        return [ frm ]
 
-    rooms = []
-    depth = []
+    depth = [ [ frm ] ]
 
     if ignore == None:
         ignore = set()
     ignore.add(frm)
 
-    # what is our highest depth
-    i = 1
-
-    # the index of the room our last depth started at
-    j = 0
-
-    # append ourself and our depth
-    rooms.append(frm)
-    depth.append(i)
-
     # figure out what zone we're doing this from
     zone = None
     if stay_zone:
-        zone = "@" + frm.proto.split("@")[-1]
+        zone = frm.locale
 
-    # keep going until we find To, or we can't go any deeper
+    # keep going until we find to, or we can't go any deeper
     found = False
     while not found:
-        prev_depth = rooms[j:]
-        for rm in prev_depth:
-            for ex in rm.exnames:
-                dest = rm.exit(ex).dest
-                if (dest == None or dest in ignore or
-                    (stay_zone and not dest.proto.endswith(zone))):
-                    continue
-                rooms.append(dest)
-                depth.append(i)
-                if dest is to:
+        layer = [ ]
+        for room in depth[-1]:
+            for dir in room.exnames:
+                dest = room.exit(dir).dest
+                if dest == None or dest in ignore:
+                    pass
+                elif zone != None and dest.locale != zone:
+                    pass
+                elif dest == to:
                     found = True
+                    layer = [ ]
                     break
-                ignore.add(rm)
-            if found:
+                else:
+                    layer.append(dest)
+                ignore.add(dest)
+            if found == True:
                 break
+        if len(layer) > 0:
+            depth.append(layer)
+        if found == True or len(layer) == 0:
+            break
 
-        i += 1
-        j += len(prev_depth)
+    # no path found
+    if found == False:
+        return None
 
-    # go backwards from our destination
-    rooms.reverse()
-    depth.reverse()
-
-    # first step, pull out our destination room
-    path = [to]
-
-    # pull out all other rooms on the shortest path
-    while len(rooms) > 0:
-        curr_depth = depth[0]
-        
-        # figure out which room in our current layer
-        # links to our previous room in the shortest path
-        for next in rooms:
-            if leads_to(next, path[len(path)-1]):
-                path.append(next)
+    # find the rooms that link each other, in reverse order
+    path  = [ to ]
+    order = range(len(depth))
+    order.reverse()
+    for i in order:
+        for room in depth[i]:
+            if leads_to(room, path[-1]):
+                path.append(room)
                 break
 
-        # clear our last layer
-        i = 0
-        while i < len(depth) and depth[i] == curr_depth:
-            i += 1
-        rooms = rooms[i:]
-        depth = depth[i:]
-
-    # put it back in order
     path.reverse()
     return path
 
@@ -115,12 +94,12 @@
     ignore.add(frm)
 
     # if we're the target room, return an empty list
-    if frm is to:
+    if frm == to:
         return [frm]
 
     zone = None
     if stay_zone:
-        zone = "@" + frm.proto.split("@")[-1]
+        zone = frm.locale
 
     # build the shortest path 
     for ex in frm.exnames:
@@ -131,12 +110,12 @@
         # get the dest room. if there is none, skip this exit
         next_room = frm.exit(ex).dest
         
-        if next_room is None:
+        if next_room == None:
             continue
 
         # if we already know this is a dead end or a loopback, skip it
         if (next_room in ignore or
-            (stay_zone and not next_room.proto.endswith(zone))):
+            (stay_zone and not next_room.locale == zone)):
             continue
 
         next_path = shortest_path(next_room, to, ignore_doors, stay_zone,ignore)
@@ -201,12 +180,12 @@
 # commands
 ################################################################################
 def cmd_path(ch, cmd, arg):
-    '''Usage: path <person>
+    '''Usage: path <room>
 
        Prints out a Python list of the directions needed to move from your
-       current location to the location of the specified person.'''
+       current location to a specified destination.'''
     try:
-        dest, = parse_args(ch, True, cmd, arg, "room")
+        dest, = mud.parse_args(ch, True, cmd, arg, "room")
     except: return
 
     path = build_patrol([ch.room, dest])
@@ -223,7 +202,7 @@
 ################################################################################
 
 # add our commands
-add_cmd("path", None, cmd_path, "admin", False)
+mudsys.add_cmd("path", None, cmd_path, "admin", False)
 
 # mud initialization
 mud.build_patrol = build_patrol
diff -ruN ../nakedmudv3.7.9/lib/pymodules/routine.py lib/pymodules/routine.py
--- ../nakedmudv3.7.9/lib/pymodules/routine.py	2009-03-02 01:45:15.000000000 -0500
+++ lib/pymodules/routine.py	2009-04-05 14:05:10.000000000 -0400
@@ -6,8 +6,6 @@
 anything else. This was primarily meant to be for path-following, but I figured
 it was worth the time to generalize it out for more complex actions
 '''
-from mud import *
-from mudsys import add_cmd
 import mud, mudsys, auxiliary, storage, event
 
 
@@ -24,6 +22,8 @@
 # auxiliary data
 ################################################################################
 class RoutineAuxData:
+    '''Holds character data related to character routines.
+    '''
     def __init__(self, set = None):
         self.routine = None   # the routine we follow
         self.repeat  = False  # after we finish it, do we repeat?
@@ -176,8 +176,8 @@
        Alternatively, these commands can be replaced with function calls.
        '''
     try:
-        tgt, routine, repeat = parse_args(ch, True, cmd, arg,
-                                          "ch.room.noself word(py_list) | bool(repeat)")
+        tgt, routine, repeat = mud.parse_args(ch, True, cmd, arg,
+                                              "ch.room.noself word(py_list) | bool(repeat)")
     except:
         return
 
@@ -197,7 +197,7 @@
 register_routine_check(lambda ch: ch.isActing())
 
 # commands
-add_cmd("routine", None, cmd_routine, "admin", False)
+mudsys.add_cmd("routine", None, cmd_routine, "admin", False)
 
 # misc initialization
 # mud.set_routine = set_routine
diff -ruN ../nakedmudv3.7.9/lib/pymodules/utils.py lib/pymodules/utils.py
--- ../nakedmudv3.7.9/lib/pymodules/utils.py	2009-03-02 02:59:02.000000000 -0500
+++ lib/pymodules/utils.py	2009-04-05 14:05:40.000000000 -0400
@@ -1,10 +1,8 @@
-################################################################################
-#
-# utils.py
-#
-# Various utility functions used by other Python modules.
-#
-################################################################################
+'''
+utils.py
+
+Various utility functions used by other Python modules.
+'''
 import mud
 
 
