nakedmudv3.3/
nakedmudv3.3/lib/
nakedmudv3.3/lib/logs/
nakedmudv3.3/lib/misc/
nakedmudv3.3/lib/players/
nakedmudv3.3/lib/txt/
nakedmudv3.3/lib/world/
nakedmudv3.3/lib/world/examples/
nakedmudv3.3/lib/world/examples/mproto/
nakedmudv3.3/lib/world/examples/oproto/
nakedmudv3.3/lib/world/examples/reset/
nakedmudv3.3/lib/world/examples/rproto/
nakedmudv3.3/lib/world/examples/trigger/
nakedmudv3.3/lib/world/limbo/
nakedmudv3.3/lib/world/limbo/room/
nakedmudv3.3/lib/world/limbo/rproto/
nakedmudv3.3/src/alias/
nakedmudv3.3/src/char_vars/
nakedmudv3.3/src/editor/
nakedmudv3.3/src/example_module/
nakedmudv3.3/src/help/
nakedmudv3.3/src/set_val/
nakedmudv3.3/src/socials/
nakedmudv3.3/src/time/
//*****************************************************************************
//
// py_char.c
//
// A python extention to allow python scripts to treat MUD characters as an
// object within the script.
//
//*****************************************************************************

#include <Python.h>
#include <structmember.h>

#include "../mud.h"
#include "../utils.h"
#include "../world.h"
#include "../room.h"
#include "../character.h"
#include "../object.h"
#include "../races.h"
#include "../handler.h"
#include "../extra_descs.h"
#include "../prototype.h"

#include "pyplugs.h"
#include "scripts.h"
#include "pychar.h"
#include "pyroom.h"
#include "pyobj.h"
#include "pyauxiliary.h"



//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "../items/items.h"
#include "../items/worn.h"



//*****************************************************************************
// local structures and defines
//*****************************************************************************
// a list of the get/setters on the Obj class
LIST *pyobj_getsetters = NULL;

// a list of the methods on the Obj class
LIST *pyobj_methods = NULL;

typedef struct {
  PyObject_HEAD
  int uid;
} PyObj;



//*****************************************************************************
// allocation, deallocation, initialization, and comparison
//*****************************************************************************
void PyObj_dealloc(PyObj *self) {
  self->ob_type->tp_free((PyObject*)self);
}

PyObject *PyObj_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
    PyObj *self;

    self = (PyObj  *)type->tp_alloc(type, 0);
    self->uid = NOTHING;
    return (PyObject *)self;
}

int PyObj_init(PyObj *self, PyObject *args, PyObject *kwds) {
  char *kwlist[] = {"uid", NULL};
  int uid = NOTHING;

  // get the universal id
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &uid)) {
    PyErr_Format(PyExc_TypeError, 
                    "Objects may only be created by uid");
    return -1;
  }

  // make sure a object with the UID exists
  if(!propertyTableGet(obj_table, uid)) {
    PyErr_Format(PyExc_TypeError, 
                    "Object with uid, %d, does not exist", uid);
    return -1;
  }

  self->uid = uid;
  return 0;
}

int PyObj_compare(PyObj *obj1, PyObj *obj2) {
  if(obj1->uid == obj2->uid)
    return 0;
  else if(obj1->uid < obj2->uid)
    return -1;
  else
    return 1;
}



//*****************************************************************************
// getters and setters for the Obj class
//*****************************************************************************
PyObject *PyObj_getname(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("s", objGetName(obj));
  else            return NULL;
}

PyObject *PyObj_getmname(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("s", objGetMultiName(obj));
  else            return NULL;
}

PyObject *PyObj_getbits(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("s", bitvectorGetBits(objGetBits(obj)));
  else            return NULL;
}

PyObject *PyObj_getkeywords(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("s", objGetKeywords(obj));
  else            return NULL;
}

PyObject *PyObj_getdesc(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("s", objGetDesc(obj));
  else            return NULL;
}

PyObject *PyObj_getrdesc(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("s", objGetRdesc(obj));
  else            return NULL;
}

PyObject *PyObj_getmdesc(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("s", objGetMultiRdesc(obj));
  else            return NULL;
}

