nakedmudv3.0/
nakedmudv3.0/lib/
nakedmudv3.0/lib/logs/
nakedmudv3.0/lib/misc/
nakedmudv3.0/lib/players/
nakedmudv3.0/lib/pymodules/
nakedmudv3.0/lib/txt/
nakedmudv3.0/lib/world/
nakedmudv3.0/lib/world/examples/
nakedmudv3.0/lib/world/examples/mproto/
nakedmudv3.0/lib/world/examples/oproto/
nakedmudv3.0/lib/world/examples/reset/
nakedmudv3.0/lib/world/examples/rproto/
nakedmudv3.0/lib/world/examples/trigger/
nakedmudv3.0/lib/world/limbo/
nakedmudv3.0/lib/world/limbo/rproto/
nakedmudv3.0/src/alias/
nakedmudv3.0/src/char_vars/
nakedmudv3.0/src/editor/
nakedmudv3.0/src/example_module/
nakedmudv3.0/src/help/
nakedmudv3.0/src/set_val/
nakedmudv3.0/src/socials/
nakedmudv3.0/src/time/
//*****************************************************************************
//
// pymud.h
//
// a python module that provides some useful utility functions for interacting
// with the MUD. Includes stuff like global variables, messaging functions,
// and a whole bunch of other stuff.
//
// WORK FOR FUTURE: Our use of Py_INCREF is probably creating a
//                  memory leak somewhere.
//
//*****************************************************************************

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

#include "../mud.h"
#include "../utils.h"
#include "../character.h"
#include "../inform.h"
#include "../handler.h"

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



//*****************************************************************************
// local variables and functions
//*****************************************************************************
// global variables we have set.
PyObject  *globals = NULL;



//*****************************************************************************
//
// GLOBAL VARIABLES
//
// the following functions allow scriptors to store/access global variables.
// globals are stored in a python map, that maps two python objects together.
// the functions used to interact with globals are:
//   get_global(key)
//   set_global(key, val)
//   erase_global(key)
//
//*****************************************************************************
PyObject *mud_get_global(PyObject *self, PyObject *args) {
  PyObject *key = NULL;

  // get the key
  if (!PyArg_ParseTuple(args, "O", &key)) {
    PyErr_Format(PyExc_TypeError, 
		 "Could not retrieve global variable - no key provided");
    return NULL;
  }

  PyObject *val = PyDict_GetItem(globals, key);
  if(val == NULL)
    val = Py_None;
  
  Py_INCREF(val);
  return val;
}

PyObject *mud_set_global(PyObject *self, PyObject *args) {
  PyObject *key = NULL, *val = NULL;

  if (!PyArg_ParseTuple(args, "OO", &key, &val)) {
    PyErr_Format(PyExc_TypeError, 
		 "Could not set global variable - need key and value");
    return NULL;
  }

  PyDict_SetItem(globals, key, val);
  return Py_BuildValue("i", 1);
}


PyObject *mud_erase_global(PyObject *self, PyObject *args) {
  PyObject *key = NULL;

  if (!PyArg_ParseTuple(args, "O", &key)) {
    PyErr_Format(PyExc_TypeError, 
		 "Could not erase global variable - need key");
    return NULL;
  }

  PyDict_SetItem(globals, key, Py_None);
  return Py_BuildValue("i", 1);
}


//
// add a new command to the mud, via a python script or module. Takes in a
// command name, a sort_by command, the function, a minimum and maximum 
// position in the form of strings, a level, and boolean values for whether the
// command can be performed by mobiles, and whether it interrupts actions.
PyObject *mud_add_cmd(PyObject *self, PyObject *args) {
  PyObject *func = NULL;
  char *name  = NULL, *sort_by = NULL, *min_pos = NULL, *max_pos = NULL,
       *group = NULL;
  bool mob_ok = FALSE, interrupts = FALSE;
  int min_pos_num, max_pos_num;

  // parse all of the values
  if (!PyArg_ParseTuple(args, "szOsssbb", &name, &sort_by, &func,
  			&min_pos, &max_pos, &group, &mob_ok, &interrupts)) {
    PyErr_Format(PyExc_TypeError, 
		 "Could not add new command. Improper arguments supplied");
    return NULL;
  }

  // get our positions
  min_pos_num = posGetNum(min_pos);
  max_pos_num = posGetNum(max_pos);
  if(min_pos_num == POS_NONE || max_pos_num == POS_NONE) {
    PyErr_Format(PyExc_TypeError, 
		 "Could not add new command. Invalid position names.");
    return NULL;
  }

  // add the command to the game
  add_py_cmd(name, sort_by, func, min_pos_num, max_pos_num,
	     group, mob_ok, interrupts);
  return Py_None;
}


