Atrinik Server 2.5
plugins/plugin_python/plugin_python.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #ifdef WIN32
00031 #   include <fcntl.h>
00032 #endif
00033 
00034 #include <plugin_python.h>
00035 
00036 #include <compile.h>
00037 #include <eval.h>
00038 #ifdef STR
00039 /* STR is redefined in node.h. Since this file doesn't use STR, we remove it */
00040 #undef STR
00041 #endif
00042 #include <node.h>
00043 
00045 struct plugin_hooklist *hooks;
00046 
00048 PyObject *AtrinikError;
00049 
00051 static PythonContext *context_stack;
00053 PythonContext *current_context;
00054 
00057 /* @cparser
00058  * @page plugin_python_constants Python constants
00059  * <h2>Python constants</h2>
00060  * List of the Python plugin constants and their meaning. */
00061 static const Atrinik_Constant constants[] =
00062 {
00063     {"NORTH", NORTH},
00064     {"NORTHEAST", NORTHEAST},
00065     {"EAST", EAST},
00066     {"SOUTHEAST", SOUTHEAST},
00067     {"SOUTH", SOUTH},
00068     {"SOUTHWEST", SOUTHWEST},
00069     {"WEST", WEST},
00070     {"NORTHWEST", NORTHWEST},
00071 
00072     {"llevSystem", llevSystem},
00073     {"llevError", llevError},
00074     {"llevBug", llevBug},
00075     {"llevInfo", llevInfo},
00076     {"llevDebug", llevDebug},
00077     {"llevChat", llevChat},
00078 
00079     {"PLUGIN_EVENT_NORMAL", PLUGIN_EVENT_NORMAL},
00080     {"PLUGIN_EVENT_GLOBAL", PLUGIN_EVENT_GLOBAL},
00081     {"PLUGIN_EVENT_MAP", PLUGIN_EVENT_MAP},
00082 
00083     {"EVENT_APPLY", EVENT_APPLY},
00084     {"EVENT_ATTACK", EVENT_ATTACK},
00085     {"EVENT_DEATH", EVENT_DEATH},
00086     {"EVENT_DROP", EVENT_DROP},
00087     {"EVENT_PICKUP", EVENT_PICKUP},
00088     {"EVENT_SAY", EVENT_SAY},
00089     {"EVENT_STOP", EVENT_STOP},
00090     {"EVENT_TIME", EVENT_TIME},
00091     {"EVENT_THROW", EVENT_THROW},
00092     {"EVENT_TRIGGER", EVENT_TRIGGER},
00093     {"EVENT_CLOSE", EVENT_CLOSE},
00094     {"EVENT_TIMER", EVENT_TIMER},
00095     {"EVENT_ASK_SHOW", EVENT_ASK_SHOW},
00096 
00097     {"MEVENT_ENTER", MEVENT_ENTER},
00098     {"MEVENT_LEAVE", MEVENT_LEAVE},
00099     {"MEVENT_RESET", MEVENT_RESET},
00100     {"MEVENT_SPELL_CAST", MEVENT_SPELL_CAST},
00101     {"MEVENT_SKILL_USED", MEVENT_SKILL_USED},
00102     {"MEVENT_DROP", MEVENT_DROP},
00103     {"MEVENT_PICK", MEVENT_PICK},
00104     {"MEVENT_PUT", MEVENT_PUT},
00105     {"MEVENT_APPLY", MEVENT_APPLY},
00106     {"MEVENT_LOGIN", MEVENT_LOGIN},
00107     {"MEVENT_CMD_DROP", MEVENT_CMD_DROP},
00108     {"MEVENT_CMD_TAKE", MEVENT_CMD_TAKE},
00109     {"MEVENT_EXAMINE", MEVENT_EXAMINE},
00110 
00111     {"GEVENT_BORN", GEVENT_BORN},
00112     {"GEVENT_LOGIN", GEVENT_LOGIN},
00113     {"GEVENT_LOGOUT", GEVENT_LOGOUT},
00114     {"GEVENT_PLAYER_DEATH", GEVENT_PLAYER_DEATH},
00115     {"GEVENT_CACHE_REMOVED", GEVENT_CACHE_REMOVED},
00116 
00117     {"MAP_INFO_NORMAL", MAP_INFO_NORMAL},
00118     {"MAP_INFO_ALL", MAP_INFO_ALL},
00119 
00120     {"COST_TRUE", COST_TRUE},
00121     {"COST_BUY", COST_BUY},
00122     {"COST_SELL", COST_SELL},
00123 
00124     {"APPLY_TOGGLE", 0},
00125     {"APPLY_ALWAYS", AP_APPLY},
00126     {"UNAPPLY_ALWAYS", AP_UNAPPLY},
00127     {"UNAPPLY_NO_MERGE", AP_NO_MERGE},
00128     {"UNAPPLY_IGNORE_CURSE", AP_IGNORE_CURSE},
00129     {"APPLY_NO_EVENT", AP_NO_EVENT},
00130 
00131     {"MAXLEVEL", MAXLEVEL},
00132 
00133     {"CAST_NORMAL", CAST_NORMAL},
00134     {"CAST_WAND", CAST_WAND},
00135     {"CAST_ROD", CAST_ROD},
00136     {"CAST_HORN", CAST_HORN},
00137     {"CAST_SCROLL", CAST_SCROLL},
00138     {"CAST_POTION", CAST_POTION},
00139     {"CAST_NPC", CAST_NPC},
00140 
00141     {"IDENTIFY_NORMAL", IDENTIFY_NORMAL},
00142     {"IDENTIFY_ALL", IDENTIFY_ALL},
00143     {"IDENTIFY_MARKED", IDENTIFY_MARKED},
00144 
00145     {"CLONE_WITH_INVENTORY", 0},
00146     {"CLONE_WITHOUT_INVENTORY", 1},
00147 
00148     {"EXP_AGILITY", EXP_AGILITY},
00149     {"EXP_MENTAL", EXP_MENTAL},
00150     {"EXP_MAGICAL", EXP_MAGICAL},
00151     {"EXP_PERSONAL", EXP_PERSONAL},
00152     {"EXP_PHYSICAL", EXP_PHYSICAL},
00153     {"EXP_WISDOM", EXP_WISDOM},
00154 
00155     {"NDI_SAY", NDI_SAY},
00156     {"NDI_SHOUT", NDI_SHOUT},
00157     {"NDI_TELL", NDI_TELL},
00158     {"NDI_PLAYER", NDI_PLAYER},
00159     {"NDI_ANIM", NDI_ANIM},
00160     {"NDI_EMOTE", NDI_EMOTE},
00161     {"NDI_ALL", NDI_ALL},
00162 
00163     {"PLAYER_EQUIP_MAIL", PLAYER_EQUIP_MAIL},
00164     {"PLAYER_EQUIP_GAUNTLET", PLAYER_EQUIP_GAUNTLET},
00165     {"PLAYER_EQUIP_BRACER", PLAYER_EQUIP_BRACER},
00166     {"PLAYER_EQUIP_HELM", PLAYER_EQUIP_HELM},
00167     {"PLAYER_EQUIP_BOOTS", PLAYER_EQUIP_BOOTS},
00168     {"PLAYER_EQUIP_CLOAK", PLAYER_EQUIP_CLOAK},
00169     {"PLAYER_EQUIP_GIRDLE", PLAYER_EQUIP_GIRDLE},
00170     {"PLAYER_EQUIP_SHIELD", PLAYER_EQUIP_SHIELD},
00171     {"PLAYER_EQUIP_RRING", PLAYER_EQUIP_RRING},
00172     {"PLAYER_EQUIP_LRING", PLAYER_EQUIP_LRING},
00173     {"PLAYER_EQUIP_AMULET", PLAYER_EQUIP_AMULET},
00174     {"PLAYER_EQUIP_WEAPON", PLAYER_EQUIP_WEAPON},
00175     {"PLAYER_EQUIP_BOW", PLAYER_EQUIP_BOW},
00176 
00177     {"QUEST_TYPE_SPECIAL", QUEST_TYPE_SPECIAL},
00178     {"QUEST_TYPE_KILL", QUEST_TYPE_KILL},
00179     {"QUEST_TYPE_KILL_ITEM", QUEST_TYPE_KILL_ITEM},
00180     {"QUEST_TYPE_MULTI", QUEST_TYPE_MULTI},
00181     {"QUEST_STATUS_COMPLETED", QUEST_STATUS_COMPLETED},
00182 
00183     {"PARTY_MESSAGE_STATUS", PARTY_MESSAGE_STATUS},
00184     {"PARTY_MESSAGE_CHAT", PARTY_MESSAGE_CHAT},
00185 
00186     {"ATNR_IMPACT", ATNR_IMPACT},
00187     {"ATNR_SLASH", ATNR_SLASH},
00188     {"ATNR_CLEAVE", ATNR_CLEAVE},
00189     {"ATNR_PIERCE", ATNR_PIERCE},
00190     {"ATNR_WEAPON_MAGIC", ATNR_WEAPON_MAGIC},
00191     {"ATNR_FIRE", ATNR_FIRE},
00192     {"ATNR_COLD", ATNR_COLD},
00193     {"ATNR_ELECTRICITY", ATNR_ELECTRICITY},
00194     {"ATNR_POISON", ATNR_POISON},
00195     {"ATNR_ACID", ATNR_ACID},
00196     {"ATNR_MAGIC", ATNR_MAGIC},
00197     {"ATNR_MIND", ATNR_MIND},
00198     {"ATNR_BLIND", ATNR_BLIND},
00199     {"ATNR_PARALYZE", ATNR_PARALYZE},
00200     {"ATNR_FORCE", ATNR_FORCE},
00201     {"ATNR_GODPOWER", ATNR_GODPOWER},
00202     {"ATNR_CHAOS", ATNR_CHAOS},
00203     {"ATNR_DRAIN", ATNR_DRAIN},
00204     {"ATNR_SLOW", ATNR_SLOW},
00205     {"ATNR_CONFUSION", ATNR_CONFUSION},
00206     {"ATNR_INTERNAL", ATNR_INTERNAL},
00207     {"NROFATTACKS", NROFATTACKS},
00208 
00209     {"TERRAIN_NOTHING", TERRAIN_NOTHING},
00210     {"TERRAIN_AIRBREATH", TERRAIN_NOTHING},
00211     {"TERRAIN_WATERWALK", TERRAIN_WATERWALK},
00212     {"TERRAIN_WATERBREATH", TERRAIN_WATERBREATH},
00213     {"TERRAIN_FIREWALK", TERRAIN_FIREWALK},
00214     {"TERRAIN_FIREBREATH", TERRAIN_FIREBREATH},
00215     {"TERRAIN_CLOUDWALK", TERRAIN_CLOUDWALK},
00216     {"TERRAIN_ALL", TERRAIN_ALL},
00217 
00218     {"P_BLOCKSVIEW", P_BLOCKSVIEW},
00219     {"P_NO_MAGIC", P_NO_MAGIC},
00220     {"P_NO_PASS", P_NO_PASS},
00221     {"P_IS_PLAYER", P_IS_PLAYER},
00222     {"P_IS_ALIVE", P_IS_ALIVE},
00223     {"P_NO_CLERIC", P_NO_CLERIC},
00224     {"P_PLAYER_ONLY", P_PLAYER_ONLY},
00225     {"P_DOOR_CLOSED", P_DOOR_CLOSED},
00226     {"P_CHECK_INV", P_CHECK_INV},
00227     {"P_NO_PVP", P_NO_PVP},
00228     {"P_PASS_THRU", P_PASS_THRU},
00229     {"P_MAGIC_EAR", P_MAGIC_EAR},
00230     {"P_WALK_ON", P_WALK_ON},
00231     {"P_WALK_OFF", P_WALK_OFF},
00232     {"P_FLY_OFF", P_FLY_OFF},
00233     {"P_FLY_ON", P_FLY_ON},
00234     {"P_MAGIC_MIRROR", P_MAGIC_MIRROR},
00235     {"P_OUTDOOR", P_OUTDOOR},
00236     {"P_OUT_OF_MAP", P_OUT_OF_MAP},
00237     {"P_FLAGS_ONLY", P_FLAGS_ONLY},
00238     {"P_FLAGS_UPDATE", P_FLAGS_UPDATE},
00239     {"P_NEED_UPDATE", P_NEED_UPDATE},
00240     {"P_NO_ERROR", P_NO_ERROR},
00241     {"P_NO_TERRAIN", P_NO_TERRAIN},
00242 
00243     {"CMD_SOUND_EFFECT", CMD_SOUND_EFFECT},
00244     {"CMD_SOUND_BACKGROUND", CMD_SOUND_BACKGROUND},
00245     {"CMD_SOUND_ABSOLUTE", CMD_SOUND_ABSOLUTE},
00246 
00247     {"BANK_SYNTAX_ERROR", BANK_SYNTAX_ERROR},
00248     {"BANK_SUCCESS", BANK_SUCCESS},
00249 
00250     {"BANK_WITHDRAW_HIGH", BANK_WITHDRAW_HIGH},
00251     {"BANK_WITHDRAW_MISSING", BANK_WITHDRAW_MISSING},
00252     {"BANK_WITHDRAW_OVERWEIGHT", BANK_WITHDRAW_OVERWEIGHT},
00253 
00254     {"BANK_DEPOSIT_COPPER", BANK_DEPOSIT_COPPER},
00255     {"BANK_DEPOSIT_SILVER", BANK_DEPOSIT_SILVER},
00256     {"BANK_DEPOSIT_GOLD", BANK_DEPOSIT_GOLD},
00257     {"BANK_DEPOSIT_MITHRIL", BANK_DEPOSIT_MITHRIL},
00258 
00259     {"AROUND_ALL", AROUND_ALL},
00260     {"AROUND_WALL", AROUND_WALL},
00261     {"AROUND_BLOCKSVIEW", AROUND_BLOCKSVIEW},
00262     {"AROUND_PLAYER_ONLY", AROUND_PLAYER_ONLY},
00263 
00264     {"LAYER_SYS", LAYER_SYS},
00265     {"LAYER_FLOOR", LAYER_FLOOR},
00266     {"LAYER_FMASK", LAYER_FMASK},
00267     {"LAYER_ITEM", LAYER_ITEM},
00268     {"LAYER_ITEM2", LAYER_ITEM2},
00269     {"LAYER_WALL", LAYER_WALL},
00270     {"LAYER_LIVING", LAYER_LIVING},
00271     {"LAYER_EFFECT", LAYER_EFFECT},
00272 
00273     {"INVENTORY_ONLY", INVENTORY_ONLY},
00274     {"INVENTORY_CONTAINERS", INVENTORY_CONTAINERS},
00275     {"INVENTORY_ALL", INVENTORY_ALL},
00276 
00277     {"GT_ENVIRONMENT", GT_ENVIRONMENT},
00278     {"GT_INVISIBLE", GT_INVISIBLE},
00279     {"GT_STARTEQUIP", GT_STARTEQUIP},
00280     {"GT_APPLY", GT_APPLY},
00281     {"GT_ONLY_GOOD", GT_ONLY_GOOD},
00282     {"GT_UPDATE_INV", GT_UPDATE_INV},
00283     {"GT_NO_VALUE", GT_NO_VALUE},
00284 
00285     {"SIZEOFFREE", SIZEOFFREE},
00286     {"SIZEOFFREE1", SIZEOFFREE1},
00287     {"SIZEOFFREE2", SIZEOFFREE2},
00288 
00289     {"NROFREALSPELLS", NROFREALSPELLS},
00290 
00291     {NULL, 0}
00292 };
00293 /* @endcparser */
00294 
00296 /* @cparser
00297  * @page plugin_python_constants_types Python game object type constants
00298  * <h2>Python game object type constants</h2>
00299  * List of the Python plugin game object type constants and their meaning. */
00300 static const Atrinik_Constant constants_types[] =
00301 {
00302     {"PLAYER", PLAYER},
00303     {"BULLET", BULLET},
00304     {"ROD", ROD},
00305     {"TREASURE", TREASURE},
00306     {"POTION", POTION},
00307     {"FOOD", FOOD},
00308     {"POISON", POISON},
00309     {"BOOK", BOOK},
00310     {"CLOCK", CLOCK},
00311     {"LIGHTNING", LIGHTNING},
00312     {"ARROW", ARROW},
00313     {"BOW", BOW},
00314     {"WEAPON", WEAPON},
00315     {"ARMOUR", ARMOUR},
00316     {"PEDESTAL", PEDESTAL},
00317     {"ALTAR", ALTAR},
00318     {"CONFUSION", CONFUSION},
00319     {"DOOR", DOOR},
00320     {"KEY", KEY},
00321     {"MAP", MAP},
00322     {"MMISSILE", MMISSILE},
00323     {"TIMED_GATE", TIMED_GATE},
00324     {"TRIGGER", TRIGGER},
00325     {"MAGIC_EAR", MAGIC_EAR},
00326     {"TRIGGER_BUTTON", TRIGGER_BUTTON},
00327     {"TRIGGER_ALTAR", TRIGGER_ALTAR},
00328     {"TRIGGER_PEDESTAL", TRIGGER_PEDESTAL},
00329     {"SHIELD", SHIELD},
00330     {"HELMET", HELMET},
00331     {"HORN", HORN},
00332     {"MONEY", MONEY},
00333     {"CLASS", CLASS},
00334     {"GRAVESTONE", GRAVESTONE},
00335     {"AMULET", AMULET},
00336     {"PLAYERMOVER", PLAYERMOVER},
00337     {"TELEPORTER", TELEPORTER},
00338     {"CREATOR", CREATOR},
00339     {"SKILL", SKILL},
00340     {"EXPERIENCE", EXPERIENCE},
00341     {"BOMB", BOMB},
00342     {"THROWN_OBJ", THROWN_OBJ},
00343     {"BLINDNESS", BLINDNESS},
00344     {"GOD", GOD},
00345     {"DETECTOR", DETECTOR},
00346     {"SKILL_ITEM", SKILL_ITEM},
00347     {"DEAD_OBJECT", DEAD_OBJECT},
00348     {"DRINK", DRINK},
00349     {"MARKER", MARKER},
00350     {"HOLY_ALTAR", HOLY_ALTAR},
00351     {"PEARL", PEARL},
00352     {"GEM", GEM},
00353     {"FIREWALL", FIREWALL},
00354     {"CHECK_INV", CHECK_INV},
00355     {"MOOD_FLOOR", MOOD_FLOOR},
00356     {"EXIT", EXIT},
00357     {"SHOP_FLOOR", SHOP_FLOOR},
00358     {"SHOP_MAT", SHOP_MAT},
00359     {"RING", RING},
00360     {"FLOOR", FLOOR},
00361     {"FLESH", FLESH},
00362     {"INORGANIC", INORGANIC},
00363     {"LIGHT_APPLY", LIGHT_APPLY},
00364     {"LIGHTER", LIGHTER},
00365     {"WALL", WALL},
00366     {"LIGHT_SOURCE", LIGHT_SOURCE},
00367     {"MISC_OBJECT", MISC_OBJECT},
00368     {"MONSTER", MONSTER},
00369     {"SPAWN_POINT", SPAWN_POINT},
00370     {"LIGHT_REFILL", LIGHT_REFILL},
00371     {"SPAWN_POINT_MOB", SPAWN_POINT_MOB},
00372     {"SPAWN_POINT_INFO", SPAWN_POINT_INFO},
00373     {"SPELLBOOK", SPELLBOOK},
00374     {"ORGANIC", ORGANIC},
00375     {"CLOAK", CLOAK},
00376     {"CONE", CONE},
00377     {"SPINNER", SPINNER},
00378     {"GATE", GATE},
00379     {"BUTTON", BUTTON},
00380     {"HANDLE", HANDLE},
00381     {"PIT", PIT},
00382     {"TRAPDOOR", TRAPDOOR},
00383     {"WORD_OF_RECALL", WORD_OF_RECALL},
00384     {"SIGN", SIGN},
00385     {"BOOTS", BOOTS},
00386     {"GLOVES", GLOVES},
00387     {"BASE_INFO", BASE_INFO},
00388     {"RANDOM_DROP", RANDOM_DROP},
00389     {"CONVERTER", CONVERTER},
00390     {"BRACERS", BRACERS},
00391     {"POISONING", POISONING},
00392     {"SAVEBED", SAVEBED},
00393     {"WAND", WAND},
00394     {"ABILITY", ABILITY},
00395     {"SCROLL", SCROLL},
00396     {"DIRECTOR", DIRECTOR},
00397     {"GIRDLE", GIRDLE},
00398     {"FORCE", FORCE},
00399     {"POTION_EFFECT", POTION_EFFECT},
00400     {"JEWEL", JEWEL},
00401     {"NUGGET", NUGGET},
00402     {"EVENT_OBJECT", EVENT_OBJECT},
00403     {"WAYPOINT_OBJECT", WAYPOINT_OBJECT},
00404     {"QUEST_CONTAINER", QUEST_CONTAINER},
00405     {"CLOSE_CON", CLOSE_CON},
00406     {"CONTAINER", CONTAINER},
00407     {"ARMOUR_IMPROVER", ARMOUR_IMPROVER},
00408     {"WEAPON_IMPROVER", WEAPON_IMPROVER},
00409     {"WEALTH", WEALTH},
00410     {"SKILLSCROLL", SKILLSCROLL},
00411     {"DEEP_SWAMP", DEEP_SWAMP},
00412     {"IDENTIFY_ALTAR", IDENTIFY_ALTAR},
00413     {"SWARM_SPELL", SWARM_SPELL},
00414     {"RUNE", RUNE},
00415     {"POWER_CRYSTAL", POWER_CRYSTAL},
00416     {"CORPSE", CORPSE},
00417     {"DISEASE", DISEASE},
00418     {"SYMPTOM", SYMPTOM},
00419     {"MAP_EVENT_OBJ", MAP_EVENT_OBJ},
00420     {"MAP_INFO", MAP_INFO},
00421     {"COMPASS", COMPASS},
00422 
00423     {NULL, 0}
00424 };
00425 /* @endcparser */
00426 
00428 /* @cparser
00429  * @page plugin_python_constants_gender Python gender constants
00430  * <h2>Python gender constants</h2>
00431  * List of the Python plugin gender constants and their meaning. */
00432 static const Atrinik_Constant constants_gender[] =
00433 {
00434     {"NEUTER", GENDER_NEUTER},
00435     {"MALE", GENDER_MALE},
00436     {"FEMALE", GENDER_FEMALE},
00437     {"HERMAPHRODITE", GENDER_HERMAPHRODITE},
00438 
00439     {NULL, 0}
00440 };
00441 /* @endcparser */
00442 
00445 /* @cparser
00446  * @page plugin_python_constants_colors Python color constants
00447  * <h2>Python color constants</h2>
00448  * List of the Python plugin color constants and their meaning. */
00449 static const char *const constants_colors[][2] =
00450 {
00451     {"COLOR_WHITE", COLOR_WHITE},
00452     {"COLOR_ORANGE", COLOR_ORANGE},
00453     {"COLOR_NAVY", COLOR_NAVY},
00454     {"COLOR_RED", COLOR_RED},
00455     {"COLOR_GREEN", COLOR_GREEN},
00456     {"COLOR_BLUE", COLOR_BLUE},
00457     {"COLOR_GRAY", COLOR_GRAY},
00458     {"COLOR_BROWN", COLOR_BROWN},
00459     {"COLOR_PURPLE", COLOR_PURPLE},
00460     {"COLOR_PINK", COLOR_PINK},
00461     {"COLOR_YELLOW", COLOR_YELLOW},
00462     {"COLOR_DK_NAVY", COLOR_DK_NAVY},
00463     {"COLOR_DK_GREEN", COLOR_DK_GREEN},
00464     {"COLOR_DK_ORANGE", COLOR_DK_ORANGE},
00465     {"COLOR_HGOLD", COLOR_HGOLD},
00466     {"COLOR_DGOLD", COLOR_DGOLD},
00467     {NULL, NULL}
00468 };
00469 /* @endcparser */
00470 
00472 static PythonCmd CustomCommand[NR_CUSTOM_CMD];
00474 static int NextCustomCommand;
00475 
00477 #define PYTHON_CACHE_SIZE 256
00478 
00480 typedef struct
00481 {
00483     const char *file;
00484 
00486     PyCodeObject *code;
00487 
00489     time_t cached_time;
00490 
00492     time_t used_time;
00493 } cacheentry;
00494 
00496 static cacheentry python_cache[PYTHON_CACHE_SIZE];
00497 
00498 static int cmd_customPython(object *op, char *params);
00499 
00502 static void initContextStack()
00503 {
00504     current_context = NULL;
00505     context_stack = NULL;
00506 }
00507 
00511 static void pushContext(PythonContext *context)
00512 {
00513     if (current_context == NULL)
00514     {
00515         context_stack = context;
00516         context->down = NULL;
00517     }
00518     else
00519     {
00520         context->down = current_context;
00521     }
00522 
00523     current_context = context;
00524 }
00525 
00531 static PythonContext *popContext()
00532 {
00533     PythonContext *oldcontext;
00534 
00535     if (current_context)
00536     {
00537         oldcontext = current_context;
00538         current_context = current_context->down;
00539         return oldcontext;
00540     }
00541 
00542     return NULL;
00543 }
00544 
00548 static void freeContext(PythonContext *context)
00549 {
00550     free(context);
00551 }
00552 
00562 static PyObject *Atrinik_LoadObject(PyObject *self, PyObject *args)
00563 {
00564     char *dumpob;
00565 
00566     (void) self;
00567 
00568     if (!PyArg_ParseTuple(args, "s", &dumpob))
00569     {
00570         return NULL;
00571     }
00572 
00573     return wrap_object(hooks->load_object_str(dumpob));
00574 }
00575 
00583 static PyObject *Atrinik_ReadyMap(PyObject *self, PyObject *args)
00584 {
00585     const char *path;
00586     int flags = 0, unique = 0;
00587 
00588     (void) self;
00589 
00590     if (!PyArg_ParseTuple(args, "s|i", &path, &unique))
00591     {
00592         return NULL;
00593     }
00594 
00595     if (unique)
00596     {
00597         flags |= MAP_PLAYER_UNIQUE;
00598     }
00599 
00600     return wrap_map(hooks->ready_map_name(path, flags));
00601 }
00602 
00608 static PyObject *Atrinik_FindPlayer(PyObject *self, PyObject *args)
00609 {
00610     const char *name;
00611     player *pl;
00612 
00613     (void) self;
00614 
00615     if (!PyArg_ParseTuple(args, "s", &name))
00616     {
00617         return NULL;
00618     }
00619 
00620     pl = hooks->find_player(name);
00621 
00622     if (pl)
00623     {
00624         return wrap_object(pl->ob);
00625     }
00626 
00627     Py_INCREF(Py_None);
00628     return Py_None;
00629 }
00630 
00636 static PyObject *Atrinik_PlayerExists(PyObject *self, PyObject *args)
00637 {
00638     const char *name;
00639     char *cp;
00640     int ret;
00641 
00642     (void) self;
00643 
00644     if (!PyArg_ParseTuple(args, "s", &name))
00645     {
00646         return NULL;
00647     }
00648 
00649     cp = hooks->strdup_local(name);
00650     hooks->adjust_player_name(cp);
00651     ret = hooks->player_exists(cp);
00652     free(cp);
00653 
00654     Py_ReturnBoolean(ret);
00655 }
00656 
00662 static PyObject *Atrinik_WhoAmI(PyObject *self, PyObject *args)
00663 {
00664     (void) self;
00665     (void) args;
00666     return wrap_object(current_context->who);
00667 }
00668 
00673 static PyObject *Atrinik_WhoIsActivator(PyObject *self, PyObject *args)
00674 {
00675     (void) self;
00676     (void) args;
00677     return wrap_object(current_context->activator);
00678 }
00679 
00685 static PyObject *Atrinik_WhoIsOther(PyObject *self, PyObject *args)
00686 {
00687     (void) self;
00688     (void) args;
00689     return wrap_object(current_context->other);
00690 }
00691 
00696 static PyObject *Atrinik_WhatIsEvent(PyObject *self, PyObject *args)
00697 {
00698     (void) self;
00699     (void) args;
00700     return wrap_object(current_context->event);
00701 }
00702 
00707 static PyObject *Atrinik_GetEventNumber(PyObject *self, PyObject *args)
00708 {
00709     (void) self;
00710     (void) args;
00711     return Py_BuildValue("i", current_context->event->sub_type);
00712 }
00713 
00718 static PyObject *Atrinik_WhatIsMessage(PyObject *self, PyObject *args)
00719 {
00720     (void) self;
00721     (void) args;
00722     return Py_BuildValue("s", current_context->text);
00723 }
00724 
00729 static PyObject *Atrinik_GetOptions(PyObject *self, PyObject *args)
00730 {
00731     (void) self;
00732     (void) args;
00733     return Py_BuildValue("s", current_context->options);
00734 }
00735 
00740 static PyObject *Atrinik_GetReturnValue(PyObject *self, PyObject *args)
00741 {
00742     (void) self;
00743     (void) args;
00744     return Py_BuildValue("i", current_context->returnvalue);
00745 }
00746 
00751 static PyObject *Atrinik_SetReturnValue(PyObject *self, PyObject *args)
00752 {
00753     int value;
00754 
00755     (void) self;
00756 
00757     if (!PyArg_ParseTuple(args, "i", &value))
00758     {
00759         return NULL;
00760     }
00761 
00762     current_context->returnvalue = value;
00763 
00764     Py_INCREF(Py_None);
00765     return Py_None;
00766 }
00767 
00775 static PyObject *Atrinik_GetEventParameters(PyObject *self, PyObject *args)
00776 {
00777     size_t i;
00778     PyObject *list = PyList_New(0);
00779 
00780     (void) self;
00781     (void) args;
00782 
00783     for (i = 0; i < sizeof(current_context->parms) / sizeof(current_context->parms[0]); i++)
00784     {
00785         PyList_Append(list, Py_BuildValue("i", current_context->parms[i]));
00786     }
00787 
00788     return list;
00789 }
00790 
00796 static PyObject *Atrinik_GetSpellNr(PyObject *self, PyObject *args)
00797 {
00798     const char *spell;
00799 
00800     (void) self;
00801 
00802     if (!PyArg_ParseTuple(args, "s", &spell))
00803     {
00804         return NULL;
00805     }
00806 
00807     return Py_BuildValue("i", hooks->look_up_spell_name(spell));
00808 }
00809 
00823 static PyObject *Atrinik_GetSpell(PyObject *self, PyObject *args)
00824 {
00825     int spell;
00826     PyObject *dict;
00827 
00828     (void) self;
00829 
00830     if (!PyArg_ParseTuple(args, "i", &spell))
00831     {
00832         return NULL;
00833     }
00834 
00835     if (spell < 0 || spell >= NROFREALSPELLS)
00836     {
00837         PyErr_SetString(PyExc_ValueError, "Invalid ID of a spell.");
00838         return NULL;
00839     }
00840 
00841     dict = PyDict_New();
00842 
00843     PyDict_SetItemString(dict, "name", Py_BuildValue("s", hooks->spells[spell].name));
00844     PyDict_SetItemString(dict, "level", Py_BuildValue("i", hooks->spells[spell].level));
00845     PyDict_SetItemString(dict, "type", Py_BuildValue("s", hooks->spells[spell].type == SPELL_TYPE_WIZARD ? "wizard" : "priest"));
00846     PyDict_SetItemString(dict, "sp", Py_BuildValue("i", hooks->spells[spell].sp));
00847     PyDict_SetItemString(dict, "time", Py_BuildValue("i", hooks->spells[spell].time));
00848 
00849     return dict;
00850 }
00851 
00857 static PyObject *Atrinik_GetSkillNr(PyObject *self, PyObject *args)
00858 {
00859     const char *skill;
00860 
00861     (void) self;
00862 
00863     if (!PyArg_ParseTuple(args, "s", &skill))
00864     {
00865         return NULL;
00866     }
00867 
00868     return Py_BuildValue("i", hooks->lookup_skill_by_name(skill));
00869 }
00870 
00879 static PyObject *Atrinik_RegisterCommand(PyObject *self, PyObject *args)
00880 {
00881     const char *name, *path;
00882     double speed;
00883     size_t i;
00884 
00885     (void) self;
00886 
00887     if (!PyArg_ParseTuple(args, "ssd", &name, &path, &speed))
00888     {
00889         return NULL;
00890     }
00891 
00892     for (i = 0; i < NR_CUSTOM_CMD; i++)
00893     {
00894         if (CustomCommand[i].name)
00895         {
00896             if (!strcmp(CustomCommand[i].name, name))
00897             {
00898                 PyErr_SetString(PyExc_ValueError, "RegisterCommand(): Command is already registered.");
00899                 return NULL;
00900             }
00901         }
00902     }
00903 
00904     for (i = 0; i < NR_CUSTOM_CMD; i++)
00905     {
00906         if (!CustomCommand[i].name)
00907         {
00908             CustomCommand[i].name = hooks->strdup_local(name);
00909             CustomCommand[i].script = hooks->strdup_local(path);
00910             CustomCommand[i].speed = speed;
00911             break;
00912         }
00913     }
00914 
00915     Py_INCREF(Py_None);
00916     return Py_None;
00917 }
00918 
00925 static PyObject *Atrinik_CreatePathname(PyObject *self, PyObject *args)
00926 {
00927     const char *path;
00928 
00929     (void) self;
00930 
00931     if (!PyArg_ParseTuple(args, "s", &path))
00932     {
00933         return NULL;
00934     }
00935 
00936     return Py_BuildValue("s", hooks->create_pathname(path));
00937 }
00938 
00956 static PyObject *Atrinik_GetTime(PyObject *self, PyObject *args)
00957 {
00958     PyObject *dict = PyDict_New();
00959     timeofday_t tod;
00960 
00961     (void) self;
00962     (void) args;
00963 
00964     hooks->get_tod(&tod);
00965 
00966     PyDict_SetItemString(dict, "year", Py_BuildValue("i", tod.year + 1));
00967     PyDict_SetItemString(dict, "month", Py_BuildValue("i", tod.month + 1));
00968     PyDict_SetItemString(dict, "month_name", Py_BuildValue("s", hooks->month_name[tod.month]));
00969     PyDict_SetItemString(dict, "day", Py_BuildValue("i", tod.day + 1));
00970     PyDict_SetItemString(dict, "hour", Py_BuildValue("i", tod.hour));
00971     PyDict_SetItemString(dict, "minute", Py_BuildValue("i", tod.minute));
00972     PyDict_SetItemString(dict, "dayofweek", Py_BuildValue("i", tod.dayofweek + 1));
00973     PyDict_SetItemString(dict, "dayofweek_name", Py_BuildValue("s", hooks->weekdays[tod.dayofweek]));
00974     PyDict_SetItemString(dict, "season", Py_BuildValue("i", tod.season + 1));
00975     PyDict_SetItemString(dict, "season_name", Py_BuildValue("s", hooks->season_name[tod.season]));
00976     PyDict_SetItemString(dict, "periodofday", Py_BuildValue("i", tod.periodofday + 1));
00977     PyDict_SetItemString(dict, "periodofday_name", Py_BuildValue("s", hooks->periodsofday[tod.periodofday]));
00978 
00979     return dict;
00980 }
00981 
00987 static PyObject *Atrinik_LocateBeacon(PyObject *self, PyObject *args)
00988 {
00989     const char *name;
00990     shstr *beacon_name = NULL;
00991     object *myob;
00992 
00993     (void) self;
00994 
00995     if (!PyArg_ParseTuple(args, "s", &name))
00996     {
00997         return NULL;
00998     }
00999 
01000     FREE_AND_COPY_HASH(beacon_name, name);
01001     myob = hooks->beacon_locate(beacon_name);
01002     FREE_AND_CLEAR_HASH(beacon_name);
01003 
01004     return wrap_object(myob);
01005 }
01006 
01012 static PyObject *Atrinik_FindParty(PyObject *self, PyObject *args)
01013 {
01014     const char *name;
01015 
01016     (void) self;
01017 
01018     if (!PyArg_ParseTuple(args, "s", &name))
01019     {
01020         return NULL;
01021     }
01022 
01023     return wrap_party(hooks->find_party(name));
01024 }
01025 
01031 static PyObject *Atrinik_CleanupChatString(PyObject *self, PyObject *args)
01032 {
01033     const char *text;
01034     char *cp;
01035     PyObject *ret;
01036 
01037     (void) self;
01038 
01039     if (!PyArg_ParseTuple(args, "s", &text))
01040     {
01041         return NULL;
01042     }
01043 
01044     cp = hooks->strdup_local(text);
01045     ret = Py_BuildValue("s", hooks->cleanup_chat_string(cp));
01046     free(cp);
01047 
01048     return ret;
01049 }
01050 
01060 static PyObject *Atrinik_LOG(PyObject *self, PyObject *args)
01061 {
01062     const char *string;
01063     uint8 mode;
01064 
01065     (void) self;
01066 
01067     if (!PyArg_ParseTuple(args, "Bs", &mode, &string))
01068     {
01069         return NULL;
01070     }
01071 
01072     LOG(mode, string);
01073 
01074     Py_INCREF(Py_None);
01075     return Py_None;
01076 }
01077 
01083 static PyObject *Atrinik_DestroyTimer(PyObject *self, PyObject *args)
01084 {
01085     int id;
01086 
01087     (void) self;
01088 
01089     if (!PyArg_ParseTuple(args, "i", &id))
01090     {
01091         return NULL;
01092     }
01093 
01094     Py_ReturnBoolean(hooks->cftimer_destroy(id) == TIMER_ERR_NONE);
01095 }
01096 
01113 static PyObject *Atrinik_GetRangeVectorFromMapCoords(PyObject *self, PyObject *args)
01114 {
01115     Atrinik_Map *map, *map2;
01116     int x, y, x2, y2, flags = 0;
01117     rv_vector rv;
01118     PyObject *tuple;
01119 
01120     (void) self;
01121 
01122     if (!PyArg_ParseTuple(args, "O!iiO!ii|i", &Atrinik_MapType, &map, &x, &y, &Atrinik_MapType, &map2, &x2, &y2, &flags))
01123     {
01124         return NULL;
01125     }
01126 
01127     if (!hooks->get_rangevector_from_mapcoords(map->map, x, y, map2->map, x2, y2, &rv, flags))
01128     {
01129         Py_INCREF(Py_None);
01130         return Py_None;
01131     }
01132 
01133     tuple = PyTuple_New(4);
01134     PyTuple_SET_ITEM(tuple, 0, Py_BuildValue("i", rv.direction));
01135     PyTuple_SET_ITEM(tuple, 1, Py_BuildValue("i", rv.distance));
01136     PyTuple_SET_ITEM(tuple, 2, Py_BuildValue("i", rv.distance_x));
01137     PyTuple_SET_ITEM(tuple, 3, Py_BuildValue("i", rv.distance_y));
01138 
01139     return tuple;
01140 }
01141 
01148 static PyObject *Atrinik_CostString(PyObject *self, PyObject *args)
01149 {
01150     sint64 value;
01151 
01152     (void) self;
01153 
01154     if (!PyArg_ParseTuple(args, "L", &value))
01155     {
01156         return NULL;
01157     }
01158 
01159     return Py_BuildValue("s", hooks->cost_string_from_value(value));
01160 }
01161 
01176 static PyObject *Atrinik_CacheAdd(PyObject *self, PyObject *args)
01177 {
01178     const char *key;
01179     PyObject *what;
01180     int ret;
01181 
01182     (void) self;
01183 
01184     if (!PyArg_ParseTuple(args, "sO", &key, &what))
01185     {
01186         return NULL;
01187     }
01188 
01189     /* Add it to the cache. */
01190     ret = hooks->cache_add(key, what, CACHE_FLAG_PYOBJ | CACHE_FLAG_GEVENT);
01191 
01192     if (ret)
01193     {
01194         Py_INCREF(what);
01195     }
01196 
01197     Py_ReturnBoolean(ret);
01198 }
01199 
01208 static PyObject *Atrinik_CacheGet(PyObject *self, PyObject *args)
01209 {
01210     const char *key;
01211     shstr *sh_key;
01212     cache_struct *result;
01213 
01214     (void) self;
01215 
01216     if (!PyArg_ParseTuple(args, "s", &key))
01217     {
01218         return NULL;
01219     }
01220 
01221     sh_key = hooks->find_string(key);
01222 
01223     /* Even if the cache entry was found, pretend it doesn't exist if
01224      * CACHE_FLAG_PYOBJ is not set. */
01225     if (!sh_key || !(result = hooks->cache_find(sh_key)) || !(result->flags & CACHE_FLAG_PYOBJ))
01226     {
01227         PyErr_SetString(PyExc_ValueError, "No such cache entry.");
01228         return NULL;
01229     }
01230     else
01231     {
01232         Py_INCREF((PyObject *) result->ptr);
01233         return (PyObject *) result->ptr;
01234     }
01235 }
01236 
01246 static PyObject *Atrinik_CacheRemove(PyObject *self, PyObject *args)
01247 {
01248     const char *key;
01249     shstr *sh_key;
01250 
01251     (void) self;
01252 
01253     if (!PyArg_ParseTuple(args, "s", &key))
01254     {
01255         return NULL;
01256     }
01257 
01258     sh_key = hooks->find_string(key);
01259 
01260     if (!sh_key || !hooks->cache_remove(sh_key))
01261     {
01262         PyErr_SetString(PyExc_ValueError, "No such cache entry.");
01263         return NULL;
01264     }
01265     else
01266     {
01267         Py_INCREF(Py_True);
01268         return Py_True;
01269     }
01270 }
01271 
01282 static PyObject *Atrinik_GetFirst(PyObject *self, PyObject *args)
01283 {
01284     const char *what;
01285 
01286     (void) self;
01287 
01288     if (!PyArg_ParseTuple(args, "s", &what))
01289     {
01290         return NULL;
01291     }
01292 
01293     if (!strcmp(what, "player"))
01294     {
01295         return wrap_player(*hooks->first_player);
01296     }
01297     else if (!strcmp(what, "map"))
01298     {
01299         return wrap_map(*hooks->first_map);
01300     }
01301     else if (!strcmp(what, "archetype"))
01302     {
01303         return wrap_archetype(*hooks->first_archetype);
01304     }
01305     else if (!strcmp(what, "party"))
01306     {
01307         return wrap_party(*hooks->first_party);
01308     }
01309     else if (!strcmp(what, "region"))
01310     {
01311         return wrap_region(*hooks->first_region);
01312     }
01313 
01314     PyErr_Format(PyExc_ValueError, "GetFirst(): '%s' is not a valid linked list.", what);
01315     return NULL;
01316 }
01317 
01327 static PyObject *Atrinik_CreateMap(PyObject *self, PyObject *args)
01328 {
01329     int width, height;
01330     const char *path;
01331     mapstruct *m;
01332     char buf[HUGE_BUF];
01333 
01334     (void) self;
01335 
01336     if (!PyArg_ParseTuple(args, "iis", &width, &height, &path))
01337     {
01338         return NULL;
01339     }
01340 
01341     m = hooks->get_empty_map(width, height);
01342     snprintf(buf, sizeof(buf), "/python-maps/%s", path);
01343     m->path = hooks->add_string(buf);
01344 
01345     return wrap_map(m);
01346 }
01347 
01356 static PyObject *Atrinik_CreateObject(PyObject *self, PyObject *args)
01357 {
01358     const char *archname;
01359     archetype *at;
01360 
01361     (void) self;
01362 
01363     if (!PyArg_ParseTuple(args, "s", &archname))
01364     {
01365         return NULL;
01366     }
01367 
01368     at = hooks->find_archetype(archname);
01369 
01370     if (!at)
01371     {
01372         PyErr_Format(AtrinikError, "CreateObject(): The archetype '%s' doesn't exist.", archname);
01373         return NULL;
01374     }
01375 
01376     return wrap_object(hooks->arch_to_object(at));
01377 }
01378 
01384 static PyMethodDef AtrinikMethods[] =
01385 {
01386     {"LoadObject", Atrinik_LoadObject, METH_VARARGS, 0},
01387     {"ReadyMap", Atrinik_ReadyMap, METH_VARARGS, 0},
01388     {"FindPlayer", Atrinik_FindPlayer, METH_VARARGS, 0},
01389     {"PlayerExists", Atrinik_PlayerExists, METH_VARARGS, 0},
01390     {"WhoAmI", Atrinik_WhoAmI, METH_NOARGS, 0},
01391     {"WhoIsActivator", Atrinik_WhoIsActivator, METH_NOARGS, 0},
01392     {"WhoIsOther", Atrinik_WhoIsOther, METH_NOARGS, 0},
01393     {"WhatIsEvent", Atrinik_WhatIsEvent, METH_NOARGS, 0},
01394     {"GetEventNumber", Atrinik_GetEventNumber, METH_NOARGS, 0},
01395     {"WhatIsMessage", Atrinik_WhatIsMessage, METH_NOARGS, 0},
01396     {"GetOptions", Atrinik_GetOptions, METH_NOARGS, 0},
01397     {"GetReturnValue", Atrinik_GetReturnValue, METH_NOARGS, 0},
01398     {"SetReturnValue", Atrinik_SetReturnValue, METH_VARARGS, 0},
01399     {"GetEventParameters", Atrinik_GetEventParameters, METH_NOARGS, 0},
01400     {"GetSpellNr", Atrinik_GetSpellNr, METH_VARARGS, 0},
01401     {"GetSpell", Atrinik_GetSpell, METH_VARARGS, 0},
01402     {"GetSkillNr", Atrinik_GetSkillNr, METH_VARARGS, 0},
01403     {"RegisterCommand", Atrinik_RegisterCommand, METH_VARARGS, 0},
01404     {"CreatePathname", Atrinik_CreatePathname, METH_VARARGS, 0},
01405     {"GetTime", Atrinik_GetTime, METH_NOARGS, 0},
01406     {"LocateBeacon", Atrinik_LocateBeacon, METH_VARARGS, 0},
01407     {"FindParty", Atrinik_FindParty, METH_VARARGS, 0},
01408     {"CleanupChatString", Atrinik_CleanupChatString, METH_VARARGS, 0},
01409     {"LOG", Atrinik_LOG, METH_VARARGS, 0},
01410     {"DestroyTimer", Atrinik_DestroyTimer, METH_VARARGS, 0},
01411     {"GetRangeVectorFromMapCoords", Atrinik_GetRangeVectorFromMapCoords, METH_VARARGS, 0},
01412     {"CostString", Atrinik_CostString, METH_VARARGS, 0},
01413     {"CacheAdd", Atrinik_CacheAdd, METH_VARARGS, 0},
01414     {"CacheGet", Atrinik_CacheGet, METH_VARARGS, 0},
01415     {"CacheRemove", Atrinik_CacheRemove, METH_VARARGS, 0},
01416     {"GetFirst", Atrinik_GetFirst, METH_VARARGS, 0},
01417     {"CreateMap", Atrinik_CreateMap, METH_VARARGS, 0},
01418     {"CreateObject", Atrinik_CreateObject, METH_VARARGS, 0},
01419     {NULL, NULL, 0, 0}
01420 };
01421 
01425 static void PyErr_LOG()
01426 {
01427     PyObject *globals, *locals, *ret;
01428     PyObject *ptype, *pvalue, *ptraceback;
01429     const char *err_handle =
01430 "from Atrinik import *\n"
01431 "import traceback\n"
01432 "exception = \"\".join(traceback.format_exception(exc_type, exc_value, exc_traceback))\n"
01433 "LOG(llevDebug, exception)\n"
01434 "player = GetFirst(\"player\")\n"
01435 "while player:\n"
01436 "   if player.ob.f_wiz or \"resetmap\" in player.cmd_permissions:\n"
01437 "       player.ob.Write(exception, COLOR_RED)\n"
01438 "   player = player.next\n";
01439 
01440     /* Fetch the exception data. */
01441     PyErr_Fetch(&ptype, &pvalue, &ptraceback);
01442     PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
01443 
01444     /* Construct globals dictionary. */
01445     globals = PyDict_New();
01446     PyDict_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());
01447 
01448     /* Construct locals dictionary, with the exception data. */
01449     locals = PyDict_New();
01450     PyDict_SetItemString(locals, "exc_type", ptype);
01451     PyDict_SetItemString(locals, "exc_value", pvalue);
01452     PyDict_SetItemString(locals, "exc_traceback", ptraceback);
01453 
01454     /* Run the Python code. */
01455     ret = PyRun_String(err_handle, Py_file_input, globals, locals);
01456 
01457     Py_DECREF(globals);
01458     Py_DECREF(locals);
01459     Py_XDECREF(ret);
01460 }
01461 
01465 static PyCodeObject *compilePython(char *filename)
01466 {
01467     shstr *sh_path = NULL;
01468     struct stat stat_buf;
01469     struct _node *n;
01470     int i;
01471     cacheentry *entry_replace = NULL, *run = NULL;
01472 
01473     if (stat(filename, &stat_buf))
01474     {
01475         LOG(llevDebug, "Python: The script file %s can't be stat()ed.\n", filename);
01476         return NULL;
01477     }
01478 
01479     FREE_AND_COPY_HASH(sh_path, filename);
01480 
01481     /* Search through cache. Three cases:
01482      * 1) script in cache, but older than file  -> replace cached
01483      * 2) script in cache and up to date        -> use cached
01484      * 3) script not in cache, cache not full   -> add to end of cache
01485      * 4) script not in cache, cache full       -> replace least recently used */
01486     for (i = 0; i < PYTHON_CACHE_SIZE; i++)
01487     {
01488         /* Script not in cache, cache not full */
01489         if (python_cache[i].file == NULL)
01490         {
01491             /* Add to end of cache. */
01492             entry_replace = &python_cache[i];
01493             break;
01494         }
01495         else if (python_cache[i].file == sh_path)
01496         {
01497             /* Script in cache */
01498             if (python_cache[i].code == NULL || (python_cache[i].cached_time < stat_buf.st_mtime))
01499             {
01500                 /* Cache older than file, replace cached. */
01501                 entry_replace = &python_cache[i];
01502             }
01503             else
01504             {
01505                 /* cache up-to-date, use cached*/
01506                 entry_replace = NULL;
01507                 run = &python_cache[i];
01508             }
01509 
01510             break;
01511         }
01512         else if (entry_replace == NULL || python_cache[i].used_time < entry_replace->used_time)
01513         {
01514             /* If we haven't found it yet, set replace to the oldest cache */
01515             entry_replace = &python_cache[i];
01516         }
01517     }
01518 
01519     /* Replace a specific cache index with the file. */
01520     if (entry_replace)
01521     {
01522         FILE *fp;
01523 
01524         fp = fopen(filename, "r");
01525 
01526         if (!fp)
01527         {
01528             LOG(llevDebug, "Python: The script file %s can't be opened.\n", filename);
01529             FREE_AND_CLEAR_HASH(sh_path);
01530             return NULL;
01531         }
01532 
01533         Py_XDECREF(entry_replace->code);
01534         entry_replace->code = NULL;
01535 
01536         /* Need to replace path string? */
01537         if (entry_replace->file != sh_path)
01538         {
01539             if (entry_replace->file)
01540             {
01541                 FREE_AND_CLEAR_HASH(entry_replace->file);
01542             }
01543 
01544             FREE_AND_COPY_HASH(entry_replace->file, sh_path);
01545         }
01546 
01547 #ifdef WIN32
01548         {
01549             char buf[HUGE_BUF], *pystr = NULL;
01550             size_t buf_len = 0, pystr_len = 0;
01551 
01552             while (fgets(buf, sizeof(buf), fp))
01553             {
01554                 buf_len = strlen(buf);
01555                 pystr_len += buf_len;
01556                 pystr = realloc(pystr, sizeof(char) * (pystr_len + 1));
01557                 strcpy(pystr + pystr_len - buf_len, buf);
01558                 pystr[pystr_len] = '\0';
01559             }
01560 
01561             n = PyParser_SimpleParseString(pystr, Py_file_input);
01562             free(pystr);
01563         }
01564 #else
01565         n = PyParser_SimpleParseFile(fp, filename, Py_file_input);
01566 #endif
01567 
01568         if (n)
01569         {
01570             entry_replace->code = PyNode_Compile(n, filename);
01571             PyNode_Free(n);
01572         }
01573 
01574         if (PyErr_Occurred())
01575         {
01576             PyErr_LOG();
01577         }
01578         else
01579         {
01580             entry_replace->cached_time = stat_buf.st_mtime;
01581             entry_replace->used_time = time(NULL);
01582         }
01583 
01584         fclose(fp);
01585         run = entry_replace;
01586     }
01587 
01588     FREE_AND_CLEAR_HASH(sh_path);
01589 
01590     if (run)
01591     {
01592         return run->code;
01593     }
01594 
01595     return NULL;
01596 }
01597 
01598 static int do_script(PythonContext *context, const char *filename, object *event)
01599 {
01600     PyCodeObject *pycode;
01601     PyObject *dict, *ret;
01602     char path[HUGE_BUF];
01603 
01604     strncpy(path, hooks->create_pathname(filename), sizeof(path) - 1);
01605 
01606     if (event && path[0] != '/')
01607     {
01608         char tmp_path[HUGE_BUF];
01609         object *outermost = event;
01610 
01611         while (outermost && outermost->env)
01612         {
01613             outermost = outermost->env;
01614         }
01615 
01616         if (outermost && outermost->map)
01617         {
01618             hooks->normalize_path(outermost->map->path, filename, tmp_path);
01619             strncpy(path, hooks->create_pathname(tmp_path), sizeof(path) - 1);
01620         }
01621     }
01622 
01623     pycode = compilePython(path);
01624 
01625     if (pycode)
01626     {
01627 #ifndef PRODUCTION_SERVER
01628         PyObject *modules = PyImport_GetModuleDict(), *key, *value;
01629         Py_ssize_t pos = 0;
01630         const char *m_filename;
01631         char m_buf[MAX_BUF];
01632 
01633         /* Create path name to the Python scripts directory. */
01634         strncpy(m_buf, hooks->create_pathname("/python"), sizeof(m_buf) - 1);
01635 
01636         /* Go through the loaded modules. */
01637         while (PyDict_Next(modules, &pos, &key, &value))
01638         {
01639             m_filename = PyModule_GetFilename(value);
01640 
01641             if (!m_filename)
01642             {
01643                 PyErr_Clear();
01644                 continue;
01645             }
01646 
01647             /* If this module was loaded from one of our script files,
01648              * reload it. */
01649             if (!strncmp(m_filename, m_buf, strlen(m_buf)))
01650             {
01651                 PyImport_ReloadModule(value);
01652 
01653                 if (PyErr_Occurred())
01654                 {
01655                     PyErr_LOG();
01656                 }
01657             }
01658         }
01659 #endif
01660 
01661         pushContext(context);
01662         dict = PyDict_New();
01663         PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins());
01664 
01665 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 2
01666         ret = PyEval_EvalCode((PyObject *) pycode, dict, NULL);
01667 #else
01668         ret = PyEval_EvalCode(pycode, dict, NULL);
01669 #endif
01670 
01671         if (PyErr_Occurred())
01672         {
01673             PyErr_LOG();
01674         }
01675 
01676         Py_XDECREF(ret);
01677         Py_DECREF(dict);
01678 
01679         return 1;
01680     }
01681 
01682     return 0;
01683 }
01684 
01689 static int handle_event(va_list args)
01690 {
01691     char *script;
01692     PythonContext *context = malloc(sizeof(PythonContext));
01693     int rv;
01694 
01695     context->activator = va_arg(args, object *);
01696     context->who = va_arg(args, object *);
01697     context->other = va_arg(args, object *);
01698     context->event = va_arg(args, object *);
01699     context->text = va_arg(args, char *);
01700     context->parms[0] = va_arg(args, int);
01701     context->parms[1] = va_arg(args, int);
01702     context->parms[2] = va_arg(args, int);
01703     context->parms[3] = va_arg(args, int);
01704     script = va_arg(args, char *);
01705     context->options = va_arg(args, char *);
01706     context->returnvalue = 0;
01707 
01708     LOG(llevDebug, "Python: Start script file >%s<, activator: %s, who: %s, other: %s, text: %s, parms: %d, %d, %d, %d\n", script, STRING_OBJ_NAME(context->activator), STRING_OBJ_NAME(context->who), STRING_OBJ_NAME(context->other), STRING_SAFE(context->text), context->parms[0], context->parms[1], context->parms[2], context->parms[3]);
01709 
01710     if (!do_script(context, script, context->who))
01711     {
01712         freeContext(context);
01713         return 0;
01714     }
01715 
01716     context = popContext();
01717 
01718     if (context->parms[3] == SCRIPT_FIX_ALL)
01719     {
01720         if (context->other && IS_LIVE(context->other))
01721         {
01722             hooks->fix_player(context->other);
01723         }
01724 
01725         if (context->who && IS_LIVE(context->who))
01726         {
01727             hooks->fix_player(context->who);
01728         }
01729 
01730         if (context->activator && IS_LIVE(context->activator))
01731         {
01732             hooks->fix_player(context->activator);
01733         }
01734     }
01735     else if (context->parms[3] == SCRIPT_FIX_ACTIVATOR && IS_LIVE(context->activator))
01736     {
01737         hooks->fix_player(context->activator);
01738     }
01739 
01740     rv = context->returnvalue;
01741     freeContext(context);
01742     LOG(llevDebug, "Python: done (returned: %d).\n", rv);
01743 
01744     return rv;
01745 }
01746 
01751 static int handle_map_event(va_list args)
01752 {
01753     PythonContext *context = calloc(1, sizeof(PythonContext));
01754     char *script;
01755     int rv;
01756 
01757     context->activator = va_arg(args, object *);
01758     context->event = va_arg(args, object *);
01759     context->other = va_arg(args, object *);
01760     context->who = va_arg(args, object *);
01761     script = va_arg(args, char *);
01762     context->options = va_arg(args, char *);
01763     context->text = va_arg(args, char *);
01764     context->parms[0] = va_arg(args, int);
01765 
01766     if (!do_script(context, script, context->who))
01767     {
01768         freeContext(context);
01769         return 0;
01770     }
01771 
01772     context = popContext();
01773     rv = context->returnvalue;
01774     freeContext(context);
01775 
01776     return rv;
01777 }
01778 
01784 static int handle_global_event(int event_type, va_list args)
01785 {
01786     PythonContext *context;
01787 
01788     switch (event_type)
01789     {
01790         case GEVENT_CACHE_REMOVED:
01791         {
01792             void *ptr = va_arg(args, void *);
01793             uint32 flags = *(uint32 *) va_arg(args, void *);
01794 
01795             if (flags & CACHE_FLAG_PYOBJ)
01796             {
01797                 PyObject *retval;
01798 
01799                 /* Attempt to close file/database/etc objects. */
01800                 retval = PyObject_CallMethod((PyObject *) ptr, "close", "");
01801 
01802                 /* No close() method, ignore the exception. */
01803                 if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError))
01804                 {
01805                     PyErr_Clear();
01806                 }
01807 
01808                 Py_XDECREF(retval);
01809 
01810                 /* Decrease the reference count. */
01811                 Py_DECREF((PyObject *) ptr);
01812             }
01813 
01814             return 0;
01815         }
01816     }
01817 
01818     context = malloc(sizeof(PythonContext));
01819     context->activator = NULL;
01820     context->who = NULL;
01821     context->other = NULL;
01822     context->event = NULL;
01823     context->parms[0] = 0;
01824     context->parms[1] = 0;
01825     context->parms[2] = 0;
01826     context->parms[3] = 0;
01827     context->text = NULL;
01828     context->options = NULL;
01829     context->returnvalue = 0;
01830 
01831     switch (event_type)
01832     {
01833         case GEVENT_BORN:
01834             context->activator = (object *) va_arg(args, void *);
01835             break;
01836 
01837         case GEVENT_LOGIN:
01838             context->activator = ((player *) va_arg(args, void *))->ob;
01839             context->text = (char *) va_arg(args, void *);
01840             break;
01841 
01842         case GEVENT_LOGOUT:
01843             context->activator = ((player *) va_arg(args, void *))->ob;
01844             context->text = (char *) va_arg(args, void *);
01845             break;
01846 
01847         case GEVENT_PLAYER_DEATH:
01848             break;
01849     }
01850 
01851     if (!do_script(context, "/python/events/python_event.py", NULL))
01852     {
01853         freeContext(context);
01854         return 0;
01855     }
01856 
01857     context = popContext();
01858     freeContext(context);
01859 
01860     return 0;
01861 }
01862 
01863 MODULEAPI void *triggerEvent(int *type, ...)
01864 {
01865     va_list args;
01866     int eventcode, event_type;
01867     static int result = 0;
01868 
01869     va_start(args, type);
01870     event_type = va_arg(args, int);
01871     eventcode = va_arg(args, int);
01872 
01873     LOG(llevDebug, "Python: triggerEvent(): eventcode %d\n", eventcode);
01874 
01875     switch (event_type)
01876     {
01877         case PLUGIN_EVENT_NORMAL:
01878             result = handle_event(args);
01879             break;
01880 
01881         case PLUGIN_EVENT_MAP:
01882             result = handle_map_event(args);
01883             break;
01884 
01885         case PLUGIN_EVENT_GLOBAL:
01886             result = handle_global_event(eventcode, args);
01887             break;
01888 
01889         default:
01890             LOG(llevBug, "Python: Requested unknown event type %d.\n", event_type);
01891             break;
01892     }
01893 
01894     va_end(args);
01895     return &result;
01896 }
01897 
01898 MODULEAPI void *getPluginProperty(int *type, ...)
01899 {
01900     va_list args;
01901     const char *propname;
01902     int i, size;
01903     char *buf;
01904 
01905     va_start(args, type);
01906     propname = va_arg(args, const char *);
01907 
01908     if (!strcmp(propname, "command?"))
01909     {
01910         const char *cmdname = va_arg(args, const char *);
01911         CommArray_s *rtn_cmd = va_arg(args, CommArray_s *);
01912 
01913         va_end(args);
01914 
01915         for (i = 0; i < NR_CUSTOM_CMD; i++)
01916         {
01917             if (CustomCommand[i].name != NULL)
01918             {
01919                 if (!strcmp(CustomCommand[i].name, cmdname))
01920                 {
01921                     rtn_cmd->name = CustomCommand[i].name;
01922                     rtn_cmd->time = (float) CustomCommand[i].speed;
01923                     rtn_cmd->func = cmd_customPython;
01924                     rtn_cmd->flags = 0;
01925                     NextCustomCommand = i;
01926                     return rtn_cmd;
01927                 }
01928             }
01929         }
01930 
01931         return NULL;
01932     }
01933     else if (!strcmp(propname, "Identification"))
01934     {
01935         buf = va_arg(args, char *);
01936         size = va_arg(args, int);
01937         va_end(args);
01938         snprintf(buf, size, PLUGIN_NAME);
01939         return NULL;
01940     }
01941     else if (!strcmp(propname, "FullName"))
01942     {
01943         buf = va_arg(args, char *);
01944         size = va_arg(args, int);
01945         va_end(args);
01946         snprintf(buf, size, PLUGIN_VERSION);
01947         return NULL;
01948     }
01949 
01950     va_end(args);
01951     return NULL;
01952 }
01953 
01959 static int cmd_customPython(object *op, char *params)
01960 {
01961     PythonContext *context = malloc(sizeof(PythonContext));
01962     int rv;
01963 
01964     LOG(llevDebug, "Python: handling command %s using script: %s\n", CustomCommand[NextCustomCommand].name, CustomCommand[NextCustomCommand].script);
01965 
01966     context->activator = op;
01967     context->who = op;
01968     context->other = op;
01969     context->event = NULL;
01970     context->parms[0] = 0;
01971     context->parms[1] = 0;
01972     context->parms[2] = 0;
01973     context->parms[3] = 0;
01974     context->text = params;
01975     context->options = NULL;
01976     context->returnvalue = 0;
01977 
01978     if (!do_script(context, CustomCommand[NextCustomCommand].script, NULL))
01979     {
01980         freeContext(context);
01981         return 0;
01982     }
01983 
01984     context = popContext();
01985     rv = context->returnvalue;
01986     freeContext(context);
01987 
01988     LOG(llevDebug, "Python: done (returned: %d).\n", rv);
01989 
01990     return rv;
01991 }
01992 
01993 MODULEAPI void postinitPlugin()
01994 {
01995     char path[HUGE_BUF];
01996     FILE *fp;
01997 
01998     LOG(llevDebug, "Python: Start postinitPlugin.\n");
01999     hooks->register_global_event(PLUGIN_NAME, GEVENT_CACHE_REMOVED);
02000     initContextStack();
02001 
02002     strncpy(path, hooks->create_pathname("/python/events/python_init.py"), sizeof(path) - 1);
02003     fp = fopen(path, "r");
02004 
02005     if (fp)
02006     {
02007 #ifdef WIN32
02008         char *pystring;
02009 
02010         fclose(fp);
02011 
02012         pystring = malloc(strlen(path) + 64);
02013         sprintf(pystring, "exec(open('%s').read())", path);
02014         PyRun_SimpleString(pystring);
02015         free(pystring);
02016 #else
02017         PyRun_SimpleFile(fp, path);
02018         fclose(fp);
02019 #endif
02020     }
02021 }
02022 
02023 #ifdef IS_PY3K
02024 static PyModuleDef AtrinikModule =
02025 {
02026     PyModuleDef_HEAD_INIT,
02027     "Atrinik",
02028     NULL,
02029     -1,
02030     AtrinikMethods,
02031     NULL, NULL, NULL, NULL
02032 };
02033 
02034 static PyObject *PyInit_Atrinik()
02035 {
02036     PyObject *m = PyModule_Create(&AtrinikModule);
02037     Py_INCREF(m);
02038     return m;
02039 }
02040 #endif
02041 
02046 static PyObject *module_create(const char *name)
02047 {
02048     char tmp[MAX_BUF];
02049 
02050     snprintf(tmp, sizeof(tmp), "Atrinik_%s", name);
02051 
02052     return PyModule_New(tmp);
02053 }
02054 
02061 static void module_add_constants(PyObject *module, const char *name, const Atrinik_Constant *consts)
02062 {
02063     size_t i = 0;
02064     PyObject *module_tmp;
02065 
02066     /* Create the new module. */
02067     module_tmp = module_create(name);
02068 
02069     /* Append constants. */
02070     while (consts[i].name)
02071     {
02072         PyModule_AddIntConstant(module_tmp, consts[i].name, consts[i].value);
02073         i++;
02074     }
02075 
02076     /* Add the module. */
02077     PyDict_SetItemString(PyModule_GetDict(module), name, module_tmp);
02078 }
02079 
02087 static void module_add_array(PyObject *module, const char *name, void *array, size_t array_size, field_type type)
02088 {
02089     size_t i;
02090     PyObject *list;
02091 
02092     /* Create a new list. */
02093     list = PyList_New(0);
02094 
02095     /* Add entries to the list. */
02096     for (i = 0; i < array_size; i++)
02097     {
02098         if (type == FIELDTYPE_SINT32)
02099         {
02100             PyList_Append(list, Py_BuildValue("i", ((sint32 *) array)[i]));
02101         }
02102         else if (type == FIELDTYPE_CSTR)
02103         {
02104             PyList_Append(list, Py_BuildValue("s", ((char **) array)[i]));
02105         }
02106     }
02107 
02108     /* Add it to the module dictionary. */
02109     PyDict_SetItemString(PyModule_GetDict(module), name, list);
02110 }
02111 
02112 #ifndef WIN32
02113 
02118 static PyObject *python_openlogfile(FILE *fp, char *name)
02119 {
02120 #ifdef IS_PY3K
02121     return PyFile_FromFd(fileno(fp), name, "w", 1, NULL, NULL, NULL, 0);
02122 #else
02123     return PyFile_FromFile(fp, name, "w", 0);
02124 #endif
02125 }
02126 #endif
02127 
02128 MODULEAPI void initPlugin(struct plugin_hooklist *hooklist)
02129 {
02130     PyObject *m, *d, *module_tmp, *logfile_ptr;
02131     int i;
02132 
02133     hooks = hooklist;
02134 
02135     LOG(llevDebug, "Python: Atrinik Python Plugin loading...\n");
02136 
02137 #ifdef IS_PY26
02138     Py_Py3kWarningFlag++;
02139 #endif
02140 
02141 #ifdef IS_PY3K
02142     PyImport_AppendInittab("Atrinik", &PyInit_Atrinik);
02143 #endif
02144 
02145     Py_Initialize();
02146 
02147     LOG(llevDebug, "Python: Start initAtrinik.\n");
02148 
02149 #ifdef IS_PY3K
02150     m = PyImport_ImportModule("Atrinik");
02151 #else
02152     m = Py_InitModule("Atrinik", AtrinikMethods);
02153 #endif
02154 
02155     d = PyModule_GetDict(m);
02156     AtrinikError = PyErr_NewException("Atrinik.error", NULL, NULL);
02157     PyDict_SetItemString(d, "AtrinikError", AtrinikError);
02158 
02159     for (i = 0; i < NR_CUSTOM_CMD; i++)
02160     {
02161         CustomCommand[i].name = NULL;
02162         CustomCommand[i].script = NULL;
02163         CustomCommand[i].speed = 0.0;
02164     }
02165 
02166     if (!Atrinik_Object_init(m) || !Atrinik_Map_init(m) || !Atrinik_Party_init(m) || !Atrinik_Region_init(m) || !Atrinik_Player_init(m) || !Atrinik_Archetype_init(m) || !Atrinik_AttrList_init(m))
02167     {
02168         return;
02169     }
02170 
02171 #ifndef WIN32
02172     logfile_ptr = python_openlogfile(*hooks->logfile, "<stdout>");
02173     PySys_SetObject("stdout", logfile_ptr);
02174     PySys_SetObject("__stdout__", logfile_ptr);
02175     logfile_ptr = python_openlogfile(*hooks->logfile, "<stderr>");
02176     PySys_SetObject("stderr", logfile_ptr);
02177     PySys_SetObject("__stderr__", logfile_ptr);
02178 #endif
02179 
02180     module_add_constants(m, "Type", constants_types);
02181     module_add_array(m, "freearr_x", hooks->freearr_x, SIZEOFFREE, FIELDTYPE_SINT32);
02182     module_add_array(m, "freearr_y", hooks->freearr_y, SIZEOFFREE, FIELDTYPE_SINT32);
02183 
02184     /* Initialize integer constants */
02185     for (i = 0; constants[i].name; i++)
02186     {
02187         PyModule_AddIntConstant(m, constants[i].name, constants[i].value);
02188     }
02189 
02190     /* Initialize integer constants */
02191     for (i = 0; constants_colors[i][0]; i++)
02192     {
02193         PyModule_AddStringConstant(m, constants_colors[i][0], constants_colors[i][1]);
02194     }
02195 
02196     module_tmp = module_create("Gender");
02197     module_add_array(module_tmp, "gender_noun", hooks->gender_noun, GENDER_MAX, FIELDTYPE_CSTR);
02198     module_add_array(module_tmp, "gender_subjective", hooks->gender_subjective, GENDER_MAX, FIELDTYPE_CSTR);
02199     module_add_array(module_tmp, "gender_subjective_upper", hooks->gender_subjective_upper, GENDER_MAX, FIELDTYPE_CSTR);
02200     module_add_array(module_tmp, "gender_objective", hooks->gender_objective, GENDER_MAX, FIELDTYPE_CSTR);
02201     module_add_array(module_tmp, "gender_possessive", hooks->gender_possessive, GENDER_MAX, FIELDTYPE_CSTR);
02202     module_add_array(module_tmp, "gender_reflexive", hooks->gender_reflexive, GENDER_MAX, FIELDTYPE_CSTR);
02203 
02204     for (i = 0; constants_gender[i].name; i++)
02205     {
02206         PyModule_AddIntConstant(module_tmp, constants_gender[i].name, constants_gender[i].value);
02207     }
02208 
02209     PyDict_SetItemString(d, "Gender", module_tmp);
02210 
02211     LOG(llevDebug, "Python:  [Done]\n");
02212 }
02213 
02214 MODULEAPI void closePlugin()
02215 {
02216     LOG(llevDebug, "Python Plugin closing.\n");
02217     hooks->cache_remove_by_flags(CACHE_FLAG_GEVENT);
02218     Py_Finalize();
02219 }
02220 
02226 static int set_face_field(void *ptr, long face_id)
02227 {
02228     if (face_id < 0 || face_id >= *hooks->nrofpixmaps)
02229     {
02230         PyErr_Format(PyExc_ValueError, "Illegal value for face field: %ld", face_id);
02231         return -1;
02232     }
02233 
02234     *(New_Face **) ptr = &(*hooks->new_faces)[face_id];
02235     return 0;
02236 }
02237 
02243 static int set_animation_field(void *ptr, long anim_id)
02244 {
02245     if (anim_id < 0 || anim_id >= *hooks->num_animations)
02246     {
02247         PyErr_Format(PyExc_ValueError, "Illegal value for animation field: %ld", anim_id);
02248         return -1;
02249     }
02250 
02251     *(uint16 *) ptr = (uint16) anim_id;
02252     return 0;
02253 }
02254 
02261 int generic_field_setter(fields_struct *field, void *ptr, PyObject *value)
02262 {
02263     void *field_ptr;
02264 
02265     if ((field->flags & FIELDFLAG_READONLY))
02266     {
02267         INTRAISE("Trying to modify readonly field.");
02268     }
02269 
02270     field_ptr = (void *) ((char *) ptr + field->offset);
02271 
02272     switch (field->type)
02273     {
02274         case FIELDTYPE_SHSTR:
02275             if (value == Py_None)
02276             {
02277                 FREE_AND_CLEAR_HASH(*(shstr **) field_ptr);
02278             }
02279             else if (PyString_Check(value))
02280             {
02281                 FREE_AND_CLEAR_HASH(*(shstr **) field_ptr);
02282                 FREE_AND_COPY_HASH(*(shstr **) field_ptr, PyString_AsString(value));
02283             }
02284             else
02285             {
02286                 INTRAISE("Illegal value for shared string field.");
02287             }
02288 
02289             break;
02290 
02291         case FIELDTYPE_CSTR:
02292             if (value == Py_None)
02293             {
02294                 FREE_AND_NULL_PTR(*(char **) field_ptr);
02295             }
02296             else if (PyString_Check(value))
02297             {
02298                 if (*(char **) field_ptr)
02299                 {
02300                     free(*(char **) field_ptr);
02301                 }
02302 
02303                 *(char **) field_ptr = hooks->strdup_local(PyString_AsString(value));
02304             }
02305             else
02306             {
02307                 INTRAISE("Illegal value for C string field.");
02308             }
02309 
02310             break;
02311 
02312         case FIELDTYPE_CARY:
02313             if (value == Py_None)
02314             {
02315                 ((char *) field_ptr)[0] = '\0';
02316             }
02317             else if (PyString_Check(value))
02318             {
02319                 memcpy((char *) field_ptr, PyString_AsString(value), field->extra_data);
02320                 ((char *) field_ptr)[field->extra_data] = '\0';
02321             }
02322             else
02323             {
02324                 INTRAISE("Illegal value for C char array field.");
02325             }
02326 
02327             break;
02328 
02329         case FIELDTYPE_UINT8:
02330             if (PyInt_Check(value))
02331             {
02332                 long val = PyLong_AsLong(value);
02333 
02334                 if (val < 0 || (unsigned long) val > UINT8_MAX)
02335                 {
02336                     PyErr_SetString(PyExc_OverflowError, "Invalid integer value for uint8 field.");
02337                     return -1;
02338                 }
02339 
02340                 *(uint8 *) field_ptr = (uint8) val;
02341             }
02342             else
02343             {
02344                 INTRAISE("Illegal value for uint8 field.");
02345             }
02346 
02347             break;
02348 
02349         case FIELDTYPE_SINT8:
02350             if (PyInt_Check(value))
02351             {
02352                 long val = PyLong_AsLong(value);
02353 
02354                 if (val < SINT8_MIN || val > SINT8_MAX)
02355                 {
02356                     PyErr_SetString(PyExc_OverflowError, "Invalid integer value for sint8 field.");
02357                     return -1;
02358                 }
02359 
02360                 *(sint8 *) field_ptr = (sint8) val;
02361             }
02362             else
02363             {
02364                 INTRAISE("Illegal value for sint8 field.");
02365             }
02366 
02367             break;
02368 
02369         case FIELDTYPE_UINT16:
02370             if (PyInt_Check(value))
02371             {
02372                 long val = PyLong_AsLong(value);
02373 
02374                 if (val < 0 || (unsigned long) val > UINT16_MAX)
02375                 {
02376                     PyErr_SetString(PyExc_OverflowError, "Invalid integer value for uint16 field.");
02377                     return -1;
02378                 }
02379 
02380                 *(uint16 *) field_ptr = (uint16) val;
02381             }
02382             else
02383             {
02384                 INTRAISE("Illegal value for uint16 field.");
02385             }
02386 
02387             break;
02388 
02389         case FIELDTYPE_SINT16:
02390             if (PyInt_Check(value))
02391             {
02392                 long val = PyLong_AsLong(value);
02393 
02394                 if (val < SINT16_MIN || val > SINT16_MAX)
02395                 {
02396                     PyErr_SetString(PyExc_OverflowError, "Invalid integer value for sint16 field.");
02397                     return -1;
02398                 }
02399 
02400                 *(sint16 *) field_ptr = (sint16) val;
02401             }
02402             else
02403             {
02404                 INTRAISE("Illegal value for sint16 field.");
02405             }
02406 
02407             break;
02408 
02409         case FIELDTYPE_UINT32:
02410             if (PyInt_Check(value))
02411             {
02412                 long val = PyLong_AsLong(value);
02413 
02414                 if (val < 0 || (unsigned long) val > UINT32_MAX)
02415                 {
02416                     PyErr_SetString(PyExc_OverflowError, "Invalid integer value for uint32 field.");
02417                     return -1;
02418                 }
02419 
02420                 *(uint32 *) field_ptr = (uint32) val;
02421             }
02422             else
02423             {
02424                 INTRAISE("Illegal value for uint32 field.");
02425             }
02426 
02427             break;
02428 
02429         case FIELDTYPE_SINT32:
02430             if (PyInt_Check(value))
02431             {
02432                 long val = PyLong_AsLong(value);
02433 
02434                 if (val < SINT32_MIN || val > SINT32_MAX)
02435                 {
02436                     PyErr_SetString(PyExc_OverflowError, "Invalid integer value for sint32 field.");
02437                     return -1;
02438                 }
02439 
02440                 *(sint32 *) field_ptr = (sint32) val;
02441             }
02442             else
02443             {
02444                 INTRAISE("Illegal value for sint32 field.");
02445             }
02446 
02447             break;
02448 
02449         case FIELDTYPE_UINT64:
02450             if (PyInt_Check(value))
02451             {
02452                 unsigned PY_LONG_LONG val = PyLong_AsUnsignedLongLong(value);
02453 
02454                 if (PyErr_Occurred())
02455                 {
02456                     PyErr_SetString(PyExc_OverflowError, "Invalid integer value for uint64 field.");
02457                     return -1;
02458                 }
02459 
02460                 *(uint64 *) field_ptr = (uint64) val;
02461             }
02462             else
02463             {
02464                 INTRAISE("Illegal value for uint64 field.");
02465             }
02466 
02467             break;
02468 
02469         case FIELDTYPE_SINT64:
02470             if (PyInt_Check(value))
02471             {
02472                 PY_LONG_LONG val = PyLong_AsLongLong(value);
02473 
02474                 if (PyErr_Occurred())
02475                 {
02476                     PyErr_SetString(PyExc_OverflowError, "Invalid integer value for sint64 field.");
02477                     return -1;
02478                 }
02479 
02480                 *(sint64 *) field_ptr = (sint64) val;
02481             }
02482             else
02483             {
02484                 INTRAISE("Illegal value for sint64 field.");
02485             }
02486 
02487             break;
02488 
02489         case FIELDTYPE_FLOAT:
02490             if (PyFloat_Check(value))
02491             {
02492                 *(float *) field_ptr = PyFloat_AsDouble(value) * 1.0;
02493             }
02494             else if (PyInt_Check(value))
02495             {
02496                 *(float *) field_ptr = PyLong_AsLong(value) * 1.0;
02497             }
02498             else
02499             {
02500                 INTRAISE("Illegal value for float field.");
02501             }
02502 
02503             break;
02504 
02505         case FIELDTYPE_OBJECT:
02506             if (value == Py_None)
02507             {
02508                 *(object **) field_ptr = NULL;
02509             }
02510             else if (PyObject_TypeCheck(value, &Atrinik_ObjectType))
02511             {
02512                 OBJEXISTCHECK_INT((Atrinik_Object *) value);
02513                 *(object **) field_ptr = (object *) ((Atrinik_Object *) value)->obj;
02514             }
02515             else
02516             {
02517                 INTRAISE("Illegal value for object field.");
02518             }
02519 
02520             break;
02521 
02522         case FIELDTYPE_OBJECT2:
02523             INTRAISE("Field type not implemented.");
02524             break;
02525 
02526         case FIELDTYPE_MAP:
02527             if (value == Py_None)
02528             {
02529                 *(mapstruct **) field_ptr = NULL;
02530             }
02531             else if (PyObject_TypeCheck(value, &Atrinik_MapType))
02532             {
02533                 *(mapstruct **) field_ptr = (mapstruct *) ((Atrinik_Map *) value)->map;
02534             }
02535             else
02536             {
02537                 INTRAISE("Illegal value for map field.");
02538             }
02539 
02540             break;
02541 
02542         case FIELDTYPE_OBJECTREF:
02543         {
02544             void *field_ptr2 = (void *) ((char *) ptr + field->extra_data);
02545 
02546             if (value == Py_None)
02547             {
02548                 *(object **) field_ptr = NULL;
02549                 *(tag_t *) field_ptr2 = 0;
02550             }
02551             else if (PyObject_TypeCheck(value, &Atrinik_ObjectType))
02552             {
02553                 object *tmp;
02554 
02555                 OBJEXISTCHECK_INT((Atrinik_Object *) value);
02556 
02557                 tmp = (object *) ((Atrinik_Object *) value)->obj;
02558                 *(object **) field_ptr = tmp;
02559                 *(tag_t *) field_ptr2 = tmp->count;
02560             }
02561             else
02562             {
02563                 INTRAISE("Illegal value for object+reference field.");
02564             }
02565 
02566             break;
02567         }
02568 
02569         case FIELDTYPE_REGION:
02570             if (value == Py_None)
02571             {
02572                 *(region **) field_ptr = NULL;
02573             }
02574             else if (PyObject_TypeCheck(value, &Atrinik_RegionType))
02575             {
02576                 *(region **) field_ptr = (region *) ((Atrinik_Region *) value)->region;
02577             }
02578             else
02579             {
02580                 INTRAISE("Illegal value for region field.");
02581             }
02582 
02583             break;
02584 
02585         case FIELDTYPE_PARTY:
02586             if (value == Py_None)
02587             {
02588                 *(party_struct **) field_ptr = NULL;
02589             }
02590             else if (PyObject_TypeCheck(value, &Atrinik_PartyType))
02591             {
02592                 *(party_struct **) field_ptr = (party_struct *) ((Atrinik_Party *) value)->party;
02593             }
02594             else
02595             {
02596                 INTRAISE("Illegal value for party field.");
02597             }
02598 
02599             break;
02600 
02601         case FIELDTYPE_ARCH:
02602             if (value == Py_None)
02603             {
02604                 *(archetype **) field_ptr = NULL;
02605             }
02606             else if (PyObject_TypeCheck(value, &Atrinik_ArchetypeType))
02607             {
02608                 *(archetype **) field_ptr = (archetype *) ((Atrinik_Archetype *) value)->at;
02609             }
02610             else
02611             {
02612                 INTRAISE("Illegal value for archetype field.");
02613             }
02614 
02615             break;
02616 
02617         case FIELDTYPE_PLAYER:
02618             if (value == Py_None)
02619             {
02620                 *(player **) field_ptr = NULL;
02621             }
02622             else if (PyObject_TypeCheck(value, &Atrinik_PlayerType))
02623             {
02624                 *(player **) field_ptr = (player *) ((Atrinik_Player *) value)->pl;
02625             }
02626             else
02627             {
02628                 INTRAISE("Illegal value for player field.");
02629             }
02630 
02631             break;
02632 
02633         case FIELDTYPE_FACE:
02634             if (PyTuple_Check(value))
02635             {
02636                 if (PyTuple_GET_SIZE(value) != 2)
02637                 {
02638                     PyErr_Format(PyExc_ValueError, "Tuple for face field must have exactly two values.");
02639                     return -1;
02640                 }
02641                 else if (!PyInt_Check(PyTuple_GET_ITEM(value, 1)))
02642                 {
02643                     PyErr_SetString(PyExc_ValueError, "Second value of tuple used for face field is not an integer.");
02644                     return -1;
02645                 }
02646 
02647                 return set_face_field(field_ptr, PyLong_AsLong(PyTuple_GET_ITEM(value, 1)));
02648             }
02649             else if (PyInt_Check(value))
02650             {
02651                 return set_face_field(field_ptr, PyLong_AsLong(value));
02652             }
02653             else if (PyString_Check(value))
02654             {
02655                 return set_face_field(field_ptr, hooks->find_face(PyString_AsString(value), 0));
02656             }
02657             else
02658             {
02659                 INTRAISE("Illegal value for face field.");
02660             }
02661 
02662             break;
02663 
02664         case FIELDTYPE_ANIMATION:
02665             if (PyTuple_Check(value))
02666             {
02667                 if (PyTuple_GET_SIZE(value) != 2)
02668                 {
02669                     PyErr_Format(PyExc_ValueError, "Tuple for animation field must have exactly two values.");
02670                     return -1;
02671                 }
02672                 else if (!PyInt_Check(PyTuple_GET_ITEM(value, 1)))
02673                 {
02674                     PyErr_SetString(PyExc_ValueError, "Second value of tuple used for animation field is not an integer.");
02675                     return -1;
02676                 }
02677 
02678                 return set_animation_field(field_ptr, PyLong_AsLong(PyTuple_GET_ITEM(value, 1)));
02679             }
02680             else if (PyInt_Check(value))
02681             {
02682                 return set_animation_field(field_ptr, PyLong_AsLong(value));
02683             }
02684             else if (PyString_Check(value))
02685             {
02686                 return set_animation_field(field_ptr, hooks->find_animation(PyString_AsString(value)));
02687             }
02688             else
02689             {
02690                 INTRAISE("Illegal value for animation field.");
02691             }
02692 
02693             break;
02694 
02695         case FIELDTYPE_BOOLEAN:
02696             if (value == Py_True)
02697             {
02698                 *(uint8 *) field_ptr = 1;
02699             }
02700             else if (value == Py_False)
02701             {
02702                 *(uint8 *) field_ptr = 0;
02703             }
02704             else
02705             {
02706                 INTRAISE("Illegal value for boolean field.");
02707             }
02708 
02709             break;
02710 
02711         default:
02712             break;
02713     }
02714 
02715     return 0;
02716 }
02717 
02724 PyObject *generic_field_getter(fields_struct *field, void *ptr)
02725 {
02726     void *field_ptr;
02727 
02728     field_ptr = (void *) ((char *) ptr + field->offset);
02729 
02730     switch (field->type)
02731     {
02732         case FIELDTYPE_SHSTR:
02733         case FIELDTYPE_CSTR:
02734         {
02735             char *str = *(char **) field_ptr;
02736             return Py_BuildValue("s", str ? str : "");
02737         }
02738 
02739         case FIELDTYPE_CARY:
02740             return Py_BuildValue("s", (char *) field_ptr);
02741 
02742         case FIELDTYPE_UINT8:
02743             return Py_BuildValue("B", *(uint8 *) field_ptr);
02744 
02745         case FIELDTYPE_SINT8:
02746             return Py_BuildValue("b", *(sint8 *) field_ptr);
02747 
02748         case FIELDTYPE_UINT16:
02749             return Py_BuildValue("H", *(uint16 *) field_ptr);
02750 
02751         case FIELDTYPE_SINT16:
02752             return Py_BuildValue("h", *(sint16 *) field_ptr);
02753 
02754         case FIELDTYPE_UINT32:
02755             return Py_BuildValue("I", *(uint32 *) field_ptr);
02756 
02757         case FIELDTYPE_SINT32:
02758             return Py_BuildValue("i", *(sint32 *) field_ptr);
02759 
02760         case FIELDTYPE_UINT64:
02761             return Py_BuildValue("K", *(uint64 *) field_ptr);
02762 
02763         case FIELDTYPE_SINT64:
02764             return Py_BuildValue("L", *(sint64 *) field_ptr);
02765 
02766         case FIELDTYPE_FLOAT:
02767             return Py_BuildValue("f", *(float *) field_ptr);
02768 
02769         case FIELDTYPE_MAP:
02770             return wrap_map(*(mapstruct **) field_ptr);
02771 
02772         case FIELDTYPE_OBJECT:
02773             return wrap_object(*(object **) field_ptr);
02774 
02775         case FIELDTYPE_OBJECT2:
02776             return wrap_object((object *) field_ptr);
02777 
02778         case FIELDTYPE_OBJECTREF:
02779         {
02780             object *obj = *(object **) field_ptr;
02781             tag_t tag = *(tag_t *) (void *) ((char *) ptr + field->extra_data);
02782 
02783             return wrap_object(OBJECT_VALID(obj, tag) ? obj : NULL);
02784         }
02785 
02786         case FIELDTYPE_REGION:
02787             return wrap_region(*(region **) field_ptr);
02788 
02789         case FIELDTYPE_PARTY:
02790             return wrap_party(*(party_struct **) field_ptr);
02791 
02792         case FIELDTYPE_ARCH:
02793             return wrap_archetype(*(archetype **) field_ptr);
02794 
02795         case FIELDTYPE_PLAYER:
02796             return wrap_player(*(player **) field_ptr);
02797 
02798         case FIELDTYPE_FACE:
02799             return Py_BuildValue("(sH)", (*(New_Face **) field_ptr)->name, (*(New_Face **) field_ptr)->number);
02800 
02801         case FIELDTYPE_ANIMATION:
02802             return Py_BuildValue("(sH)", (&(*hooks->animations)[*(uint16 *) field_ptr])->name, *(uint16 *) field_ptr);
02803 
02804         case FIELDTYPE_BOOLEAN:
02805             Py_ReturnBoolean(*(uint8 *) field_ptr);
02806 
02807         case FIELDTYPE_LIST:
02808             return wrap_attr_list(ptr, field->offset, field->extra_data);
02809 
02810         default:
02811             break;
02812     }
02813 
02814     RAISE("Unknown field type.");
02815 }
02816 
02822 PyObject *generic_rich_compare(int op, int result)
02823 {
02824     /* Based on how Python 3.0 (GPL compatible) implements it for internal types. */
02825     switch (op)
02826     {
02827         case Py_EQ:
02828             result = (result == 0);
02829             break;
02830         case Py_NE:
02831             result = (result != 0);
02832             break;
02833         case Py_LE:
02834             result = (result <= 0);
02835             break;
02836         case Py_GE:
02837             result = (result >= 0);
02838             break;
02839         case Py_LT:
02840             result = (result == -1);
02841             break;
02842         case Py_GT:
02843             result = (result == 1);
02844             break;
02845     }
02846 
02847     return PyBool_FromLong(result);
02848 }
02849 
02856 int python_call_int(PyObject *callable, PyObject *arglist)
02857 {
02858     PyObject *result;
02859     int retval = 0;
02860 
02861     /* Call the Python function. */
02862     result = PyEval_CallObject(callable, arglist);
02863 
02864     /* Check the result. */
02865     if (result && PyInt_Check(result))
02866     {
02867         retval = PyInt_AsLong(result);
02868     }
02869 
02870     Py_XDECREF(result);
02871     Py_DECREF(arglist);
02872 
02873     return retval;
02874 }