PyObject *PyObj_getuid(PyObj *self, void *closure) {
  return Py_BuildValue("i", self->uid);
}

PyObject *PyObj_getprototypes(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("s", objGetPrototypes(obj));
  else           return NULL;
}

PyObject *PyObj_getweight(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("d", objGetWeight(obj));
  else            return NULL;
}


PyObject *PyObj_get_weight_raw(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) return Py_BuildValue("d", objGetWeightRaw(obj));
  else            return NULL;
}

PyObject *PyObj_getcontents(PyObj *self, PyObject *args) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj == NULL) 
    return NULL;

  LIST_ITERATOR *cont_i = newListIterator(objGetContents(obj));
  PyObject *list = PyList_New(0);
  OBJ_DATA *cont;
  
  // for each obj in the contentory, add it to the Python list
  ITERATE_LIST(cont, cont_i)
    PyList_Append(list, objGetPyFormBorrowed(cont));
  deleteListIterator(cont_i);
  PyObject *retval = Py_BuildValue("O", list);
  Py_DECREF(list);
  return retval;
}

PyObject *PyObj_getchars(PyObj *self, PyObject *args) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj == NULL) 
    return NULL;

  LIST_ITERATOR *char_i = newListIterator(objGetUsers(obj));
  PyObject *list = PyList_New(0);
  CHAR_DATA *ch;
  
  // for each obj in the contentory, add it to the Python list
  ITERATE_LIST(ch, char_i)
    PyList_Append(list, charGetPyFormBorrowed(ch));
  deleteListIterator(char_i);
  PyObject *retval = Py_BuildValue("O", list);
  Py_DECREF(list);
  return retval;
}

PyObject *PyObj_getcarrier(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj == NULL)
    return NULL;
  if(objGetCarrier(obj) == NULL)
    return Py_BuildValue("O", Py_None);
  return Py_BuildValue("O", charGetPyFormBorrowed(objGetCarrier(obj)));
}

PyObject *PyObj_getroom(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj == NULL)
    return NULL;
  if(objGetRoom(obj) == NULL)
    return Py_BuildValue("O", Py_None);
  return Py_BuildValue("O", roomGetPyFormBorrowed(objGetRoom(obj)));
}

PyObject *PyObj_getcontainer(PyObj *self, void *closure) {
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj == NULL)
    return NULL;
  if(objGetContainer(obj) == NULL)
    return Py_BuildValue("O", Py_None);
  return Py_BuildValue("O", objGetPyFormBorrowed(objGetContainer(obj)));
}

//
// Standard check to make sure the object exists when
// trying to set a value for it. If successful, assign the
// object to ch. Otherwise, return -1 (error)
#define PYOBJ_CHECK_OBJ_EXISTS(uid, obj)                                       \
  obj = propertyTableGet(obj_table, uid);                                      \
  if(obj == NULL) {                                                            \
    PyErr_Format(PyExc_TypeError,                                              \
		    "Tried to modify nonexistant object, %d", uid);            \
    return -1;                                                                 \
  }                                                                            

int PyObj_setname(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's name");
    return -1;
  }
  
  if (!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Object names must be strings");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  objSetName(obj, PyString_AsString(value));
  return 0;
}

int PyObj_setmname(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's multi-name");
    return -1;
  }
  
  if (!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Object multi-names must be strings");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  objSetMultiName(obj, PyString_AsString(value));
  return 0;
}

int PyObj_setbits(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's bits");
    return -1;
  }
  
  if (!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Object bits must be strings");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  bitClear(objGetBits(obj));
  bitSet(objGetBits(obj), PyString_AsString(value));
  return 0;
}

int PyObj_setkeywords(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's keywords");
    return -1;
  }
  
  if (!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Object keywords must be strings");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  objSetKeywords(obj, PyString_AsString(value));
  return 0;
}

int PyObj_setdesc(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's description");
    return -1;
  }
  
  if (!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Object descriptions must be strings");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  objSetDesc(obj, PyString_AsString(value));
  return 0;
}

int PyObj_setrdesc(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's rdesc");
    return -1;
  }
  
  if (!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Object rdescs must be strings");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  objSetRdesc(obj, PyString_AsString(value));
  return 0;
}

