Crossfire Server, Branch 1.12  R12190
cfpython.c
Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /* CFPython - A Python module for Crossfire RPG.                             */
00003 /*****************************************************************************/
00004 /* This is the third version of the Crossfire Scripting Engine.              */
00005 /* The first version used Guile. It was directly integrated in the server    */
00006 /* code, but since Guile wasn't perceived as an easy-to-learn, easy-to-use   */
00007 /* language by many, it was dropped in favor of Python.                      */
00008 /* The second version, CFPython 1.0, was included as a plugin and provided   */
00009 /* just about the same level of functionality the current version has. But   */
00010 /* it used a rather counter-intuitive, procedural way of presenting things.  */
00011 /*                                                                           */
00012 /* CFPython 2.0 aims at correcting many of the design flaws crippling the    */
00013 /* older version. It is also the first plugin to be implemented using the    */
00014 /* new interface, that doesn't need awkward stuff like the horrible CFParm   */
00015 /* structure. For the Python writer, things should probably be easier and    */
00016 /* lead to more readable code: instead of writing "CFPython.getObjectXPos(ob)*/
00017 /* he/she now can simply write "ob.X".                                       */
00018 /*                                                                           */
00019 /*****************************************************************************/
00020 /* Please note that it is still very beta - some of the functions may not    */
00021 /* work as expected and could even cause the server to crash.                */
00022 /*****************************************************************************/
00023 /* Version history:                                                          */
00024 /* 0.1  "Ophiuchus"   - Initial Alpha release                                */
00025 /* 0.5  "Stalingrad"  - Message length overflow corrected.                   */
00026 /* 0.6  "Kharkov"     - Message and Write correctly redefined.               */
00027 /* 0.7  "Koursk"      - Setting informations implemented.                    */
00028 /* 1.0a "Petersburg"  - Last "old-fashioned" version, never submitted to CVS.*/
00029 /* 2.0  "Arkangelsk"  - First release of the 2.x series.                     */
00030 /*****************************************************************************/
00031 /* Version: 2.0beta8 (also known as "Alexander")                             */
00032 /* Contact: yann.chachkoff@myrealbox.com                                     */
00033 /*****************************************************************************/
00034 /* That code is placed under the GNU General Public Licence (GPL)            */
00035 /* (C)2001-2005 by Chachkoff Yann (Feel free to deliver your complaints)     */
00036 /*****************************************************************************/
00037 /*  CrossFire, A Multiplayer game for X-windows                              */
00038 /*                                                                           */
00039 /*  Copyright (C) 2000 Mark Wedel                                            */
00040 /*  Copyright (C) 1992 Frank Tore Johansen                                   */
00041 /*                                                                           */
00042 /*  This program is free software; you can redistribute it and/or modify     */
00043 /*  it under the terms of the GNU General Public License as published by     */
00044 /*  the Free Software Foundation; either version 2 of the License, or        */
00045 /*  (at your option) any later version.                                      */
00046 /*                                                                           */
00047 /*  This program is distributed in the hope that it will be useful,          */
00048 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
00049 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
00050 /*  GNU General Public License for more details.                             */
00051 /*                                                                           */
00052 /*  You should have received a copy of the GNU General Public License        */
00053 /*  along with this program; if not, write to the Free Software              */
00054 /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
00055 /*                                                                           */
00056 /*****************************************************************************/
00057 
00058 /* First let's include the header file needed                                */
00059 
00060 #include <cfpython.h>
00061 #include <stdarg.h>
00062 #include <node.h>
00063 
00064 #define PYTHON_DEBUG   /* give us some general infos out */
00065 #define PYTHON_CACHE_SIZE 16    /* number of python scripts to store the bytecode of at a time */
00066 
00067 typedef struct {
00068     sstring file;
00069     PyCodeObject *code;
00070     time_t cached_time, used_time;
00071 } pycode_cache_entry;
00072 
00073 static PythonCmd CustomCommand[NR_CUSTOM_CMD];
00074 
00075 static pycode_cache_entry pycode_cache[PYTHON_CACHE_SIZE];
00076 
00077 static void set_exception(const char *fmt, ...);
00078 static PyObject *createCFObject(PyObject *self, PyObject *args);
00079 static PyObject *createCFObjectByName(PyObject *self, PyObject *args);
00080 static PyObject *getCFPythonVersion(PyObject *self, PyObject *args);
00081 static PyObject *getReturnValue(PyObject *self, PyObject *args);
00082 static PyObject *setReturnValue(PyObject *self, PyObject *args);
00083 static PyObject *matchString(PyObject *self, PyObject *args);
00084 static PyObject *findPlayer(PyObject *self, PyObject *args);
00085 static PyObject *readyMap(PyObject *self, PyObject *args);
00086 static PyObject *createMap(PyObject *self, PyObject *args);
00087 static PyObject *getMapDirectory(PyObject *self, PyObject *args);
00088 static PyObject *getUniqueDirectory(PyObject *self, PyObject *args);
00089 static PyObject *getTempDirectory(PyObject *self, PyObject *args);
00090 static PyObject *getConfigDirectory(PyObject *self, PyObject *args);
00091 static PyObject *getLocalDirectory(PyObject *self, PyObject *args);
00092 static PyObject *getPlayerDirectory(PyObject *self, PyObject *args);
00093 static PyObject *getDataDirectory(PyObject *self, PyObject *args);
00094 static PyObject *getWhoAmI(PyObject *self, PyObject *args);
00095 static PyObject *getWhoIsActivator(PyObject *self, PyObject *args);
00096 static PyObject *getWhoIsThird(PyObject *self, PyObject *args);
00097 static PyObject *getWhatIsMessage(PyObject *self, PyObject *args);
00098 static PyObject *getScriptName(PyObject *self, PyObject *args);
00099 static PyObject *getScriptParameters(PyObject *self, PyObject *args);
00100 static PyObject *getEvent(PyObject *self, PyObject *args);
00101 static PyObject *getPrivateDictionary(PyObject *self, PyObject *args);
00102 static PyObject *getSharedDictionary(PyObject *self, PyObject *args);
00103 static PyObject *getArchetypes(PyObject *self, PyObject *args);
00104 static PyObject *getPlayers(PyObject *self, PyObject *args);
00105 static PyObject *getMaps(PyObject *self, PyObject *args);
00106 static PyObject *getParties(PyObject *self, PyObject *args);
00107 static PyObject *getRegions(PyObject *self, PyObject *args);
00108 static PyObject *getFriendlyList(PyObject *self, PyObject *args);
00109 static PyObject *registerCommand(PyObject *self, PyObject *args);
00110 static PyObject *registerGEvent(PyObject *self, PyObject *args);
00111 static PyObject *unregisterGEvent(PyObject *self, PyObject *args);
00112 static PyObject *CFPythonError;
00113 static PyObject *getTime(PyObject *self, PyObject *args);
00114 static PyObject *destroyTimer(PyObject *self, PyObject *args);
00115 static PyObject *getMapHasBeenLoaded(PyObject *self, PyObject *args);
00116 static PyObject *findAnimation(PyObject *self, PyObject *args);
00117 static PyObject *log_message(PyObject *self, PyObject *args);
00118 static PyObject *findFace(PyObject *self, PyObject *args);
00119 static PyObject *getSeasonName(PyObject *self, PyObject *args);
00120 static PyObject *getMonthName(PyObject *self, PyObject *args);
00121 static PyObject *getWeekdayName(PyObject *self, PyObject *args);
00122 static PyObject *getPeriodofdayName(PyObject *self, PyObject *args);
00123 
00125 static void set_exception(const char *fmt, ...) {
00126     char buf[1024];
00127     va_list arg;
00128 
00129     va_start(arg, fmt);
00130     vsnprintf(buf, sizeof(buf), fmt, arg);
00131     va_end(arg);
00132 
00133     PyErr_SetString(PyExc_ValueError, buf);
00134 }
00135 
00136 static PyMethodDef CFPythonMethods[] = {
00137     { "WhoAmI",              getWhoAmI,              METH_NOARGS,  NULL },
00138     { "WhoIsActivator",      getWhoIsActivator,      METH_NOARGS,  NULL },
00139     { "WhoIsOther",          getWhoIsThird,          METH_NOARGS,  NULL },
00140     { "WhatIsMessage",       getWhatIsMessage,       METH_NOARGS,  NULL },
00141     { "ScriptName",          getScriptName,          METH_NOARGS,  NULL },
00142     { "ScriptParameters",    getScriptParameters,    METH_NOARGS,  NULL },
00143     { "WhatIsEvent",         getEvent,               METH_NOARGS,  NULL },
00144     { "MapDirectory",        getMapDirectory,        METH_NOARGS,  NULL },
00145     { "UniqueDirectory",     getUniqueDirectory,     METH_NOARGS,  NULL },
00146     { "TempDirectory",       getTempDirectory,       METH_NOARGS,  NULL },
00147     { "ConfigDirectory",     getConfigDirectory,     METH_NOARGS,  NULL },
00148     { "LocalDirectory",      getLocalDirectory,      METH_NOARGS,  NULL },
00149     { "PlayerDirectory",     getPlayerDirectory,     METH_NOARGS,  NULL },
00150     { "DataDirectory",       getDataDirectory,       METH_NOARGS,  NULL },
00151     { "ReadyMap",            readyMap,               METH_VARARGS, NULL },
00152     { "CreateMap",           createMap,              METH_VARARGS, NULL },
00153     { "FindPlayer",          findPlayer,             METH_VARARGS, NULL },
00154     { "MatchString",         matchString,            METH_VARARGS, NULL },
00155     { "GetReturnValue",      getReturnValue,         METH_NOARGS,  NULL },
00156     { "SetReturnValue",      setReturnValue,         METH_VARARGS, NULL },
00157     { "PluginVersion",       getCFPythonVersion,     METH_NOARGS,  NULL },
00158     { "CreateObject",        createCFObject,         METH_NOARGS,  NULL },
00159     { "CreateObjectByName",  createCFObjectByName,   METH_VARARGS, NULL },
00160     { "GetPrivateDictionary", getPrivateDictionary,  METH_NOARGS,  NULL },
00161     { "GetSharedDictionary", getSharedDictionary,    METH_NOARGS,  NULL },
00162     { "GetPlayers",          getPlayers,             METH_NOARGS,  NULL },
00163     { "GetArchetypes",       getArchetypes,          METH_NOARGS,  NULL },
00164     { "GetMaps",             getMaps,                METH_NOARGS,  NULL },
00165     { "GetParties",          getParties,             METH_NOARGS,  NULL },
00166     { "GetRegions",          getRegions,             METH_NOARGS,  NULL },
00167     { "GetFriendlyList",     getFriendlyList,        METH_NOARGS,  NULL },
00168     { "RegisterCommand",     registerCommand,        METH_VARARGS, NULL },
00169     { "RegisterGlobalEvent", registerGEvent,         METH_VARARGS, NULL },
00170     { "UnregisterGlobalEvent", unregisterGEvent,     METH_VARARGS, NULL },
00171     { "GetTime",             getTime,                METH_NOARGS,  NULL },
00172     { "DestroyTimer",        destroyTimer,           METH_VARARGS, NULL },
00173     { "MapHasBeenLoaded",    getMapHasBeenLoaded,    METH_VARARGS, NULL },
00174     { "Log",                 log_message,            METH_VARARGS, NULL },
00175     { "FindFace",            findFace,               METH_VARARGS, NULL },
00176     { "FindAnimation",       findAnimation,          METH_VARARGS, NULL },
00177     { "GetSeasonName",       getSeasonName,          METH_VARARGS, NULL },
00178     { "GetMonthName",        getMonthName,           METH_VARARGS, NULL },
00179     { "GetWeekdayName",      getWeekdayName,         METH_VARARGS, NULL },
00180     { "GetPeriodofdayName",  getPeriodofdayName,     METH_VARARGS, NULL },
00181     { NULL, NULL, 0, NULL }
00182 };
00183 
00184 CFPContext *context_stack;
00185 
00186 CFPContext *current_context;
00187 
00188 static int current_command = -999;
00189 
00190 static PyObject *shared_data = NULL;
00191 
00192 static PyObject *private_data = NULL;
00193 
00194 static PyObject *registerGEvent(PyObject *self, PyObject *args) {
00195     int eventcode;
00196 
00197     if (!PyArg_ParseTuple(args, "i", &eventcode))
00198         return NULL;
00199 
00200     cf_system_register_global_event(eventcode, PLUGIN_NAME, cfpython_globalEventListener);
00201 
00202     Py_INCREF(Py_None);
00203     return Py_None;
00204 }
00205 
00206 static PyObject *unregisterGEvent(PyObject *self, PyObject *args) {
00207     int eventcode;
00208 
00209     if (!PyArg_ParseTuple(args, "i", &eventcode))
00210         return NULL;
00211 
00212     cf_system_unregister_global_event(EVENT_TELL, PLUGIN_NAME);
00213 
00214     Py_INCREF(Py_None);
00215     return Py_None;
00216 }
00217 
00218 static PyObject *createCFObject(PyObject *self, PyObject *args) {
00219     object *op;
00220 
00221     op = cf_create_object();
00222 
00223     return Crossfire_Object_wrap(op);
00224 }
00225 
00226 static PyObject *createCFObjectByName(PyObject *self, PyObject *args) {
00227     char *obname;
00228     object *op;
00229 
00230     if (!PyArg_ParseTuple(args, "s", &obname))
00231         return NULL;
00232 
00233     op = cf_create_object_by_name(obname);
00234 
00235     return Crossfire_Object_wrap(op);
00236 }
00237 
00238 static PyObject *getCFPythonVersion(PyObject *self, PyObject *args) {
00239     int i = 2044;
00240 
00241     return Py_BuildValue("i", i);
00242 }
00243 
00244 static PyObject *getReturnValue(PyObject *self, PyObject *args) {
00245     return Py_BuildValue("i", current_context->returnvalue);
00246 }
00247 
00248 static PyObject *setReturnValue(PyObject *self, PyObject *args) {
00249     int i;
00250 
00251     if (!PyArg_ParseTuple(args, "i", &i))
00252         return NULL;
00253     current_context->returnvalue = i;
00254     Py_INCREF(Py_None);
00255     return Py_None;
00256 }
00257 
00258 static PyObject *matchString(PyObject *self, PyObject *args) {
00259     char *premiere;
00260     char *seconde;
00261     const char *result;
00262 
00263     if (!PyArg_ParseTuple(args, "ss", &premiere, &seconde))
00264         return NULL;
00265 
00266     result = cf_re_cmp(premiere, seconde);
00267     if (result != NULL)
00268         return Py_BuildValue("i", 1);
00269     else
00270         return Py_BuildValue("i", 0);
00271 }
00272 
00273 static PyObject *findPlayer(PyObject *self, PyObject *args) {
00274     player *foundpl;
00275     char *txt;
00276 
00277     if (!PyArg_ParseTuple(args, "s", &txt))
00278         return NULL;
00279 
00280     foundpl = cf_player_find(txt);
00281 
00282     if (foundpl != NULL)
00283         return Py_BuildValue("O", Crossfire_Object_wrap(foundpl->ob));
00284     else {
00285         Py_INCREF(Py_None);
00286         return Py_None;
00287     }
00288 }
00289 
00290 static PyObject *readyMap(PyObject *self, PyObject *args) {
00291     char *mapname;
00292     mapstruct *map;
00293     int flags = 0;
00294 
00295     if (!PyArg_ParseTuple(args, "s|i", &mapname, &flags))
00296         return NULL;
00297 
00298     map = cf_map_get_map(mapname, flags);
00299 
00300     return Crossfire_Map_wrap(map);
00301 }
00302 
00303 static PyObject *createMap(PyObject *self, PyObject *args) {
00304     int sizex, sizey;
00305     mapstruct *map;
00306 
00307     if (!PyArg_ParseTuple(args, "ii", &sizex, &sizey))
00308         return NULL;
00309 
00310     map = cf_get_empty_map(sizex, sizey);
00311 
00312     return Crossfire_Map_wrap(map);
00313 }
00314 
00315 static PyObject *getMapDirectory(PyObject *self, PyObject *args) {
00316     return Py_BuildValue("s", cf_get_directory(0));
00317 }
00318 
00319 static PyObject *getUniqueDirectory(PyObject *self, PyObject *args) {
00320     return Py_BuildValue("s", cf_get_directory(1));
00321 }
00322 
00323 static PyObject *getTempDirectory(PyObject *self, PyObject *args) {
00324     return Py_BuildValue("s", cf_get_directory(2));
00325 }
00326 
00327 static PyObject *getConfigDirectory(PyObject *self, PyObject *args) {
00328     return Py_BuildValue("s", cf_get_directory(3));
00329 }
00330 
00331 static PyObject *getLocalDirectory(PyObject *self, PyObject *args) {
00332     return Py_BuildValue("s", cf_get_directory(4));
00333 }
00334 
00335 static PyObject *getPlayerDirectory(PyObject *self, PyObject *args) {
00336     return Py_BuildValue("s", cf_get_directory(5));
00337 }
00338 
00339 static PyObject *getDataDirectory(PyObject *self, PyObject *args) {
00340     return Py_BuildValue("s", cf_get_directory(6));
00341 }
00342 
00343 static PyObject *getWhoAmI(PyObject *self, PyObject *args) {
00344     if (!current_context->who) {
00345         Py_INCREF(Py_None);
00346         return Py_None;
00347     }
00348     Py_INCREF(current_context->who);
00349     return current_context->who;
00350 }
00351 
00352 static PyObject *getWhoIsActivator(PyObject *self, PyObject *args) {
00353     if (!current_context->activator) {
00354         Py_INCREF(Py_None);
00355         return Py_None;
00356     }
00357     Py_INCREF(current_context->activator);
00358     return current_context->activator;
00359 }
00360 
00361 static PyObject *getWhoIsThird(PyObject *self, PyObject *args) {
00362     if (!current_context->third) {
00363         Py_INCREF(Py_None);
00364         return Py_None;
00365     }
00366     Py_INCREF(current_context->third);
00367     return current_context->third;
00368 }
00369 
00370 static PyObject *getWhatIsMessage(PyObject *self, PyObject *args) {
00371     if (current_context->message == NULL)
00372         return Py_BuildValue("");
00373     else
00374         return Py_BuildValue("s", current_context->message);
00375 }
00376 
00377 static PyObject *getScriptName(PyObject *self, PyObject *args) {
00378     return Py_BuildValue("s", current_context->script);
00379 }
00380 
00381 static PyObject *getScriptParameters(PyObject *self, PyObject *args) {
00382     if (!current_context->options) {
00383         Py_INCREF(Py_None);
00384         return Py_None;
00385     }
00386     return Py_BuildValue("s", current_context->options);
00387 }
00388 
00389 static PyObject *getEvent(PyObject *self, PyObject *args) {
00390     if (!current_context->event) {
00391         Py_INCREF(Py_None);
00392         return Py_None;
00393     }
00394     Py_INCREF(current_context->event);
00395     return current_context->event;
00396 }
00397 
00398 static PyObject *getPrivateDictionary(PyObject *self, PyObject *args) {
00399     PyObject *data;
00400 
00401     data = PyDict_GetItemString(private_data, current_context->script);
00402     if (!data) {
00403         data = PyDict_New();
00404         PyDict_SetItemString(private_data, current_context->script, data);
00405         Py_DECREF(data);
00406     }
00407     Py_INCREF(data);
00408     return data;
00409 }
00410 
00411 static PyObject *getSharedDictionary(PyObject *self, PyObject *args) {
00412     Py_INCREF(shared_data);
00413     return shared_data;
00414 }
00415 
00416 static PyObject *getArchetypes(PyObject *self, PyObject *args) {
00417     PyObject *list;
00418     archetype *arch;
00419 
00420     list = PyList_New(0);
00421     arch = cf_archetype_get_first();
00422     while (arch) {
00423         PyList_Append(list, Crossfire_Archetype_wrap(arch));
00424         arch = cf_archetype_get_next(arch);
00425     }
00426     return list;
00427 }
00428 
00429 static PyObject *getPlayers(PyObject *self, PyObject *args) {
00430     PyObject *list;
00431     object *pl;
00432 
00433     list = PyList_New(0);
00434     pl = cf_object_get_object_property(NULL, CFAPI_PLAYER_PROP_NEXT);
00435     while (pl) {
00436         PyList_Append(list, Crossfire_Object_wrap(pl));
00437         pl = cf_object_get_object_property(pl, CFAPI_PLAYER_PROP_NEXT);
00438     }
00439     return list;
00440 }
00441 
00442 static PyObject *getMaps(PyObject *self, PyObject *args) {
00443     PyObject *list;
00444     mapstruct *map;
00445 
00446     list = PyList_New(0);
00447     map = cf_map_get_first();
00448     while (map) {
00449         PyList_Append(list, Crossfire_Map_wrap(map));
00450         map = cf_map_get_map_property(map, CFAPI_MAP_PROP_NEXT);
00451     }
00452     return list;
00453 }
00454 
00455 static PyObject *getParties(PyObject *self, PyObject *args) {
00456     PyObject *list;
00457     partylist *party;
00458 
00459     list = PyList_New(0);
00460     party = cf_party_get_first();
00461     while (party) {
00462         PyList_Append(list, Crossfire_Party_wrap(party));
00463         party = cf_party_get_next(party);
00464     }
00465     return list;
00466 }
00467 
00468 static PyObject *getRegions(PyObject *self, PyObject *args) {
00469     PyObject *list;
00470     region *reg;
00471 
00472     list = PyList_New(0);
00473     reg = cf_region_get_first();
00474     while (reg) {
00475         PyList_Append(list, Crossfire_Region_wrap(reg));
00476         reg = cf_region_get_next(reg);
00477    }
00478    return list;
00479 }
00480 
00481 static PyObject *getFriendlyList(PyObject *self, PyObject *args) {
00482     PyObject *list;
00483     object *ob;
00484 
00485     list = PyList_New(0);
00486     ob = cf_friendlylist_get_first();
00487     while (ob) {
00488         PyList_Append(list, Crossfire_Object_wrap(ob));
00489         ob = cf_friendlylist_get_next(ob);
00490    }
00491    return list;
00492 }
00493 
00494 static PyObject *registerCommand(PyObject *self, PyObject *args) {
00495     char *cmdname;
00496     char *scriptname;
00497     double cmdspeed;
00498     int i;
00499 
00500     if (!PyArg_ParseTuple(args, "ssd", &cmdname, &scriptname, &cmdspeed))
00501         return NULL;
00502 
00503     if (cmdspeed < 0) {
00504         set_exception("speed must not be negative");
00505         return NULL;
00506     }
00507 
00508     for (i = 0; i < NR_CUSTOM_CMD; i++) {
00509         if (CustomCommand[i].name != NULL) {
00510             if (!strcmp(CustomCommand[i].name, cmdname)) {
00511                 set_exception("command '%s' is already registered", cmdname);
00512                 return NULL;
00513             }
00514         }
00515     }
00516     for (i = 0; i < NR_CUSTOM_CMD; i++) {
00517         if (CustomCommand[i].name == NULL) {
00518             CustomCommand[i].name = cf_strdup_local(cmdname);
00519             CustomCommand[i].script = cf_strdup_local(scriptname);
00520             CustomCommand[i].speed = cmdspeed;
00521             break;
00522         }
00523     }
00524 
00525     Py_INCREF(Py_None);
00526     return Py_None;
00527 }
00528 
00529 static PyObject *getTime(PyObject *self, PyObject *args) {
00530     PyObject *list;
00531     timeofday_t tod;
00532 
00533     cf_get_time(&tod);
00534 
00535     list = PyList_New(0);
00536     PyList_Append(list, Py_BuildValue("i", tod.year));
00537     PyList_Append(list, Py_BuildValue("i", tod.month));
00538     PyList_Append(list, Py_BuildValue("i", tod.day));
00539     PyList_Append(list, Py_BuildValue("i", tod.hour));
00540     PyList_Append(list, Py_BuildValue("i", tod.minute));
00541     PyList_Append(list, Py_BuildValue("i", tod.dayofweek));
00542     PyList_Append(list, Py_BuildValue("i", tod.weekofmonth));
00543     PyList_Append(list, Py_BuildValue("i", tod.season));
00544     PyList_Append(list, Py_BuildValue("i", tod.periodofday));
00545 
00546     return list;
00547 }
00548 
00549 static PyObject *destroyTimer(PyObject *self, PyObject *args) {
00550     int id;
00551 
00552     if (!PyArg_ParseTuple(args, "i", &id))
00553         return NULL;
00554     return Py_BuildValue("i", cf_timer_destroy(id));
00555 }
00556 
00557 static PyObject *getMapHasBeenLoaded(PyObject *self, PyObject *args) {
00558     char *name;
00559 
00560     if (!PyArg_ParseTuple(args, "s", &name))
00561         return NULL;
00562     return Crossfire_Map_wrap(cf_map_has_been_loaded(name));
00563 }
00564 
00565 static PyObject *findFace(PyObject *self, PyObject *args) {
00566     char *name;
00567 
00568     if (!PyArg_ParseTuple(args, "s", &name))
00569         return NULL;
00570     return Py_BuildValue("i", cf_find_face(name, 0));
00571 }
00572 
00573 static PyObject *log_message(PyObject *self, PyObject *args) {
00574     LogLevel level;
00575     int intLevel;
00576     char *message;
00577 
00578     if (!PyArg_ParseTuple(args, "is", &intLevel, &message))
00579         return NULL;
00580 
00581     switch (intLevel) {
00582     case llevError:
00583         level = llevError;
00584         break;
00585 
00586     case llevInfo:
00587         level = llevInfo;
00588         break;
00589 
00590     case llevDebug:
00591         level = llevDebug;
00592         break;
00593 
00594     case llevMonster:
00595         level = llevMonster;
00596         break;
00597 
00598     default:
00599         return NULL;
00600     }
00601     if ((message != NULL) && (message[strlen(message)] == '\n'))
00602         cf_log(level, "CFPython: %s", message);
00603     else
00604         cf_log(level, "CFPython: %s\n", message);
00605     Py_INCREF(Py_None);
00606     return Py_None;
00607 }
00608 
00609 static PyObject *findAnimation(PyObject *self, PyObject *args) {
00610     char *name;
00611 
00612     if (!PyArg_ParseTuple(args, "s", &name))
00613         return NULL;
00614     return Py_BuildValue("i", cf_find_animation(name));
00615 }
00616 
00617 static PyObject *getSeasonName(PyObject *self, PyObject *args) {
00618     int i;
00619 
00620     if (!PyArg_ParseTuple(args, "i", &i))
00621         return NULL;
00622     return Py_BuildValue("s", cf_get_season_name(i));
00623 }
00624 
00625 static PyObject *getMonthName(PyObject *self, PyObject *args) {
00626     int i;
00627 
00628     if (!PyArg_ParseTuple(args, "i", &i))
00629         return NULL;
00630     return Py_BuildValue("s", cf_get_month_name(i));
00631 }
00632 
00633 static PyObject *getWeekdayName(PyObject *self, PyObject *args) {
00634     int i;
00635 
00636     if (!PyArg_ParseTuple(args, "i", &i))
00637         return NULL;
00638     return Py_BuildValue("s", cf_get_weekday_name(i));
00639 }
00640 
00641 static PyObject *getPeriodofdayName(PyObject *self, PyObject *args) {
00642     int i;
00643 
00644     if (!PyArg_ParseTuple(args, "i", &i))
00645         return NULL;
00646     return Py_BuildValue("s", cf_get_periodofday_name(i));
00647 }
00648 
00649 static void initContextStack(void) {
00650     current_context = NULL;
00651     context_stack = NULL;
00652 }
00653 
00654 static void pushContext(CFPContext *context) {
00655     if (current_context == NULL) {
00656         context_stack = context;
00657         context->down = NULL;
00658     } else {
00659         context->down = current_context;
00660     }
00661     current_context = context;
00662 }
00663 
00664 static CFPContext *popContext(void) {
00665     CFPContext *oldcontext;
00666 
00667     if (current_context != NULL) {
00668         oldcontext = current_context;
00669         current_context = current_context->down;
00670         return oldcontext;
00671     }
00672     else
00673         return NULL;
00674 }
00675 
00676 static void freeContext(CFPContext *context) {
00677     Py_XDECREF(context->event);
00678     Py_XDECREF(context->third);
00679     Py_XDECREF(context->who);
00680     Py_XDECREF(context->activator);
00681     free(context);
00682 }
00683 
00685 static PyCodeObject *compilePython(char *filename) {
00686     PyObject *scriptfile;
00687     sstring sh_path;
00688     struct stat stat_buf;
00689     struct _node *n;
00690     int i;
00691     pycode_cache_entry *replace = NULL, *run = NULL;
00692 
00693     if (!(scriptfile = PyFile_FromString(filename, "r"))) {
00694         cf_log(llevDebug, "cfpython - The Script file %s can't be opened\n", filename);
00695         return NULL;
00696     }
00697     if (stat(filename, &stat_buf)) {
00698         cf_log(llevDebug, "cfpython - The Script file %s can't be stat:ed\n", filename);
00699         if (scriptfile) {
00700             Py_DECREF(scriptfile);
00701         }
00702         return NULL;
00703     }
00704 
00705     sh_path = cf_add_string(filename);
00706 
00707     /* Search through cache. Three cases:
00708      * 1) script in cache, but older than file  -> replace cached
00709      * 2) script in cache and up to date        -> use cached
00710      * 3) script not in cache, cache not full   -> add to end of cache
00711      * 4) script not in cache, cache full       -> replace least recently used
00712      */
00713     for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
00714         if (pycode_cache[i].file == NULL) {  /* script not in cache, cache not full */
00715             replace = &pycode_cache[i];     /* add to end of cache */
00716             break;
00717         } else if (pycode_cache[i].file == sh_path) {
00718             /* script in cache */
00719             if (pycode_cache[i].code == NULL || (pycode_cache[i].cached_time < stat_buf.st_mtime)) {
00720                 /* cache older than file, replace cached */
00721                 replace = &pycode_cache[i];
00722             } else {
00723                 /* cache uptodate, use cached*/
00724                 replace = NULL;
00725                 run = &pycode_cache[i];
00726             }
00727             break;
00728         } else if (replace == NULL || pycode_cache[i].used_time < replace->used_time)
00729             /* if we haven't found it yet, set replace to the oldest cache */
00730             replace = &pycode_cache[i];
00731     }
00732 
00733     /* replace a specific cache index with the file */
00734     if (replace) {
00735         Py_XDECREF(replace->code); /* safe to call on NULL */
00736         replace->code = NULL;
00737 
00738         /* Need to replace path string? */
00739         if (replace->file != sh_path) {
00740             if (replace->file) {
00741                 cf_free_string(replace->file);
00742             }
00743             replace->file = cf_add_string(sh_path);
00744         }
00745 
00746         /* Load, parse and compile */
00747         if (!scriptfile && !(scriptfile = PyFile_FromString(filename, "r"))) {
00748             cf_log(llevDebug, "cfpython - The Script file %s can't be opened\n", filename);
00749             replace->code = NULL;
00750             return NULL;
00751         } else {
00752             if ((n = PyParser_SimpleParseFile(PyFile_AsFile(scriptfile), filename, Py_file_input))) {
00753                 replace->code = PyNode_Compile(n, filename);
00754                 PyNode_Free(n);
00755             }
00756 
00757             if (PyErr_Occurred())
00758                 PyErr_Print();
00759             else
00760                 replace->cached_time = stat_buf.st_mtime;
00761             run = replace;
00762         }
00763     }
00764 
00765     cf_free_string(sh_path);
00766 
00767     if (scriptfile) {
00768         Py_DECREF(scriptfile);
00769     }
00770 
00771     if (run)
00772         return run->code;
00773     else
00774         return NULL;
00775 }
00776 
00777 static int do_script(CFPContext *context, int silent) {
00778     PyCodeObject *pycode;
00779     PyObject *dict;
00780     PyObject *ret;
00781 #if 0
00782     PyObject *list;
00783     int item;
00784 #endif
00785 
00786     pycode = compilePython(context->script);
00787     if (pycode) {
00788         pushContext(context);
00789         dict = PyDict_New();
00790         PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins());
00791         ret = PyEval_EvalCode(pycode, dict, NULL);
00792         if (PyErr_Occurred()) {
00793             PyErr_Print();
00794         }
00795         Py_XDECREF(ret);
00796 #if 0
00797         printf("cfpython - %d items in heap\n", PyDict_Size(dict));
00798         list = PyDict_Values(dict);
00799         for (item = PyList_Size(list)-1; item >= 0; item--) {
00800             dict = PyList_GET_ITEM(list, item);
00801             ret = PyObject_Str(dict);
00802             printf(" ref %s = %d\n", PyString_AsString(ret), dict->ob_refcnt);
00803             Py_XDECREF(ret);
00804         }
00805         Py_DECREF(list);
00806 #endif
00807         Py_DECREF(dict);
00808         return 1;
00809     } else
00810         return 0;
00811 }
00812 
00813 typedef struct {
00814     const char *name;
00815     const int value;
00816 } CFConstant;
00817 
00818 static void addConstants(PyObject *module, const char *name, const CFConstant *constants) {
00819     int i = 0;
00820     char tmp[1024];
00821     PyObject *new;
00822     PyObject *dict;
00823 
00824     strncpy(tmp, "Crossfire_", sizeof(tmp));
00825     strncat(tmp, name, sizeof(tmp)-strlen(tmp));
00826 
00827     new = Py_InitModule(tmp, NULL);
00828     dict = PyDict_New();
00829 
00830     while (constants[i].name != NULL) {
00831         PyModule_AddIntConstant(new, (char *)constants[i].name, constants[i].value);
00832         PyDict_SetItem(dict, PyInt_FromLong(constants[i].value), PyString_FromString(constants[i].name));
00833         i++;
00834     }
00835     PyDict_SetItemString(PyModule_GetDict(module), name, new);
00836     /* This cause assert() in debug builds if enabled. */
00837 #if 0
00838     Py_DECREF(new);
00839 #endif
00840 
00841     strncpy(tmp, name, sizeof(tmp));
00842     strncat(tmp, "Name", sizeof(tmp)-strlen(tmp));
00843     PyDict_SetItemString(PyModule_GetDict(module), tmp, dict);
00844     Py_DECREF(dict);
00845 }
00852 static void addSimpleConstants(PyObject *module, const char *name, const CFConstant *constants) {
00853     int i = 0;
00854     char tmp[1024];
00855     PyObject *new;
00856 
00857     strncpy(tmp, "Crossfire_", sizeof(tmp));
00858     strncat(tmp, name, sizeof(tmp)-strlen(tmp));
00859 
00860     new = Py_InitModule(tmp, NULL);
00861 
00862     while (constants[i].name != NULL) {
00863         PyModule_AddIntConstant(new, (char *)constants[i].name, constants[i].value);
00864         i++;
00865     }
00866     PyDict_SetItemString(PyModule_GetDict(module), name, new);
00867     /* This cause assert() in debug builds if enabled. */
00868 #if 0
00869     Py_DECREF(new);
00870 #endif
00871 }
00872 
00873 static void initConstants(PyObject *module) {
00874     static const CFConstant cstDirection[] = {
00875         { "NORTH", 1 },
00876         { "NORTHEAST", 2 },
00877         { "EAST", 3 },
00878         { "SOUTHEAST", 4 },
00879         { "SOUTH", 5 },
00880         { "SOUTHWEST", 6 },
00881         { "WEST", 7 },
00882         { "NORTHWEST", 8 },
00883         { NULL, 0 }
00884     };
00885 
00886     static const CFConstant cstType[] = {
00887         { "PLAYER", PLAYER },
00888         { "TRANSPORT", TRANSPORT },
00889         { "ROD", ROD },
00890         { "TREASURE", TREASURE },
00891         { "POTION", POTION },
00892         { "FOOD", FOOD },
00893         { "POISON", POISON },
00894         { "BOOK", BOOK },
00895         { "CLOCK", CLOCK },
00896         { "ARROW", ARROW },
00897         { "BOW", BOW },
00898         { "WEAPON", WEAPON },
00899         { "ARMOUR", ARMOUR },
00900         { "PEDESTAL", PEDESTAL },
00901         { "ALTAR", ALTAR },
00902         { "LOCKED_DOOR", LOCKED_DOOR },
00903         { "SPECIAL_KEY", SPECIAL_KEY },
00904         { "MAP", MAP },
00905         { "DOOR", DOOR },
00906         { "KEY", KEY },
00907         { "TIMED_GATE", TIMED_GATE },
00908         { "TRIGGER", TRIGGER },
00909         { "GRIMREAPER", GRIMREAPER },
00910         { "MAGIC_EAR", MAGIC_EAR },
00911         { "TRIGGER_BUTTON", TRIGGER_BUTTON },
00912         { "TRIGGER_ALTAR", TRIGGER_ALTAR },
00913         { "TRIGGER_PEDESTAL", TRIGGER_PEDESTAL },
00914         { "SHIELD", SHIELD },
00915         { "HELMET", HELMET },
00916         { "HORN", HORN },
00917         { "MONEY", MONEY },
00918         { "CLASS", CLASS },
00919         { "AMULET", AMULET },
00920         { "PLAYERMOVER", PLAYERMOVER },
00921         { "TELEPORTER", TELEPORTER },
00922         { "CREATOR", CREATOR },
00923         { "SKILL", SKILL },
00924         { "EXPERIENCE", EXPERIENCE },
00925         { "EARTHWALL", EARTHWALL },
00926         { "GOLEM", GOLEM },
00927         { "THROWN_OBJ", THROWN_OBJ },
00928         { "BLINDNESS", BLINDNESS },
00929         { "GOD", GOD },
00930         { "DETECTOR", DETECTOR },
00931         { "TRIGGER_MARKER", TRIGGER_MARKER },
00932         { "DEAD_OBJECT", DEAD_OBJECT },
00933         { "DRINK", DRINK },
00934         { "MARKER", MARKER },
00935         { "HOLY_ALTAR", HOLY_ALTAR },
00936         { "PLAYER_CHANGER", PLAYER_CHANGER },
00937         { "BATTLEGROUND", BATTLEGROUND },
00938         { "PEACEMAKER", PEACEMAKER },
00939         { "GEM", GEM },
00940         { "FIREWALL", FIREWALL },
00941         { "CHECK_INV", CHECK_INV },
00942         { "MOOD_FLOOR", MOOD_FLOOR },
00943         { "EXIT", EXIT },
00944         { "ENCOUNTER", ENCOUNTER },
00945         { "SHOP_FLOOR", SHOP_FLOOR },
00946         { "SHOP_MAT", SHOP_MAT },
00947         { "RING", RING },
00948         { "FLOOR", FLOOR },
00949         { "FLESH", FLESH },
00950         { "INORGANIC", INORGANIC },
00951         { "SKILL_TOOL", SKILL_TOOL },
00952         { "LIGHTER", LIGHTER },
00953         { "WALL", WALL },
00954         { "MISC_OBJECT", MISC_OBJECT },
00955         { "MONSTER", MONSTER },
00956         { "LAMP", LAMP },
00957         { "DUPLICATOR", DUPLICATOR },
00958         { "SPELLBOOK", SPELLBOOK },
00959         { "CLOAK", CLOAK },
00960         { "SPINNER", SPINNER },
00961         { "GATE", GATE },
00962         { "BUTTON", BUTTON },
00963         { "CF_HANDLE", CF_HANDLE },
00964         { "HOLE", HOLE },
00965         { "TRAPDOOR", TRAPDOOR },
00966         { "SIGN", SIGN },
00967         { "BOOTS", BOOTS },
00968         { "GLOVES", GLOVES },
00969         { "SPELL", SPELL },
00970         { "SPELL_EFFECT", SPELL_EFFECT },
00971         { "CONVERTER", CONVERTER },
00972         { "BRACERS", BRACERS },
00973         { "POISONING", POISONING },
00974         { "SAVEBED", SAVEBED },
00975         { "WAND", WAND },
00976         { "SCROLL", SCROLL },
00977         { "DIRECTOR", DIRECTOR },
00978         { "GIRDLE", GIRDLE },
00979         { "FORCE", FORCE },
00980         { "POTION_EFFECT", POTION_EFFECT },
00981         { "EVENT_CONNECTOR", EVENT_CONNECTOR },
00982         { "CLOSE_CON", CLOSE_CON },
00983         { "CONTAINER", CONTAINER },
00984         { "ARMOUR_IMPROVER", ARMOUR_IMPROVER },
00985         { "WEAPON_IMPROVER", WEAPON_IMPROVER },
00986         { "SKILLSCROLL", SKILLSCROLL },
00987         { "DEEP_SWAMP", DEEP_SWAMP },
00988         { "IDENTIFY_ALTAR", IDENTIFY_ALTAR },
00989         { "SHOP_INVENTORY", SHOP_INVENTORY },
00990         { "RUNE", RUNE },
00991         { "TRAP", TRAP },
00992         { "POWER_CRYSTAL", POWER_CRYSTAL },
00993         { "CORPSE", CORPSE },
00994         { "DISEASE", DISEASE },
00995         { "SYMPTOM", SYMPTOM },
00996         { "BUILDER", BUILDER },
00997         { "MATERIAL", MATERIAL },
00998         { NULL, 0 }
00999     };
01000 
01001     static const CFConstant cstMove[] = {
01002         { "WALK", MOVE_WALK },
01003         { "FLY_LOW", MOVE_FLY_LOW },
01004         { "FLY_HIGH", MOVE_FLY_HIGH },
01005         { "FLYING", MOVE_FLYING },
01006         { "SWIM", MOVE_SWIM },
01007         { "BOAT", MOVE_BOAT },
01008         { "ALL", MOVE_ALL },
01009         { NULL, 0 }
01010     };
01011 
01012     static const CFConstant cstMessageFlag[] = {
01013         { "NDI_BLACK", NDI_BLACK },
01014         { "NDI_WHITE", NDI_WHITE },
01015         { "NDI_NAVY", NDI_NAVY },
01016         { "NDI_RED", NDI_RED },
01017         { "NDI_ORANGE", NDI_ORANGE },
01018         { "NDI_BLUE", NDI_BLUE },
01019         { "NDI_DK_ORANGE", NDI_DK_ORANGE },
01020         { "NDI_GREEN", NDI_GREEN },
01021         { "NDI_LT_GREEN", NDI_LT_GREEN },
01022         { "NDI_GREY", NDI_GREY },
01023         { "NDI_BROWN", NDI_BROWN },
01024         { "NDI_GOLD", NDI_GOLD },
01025         { "NDI_TAN", NDI_TAN },
01026         { "NDI_UNIQUE", NDI_UNIQUE },
01027         { "NDI_ALL", NDI_ALL },
01028         { NULL, 0 }
01029     };
01030 
01031     static const CFConstant cstCostFlag[] = {
01032         { "TRUE", F_TRUE },
01033         { "BUY", F_BUY },
01034         { "SELL", F_SELL },
01035         { "NOBARGAIN", F_NO_BARGAIN },
01036         { "IDENTIFIED", F_IDENTIFIED },
01037         { "NOTCURSED", F_NOT_CURSED },
01038         { NULL, 0 }
01039     };
01040 
01041     static const CFConstant cstAttackType[] = {
01042         { "PHYSICAL", AT_PHYSICAL },
01043         { "MAGIC", AT_MAGIC },
01044         { "FIRE", AT_FIRE },
01045         { "ELECTRICITY", AT_ELECTRICITY },
01046         { "COLD", AT_COLD },
01047         { "CONFUSION", AT_CONFUSION },
01048         { "ACID", AT_ACID },
01049         { "DRAIN", AT_DRAIN },
01050         { "WEAPONMAGIC", AT_WEAPONMAGIC },
01051         { "GHOSTHIT", AT_GHOSTHIT },
01052         { "POISON", AT_POISON },
01053         { "SLOW", AT_SLOW },
01054         { "PARALYZE", AT_PARALYZE },
01055         { "TURN_UNDEAD", AT_TURN_UNDEAD },
01056         { "FEAR", AT_FEAR },
01057         { "CANCELLATION", AT_CANCELLATION },
01058         { "DEPLETE", AT_DEPLETE },
01059         { "DEATH", AT_DEATH },
01060         { "CHAOS", AT_CHAOS },
01061         { "COUNTERSPELL", AT_COUNTERSPELL },
01062         { "GODPOWER", AT_GODPOWER },
01063         { "HOLYWORD", AT_HOLYWORD },
01064         { "BLIND", AT_BLIND },
01065         { "INTERNAL", AT_INTERNAL },
01066         { "LIFE_STEALING", AT_LIFE_STEALING },
01067         { "DISEASE", AT_DISEASE },
01068         { NULL, 0 }
01069     };
01070 
01071     static const CFConstant cstAttackTypeNumber[] = {
01072         { "PHYSICAL", ATNR_PHYSICAL },
01073         { "MAGIC", ATNR_MAGIC },
01074         { "FIRE", ATNR_FIRE },
01075         { "ELECTRICITY", ATNR_ELECTRICITY },
01076         { "COLD", ATNR_COLD },
01077         { "CONFUSION", ATNR_CONFUSION },
01078         { "ACID", ATNR_ACID },
01079         { "DRAIN", ATNR_DRAIN },
01080         { "WEAPONMAGIC", ATNR_WEAPONMAGIC },
01081         { "GHOSTHIT", ATNR_GHOSTHIT },
01082         { "POISON", ATNR_POISON },
01083         { "SLOW", ATNR_SLOW },
01084         { "PARALYZE", ATNR_PARALYZE },
01085         { "TURN_UNDEAD", ATNR_TURN_UNDEAD },
01086         { "FEAR", ATNR_FEAR },
01087         { "CANCELLATION", ATNR_CANCELLATION },
01088         { "DEPLETE", ATNR_DEPLETE },
01089         { "DEATH", ATNR_DEATH },
01090         { "CHAOS", ATNR_CHAOS },
01091         { "COUNTERSPELL", ATNR_COUNTERSPELL },
01092         { "GODPOWER", ATNR_GODPOWER },
01093         { "HOLYWORD", ATNR_HOLYWORD },
01094         { "BLIND", ATNR_BLIND },
01095         { "INTERNAL", ATNR_INTERNAL },
01096         { "LIFE_STEALING", ATNR_LIFE_STEALING },
01097         { "DISEASE", ATNR_DISEASE },
01098         { NULL, 0 }
01099     };
01100 
01101     static const CFConstant cstEventType[] = {
01102         { "APPLY", EVENT_APPLY },
01103         { "ATTACK", EVENT_ATTACK },
01104         { "DEATH", EVENT_DEATH },
01105         { "DROP", EVENT_DROP },
01106         { "PICKUP", EVENT_PICKUP },
01107         { "SAY", EVENT_SAY },
01108         { "STOP", EVENT_STOP },
01109         { "TIME", EVENT_TIME },
01110         { "THROW", EVENT_THROW },
01111         { "TRIGGER", EVENT_TRIGGER },
01112         { "CLOSE", EVENT_CLOSE },
01113         { "TIMER", EVENT_TIMER },
01114         { "DESTROY", EVENT_DESTROY },
01115         { "BORN", EVENT_BORN },
01116         { "CLOCK", EVENT_CLOCK },
01117         { "CRASH", EVENT_CRASH },
01118         { "PLAYER_DEATH", EVENT_PLAYER_DEATH },
01119         { "GKILL", EVENT_GKILL },
01120         { "LOGIN", EVENT_LOGIN },
01121         { "LOGOUT", EVENT_LOGOUT },
01122         { "MAPENTER", EVENT_MAPENTER },
01123         { "MAPLEAVE", EVENT_MAPLEAVE },
01124         { "MAPRESET", EVENT_MAPRESET },
01125         { "REMOVE", EVENT_REMOVE },
01126         { "SHOUT", EVENT_SHOUT },
01127         { "TELL", EVENT_TELL },
01128         { "MUZZLE", EVENT_MUZZLE },
01129         { "KICK", EVENT_KICK },
01130         { "MAPUNLOAD", EVENT_MAPUNLOAD },
01131         { "MAPLOAD", EVENT_MAPLOAD },
01132         { "USER", EVENT_USER },
01133         { NULL, 0 }
01134     };
01135 
01136     static const CFConstant cstTime[] = {
01137         { "HOURS_PER_DAY", HOURS_PER_DAY },
01138         { "DAYS_PER_WEEK", DAYS_PER_WEEK },
01139         { "WEEKS_PER_MONTH", WEEKS_PER_MONTH },
01140         { "MONTHS_PER_YEAR", MONTHS_PER_YEAR },
01141         { "SEASONS_PER_YEAR", SEASONS_PER_YEAR },
01142         { "PERIODS_PER_DAY", PERIODS_PER_DAY },
01143         { NULL, 0 }
01144     };
01145 
01146     addConstants(module, "Direction", cstDirection);
01147     addConstants(module, "Type", cstType);
01148     addConstants(module, "Move", cstMove);
01149     addConstants(module, "MessageFlag", cstMessageFlag);
01150     addConstants(module, "CostFlag", cstCostFlag);
01151     addConstants(module, "AttackType", cstAttackType);
01152     addConstants(module, "AttackTypeNumber", cstAttackTypeNumber);
01153     addConstants(module, "EventType", cstEventType);
01154     addSimpleConstants(module, "Time", cstTime);
01155 }
01156 
01157 extern PyMODINIT_FUNC initcjson(void);
01158 
01159 CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) {
01160     PyObject *m, *d;
01161     int i;
01162 
01163     cf_init_plugin(gethooksptr);
01164     cf_log(llevDebug, "CFPython 2.0a init\n");
01165 
01166     init_object_assoc_table();
01167     init_map_assoc_table();
01168 
01169 #ifdef IS_PY26
01170     Py_Py3kWarningFlag++;
01171 #endif
01172 
01173     Py_Initialize();
01174     Crossfire_ObjectType.tp_new = PyType_GenericNew;
01175     Crossfire_MapType.tp_new    = PyType_GenericNew;
01176     Crossfire_PlayerType.tp_new = PyType_GenericNew;
01177     Crossfire_ArchetypeType.tp_new = PyType_GenericNew;
01178     Crossfire_PartyType.tp_new = PyType_GenericNew;
01179     Crossfire_RegionType.tp_new = PyType_GenericNew;
01180     PyType_Ready(&Crossfire_ObjectType);
01181     PyType_Ready(&Crossfire_MapType);
01182     PyType_Ready(&Crossfire_PlayerType);
01183     PyType_Ready(&Crossfire_ArchetypeType);
01184     PyType_Ready(&Crossfire_PartyType);
01185     PyType_Ready(&Crossfire_RegionType);
01186 
01187     m = Py_InitModule("Crossfire", CFPythonMethods);
01188     d = PyModule_GetDict(m);
01189     Py_INCREF(&Crossfire_ObjectType);
01190     Py_INCREF(&Crossfire_MapType);
01191     Py_INCREF(&Crossfire_PlayerType);
01192     Py_INCREF(&Crossfire_ArchetypeType);
01193     Py_INCREF(&Crossfire_PartyType);
01194     Py_INCREF(&Crossfire_RegionType);
01195 
01196     PyModule_AddObject(m, "Object", (PyObject *)&Crossfire_ObjectType);
01197     PyModule_AddObject(m, "Map", (PyObject *)&Crossfire_MapType);
01198     PyModule_AddObject(m, "Player", (PyObject *)&Crossfire_PlayerType);
01199     PyModule_AddObject(m, "Archetype", (PyObject *)&Crossfire_ArchetypeType);
01200     PyModule_AddObject(m, "Party", (PyObject *)&Crossfire_PartyType);
01201     PyModule_AddObject(m, "Region", (PyObject *)&Crossfire_RegionType);
01202 
01203     PyModule_AddObject(m, "LogError", Py_BuildValue("i", llevError));
01204     PyModule_AddObject(m, "LogInfo", Py_BuildValue("i", llevInfo));
01205     PyModule_AddObject(m, "LogDebug", Py_BuildValue("i", llevDebug));
01206     PyModule_AddObject(m, "LogMonster", Py_BuildValue("i", llevMonster));
01207 
01208     CFPythonError = PyErr_NewException("Crossfire.error", NULL, NULL);
01209     PyDict_SetItemString(d, "error", CFPythonError);
01210     for (i = 0; i < NR_CUSTOM_CMD; i++) {
01211         CustomCommand[i].name   = NULL;
01212         CustomCommand[i].script = NULL;
01213         CustomCommand[i].speed  = 0.0;
01214     }
01215     initConstants(m);
01216     private_data = PyDict_New();
01217     shared_data = PyDict_New();
01218 
01219     /* add cjson module*/
01220     initcjson();
01221     return 0;
01222 }
01223 
01224 CF_PLUGIN void *getPluginProperty(int *type, ...) {
01225     va_list args;
01226     const char *propname;
01227     int i, size;
01228     command_array_struct *rtn_cmd;
01229     char *buf;
01230 
01231     va_start(args, type);
01232     propname = va_arg(args, const char *);
01233 
01234     if (!strcmp(propname, "command?")) {
01235         const char *cmdname;
01236         cmdname = va_arg(args, const char *);
01237         rtn_cmd = va_arg(args, command_array_struct *);
01238         va_end(args);
01239 
01240         for (i = 0; i < NR_CUSTOM_CMD; i++) {
01241             if (CustomCommand[i].name != NULL) {
01242                 if (!strcmp(CustomCommand[i].name, cmdname)) {
01243                     rtn_cmd->name = CustomCommand[i].name;
01244                     rtn_cmd->time = (float)CustomCommand[i].speed;
01245                     rtn_cmd->func = cfpython_runPluginCommand;
01246                     current_command = i;
01247                     return rtn_cmd;
01248                 }
01249             }
01250         }
01251         return NULL;
01252     } else if (!strcmp(propname, "Identification")) {
01253         buf = va_arg(args, char *);
01254         size = va_arg(args, int);
01255         va_end(args);
01256         snprintf(buf, size, PLUGIN_NAME);
01257         return NULL;
01258     } else if (!strcmp(propname, "FullName")) {
01259         buf = va_arg(args, char *);
01260         size = va_arg(args, int);
01261         va_end(args);
01262         snprintf(buf, size, PLUGIN_VERSION);
01263         return NULL;
01264     }
01265     va_end(args);
01266     return NULL;
01267 }
01268 
01269 CF_PLUGIN int cfpython_runPluginCommand(object *op, char *params) {
01270     char buf[1024], path[1024];
01271     CFPContext *context;
01272     static int rv = 0;
01273 
01274     rv = 0;
01275 
01276     if (current_command < 0) {
01277         cf_log(llevError, "Illegal call of cfpython_runPluginCommand, call find_plugin_command first.\n");
01278         return 1;
01279     }
01280     snprintf(buf, sizeof(buf), "%s.py", cf_get_maps_directory(CustomCommand[current_command].script, path, sizeof(path)));
01281 
01282     context = malloc(sizeof(CFPContext));
01283     context->message[0] = 0;
01284 
01285     context->who         = Crossfire_Object_wrap(op);
01286     context->activator   = NULL;
01287     context->third       = NULL;
01288     context->fix         = 0;
01289     snprintf(context->script, sizeof(context->script), "%s", buf);
01290     if (params)
01291         snprintf(context->options, sizeof(context->options), "%s", params);
01292     else
01293         context->options[0] = 0;
01294     context->returnvalue = 1; /* Default is "command successful" */
01295 
01296     current_command = -999;
01297     if (!do_script(context, 0)) {
01298         freeContext(context);
01299         return rv;
01300     }
01301 
01302     context = popContext();
01303     rv = context->returnvalue;
01304     freeContext(context);
01305 /*    printf("Execution complete"); */
01306     return rv;
01307 }
01308 
01309 CF_PLUGIN int postInitPlugin(void) {
01310     PyObject *scriptfile;
01311     char path[1024];
01312 
01313     cf_log(llevDebug, "CFPython 2.0a post init\n");
01314     initContextStack();
01315     cf_system_register_global_event(EVENT_BORN, PLUGIN_NAME, cfpython_globalEventListener);
01316     cf_system_register_global_event(EVENT_CLOCK, PLUGIN_NAME, cfpython_globalEventListener);
01317     /*registerGlobalEvent(NULL, EVENT_CRASH, PLUGIN_NAME, cfpython_globalEventListener);*/
01318     cf_system_register_global_event(EVENT_PLAYER_DEATH, PLUGIN_NAME, cfpython_globalEventListener);
01319     cf_system_register_global_event(EVENT_GKILL, PLUGIN_NAME, cfpython_globalEventListener);
01320     cf_system_register_global_event(EVENT_LOGIN, PLUGIN_NAME, cfpython_globalEventListener);
01321     cf_system_register_global_event(EVENT_LOGOUT, PLUGIN_NAME, cfpython_globalEventListener);
01322     cf_system_register_global_event(EVENT_MAPENTER, PLUGIN_NAME, cfpython_globalEventListener);
01323     cf_system_register_global_event(EVENT_MAPLEAVE, PLUGIN_NAME, cfpython_globalEventListener);
01324     cf_system_register_global_event(EVENT_MAPRESET, PLUGIN_NAME, cfpython_globalEventListener);
01325     cf_system_register_global_event(EVENT_REMOVE, PLUGIN_NAME, cfpython_globalEventListener);
01326     cf_system_register_global_event(EVENT_SHOUT, PLUGIN_NAME, cfpython_globalEventListener);
01327     cf_system_register_global_event(EVENT_TELL, PLUGIN_NAME, cfpython_globalEventListener);
01328     cf_system_register_global_event(EVENT_MUZZLE, PLUGIN_NAME, cfpython_globalEventListener);
01329     cf_system_register_global_event(EVENT_KICK, PLUGIN_NAME, cfpython_globalEventListener);
01330     cf_system_register_global_event(EVENT_MAPUNLOAD, PLUGIN_NAME, cfpython_globalEventListener);
01331     cf_system_register_global_event(EVENT_MAPLOAD, PLUGIN_NAME, cfpython_globalEventListener);
01332 
01333     scriptfile = PyFile_FromString(cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)), "r");
01334     if (scriptfile != NULL) {
01335         PyRun_SimpleFile(PyFile_AsFile(scriptfile), cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)));
01336         Py_DECREF(scriptfile);
01337     }
01338 
01339     return 0;
01340 }
01341 
01342 CF_PLUGIN void *cfpython_globalEventListener(int *type, ...) {
01343     va_list args;
01344     static int rv = 0;
01345     CFPContext *context;
01346     char *buf;
01347     player *pl;
01348     object *op;
01349     context = malloc(sizeof(CFPContext));
01350 
01351     rv = 0;
01352 
01353     va_start(args, type);
01354     context->event_code = va_arg(args, int);
01355 
01356     context->message[0] = 0;
01357 
01358     context->who         = NULL;
01359     context->activator   = NULL;
01360     context->third       = NULL;
01361     context->event       = NULL;
01362     rv = context->returnvalue = 0;
01363     cf_get_maps_directory("python/events/python_event.py", context->script, sizeof(context->script));
01364     strcpy(context->options, "");
01365     switch (context->event_code) {
01366     case EVENT_CRASH:
01367         cf_log(llevDebug, "Unimplemented for now\n");
01368         break;
01369 
01370     case EVENT_BORN:
01371         op = va_arg(args, object *);
01372         context->activator = Crossfire_Object_wrap(op);
01373         snprintf(context->options, sizeof(context->options), "born");
01374         break;
01375 
01376     case EVENT_PLAYER_DEATH:
01377         op = va_arg(args, object *);
01378         context->who = Crossfire_Object_wrap(op);
01379         snprintf(context->options, sizeof(context->options), "death");
01380         break;
01381 
01382     case EVENT_GKILL:
01383         op = va_arg(args, object *);
01384         context->who = Crossfire_Object_wrap(op);
01385         context->activator = Crossfire_Object_wrap(op);
01386         snprintf(context->options, sizeof(context->options), "gkill");
01387         break;
01388 
01389     case EVENT_LOGIN:
01390         pl = va_arg(args, player *);
01391         context->activator = Crossfire_Object_wrap(pl->ob);
01392         buf = va_arg(args, char *);
01393         if (buf != NULL)
01394             snprintf(context->message, sizeof(context->message), "%s", buf);
01395         snprintf(context->options, sizeof(context->options), "login");
01396         break;
01397 
01398     case EVENT_LOGOUT:
01399         pl = va_arg(args, player *);
01400         context->activator = Crossfire_Object_wrap(pl->ob);
01401         buf = va_arg(args, char *);
01402         if (buf != NULL)
01403             snprintf(context->message, sizeof(context->message), "%s", buf);
01404         snprintf(context->options, sizeof(context->options), "logout");
01405         break;
01406 
01407     case EVENT_REMOVE:
01408         op = va_arg(args, object *);
01409         context->activator = Crossfire_Object_wrap(op);
01410         snprintf(context->options, sizeof(context->options), "remove");
01411         break;
01412 
01413     case EVENT_SHOUT:
01414         op = va_arg(args, object *);
01415         context->activator = Crossfire_Object_wrap(op);
01416         buf = va_arg(args, char *);
01417         if (buf != NULL)
01418             snprintf(context->message, sizeof(context->message), "%s", buf);
01419         snprintf(context->options, sizeof(context->options), "shout");
01420         break;
01421 
01422     case EVENT_MUZZLE:
01423         op = va_arg(args, object *);
01424         context->activator = Crossfire_Object_wrap(op);
01425         buf = va_arg(args, char *);
01426         if (buf != NULL)
01427             snprintf(context->message, sizeof(context->message), "%s", buf);
01428         snprintf(context->options, sizeof(context->options), "muzzle");
01429         break;
01430 
01431     case EVENT_KICK:
01432         op = va_arg(args, object *);
01433         context->activator = Crossfire_Object_wrap(op);
01434         buf = va_arg(args, char *);
01435         if (buf != NULL)
01436             snprintf(context->message, sizeof(context->message), "%s", buf);
01437         snprintf(context->options, sizeof(context->options), "kick");
01438         break;
01439 
01440     case EVENT_MAPENTER:
01441         op = va_arg(args, object *);
01442         context->activator = Crossfire_Object_wrap(op);
01443         context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
01444         snprintf(context->options, sizeof(context->options), "mapenter");
01445         break;
01446 
01447     case EVENT_MAPLEAVE:
01448         op = va_arg(args, object *);
01449         context->activator = Crossfire_Object_wrap(op);
01450         context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
01451         snprintf(context->options, sizeof(context->options), "mapleave");
01452         break;
01453 
01454     case EVENT_CLOCK:
01455         snprintf(context->options, sizeof(context->options), "clock");
01456         break;
01457 
01458     case EVENT_MAPRESET:
01459         context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
01460         snprintf(context->options, sizeof(context->options), "mapreset");
01461         break;
01462 
01463     case EVENT_TELL:
01464         op = va_arg(args, object *);
01465         buf = va_arg(args, char *);
01466         context->activator = Crossfire_Object_wrap(op);
01467         if (buf != NULL)
01468             snprintf(context->message, sizeof(context->message), "%s", buf);
01469         op = va_arg(args, object *);
01470         context->third = Crossfire_Object_wrap(op);
01471         snprintf(context->options, sizeof(context->options), "tell");
01472         break;
01473 
01474     case EVENT_MAPUNLOAD:
01475         context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
01476         snprintf(context->options, sizeof(context->options), "mapunload");
01477         break;
01478 
01479     case EVENT_MAPLOAD:
01480         context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
01481         snprintf(context->options, sizeof(context->options), "mapload");
01482         break;
01483     }
01484     va_end(args);
01485     context->returnvalue = 0;
01486 
01487     if (!do_script(context, 1)) {
01488         freeContext(context);
01489         return &rv;
01490     }
01491 
01492     context = popContext();
01493     rv = context->returnvalue;
01494 
01495     /* Invalidate freed map wrapper. */
01496     if (context->event_code == EVENT_MAPUNLOAD)
01497         Handle_Map_Unload_Hook((Crossfire_Map *)context->who);
01498 
01499     freeContext(context);
01500 
01501     return &rv;
01502 }
01503 
01504 CF_PLUGIN void *eventListener(int *type, ...) {
01505     static int rv = 0;
01506     va_list args;
01507     char *buf;
01508     CFPContext *context;
01509     object *event;
01510 
01511     rv = 0;
01512 
01513     context = malloc(sizeof(CFPContext));
01514 
01515     context->message[0] = 0;
01516 
01517     va_start(args, type);
01518 
01519     context->who         = Crossfire_Object_wrap(va_arg(args, object *));
01520     context->activator   = Crossfire_Object_wrap(va_arg(args, object *));
01521     context->third       = Crossfire_Object_wrap(va_arg(args, object *));
01522     buf = va_arg(args, char *);
01523     if (buf != NULL)
01524         snprintf(context->message, sizeof(context->message), "%s", buf);
01525     context->fix         = va_arg(args, int);
01526     event = va_arg(args, object *);
01527     context->event_code  = event->subtype;
01528     context->event       = Crossfire_Object_wrap(event);
01529     cf_get_maps_directory(event->slaying, context->script, sizeof(context->script));
01530     snprintf(context->options, sizeof(context->options), "%s", event->name);
01531     context->returnvalue = 0;
01532 
01533     va_end(args);
01534 
01535     if (!do_script(context, 0)) {
01536         freeContext(context);
01537         return &rv;
01538     }
01539 
01540     context = popContext();
01541     rv = context->returnvalue;
01542     freeContext(context);
01543     return &rv;
01544 }
01545 
01546 CF_PLUGIN int   closePlugin(void) {
01547     cf_log(llevDebug, "CFPython 2.0a closing\n");
01548     Py_Finalize();
01549     return 0;
01550 }