//
// format a string to be into a typical description style
PyObject *mud_format_string(PyObject *self, PyObject *args) {
  char *string = NULL;

  // parse all of the values
  if (!PyArg_ParseTuple(args, "s", &string)) {
    PyErr_Format(PyExc_TypeError, 
		 "Can not format non-string values.");
    return NULL;
  }

  // dup the string so we can work with it and not intrude on the PyString data
  BUFFER *buf = newBuffer(MAX_BUFFER);
  bufferCat(buf, string);
  bufferFormat(buf, SCREEN_WIDTH, PARA_INDENT);
  PyObject *ret = Py_BuildValue("s", bufferString(buf));
  deleteBuffer(buf);
  return ret;
}

//
// a wrapper around NakedMud's generic_find() function
PyObject *mud_generic_find(PyObject *self, PyObject *args) {
  PyObject *py_looker = Py_None;     CHAR_DATA *looker = NULL;
  char      *type_str = NULL;        bitvector_t  type = 0; 
  char     *scope_str = NULL;        bitvector_t scope = 0;
  char           *arg = NULL;
  bool         all_ok = TRUE;

  // parse the arguments
  if(!PyArg_ParseTuple(args, "Osss|b", &py_looker, &arg, &type_str, &scope_str,
		       &all_ok)) {
    PyErr_Format(PyExc_TypeError,
		 "Invalid arguments supplied to mud.generic_find()");
    return NULL;
  }

  // convert the looker
  if(py_looker != Py_None) {
    if(!PyChar_Check(py_looker) || (looker = PyChar_AsChar(py_looker)) == NULL){
      PyErr_Format(PyExc_TypeError, 
		   "First argument must be an existent character or None!");
      return NULL;
    }
  }

  // convert the scope
  if(is_keyword(scope_str, "room", FALSE))
    SET_BIT(scope, FIND_SCOPE_ROOM);
  if(is_keyword(scope_str, "inv", FALSE))
    SET_BIT(scope, FIND_SCOPE_INV);
  if(is_keyword(scope_str, "worn", FALSE))
    SET_BIT(scope, FIND_SCOPE_WORN);
  if(is_keyword(scope_str, "world", FALSE))
    SET_BIT(scope, FIND_SCOPE_WORLD);
  if(is_keyword(scope_str, "visible", FALSE))
    SET_BIT(scope, FIND_SCOPE_VISIBLE);
  if(is_keyword(scope_str, "immediate", FALSE))
    SET_BIT(scope, FIND_SCOPE_IMMEDIATE);
  if(is_keyword(scope_str, "all", FALSE))
    SET_BIT(scope, FIND_SCOPE_ALL);

  // convert the types
  if(is_keyword(type_str, "obj", FALSE))
    SET_BIT(type, FIND_TYPE_OBJ);
  if(is_keyword(type_str, "char", FALSE))
    SET_BIT(type, FIND_TYPE_CHAR);
  if(is_keyword(type_str, "in", FALSE))
    SET_BIT(type, FIND_TYPE_IN_OBJ);

  // do the search
  int found_type = FOUND_NONE;
  void    *found = generic_find(looker, arg, type, scope, all_ok, &found_type);

  if(found_type == FOUND_CHAR)
    return Py_BuildValue("Os", newPyChar(found), "char");
  else if(found_type == FOUND_OBJ)
    return Py_BuildValue("Os", newPyObj(found), "obj");
  else if(found_type == FOUND_IN_OBJ)
    return Py_BuildValue("Os", newPyObj(found), "in");
  // now it gets a bit more tricky... we have to see what other bit was set
  else if(found_type == FOUND_LIST) {
    PyObject         *list = PyList_New(0);
    LIST_ITERATOR *found_i = newListIterator(found);
    void        *one_found = NULL;
    if(IS_SET(type, FIND_TYPE_CHAR)) {
      ITERATE_LIST(one_found, found_i)
	PyList_Append(list, newPyChar(one_found));
    }
    else if(IS_SET(type, FIND_TYPE_OBJ | FIND_TYPE_IN_OBJ)) {
      ITERATE_LIST(one_found, found_i)
	PyList_Append(list, newPyChar(one_found));
    }
    deleteListIterator(found_i);
    deleteList(found);
    return Py_BuildValue("Os", list, "list");
  }

  // nothing was found...
  return Py_BuildValue("Os", Py_None, Py_None);
}