int PyObj_setmdesc(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's multi-rdesc");
    return -1;
  }
  
  if (!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Object multi-rdescs must be strings");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  objSetMultiRdesc(obj, PyString_AsString(value));
  return 0;
}

int PyObj_setweight(PyObj *self, PyObject *value, void *closure) {
  double weight = 0;
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's weight");
    return -1;
  }

  if(PyFloat_Check(value))
    weight = PyFloat_AsDouble(value);
  else if(PyInt_Check(value))
    weight = PyInt_AsLong(value);
  else {
    PyErr_Format(PyExc_TypeError, "Object weight must be a numeric value.");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  objSetWeightRaw(obj, weight);
  return 0;
}

int PyObj_setcarrier(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's carrier");
    return -1;
  }

  if (!PyChar_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Carrier must be a character!");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  CHAR_DATA *carrier = PyChar_AsChar(value);
  // remove us from whatever we're currently in
  if(objGetRoom(obj))
    obj_from_room(obj);
  if(objGetCarrier(obj))
    obj_from_char(obj);
  if(objGetContainer(obj))
    obj_from_obj(obj);
  if(objGetWearer(obj)) {
    // weird... we couldn't unequip the item from the current wearer
    if(!try_unequip(objGetWearer(obj), obj)) {
      PyErr_Format(PyExc_StandardError, "Could not unequip previous wearer.");
      return -1;
    }
  }

  // give the obj to the character
  obj_to_char(obj, carrier);
  return 0;
}

int PyObj_setroom(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's room");
    return -1;
  }

  if (!PyRoom_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Room must be a room!");
    return -1;
  }

  OBJ_DATA *obj;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  ROOM_DATA *room = PyRoom_AsRoom(value);
  // remove us from whatever we're currently in
  if(objGetRoom(obj))
    obj_from_room(obj);
  if(objGetCarrier(obj))
    obj_from_char(obj);
  if(objGetContainer(obj))
    obj_from_obj(obj);
  if(objGetWearer(obj)) {
    // weird... we couldn't unequip the item from the current wearer
    if(!try_unequip(objGetWearer(obj), obj)) {
      PyErr_Format(PyExc_StandardError, "Could not unequip wearer.");
      return -1;
    }
  }

  // give the obj to the character
  obj_to_room(obj, room);
  return 0;
}

int PyObj_setcontainer(PyObj *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete object's container");
    return -1;
  }

  if (!PyObj_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Container must be an object!");
    return -1;
  }

  OBJ_DATA *obj, *cont;
  PYOBJ_CHECK_OBJ_EXISTS(self->uid, obj);
  PYOBJ_CHECK_OBJ_EXISTS(((PyObj *)value)->uid, cont);
  // remove us from whatever we're currently in
  if(objGetRoom(obj))
    obj_from_room(obj);
  if(objGetCarrier(obj))
    obj_from_char(obj);
  if(objGetContainer(obj))
    obj_from_obj(obj);
  if(objGetWearer(obj)) {
    // weird... we couldn't unequip the item from the current wearer
    if(!try_unequip(objGetWearer(obj), obj)) {
      PyErr_Format(PyExc_StandardError, "Could not unequip wearer.");
      return -1;
    }
  }

  // give the obj to the character
  obj_to_obj(obj, cont);
  return 0;
}



//*****************************************************************************
// methods for the obj class
//*****************************************************************************
PyObject *PyObj_attach(PyObj *self, PyObject *args) {  
  char *key = NULL;

  // make sure we're getting passed the right type of data
  if (!PyArg_ParseTuple(args, "s", &key)) {
    PyErr_Format(PyExc_TypeError, 
		 "To attach a trigger, the key must be suppplied.");
    return NULL;
  }

  // pull out the character and do the attaching
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj == NULL) {
    PyErr_Format(PyExc_StandardError,
		 "Tried to attach trigger to nonexistant obj, %d.", self->uid);
    return NULL;
  }

  TRIGGER_DATA *trig =
    worldGetType(gameworld, "trigger", 
		 get_fullkey_relative(key, get_script_locale()));
  if(trig != NULL) {
    triggerListAdd(objGetTriggers(obj), triggerGetKey(trig));
    return Py_BuildValue("i", 1);
  }
  else {
    PyErr_Format(PyExc_StandardError, 
		 "Tried to attach nonexistant script, %s, to object %s.",
		 key, objGetClass(obj));
    return NULL;
  }
}

