//*****************************************************************************
//
// 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 "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;
// make sure we parse everything before we call the function
if(PyArg_ParseTuple(tuple, "OOO", &PyOwner, &efunc, &edata)) {
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
// 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;
else if(PyChar_Check(PyOwner))
owner = PyChar_AsChar(PyOwner);
else if(PyRoom_Check(PyOwner))
owner = PyRoom_AsRoom(PyOwner);
else if(PyObj_Check(PyOwner))
owner = PyObj_AsObj(PyOwner);
// 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("OOO", PyOwner, 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.");
}