nakedmudv3.6/
nakedmudv3.6/lib/
nakedmudv3.6/lib/help/A/
nakedmudv3.6/lib/help/B/
nakedmudv3.6/lib/help/C/
nakedmudv3.6/lib/help/D/
nakedmudv3.6/lib/help/G/
nakedmudv3.6/lib/help/H/
nakedmudv3.6/lib/help/J/
nakedmudv3.6/lib/help/L/
nakedmudv3.6/lib/help/M/
nakedmudv3.6/lib/help/O/
nakedmudv3.6/lib/help/P/
nakedmudv3.6/lib/help/R/
nakedmudv3.6/lib/help/S/
nakedmudv3.6/lib/help/W/
nakedmudv3.6/lib/logs/
nakedmudv3.6/lib/misc/
nakedmudv3.6/lib/players/
nakedmudv3.6/lib/txt/
nakedmudv3.6/lib/world/
nakedmudv3.6/lib/world/examples/
nakedmudv3.6/lib/world/examples/mproto/
nakedmudv3.6/lib/world/examples/oproto/
nakedmudv3.6/lib/world/examples/reset/
nakedmudv3.6/lib/world/examples/rproto/
nakedmudv3.6/lib/world/examples/trigger/
nakedmudv3.6/lib/world/limbo/
nakedmudv3.6/lib/world/limbo/room/
nakedmudv3.6/lib/world/limbo/rproto/
nakedmudv3.6/src/alias/
nakedmudv3.6/src/dyn_vars/
nakedmudv3.6/src/editor/
nakedmudv3.6/src/example_module/
nakedmudv3.6/src/help2/
nakedmudv3.6/src/set_val/
nakedmudv3.6/src/socials/
nakedmudv3.6/src/time/
//*****************************************************************************
//
// pyevent.c
//
// pyevent gives Python access to NakedMud's event handler in a limited form.
// Unlike normal events which can have owners of any sort, python events can
// only have owners that are characters, objects, or rooms. Other than that,
// python events are identical to normal events.
//
//*****************************************************************************

#include <Python.h>

#include "../mud.h"
#include "../event.h"

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



//*****************************************************************************
// local functions
//*****************************************************************************
void PyEvent_on_complete(void *owner, PyObject *tuple, const char *arg) {
  PyObject *PyOwner = NULL;
  PyObject   *efunc = NULL;
  PyObject   *edata = NULL;
  char       *otype = NULL;

  // make sure we parse everything before we call the function
  if(PyArg_ParseTuple(tuple, "sOO", &otype, &efunc, &edata)) {
    if(!strcasecmp(otype, "char"))
      PyOwner = charGetPyFormBorrowed(owner);
    else if(!strcasecmp(otype, "room"))
      PyOwner = roomGetPyFormBorrowed(owner);
    else if(!strcasecmp(otype, "obj"))
      PyOwner = objGetPyFormBorrowed(owner);
    else
      PyOwner = Py_None;

    PyObject *ret = PyObject_CallFunction(efunc, "OOs", PyOwner, edata, arg);
    Py_XDECREF(ret);
  }

  // decrease the reference on our function and data
  Py_XDECREF(tuple);
}



//*****************************************************************************
// implementation of our methods and method table
//*****************************************************************************

//
// no point in reinventing the wheel; start_event and start_update both
// need to be handled exactly the same, so here's a function to do just that
PyObject *PyEvent_start(PyObject *self, PyObject *args, void *func) {
  void (* start_func)(void *, int, void *, void *, void *, const char *) = func;
  PyObject *PyOwner = NULL;    // the python representation of our owner
  PyObject   *efunc = NULL;    // the event function
  PyObject   *edata = Py_None; // the event data
  char         *arg = NULL;    // the arg we will be supplying to the function
  double      delay = 0;       // how long the event delay is (in seconds)
  void       *owner = NULL;    // actual owner supplied to the event handler
  char    otype[20];           // is the owner a char, room, obj, or None?

  // try to parse all of our values
  if(!PyArg_ParseTuple(args, "OdO|Os", &PyOwner, &delay, &efunc, &edata, &arg)){
    PyErr_Format(PyExc_TypeError, 
		 "Invalid arguments provided to event handler");
    return NULL;
  }

  // make sure our event is a function
  if(!PyFunction_Check(efunc)) {
    PyErr_Format(PyExc_TypeError,
		 "The event handler supplied must be a python function");
    return NULL;
  }

  // figure out what type of data our owner is
  if(PyOwner == Py_None) {
    owner = Py_None;
    sprintf(otype, "none");
  }
  else if(PyChar_Check(PyOwner)) {
    owner = PyChar_AsChar(PyOwner);
    sprintf(otype, "char");
  }
  else if(PyRoom_Check(PyOwner)) {
    owner = PyRoom_AsRoom(PyOwner);
    sprintf(otype, "room");
  }
  else if(PyObj_Check(PyOwner)) {
    owner = PyObj_AsObj(PyOwner);
    sprintf(otype, "obj");
  }
  // invalid type
  else {
    PyErr_Format(PyExc_TypeError,
		 "An event owner must be a room, char, obj, or none");
    return NULL;
  }

  // make sure the owner exists
  if(owner == NULL) {
    PyErr_Format(PyExc_StandardError, "Owner supplied does not exist in game");
    return NULL;
  }
  
  // now, queue up the action
  start_func(owner, (int)(delay SECONDS), PyEvent_on_complete, NULL, 
	     Py_BuildValue("sOO", otype, efunc, edata), arg);

  // everything seems ok. exit normally
  return Py_BuildValue("i", 1);
}


//
// start a new event
PyObject *PyEvent_start_event(PyObject *self, PyObject *args) {
  return PyEvent_start(self, args, start_event);
}


//
// start a new update (event that re-queues itself after completion)
PyObject *PyEvent_start_update(PyObject *self, PyObject *args) {
  PyErr_Format(PyExc_StandardError, "start_update is deprecated. Use start_event.");
  return NULL;
  /* return PyEvent_start(self, args, start_update); */
}

//
// interrupt an event involving the given room, object, or mobile
PyObject *PyEvent_interrupt_event(PyObject *self, PyObject *args) {
  PyObject *PyOwner = NULL; // the python representation of our owner

  // parse our owner
  if(!PyArg_ParseTuple(args, "O", &PyOwner)) {
    PyErr_Format(PyExc_TypeError,
		 "A target must be specified for interrupting events.");
    return NULL;
  }

  // check the possibilities
  if(PyOwner == Py_None)
    interrupt_events_involving(NULL);
  else if(PyChar_Check(PyOwner))
    interrupt_events_involving(PyChar_AsChar(PyOwner));
  else if(PyRoom_Check(PyOwner))
    interrupt_events_involving(PyRoom_AsRoom(PyOwner));
  else if(PyObj_Check(PyOwner))
    interrupt_events_involving(PyObj_AsObj(PyOwner));

  // everything ok
  return Py_BuildValue("i", 1);
}


//
// 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_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."},
  {"interrupt_events_involving",  PyEvent_interrupt_event, METH_VARARGS,
   "Interrupt all of the events involving the given object, room, or char."},
  {NULL, NULL, 0, NULL}  /* Sentinel */
};



//*****************************************************************************
// implementation of pyevent.h
//*****************************************************************************
PyMODINIT_FUNC init_PyEvent(void) {
  Py_InitModule3("event", event_module_methods, "The mud's event handler.");
}