PyObject *PyObj_detach(PyObj *self, PyObject *args) {  
  char *key = NULL;

  // make sure we're getting passed the right type of data
  if (!PyArg_ParseTuple(args, "s", &key)) {
    PyErr_Format(PyExc_TypeError, 
		 "To detach a trigger, its key must be suppplied.");
    return NULL;
  }

  // pull out the character and do the attaching
  OBJ_DATA    *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) {
    const char *fkey = get_fullkey_relative(key, get_script_locale());
    triggerListRemove(objGetTriggers(obj), fkey);
    return Py_BuildValue("i", 1);
  }
  else {
    PyErr_Format(PyExc_StandardError, 
		 "Tried to detach script from nonexistant obj, %d.", self->uid);
    return NULL;
  }
}

PyObject *PyObj_isinstance(PyObj *self, PyObject *args) {  
  char *type = NULL;

  // make sure we're getting passed the right type of data
  if (!PyArg_ParseTuple(args, "s", &type)) {
    PyErr_Format(PyExc_TypeError, "isinstance only accepts strings.");
    return NULL;
  }

  // pull out the object and check the type
  OBJ_DATA    *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) {
    PyObject *retval = NULL;
    char     *locale = NULL;
    if(get_script_locale())
      locale = strdup(get_script_locale());
    else
      locale = strdup(get_key_locale(objGetClass(obj)));

    retval = 
      Py_BuildValue("i", objIsInstance(obj, get_fullkey_relative(type,locale)));
    free(locale);
    return retval;
  }
  else {
    PyErr_Format(PyExc_StandardError, 
		 "Tried to check instances of nonexistent object, %d.", self->uid);
    return NULL;
  }
}

PyObject *PyObj_istype(PyObj *self, PyObject *args) {  
  char *type = NULL;

  // make sure we're getting passed the right type of data
  if (!PyArg_ParseTuple(args, "s", &type)) {
    PyErr_Format(PyExc_TypeError, "istype only accepts strings.");
    return NULL;
  }

  // pull out the object and check the type
  OBJ_DATA    *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL)
    return Py_BuildValue("i", objIsType(obj, type));
  else {
    PyErr_Format(PyExc_StandardError, 
		 "Tried to check type of nonexistent object, %d.", self->uid);
    return NULL;
  }
}

PyObject *PyObj_settype(PyObj *self, PyObject *args) {  
  char *type = NULL;

  // make sure we're getting passed the right type of data
  if (!PyArg_ParseTuple(args, "s", &type)) {
    PyErr_Format(PyExc_TypeError, "settype only accepts strings.");
    return NULL;
  }

  // pull out the object and check the type
  OBJ_DATA    *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) {
    objSetType(obj, type);
    return Py_BuildValue("i", 1);
  }
  else {
    PyErr_Format(PyExc_StandardError, 
		 "Tried to set type of nonexistent object, %d.", self->uid);
    return NULL;
  }
}

//
// create a new extra description for the object
PyObject *PyObj_edesc(PyObj *self, PyObject *value) {
  char *keywords = NULL;
  char     *desc = NULL;

  if (!PyArg_ParseTuple(value, "ss", &keywords, &desc)) {
    PyErr_Format(PyExc_TypeError, "Extra descs must be strings.");
    return NULL;
  }

  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj != NULL) {
    EDESC_DATA *edesc = newEdesc(keywords, desc);
    edescSetPut(objGetEdescs(obj), edesc);
    return Py_BuildValue("i", 1);
  }
  else {
    PyErr_Format(PyExc_TypeError,
		 "Tried to set edesc for nonexistent obj, %d.", self->uid);
    return NULL;
  }
}

