Atrinik Server  4.0
plugin_python.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
33 #ifdef WIN32
34 #include <fcntl.h>
35 #endif
36 
37 #include <plugin_python.h>
38 #include <toolkit/packet.h>
39 #include <player.h>
40 #include <object.h>
41 #include <object_methods.h>
42 
43 #include <compile.h>
44 #include <eval.h>
45 #ifdef STR
46 /* STR is redefined in node.h. Since this file doesn't use STR, we remove it */
47 #undef STR
48 #endif
49 #include <node.h>
50 
52 struct plugin_hooklist *hooks;
53 
55 PyObject *AtrinikError;
56 
64 static PyObject *py_globals_dict = NULL;
65 
71 typedef struct python_eval_struct {
74 
75  PyObject *globals;
76  PyObject *locals;
77  PyCodeObject *code;
78  double seconds;
80 
85 
87 static const char package_doc[] =
88 "The Atrinik Python package provides an interface to the Atrinik server.\n\n"
89 "The server is able to run Python scripts dynamically, usually as a response "
90 "to some event.";
91 
93 static const char module_doc_type[] =
94 "Contains all the Atrinik object types as constants.";
95 
97 static const char module_doc_gender[] =
98 "Contains gender related constants.";
99 
103 static const Atrinik_Constant constants[] = {
104  {"NORTH", NORTH},
105  {"NORTHEAST", NORTHEAST},
106  {"EAST", EAST},
107  {"SOUTHEAST", SOUTHEAST},
108  {"SOUTH", SOUTH},
109  {"SOUTHWEST", SOUTHWEST},
110  {"WEST", WEST},
111  {"NORTHWEST", NORTHWEST},
112 
113  {"PLUGIN_EVENT_NORMAL", PLUGIN_EVENT_NORMAL},
114  {"PLUGIN_EVENT_GLOBAL", PLUGIN_EVENT_GLOBAL},
115  {"PLUGIN_EVENT_MAP", PLUGIN_EVENT_MAP},
116 
117  {"EVENT_APPLY", EVENT_APPLY},
118  {"EVENT_ATTACK", EVENT_ATTACK},
119  {"EVENT_DEATH", EVENT_DEATH},
120  {"EVENT_DROP", EVENT_DROP},
121  {"EVENT_PICKUP", EVENT_PICKUP},
122  {"EVENT_SAY", EVENT_SAY},
123  {"EVENT_STOP", EVENT_STOP},
124  {"EVENT_TIME", EVENT_TIME},
125  {"EVENT_THROW", EVENT_THROW},
126  {"EVENT_TRIGGER", EVENT_TRIGGER},
127  {"EVENT_CLOSE", EVENT_CLOSE},
128  {"EVENT_ASK_SHOW", EVENT_ASK_SHOW},
129 
130  {"MEVENT_ENTER", MEVENT_ENTER},
131  {"MEVENT_LEAVE", MEVENT_LEAVE},
132  {"MEVENT_RESET", MEVENT_RESET},
133  {"MEVENT_SPELL_CAST", MEVENT_SPELL_CAST},
134  {"MEVENT_SKILL_USED", MEVENT_SKILL_USED},
135  {"MEVENT_DROP", MEVENT_DROP},
136  {"MEVENT_PICK", MEVENT_PICK},
137  {"MEVENT_PUT", MEVENT_PUT},
138  {"MEVENT_APPLY", MEVENT_APPLY},
139  {"MEVENT_LOGIN", MEVENT_LOGIN},
140  {"MEVENT_CMD_DROP", MEVENT_CMD_DROP},
141  {"MEVENT_CMD_TAKE", MEVENT_CMD_TAKE},
142  {"MEVENT_EXAMINE", MEVENT_EXAMINE},
143 
144  {"GEVENT_BORN", GEVENT_BORN},
145  {"GEVENT_LOGIN", GEVENT_LOGIN},
146  {"GEVENT_LOGOUT", GEVENT_LOGOUT},
147  {"GEVENT_PLAYER_DEATH", GEVENT_PLAYER_DEATH},
148  {"GEVENT_CACHE_REMOVED", GEVENT_CACHE_REMOVED},
149 
150  {"MAP_INFO_NORMAL", MAP_INFO_NORMAL},
151  {"MAP_INFO_ALL", MAP_INFO_ALL},
152 
153  {"COST_TRUE", COST_TRUE},
154  {"COST_BUY", COST_BUY},
155  {"COST_SELL", COST_SELL},
156 
157  {"APPLY_NORMAL", APPLY_NORMAL},
158  {"APPLY_ALWAYS", APPLY_ALWAYS},
159  {"APPLY_ALWAYS_UNAPPLY", APPLY_ALWAYS_UNAPPLY},
160  {"APPLY_NO_MERGE", APPLY_NO_MERGE},
161  {"APPLY_IGNORE_CURSE", APPLY_IGNORE_CURSE},
162  {"APPLY_NO_EVENT", APPLY_NO_EVENT},
163 
164  {"MAXLEVEL", MAXLEVEL},
165 
166  {"CAST_NORMAL", CAST_NORMAL},
167  {"CAST_WAND", CAST_WAND},
168  {"CAST_ROD", CAST_ROD},
169  {"CAST_SCROLL", CAST_SCROLL},
170  {"CAST_POTION", CAST_POTION},
171  {"CAST_NPC", CAST_NPC},
172 
173  {"IDENTIFY_NORMAL", IDENTIFY_NORMAL},
174  {"IDENTIFY_ALL", IDENTIFY_ALL},
175  {"IDENTIFY_MARKED", IDENTIFY_MARKED},
176 
177  {"CHAT_TYPE_ALL", CHAT_TYPE_ALL},
178  {"CHAT_TYPE_GAME", CHAT_TYPE_GAME},
179  {"CHAT_TYPE_CHAT", CHAT_TYPE_CHAT},
180  {"CHAT_TYPE_LOCAL", CHAT_TYPE_LOCAL},
181  {"CHAT_TYPE_PRIVATE", CHAT_TYPE_PRIVATE},
182  {"CHAT_TYPE_GUILD", CHAT_TYPE_GUILD},
183  {"CHAT_TYPE_PARTY", CHAT_TYPE_PARTY},
184  {"CHAT_TYPE_OPERATOR", CHAT_TYPE_OPERATOR},
185 
186  {"PLAYER_EQUIP_AMMO", PLAYER_EQUIP_AMMO},
187  {"PLAYER_EQUIP_AMULET", PLAYER_EQUIP_AMULET},
188  {"PLAYER_EQUIP_WEAPON", PLAYER_EQUIP_WEAPON},
189  {"PLAYER_EQUIP_SHIELD", PLAYER_EQUIP_SHIELD},
190  {"PLAYER_EQUIP_GAUNTLETS", PLAYER_EQUIP_GAUNTLETS},
191  {"PLAYER_EQUIP_RING_RIGHT", PLAYER_EQUIP_RING_RIGHT},
192  {"PLAYER_EQUIP_HELM", PLAYER_EQUIP_HELM},
193  {"PLAYER_EQUIP_ARMOUR", PLAYER_EQUIP_ARMOUR},
194  {"PLAYER_EQUIP_BELT", PLAYER_EQUIP_BELT},
195  {"PLAYER_EQUIP_PANTS", PLAYER_EQUIP_PANTS},
196  {"PLAYER_EQUIP_BOOTS", PLAYER_EQUIP_BOOTS},
197  {"PLAYER_EQUIP_CLOAK", PLAYER_EQUIP_CLOAK},
198  {"PLAYER_EQUIP_BRACERS", PLAYER_EQUIP_BRACERS},
199  {"PLAYER_EQUIP_WEAPON_RANGED", PLAYER_EQUIP_WEAPON_RANGED},
200  {"PLAYER_EQUIP_LIGHT", PLAYER_EQUIP_LIGHT},
201  {"PLAYER_EQUIP_RING_LEFT", PLAYER_EQUIP_RING_LEFT},
202  {"PLAYER_EQUIP_SKILL_ITEM", PLAYER_EQUIP_SKILL_ITEM},
203 
204  {"QUEST_TYPE_KILL", QUEST_TYPE_KILL},
205  {"QUEST_TYPE_ITEM", QUEST_TYPE_ITEM},
206  {"QUEST_TYPE_ITEM_DROP", QUEST_TYPE_ITEM_DROP},
207  {"QUEST_TYPE_SPECIAL", QUEST_TYPE_SPECIAL},
208  {"QUEST_STATUS_INVALID", QUEST_STATUS_INVALID},
209  {"QUEST_STATUS_STARTED", QUEST_STATUS_STARTED},
210  {"QUEST_STATUS_COMPLETED", QUEST_STATUS_COMPLETED},
211  {"QUEST_STATUS_FAILED", QUEST_STATUS_FAILED},
212 
213  {"PARTY_MESSAGE_STATUS", PARTY_MESSAGE_STATUS},
214  {"PARTY_MESSAGE_CHAT", PARTY_MESSAGE_CHAT},
215 
216  {"ATNR_IMPACT", ATNR_IMPACT},
217  {"ATNR_SLASH", ATNR_SLASH},
218  {"ATNR_CLEAVE", ATNR_CLEAVE},
219  {"ATNR_PIERCE", ATNR_PIERCE},
220  {"ATNR_WEAPON_MAGIC", ATNR_WEAPON_MAGIC},
221  {"ATNR_FIRE", ATNR_FIRE},
222  {"ATNR_COLD", ATNR_COLD},
223  {"ATNR_ELECTRICITY", ATNR_ELECTRICITY},
224  {"ATNR_POISON", ATNR_POISON},
225  {"ATNR_ACID", ATNR_ACID},
226  {"ATNR_MAGIC", ATNR_MAGIC},
227  {"ATNR_LIFESTEAL", ATNR_LIFESTEAL},
228  {"ATNR_BLIND", ATNR_BLIND},
229  {"ATNR_PARALYZE", ATNR_PARALYZE},
230  {"ATNR_FORCE", ATNR_FORCE},
231  {"ATNR_GODPOWER", ATNR_GODPOWER},
232  {"ATNR_CHAOS", ATNR_CHAOS},
233  {"ATNR_DRAIN", ATNR_DRAIN},
234  {"ATNR_SLOW", ATNR_SLOW},
235  {"ATNR_CONFUSION", ATNR_CONFUSION},
236  {"ATNR_INTERNAL", ATNR_INTERNAL},
237  {"NROFATTACKS", NROFATTACKS},
238 
239  {"TERRAIN_NOTHING", TERRAIN_NOTHING},
240  {"TERRAIN_AIRBREATH", TERRAIN_AIRBREATH},
241  {"TERRAIN_WATERWALK", TERRAIN_WATERWALK},
242  {"TERRAIN_WATERBREATH", TERRAIN_WATERBREATH},
243  {"TERRAIN_FIREWALK", TERRAIN_FIREWALK},
244  {"TERRAIN_FIREBREATH", TERRAIN_FIREBREATH},
245  {"TERRAIN_CLOUDWALK", TERRAIN_CLOUDWALK},
246  {"TERRAIN_WATER_SHALLOW", TERRAIN_WATER_SHALLOW},
247  {"TERRAIN_ALL", TERRAIN_ALL},
248 
249  {"P_BLOCKSVIEW", P_BLOCKSVIEW},
250  {"P_NO_MAGIC", P_NO_MAGIC},
251  {"P_NO_PASS", P_NO_PASS},
252  {"P_IS_PLAYER", P_IS_PLAYER},
253  {"P_IS_MONSTER", P_IS_MONSTER},
254  {"P_PLAYER_ONLY", P_PLAYER_ONLY},
255  {"P_DOOR_CLOSED", P_DOOR_CLOSED},
256  {"P_CHECK_INV", P_CHECK_INV},
257  {"P_NO_PVP", P_NO_PVP},
258  {"P_PASS_THRU", P_PASS_THRU},
259  {"P_WALK_ON", P_WALK_ON},
260  {"P_WALK_OFF", P_WALK_OFF},
261  {"P_FLY_OFF", P_FLY_OFF},
262  {"P_FLY_ON", P_FLY_ON},
263  {"P_MAGIC_MIRROR", P_MAGIC_MIRROR},
264  {"P_OUTDOOR", P_OUTDOOR},
265  {"P_OUT_OF_MAP", P_OUT_OF_MAP},
266  {"P_NEED_UPDATE", P_NEED_UPDATE},
267  {"P_NO_TERRAIN", P_NO_TERRAIN},
268 
269  {"CMD_SOUND_EFFECT", CMD_SOUND_EFFECT},
270  {"CMD_SOUND_BACKGROUND", CMD_SOUND_BACKGROUND},
271  {"CMD_SOUND_ABSOLUTE", CMD_SOUND_ABSOLUTE},
272 
273  {"BANK_SYNTAX_ERROR", BANK_SYNTAX_ERROR},
274  {"BANK_SUCCESS", BANK_SUCCESS},
275 
276  {"BANK_WITHDRAW_HIGH", BANK_WITHDRAW_HIGH},
277  {"BANK_WITHDRAW_MISSING", BANK_WITHDRAW_MISSING},
278  {"BANK_WITHDRAW_OVERWEIGHT", BANK_WITHDRAW_OVERWEIGHT},
279 
280  {"BANK_DEPOSIT_COPPER", BANK_DEPOSIT_COPPER},
281  {"BANK_DEPOSIT_SILVER", BANK_DEPOSIT_SILVER},
282  {"BANK_DEPOSIT_GOLD", BANK_DEPOSIT_GOLD},
283  {"BANK_DEPOSIT_JADE", BANK_DEPOSIT_JADE},
284  {"BANK_DEPOSIT_MITHRIL", BANK_DEPOSIT_MITHRIL},
285  {"BANK_DEPOSIT_AMBER", BANK_DEPOSIT_AMBER},
286 
287  {"AROUND_ALL", AROUND_ALL},
288  {"AROUND_WALL", AROUND_WALL},
289  {"AROUND_BLOCKSVIEW", AROUND_BLOCKSVIEW},
290  {"AROUND_PLAYER_ONLY", AROUND_PLAYER_ONLY},
291 
292  {"LAYER_SYS", LAYER_SYS},
293  {"LAYER_FLOOR", LAYER_FLOOR},
294  {"LAYER_FMASK", LAYER_FMASK},
295  {"LAYER_ITEM", LAYER_ITEM},
296  {"LAYER_ITEM2", LAYER_ITEM2},
297  {"LAYER_WALL", LAYER_WALL},
298  {"LAYER_LIVING", LAYER_LIVING},
299  {"LAYER_EFFECT", LAYER_EFFECT},
300 
301  {"NUM_LAYERS", NUM_LAYERS},
302  {"NUM_SUB_LAYERS", NUM_SUB_LAYERS},
303 
304  {"INVENTORY_ONLY", INVENTORY_ONLY},
305  {"INVENTORY_CONTAINERS", INVENTORY_CONTAINERS},
306  {"INVENTORY_ALL", INVENTORY_ALL},
307 
308  {"GT_ENVIRONMENT", GT_ENVIRONMENT},
309  {"GT_STARTEQUIP", GT_STARTEQUIP},
310  {"GT_APPLY", GT_APPLY},
311  {"GT_ONLY_GOOD", GT_ONLY_GOOD},
312  {"GT_UPDATE_INV", GT_UPDATE_INV},
313  {"GT_NO_VALUE", GT_NO_VALUE},
314 
315  {"SIZEOFFREE1", SIZEOFFREE1},
316  {"SIZEOFFREE2", SIZEOFFREE2},
317  {"SIZEOFFREE3", SIZEOFFREE3},
318  {"SIZEOFFREE", SIZEOFFREE},
319 
320  {"NROFREALSPELLS", NROFREALSPELLS},
321 
322  {"MAX_TIME", MAX_TIME},
323 
324  {"OBJECT_METHOD_UNHANDLED", OBJECT_METHOD_UNHANDLED},
325  {"OBJECT_METHOD_OK", OBJECT_METHOD_OK},
326  {"OBJECT_METHOD_ERROR", OBJECT_METHOD_ERROR},
327 
328  {"UPD_LOCATION", UPD_LOCATION},
329  {"UPD_FLAGS", UPD_FLAGS},
330  {"UPD_WEIGHT", UPD_WEIGHT},
331  {"UPD_FACE", UPD_FACE},
332  {"UPD_NAME", UPD_NAME},
333  {"UPD_ANIM", UPD_ANIM},
334  {"UPD_ANIMSPEED", UPD_ANIMSPEED},
335  {"UPD_NROF", UPD_NROF},
336  {"UPD_DIRECTION", UPD_DIRECTION},
337  {"UPD_TYPE", UPD_TYPE},
338  {"UPD_EXTRA", UPD_EXTRA},
339  {"UPD_GLOW", UPD_GLOW},
340 
341  {"RV_MANHATTAN_DISTANCE", RV_MANHATTAN_DISTANCE},
342  {"RV_EUCLIDIAN_DISTANCE", RV_EUCLIDIAN_DISTANCE},
343  {"RV_DIAGONAL_DISTANCE", RV_DIAGONAL_DISTANCE},
344  {"RV_NO_DISTANCE", RV_NO_DISTANCE},
345  {"RV_IGNORE_MULTIPART", RV_IGNORE_MULTIPART},
346  {"RV_RECURSIVE_SEARCH", RV_RECURSIVE_SEARCH},
347  {"RV_NO_LOAD", RV_NO_LOAD},
348 
349  {"TREASURE_ARTIFACT_CHANCE", TREASURE_ARTIFACT_CHANCE},
350 
351  {NULL, 0}
352 };
353 
358  {"PLAYER", PLAYER},
359  {"BULLET", BULLET},
360  {"ROD", ROD},
361  {"TREASURE", TREASURE},
362  {"POTION", POTION},
363  {"FOOD", FOOD},
364  {"REGION_MAP", REGION_MAP},
365  {"BOOK", BOOK},
366  {"CLOCK", CLOCK},
367  {"MATERIAL", MATERIAL},
368  {"DUPLICATOR", DUPLICATOR},
369  {"LIGHTNING", LIGHTNING},
370  {"ARROW", ARROW},
371  {"BOW", BOW},
372  {"WEAPON", WEAPON},
373  {"ARMOUR", ARMOUR},
374  {"PEDESTAL", PEDESTAL},
375  {"CONFUSION", CONFUSION},
376  {"DOOR", DOOR},
377  {"KEY", KEY},
378  {"MAP", MAP},
379  {"MAGIC_MIRROR", MAGIC_MIRROR},
380  {"SPELL", SPELL},
381  {"SHIELD", SHIELD},
382  {"HELMET", HELMET},
383  {"PANTS", PANTS},
384  {"MONEY", MONEY},
385  {"AMULET", AMULET},
386  {"PLAYER_MOVER", PLAYER_MOVER},
387  {"CREATOR", CREATOR},
388  {"SKILL", SKILL},
389  {"BLINDNESS", BLINDNESS},
390  {"GOD", GOD},
391  {"DETECTOR", DETECTOR},
392  {"SKILL_ITEM", SKILL_ITEM},
393  {"DEAD_OBJECT", DEAD_OBJECT},
394  {"DRINK", DRINK},
395  {"MARKER", MARKER},
396  {"HOLY_ALTAR", HOLY_ALTAR},
397  {"PEARL", PEARL},
398  {"GEM", GEM},
399  {"SOUND_AMBIENT", SOUND_AMBIENT},
400  {"FIREWALL", FIREWALL},
401  {"CHECK_INV", CHECK_INV},
402  {"EXIT", EXIT},
403  {"SHOP_FLOOR", SHOP_FLOOR},
404  {"RING", RING},
405  {"FLOOR", FLOOR},
406  {"FLESH", FLESH},
407  {"INORGANIC", INORGANIC},
408  {"LIGHT_APPLY", LIGHT_APPLY},
409  {"WALL", WALL},
410  {"LIGHT_SOURCE", LIGHT_SOURCE},
411  {"MISC_OBJECT", MISC_OBJECT},
412  {"MONSTER", MONSTER},
413  {"SPAWN_POINT", SPAWN_POINT},
414  {"LIGHT_REFILL", LIGHT_REFILL},
415  {"SPAWN_POINT_MOB", SPAWN_POINT_MOB},
416  {"SPAWN_POINT_INFO", SPAWN_POINT_INFO},
417  {"BOOK_SPELL", BOOK_SPELL},
418  {"ORGANIC", ORGANIC},
419  {"CLOAK", CLOAK},
420  {"CONE", CONE},
421  {"SPINNER", SPINNER},
422  {"GATE", GATE},
423  {"BUTTON", BUTTON},
424  {"HANDLE", TYPE_HANDLE},
425  {"WORD_OF_RECALL", WORD_OF_RECALL},
426  {"SIGN", SIGN},
427  {"BOOTS", BOOTS},
428  {"GLOVES", GLOVES},
429  {"BASE_INFO", BASE_INFO},
430  {"RANDOM_DROP", RANDOM_DROP},
431  {"BRACERS", BRACERS},
432  {"POISONING", POISONING},
433  {"SAVEBED", SAVEBED},
434  {"WAND", WAND},
435  {"ABILITY", ABILITY},
436  {"SCROLL", SCROLL},
437  {"DIRECTOR", DIRECTOR},
438  {"GIRDLE", GIRDLE},
439  {"FORCE", FORCE},
440  {"POTION_EFFECT", POTION_EFFECT},
441  {"JEWEL", JEWEL},
442  {"NUGGET", NUGGET},
443  {"EVENT_OBJECT", EVENT_OBJECT},
444  {"WAYPOINT_OBJECT", WAYPOINT_OBJECT},
445  {"QUEST_CONTAINER", QUEST_CONTAINER},
446  {"CONTAINER", CONTAINER},
447  {"WEALTH", WEALTH},
448  {"BEACON", BEACON},
449  {"MAP_EVENT_OBJ", MAP_EVENT_OBJ},
450  {"COMPASS", COMPASS},
451  {"MAP_INFO", MAP_INFO},
452  {"SWARM_SPELL", SWARM_SPELL},
453  {"RUNE", RUNE},
454  {"CLIENT_MAP_INFO", CLIENT_MAP_INFO},
455  {"POWER_CRYSTAL", POWER_CRYSTAL},
456  {"CORPSE", CORPSE},
457  {"DISEASE", DISEASE},
458  {"SYMPTOM", SYMPTOM},
459  {"TRINKET", TRINKET},
460 
461  {NULL, 0}
462 };
463 
468  {"NEUTER", GENDER_NEUTER},
469  {"MALE", GENDER_MALE},
470  {"FEMALE", GENDER_FEMALE},
471  {"HERMAPHRODITE", GENDER_HERMAPHRODITE},
472 
473  {NULL, 0}
474 };
475 
479 static const char *const constants_colors[][2] = {
480  {"COLOR_WHITE", COLOR_WHITE},
481  {"COLOR_ORANGE", COLOR_ORANGE},
482  {"COLOR_NAVY", COLOR_NAVY},
483  {"COLOR_RED", COLOR_RED},
484  {"COLOR_GREEN", COLOR_GREEN},
485  {"COLOR_BLUE", COLOR_BLUE},
486  {"COLOR_GRAY", COLOR_GRAY},
487  {"COLOR_BROWN", COLOR_BROWN},
488  {"COLOR_PURPLE", COLOR_PURPLE},
489  {"COLOR_PINK", COLOR_PINK},
490  {"COLOR_YELLOW", COLOR_YELLOW},
491  {"COLOR_DK_NAVY", COLOR_DK_NAVY},
492  {"COLOR_DK_GREEN", COLOR_DK_GREEN},
493  {"COLOR_DK_ORANGE", COLOR_DK_ORANGE},
494  {"COLOR_HGOLD", COLOR_HGOLD},
495  {"COLOR_DGOLD", COLOR_DGOLD},
496  {NULL, NULL}
497 };
498 
501 
505 static void initContextStack(void)
506 {
507  current_context = NULL;
508  context_stack = NULL;
509 }
510 
516 static void pushContext(PythonContext *context)
517 {
518  if (current_context == NULL) {
519  context_stack = context;
520  context->down = NULL;
521  } else {
522  context->down = current_context;
523  }
524 
525  current_context = context;
526 }
527 
536 {
537  PythonContext *oldcontext;
538 
539  if (current_context) {
540  oldcontext = current_context;
541  current_context = current_context->down;
542  return oldcontext;
543  }
544 
545  return NULL;
546 }
547 
553 static void freeContext(PythonContext *context)
554 {
555  free(context);
556 }
557 
570 static PyObject *py_runfile(const char *path, PyObject *globals,
571  PyObject *locals)
572 {
573  char *fullpath;
574  FILE *fp;
575  PyObject *ret = NULL;
576 
577  fullpath = strdup(hooks->create_pathname(path));
578 
579  fp = fopen(fullpath, "r");
580 
581  if (fp) {
582 #ifdef WIN32
583  StringBuffer *sb;
584  char *cp;
585 
586  fclose(fp);
587 
588  sb = hooks->stringbuffer_new();
589  hooks->stringbuffer_append_printf(sb, "exec(open('%s').read())",
590  fullpath);
591  cp = hooks->stringbuffer_finish(sb);
592  PyRun_String(cp, Py_file_input, globals, locals);
593  efree(cp);
594 #else
595  ret = PyRun_File(fp, fullpath, Py_file_input, globals, locals);
596  fclose(fp);
597 #endif
598  }
599 
600  free(fullpath);
601 
602  return ret;
603 }
604 
613 static void py_runfile_simple(const char *path, PyObject *locals)
614 {
615  PyObject *globals, *ret;
616 
617  /* Construct globals dictionary. */
618  globals = PyDict_New();
619  PyDict_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());
620 
621  /* Run the Python code. */
622  ret = py_runfile(path, globals, locals);
623 
624  Py_DECREF(globals);
625  Py_XDECREF(ret);
626 }
627 
632 static void PyErr_LOG(void)
633 {
634  PyObject *locals;
635  PyObject *ptype, *pvalue, *ptraceback;
636 
637  /* Fetch the exception data. */
638  PyErr_Fetch(&ptype, &pvalue, &ptraceback);
639  PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
640 
641  /* Construct locals dictionary, with the exception data. */
642  locals = PyDict_New();
643  PyDict_SetItemString(locals, "exc_type", ptype);
644  PyDict_SetItemString(locals, "exc_value", pvalue);
645 
646  if (ptraceback != NULL) {
647  PyDict_SetItemString(locals, "exc_traceback", ptraceback);
648  } else {
649  Py_INCREF(Py_None);
650  PyDict_SetItemString(locals, "exc_traceback", Py_None);
651  }
652 
653  py_runfile_simple("/python/events/python_exception.py", locals);
654  Py_DECREF(locals);
655 
656  Py_XDECREF(ptype);
657  Py_XDECREF(pvalue);
658  Py_XDECREF(ptraceback);
659 }
660 
665 static PyCodeObject *compilePython(char *filename)
666 {
667  struct stat stat_buf;
669 
670  if (stat(filename, &stat_buf)) {
671  LOG(DEBUG, "Python: The script file %s can't be stat()ed.", filename);
672  return NULL;
673  }
674 
675  HASH_FIND_STR(python_cache, filename, cache);
676 
677  if (!cache || cache->cached_time < stat_buf.st_mtime) {
678  FILE *fp;
679  struct _node *n;
680  PyCodeObject *code = NULL;
681 
682  if (cache) {
683  HASH_DEL(python_cache, cache);
684  Py_XDECREF(cache->code);
685  free(cache->file);
686  free(cache);
687  }
688 
689  fp = fopen(filename, "r");
690 
691  if (!fp) {
692  LOG(BUG, "Python: The script file %s can't be opened.", filename);
693  return NULL;
694  }
695 
696 #ifdef WIN32
697  {
698  char buf[HUGE_BUF], *pystr = NULL;
699  size_t buf_len = 0, pystr_len = 0;
700 
701  while (fgets(buf, sizeof(buf), fp)) {
702  buf_len = strlen(buf);
703  pystr_len += buf_len;
704  pystr = realloc(pystr, sizeof(char) * (pystr_len + 1));
705  strcpy(pystr + pystr_len - buf_len, buf);
706  pystr[pystr_len] = '\0';
707  }
708 
709  n = PyParser_SimpleParseString(pystr, Py_file_input);
710  free(pystr);
711  }
712 #else
713  n = PyParser_SimpleParseFile(fp, filename, Py_file_input);
714 #endif
715 
716  if (n) {
717  code = PyNode_Compile(n, filename);
718  PyNode_Free(n);
719  }
720 
721  fclose(fp);
722 
723  if (PyErr_Occurred()) {
724  PyErr_LOG();
725  return NULL;
726  }
727 
728  cache = malloc(sizeof(*cache));
729  cache->file = strdup(filename);
730  cache->code = code;
731  cache->cached_time = stat_buf.st_mtime;
732  HASH_ADD_KEYPTR(hh, python_cache, cache->file, strlen(cache->file),
733  cache);
734  }
735 
736  return cache->code;
737 }
738 
739 static int do_script(PythonContext *context, const char *filename)
740 {
741  PyCodeObject *pycode;
742  PyObject *dict, *ret;
743  PyGILState_STATE gilstate;
744 
745  if (filename == NULL) {
746  return 0;
747  }
748 
749  if (context->event && !hooks->map_path_isabs(filename)) {
750  char *path;
751  object *env;
752 
753  env = hooks->object_get_env(context->event);
754 
755  path = hooks->map_get_path(env->map, filename, 0, NULL);
756  FREE_AND_COPY_HASH(context->event->race, path);
757  efree(path);
758  }
759 
760  if (context->event != NULL && hooks->string_endswith(filename, ".xml")) {
761  char *path;
762 
763  if (hooks->string_endswith(filename, "quest.xml")) {
764  char *dirname, inf_filename[MAX_BUF];
765  const char *cp;
766  size_t i;
767 
768  for (cp = context->who->name, i = 0; *cp != '\0'; cp++) {
769  if (i == sizeof(inf_filename) - 1) {
770  break;
771  }
772 
773  if (*cp == '_' || *cp == ' ' || isalpha(*cp) || isdigit(*cp)) {
774  inf_filename[i] = *cp == ' ' ? '_' : tolower(*cp);
775  i++;
776  }
777  }
778 
779  inf_filename[i] = '\0';
780  strncat(inf_filename, ".py", sizeof(inf_filename) - i - 1);
781 
782  dirname = hooks->path_dirname(filename);
783  path = hooks->path_join(dirname, inf_filename);
784  efree(dirname);
785  } else {
786  char *cp;
787 
788  cp = hooks->string_sub(filename, 0, -3 MEMORY_DEBUG_INFO);
789  path = hooks->string_join("", cp, "py", NULL);
790  efree(cp);
791  }
792 
793  FREE_AND_COPY_HASH(context->event->race, path);
794  efree(path);
795  }
796 
797  gilstate = PyGILState_Ensure();
798 
799  pycode = compilePython(hooks->create_pathname(
800  context->event != NULL ? context->event->race : filename));
801  if (pycode != NULL) {
802  if (hooks->settings->python_reload_modules) {
803  PyObject *modules = PyImport_GetModuleDict(), *key, *value;
804  Py_ssize_t pos = 0;
805  const char *m_filename;
806  char m_buf[MAX_BUF];
807 
808  /* Create path name to the Python scripts directory. */
809  strncpy(m_buf, hooks->create_pathname("/python"),
810  sizeof(m_buf) - 1);
811 
812  /* Go through the loaded modules. */
813  while (PyDict_Next(modules, &pos, &key, &value)) {
814  m_filename = PyModule_GetFilename(value);
815 
816  if (!m_filename) {
817  PyErr_Clear();
818  continue;
819  }
820 
821  /* If this module was loaded from one of our script files,
822  * reload it. */
823  if (!strncmp(m_filename, m_buf, strlen(m_buf))) {
824  PyImport_ReloadModule(value);
825 
826  if (PyErr_Occurred()) {
827  PyErr_LOG();
828  }
829  }
830  }
831  }
832 
833  pushContext(context);
834  dict = PyDict_Copy(py_globals_dict);
835  PyDict_SetItemString(dict, "activator",
836  wrap_object(context->activator));
837  PyDict_SetItemString(dict, "pl",
838  wrap_player(context->activator != NULL &&
839  context->activator->type == PLAYER ?
840  CONTR(context->activator) : NULL));
841  PyDict_SetItemString(dict, "me", wrap_object(context->who));
842 
843  if (context->text) {
844  PyDict_SetItemString(dict, "msg",
845  Py_BuildValue("s", context->text));
846  } else if (context->event && context->event->sub_type == EVENT_SAY) {
847  PyDict_SetItemString(dict, "msg", Py_BuildValue(""));
848  }
849 
850 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 2
851  ret = PyEval_EvalCode((PyObject *) pycode, dict, NULL);
852 #else
853  ret = PyEval_EvalCode(pycode, dict, NULL);
854 #endif
855 
856  if (PyErr_Occurred()) {
857  PyErr_LOG();
858  }
859 
860  Py_XDECREF(ret);
861  Py_DECREF(dict);
862 
863  PyGILState_Release(gilstate);
864 
865  return 1;
866  }
867 
868  PyGILState_Release(gilstate);
869 
870  return 0;
871 }
872 
874 static void command_custom_python(object *op, const char *command, char *params)
875 {
876  PythonContext *context = malloc(sizeof(PythonContext));
877  if (context == NULL) {
878  return;
879  }
880 
881  context->activator = op;
882  context->who = op;
883  context->other = op;
884  context->event = NULL;
885  context->parms[0] = 0;
886  context->parms[1] = 0;
887  context->parms[2] = 0;
888  context->parms[3] = 0;
889  context->text = params ? params : "";
890  context->options = NULL;
891  context->returnvalue = 0;
892 
893  char path[MAX_BUF];
894  snprintf(VS(path), "/python/commands/%s.py", command);
895  if (!do_script(context, path)) {
896  freeContext(context);
897  return;
898  }
899 
900  context = popContext();
901  freeContext(context);
902 }
903 
905 static const char doc_Atrinik_LoadObject[] =
906 ".. function:: LoadObject(text).\n\n"
907 "Load an object from a string dump, for example, one stored using "
908 ":meth:`Atrinik.Object.Object.Save`.\n\n"
909 ":param text: The object text dump.\n"
910 ":type text: str\n"
911 ":returns: New object, loaded from the text or None in case of failure.\n"
912 ":rtype: :class:`Atrinik.Object.Object` or None";
913 
918 static PyObject *Atrinik_LoadObject(PyObject *self, PyObject *args)
919 {
920  char *dumpob;
921 
922  if (!PyArg_ParseTuple(args, "s", &dumpob)) {
923  return NULL;
924  }
925 
926  return wrap_object(hooks->object_load_str(dumpob));
927 }
928 
930 static const char doc_Atrinik_ReadyMap[] =
931 ".. function:: ReadyMap(path, unique=False).\n\n"
932 "Make sure the named map is loaded into memory, loading it if necessary.\n\n"
933 ":param path: Path to the map.\n"
934 ":type path: str\n"
935 ":param unique: Whether the destination should be loaded as a unique map, for "
936 "example, apartments.\n"
937 ":type unique: bool\n"
938 ":returns: The map associated with the specified path or None in case of "
939 "failure.\n"
940 ":rtype: :class:`Atrinik.Map.Map` or None";
941 
946 static PyObject *Atrinik_ReadyMap(PyObject *self, PyObject *args)
947 {
948  const char *path;
949  int flags = 0, unique = 0;
950 
951  if (!PyArg_ParseTuple(args, "s|i", &path, &unique)) {
952  return NULL;
953  }
954 
955  if (unique) {
956  flags |= MAP_PLAYER_UNIQUE;
957  }
958 
959  return wrap_map(hooks->ready_map_name(path, NULL, flags));
960 }
961 
963 static const char doc_Atrinik_FindPlayer[] =
964 ".. function:: FindPlayer(name).\n\n"
965 "Find a player by name.\n\n"
966 ":param name: The player name to find.\n"
967 ":type name: str\n"
968 ":returns: The player's object if found, None otherwise.\n"
969 ":rtype: :class:`Atrinik.Object.Object` or None";
970 
975 static PyObject *Atrinik_FindPlayer(PyObject *self, PyObject *args)
976 {
977  const char *name;
978 
979  if (!PyArg_ParseTuple(args, "s", &name)) {
980  return NULL;
981  }
982 
983  player *pl = hooks->find_player(name);
984  if (pl != NULL) {
985  return wrap_object(pl->ob);
986  }
987 
988  Py_INCREF(Py_None);
989  return Py_None;
990 }
991 
993 static const char doc_Atrinik_PlayerExists[] =
994 ".. function:: PlayerExists(name).\n\n"
995 "Check if player exists.\n\n"
996 ":param name: The player name to check.\n"
997 ":type name: str\n"
998 ":returns: True if the player exists, False otherwise.\n"
999 ":rtype: bool";
1000 
1005 static PyObject *Atrinik_PlayerExists(PyObject *self, PyObject *args)
1006 {
1007  const char *name;
1008 
1009  if (!PyArg_ParseTuple(args, "s", &name)) {
1010  return NULL;
1011  }
1012 
1013  char *cp = strdup(name);
1014  hooks->player_cleanup_name(cp);
1015  int ret = hooks->player_exists(cp);
1016  free(cp);
1017 
1018  return Py_BuildBoolean(ret);
1019 }
1020 
1022 static const char doc_Atrinik_WhoAmI[] =
1023 ".. function:: WhoAmI().\n\n"
1024 "Get the owner of the active script (the object that has the event "
1025 "handler).\n\n"
1026 ":returns: The script owner.\n"
1027 ":rtype: :class:`Atrinik.Object.Object` or None\n"
1028 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1029 "script is running in a thread).";
1030 
1035 static PyObject *Atrinik_WhoAmI(PyObject *self)
1036 {
1037  if (current_context == NULL) {
1038  PyErr_SetString(AtrinikError, "There is no event context.");
1039  return NULL;
1040  }
1041 
1042  return wrap_object(current_context->who);
1043 }
1044 
1046 static const char doc_Atrinik_WhoIsActivator[] =
1047 ".. function:: WhoIsActivator().\n\n"
1048 "Get the object that activated the current event.\n\n"
1049 ":returns: The script activator.\n"
1050 ":rtype: :class:`Atrinik.Object.Object` or None\n"
1051 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1052 "script is running in a thread).";
1053 
1058 static PyObject *Atrinik_WhoIsActivator(PyObject *self)
1059 {
1060  if (current_context == NULL) {
1061  PyErr_SetString(AtrinikError, "There is no event context.");
1062  return NULL;
1063  }
1064 
1065  return wrap_object(current_context->activator);
1066 }
1067 
1069 static const char doc_Atrinik_WhoIsOther[] =
1070 ".. function:: WhoIsOther().\n\n"
1071 "Get another object related to the event. What this object is depends on the "
1072 "event.\n\n"
1073 ":returns: The other object.\n"
1074 ":rtype: :class:`Atrinik.Object.Object` or None\n"
1075 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1076 "script is running in a thread).";
1077 
1082 static PyObject *Atrinik_WhoIsOther(PyObject *self)
1083 {
1084  if (current_context == NULL) {
1085  PyErr_SetString(AtrinikError, "There is no event context.");
1086  return NULL;
1087  }
1088 
1089  return wrap_object(current_context->other);
1090 }
1091 
1093 static const char doc_Atrinik_WhatIsEvent[] =
1094 ".. function:: WhatIsEvent().\n\n"
1095 "Get the event object that caused this event to trigger.\n\n"
1096 ":returns: The event object.\n"
1097 ":rtype: :class:`Atrinik.Object.Object` or None\n"
1098 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1099 "script is running in a thread).";
1100 
1105 static PyObject *Atrinik_WhatIsEvent(PyObject *self)
1106 {
1107  if (current_context == NULL) {
1108  PyErr_SetString(AtrinikError, "There is no event context.");
1109  return NULL;
1110  }
1111 
1112  return wrap_object(current_context->event);
1113 }
1114 
1116 static const char doc_Atrinik_GetEventNumber[] =
1117 ".. function:: GetEventNumber().\n\n"
1118 "Get the ID of the event that is being triggered.\n\n"
1119 ":returns: Event ID.\n"
1120 ":rtype: int\n"
1121 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1122 "script is running in a thread).\n"
1123 ":raises Atrinik.AtrinikError: If there is no event object.";
1124 
1129 static PyObject *Atrinik_GetEventNumber(PyObject *self)
1130 {
1131  if (current_context == NULL) {
1132  PyErr_SetString(AtrinikError, "There is no event context.");
1133  return NULL;
1134  }
1135 
1136  if (current_context->event == NULL) {
1137  PyErr_SetString(AtrinikError, "There is no event object.");
1138  return NULL;
1139  }
1140 
1141  return Py_BuildValue("i", current_context->event->sub_type);
1142 }
1143 
1145 static const char doc_Atrinik_WhatIsMessage[] =
1146 ".. function:: WhatIsMessage().\n\n"
1147 "Gets the actual message in SAY events.\n\n"
1148 ":returns: The message.\n"
1149 ":rtype: str or None\n"
1150 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1151 "script is running in a thread).";
1152 
1157 static PyObject *Atrinik_WhatIsMessage(PyObject *self)
1158 {
1159  if (current_context == NULL) {
1160  PyErr_SetString(AtrinikError, "There is no event context.");
1161  return NULL;
1162  }
1163 
1164  return Py_BuildValue("s", current_context->text);
1165 }
1166 
1168 static const char doc_Atrinik_GetOptions[] =
1169 ".. function:: GetOptions().\n\n"
1170 "Gets the script options (as passed in the event's slaying field).\n\n"
1171 ":returns: The script options.\n"
1172 ":rtype: str or None\n"
1173 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1174 "script is running in a thread).";
1175 
1180 static PyObject *Atrinik_GetOptions(PyObject *self)
1181 {
1182  if (current_context == NULL) {
1183  PyErr_SetString(AtrinikError, "There is no event context.");
1184  return NULL;
1185  }
1186 
1187  return Py_BuildValue("s", current_context->options);
1188 }
1189 
1191 static const char doc_Atrinik_GetReturnValue[] =
1192 ".. function:: GetReturnValue().\n\n"
1193 "Gets the script's return value.\n\n"
1194 ":returns: The return value.\n"
1195 ":rtype: int\n"
1196 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1197 "script is running in a thread).";
1198 
1203 static PyObject *Atrinik_GetReturnValue(PyObject *self)
1204 {
1205  if (current_context == NULL) {
1206  PyErr_SetString(AtrinikError, "There is no event context.");
1207  return NULL;
1208  }
1209 
1210  return Py_BuildValue("i", current_context->returnvalue);
1211 }
1212 
1214 static const char doc_Atrinik_SetReturnValue[] =
1215 ".. function:: SetReturnValue(value).\n\n"
1216 "Sets the script's return value.\n\n"
1217 ":param value: The new return value.\n"
1218 ":type value: int\n"
1219 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1220 "script is running in a thread).";
1221 
1226 static PyObject *Atrinik_SetReturnValue(PyObject *self, PyObject *args)
1227 {
1228  int value;
1229 
1230  if (!PyArg_ParseTuple(args, "i", &value)) {
1231  return NULL;
1232  }
1233 
1234  if (current_context == NULL) {
1235  PyErr_SetString(AtrinikError, "There is no event context.");
1236  return NULL;
1237  }
1238 
1239  current_context->returnvalue = value;
1240 
1241  Py_INCREF(Py_None);
1242  return Py_None;
1243 }
1244 
1246 static const char doc_Atrinik_GetEventParameters[] =
1247 ".. function:: GetEventParameters().\n\n"
1248 "Get the parameters of an event. This varies from event to event, and some "
1249 "events pass all parameters as 0. EVENT_ATTACK usually passes damage done and "
1250 "the WC of the hit as second and third parameter, respectively.\n\n"
1251 ":returns: A list of the event parameters. The last entry is the event flags, "
1252 "used to determine whom to call :meth:`Atrinik.Object.Object.Update` on after "
1253 "executing the script.\n"
1254 ":rtype: list\n"
1255 ":raises Atrinik.AtrinikError: If there's no event context (for example, the "
1256 "script is running in a thread).";
1257 
1262 static PyObject *Atrinik_GetEventParameters(PyObject *self)
1263 {
1264  if (current_context == NULL) {
1265  PyErr_SetString(AtrinikError, "There is no event context.");
1266  return NULL;
1267  }
1268 
1269  PyObject *list = PyList_New(0);
1270  for (size_t i = 0; i < arraysize(current_context->parms); i++) {
1271  PyList_Append(list, Py_BuildValue("i", current_context->parms[i]));
1272  }
1273 
1274  return list;
1275 }
1276 
1278 static const char doc_Atrinik_RegisterCommand[] =
1279 ".. function:: RegisterCommand(name, speed, flags=0).\n\n"
1280 "Register a custom command ran using Python script.\n\n"
1281 ":param name: Name of the command. For example, \"roll\" in order to create "
1282 "/roll command. Note the lack of forward slash in the name.\n"
1283 ":type name: str\n"
1284 ":param speed: How long it takes to execute the command; 1.0 is usually fine.\n"
1285 ":type speed: float\n"
1286 ":param flags: Optional flags.\n"
1287 ":type flags: int";
1288 
1293 static PyObject *Atrinik_RegisterCommand(PyObject *self, PyObject *args)
1294 {
1295  const char *name;
1296  double speed;
1297  uint64_t flags = 0;
1298 
1299  if (!PyArg_ParseTuple(args, "sd|K", &name, &speed, &flags)) {
1300  return NULL;
1301  }
1302 
1303  hooks->commands_add(name, command_custom_python, speed, flags);
1304 
1305  Py_INCREF(Py_None);
1306  return Py_None;
1307 }
1308 
1310 static const char doc_Atrinik_CreatePathname[] =
1311 ".. function:: CreatePathname(path).\n\n"
1312 "Creates path to a file in the maps directory. For example, '/hall_of_dms' -> "
1313 "'../maps/hall_of_dms'.\n\n"
1314 ":param path: Path to the map.\n"
1315 ":type path: str\n"
1316 ":returns: Real path of the map on the system.\n"
1317 ":rtype: str";
1318 
1323 static PyObject *Atrinik_CreatePathname(PyObject *self, PyObject *args)
1324 {
1325  const char *path;
1326 
1327  if (!PyArg_ParseTuple(args, "s", &path)) {
1328  return NULL;
1329  }
1330 
1331  return Py_BuildValue("s", hooks->create_pathname(path));
1332 }
1333 
1335 static const char doc_Atrinik_GetTime[] =
1336 ".. function:: GetTime().\n\n"
1337 "Get the game time.\n\n"
1338 ":returns: A dictionary containing all the information about the in-game "
1339 "time:\n\n"
1340 " * **year**: Current year.\n"
1341 " * **month**: Current month.\n"
1342 " * **month_name**: Name of the current month.\n"
1343 " * **day**: Day.\n"
1344 " * **hour**: Hour.\n"
1345 " * **minute**: Minute.\n"
1346 " * **dayofweek**: Day of the week.\n"
1347 " * **dayofweek_name**: Name of the week day.\n"
1348 " * **season**: Season.\n"
1349 " * **season_name**: Name of the season.\n"
1350 " * **periodofday**: Period of the day.\n"
1351 " * **periodofday_name**: Name of the period of the day.\n"
1352 ":rtype: dict";
1353 
1358 static PyObject *Atrinik_GetTime(PyObject *self)
1359 {
1360  timeofday_t tod;
1361  hooks->get_tod(&tod);
1362 
1363  PyObject *dict = PyDict_New();
1364  PyDict_SetItemString(dict, "year",
1365  Py_BuildValue("i", tod.year + 1));
1366  PyDict_SetItemString(dict, "month",
1367  Py_BuildValue("i", tod.month + 1));
1368  PyDict_SetItemString(dict, "month_name",
1369  Py_BuildValue("s", hooks->month_name[tod.month]));
1370  PyDict_SetItemString(dict, "day",
1371  Py_BuildValue("i", tod.day + 1));
1372  PyDict_SetItemString(dict, "hour",
1373  Py_BuildValue("i", tod.hour));
1374  PyDict_SetItemString(dict, "minute",
1375  Py_BuildValue("i", tod.minute));
1376  PyDict_SetItemString(dict, "dayofweek",
1377  Py_BuildValue("i", tod.dayofweek + 1));
1378  PyDict_SetItemString(dict, "dayofweek_name",
1379  Py_BuildValue("s", hooks->weekdays[tod.dayofweek]));
1380  PyDict_SetItemString(dict, "season",
1381  Py_BuildValue("i", tod.season + 1));
1382  PyDict_SetItemString(dict, "season_name",
1383  Py_BuildValue("s", hooks->season_name[tod.season]));
1384  PyDict_SetItemString(dict, "periodofday",
1385  Py_BuildValue("i", tod.periodofday + 1));
1386  PyDict_SetItemString(dict, "periodofday_name",
1387  Py_BuildValue("s", hooks->periodsofday[tod.periodofday]));
1388 
1389  return dict;
1390 }
1391 
1393 static const char doc_Atrinik_FindParty[] =
1394 ".. function:: FindParty(name).\n\n"
1395 "Find a party by name.\n\n"
1396 ":param name: The party name to find.\n"
1397 ":type name: str\n"
1398 ":returns: The party if found, None otherwise.\n"
1399 ":rtype: :class:`Atrinik.Party.Party` or None";
1400 
1405 static PyObject *Atrinik_FindParty(PyObject *self, PyObject *args)
1406 {
1407  const char *name;
1408 
1409  if (!PyArg_ParseTuple(args, "s", &name)) {
1410  return NULL;
1411  }
1412 
1413  return wrap_party(hooks->find_party(name));
1414 }
1415 
1417 static const char doc_Atrinik_Logger[] =
1418 ".. function:: Logger(level, message).\n\n"
1419 "Logs a message.\n\n"
1420 ":param level: Level of the log message, eg, \"BUG\", \"ERROR\", \"CHAT\", "
1421 "\"INFO\", etc.\n"
1422 ":type level: str\n"
1423 ":param message: The message to log. Cannot contain newlines.\n"
1424 ":type message: str";
1425 
1430 static PyObject *Atrinik_Logger(PyObject *self, PyObject *args)
1431 {
1432  const char *mode, *string;
1433 
1434  if (!PyArg_ParseTuple(args, "ss", &mode, &string)) {
1435  return NULL;
1436  }
1437 
1438  logger_print(hooks->logger_get_level(mode), __FUNCTION__, __LINE__,
1439  string);
1440 
1441  Py_INCREF(Py_None);
1442  return Py_None;
1443 }
1444 
1447 ".. function:: GetRangeVectorFromMapCoords(map1, x1, y1, map2, x2, y2, "
1448 "flags=0).\n\n"
1449 "Get the distance and direction from one map coordinate to another.\n\n"
1450 ":param map1: From which map to get the distance from.\n"
1451 ":type map1: :class:`Atrinik.Map.Map`\n"
1452 ":param x1: X coordinate on *map1*.\n"
1453 ":type x1: int\n"
1454 ":param y1: Y coordinate on *map1*.\n"
1455 ":type y1: int\n"
1456 ":param map2: From which map to get the distance to.\n"
1457 ":type map2: :class:`Atrinik.Map.Map`\n"
1458 ":param x2: X coordinate on *map2*.\n"
1459 ":type x2: int\n"
1460 ":param y2: Y coordinate on *map2*.\n"
1461 ":type y2: int\n"
1462 ":param flags: One or a combination of RV_xxx, eg, :attr:"
1463 "`~Atrinik.RV_MANHATTAN_DISTANCE`\n"
1464 ":type flags: int\n"
1465 ":returns: None if the distance couldn't be calculated, otherwise a "
1466 "tuple containing:\n\n"
1467 " * Direction from the first coordinate to the second, eg, :attr:\n"
1468 " `~Atrinik.NORTH`\n"
1469 " * Distance between the two coordinates.\n"
1470 " * X distance.\n"
1471 " * Y distance.\n"
1472 ":rtype: tuple or None";
1473 
1478 static PyObject *Atrinik_GetRangeVectorFromMapCoords(PyObject *self,
1479  PyObject *args)
1480 {
1481  Atrinik_Map *map, *map2;
1482  int x, y, x2, y2, flags = 0;
1483 
1484  if (!PyArg_ParseTuple(args, "O!iiO!ii|i", &Atrinik_MapType, &map, &x, &y,
1485  &Atrinik_MapType, &map2, &x2, &y2, &flags)) {
1486  return NULL;
1487  }
1488 
1489  rv_vector rv;
1490  if (!hooks->get_rangevector_from_mapcoords(map->map, x, y,
1491  map2->map, x2, y2, &rv, flags)) {
1492  Py_INCREF(Py_None);
1493  return Py_None;
1494  }
1495 
1496  PyObject *tuple = PyTuple_New(4);
1497  PyTuple_SET_ITEM(tuple, 0, Py_BuildValue("i", rv.direction));
1498  PyTuple_SET_ITEM(tuple, 1, Py_BuildValue("i", rv.distance));
1499  PyTuple_SET_ITEM(tuple, 2, Py_BuildValue("i", rv.distance_x));
1500  PyTuple_SET_ITEM(tuple, 3, Py_BuildValue("i", rv.distance_y));
1501 
1502  return tuple;
1503 }
1504 
1506 static const char doc_Atrinik_CostString[] =
1507 ".. function:: CostString(value).\n\n"
1508 "Build a string representation of the value in the game's money syntax, for "
1509 "example, a value of 134 would become \"1 silver coin and 34 copper "
1510 "coins\".\n\n"
1511 ":param value: Value to build the string from.\n"
1512 ":type value: int\n"
1513 ":returns: The string.\n"
1514 ":rtype: str";
1515 
1520 static PyObject *Atrinik_CostString(PyObject *self, PyObject *args)
1521 {
1522  int64_t value;
1523 
1524  if (!PyArg_ParseTuple(args, "L", &value)) {
1525  return NULL;
1526  }
1527 
1528  return Py_BuildValue("s", hooks->shop_get_cost_string(value));
1529 }
1530 
1532 static const char doc_Atrinik_CacheAdd[] =
1533 ".. function:: CacheAdd(key, what).\n\n"
1534 "Store 'what' in memory identified by unique identifier 'key'.\n\n"
1535 "The object will be stored forever in memory, until it's either removed by "
1536 ":func:`~Atrinik.CacheRemove` or the server is shut down; in both cases, the "
1537 "object will be closed, if applicable (databases, file objects, etc)\n\n."
1538 "A stored object can be retrieved at any time using :func:"
1539 "`~Atrinik.CacheGet`.\n\n"
1540 ":param key: The unique identifier for the cache entry.\n"
1541 ":type key: str\n"
1542 ":param what: Any Python object (string, integer, database, etc) to store in "
1543 "memory.\n"
1544 ":type what: object\n"
1545 ":returns: True if the object was cached successfully, False otherwise (cache "
1546 "entry with same key name already exists).\n"
1547 ":rtype: bool";
1548 
1553 static PyObject *Atrinik_CacheAdd(PyObject *self, PyObject *args)
1554 {
1555  const char *key;
1556  PyObject *what;
1557 
1558  if (!PyArg_ParseTuple(args, "sO", &key, &what)) {
1559  return NULL;
1560  }
1561 
1562  /* Add it to the cache. */
1563  int ret = hooks->cache_add(key, what, CACHE_FLAG_PYOBJ | CACHE_FLAG_GEVENT);
1564  if (ret) {
1565  Py_INCREF(what);
1566  }
1567 
1568  return Py_BuildBoolean(ret);
1569 }
1570 
1572 static const char doc_Atrinik_CacheGet[] =
1573 ".. function:: CacheGet(key).\n\n"
1574 "Attempt to find a cache entry identified by 'key' that was previously added "
1575 "using :func:`~Atrinik.CacheAdd`.\n\n"
1576 ":param key: Unique identifier of the cache entry to find.\n"
1577 ":type key: str\n"
1578 ":returns: The cache entry.\n"
1579 ":rtype: object\n"
1580 ":raises ValueError: If the cache entry could not be found.";
1581 
1586 static PyObject *Atrinik_CacheGet(PyObject *self, PyObject *args)
1587 {
1588  const char *key;
1589 
1590  if (!PyArg_ParseTuple(args, "s", &key)) {
1591  return NULL;
1592  }
1593 
1594  shstr *sh_key = hooks->find_string(key);
1595  if (sh_key == NULL) {
1596  goto not_found;
1597  }
1598 
1599  cache_struct *result = hooks->cache_find(sh_key);
1600  if (result == NULL) {
1601  goto not_found;
1602  }
1603 
1604  /* Even if the cache entry was found, pretend it doesn't exist if
1605  * CACHE_FLAG_PYOBJ is not set. */
1606  if (!(result->flags & CACHE_FLAG_PYOBJ)) {
1607  goto not_found;
1608  }
1609 
1610  Py_INCREF((PyObject *) result->ptr);
1611  return result->ptr;
1612 
1613 not_found:
1614  PyErr_SetString(PyExc_ValueError, "No such cache entry.");
1615  return NULL;
1616 }
1617 
1619 static const char doc_Atrinik_CacheRemove[] =
1620 ".. function:: CacheRemove(key).\n\n"
1621 "Remove a cache entry that was added with a previous call to :func:"
1622 "`~Atrinik.CacheAdd`.\n\n"
1623 ":param key: Unique identifier of the cache entry to remove.\n"
1624 ":type key: str\n"
1625 ":returns: True is always returned.\n"
1626 ":rtype: bool\n"
1627 ":raises ValueError: If the cache entry could not be removed (it didn't exist)";
1628 
1633 static PyObject *Atrinik_CacheRemove(PyObject *self, PyObject *args)
1634 {
1635  const char *key;
1636 
1637  if (!PyArg_ParseTuple(args, "s", &key)) {
1638  return NULL;
1639  }
1640 
1641  shstr *sh_key = hooks->find_string(key);
1642  if (sh_key == NULL) {
1643  goto not_found;
1644  }
1645 
1646  if (!hooks->cache_remove(sh_key)) {
1647  goto not_found;
1648  }
1649 
1650  Py_INCREF(Py_True);
1651  return Py_True;
1652 
1653 not_found:
1654  PyErr_SetString(PyExc_ValueError, "No such cache entry.");
1655  return NULL;
1656 }
1657 
1659 static const char doc_Atrinik_GetFirst[] =
1660 ".. function:: GetFirst(what).\n\n"
1661 "Get first member of various linked lists.\n\n"
1662 ":param what: What list to get first member of. Available list names:\n\n"
1663 " * player: First player.\n"
1664 " * map: First map.\n"
1665 " * archetype: First archetype.\n"
1666 " * party: First party.\n"
1667 " * region: First region.\n"
1668 ":type what: str\n"
1669 ":returns: First member of the specified linked list.\n"
1670 ":rtype: :class:`Atrinik.Player.Player` or :class:`Atrinik.Map.Map` or "
1671 ":class:`Atrinik.Party.Party` or :class:`Atrinik.Region.Region`\n"
1672 ":raises ValueError: If *what* is invalid.";
1673 
1678 static PyObject *Atrinik_GetFirst(PyObject *self, PyObject *args)
1679 {
1680  const char *what;
1681 
1682  if (!PyArg_ParseTuple(args, "s", &what)) {
1683  return NULL;
1684  }
1685 
1686  if (strcmp(what, "player") == 0) {
1687  return wrap_player(*hooks->first_player);
1688  } else if (strcmp(what, "map") == 0) {
1689  return wrap_map(*hooks->first_map);
1690  } else if (strcmp(what, "party") == 0) {
1691  return wrap_party(*hooks->first_party);
1692  } else if (strcmp(what, "region") == 0) {
1693  return wrap_region(*hooks->first_region);
1694  }
1695 
1696  PyErr_Format(PyExc_ValueError, "'%s' is not a valid linked list.", what);
1697  return NULL;
1698 }
1699 
1701 static const char doc_Atrinik_CreateMap[] =
1702 ".. function:: CreateMap(width, height, path).\n\n"
1703 "Creates an empty map.\n\n"
1704 ":param width: The new map's width.\n"
1705 ":type width: int\n"
1706 ":param height: The new map's height.\n"
1707 ":type height: int\n"
1708 ":param path: Path to the new map. This should be a unique path to avoid "
1709 "collisions. \"/python-maps/\" is prepended to this to ensure no collision "
1710 "with regular maps.\n"
1711 ":type path: str\n"
1712 ":returns: The new empty map.\n"
1713 ":rtype: :class:`Atrinik.Map.Map`";
1714 
1719 static PyObject *Atrinik_CreateMap(PyObject *self, PyObject *args)
1720 {
1721  int width, height;
1722  const char *path;
1723 
1724  if (!PyArg_ParseTuple(args, "iis", &width, &height, &path)) {
1725  return NULL;
1726  }
1727 
1728  mapstruct *m = hooks->get_empty_map(width, height);
1729  char buf[HUGE_BUF];
1730  snprintf(VS(buf), "/python-maps/%s", path);
1731  m->path = hooks->add_string(buf);
1732 
1733  return wrap_map(m);
1734 }
1735 
1737 static const char doc_Atrinik_CreateObject[] =
1738 ".. function:: CreateObject(archname).\n\n"
1739 "Creates a new object. Note that if the created object is not put on map or "
1740 "inside an inventory of another object, it will be considered a leaked object. "
1741 "Use :meth:`Atrinik.Object.Object.Destroy` to free it if you no longer need "
1742 "it.\n\n"
1743 ":param archname: Name of the arch to create.\n"
1744 ":type archname: str\n"
1745 ":returns: The newly created object.\n"
1746 ":rtype: :class:`Atrinik.Object.Object`\n"
1747 ":raises Atrinik.AtrinikError: If *archname* is not a valid archetype.";
1748 
1753 static PyObject *Atrinik_CreateObject(PyObject *self, PyObject *args)
1754 {
1755  const char *archname;
1756 
1757  if (!PyArg_ParseTuple(args, "s", &archname)) {
1758  return NULL;
1759  }
1760 
1761  archetype_t *at = hooks->arch_find(archname);
1762  if (at == NULL) {
1763  PyErr_Format(AtrinikError, "The archetype '%s' doesn't exist.",
1764  archname);
1765  return NULL;
1766  }
1767 
1768  return wrap_object(hooks->arch_to_object(at));
1769 }
1770 
1772 static const char doc_Atrinik_GetTicks[] =
1773 ".. function:: GetTicks().\n\n"
1774 "Acquires the current server ticks value.\n\n"
1775 ":returns: The server ticks.\n"
1776 ":rtype: int";
1777 
1782 static PyObject *Atrinik_GetTicks(PyObject *self)
1783 {
1784  return Py_BuildValue("l", *hooks->pticks);
1785 }
1786 
1788 static const char doc_Atrinik_GetArchetype[] =
1789 ".. function:: GetArchetype(archname).\n\n"
1790 "Finds an archetype.\n\n"
1791 ":param archname: Name of the archetype to find.\n"
1792 ":type archname: str\n"
1793 ":returns: The archetype.\n"
1794 ":rtype: :class:`Atrinik.Archetype.Archetype`\n"
1795 ":raises Atrinik.AtrinikError: If *archname* is not a valid archetype.";
1796 
1801 static PyObject *Atrinik_GetArchetype(PyObject *self, PyObject *args)
1802 {
1803  const char *archname;
1804 
1805  if (!PyArg_ParseTuple(args, "s", &archname)) {
1806  return NULL;
1807  }
1808 
1809  archetype_t *at = hooks->arch_find(archname);
1810  if (at == NULL) {
1811  PyErr_Format(AtrinikError, "The archetype '%s' doesn't exist.",
1812  archname);
1813  return NULL;
1814  }
1815 
1816  return wrap_archetype(at);
1817 }
1818 
1820 static const char doc_Atrinik_print[] =
1821 ".. function:: print(...).\n\n"
1822 "Prints the string representations of the given objects to the server log, as "
1823 "well as all online DMs. Essentially a replacement for standard library "
1824 "print() function.\n\n";
1825 
1830 static PyObject *Atrinik_print(PyObject *self, PyObject *args)
1831 {
1832  StringBuffer *sb = hooks->stringbuffer_new();
1833 
1834  for (Py_ssize_t i = 0; i < PyTuple_Size(args); i++) {
1835  if (i > 0) {
1836  hooks->stringbuffer_append_string(sb, " ");
1837  }
1838 
1839  hooks->stringbuffer_append_string(sb,
1840  PyString_AsString(PyObject_Str(PyTuple_GetItem(args, i))));
1841  }
1842 
1843  char *cp = hooks->stringbuffer_finish(sb);
1844 
1845  PyObject *locals = PyDict_New();
1846  PyDict_SetItemString(locals, "print_msg", Py_BuildValue("s", cp));
1847  efree(cp);
1848 
1849  py_runfile_simple("/python/events/python_print.py", locals);
1850  Py_DECREF(locals);
1851 
1852  Py_INCREF(Py_None);
1853  return Py_None;
1854 }
1855 
1857 static const char doc_Atrinik_Eval[] =
1858 ".. function:: Eval(code, seconds=0.0).\n\n"
1859 "Executes the specified code from the main thread after the specified delay in "
1860 "seconds.\n\n"
1861 ":param code: The code to compile and execute.\n"
1862 ":type code: str\n"
1863 ":param seconds: How long to wait, eg, 0.5 for half a second, 10.0 for 10 "
1864 "seconds, etc.\n"
1865 ":type seconds: float";
1866 
1871 static PyObject *Atrinik_Eval(PyObject *self, PyObject *args)
1872 {
1873  double seconds = 0.0f;
1874  const char *s;
1875  struct _node *n;
1876  PyCodeObject *code = NULL;
1877 
1878  if (!PyArg_ParseTuple(args, "s|d", &s, &seconds)) {
1879  return NULL;
1880  }
1881 
1882  n = PyParser_SimpleParseString(s, Py_file_input);
1883 
1884  if (n != NULL) {
1885  code = PyNode_Compile(n, "eval'd code");
1886  PyNode_Free(n);
1887  }
1888 
1889  if (PyErr_Occurred()) {
1890  PyErr_LOG();
1891  return NULL;
1892  }
1893 
1894  if (code != NULL) {
1895  python_eval_struct *tmp;
1896  PyGILState_STATE gilstate;
1897  struct timeval tv;
1898 
1899  gettimeofday(&tv, NULL);
1900 
1901  tmp = malloc(sizeof(*tmp));
1902  tmp->globals = PyEval_GetGlobals();
1903  Py_INCREF(tmp->globals);
1904  tmp->locals = PyEval_GetLocals();
1905  Py_INCREF(tmp->locals);
1906  tmp->code = code;
1907  tmp->seconds = tv.tv_sec + tv.tv_usec / 1000000. + seconds;
1908  DL_APPEND(python_eval, tmp);
1909 
1910  gilstate = PyGILState_Ensure();
1911  DL_APPEND(python_eval, tmp);
1912  PyGILState_Release(gilstate);
1913  }
1914 
1915  Py_INCREF(Py_None);
1916  return Py_None;
1917 }
1918 
1920 static const char doc_Atrinik_GetSettings[] =
1921 ".. function:: GetSettings().\n\n"
1922 "Acquire a dictionary containing the server's settings.\n\n"
1923 ":returns: Dictionary with the server's settings, such as the maps path.\n"
1924 ":rtype: dict";
1925 
1930 static PyObject *Atrinik_GetSettings(PyObject *self)
1931 {
1932  PyObject *dict = PyDict_New();
1933  PyDict_SetItemString(dict, "port", Py_BuildValue("H",
1934  hooks->settings->port));
1935  PyDict_SetItemString(dict, "libpath", Py_BuildValue("s",
1936  hooks->settings->libpath));
1937  PyDict_SetItemString(dict, "datapath", Py_BuildValue("s",
1938  hooks->settings->datapath));
1939  PyDict_SetItemString(dict, "mapspath", Py_BuildValue("s",
1940  hooks->settings->mapspath));
1941  PyDict_SetItemString(dict, "httppath", Py_BuildValue("s",
1942  hooks->settings->httppath));
1943  PyDict_SetItemString(dict, "metaserver_url", Py_BuildValue("s",
1944  hooks->settings->metaserver_url));
1945  PyDict_SetItemString(dict, "server_host", Py_BuildValue("s",
1946  hooks->settings->server_host));
1947  PyDict_SetItemString(dict, "server_name", Py_BuildValue("s",
1948  hooks->settings->server_name));
1949  PyDict_SetItemString(dict, "server_desc", Py_BuildValue("s",
1950  hooks->settings->server_desc));
1951  PyDict_SetItemString(dict, "world_maker", Py_BuildBoolean(
1952  hooks->settings->world_maker));
1953  PyDict_SetItemString(dict, "unit_tests", Py_BuildBoolean(
1954  hooks->settings->unit_tests));
1955  PyDict_SetItemString(dict, "plugin_unit_tests", Py_BuildBoolean(
1956  hooks->settings->plugin_unit_tests));
1957  PyDict_SetItemString(dict, "plugin_unit_test", Py_BuildValue("s",
1958  hooks->settings->plugin_unit_test));
1959  PyDict_SetItemString(dict, "magic_devices_level", Py_BuildValue("b",
1960  hooks->settings->magic_devices_level));
1961  PyDict_SetItemString(dict, "magic_devices_level", Py_BuildValue("b",
1962  hooks->settings->magic_devices_level));
1963  PyDict_SetItemString(dict, "item_power_factor", Py_BuildValue("d",
1964  hooks->settings->item_power_factor));
1965  PyDict_SetItemString(dict, "python_reload_modules", Py_BuildBoolean(
1966  hooks->settings->python_reload_modules));
1967  PyDict_SetItemString(dict, "default_permission_groups", Py_BuildValue("s",
1968  hooks->settings->default_permission_groups));
1969 
1970  PyObject *list_allowed_chars = PyList_New(ALLOWED_CHARS_NUM);
1971  PyDict_SetItemString(dict, "allowed_chars", list_allowed_chars);
1972  PyObject *list_limits = PyList_New(ALLOWED_CHARS_NUM);
1973  PyDict_SetItemString(dict, "limits", list_limits);
1974 
1975  for (Py_ssize_t i = 0; i < ALLOWED_CHARS_NUM; i++) {
1976  PyList_SetItem(list_allowed_chars, i, Py_BuildValue("s",
1977  hooks->settings->allowed_chars[i]));
1978  PyList_SetItem(list_limits, i, Py_BuildValue("KK",
1979  (unsigned PY_LONG_LONG) hooks->settings->limits[i][0],
1980  (unsigned PY_LONG_LONG) hooks->settings->limits[i][1]));
1981  }
1982 
1983  PyDict_SetItemString(dict, "control_allowed_ips", Py_BuildValue("s",
1984  hooks->settings->control_allowed_ips));
1985  PyDict_SetItemString(dict, "control_player", Py_BuildValue("s",
1986  hooks->settings->control_player));
1987  PyDict_SetItemString(dict, "recycle_tmp_maps", Py_BuildBoolean(
1988  hooks->settings->recycle_tmp_maps));
1989  PyDict_SetItemString(dict, "http_url", Py_BuildValue("s",
1990  hooks->settings->http_url));
1991  return dict;
1992 }
1993 
1995 static const char doc_Atrinik_Process[] =
1996 ".. function:: Process().\n\n"
1997 "Simulates server processing.\n\n"
1998 ":raises Atrinik.AtrinikError: If called outside the plugin unit tests.";
1999 
2004 static PyObject *Atrinik_Process(PyObject *self)
2005 {
2006  if (!hooks->settings->plugin_unit_tests) {
2007  PyErr_SetString(AtrinikError, "Method cannot be used outside of unit "
2008  "tests.");
2009  return NULL;
2010  }
2011 
2012  hooks->main_process();
2013 
2014  Py_INCREF(Py_None);
2015  return Py_None;
2016 }
2017 
2022 static PyMethodDef AtrinikMethods[] = {
2023  {"LoadObject", (PyCFunction) Atrinik_LoadObject, METH_VARARGS,
2024  doc_Atrinik_LoadObject},
2025  {"ReadyMap", (PyCFunction) Atrinik_ReadyMap, METH_VARARGS,
2026  doc_Atrinik_ReadyMap},
2027  {"FindPlayer", (PyCFunction) Atrinik_FindPlayer, METH_VARARGS,
2028  doc_Atrinik_FindPlayer},
2029  {"PlayerExists", (PyCFunction) Atrinik_PlayerExists, METH_VARARGS,
2030  doc_Atrinik_PlayerExists},
2031  {"WhoAmI", (PyCFunction) Atrinik_WhoAmI, METH_NOARGS,
2032  doc_Atrinik_WhoAmI},
2033  {"WhoIsActivator", (PyCFunction) Atrinik_WhoIsActivator, METH_NOARGS,
2034  doc_Atrinik_WhoIsActivator},
2035  {"WhoIsOther", (PyCFunction) Atrinik_WhoIsOther, METH_NOARGS,
2036  doc_Atrinik_WhoIsOther},
2037  {"WhatIsEvent", (PyCFunction) Atrinik_WhatIsEvent, METH_NOARGS,
2038  doc_Atrinik_WhatIsEvent},
2039  {"GetEventNumber", (PyCFunction) Atrinik_GetEventNumber, METH_NOARGS,
2040  doc_Atrinik_GetEventNumber},
2041  {"WhatIsMessage", (PyCFunction) Atrinik_WhatIsMessage, METH_NOARGS,
2042  doc_Atrinik_WhatIsMessage},
2043  {"GetOptions", (PyCFunction) Atrinik_GetOptions, METH_NOARGS,
2044  doc_Atrinik_GetOptions},
2045  {"GetReturnValue", (PyCFunction) Atrinik_GetReturnValue, METH_NOARGS,
2046  doc_Atrinik_GetReturnValue},
2047  {"SetReturnValue", (PyCFunction) Atrinik_SetReturnValue, METH_VARARGS,
2048  doc_Atrinik_SetReturnValue},
2049  {"GetEventParameters", (PyCFunction) Atrinik_GetEventParameters,
2050  METH_NOARGS, doc_Atrinik_GetEventParameters},
2051  {"RegisterCommand", (PyCFunction) Atrinik_RegisterCommand, METH_VARARGS,
2052  doc_Atrinik_RegisterCommand},
2053  {"CreatePathname", (PyCFunction) Atrinik_CreatePathname, METH_VARARGS,
2054  doc_Atrinik_CreatePathname},
2055  {"GetTime", (PyCFunction) Atrinik_GetTime, METH_NOARGS,
2056  doc_Atrinik_GetTime},
2057  {"FindParty", (PyCFunction) Atrinik_FindParty, METH_VARARGS,
2058  doc_Atrinik_FindParty},
2059  {"Logger", (PyCFunction) Atrinik_Logger, METH_VARARGS,
2060  doc_Atrinik_Logger},
2061  {"GetRangeVectorFromMapCoords",
2062  (PyCFunction) Atrinik_GetRangeVectorFromMapCoords, METH_VARARGS,
2063  doc_Atrinik_GetRangeVectorFromMapCoords},
2064  {"CostString", (PyCFunction) Atrinik_CostString, METH_VARARGS,
2065  doc_Atrinik_CostString},
2066  {"CacheAdd", (PyCFunction) Atrinik_CacheAdd, METH_VARARGS,
2067  doc_Atrinik_CacheAdd},
2068  {"CacheGet", (PyCFunction) Atrinik_CacheGet, METH_VARARGS,
2069  doc_Atrinik_CacheGet},
2070  {"CacheRemove", (PyCFunction) Atrinik_CacheRemove, METH_VARARGS,
2071  doc_Atrinik_CacheRemove},
2072  {"GetFirst", (PyCFunction) Atrinik_GetFirst, METH_VARARGS,
2073  doc_Atrinik_GetFirst},
2074  {"CreateMap", (PyCFunction) Atrinik_CreateMap, METH_VARARGS,
2075  doc_Atrinik_CreateMap},
2076  {"CreateObject", (PyCFunction) Atrinik_CreateObject, METH_VARARGS,
2077  doc_Atrinik_CreateObject},
2078  {"GetTicks", (PyCFunction) Atrinik_GetTicks, METH_NOARGS,
2079  doc_Atrinik_GetTicks},
2080  {"GetArchetype", (PyCFunction) Atrinik_GetArchetype, METH_VARARGS,
2081  doc_Atrinik_GetArchetype},
2082  {"print", (PyCFunction) Atrinik_print, METH_VARARGS,
2083  doc_Atrinik_print},
2084  {"Eval", (PyCFunction) Atrinik_Eval, METH_VARARGS,
2085  doc_Atrinik_Eval},
2086  {"GetSettings", (PyCFunction) Atrinik_GetSettings, METH_NOARGS,
2087  doc_Atrinik_GetSettings},
2088  {"Process", (PyCFunction) Atrinik_Process, METH_NOARGS,
2089  doc_Atrinik_Process},
2090  {NULL, NULL, 0, 0}
2091 };
2092 
2100 static int handle_event(va_list args)
2101 {
2102  char *script;
2103  PythonContext *context = malloc(sizeof(PythonContext));
2104  int rv;
2105 
2106  context->activator = va_arg(args, object *);
2107  context->who = va_arg(args, object *);
2108  context->other = va_arg(args, object *);
2109  context->event = va_arg(args, object *);
2110  context->text = va_arg(args, char *);
2111  context->parms[0] = va_arg(args, int);
2112  context->parms[1] = va_arg(args, int);
2113  context->parms[2] = va_arg(args, int);
2114  context->parms[3] = va_arg(args, int);
2115  script = va_arg(args, char *);
2116  context->options = va_arg(args, char *);
2117  context->returnvalue = 0;
2118 
2119  if (!do_script(context, script)) {
2120  freeContext(context);
2121  return 0;
2122  }
2123 
2124  context = popContext();
2125 
2126  rv = context->returnvalue;
2127  freeContext(context);
2128 
2129  return rv;
2130 }
2131 
2139 static int handle_map_event(va_list args)
2140 {
2141  PythonContext *context = calloc(1, sizeof(PythonContext));
2142  char *script;
2143  int rv;
2144 
2145  context->activator = va_arg(args, object *);
2146  context->event = va_arg(args, object *);
2147  context->other = va_arg(args, object *);
2148  context->who = va_arg(args, object *);
2149  script = va_arg(args, char *);
2150  context->options = va_arg(args, char *);
2151  context->text = va_arg(args, char *);
2152  context->parms[0] = va_arg(args, int);
2153 
2154  if (!do_script(context, script)) {
2155  freeContext(context);
2156  return 0;
2157  }
2158 
2159  context = popContext();
2160  rv = context->returnvalue;
2161  freeContext(context);
2162 
2163  return rv;
2164 }
2165 
2175 static int handle_global_event(int event_type, va_list args)
2176 {
2177  PythonContext *context;
2178 
2179  switch (event_type) {
2180  case GEVENT_CACHE_REMOVED:
2181  {
2182  void *ptr = va_arg(args, void *);
2183  uint32_t flags = *(uint32_t *) va_arg(args, void *);
2184 
2185  if (flags & CACHE_FLAG_PYOBJ) {
2186  PyObject *retval;
2187  PyGILState_STATE gilstate;
2188 
2189  gilstate = PyGILState_Ensure();
2190 
2191  /* Attempt to close file/database/etc objects. */
2192  retval = PyObject_CallMethod(ptr, "close", "");
2193 
2194  /* No close() method, ignore the exception. */
2195  if (PyErr_Occurred() &&
2196  PyErr_ExceptionMatches(PyExc_AttributeError)) {
2197  PyErr_Clear();
2198  }
2199 
2200  Py_XDECREF(retval);
2201 
2202  /* Decrease the reference count. */
2203  Py_DECREF((PyObject *) ptr);
2204 
2205  PyGILState_Release(gilstate);
2206  }
2207 
2208  return 0;
2209  }
2210 
2211  case GEVENT_TICK:
2212  {
2213  python_eval_struct *eval, *tmp;
2214  PyGILState_STATE gilstate;
2215  PyObject *ret;
2216  double seconds;
2217 
2218  gilstate = PyGILState_Ensure();
2219 
2220  if (python_eval != NULL) {
2221  struct timeval tv;
2222 
2223  gettimeofday(&tv, NULL);
2224  seconds = tv.tv_sec + tv.tv_usec / 1000000.;
2225  }
2226 
2227  DL_FOREACH_SAFE(python_eval, eval, tmp)
2228  {
2229  if (seconds < eval->seconds) {
2230  continue;
2231  }
2232 
2233  DL_DELETE(python_eval, eval);
2234 
2235 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 2
2236  ret = PyEval_EvalCode((PyObject *) eval->code, eval->globals,
2237  eval->locals);
2238 #else
2239  ret = PyEval_EvalCode(eval->code, eval->globals, eval->locals);
2240 #endif
2241 
2242  if (PyErr_Occurred()) {
2243  PyErr_LOG();
2244  }
2245 
2246  Py_XDECREF(ret);
2247  Py_DECREF(eval->globals);
2248  Py_DECREF(eval->locals);
2249  Py_DECREF(eval->code);
2250 
2251  free(eval);
2252  }
2253 
2254  PyGILState_Release(gilstate);
2255 
2256  return 0;
2257  }
2258  }
2259 
2260  context = malloc(sizeof(PythonContext));
2261  context->activator = NULL;
2262  context->who = NULL;
2263  context->other = NULL;
2264  context->event = NULL;
2265  context->parms[0] = 0;
2266  context->parms[1] = 0;
2267  context->parms[2] = 0;
2268  context->parms[3] = 0;
2269  context->text = NULL;
2270  context->options = NULL;
2271  context->returnvalue = 0;
2272 
2273  switch (event_type) {
2274  case GEVENT_BORN:
2275  context->activator = va_arg(args, void *);
2276  break;
2277 
2278  case GEVENT_LOGIN:
2279  context->activator = ((player *) va_arg(args, void *))->ob;
2280  context->text = va_arg(args, void *);
2281  break;
2282 
2283  case GEVENT_LOGOUT:
2284  context->activator = ((player *) va_arg(args, void *))->ob;
2285  context->text = va_arg(args, void *);
2286  break;
2287 
2288  case GEVENT_PLAYER_DEATH:
2289  break;
2290  }
2291 
2292  if (!do_script(context, "/python/events/python_event.py")) {
2293  freeContext(context);
2294  return 0;
2295  }
2296 
2297  context = popContext();
2298  freeContext(context);
2299 
2300  return 0;
2301 }
2302 
2310 static int handle_unit_event(va_list args)
2311 {
2312  PythonContext *context = malloc(sizeof(*context));
2313  if (context == NULL) {
2314  return 0;
2315  }
2316 
2317  context->activator = va_arg(args, object *);
2318  context->who = va_arg(args, object *);
2319  context->other = NULL;
2320  context->event = NULL;
2321  context->parms[0] = 0;
2322  context->parms[1] = 0;
2323  context->parms[2] = 0;
2324  context->parms[3] = 0;
2325  context->text = "";
2326  context->options = NULL;
2327  context->returnvalue = 0;
2328 
2329  if (do_script(context, "/python/events/python_unit.py")) {
2330  context = popContext();
2331  }
2332 
2333  freeContext(context);
2334  return 0;
2335 }
2336 
2337 MODULEAPI void *triggerEvent(int *type, ...)
2338 {
2339  va_list args;
2340  int eventcode, event_type;
2341  static int result = 0;
2342 
2343  va_start(args, type);
2344  event_type = va_arg(args, int);
2345  eventcode = va_arg(args, int);
2346 
2347  switch (event_type) {
2348  case PLUGIN_EVENT_NORMAL:
2349  result = handle_event(args);
2350  break;
2351 
2352  case PLUGIN_EVENT_MAP:
2353  result = handle_map_event(args);
2354  break;
2355 
2356  case PLUGIN_EVENT_GLOBAL:
2357  result = handle_global_event(eventcode, args);
2358  break;
2359 
2360  case PLUGIN_EVENT_UNIT:
2361  result = handle_unit_event(args);
2362  break;
2363 
2364  default:
2365  LOG(BUG, "Python: Requested unknown event type %d.", event_type);
2366  break;
2367  }
2368 
2369  va_end(args);
2370  return &result;
2371 }
2372 
2373 MODULEAPI void getPluginProperty(int *type, ...)
2374 {
2375  va_list args;
2376  const char *propname;
2377  int size;
2378  char *buf;
2379 
2380  va_start(args, type);
2381  propname = va_arg(args, const char *);
2382 
2383  if (!strcmp(propname, "Identification")) {
2384  buf = va_arg(args, char *);
2385  size = va_arg(args, int);
2386  va_end(args);
2387  snprintf(buf, size, PLUGIN_NAME);
2388  } else if (!strcmp(propname, "FullName")) {
2389  buf = va_arg(args, char *);
2390  size = va_arg(args, int);
2391  va_end(args);
2392  snprintf(buf, size, PLUGIN_VERSION);
2393  }
2394 
2395  va_end(args);
2396 }
2397 
2398 MODULEAPI void postinitPlugin(void)
2399 {
2400  PyGILState_STATE gilstate;
2401 
2402  hooks->register_global_event(PLUGIN_NAME, GEVENT_CACHE_REMOVED);
2403  hooks->register_global_event(PLUGIN_NAME, GEVENT_TICK);
2404  initContextStack();
2405 
2406  gilstate = PyGILState_Ensure();
2407  py_runfile_simple("/python/events/python_init.py", NULL);
2408 
2409  if (PyErr_Occurred()) {
2410  PyErr_LOG();
2411  }
2412 
2413  PyGILState_Release(gilstate);
2414 }
2415 
2416 #ifdef IS_PY3K
2417 static PyModuleDef AtrinikModule = {
2418  PyModuleDef_HEAD_INIT,
2419  "Atrinik",
2420  NULL,
2421  -1,
2423  NULL, NULL, NULL, NULL
2424 };
2425 
2426 static PyObject *PyInit_Atrinik(void)
2427 {
2428  PyObject *m = PyModule_Create(&AtrinikModule);
2429  Py_INCREF(m);
2430  return m;
2431 }
2432 #endif
2433 
2443 static PyObject *module_create(PyObject *parent, const char *name)
2444 {
2445  char tmp[MAX_BUF];
2446  snprintf(VS(tmp), "Atrinik_%s", name);
2447  PyObject *module = PyModule_New(tmp);
2448  PyDict_SetItemString(PyModule_GetDict(parent), name, module);
2449  return module;
2450 }
2451 
2464 static void module_add_constants(PyObject *module, const char *name,
2465  const Atrinik_Constant *consts, const char *doc)
2466 {
2467  size_t i = 0;
2468  PyObject *module_tmp;
2469 
2470  /* Create the new module. */
2471  module_tmp = module_create(module, name);
2472  PyModule_AddStringConstant(module_tmp, "__doc__", doc);
2473 
2474  /* Append constants. */
2475  while (consts[i].name) {
2476  PyModule_AddIntConstant(module_tmp, consts[i].name, consts[i].value);
2477  i++;
2478  }
2479 }
2480 
2494 static void module_add_array(PyObject *module, const char *name, void *array,
2495  size_t array_size, field_type type)
2496 {
2497  size_t i;
2498  PyObject *list;
2499 
2500  /* Create a new list. */
2501  list = PyList_New(0);
2502 
2503  /* Add entries to the list. */
2504  for (i = 0; i < array_size; i++) {
2505  if (type == FIELDTYPE_INT32) {
2506  PyList_Append(list, Py_BuildValue("i", ((int32_t *) array)[i]));
2507  } else if (type == FIELDTYPE_CSTR) {
2508  PyList_Append(list, Py_BuildValue("s", ((char **) array)[i]));
2509  }
2510  }
2511 
2512  /* Add it to the module dictionary. */
2513  PyDict_SetItemString(PyModule_GetDict(module), name, list);
2514 }
2515 
2516 MODULEAPI void initPlugin(struct plugin_hooklist *hooklist)
2517 {
2518  PyObject *m, *d, *module_tmp;
2519  int i;
2520  PyThreadState *py_tstate = NULL;
2521 
2522  hooks = hooklist;
2523 
2524 #ifdef IS_PY26
2525  Py_Py3kWarningFlag++;
2526 #endif
2527 
2528 #ifdef IS_PY3K
2529  PyImport_AppendInittab("Atrinik", &PyInit_Atrinik);
2530 #endif
2531 
2532  Py_Initialize();
2533  PyEval_InitThreads();
2534 
2535 #ifdef IS_PY3K
2536  m = PyImport_ImportModule("Atrinik");
2537 #else
2538  m = Py_InitModule("Atrinik", AtrinikMethods);
2539 #endif
2540 
2541  PyModule_AddStringConstant(m, "__doc__", package_doc);
2542  d = PyModule_GetDict(m);
2543  AtrinikError = PyErr_NewException("Atrinik.error", NULL, NULL);
2544  PyDict_SetItemString(d, "AtrinikError", AtrinikError);
2545 
2546  module_tmp = module_create(m, "Object");
2547  if (!Atrinik_Object_init(module_tmp)) {
2548  return;
2549  }
2550 
2551  module_tmp = module_create(m, "Map");
2552  if (!Atrinik_Map_init(module_tmp)) {
2553  return;
2554  }
2555 
2556  module_tmp = module_create(m, "Party");
2557  if (!Atrinik_Party_init(module_tmp)) {
2558  return;
2559  }
2560 
2561  module_tmp = module_create(m, "Region");
2562  if (!Atrinik_Region_init(module_tmp)) {
2563  return;
2564  }
2565 
2566  module_tmp = module_create(m, "Player");
2567  if (!Atrinik_Player_init(module_tmp)) {
2568  return;
2569  }
2570 
2571  module_tmp = module_create(m, "Archetype");
2572  if (!Atrinik_Archetype_init(module_tmp)) {
2573  return;
2574  }
2575 
2576  module_tmp = module_create(m, "AttrList");
2577  if (!Atrinik_AttrList_init(module_tmp)) {
2578  return;
2579  }
2580 
2581  module_add_constants(m, "Type", constants_types, module_doc_type);
2582  module_add_array(m, "freearr_x", hooks->freearr_x, SIZEOFFREE,
2583  FIELDTYPE_INT32);
2584  module_add_array(m, "freearr_y", hooks->freearr_y, SIZEOFFREE,
2585  FIELDTYPE_INT32);
2586 
2587  /* Initialize integer constants */
2588  for (i = 0; constants[i].name; i++) {
2589  PyModule_AddIntConstant(m, constants[i].name, constants[i].value);
2590  }
2591 
2592  /* Initialize integer constants */
2593  for (i = 0; constants_colors[i][0]; i++) {
2594  PyModule_AddStringConstant(m, constants_colors[i][0],
2595  constants_colors[i][1]);
2596  }
2597 
2598  module_tmp = module_create(m, "Gender");
2599  PyModule_AddStringConstant(module_tmp, "__doc__", module_doc_gender);
2600  module_add_array(module_tmp, "gender_noun",
2601  hooks->gender_noun, GENDER_MAX, FIELDTYPE_CSTR);
2602  module_add_array(module_tmp, "gender_subjective",
2603  hooks->gender_subjective, GENDER_MAX, FIELDTYPE_CSTR);
2604  module_add_array(module_tmp, "gender_subjective_upper",
2605  hooks->gender_subjective_upper, GENDER_MAX, FIELDTYPE_CSTR);
2606  module_add_array(module_tmp, "gender_objective",
2607  hooks->gender_objective, GENDER_MAX, FIELDTYPE_CSTR);
2608  module_add_array(module_tmp, "gender_possessive",
2609  hooks->gender_possessive, GENDER_MAX, FIELDTYPE_CSTR);
2610  module_add_array(module_tmp, "gender_reflexive",
2611  hooks->gender_reflexive, GENDER_MAX, FIELDTYPE_CSTR);
2612 
2613  for (i = 0; constants_gender[i].name; i++) {
2614  PyModule_AddIntConstant(module_tmp, constants_gender[i].name,
2615  constants_gender[i].value);
2616  }
2617 
2618  /* Create the global scope dictionary. */
2619  py_globals_dict = PyDict_New();
2620  /* Add the builtings to the global scope. */
2621  PyDict_SetItemString(py_globals_dict, "__builtins__", PyEval_GetBuiltins());
2622  /* Add Atrinik module members to the global scope. */
2623  PyRun_String("from Atrinik import *", Py_file_input, py_globals_dict, NULL);
2624 
2625  py_tstate = PyGILState_GetThisThreadState();
2626  PyEval_ReleaseThread(py_tstate);
2627 }
2628 
2629 MODULEAPI void closePlugin(void)
2630 {
2631  hooks->cache_remove_by_flags(CACHE_FLAG_GEVENT);
2632  PyGILState_Ensure();
2633  Py_Finalize();
2634 }
2635 
2645 static int set_face_field(void *ptr, long face_id)
2646 {
2647  if (face_id < 0 || face_id >= *hooks->nrofpixmaps) {
2648  PyErr_Format(PyExc_ValueError, "Illegal value for face field: %ld",
2649  face_id);
2650  return -1;
2651  }
2652 
2653  *(New_Face **) ptr = &(*hooks->new_faces)[face_id];
2654  return 0;
2655 }
2656 
2666 static int set_animation_field(void *ptr, long anim_id)
2667 {
2668  if (anim_id < 0 || anim_id >= *hooks->num_animations) {
2669  PyErr_Format(PyExc_ValueError, "Illegal value for animation field: %ld",
2670  anim_id);
2671  return -1;
2672  }
2673 
2674  *(uint16_t *) ptr = (uint16_t) anim_id;
2675  return 0;
2676 }
2677 
2688 int generic_field_setter(fields_struct *field, void *ptr, PyObject *value)
2689 {
2690  void *field_ptr;
2691 
2692  if ((field->flags & FIELDFLAG_READONLY)) {
2693  INTRAISE("Trying to modify readonly field.");
2694  }
2695 
2696  field_ptr = (char *) ptr + field->offset;
2697 
2698  switch (field->type) {
2699  case FIELDTYPE_SHSTR:
2700  if (value == Py_None) {
2701  FREE_AND_CLEAR_HASH(*(shstr **) field_ptr);
2702  } else if (PyString_Check(value)) {
2703  FREE_AND_CLEAR_HASH(*(shstr **) field_ptr);
2704  FREE_AND_COPY_HASH(*(shstr **) field_ptr, PyString_AsString(value));
2705  } else {
2706  INTRAISE("Illegal value for shared string field.");
2707  }
2708 
2709  break;
2710 
2711  case FIELDTYPE_CSTR:
2712  if (value == Py_None || PyString_Check(value)) {
2713  if (*(char **) field_ptr != NULL) {
2714  efree(*(char **) field_ptr);
2715  }
2716 
2717  if (value == Py_None) {
2718  *(char **) field_ptr = NULL;
2719  } else {
2720  *(char **) field_ptr = estrdup(PyString_AsString(value));
2721  }
2722  } else {
2723  INTRAISE("Illegal value for C string field.");
2724  }
2725 
2726  break;
2727 
2728  case FIELDTYPE_CARY:
2729  if (value == Py_None) {
2730  ((char *) field_ptr)[0] = '\0';
2731  } else if (PyString_Check(value)) {
2732  memcpy(field_ptr, PyString_AsString(value), field->extra_data);
2733  ((char *) field_ptr)[field->extra_data] = '\0';
2734  } else {
2735  INTRAISE("Illegal value for C char array field.");
2736  }
2737 
2738  break;
2739 
2740  case FIELDTYPE_UINT8:
2741  if (PyInt_Check(value)) {
2742  unsigned long val = PyLong_AsUnsignedLong(value);
2743  if (PyErr_Occurred() || val > UINT8_MAX) {
2744  PyErr_SetString(PyExc_OverflowError,
2745  "Invalid integer value for uint8 field.");
2746  return -1;
2747  }
2748 
2749  *(uint8_t *) field_ptr = (uint8_t) val;
2750  } else {
2751  INTRAISE("Illegal value for uint8 field.");
2752  }
2753 
2754  break;
2755 
2756  case FIELDTYPE_INT8:
2757  if (PyInt_Check(value)) {
2758  long val = PyLong_AsLong(value);
2759  if (PyErr_Occurred() || val < INT8_MIN || val > INT8_MAX) {
2760  PyErr_SetString(PyExc_OverflowError,
2761  "Invalid integer value for int8 field.");
2762  return -1;
2763  }
2764 
2765  *(int8_t *) field_ptr = (int8_t) val;
2766  } else {
2767  INTRAISE("Illegal value for int8 field.");
2768  }
2769 
2770  break;
2771 
2772  case FIELDTYPE_UINT16:
2773  if (PyInt_Check(value)) {
2774  unsigned long val = PyLong_AsUnsignedLong(value);
2775  if (PyErr_Occurred() || val > UINT16_MAX) {
2776  PyErr_SetString(PyExc_OverflowError,
2777  "Invalid integer value for uint16 field.");
2778  return -1;
2779  }
2780 
2781  *(uint16_t *) field_ptr = (uint16_t) val;
2782  } else {
2783  INTRAISE("Illegal value for uint16 field.");
2784  }
2785 
2786  break;
2787 
2788  case FIELDTYPE_INT16:
2789  if (PyInt_Check(value)) {
2790  long val = PyLong_AsLong(value);
2791  if (PyErr_Occurred() || val < INT16_MIN || val > INT16_MAX) {
2792  PyErr_SetString(PyExc_OverflowError,
2793  "Invalid integer value for int16 field.");
2794  return -1;
2795  }
2796 
2797  *(int16_t *) field_ptr = (int16_t) val;
2798  } else {
2799  INTRAISE("Illegal value for int16 field.");
2800  }
2801 
2802  break;
2803 
2804  case FIELDTYPE_UINT32:
2805  if (PyInt_Check(value)) {
2806  unsigned long val = PyLong_AsUnsignedLong(value);
2807  if (PyErr_Occurred() || val > UINT32_MAX) {
2808  PyErr_SetString(PyExc_OverflowError,
2809  "Invalid integer value for uint32 field.");
2810  return -1;
2811  }
2812 
2813  *(uint32_t *) field_ptr = (uint32_t) val;
2814  } else {
2815  INTRAISE("Illegal value for uint32 field.");
2816  }
2817 
2818  break;
2819 
2820  case FIELDTYPE_INT32:
2821  if (PyInt_Check(value)) {
2822  int overflow;
2823  long val = PyLong_AsLongAndOverflow(value, &overflow);
2824  if (PyErr_Occurred() || overflow != 0 || val < INT32_MIN ||
2825  val > INT32_MAX) {
2826  PyErr_SetString(PyExc_OverflowError,
2827  "Invalid integer value for int32 field.");
2828  return -1;
2829  }
2830 
2831  *(int32_t *) field_ptr = (int32_t) val;
2832  } else {
2833  INTRAISE("Illegal value for int32 field.");
2834  }
2835 
2836  break;
2837 
2838  case FIELDTYPE_UINT64:
2839  if (PyInt_Check(value)) {
2840  unsigned PY_LONG_LONG val = PyLong_AsUnsignedLongLong(value);
2841  if (PyErr_Occurred()) {
2842  PyErr_SetString(PyExc_OverflowError,
2843  "Invalid integer value for uint64 field.");
2844  return -1;
2845  }
2846 
2847  *(uint64_t *) field_ptr = (uint64_t) val;
2848  } else {
2849  INTRAISE("Illegal value for uint64 field.");
2850  }
2851 
2852  break;
2853 
2854  case FIELDTYPE_INT64:
2855  if (PyInt_Check(value)) {
2856  PY_LONG_LONG val = PyLong_AsLongLong(value);
2857  if (PyErr_Occurred()) {
2858  PyErr_SetString(PyExc_OverflowError,
2859  "Invalid integer value for int64 field.");
2860  return -1;
2861  }
2862 
2863  *(int64_t *) field_ptr = (int64_t) val;
2864  } else {
2865  INTRAISE("Illegal value for int64 field.");
2866  }
2867 
2868  break;
2869 
2870  case FIELDTYPE_FLOAT:
2871  if (PyFloat_Check(value)) {
2872  *(float *) field_ptr = PyFloat_AsDouble(value);
2873  } else if (PyInt_Check(value)) {
2874  *(float *) field_ptr = PyLong_AsLong(value) * 1.0;
2875  } else {
2876  INTRAISE("Illegal value for float field.");
2877  }
2878 
2879  break;
2880 
2881  case FIELDTYPE_DOUBLE:
2882  if (PyFloat_Check(value)) {
2883  *(double *) field_ptr = PyFloat_AsDouble(value);
2884  } else if (PyInt_Check(value)) {
2885  *(double *) field_ptr = PyLong_AsLong(value) * 1.0;
2886  } else {
2887  INTRAISE("Illegal value for double field.");
2888  }
2889 
2890  break;
2891 
2892  case FIELDTYPE_OBJECT:
2893  if (value == Py_None) {
2894  *(object **) field_ptr = NULL;
2895  } else if (PyObject_TypeCheck(value, &Atrinik_ObjectType)) {
2896  OBJEXISTCHECK_INT((Atrinik_Object *) value);
2897  *(object **) field_ptr = (object *) ((Atrinik_Object *) value)->obj;
2898  } else {
2899  INTRAISE("Illegal value for object field.");
2900  }
2901 
2902  break;
2903 
2904  case FIELDTYPE_OBJECT2:
2906  INTRAISE("Field type not implemented.");
2907  break;
2908 
2909  case FIELDTYPE_MAP:
2910  if (value == Py_None) {
2911  *(mapstruct **) field_ptr = NULL;
2912  } else if (PyObject_TypeCheck(value, &Atrinik_MapType)) {
2913  *(mapstruct **) field_ptr =
2914  (mapstruct *) ((Atrinik_Map *) value)->map;
2915  } else {
2916  INTRAISE("Illegal value for map field.");
2917  }
2918 
2919  break;
2920 
2921  case FIELDTYPE_OBJECTREF:
2922  {
2923  void *field_ptr2 = (char *) ptr + field->extra_data;
2924  if (value == Py_None) {
2925  *(object **) field_ptr = NULL;
2926  *(tag_t *) field_ptr2 = 0;
2927  } else if (PyObject_TypeCheck(value, &Atrinik_ObjectType)) {
2928  object *tmp;
2929 
2930  OBJEXISTCHECK_INT((Atrinik_Object *) value);
2931 
2932  tmp = (object *) ((Atrinik_Object *) value)->obj;
2933  *(object **) field_ptr = tmp;
2934  *(tag_t *) field_ptr2 = tmp->count;
2935  } else {
2936  INTRAISE("Illegal value for object+reference field.");
2937  }
2938 
2939  break;
2940  }
2941 
2942  case FIELDTYPE_REGION:
2943  if (value == Py_None) {
2944  *(region_struct **) field_ptr = NULL;
2945  } else if (PyObject_TypeCheck(value, &Atrinik_RegionType)) {
2946  *(region_struct **) field_ptr =
2947  (region_struct *) ((Atrinik_Region *) value)->region;
2948  } else {
2949  INTRAISE("Illegal value for region field.");
2950  }
2951 
2952  break;
2953 
2954  case FIELDTYPE_PARTY:
2955  if (value == Py_None) {
2956  *(party_struct **) field_ptr = NULL;
2957  } else if (PyObject_TypeCheck(value, &Atrinik_PartyType)) {
2958  *(party_struct **) field_ptr =
2959  (party_struct *) ((Atrinik_Party *) value)->party;
2960  } else {
2961  INTRAISE("Illegal value for party field.");
2962  }
2963 
2964  break;
2965 
2966  case FIELDTYPE_ARCH:
2967  if (value == Py_None) {
2968  *(archetype_t **) field_ptr = NULL;
2969  } else if (PyObject_TypeCheck(value, &Atrinik_ArchetypeType)) {
2970  *(archetype_t **) field_ptr =
2971  (archetype_t *) ((Atrinik_Archetype *) value)->at;
2972  } else if (PyString_Check(value)) {
2973  const char *archname;
2974  archetype_t *arch;
2975 
2976  archname = PyString_AsString(value);
2977  arch = hooks->arch_find(archname);
2978 
2979  if (!arch) {
2980  PyErr_Format(AtrinikError, "Could not find archetype '%s'.",
2981  archname);
2982  return -1;
2983  } else {
2984  *(archetype_t **) field_ptr = arch;
2985  }
2986  } else {
2987  INTRAISE("Illegal value for archetype field.");
2988  }
2989 
2990  break;
2991 
2992  case FIELDTYPE_PLAYER:
2993  if (value == Py_None) {
2994  *(player **) field_ptr = NULL;
2995  } else if (PyObject_TypeCheck(value, &Atrinik_PlayerType)) {
2996  *(player **) field_ptr = (player *) ((Atrinik_Player *) value)->pl;
2997  } else {
2998  INTRAISE("Illegal value for player field.");
2999  }
3000 
3001  break;
3002 
3003  case FIELDTYPE_FACE:
3004  if (PyTuple_Check(value)) {
3005  if (PyTuple_GET_SIZE(value) != 2) {
3006  PyErr_Format(PyExc_ValueError,
3007  "Tuple for face field must have exactly two values.");
3008  return -1;
3009  } else if (!PyInt_Check(PyTuple_GET_ITEM(value, 1))) {
3010  PyErr_SetString(PyExc_ValueError,
3011  "Second value of tuple used for face field is not an "
3012  "integer.");
3013  return -1;
3014  }
3015 
3016  return set_face_field(field_ptr,
3017  PyLong_AsLong(PyTuple_GET_ITEM(value, 1)));
3018  } else if (PyInt_Check(value)) {
3019  return set_face_field(field_ptr, PyLong_AsLong(value));
3020  } else if (PyString_Check(value)) {
3021  return set_face_field(field_ptr,
3022  hooks->find_face(PyString_AsString(value), 0));
3023  } else {
3024  INTRAISE("Illegal value for face field.");
3025  }
3026 
3027  break;
3028 
3029  case FIELDTYPE_ANIMATION:
3030  if (PyTuple_Check(value)) {
3031  if (PyTuple_GET_SIZE(value) != 2) {
3032  PyErr_Format(PyExc_ValueError,
3033  "Tuple for animation field must have exactly two "
3034  "values.");
3035  return -1;
3036  } else if (!PyInt_Check(PyTuple_GET_ITEM(value, 1))) {
3037  PyErr_SetString(PyExc_ValueError,
3038  "Second value of tuple used for animation field is not "
3039  "an integer.");
3040  return -1;
3041  }
3042 
3043  return set_animation_field(field_ptr,
3044  PyLong_AsLong(PyTuple_GET_ITEM(value, 1)));
3045  } else if (PyInt_Check(value)) {
3046  return set_animation_field(field_ptr, PyLong_AsLong(value));
3047  } else if (PyString_Check(value)) {
3048  return set_animation_field(field_ptr,
3049  hooks->find_animation(PyString_AsString(value)));
3050  } else {
3051  INTRAISE("Illegal value for animation field.");
3052  }
3053 
3054  break;
3055 
3056  case FIELDTYPE_BOOLEAN:
3057  if (value == Py_True) {
3058  *(uint8_t *) field_ptr = 1;
3059  } else if (value == Py_False) {
3060  *(uint8_t *) field_ptr = 0;
3061  } else {
3062  INTRAISE("Illegal value for boolean field.");
3063  }
3064 
3065  break;
3066 
3067  case FIELDTYPE_CONNECTION:
3068  if (PyInt_Check(value)) {
3069  hooks->connection_object_add(ptr, ((object *) ptr)->map,
3070  PyLong_AsLong(value));
3071  } else {
3072  INTRAISE("Illegal value for connection field.");
3073  }
3074 
3075  break;
3076 
3078  if (PyString_Check(value)) {
3079  *(treasure_list_t **) field_ptr =
3080  hooks->treasure_list_find(PyString_AsString(value));
3081  } else {
3082  INTRAISE("Illegal value for treasure list field.");
3083  }
3084 
3085  break;
3086 
3087  case FIELDTYPE_PACKET:
3088  {
3089  if (!PyBytes_Check(value)) {
3090  INTRAISE("Illegal value for packet field.");
3091  }
3092 
3093  packet_struct *packet = *(packet_struct **) field_ptr;
3094  char *str = PyBytes_AsString(value);
3095  size_t len = PyBytes_Size(value);
3096  if (len > packet->size) {
3097  PyErr_Format(PyExc_OverflowError,
3098  "Data too large for the packet to hold.");
3099  return -1;
3100  }
3101 
3102  packet->len = 0;
3103  hooks->packet_append_data_len(packet, (uint8_t *) str, len);
3104  break;
3105  }
3106 
3107  default:
3108  break;
3109  }
3110 
3111  return 0;
3112 }
3113 
3126 PyObject *generic_field_getter(fields_struct *field, void *ptr)
3127 {
3128  void *field_ptr;
3129 
3130  field_ptr = (char *) ptr + field->offset;
3131 
3132  switch (field->type) {
3133  case FIELDTYPE_SHSTR:
3134  case FIELDTYPE_CSTR:
3135  {
3136  char *str = *(char **) field_ptr;
3137 
3138  if (str == NULL) {
3139  Py_INCREF(Py_None);
3140  return Py_None;
3141  }
3142 
3143  return Py_BuildValue("s", str);
3144  }
3145 
3146  case FIELDTYPE_CARY:
3147  return Py_BuildValue("s", (char *) field_ptr);
3148 
3149  case FIELDTYPE_UINT8:
3150  return Py_BuildValue("B", *(uint8_t *) field_ptr);
3151 
3152  case FIELDTYPE_INT8:
3153  return Py_BuildValue("b", *(int8_t *) field_ptr);
3154 
3155  case FIELDTYPE_UINT16:
3156  return Py_BuildValue("H", *(uint16_t *) field_ptr);
3157 
3158  case FIELDTYPE_INT16:
3159  return Py_BuildValue("h", *(int16_t *) field_ptr);
3160 
3161  case FIELDTYPE_UINT32:
3162  return Py_BuildValue("I", *(uint32_t *) field_ptr);
3163 
3164  case FIELDTYPE_INT32:
3165  return Py_BuildValue("i", *(int32_t *) field_ptr);
3166 
3167  case FIELDTYPE_UINT64:
3168  return Py_BuildValue("K", *(uint64_t *) field_ptr);
3169 
3170  case FIELDTYPE_INT64:
3171  return Py_BuildValue("L", *(int64_t *) field_ptr);
3172 
3173  case FIELDTYPE_FLOAT:
3174  return Py_BuildValue("f", *(float *) field_ptr);
3175 
3176  case FIELDTYPE_DOUBLE:
3177  return Py_BuildValue("d", *(double *) field_ptr);
3178 
3179  case FIELDTYPE_MAP:
3180  return wrap_map(*(mapstruct **) field_ptr);
3181 
3182  case FIELDTYPE_OBJECT:
3183  return wrap_object(*(object **) field_ptr);
3184 
3185  case FIELDTYPE_OBJECT2:
3186  return wrap_object(field_ptr);
3187 
3189  return wrap_object_iterator(*(object **) field_ptr);
3190 
3191  case FIELDTYPE_OBJECTREF:
3192  {
3193  object *obj = *(object **) field_ptr;
3194  tag_t tag = *(tag_t *) (void *) ((char *) ptr + field->extra_data);
3195 
3196  return wrap_object(OBJECT_VALID(obj, tag) ? obj : NULL);
3197  }
3198 
3199  case FIELDTYPE_REGION:
3200  return wrap_region(*(region_struct **) field_ptr);
3201 
3202  case FIELDTYPE_PARTY:
3203  return wrap_party(*(party_struct **) field_ptr);
3204 
3205  case FIELDTYPE_ARCH:
3206  return wrap_archetype(*(archetype_t **) field_ptr);
3207 
3208  case FIELDTYPE_PLAYER:
3209  return wrap_player(*(player **) field_ptr);
3210 
3211  case FIELDTYPE_FACE:
3212  return Py_BuildValue("(sH)", (*(New_Face **) field_ptr)->name,
3213  (*(New_Face **) field_ptr)->number);
3214 
3215  case FIELDTYPE_ANIMATION:
3216  return Py_BuildValue("(sH)",
3217  (&(*hooks->animations)[*(uint16_t *) field_ptr])->name,
3218  *(uint16_t *) field_ptr);
3219 
3220  case FIELDTYPE_BOOLEAN:
3221  return Py_BuildBoolean(*(uint8_t *) field_ptr);
3222 
3223  case FIELDTYPE_LIST:
3224  return wrap_attr_list(ptr, field->offset, field->extra_data);
3225 
3226  case FIELDTYPE_CONNECTION:
3227  return Py_BuildValue("i", hooks->connection_object_get_value(ptr));
3228 
3230  {
3231  treasure_list_t *tl = *(treasure_list_t **) field_ptr;
3232  if (tl == NULL) {
3233  Py_INCREF(Py_None);
3234  return Py_None;
3235  }
3236 
3237  return Py_BuildValue("s", tl->name);
3238  }
3239 
3240  case FIELDTYPE_PACKET:
3241  {
3242  packet_struct *packet = *(packet_struct **) field_ptr;
3243  return PyBytes_FromStringAndSize((const char *) packet->data,
3244  packet->len);
3245  }
3246 
3247  default:
3248  break;
3249  }
3250 
3251  RAISE("Unknown field type.");
3252 }
3253 
3263 PyObject *generic_rich_compare(int op, int result)
3264 {
3265  /* Based on how Python 3.0 (GPL compatible) implements it for internal
3266  * types. */
3267  switch (op) {
3268  case Py_EQ:
3269  result = (result == 0);
3270  break;
3271  case Py_NE:
3272  result = (result != 0);
3273  break;
3274  case Py_LE:
3275  result = (result <= 0);
3276  break;
3277  case Py_GE:
3278  result = (result >= 0);
3279  break;
3280  case Py_LT:
3281  result = (result == -1);
3282  break;
3283  case Py_GT:
3284  result = (result == 1);
3285  break;
3286  }
3287 
3288  return PyBool_FromLong(result);
3289 }
3290 
3301 int python_call_int(PyObject *callable, PyObject *arglist)
3302 {
3303  /* Call the Python function. */
3304  PyObject *result = PyEval_CallObject(callable, arglist);
3305 
3306  int retval = 0;
3307  /* Check the result. */
3308  if (result != NULL && PyInt_Check(result)) {
3309  retval = PyInt_AsLong(result);
3310  }
3311 
3312  Py_XDECREF(result);
3313  Py_DECREF(arglist);
3314 
3315  return retval;
3316 }
PyTypeObject Atrinik_PlayerType
#define SCROLL
Definition: define.h:453
#define GENDER_MALE
Definition: object.h:633
static const char doc_Atrinik_CreateObject[]
#define GT_ONLY_GOOD
Definition: treasure.h:63
PyTypeObject Atrinik_ObjectType
Definition: object.h:94
static PyObject * Atrinik_FindParty(PyObject *self, PyObject *args)
#define CONE
Definition: define.h:385
#define FREE_AND_COPY_HASH(_sv_, _nv_)
Definition: global.h:100
#define MONSTER
Definition: define.h:353
#define EXIT
Definition: define.h:312
static const Atrinik_Constant constants_gender[]
#define TERRAIN_FIREWALK
Definition: define.h:684
static const Atrinik_Constant constants[]
static void module_add_array(PyObject *module, const char *name, void *array, size_t array_size, field_type type)
long seconds(void)
Definition: time.c:338
#define REGION_MAP
Definition: define.h:146
#define EVENT_CLOSE
Definition: plugin.h:95
int direction
Definition: map.h:787
static const char doc_Atrinik_GetFirst[]
const char * race
Definition: object.h:174
#define MEVENT_SKILL_USED
Definition: plugin.h:127
#define GT_STARTEQUIP
Definition: treasure.h:59
#define DISEASE
Definition: define.h:538
#define DEAD_OBJECT
Definition: define.h:275
static void py_runfile_simple(const char *path, PyObject *locals)
#define LAYER_FMASK
Definition: map.h:51
struct plugin_hooklist * hooks
Definition: plugin_python.c:52
#define BOOK
Definition: define.h:150
#define SAVEBED
Definition: define.h:441
unsigned int distance
Definition: map.h:775
Always apply, never unapply.
Definition: define.h:1490
#define RV_NO_DISTANCE
Definition: map.h:813
#define JEWEL
Definition: define.h:473
#define MARKER
Definition: define.h:284
#define AROUND_ALL
#define QUEST_CONTAINER
Definition: define.h:489
#define MAP_INFO_ALL
Definition: global.h:85
#define GT_NO_VALUE
Definition: treasure.h:67
#define MEVENT_SPELL_CAST
Definition: plugin.h:125
static const char doc_Atrinik_FindParty[]
Regular apply.
Definition: define.h:1489
#define MEVENT_DROP
Definition: plugin.h:129
PyObject * generic_rich_compare(int op, int result)
#define P_NEED_UPDATE
Definition: map.h:307
#define SOUTH
Definition: map.h:845
#define CREATOR
Definition: define.h:242
Allow unapplying cursed items.
Definition: define.h:1495
#define PEDESTAL
Definition: define.h:186
uint8_t type
One of operation types.
Definition: sound_ambient.c:45
static const char doc_Atrinik_SetReturnValue[]
PyObject * wrap_object_iterator(object *what)
#define GEVENT_LOGIN
Definition: plugin.h:153
static PyObject * Atrinik_GetRangeVectorFromMapCoords(PyObject *self, PyObject *args)
#define ORGANIC
Definition: define.h:377
shstr * path
Definition: map.h:568
#define NROFREALSPELLS
Definition: define.h:664
#define SIZEOFFREE1
Definition: define.h:654
const char * text
#define WAND
Definition: define.h:445
#define GIRDLE
Definition: define.h:461
#define Py_BuildBoolean(val)
uint32_t flags
#define BOW
Definition: define.h:174
int minute
Definition: tod.h:82
const char * name
#define RV_EUCLIDIAN_DISTANCE
Definition: map.h:805
int distance_x
Definition: map.h:778
#define OBJECT_METHOD_ERROR
#define INVENTORY_CONTAINERS
#define GT_UPDATE_INV
Definition: treasure.h:65
static PyObject * Atrinik_ReadyMap(PyObject *self, PyObject *args)
#define LIGHT_SOURCE
Definition: define.h:344
#define SHIELD
Definition: define.h:214
static const char doc_Atrinik_WhatIsMessage[]
static PyObject * Atrinik_CreateObject(PyObject *self, PyObject *args)
#define TREASURE
Definition: define.h:134
#define P_NO_PASS
Definition: map.h:254
#define BUTTON
Definition: define.h:397
#define SHOP_FLOOR
Definition: define.h:316
object * ob
Definition: player.h:185
static PyObject * Atrinik_LoadObject(PyObject *self, PyObject *args)
#define CACHE_FLAG_GEVENT
Definition: global.h:503
#define HOLY_ALTAR
Definition: define.h:288
static const char doc_Atrinik_GetSettings[]
#define LAYER_FLOOR
Definition: map.h:49
static python_eval_struct * python_eval
Definition: plugin_python.c:84
PyObject * locals
Locals dictionary.
Definition: plugin_python.c:76
#define RAISE(msg)
#define CLIENT_MAP_INFO
Definition: define.h:526
#define GENDER_MAX
Definition: object.h:639
struct python_eval_struct * next
Next pointer.
Definition: plugin_python.c:72
#define TERRAIN_WATERWALK
Definition: define.h:680
#define P_OUT_OF_MAP
Definition: map.h:305
#define GEVENT_TICK
Definition: plugin.h:161
#define LAYER_ITEM
Definition: map.h:53
#define CAST_WAND
Definition: spells.h:277
#define MISC_OBJECT
Definition: define.h:349
#define MONEY
Definition: define.h:226
Always unapply, never apply.
Definition: define.h:1491
static PyObject * Atrinik_WhatIsEvent(PyObject *self)
#define BRACERS
Definition: define.h:433
#define MEVENT_LOGIN
Definition: plugin.h:137
#define WEALTH
Definition: define.h:498
static const char doc_Atrinik_GetArchetype[]
static void PyErr_LOG(void)
#define P_FLY_ON
Definition: map.h:296
#define TYPE_HANDLE
Definition: define.h:401
#define PLAYER
Definition: define.h:122
#define RV_IGNORE_MULTIPART
Definition: map.h:819
#define P_FLY_OFF
Definition: map.h:294
static void initContextStack(void)
#define WEST
Definition: map.h:849
#define GT_ENVIRONMENT
Definition: treasure.h:57
PyObject * AtrinikError
Definition: plugin_python.c:55
static PyObject * Atrinik_GetReturnValue(PyObject *self)
#define P_PASS_THRU
Definition: map.h:288
#define RV_MANHATTAN_DISTANCE
Definition: map.h:801
PyObject * wrap_region(region_struct *what)
PyObject * wrap_object(object *what)
static PyObject * Atrinik_CostString(PyObject *self, PyObject *args)
#define P_WALK_OFF
Definition: map.h:292
#define MEVENT_PICK
Definition: plugin.h:131
static const char doc_Atrinik_WhoAmI[]
#define PLUGIN_NAME
Definition: plugin_arena.c:95
#define EVENT_OBJECT
Definition: define.h:481
#define QUEST_TYPE_ITEM_DROP
Definition: define.h:1541
#define EVENT_TIME
Definition: plugin.h:89
#define BANK_WITHDRAW_OVERWEIGHT
Definition: global.h:59
#define MAP_PLAYER_UNIQUE
Definition: map.h:149
#define PLUGIN_VERSION
Definition: plugin_arena.c:98
#define EVENT_APPLY
Definition: plugin.h:75
#define DETECTOR
Definition: define.h:267
static cache_struct * cache
Definition: cache.c:61
#define CLOCK
Definition: define.h:154
#define POISONING
Definition: define.h:437
#define MAGIC_MIRROR
Definition: define.h:206
PyTypeObject Atrinik_ArchetypeType
#define BANK_DEPOSIT_SILVER
Definition: global.h:64
int periodofday
Definition: tod.h:91
static PythonContext * context_stack
Definition: plugin_python.c:58
#define WALL
Definition: define.h:340
double seconds
When to execute.
Definition: plugin_python.c:78
static const char doc_Atrinik_CacheGet[]
static const char doc_Atrinik_GetEventNumber[]
static PyObject * Atrinik_CacheRemove(PyObject *self, PyObject *args)
#define QUEST_STATUS_INVALID
Definition: define.h:1518
static PythonContext * popContext(void)
#define GT_APPLY
Definition: treasure.h:61
#define RV_NO_LOAD
Definition: map.h:829
#define P_MAGIC_MIRROR
Definition: map.h:298
#define MEVENT_LEAVE
Definition: plugin.h:121
int year
Definition: tod.h:67
#define FLESH
Definition: define.h:328
#define SPAWN_POINT
Definition: define.h:357
#define LAYER_SYS
Definition: map.h:47
static PyObject * py_globals_dict
Definition: plugin_python.c:64
struct python_eval_struct * prev
Previous pointer.
Definition: plugin_python.c:73
#define EVENT_PICKUP
Definition: plugin.h:83
#define WORD_OF_RECALL
Definition: define.h:405
#define CACHE_FLAG_PYOBJ
Definition: global.h:499
#define ARMOUR
Definition: define.h:182
PyObject * globals
Globals dictionary.
Definition: plugin_python.c:75
static const char doc_Atrinik_FindPlayer[]
#define SPAWN_POINT_INFO
Definition: define.h:369
int distance_y
Definition: map.h:781
#define SPINNER
Definition: define.h:389
static PyObject * Atrinik_GetSettings(PyObject *self)
#define NORTH
Definition: map.h:837
PyObject * wrap_attr_list(void *ptr, size_t offset, field_type field)
Definition: attr_list.c:810
#define MEVENT_CMD_TAKE
Definition: plugin.h:141
#define P_BLOCKSVIEW
Definition: map.h:250
int Atrinik_Region_init(PyObject *module)
#define BANK_DEPOSIT_MITHRIL
Definition: global.h:70
#define EVENT_TRIGGER
Definition: plugin.h:93
#define P_DOOR_CLOSED
Definition: map.h:272
static PyObject * Atrinik_Logger(PyObject *self, PyObject *args)
#define COST_BUY
Definition: define.h:1370
static const char doc_Atrinik_CacheAdd[]
static const Atrinik_Constant constants_types[]
shstr * name
Definition: treasure.h:177
#define COST_TRUE
Definition: define.h:1374
static const char doc_Atrinik_WhatIsEvent[]
static PyObject * Atrinik_GetFirst(PyObject *self, PyObject *args)
#define P_IS_PLAYER
Definition: map.h:256
static const char doc_Atrinik_Process[]
#define SWARM_SPELL
Definition: define.h:518
static const char doc_Atrinik_CreatePathname[]
#define QUEST_TYPE_KILL
Definition: define.h:1534
#define ABILITY
Definition: define.h:449
static const char doc_Atrinik_Eval[]
int Atrinik_Archetype_init(PyObject *module)
static PyObject * Atrinik_CacheGet(PyObject *self, PyObject *args)
#define BANK_DEPOSIT_COPPER
Definition: global.h:62
Do not merge unapplied items.
Definition: define.h:1494
static PyObject * Atrinik_WhatIsMessage(PyObject *self)
#define GENDER_HERMAPHRODITE
Definition: object.h:637
Definition: arch.h:40
MODULEAPI void closePlugin(void)
static PyObject * Atrinik_WhoAmI(PyObject *self)
#define MAP_INFO_NORMAL
Definition: global.h:83
#define GOD
Definition: define.h:262
static PyObject * Atrinik_WhoIsActivator(PyObject *self)
uint32_t flags
Definition: global.h:515
#define EVENT_DEATH
Definition: plugin.h:79
static const char doc_Atrinik_GetReturnValue[]
PyObject * wrap_map(mapstruct *what)
Definition: atrinik_map.c:1139
#define SIZEOFFREE2
Definition: define.h:656
#define RV_RECURSIVE_SEARCH
Definition: map.h:825
uint32_t extra_data
static int handle_global_event(int event_type, va_list args)
#define POWER_CRYSTAL
Definition: define.h:530
#define CAST_NPC
Definition: spells.h:288
static const char package_doc[]
Definition: plugin_python.c:87
#define EAST
Definition: map.h:841
static const char doc_Atrinik_PlayerExists[]
#define IDENTIFY_MARKED
Definition: define.h:62
static PyObject * Atrinik_PlayerExists(PyObject *self, PyObject *args)
#define GENDER_NEUTER
Definition: object.h:631
static PyObject * Atrinik_RegisterCommand(PyObject *self, PyObject *args)
#define BANK_DEPOSIT_GOLD
Definition: global.h:66
int python_call_int(PyObject *callable, PyObject *arglist)
struct mapdef * map
Definition: object.h:139
static PyCodeObject * compilePython(char *filename)
#define PLUGIN_EVENT_NORMAL
Definition: plugin.h:59
static int handle_map_event(va_list args)
static PyObject * Atrinik_CreateMap(PyObject *self, PyObject *args)
static int set_animation_field(void *ptr, long anim_id)
#define FIELDFLAG_READONLY
#define BANK_WITHDRAW_HIGH
Definition: global.h:55
static int handle_event(va_list args)
int month
Definition: tod.h:70
#define INVENTORY_ALL
#define CONFUSION
Definition: define.h:190
#define PLAYER_MOVER
Definition: define.h:238
PyObject * wrap_archetype(archetype_t *at)
#define MAP_INFO
Definition: define.h:514
#define GEVENT_BORN
Definition: plugin.h:151
static const char doc_Atrinik_CacheRemove[]
const char * name
Definition: object.h:168
#define BANK_SYNTAX_ERROR
Definition: global.h:50
static PyObject * Atrinik_Eval(PyObject *self, PyObject *args)
#define LAYER_LIVING
Definition: map.h:59
#define MAX_TIME
Definition: config.h:72
#define SIZEOFFREE3
Definition: define.h:658
#define MEVENT_CMD_DROP
Definition: plugin.h:139
#define P_OUTDOOR
Definition: map.h:300
static const char doc_Atrinik_GetRangeVectorFromMapCoords[]
static PyObject * Atrinik_WhoIsOther(PyObject *self)
#define CONTAINER
Definition: define.h:493
static const char *const constants_colors[][2]
#define AROUND_BLOCKSVIEW
#define P_NO_MAGIC
Definition: map.h:252
#define WAYPOINT_OBJECT
Definition: define.h:485
int day
Definition: tod.h:73
#define QUEST_TYPE_SPECIAL
Definition: define.h:1546
int generic_field_setter(fields_struct *field, void *ptr, PyObject *value)
Do not trigger an event.
Definition: define.h:1496
field_type type
int dayofweek
Definition: tod.h:76
const char * options
static PyObject * py_runfile(const char *path, PyObject *globals, PyObject *locals)
static int handle_unit_event(va_list args)
#define SOUTHEAST
Definition: map.h:843
int Atrinik_AttrList_init(PyObject *module)
Definition: attr_list.c:784
#define BANK_WITHDRAW_MISSING
Definition: global.h:57
#define BOOK_SPELL
Definition: define.h:373
#define EVENT_SAY
Definition: plugin.h:85
#define ARROW
Definition: define.h:170
char * file
MODULEAPI void * triggerEvent(int *type,...)
#define SPAWN_POINT_MOB
Definition: define.h:365
#define COST_SELL
Definition: define.h:1372
#define GEM
Definition: define.h:296
#define ROD
Definition: define.h:130
#define GEVENT_PLAYER_DEATH
Definition: plugin.h:157
#define MEVENT_APPLY
Definition: plugin.h:135
field_type
#define NUM_LAYERS
Definition: map.h:67
#define CAST_SCROLL
Definition: spells.h:281
static void freeContext(PythonContext *context)
#define SIGN
Definition: define.h:409
#define BANK_DEPOSIT_JADE
Definition: global.h:68
#define INVENTORY_ONLY
#define OBJECT_METHOD_UNHANDLED
int Atrinik_Player_init(PyObject *module)
#define POTION
Definition: define.h:138
#define NUGGET
Definition: define.h:477
static PyObject * Atrinik_GetEventParameters(PyObject *self)
MODULEAPI void getPluginProperty(int *type,...)
static PyObject * Atrinik_GetOptions(PyObject *self)
static const char doc_Atrinik_WhoIsActivator[]
#define TERRAIN_FIREBREATH
Definition: define.h:686
static const char doc_Atrinik_Logger[]
#define P_PLAYER_ONLY
Definition: map.h:267
#define TREASURE_ARTIFACT_CHANCE
Artifact chance value is not set.
Definition: global.h:173
#define CAST_ROD
Definition: spells.h:279
#define NUM_SUB_LAYERS
Definition: map.h:71
#define EVENT_ATTACK
Definition: plugin.h:77
PyTypeObject Atrinik_PartyType
#define POTION_EFFECT
Definition: define.h:469
PyObject_HEAD mapstruct * map
#define LAYER_ITEM2
Definition: map.h:55
#define GEVENT_CACHE_REMOVED
Definition: plugin.h:159
PyObject * generic_field_getter(fields_struct *field, void *ptr)
static const char doc_Atrinik_GetTime[]
#define PEARL
Definition: define.h:292
PythonContext * current_context
Definition: plugin_python.c:60
static const char doc_Atrinik_print[]
#define BANK_SUCCESS
Definition: global.h:52
#define LIGHTNING
Definition: define.h:166
#define LIGHT_APPLY
Definition: define.h:336
#define SIZEOFFREE
Definition: define.h:660
#define DIRECTOR
Definition: define.h:457
static PyObject * Atrinik_GetTime(PyObject *self)
PyTypeObject Atrinik_RegionType
#define MAXLEVEL
Definition: global.h:221
#define RANDOM_DROP
Definition: define.h:429
static PyObject * Atrinik_CacheAdd(PyObject *self, PyObject *args)
#define GATE
Definition: define.h:393
int Atrinik_Party_init(PyObject *module)
static PyObject * Atrinik_GetArchetype(PyObject *self, PyObject *args)
static PyObject * Atrinik_print(PyObject *self, PyObject *args)
static void command_custom_python(object *op, const char *command, char *params)
static python_cache_entry * python_cache
#define DUPLICATOR
Definition: define.h:162
#define GENDER_FEMALE
Definition: object.h:635
#define TERRAIN_NOTHING
Definition: define.h:676
#define MATERIAL
Definition: define.h:158
static const char doc_Atrinik_LoadObject[]
#define FLOOR
Definition: define.h:324
#define MEVENT_EXAMINE
Definition: plugin.h:143
#define RING
Definition: define.h:320
static PyObject * Atrinik_GetTicks(PyObject *self)
void * ptr
Definition: global.h:512
#define RV_DIAGONAL_DISTANCE
Definition: map.h:809
#define PLUGIN_EVENT_UNIT
Definition: plugin.h:65
static const char doc_Atrinik_CostString[]
#define FIREWALL
Definition: define.h:304
#define LAYER_EFFECT
Definition: map.h:61
static const char doc_Atrinik_WhoIsOther[]
static const char doc_Atrinik_GetEventParameters[]
#define GEVENT_LOGOUT
Definition: plugin.h:155
static const char doc_Atrinik_ReadyMap[]
#define QUEST_STATUS_COMPLETED
Definition: define.h:1522
tag_t count
Definition: object.h:142
#define QUEST_STATUS_STARTED
Definition: define.h:1520
#define P_WALK_ON
Definition: map.h:290
static PyMethodDef AtrinikMethods[]
PyObject * wrap_party(party_struct *what)
#define BLINDNESS
Definition: define.h:258
#define P_CHECK_INV
Definition: map.h:276
Definition: tod.h:65
#define SKILL
Definition: define.h:246
uint8_t type
Definition: object.h:360
#define IDENTIFY_NORMAL
Definition: define.h:58
#define WEAPON
Definition: define.h:178
static const char module_doc_gender[]
Definition: plugin_python.c:97
#define PARTY_MESSAGE_STATUS
Definition: party.h:41
static const char doc_Atrinik_RegisterCommand[]
static PyObject * Atrinik_FindPlayer(PyObject *self, PyObject *args)
#define PARTY_MESSAGE_CHAT
Definition: party.h:45
#define FOOD
Definition: define.h:142
#define INORGANIC
Definition: define.h:332
int hour
Definition: tod.h:79
#define IDENTIFY_ALL
Definition: define.h:60
#define QUEST_STATUS_FAILED
Definition: define.h:1524
#define FREE_AND_CLEAR_HASH(_nv_)
Definition: global.h:130
#define RUNE
Definition: define.h:522
#define MEVENT_ENTER
Definition: plugin.h:119
int Atrinik_Object_init(PyObject *module)
static PyObject * Atrinik_Process(PyObject *self)
#define MAP
Definition: define.h:202
#define OBJECT_METHOD_OK
#define OBJECT_VALID(_ob_, _count_)
Definition: object.h:548
#define EVENT_THROW
Definition: plugin.h:91
static PyObject * Atrinik_SetReturnValue(PyObject *self, PyObject *args)
#define NORTHEAST
Definition: map.h:839
#define HELMET
Definition: define.h:218
#define TERRAIN_AIRBREATH
Definition: define.h:678
static void module_add_constants(PyObject *module, const char *name, const Atrinik_Constant *consts, const char *doc)
PyObject * wrap_player(player *pl)
#define KEY
Definition: define.h:198
#define SOUND_AMBIENT
Definition: define.h:300
static PyObject * Atrinik_CreatePathname(PyObject *self, PyObject *args)
#define DOOR
Definition: define.h:194
#define INTRAISE(msg)
#define SOUTHWEST
Definition: map.h:847
#define BOOTS
Definition: define.h:413
#define AROUND_WALL
#define SYMPTOM
Definition: define.h:542
MODULEAPI void postinitPlugin(void)
#define P_IS_MONSTER
Definition: map.h:258
#define PLUGIN_EVENT_MAP
Definition: plugin.h:61
int Atrinik_Map_init(PyObject *module)
Definition: atrinik_map.c:1086
struct python_eval_struct python_eval_struct
struct _pythoncontext * down
#define GLOVES
Definition: define.h:417
#define DRINK
Definition: define.h:279
#define BULLET
Definition: define.h:126
#define EVENT_ASK_SHOW
Definition: plugin.h:99
PyTypeObject Atrinik_MapType
Definition: atrinik_map.c:1040
#define P_NO_TERRAIN
Definition: map.h:312
static const char module_doc_type[]
Definition: plugin_python.c:93
#define QUEST_TYPE_ITEM
Definition: define.h:1536
#define MEVENT_PUT
Definition: plugin.h:133
#define PANTS
Definition: define.h:222
#define MEVENT_RESET
Definition: plugin.h:123
#define AROUND_PLAYER_ONLY
#define CAST_POTION
Definition: spells.h:283
#define NORTHWEST
Definition: map.h:851
Definition: map.h:536
#define P_NO_PVP
Definition: map.h:280
static const char doc_Atrinik_CreateMap[]
#define AMULET
Definition: define.h:234
#define CLOAK
Definition: define.h:381
#define CAST_NORMAL
Definition: spells.h:275
static const char doc_Atrinik_GetOptions[]
#define COMPASS
Definition: define.h:510
static void pushContext(PythonContext *context)
#define CHECK_INV
Definition: define.h:308
#define EVENT_STOP
Definition: plugin.h:87
static PyObject * Atrinik_GetEventNumber(PyObject *self)
#define TERRAIN_ALL
Definition: define.h:692
#define FORCE
Definition: define.h:465
#define MAP_EVENT_OBJ
Definition: define.h:506
static PyObject * module_create(PyObject *parent, const char *name)
#define LIGHT_REFILL
Definition: define.h:361
#define EVENT_DROP
Definition: plugin.h:81
MODULEAPI void initPlugin(struct plugin_hooklist *hooklist)
static int set_face_field(void *ptr, long face_id)
#define CORPSE
Definition: define.h:534
#define BASE_INFO
Definition: define.h:421
#define BANK_DEPOSIT_AMBER
Definition: global.h:72
#define TERRAIN_WATERBREATH
Definition: define.h:682
#define PLUGIN_EVENT_GLOBAL
Definition: plugin.h:63
#define LAYER_WALL
Definition: map.h:57
PyCodeObject * code
Compiled code to execute.
Definition: plugin_python.c:77
int season
Definition: tod.h:88
#define SKILL_ITEM
Definition: define.h:271
#define TERRAIN_WATER_SHALLOW
Definition: define.h:690
#define BEACON
Definition: define.h:502
static const char doc_Atrinik_GetTicks[]
object * activator
#define SPELL
Definition: define.h:210
uint8_t sub_type
Definition: object.h:363
#define TERRAIN_CLOUDWALK
Definition: define.h:688