server-1.12/plugins/cfpython/cfpython.c

1551 lines
52 KiB
C

/*****************************************************************************/
/* CFPython - A Python module for Crossfire RPG. */
/*****************************************************************************/
/* This is the third version of the Crossfire Scripting Engine. */
/* The first version used Guile. It was directly integrated in the server */
/* code, but since Guile wasn't perceived as an easy-to-learn, easy-to-use */
/* language by many, it was dropped in favor of Python. */
/* The second version, CFPython 1.0, was included as a plugin and provided */
/* just about the same level of functionality the current version has. But */
/* it used a rather counter-intuitive, procedural way of presenting things. */
/* */
/* CFPython 2.0 aims at correcting many of the design flaws crippling the */
/* older version. It is also the first plugin to be implemented using the */
/* new interface, that doesn't need awkward stuff like the horrible CFParm */
/* structure. For the Python writer, things should probably be easier and */
/* lead to more readable code: instead of writing "CFPython.getObjectXPos(ob)*/
/* he/she now can simply write "ob.X". */
/* */
/*****************************************************************************/
/* Please note that it is still very beta - some of the functions may not */
/* work as expected and could even cause the server to crash. */
/*****************************************************************************/
/* Version history: */
/* 0.1 "Ophiuchus" - Initial Alpha release */
/* 0.5 "Stalingrad" - Message length overflow corrected. */
/* 0.6 "Kharkov" - Message and Write correctly redefined. */
/* 0.7 "Koursk" - Setting informations implemented. */
/* 1.0a "Petersburg" - Last "old-fashioned" version, never submitted to CVS.*/
/* 2.0 "Arkangelsk" - First release of the 2.x series. */
/*****************************************************************************/
/* Version: 2.0beta8 (also known as "Alexander") */
/* Contact: yann.chachkoff@myrealbox.com */
/*****************************************************************************/
/* That code is placed under the GNU General Public Licence (GPL) */
/* (C)2001-2005 by Chachkoff Yann (Feel free to deliver your complaints) */
/*****************************************************************************/
/* CrossFire, A Multiplayer game for X-windows */
/* */
/* Copyright (C) 2000 Mark Wedel */
/* Copyright (C) 1992 Frank Tore Johansen */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* */
/*****************************************************************************/
/* First let's include the header file needed */
#include <cfpython.h>
#include <stdarg.h>
#include <node.h>
#define PYTHON_DEBUG /* give us some general infos out */
#define PYTHON_CACHE_SIZE 16 /* number of python scripts to store the bytecode of at a time */
typedef struct {
sstring file;
PyCodeObject *code;
time_t cached_time, used_time;
} pycode_cache_entry;
static PythonCmd CustomCommand[NR_CUSTOM_CMD];
static pycode_cache_entry pycode_cache[PYTHON_CACHE_SIZE];
static void set_exception(const char *fmt, ...);
static PyObject *createCFObject(PyObject *self, PyObject *args);
static PyObject *createCFObjectByName(PyObject *self, PyObject *args);
static PyObject *getCFPythonVersion(PyObject *self, PyObject *args);
static PyObject *getReturnValue(PyObject *self, PyObject *args);
static PyObject *setReturnValue(PyObject *self, PyObject *args);
static PyObject *matchString(PyObject *self, PyObject *args);
static PyObject *findPlayer(PyObject *self, PyObject *args);
static PyObject *readyMap(PyObject *self, PyObject *args);
static PyObject *createMap(PyObject *self, PyObject *args);
static PyObject *getMapDirectory(PyObject *self, PyObject *args);
static PyObject *getUniqueDirectory(PyObject *self, PyObject *args);
static PyObject *getTempDirectory(PyObject *self, PyObject *args);
static PyObject *getConfigDirectory(PyObject *self, PyObject *args);
static PyObject *getLocalDirectory(PyObject *self, PyObject *args);
static PyObject *getPlayerDirectory(PyObject *self, PyObject *args);
static PyObject *getDataDirectory(PyObject *self, PyObject *args);
static PyObject *getWhoAmI(PyObject *self, PyObject *args);
static PyObject *getWhoIsActivator(PyObject *self, PyObject *args);
static PyObject *getWhoIsThird(PyObject *self, PyObject *args);
static PyObject *getWhatIsMessage(PyObject *self, PyObject *args);
static PyObject *getScriptName(PyObject *self, PyObject *args);
static PyObject *getScriptParameters(PyObject *self, PyObject *args);
static PyObject *getEvent(PyObject *self, PyObject *args);
static PyObject *getPrivateDictionary(PyObject *self, PyObject *args);
static PyObject *getSharedDictionary(PyObject *self, PyObject *args);
static PyObject *getArchetypes(PyObject *self, PyObject *args);
static PyObject *getPlayers(PyObject *self, PyObject *args);
static PyObject *getMaps(PyObject *self, PyObject *args);
static PyObject *getParties(PyObject *self, PyObject *args);
static PyObject *getRegions(PyObject *self, PyObject *args);
static PyObject *getFriendlyList(PyObject *self, PyObject *args);
static PyObject *registerCommand(PyObject *self, PyObject *args);
static PyObject *registerGEvent(PyObject *self, PyObject *args);
static PyObject *unregisterGEvent(PyObject *self, PyObject *args);
static PyObject *CFPythonError;
static PyObject *getTime(PyObject *self, PyObject *args);
static PyObject *destroyTimer(PyObject *self, PyObject *args);
static PyObject *getMapHasBeenLoaded(PyObject *self, PyObject *args);
static PyObject *findAnimation(PyObject *self, PyObject *args);
static PyObject *log_message(PyObject *self, PyObject *args);
static PyObject *findFace(PyObject *self, PyObject *args);
static PyObject *getSeasonName(PyObject *self, PyObject *args);
static PyObject *getMonthName(PyObject *self, PyObject *args);
static PyObject *getWeekdayName(PyObject *self, PyObject *args);
static PyObject *getPeriodofdayName(PyObject *self, PyObject *args);
/** Set up an Python exception object. */
static void set_exception(const char *fmt, ...) {
char buf[1024];
va_list arg;
va_start(arg, fmt);
vsnprintf(buf, sizeof(buf), fmt, arg);
va_end(arg);
PyErr_SetString(PyExc_ValueError, buf);
}
static PyMethodDef CFPythonMethods[] = {
{ "WhoAmI", getWhoAmI, METH_NOARGS, NULL },
{ "WhoIsActivator", getWhoIsActivator, METH_NOARGS, NULL },
{ "WhoIsOther", getWhoIsThird, METH_NOARGS, NULL },
{ "WhatIsMessage", getWhatIsMessage, METH_NOARGS, NULL },
{ "ScriptName", getScriptName, METH_NOARGS, NULL },
{ "ScriptParameters", getScriptParameters, METH_NOARGS, NULL },
{ "WhatIsEvent", getEvent, METH_NOARGS, NULL },
{ "MapDirectory", getMapDirectory, METH_NOARGS, NULL },
{ "UniqueDirectory", getUniqueDirectory, METH_NOARGS, NULL },
{ "TempDirectory", getTempDirectory, METH_NOARGS, NULL },
{ "ConfigDirectory", getConfigDirectory, METH_NOARGS, NULL },
{ "LocalDirectory", getLocalDirectory, METH_NOARGS, NULL },
{ "PlayerDirectory", getPlayerDirectory, METH_NOARGS, NULL },
{ "DataDirectory", getDataDirectory, METH_NOARGS, NULL },
{ "ReadyMap", readyMap, METH_VARARGS, NULL },
{ "CreateMap", createMap, METH_VARARGS, NULL },
{ "FindPlayer", findPlayer, METH_VARARGS, NULL },
{ "MatchString", matchString, METH_VARARGS, NULL },
{ "GetReturnValue", getReturnValue, METH_NOARGS, NULL },
{ "SetReturnValue", setReturnValue, METH_VARARGS, NULL },
{ "PluginVersion", getCFPythonVersion, METH_NOARGS, NULL },
{ "CreateObject", createCFObject, METH_NOARGS, NULL },
{ "CreateObjectByName", createCFObjectByName, METH_VARARGS, NULL },
{ "GetPrivateDictionary", getPrivateDictionary, METH_NOARGS, NULL },
{ "GetSharedDictionary", getSharedDictionary, METH_NOARGS, NULL },
{ "GetPlayers", getPlayers, METH_NOARGS, NULL },
{ "GetArchetypes", getArchetypes, METH_NOARGS, NULL },
{ "GetMaps", getMaps, METH_NOARGS, NULL },
{ "GetParties", getParties, METH_NOARGS, NULL },
{ "GetRegions", getRegions, METH_NOARGS, NULL },
{ "GetFriendlyList", getFriendlyList, METH_NOARGS, NULL },
{ "RegisterCommand", registerCommand, METH_VARARGS, NULL },
{ "RegisterGlobalEvent", registerGEvent, METH_VARARGS, NULL },
{ "UnregisterGlobalEvent", unregisterGEvent, METH_VARARGS, NULL },
{ "GetTime", getTime, METH_NOARGS, NULL },
{ "DestroyTimer", destroyTimer, METH_VARARGS, NULL },
{ "MapHasBeenLoaded", getMapHasBeenLoaded, METH_VARARGS, NULL },
{ "Log", log_message, METH_VARARGS, NULL },
{ "FindFace", findFace, METH_VARARGS, NULL },
{ "FindAnimation", findAnimation, METH_VARARGS, NULL },
{ "GetSeasonName", getSeasonName, METH_VARARGS, NULL },
{ "GetMonthName", getMonthName, METH_VARARGS, NULL },
{ "GetWeekdayName", getWeekdayName, METH_VARARGS, NULL },
{ "GetPeriodofdayName", getPeriodofdayName, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
CFPContext *context_stack;
CFPContext *current_context;
static int current_command = -999;
static PyObject *shared_data = NULL;
static PyObject *private_data = NULL;
static PyObject *registerGEvent(PyObject *self, PyObject *args) {
int eventcode;
if (!PyArg_ParseTuple(args, "i", &eventcode))
return NULL;
cf_system_register_global_event(eventcode, PLUGIN_NAME, cfpython_globalEventListener);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *unregisterGEvent(PyObject *self, PyObject *args) {
int eventcode;
if (!PyArg_ParseTuple(args, "i", &eventcode))
return NULL;
cf_system_unregister_global_event(EVENT_TELL, PLUGIN_NAME);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *createCFObject(PyObject *self, PyObject *args) {
object *op;
op = cf_create_object();
return Crossfire_Object_wrap(op);
}
static PyObject *createCFObjectByName(PyObject *self, PyObject *args) {
char *obname;
object *op;
if (!PyArg_ParseTuple(args, "s", &obname))
return NULL;
op = cf_create_object_by_name(obname);
return Crossfire_Object_wrap(op);
}
static PyObject *getCFPythonVersion(PyObject *self, PyObject *args) {
int i = 2044;
return Py_BuildValue("i", i);
}
static PyObject *getReturnValue(PyObject *self, PyObject *args) {
return Py_BuildValue("i", current_context->returnvalue);
}
static PyObject *setReturnValue(PyObject *self, PyObject *args) {
int i;
if (!PyArg_ParseTuple(args, "i", &i))
return NULL;
current_context->returnvalue = i;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *matchString(PyObject *self, PyObject *args) {
char *premiere;
char *seconde;
const char *result;
if (!PyArg_ParseTuple(args, "ss", &premiere, &seconde))
return NULL;
result = cf_re_cmp(premiere, seconde);
if (result != NULL)
return Py_BuildValue("i", 1);
else
return Py_BuildValue("i", 0);
}
static PyObject *findPlayer(PyObject *self, PyObject *args) {
player *foundpl;
char *txt;
if (!PyArg_ParseTuple(args, "s", &txt))
return NULL;
foundpl = cf_player_find(txt);
if (foundpl != NULL)
return Py_BuildValue("O", Crossfire_Object_wrap(foundpl->ob));
else {
Py_INCREF(Py_None);
return Py_None;
}
}
static PyObject *readyMap(PyObject *self, PyObject *args) {
char *mapname;
mapstruct *map;
int flags = 0;
if (!PyArg_ParseTuple(args, "s|i", &mapname, &flags))
return NULL;
map = cf_map_get_map(mapname, flags);
return Crossfire_Map_wrap(map);
}
static PyObject *createMap(PyObject *self, PyObject *args) {
int sizex, sizey;
mapstruct *map;
if (!PyArg_ParseTuple(args, "ii", &sizex, &sizey))
return NULL;
map = cf_get_empty_map(sizex, sizey);
return Crossfire_Map_wrap(map);
}
static PyObject *getMapDirectory(PyObject *self, PyObject *args) {
return Py_BuildValue("s", cf_get_directory(0));
}
static PyObject *getUniqueDirectory(PyObject *self, PyObject *args) {
return Py_BuildValue("s", cf_get_directory(1));
}
static PyObject *getTempDirectory(PyObject *self, PyObject *args) {
return Py_BuildValue("s", cf_get_directory(2));
}
static PyObject *getConfigDirectory(PyObject *self, PyObject *args) {
return Py_BuildValue("s", cf_get_directory(3));
}
static PyObject *getLocalDirectory(PyObject *self, PyObject *args) {
return Py_BuildValue("s", cf_get_directory(4));
}
static PyObject *getPlayerDirectory(PyObject *self, PyObject *args) {
return Py_BuildValue("s", cf_get_directory(5));
}
static PyObject *getDataDirectory(PyObject *self, PyObject *args) {
return Py_BuildValue("s", cf_get_directory(6));
}
static PyObject *getWhoAmI(PyObject *self, PyObject *args) {
if (!current_context->who) {
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(current_context->who);
return current_context->who;
}
static PyObject *getWhoIsActivator(PyObject *self, PyObject *args) {
if (!current_context->activator) {
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(current_context->activator);
return current_context->activator;
}
static PyObject *getWhoIsThird(PyObject *self, PyObject *args) {
if (!current_context->third) {
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(current_context->third);
return current_context->third;
}
static PyObject *getWhatIsMessage(PyObject *self, PyObject *args) {
if (current_context->message == NULL)
return Py_BuildValue("");
else
return Py_BuildValue("s", current_context->message);
}
static PyObject *getScriptName(PyObject *self, PyObject *args) {
return Py_BuildValue("s", current_context->script);
}
static PyObject *getScriptParameters(PyObject *self, PyObject *args) {
if (!current_context->options) {
Py_INCREF(Py_None);
return Py_None;
}
return Py_BuildValue("s", current_context->options);
}
static PyObject *getEvent(PyObject *self, PyObject *args) {
if (!current_context->event) {
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(current_context->event);
return current_context->event;
}
static PyObject *getPrivateDictionary(PyObject *self, PyObject *args) {
PyObject *data;
data = PyDict_GetItemString(private_data, current_context->script);
if (!data) {
data = PyDict_New();
PyDict_SetItemString(private_data, current_context->script, data);
Py_DECREF(data);
}
Py_INCREF(data);
return data;
}
static PyObject *getSharedDictionary(PyObject *self, PyObject *args) {
Py_INCREF(shared_data);
return shared_data;
}
static PyObject *getArchetypes(PyObject *self, PyObject *args) {
PyObject *list;
archetype *arch;
list = PyList_New(0);
arch = cf_archetype_get_first();
while (arch) {
PyList_Append(list, Crossfire_Archetype_wrap(arch));
arch = cf_archetype_get_next(arch);
}
return list;
}
static PyObject *getPlayers(PyObject *self, PyObject *args) {
PyObject *list;
object *pl;
list = PyList_New(0);
pl = cf_object_get_object_property(NULL, CFAPI_PLAYER_PROP_NEXT);
while (pl) {
PyList_Append(list, Crossfire_Object_wrap(pl));
pl = cf_object_get_object_property(pl, CFAPI_PLAYER_PROP_NEXT);
}
return list;
}
static PyObject *getMaps(PyObject *self, PyObject *args) {
PyObject *list;
mapstruct *map;
list = PyList_New(0);
map = cf_map_get_first();
while (map) {
PyList_Append(list, Crossfire_Map_wrap(map));
map = cf_map_get_map_property(map, CFAPI_MAP_PROP_NEXT);
}
return list;
}
static PyObject *getParties(PyObject *self, PyObject *args) {
PyObject *list;
partylist *party;
list = PyList_New(0);
party = cf_party_get_first();
while (party) {
PyList_Append(list, Crossfire_Party_wrap(party));
party = cf_party_get_next(party);
}
return list;
}
static PyObject *getRegions(PyObject *self, PyObject *args) {
PyObject *list;
region *reg;
list = PyList_New(0);
reg = cf_region_get_first();
while (reg) {
PyList_Append(list, Crossfire_Region_wrap(reg));
reg = cf_region_get_next(reg);
}
return list;
}
static PyObject *getFriendlyList(PyObject *self, PyObject *args) {
PyObject *list;
object *ob;
list = PyList_New(0);
ob = cf_friendlylist_get_first();
while (ob) {
PyList_Append(list, Crossfire_Object_wrap(ob));
ob = cf_friendlylist_get_next(ob);
}
return list;
}
static PyObject *registerCommand(PyObject *self, PyObject *args) {
char *cmdname;
char *scriptname;
double cmdspeed;
int i;
if (!PyArg_ParseTuple(args, "ssd", &cmdname, &scriptname, &cmdspeed))
return NULL;
if (cmdspeed < 0) {
set_exception("speed must not be negative");
return NULL;
}
for (i = 0; i < NR_CUSTOM_CMD; i++) {
if (CustomCommand[i].name != NULL) {
if (!strcmp(CustomCommand[i].name, cmdname)) {
set_exception("command '%s' is already registered", cmdname);
return NULL;
}
}
}
for (i = 0; i < NR_CUSTOM_CMD; i++) {
if (CustomCommand[i].name == NULL) {
CustomCommand[i].name = cf_strdup_local(cmdname);
CustomCommand[i].script = cf_strdup_local(scriptname);
CustomCommand[i].speed = cmdspeed;
break;
}
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *getTime(PyObject *self, PyObject *args) {
PyObject *list;
timeofday_t tod;
cf_get_time(&tod);
list = PyList_New(0);
PyList_Append(list, Py_BuildValue("i", tod.year));
PyList_Append(list, Py_BuildValue("i", tod.month));
PyList_Append(list, Py_BuildValue("i", tod.day));
PyList_Append(list, Py_BuildValue("i", tod.hour));
PyList_Append(list, Py_BuildValue("i", tod.minute));
PyList_Append(list, Py_BuildValue("i", tod.dayofweek));
PyList_Append(list, Py_BuildValue("i", tod.weekofmonth));
PyList_Append(list, Py_BuildValue("i", tod.season));
PyList_Append(list, Py_BuildValue("i", tod.periodofday));
return list;
}
static PyObject *destroyTimer(PyObject *self, PyObject *args) {
int id;
if (!PyArg_ParseTuple(args, "i", &id))
return NULL;
return Py_BuildValue("i", cf_timer_destroy(id));
}
static PyObject *getMapHasBeenLoaded(PyObject *self, PyObject *args) {
char *name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
return Crossfire_Map_wrap(cf_map_has_been_loaded(name));
}
static PyObject *findFace(PyObject *self, PyObject *args) {
char *name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
return Py_BuildValue("i", cf_find_face(name, 0));
}
static PyObject *log_message(PyObject *self, PyObject *args) {
LogLevel level;
int intLevel;
char *message;
if (!PyArg_ParseTuple(args, "is", &intLevel, &message))
return NULL;
switch (intLevel) {
case llevError:
level = llevError;
break;
case llevInfo:
level = llevInfo;
break;
case llevDebug:
level = llevDebug;
break;
case llevMonster:
level = llevMonster;
break;
default:
return NULL;
}
if ((message != NULL) && (message[strlen(message)] == '\n'))
cf_log(level, "CFPython: %s", message);
else
cf_log(level, "CFPython: %s\n", message);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *findAnimation(PyObject *self, PyObject *args) {
char *name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
return Py_BuildValue("i", cf_find_animation(name));
}
static PyObject *getSeasonName(PyObject *self, PyObject *args) {
int i;
if (!PyArg_ParseTuple(args, "i", &i))
return NULL;
return Py_BuildValue("s", cf_get_season_name(i));
}
static PyObject *getMonthName(PyObject *self, PyObject *args) {
int i;
if (!PyArg_ParseTuple(args, "i", &i))
return NULL;
return Py_BuildValue("s", cf_get_month_name(i));
}
static PyObject *getWeekdayName(PyObject *self, PyObject *args) {
int i;
if (!PyArg_ParseTuple(args, "i", &i))
return NULL;
return Py_BuildValue("s", cf_get_weekday_name(i));
}
static PyObject *getPeriodofdayName(PyObject *self, PyObject *args) {
int i;
if (!PyArg_ParseTuple(args, "i", &i))
return NULL;
return Py_BuildValue("s", cf_get_periodofday_name(i));
}
static void initContextStack(void) {
current_context = NULL;
context_stack = NULL;
}
static void pushContext(CFPContext *context) {
if (current_context == NULL) {
context_stack = context;
context->down = NULL;
} else {
context->down = current_context;
}
current_context = context;
}
static CFPContext *popContext(void) {
CFPContext *oldcontext;
if (current_context != NULL) {
oldcontext = current_context;
current_context = current_context->down;
return oldcontext;
}
else
return NULL;
}
static void freeContext(CFPContext *context) {
Py_XDECREF(context->event);
Py_XDECREF(context->third);
Py_XDECREF(context->who);
Py_XDECREF(context->activator);
free(context);
}
/** Outputs the compiled bytecode for a given python file, using in-memory caching of bytecode */
static PyCodeObject *compilePython(char *filename) {
PyObject *scriptfile;
sstring sh_path;
struct stat stat_buf;
struct _node *n;
int i;
pycode_cache_entry *replace = NULL, *run = NULL;
if (!(scriptfile = PyFile_FromString(filename, "r"))) {
cf_log(llevDebug, "cfpython - The Script file %s can't be opened\n", filename);
return NULL;
}
if (stat(filename, &stat_buf)) {
cf_log(llevDebug, "cfpython - The Script file %s can't be stat:ed\n", filename);
if (scriptfile) {
Py_DECREF(scriptfile);
}
return NULL;
}
sh_path = cf_add_string(filename);
/* Search through cache. Three cases:
* 1) script in cache, but older than file -> replace cached
* 2) script in cache and up to date -> use cached
* 3) script not in cache, cache not full -> add to end of cache
* 4) script not in cache, cache full -> replace least recently used
*/
for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
if (pycode_cache[i].file == NULL) { /* script not in cache, cache not full */
replace = &pycode_cache[i]; /* add to end of cache */
break;
} else if (pycode_cache[i].file == sh_path) {
/* script in cache */
if (pycode_cache[i].code == NULL || (pycode_cache[i].cached_time < stat_buf.st_mtime)) {
/* cache older than file, replace cached */
replace = &pycode_cache[i];
} else {
/* cache uptodate, use cached*/
replace = NULL;
run = &pycode_cache[i];
}
break;
} else if (replace == NULL || pycode_cache[i].used_time < replace->used_time)
/* if we haven't found it yet, set replace to the oldest cache */
replace = &pycode_cache[i];
}
/* replace a specific cache index with the file */
if (replace) {
Py_XDECREF(replace->code); /* safe to call on NULL */
replace->code = NULL;
/* Need to replace path string? */
if (replace->file != sh_path) {
if (replace->file) {
cf_free_string(replace->file);
}
replace->file = cf_add_string(sh_path);
}
/* Load, parse and compile */
if (!scriptfile && !(scriptfile = PyFile_FromString(filename, "r"))) {
cf_log(llevDebug, "cfpython - The Script file %s can't be opened\n", filename);
replace->code = NULL;
return NULL;
} else {
if ((n = PyParser_SimpleParseFile(PyFile_AsFile(scriptfile), filename, Py_file_input))) {
replace->code = PyNode_Compile(n, filename);
PyNode_Free(n);
}
if (PyErr_Occurred())
PyErr_Print();
else
replace->cached_time = stat_buf.st_mtime;
run = replace;
}
}
cf_free_string(sh_path);
if (scriptfile) {
Py_DECREF(scriptfile);
}
if (run)
return run->code;
else
return NULL;
}
static int do_script(CFPContext *context, int silent) {
PyCodeObject *pycode;
PyObject *dict;
PyObject *ret;
#if 0
PyObject *list;
int item;
#endif
pycode = compilePython(context->script);
if (pycode) {
pushContext(context);
dict = PyDict_New();
PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins());
ret = PyEval_EvalCode(pycode, dict, NULL);
if (PyErr_Occurred()) {
PyErr_Print();
}
Py_XDECREF(ret);
#if 0
printf("cfpython - %d items in heap\n", PyDict_Size(dict));
list = PyDict_Values(dict);
for (item = PyList_Size(list)-1; item >= 0; item--) {
dict = PyList_GET_ITEM(list, item);
ret = PyObject_Str(dict);
printf(" ref %s = %d\n", PyString_AsString(ret), dict->ob_refcnt);
Py_XDECREF(ret);
}
Py_DECREF(list);
#endif
Py_DECREF(dict);
return 1;
} else
return 0;
}
typedef struct {
const char *name;
const int value;
} CFConstant;
static void addConstants(PyObject *module, const char *name, const CFConstant *constants) {
int i = 0;
char tmp[1024];
PyObject *new;
PyObject *dict;
strncpy(tmp, "Crossfire_", sizeof(tmp));
strncat(tmp, name, sizeof(tmp)-strlen(tmp));
new = Py_InitModule(tmp, NULL);
dict = PyDict_New();
while (constants[i].name != NULL) {
PyModule_AddIntConstant(new, (char *)constants[i].name, constants[i].value);
PyDict_SetItem(dict, PyInt_FromLong(constants[i].value), PyString_FromString(constants[i].name));
i++;
}
PyDict_SetItemString(PyModule_GetDict(module), name, new);
/* This cause assert() in debug builds if enabled. */
#if 0
Py_DECREF(new);
#endif
strncpy(tmp, name, sizeof(tmp));
strncat(tmp, "Name", sizeof(tmp)-strlen(tmp));
PyDict_SetItemString(PyModule_GetDict(module), tmp, dict);
Py_DECREF(dict);
}
/**
* Do half the job of addConstants. It only
* Set constantc, but not a hashtable to get constant
* names from values. To be used for collections of constants
* which are not unique but still are usefull for scripts
*/
static void addSimpleConstants(PyObject *module, const char *name, const CFConstant *constants) {
int i = 0;
char tmp[1024];
PyObject *new;
strncpy(tmp, "Crossfire_", sizeof(tmp));
strncat(tmp, name, sizeof(tmp)-strlen(tmp));
new = Py_InitModule(tmp, NULL);
while (constants[i].name != NULL) {
PyModule_AddIntConstant(new, (char *)constants[i].name, constants[i].value);
i++;
}
PyDict_SetItemString(PyModule_GetDict(module), name, new);
/* This cause assert() in debug builds if enabled. */
#if 0
Py_DECREF(new);
#endif
}
static void initConstants(PyObject *module) {
static const CFConstant cstDirection[] = {
{ "NORTH", 1 },
{ "NORTHEAST", 2 },
{ "EAST", 3 },
{ "SOUTHEAST", 4 },
{ "SOUTH", 5 },
{ "SOUTHWEST", 6 },
{ "WEST", 7 },
{ "NORTHWEST", 8 },
{ NULL, 0 }
};
static const CFConstant cstType[] = {
{ "PLAYER", PLAYER },
{ "TRANSPORT", TRANSPORT },
{ "ROD", ROD },
{ "TREASURE", TREASURE },
{ "POTION", POTION },
{ "FOOD", FOOD },
{ "POISON", POISON },
{ "BOOK", BOOK },
{ "CLOCK", CLOCK },
{ "ARROW", ARROW },
{ "BOW", BOW },
{ "WEAPON", WEAPON },
{ "ARMOUR", ARMOUR },
{ "PEDESTAL", PEDESTAL },
{ "ALTAR", ALTAR },
{ "LOCKED_DOOR", LOCKED_DOOR },
{ "SPECIAL_KEY", SPECIAL_KEY },
{ "MAP", MAP },
{ "DOOR", DOOR },
{ "KEY", KEY },
{ "TIMED_GATE", TIMED_GATE },
{ "TRIGGER", TRIGGER },
{ "GRIMREAPER", GRIMREAPER },
{ "MAGIC_EAR", MAGIC_EAR },
{ "TRIGGER_BUTTON", TRIGGER_BUTTON },
{ "TRIGGER_ALTAR", TRIGGER_ALTAR },
{ "TRIGGER_PEDESTAL", TRIGGER_PEDESTAL },
{ "SHIELD", SHIELD },
{ "HELMET", HELMET },
{ "HORN", HORN },
{ "MONEY", MONEY },
{ "CLASS", CLASS },
{ "AMULET", AMULET },
{ "PLAYERMOVER", PLAYERMOVER },
{ "TELEPORTER", TELEPORTER },
{ "CREATOR", CREATOR },
{ "SKILL", SKILL },
{ "EXPERIENCE", EXPERIENCE },
{ "EARTHWALL", EARTHWALL },
{ "GOLEM", GOLEM },
{ "THROWN_OBJ", THROWN_OBJ },
{ "BLINDNESS", BLINDNESS },
{ "GOD", GOD },
{ "DETECTOR", DETECTOR },
{ "TRIGGER_MARKER", TRIGGER_MARKER },
{ "DEAD_OBJECT", DEAD_OBJECT },
{ "DRINK", DRINK },
{ "MARKER", MARKER },
{ "HOLY_ALTAR", HOLY_ALTAR },
{ "PLAYER_CHANGER", PLAYER_CHANGER },
{ "BATTLEGROUND", BATTLEGROUND },
{ "PEACEMAKER", PEACEMAKER },
{ "GEM", GEM },
{ "FIREWALL", FIREWALL },
{ "CHECK_INV", CHECK_INV },
{ "MOOD_FLOOR", MOOD_FLOOR },
{ "EXIT", EXIT },
{ "ENCOUNTER", ENCOUNTER },
{ "SHOP_FLOOR", SHOP_FLOOR },
{ "SHOP_MAT", SHOP_MAT },
{ "RING", RING },
{ "FLOOR", FLOOR },
{ "FLESH", FLESH },
{ "INORGANIC", INORGANIC },
{ "SKILL_TOOL", SKILL_TOOL },
{ "LIGHTER", LIGHTER },
{ "WALL", WALL },
{ "MISC_OBJECT", MISC_OBJECT },
{ "MONSTER", MONSTER },
{ "LAMP", LAMP },
{ "DUPLICATOR", DUPLICATOR },
{ "SPELLBOOK", SPELLBOOK },
{ "CLOAK", CLOAK },
{ "SPINNER", SPINNER },
{ "GATE", GATE },
{ "BUTTON", BUTTON },
{ "CF_HANDLE", CF_HANDLE },
{ "HOLE", HOLE },
{ "TRAPDOOR", TRAPDOOR },
{ "SIGN", SIGN },
{ "BOOTS", BOOTS },
{ "GLOVES", GLOVES },
{ "SPELL", SPELL },
{ "SPELL_EFFECT", SPELL_EFFECT },
{ "CONVERTER", CONVERTER },
{ "BRACERS", BRACERS },
{ "POISONING", POISONING },
{ "SAVEBED", SAVEBED },
{ "WAND", WAND },
{ "SCROLL", SCROLL },
{ "DIRECTOR", DIRECTOR },
{ "GIRDLE", GIRDLE },
{ "FORCE", FORCE },
{ "POTION_EFFECT", POTION_EFFECT },
{ "EVENT_CONNECTOR", EVENT_CONNECTOR },
{ "CLOSE_CON", CLOSE_CON },
{ "CONTAINER", CONTAINER },
{ "ARMOUR_IMPROVER", ARMOUR_IMPROVER },
{ "WEAPON_IMPROVER", WEAPON_IMPROVER },
{ "SKILLSCROLL", SKILLSCROLL },
{ "DEEP_SWAMP", DEEP_SWAMP },
{ "IDENTIFY_ALTAR", IDENTIFY_ALTAR },
{ "SHOP_INVENTORY", SHOP_INVENTORY },
{ "RUNE", RUNE },
{ "TRAP", TRAP },
{ "POWER_CRYSTAL", POWER_CRYSTAL },
{ "CORPSE", CORPSE },
{ "DISEASE", DISEASE },
{ "SYMPTOM", SYMPTOM },
{ "BUILDER", BUILDER },
{ "MATERIAL", MATERIAL },
{ NULL, 0 }
};
static const CFConstant cstMove[] = {
{ "WALK", MOVE_WALK },
{ "FLY_LOW", MOVE_FLY_LOW },
{ "FLY_HIGH", MOVE_FLY_HIGH },
{ "FLYING", MOVE_FLYING },
{ "SWIM", MOVE_SWIM },
{ "BOAT", MOVE_BOAT },
{ "ALL", MOVE_ALL },
{ NULL, 0 }
};
static const CFConstant cstMessageFlag[] = {
{ "NDI_BLACK", NDI_BLACK },
{ "NDI_WHITE", NDI_WHITE },
{ "NDI_NAVY", NDI_NAVY },
{ "NDI_RED", NDI_RED },
{ "NDI_ORANGE", NDI_ORANGE },
{ "NDI_BLUE", NDI_BLUE },
{ "NDI_DK_ORANGE", NDI_DK_ORANGE },
{ "NDI_GREEN", NDI_GREEN },
{ "NDI_LT_GREEN", NDI_LT_GREEN },
{ "NDI_GREY", NDI_GREY },
{ "NDI_BROWN", NDI_BROWN },
{ "NDI_GOLD", NDI_GOLD },
{ "NDI_TAN", NDI_TAN },
{ "NDI_UNIQUE", NDI_UNIQUE },
{ "NDI_ALL", NDI_ALL },
{ NULL, 0 }
};
static const CFConstant cstCostFlag[] = {
{ "TRUE", F_TRUE },
{ "BUY", F_BUY },
{ "SELL", F_SELL },
{ "NOBARGAIN", F_NO_BARGAIN },
{ "IDENTIFIED", F_IDENTIFIED },
{ "NOTCURSED", F_NOT_CURSED },
{ NULL, 0 }
};
static const CFConstant cstAttackType[] = {
{ "PHYSICAL", AT_PHYSICAL },
{ "MAGIC", AT_MAGIC },
{ "FIRE", AT_FIRE },
{ "ELECTRICITY", AT_ELECTRICITY },
{ "COLD", AT_COLD },
{ "CONFUSION", AT_CONFUSION },
{ "ACID", AT_ACID },
{ "DRAIN", AT_DRAIN },
{ "WEAPONMAGIC", AT_WEAPONMAGIC },
{ "GHOSTHIT", AT_GHOSTHIT },
{ "POISON", AT_POISON },
{ "SLOW", AT_SLOW },
{ "PARALYZE", AT_PARALYZE },
{ "TURN_UNDEAD", AT_TURN_UNDEAD },
{ "FEAR", AT_FEAR },
{ "CANCELLATION", AT_CANCELLATION },
{ "DEPLETE", AT_DEPLETE },
{ "DEATH", AT_DEATH },
{ "CHAOS", AT_CHAOS },
{ "COUNTERSPELL", AT_COUNTERSPELL },
{ "GODPOWER", AT_GODPOWER },
{ "HOLYWORD", AT_HOLYWORD },
{ "BLIND", AT_BLIND },
{ "INTERNAL", AT_INTERNAL },
{ "LIFE_STEALING", AT_LIFE_STEALING },
{ "DISEASE", AT_DISEASE },
{ NULL, 0 }
};
static const CFConstant cstAttackTypeNumber[] = {
{ "PHYSICAL", ATNR_PHYSICAL },
{ "MAGIC", ATNR_MAGIC },
{ "FIRE", ATNR_FIRE },
{ "ELECTRICITY", ATNR_ELECTRICITY },
{ "COLD", ATNR_COLD },
{ "CONFUSION", ATNR_CONFUSION },
{ "ACID", ATNR_ACID },
{ "DRAIN", ATNR_DRAIN },
{ "WEAPONMAGIC", ATNR_WEAPONMAGIC },
{ "GHOSTHIT", ATNR_GHOSTHIT },
{ "POISON", ATNR_POISON },
{ "SLOW", ATNR_SLOW },
{ "PARALYZE", ATNR_PARALYZE },
{ "TURN_UNDEAD", ATNR_TURN_UNDEAD },
{ "FEAR", ATNR_FEAR },
{ "CANCELLATION", ATNR_CANCELLATION },
{ "DEPLETE", ATNR_DEPLETE },
{ "DEATH", ATNR_DEATH },
{ "CHAOS", ATNR_CHAOS },
{ "COUNTERSPELL", ATNR_COUNTERSPELL },
{ "GODPOWER", ATNR_GODPOWER },
{ "HOLYWORD", ATNR_HOLYWORD },
{ "BLIND", ATNR_BLIND },
{ "INTERNAL", ATNR_INTERNAL },
{ "LIFE_STEALING", ATNR_LIFE_STEALING },
{ "DISEASE", ATNR_DISEASE },
{ NULL, 0 }
};
static const CFConstant cstEventType[] = {
{ "APPLY", EVENT_APPLY },
{ "ATTACK", EVENT_ATTACK },
{ "DEATH", EVENT_DEATH },
{ "DROP", EVENT_DROP },
{ "PICKUP", EVENT_PICKUP },
{ "SAY", EVENT_SAY },
{ "STOP", EVENT_STOP },
{ "TIME", EVENT_TIME },
{ "THROW", EVENT_THROW },
{ "TRIGGER", EVENT_TRIGGER },
{ "CLOSE", EVENT_CLOSE },
{ "TIMER", EVENT_TIMER },
{ "DESTROY", EVENT_DESTROY },
{ "BORN", EVENT_BORN },
{ "CLOCK", EVENT_CLOCK },
{ "CRASH", EVENT_CRASH },
{ "PLAYER_DEATH", EVENT_PLAYER_DEATH },
{ "GKILL", EVENT_GKILL },
{ "LOGIN", EVENT_LOGIN },
{ "LOGOUT", EVENT_LOGOUT },
{ "MAPENTER", EVENT_MAPENTER },
{ "MAPLEAVE", EVENT_MAPLEAVE },
{ "MAPRESET", EVENT_MAPRESET },
{ "REMOVE", EVENT_REMOVE },
{ "SHOUT", EVENT_SHOUT },
{ "TELL", EVENT_TELL },
{ "MUZZLE", EVENT_MUZZLE },
{ "KICK", EVENT_KICK },
{ "MAPUNLOAD", EVENT_MAPUNLOAD },
{ "MAPLOAD", EVENT_MAPLOAD },
{ "USER", EVENT_USER },
{ NULL, 0 }
};
static const CFConstant cstTime[] = {
{ "HOURS_PER_DAY", HOURS_PER_DAY },
{ "DAYS_PER_WEEK", DAYS_PER_WEEK },
{ "WEEKS_PER_MONTH", WEEKS_PER_MONTH },
{ "MONTHS_PER_YEAR", MONTHS_PER_YEAR },
{ "SEASONS_PER_YEAR", SEASONS_PER_YEAR },
{ "PERIODS_PER_DAY", PERIODS_PER_DAY },
{ NULL, 0 }
};
addConstants(module, "Direction", cstDirection);
addConstants(module, "Type", cstType);
addConstants(module, "Move", cstMove);
addConstants(module, "MessageFlag", cstMessageFlag);
addConstants(module, "CostFlag", cstCostFlag);
addConstants(module, "AttackType", cstAttackType);
addConstants(module, "AttackTypeNumber", cstAttackTypeNumber);
addConstants(module, "EventType", cstEventType);
addSimpleConstants(module, "Time", cstTime);
}
extern PyMODINIT_FUNC initcjson(void);
CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) {
PyObject *m, *d;
int i;
cf_init_plugin(gethooksptr);
cf_log(llevDebug, "CFPython 2.0a init\n");
init_object_assoc_table();
init_map_assoc_table();
#ifdef IS_PY26
Py_Py3kWarningFlag++;
#endif
Py_Initialize();
Crossfire_ObjectType.tp_new = PyType_GenericNew;
Crossfire_MapType.tp_new = PyType_GenericNew;
Crossfire_PlayerType.tp_new = PyType_GenericNew;
Crossfire_ArchetypeType.tp_new = PyType_GenericNew;
Crossfire_PartyType.tp_new = PyType_GenericNew;
Crossfire_RegionType.tp_new = PyType_GenericNew;
PyType_Ready(&Crossfire_ObjectType);
PyType_Ready(&Crossfire_MapType);
PyType_Ready(&Crossfire_PlayerType);
PyType_Ready(&Crossfire_ArchetypeType);
PyType_Ready(&Crossfire_PartyType);
PyType_Ready(&Crossfire_RegionType);
m = Py_InitModule("Crossfire", CFPythonMethods);
d = PyModule_GetDict(m);
Py_INCREF(&Crossfire_ObjectType);
Py_INCREF(&Crossfire_MapType);
Py_INCREF(&Crossfire_PlayerType);
Py_INCREF(&Crossfire_ArchetypeType);
Py_INCREF(&Crossfire_PartyType);
Py_INCREF(&Crossfire_RegionType);
PyModule_AddObject(m, "Object", (PyObject *)&Crossfire_ObjectType);
PyModule_AddObject(m, "Map", (PyObject *)&Crossfire_MapType);
PyModule_AddObject(m, "Player", (PyObject *)&Crossfire_PlayerType);
PyModule_AddObject(m, "Archetype", (PyObject *)&Crossfire_ArchetypeType);
PyModule_AddObject(m, "Party", (PyObject *)&Crossfire_PartyType);
PyModule_AddObject(m, "Region", (PyObject *)&Crossfire_RegionType);
PyModule_AddObject(m, "LogError", Py_BuildValue("i", llevError));
PyModule_AddObject(m, "LogInfo", Py_BuildValue("i", llevInfo));
PyModule_AddObject(m, "LogDebug", Py_BuildValue("i", llevDebug));
PyModule_AddObject(m, "LogMonster", Py_BuildValue("i", llevMonster));
CFPythonError = PyErr_NewException("Crossfire.error", NULL, NULL);
PyDict_SetItemString(d, "error", CFPythonError);
for (i = 0; i < NR_CUSTOM_CMD; i++) {
CustomCommand[i].name = NULL;
CustomCommand[i].script = NULL;
CustomCommand[i].speed = 0.0;
}
initConstants(m);
private_data = PyDict_New();
shared_data = PyDict_New();
/* add cjson module*/
initcjson();
return 0;
}
CF_PLUGIN void *getPluginProperty(int *type, ...) {
va_list args;
const char *propname;
int i, size;
command_array_struct *rtn_cmd;
char *buf;
va_start(args, type);
propname = va_arg(args, const char *);
if (!strcmp(propname, "command?")) {
const char *cmdname;
cmdname = va_arg(args, const char *);
rtn_cmd = va_arg(args, command_array_struct *);
va_end(args);
for (i = 0; i < NR_CUSTOM_CMD; i++) {
if (CustomCommand[i].name != NULL) {
if (!strcmp(CustomCommand[i].name, cmdname)) {
rtn_cmd->name = CustomCommand[i].name;
rtn_cmd->time = (float)CustomCommand[i].speed;
rtn_cmd->func = cfpython_runPluginCommand;
current_command = i;
return rtn_cmd;
}
}
}
return NULL;
} else if (!strcmp(propname, "Identification")) {
buf = va_arg(args, char *);
size = va_arg(args, int);
va_end(args);
snprintf(buf, size, PLUGIN_NAME);
return NULL;
} else if (!strcmp(propname, "FullName")) {
buf = va_arg(args, char *);
size = va_arg(args, int);
va_end(args);
snprintf(buf, size, PLUGIN_VERSION);
return NULL;
}
va_end(args);
return NULL;
}
CF_PLUGIN int cfpython_runPluginCommand(object *op, char *params) {
char buf[1024], path[1024];
CFPContext *context;
static int rv = 0;
rv = 0;
if (current_command < 0) {
cf_log(llevError, "Illegal call of cfpython_runPluginCommand, call find_plugin_command first.\n");
return 1;
}
snprintf(buf, sizeof(buf), "%s.py", cf_get_maps_directory(CustomCommand[current_command].script, path, sizeof(path)));
context = malloc(sizeof(CFPContext));
context->message[0] = 0;
context->who = Crossfire_Object_wrap(op);
context->activator = NULL;
context->third = NULL;
context->fix = 0;
snprintf(context->script, sizeof(context->script), "%s", buf);
if (params)
snprintf(context->options, sizeof(context->options), "%s", params);
else
context->options[0] = 0;
context->returnvalue = 1; /* Default is "command successful" */
current_command = -999;
if (!do_script(context, 0)) {
freeContext(context);
return rv;
}
context = popContext();
rv = context->returnvalue;
freeContext(context);
/* printf("Execution complete"); */
return rv;
}
CF_PLUGIN int postInitPlugin(void) {
PyObject *scriptfile;
char path[1024];
cf_log(llevDebug, "CFPython 2.0a post init\n");
initContextStack();
cf_system_register_global_event(EVENT_BORN, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_CLOCK, PLUGIN_NAME, cfpython_globalEventListener);
/*registerGlobalEvent(NULL, EVENT_CRASH, PLUGIN_NAME, cfpython_globalEventListener);*/
cf_system_register_global_event(EVENT_PLAYER_DEATH, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_GKILL, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_LOGIN, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_LOGOUT, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_MAPENTER, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_MAPLEAVE, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_MAPRESET, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_REMOVE, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_SHOUT, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_TELL, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_MUZZLE, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_KICK, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_MAPUNLOAD, PLUGIN_NAME, cfpython_globalEventListener);
cf_system_register_global_event(EVENT_MAPLOAD, PLUGIN_NAME, cfpython_globalEventListener);
scriptfile = PyFile_FromString(cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)), "r");
if (scriptfile != NULL) {
PyRun_SimpleFile(PyFile_AsFile(scriptfile), cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)));
Py_DECREF(scriptfile);
}
return 0;
}
CF_PLUGIN void *cfpython_globalEventListener(int *type, ...) {
va_list args;
static int rv = 0;
CFPContext *context;
char *buf;
player *pl;
object *op;
context = malloc(sizeof(CFPContext));
rv = 0;
va_start(args, type);
context->event_code = va_arg(args, int);
context->message[0] = 0;
context->who = NULL;
context->activator = NULL;
context->third = NULL;
context->event = NULL;
rv = context->returnvalue = 0;
cf_get_maps_directory("python/events/python_event.py", context->script, sizeof(context->script));
strcpy(context->options, "");
switch (context->event_code) {
case EVENT_CRASH:
cf_log(llevDebug, "Unimplemented for now\n");
break;
case EVENT_BORN:
op = va_arg(args, object *);
context->activator = Crossfire_Object_wrap(op);
snprintf(context->options, sizeof(context->options), "born");
break;
case EVENT_PLAYER_DEATH:
op = va_arg(args, object *);
context->who = Crossfire_Object_wrap(op);
snprintf(context->options, sizeof(context->options), "death");
break;
case EVENT_GKILL:
op = va_arg(args, object *);
context->who = Crossfire_Object_wrap(op);
context->activator = Crossfire_Object_wrap(op);
snprintf(context->options, sizeof(context->options), "gkill");
break;
case EVENT_LOGIN:
pl = va_arg(args, player *);
context->activator = Crossfire_Object_wrap(pl->ob);
buf = va_arg(args, char *);
if (buf != NULL)
snprintf(context->message, sizeof(context->message), "%s", buf);
snprintf(context->options, sizeof(context->options), "login");
break;
case EVENT_LOGOUT:
pl = va_arg(args, player *);
context->activator = Crossfire_Object_wrap(pl->ob);
buf = va_arg(args, char *);
if (buf != NULL)
snprintf(context->message, sizeof(context->message), "%s", buf);
snprintf(context->options, sizeof(context->options), "logout");
break;
case EVENT_REMOVE:
op = va_arg(args, object *);
context->activator = Crossfire_Object_wrap(op);
snprintf(context->options, sizeof(context->options), "remove");
break;
case EVENT_SHOUT:
op = va_arg(args, object *);
context->activator = Crossfire_Object_wrap(op);
buf = va_arg(args, char *);
if (buf != NULL)
snprintf(context->message, sizeof(context->message), "%s", buf);
snprintf(context->options, sizeof(context->options), "shout");
break;
case EVENT_MUZZLE:
op = va_arg(args, object *);
context->activator = Crossfire_Object_wrap(op);
buf = va_arg(args, char *);
if (buf != NULL)
snprintf(context->message, sizeof(context->message), "%s", buf);
snprintf(context->options, sizeof(context->options), "muzzle");
break;
case EVENT_KICK:
op = va_arg(args, object *);
context->activator = Crossfire_Object_wrap(op);
buf = va_arg(args, char *);
if (buf != NULL)
snprintf(context->message, sizeof(context->message), "%s", buf);
snprintf(context->options, sizeof(context->options), "kick");
break;
case EVENT_MAPENTER:
op = va_arg(args, object *);
context->activator = Crossfire_Object_wrap(op);
context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
snprintf(context->options, sizeof(context->options), "mapenter");
break;
case EVENT_MAPLEAVE:
op = va_arg(args, object *);
context->activator = Crossfire_Object_wrap(op);
context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
snprintf(context->options, sizeof(context->options), "mapleave");
break;
case EVENT_CLOCK:
snprintf(context->options, sizeof(context->options), "clock");
break;
case EVENT_MAPRESET:
context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
snprintf(context->options, sizeof(context->options), "mapreset");
break;
case EVENT_TELL:
op = va_arg(args, object *);
buf = va_arg(args, char *);
context->activator = Crossfire_Object_wrap(op);
if (buf != NULL)
snprintf(context->message, sizeof(context->message), "%s", buf);
op = va_arg(args, object *);
context->third = Crossfire_Object_wrap(op);
snprintf(context->options, sizeof(context->options), "tell");
break;
case EVENT_MAPUNLOAD:
context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
snprintf(context->options, sizeof(context->options), "mapunload");
break;
case EVENT_MAPLOAD:
context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
snprintf(context->options, sizeof(context->options), "mapload");
break;
}
va_end(args);
context->returnvalue = 0;
if (!do_script(context, 1)) {
freeContext(context);
return &rv;
}
context = popContext();
rv = context->returnvalue;
/* Invalidate freed map wrapper. */
if (context->event_code == EVENT_MAPUNLOAD)
Handle_Map_Unload_Hook((Crossfire_Map *)context->who);
freeContext(context);
return &rv;
}
CF_PLUGIN void *eventListener(int *type, ...) {
static int rv = 0;
va_list args;
char *buf;
CFPContext *context;
object *event;
rv = 0;
context = malloc(sizeof(CFPContext));
context->message[0] = 0;
va_start(args, type);
context->who = Crossfire_Object_wrap(va_arg(args, object *));
context->activator = Crossfire_Object_wrap(va_arg(args, object *));
context->third = Crossfire_Object_wrap(va_arg(args, object *));
buf = va_arg(args, char *);
if (buf != NULL)
snprintf(context->message, sizeof(context->message), "%s", buf);
context->fix = va_arg(args, int);
event = va_arg(args, object *);
context->event_code = event->subtype;
context->event = Crossfire_Object_wrap(event);
cf_get_maps_directory(event->slaying, context->script, sizeof(context->script));
snprintf(context->options, sizeof(context->options), "%s", event->name);
context->returnvalue = 0;
va_end(args);
if (!do_script(context, 0)) {
freeContext(context);
return &rv;
}
context = popContext();
rv = context->returnvalue;
freeContext(context);
return &rv;
}
CF_PLUGIN int closePlugin(void) {
cf_log(llevDebug, "CFPython 2.0a closing\n");
Py_Finalize();
return 0;
}