//
// returns the specified piece of auxiliary data from the object
// if it is a piece of python auxiliary data.
PyObject *PyObj_get_auxiliary(PyObj *self, PyObject *args) {
  char *keyword = NULL;
  if(!PyArg_ParseTuple(args, "s", &keyword)) {
    PyErr_Format(PyExc_TypeError,
		 "getAuxiliary() must be supplied with the name that the "
		 "auxiliary data was installed under!");
    return NULL;
  }

  // make sure we exist
  OBJ_DATA *obj = PyObj_AsObj((PyObject *)self);
  if(obj == NULL) {
    PyErr_Format(PyExc_StandardError,
		 "Tried to get auxiliary data for a nonexistant object.");
    return NULL;
  }

  // make sure the auxiliary data exists
  if(!pyAuxiliaryDataExists(keyword)) {
    PyErr_Format(PyExc_StandardError,
		 "No auxiliary data named '%s' exists!", keyword);
    return NULL;
  }

  PyObject *data = objGetAuxiliaryData(obj, keyword);
  if(data == NULL)
    data = Py_None;
  PyObject *retval = Py_BuildValue("O", data);
  //  Py_DECREF(data);
  return retval;
}



//*****************************************************************************
// structures to define our methods and classes
//*****************************************************************************
PyTypeObject PyObj_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "obj.Obj",                 /*tp_name*/
    sizeof(PyObj),             /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)PyObj_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    (cmpfunc)PyObj_compare,    /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    "Obj/Obj objects",         /* tp_doc */
    0,		               /* tp_traverse */
    0,		               /* tp_clear */
    0,		               /* tp_richcompare */
    0,		               /* tp_weaklistoffset */
    0,		               /* tp_iter */
    0,		               /* tp_iternext */
    0,                         /* tp_methods */
    0,                         /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)PyObj_init,      /* tp_init */
    0,                         /* tp_alloc */
    PyObj_new,                 /* tp_new */
};



//*****************************************************************************
// the obj module
//*****************************************************************************
PyObject *PyObj_load_obj(PyObject *self, PyObject *args) {
  char          *key = NULL;
  PyObject       *in = NULL;
  ROOM_DATA    *room = NULL; // are we loading to a room?
  OBJ_DATA     *cont = NULL; // are we loading to a container?
  CHAR_DATA      *ch = NULL; // are we loading to a character?
  char     *equip_to = NULL; // are we trying to equip the character?

  if (!PyArg_ParseTuple(args, "sO|s", &key, &in, &equip_to)) {
    PyErr_Format(PyExc_TypeError, 
		 "Load obj failed - it needs a key and destination.");
    return NULL;
  }

  // figure out what we're trying to load this thing into
  if(PyString_Check(in))
    room = worldGetRoom(gameworld, PyString_AsString(in));
  else if(PyRoom_Check(in))
    room = PyRoom_AsRoom(in);
  else if(PyObj_Check(in))
    cont = propertyTableGet(obj_table, PyObj_AsUid(in));
  else if(PyChar_Check(in))
      ch = propertyTableGet(mob_table, PyChar_AsUid(in));

  // make sure a destination exists
  if(room == NULL && cont == NULL && ch == NULL) {
    PyErr_Format(PyExc_TypeError, 
		 "Load obj failed: destination does not exist.");
    return NULL;
  }

  // check the obj
  PROTO_DATA *obj_proto = 
    worldGetType(gameworld, "oproto", 
		 get_fullkey_relative(key, get_script_locale()));
  if(obj_proto == NULL) {
    PyErr_Format(PyExc_TypeError, 
		 "Load obj failed: oproto %s does not exist.", 
		 get_fullkey_relative(key, get_script_locale()));
    return NULL;
  }

  // copy the object
  OBJ_DATA *obj = protoObjRun(obj_proto);
  if(obj == NULL) {
    //    PyErr_Format(PyExc_TypeError,
    //		 "Load obj failed: proto script terminated with an error.");
    return NULL;
  }

  // figure out where we're trying to load the object to
  if(room != NULL)
    obj_to_room(obj, room);
  else if(cont != NULL)
    obj_to_obj(obj, cont);
  else if(ch != NULL) {
    // if we have supplied locations, equip to those
    if(equip_to && *equip_to) {
      if(!try_equip(ch, obj, equip_to, NULL))
	obj_to_char(obj, ch);
    }

    // otherwise, assume it's worn equipemnt
    else if(objIsType(obj, "worn")) {
      if(!try_equip(ch, obj, NULL, wornGetPositions(obj)))
	obj_to_char(obj, ch);
    }

    // failed. Just give it to us
    else
      obj_to_char(obj, ch);
  }

  // create a python object for the new obj, and return it
  return Py_BuildValue("O", objGetPyFormBorrowed(obj));
}