//
// execute message() from inform.h
PyObject *mud_message(PyObject *self, PyObject *args) {
  // the python/C representations of the various variables that message() needs
  PyObject    *pych = NULL;     CHAR_DATA     *ch = NULL;
  PyObject  *pyvict = NULL;     CHAR_DATA   *vict = NULL;
  PyObject   *pyobj = NULL;     OBJ_DATA     *obj = NULL;
  PyObject  *pyvobj = NULL;     OBJ_DATA    *vobj = NULL;
  char     *pyrange = NULL;     bitvector_t range = 0;
  char        *mssg = NULL;
  int    hide_nosee = 0;

  // parse all of the arguments
  if(!PyArg_ParseTuple(args, "OOOObss", &pych, &pyvict, &pyobj, &pyvobj,
		       &hide_nosee, &pyrange, &mssg)) {
    PyErr_Format(PyExc_TypeError,"Invalid arguments supplied to mud.message()");
    return NULL;
  }

  // convert the character
  if(pych != Py_None) {
    if(!PyChar_Check(pych) || (ch = PyChar_AsChar(pych)) == NULL) {
      PyErr_Format(PyExc_TypeError, 
		   "First argument must be an existent character or None!");
      return NULL;
    }
  }

  // convert the victim
  if(pyvict != Py_None) {
    if(!PyChar_Check(pyvict) || (vict = PyChar_AsChar(pyvict)) == NULL) {
      PyErr_Format(PyExc_TypeError, 
		   "Second argument must be an existent character or None!");
      return NULL;
    }
  }

  // convert the object
  if(pyobj != Py_None) {
    if(!PyObj_Check(pyobj) || (obj = PyObj_AsObj(pyobj)) == NULL) {
      PyErr_Format(PyExc_TypeError, 
		   "Third argument must be an existent object or None!");
      return NULL;
    }
  }

  // convert the target object
  if(pyvobj != Py_None) {
    if(!PyObj_Check(pyvobj) || (vobj = PyObj_AsObj(pyvobj)) == NULL) {
      PyErr_Format(PyExc_TypeError, 
		   "Fourth argument must be an existent object or None!");
      return NULL;
    }
  }

  // check all of our keywords: char, vict, room
  if(is_keyword(pyrange, "to_char", FALSE))
    SET_BIT(range, TO_CHAR);
  if(is_keyword(pyrange, "to_vict", FALSE))
    SET_BIT(range, TO_VICT);
  if(is_keyword(pyrange, "to_room", FALSE))
    SET_BIT(range, TO_ROOM);

  // finally, send out the message
  message(ch, vict, obj, vobj, hide_nosee, range, mssg);
  return Py_BuildValue("i", 1);
}


//
// extracts an mob or object from the game
PyObject *mud_extract(PyObject *self, PyObject *args) {
  PyObject *thing = NULL;

  // parse the value
  if (!PyArg_ParseTuple(args, "O", &thing)) {
    PyErr_Format(PyExc_TypeError, 
		 "extract must be provided with an object or mob to extract!.");
    return NULL;
  }

  // check its type
  if(PyChar_Check(thing)) {
    CHAR_DATA *ch = PyChar_AsChar(thing);
    if(ch != NULL)
      extract_mobile(ch);
    else {
      PyErr_Format(PyExc_StandardError,
		   "Tried to extract nonexistent character!");
      return NULL;
    }
  }
  else if(PyObj_Check(thing)) {
    OBJ_DATA *obj = PyObj_AsObj(thing);
    if(obj != NULL)
      extract_obj(obj);
    else {
      PyErr_Format(PyExc_StandardError,
		   "Tried to extract nonexistent object!");
      return NULL;
    }
  }
  
  // success
  return Py_BuildValue("i", 1);
}

//
// functional form of if/then/else
PyObject *mud_ite(PyObject *self, PyObject *args) {
  PyObject *condition = NULL;
  PyObject  *true_act = NULL;
  PyObject *false_act = Py_None;

  if (!PyArg_ParseTuple(args, "OO|O", &condition, &true_act, &false_act)) {
    PyErr_Format(PyExc_TypeError, "ite must be specified 2 and an optional 3rd "
		 "arg");
    return NULL;
  }

  // check to see if our condition is true
  if( (PyInt_Check(condition)    && PyInt_AsLong(condition) != 0) ||
      (PyString_Check(condition) && strlen(PyString_AsString(condition)) > 0))
    return true_act;
  else
    return false_act;
}



//*****************************************************************************
// MUD module
//*****************************************************************************
PyMethodDef mud_module_methods[] = {
    {"get_global",  mud_get_global, METH_VARARGS,
     "Get the value of a global variable."},
    {"set_global",  mud_set_global, METH_VARARGS,
     "Set the value of a global variable."},
    {"erase_global",  mud_erase_global, METH_VARARGS,
     "Erase the value of a global variable."},
    {"add_cmd", mud_add_cmd, METH_VARARGS,
     "Add a new command to the game."},
    {"message", mud_message, METH_VARARGS,
     "plugs into the message() function from inform.h" },
    {"format_string", mud_format_string, METH_VARARGS,
     "format a string to be 80 chars wide and indented. Like a desc."},
    {"generic_find",  mud_generic_find, METH_VARARGS,
     "Python wrapper around the generic_find() function"},
    {"extract", mud_extract, METH_VARARGS,
    "extracts an object or character from the game. This method is dangerous, "
    "since the object may still be needed in whichever function called the "
    "script that activated this method" },
    {"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." },
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


PyMODINIT_FUNC
init_PyMud(void) {
  PyObject *m;

  globals = PyDict_New();
  Py_INCREF(globals);

  m = Py_InitModule3("mud", mud_module_methods,
		     "The mud module, for all MUD misc mud utils.");
}