PyObject *PyObj_count_objs(PyObject *self, PyObject *args) {
  LIST            *list = NULL;
  char             *tgt = NULL;
  PyObject          *in = NULL;
  ROOM_DATA       *room = NULL;
  OBJ_DATA        *cont = NULL;
  CHAR_DATA         *ch = NULL;
  const char *prototype = NULL;

  if (!PyArg_ParseTuple(args, "s|O", &tgt, &in)) {
    PyErr_Format(PyExc_TypeError, "count_objs failed. No arguments supplied.");
    return NULL;
  }

  // get the full key for our prototype
  prototype = get_fullkey_relative(tgt, get_script_locale());

  // if we didn't supply something to look in, assume it means the world
  if(in == NULL)
    return Py_BuildValue("i", count_objs(NULL, object_list, NULL, prototype, 
					 FALSE));

  // see what we're looking in
  if(PyString_Check(in))
    room = worldGetRoom(gameworld, PyString_AsString(in));
  else if(PyRoom_Check(in))
    room = PyRoom_AsRoom(in);
  else if(PyObj_Check(in))
    cont = propertyTableGet(obj_table, PyObj_AsUid(in));
  else if(PyChar_Check(in))
    ch   = propertyTableGet(mob_table, PyChar_AsUid(in));

  // now find the list we're dealing with
  if(room) list = roomGetContents(room);
  if(cont) list = objGetContents(cont);
  if(ch)   list = charGetInventory(ch);

  if(list == NULL) {
    PyErr_Format(PyExc_TypeError, 
		 "count_objs failed. invalid argument supplied.");
    return NULL;
  }
  
  return Py_BuildValue("i", count_objs(NULL, list, NULL, prototype, FALSE));
}


PyObject *PyObj_find_obj(PyObject *self, PyObject *args) {
  LIST *list           = object_list;
  PyObject *in         = NULL;
  ROOM_DATA *room      = NULL;
  OBJ_DATA  *cont      = NULL;
  CHAR_DATA *ch        = NULL;
  CHAR_DATA *looker_ch = NULL;
  PyObject *looker     = NULL;
  char *tgt            = NULL;

  if (!PyArg_ParseTuple(args, "s|OO", &tgt, &in, &looker)) {
    PyErr_Format(PyExc_TypeError, 
                    "find_obj failed. No arguments supplied.");
    return NULL;
  }

  // check for scope of search
  if(in) {
    if(PyString_Check(in))
      room = worldGetRoom(gameworld, PyString_AsString(in));
    else if(PyRoom_Check(in))
      room = PyRoom_AsRoom(in);
    else if(PyObj_Check(in))
      cont = propertyTableGet(obj_table, PyObj_AsUid(in));
    else if(PyChar_Check(in))
      ch   = propertyTableGet(mob_table, PyChar_AsUid(in));
  }

  // check to see who's looking
  if(looker && PyChar_Check(looker))
    looker_ch = propertyTableGet(mob_table, PyChar_AsUid(looker));

  // now find the list we're dealing with
  if(room) list = roomGetContents(room);
  if(cont) list = objGetContents(cont);
  if(ch)   list = charGetInventory(ch);

  // now, do the search
  int count = 1;
  char name[SMALL_BUFFER] = "";
  get_count(tgt, name, &count);

  // we're just looking for a single item
  if(count != COUNT_ALL) {
    OBJ_DATA *obj    = find_obj(looker_ch, list, count, name, NULL, 
				(looker_ch ? TRUE : FALSE));
    PyObject *py_obj = Py_None;
    if(obj) py_obj = objGetPyFormBorrowed(obj);
    return Py_BuildValue("O", py_obj);
  }
  // otherwise, return everything that meets our critereon
  else {
    //***********
    // FINISH ME
    //***********
    return Py_BuildValue("O", Py_None);
  }
}

PyObject *PyObj_find_obj_key(PyObject *self, PyObject *args) {
  LIST *list           = object_list;
  PyObject *in         = NULL;
  ROOM_DATA *room      = NULL;
  OBJ_DATA  *cont      = NULL;
  CHAR_DATA *ch        = NULL;
  CHAR_DATA *looker_ch = NULL;
  PyObject *looker     = NULL;
  char *tgt            = NULL;
  const char *key      = NULL;

  if (!PyArg_ParseTuple(args, "s|OO", &tgt, &in, &looker)) {
    PyErr_Format(PyExc_TypeError, 
                    "find_obj failed. No arguments supplied.");
    return NULL;
  }

  // figure out our key
  key = get_fullkey_relative(tgt, get_script_locale());

  // check for scope of search
  if(in) {
    if(PyString_Check(in))
      room = worldGetRoom(gameworld, PyString_AsString(in));
    else if(PyRoom_Check(in))
      room = PyRoom_AsRoom(in);
    else if(PyObj_Check(in))
      cont = propertyTableGet(obj_table, PyObj_AsUid(in));
    else if(PyChar_Check(in))
      ch   = propertyTableGet(mob_table, PyChar_AsUid(in));
  }

  // check to see who's looking
  if(looker && PyChar_Check(looker))
    looker_ch = propertyTableGet(mob_table, PyChar_AsUid(looker));

  // now, do the search
  int count = 1;
  char name[SMALL_BUFFER] = "";
  get_count(tgt, name, &count);

  // we're just looking for a single item
  if(count != COUNT_ALL) {
    OBJ_DATA *obj    = find_obj(looker_ch, list, count, NULL, key,
				(looker_ch ? TRUE : FALSE));
    PyObject *py_obj = Py_None;
    if(obj) py_obj = objGetPyFormBorrowed(obj);
    return Py_BuildValue("O", py_obj);
  }
  // otherwise, return everything that meets our critereon
  else {
    //***********
    // FINISH ME
    //***********
    return Py_BuildValue("O", Py_None);
  }
}


PyMethodDef obj_module_methods[] = {
  { "load_obj", PyObj_load_obj, METH_VARARGS,
    "load a object with the specified oproto to a room." },
  { "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."},
  { "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."},
  { "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."},
  {NULL, NULL, 0, NULL}  /* Sentinel */
};



//*****************************************************************************
// implementation of pyobj.h
//*****************************************************************************
void PyObj_addGetSetter(const char *name, void *g, void *s, const char *doc) {
  // make sure our list of get/setters is created
  if(pyobj_getsetters == NULL) pyobj_getsetters = newList();

  // make the GetSetter def
  PyGetSetDef *def = calloc(1, sizeof(PyGetSetDef));
  def->name        = strdup(name);
  def->get         = (getter)g;
  def->set         = (setter)s;
  def->doc         = (doc ? strdup(doc) : NULL);
  def->closure     = NULL;
  listPut(pyobj_getsetters, def);
}

void PyObj_addMethod(const char *name, void *f, int flags, const char *doc) {
  // make sure our list of methods is created
  if(pyobj_methods == NULL) pyobj_methods = newList();

  // make the Method def
  PyMethodDef *def = calloc(1, sizeof(PyMethodDef));
  def->ml_name     = strdup(name);
  def->ml_meth     = (PyCFunction)f;
  def->ml_flags    = flags;
  def->ml_doc      = (doc ? strdup(doc) : NULL);
  listPut(pyobj_methods, def);
}

PyMODINIT_FUNC
init_PyObj(void) {
    PyObject* m;

    // getters and setters
    PyObj_addGetSetter("contents", PyObj_getcontents, NULL,
		       "the object's contents");
    PyObj_addGetSetter("objs", PyObj_getcontents, NULL,
		       "the object's contents");
    PyObj_addGetSetter("chars", PyObj_getchars, NULL,
		       "the characters sitting on/riding the object");
    PyObj_addGetSetter("name", PyObj_getname, PyObj_setname,
		       "the object's name");
    PyObj_addGetSetter("mname", PyObj_getmname, PyObj_setmname,
		       "the object's multi-name");
    PyObj_addGetSetter("desc", PyObj_getdesc, PyObj_setdesc,
		       "the object's long description");
    PyObj_addGetSetter("rdesc", PyObj_getrdesc, PyObj_setrdesc,
		       "the object's room description");
    PyObj_addGetSetter("mdesc", PyObj_getmdesc, PyObj_setmdesc,
		       "the object's multi room description");
    PyObj_addGetSetter("keywords", PyObj_getkeywords, PyObj_setkeywords,
		       "the object's keywords");
    PyObj_addGetSetter("weight", PyObj_getweight, PyObj_setweight,
		       "the object's weight (plus contents)");
    PyObj_addGetSetter("weight_raw", PyObj_get_weight_raw, NULL,
		       "the object's weight (minus contents)");
    PyObj_addGetSetter("uid", PyObj_getuid, NULL,
		       "the object's unique identification number");
    PyObj_addGetSetter("prototypes", PyObj_getprototypes, NULL,
		       "a comma-separated list of this obj's prototypes.");
    PyObj_addGetSetter("bits", PyObj_getbits, PyObj_setbits,
		       "the object's basic bitvector.");
    PyObj_addGetSetter("carrier", PyObj_getcarrier, PyObj_setcarrier,
		       "the person carrying the object");
    PyObj_addGetSetter("room", PyObj_getroom, PyObj_setroom,
		       "The room this object is in. "
		       "None if on a character or in another object");
    PyObj_addGetSetter("container", PyObj_getcontainer, PyObj_setcontainer,
		       "The container this object is in. "
		       "None if on a character or in a room");

    // methods
    PyObj_addMethod("attach", PyObj_attach, METH_VARARGS,
		    "attach a new script to the object");
    PyObj_addMethod("detach", PyObj_detach, METH_VARARGS,
		    "detach an old script from the object, by vnum");
    PyObj_addMethod("isinstance", PyObj_isinstance, METH_VARARGS,
		    "checks to see if the object inherits from the class");
    PyObj_addMethod("istype", PyObj_istype, METH_VARARGS,
		     "checks to see if the object is of the specified type");
    PyObj_addMethod("settype", PyObj_settype, METH_VARARGS,
		    "the object will become of the specified type");
    PyObj_addMethod("edesc", PyObj_edesc, METH_VARARGS,
		    "adds an extra description to the object.");
    PyObj_addMethod("getAuxiliary", PyObj_get_auxiliary, METH_VARARGS,
		    "get's the specified piece of aux data from the obj");

    makePyType(&PyObj_Type, pyobj_getsetters, pyobj_methods);
    deleteListWith(pyobj_getsetters, free); pyobj_getsetters = NULL;
    deleteListWith(pyobj_methods,    free); pyobj_methods    = NULL;

    // make sure the obj class is ready to be made
    if (PyType_Ready(&PyObj_Type) < 0)
        return;

    // make the obj module
    m = Py_InitModule3("obj", obj_module_methods,
                       "The object module, for all object-related MUD stuff.");

    // make sure the obj module parsed OK
    if (m == NULL)
      return;

    // add the obj class to the obj module
    PyTypeObject *type = &PyObj_Type;
    Py_INCREF(&PyObj_Type);
    PyModule_AddObject(m, "Obj", (PyObject *)type);
}


int PyObj_Check(PyObject *value) {
  return PyObject_TypeCheck(value, &PyObj_Type);
}

int PyObj_AsUid(PyObject *obj) {
  return ((PyObj *)obj)->uid;
}

OBJ_DATA *PyObj_AsObj(PyObject *obj) {
  return propertyTableGet(obj_table, PyObj_AsUid(obj));
}

PyObject *
newPyObj(OBJ_DATA *obj) {
  PyObj *py_obj = (PyObj *)PyObj_new(&PyObj_Type, NULL, NULL);
  py_obj->uid = objGetUID(obj);
  return (PyObject *)py_obj;
}