Crossfire Server, Trunk  R20763
cfpython.c
Go to the documentation of this file.
1 /*****************************************************************************/
2 /* CFPython - A Python module for Crossfire RPG. */
3 /*****************************************************************************/
4 /* This is the third version of the Crossfire Scripting Engine. */
5 /* The first version used Guile. It was directly integrated in the server */
6 /* code, but since Guile wasn't perceived as an easy-to-learn, easy-to-use */
7 /* language by many, it was dropped in favor of Python. */
8 /* The second version, CFPython 1.0, was included as a plugin and provided */
9 /* just about the same level of functionality the current version has. But */
10 /* it used a rather counter-intuitive, procedural way of presenting things. */
11 /* */
12 /* CFPython 2.0 aims at correcting many of the design flaws crippling the */
13 /* older version. It is also the first plugin to be implemented using the */
14 /* new interface, that doesn't need awkward stuff like the horrible CFParm */
15 /* structure. For the Python writer, things should probably be easier and */
16 /* lead to more readable code: instead of writing "CFPython.getObjectXPos(ob)*/
17 /* he/she now can simply write "ob.X". */
18 /* */
19 /*****************************************************************************/
20 /* Please note that it is still very beta - some of the functions may not */
21 /* work as expected and could even cause the server to crash. */
22 /*****************************************************************************/
23 /* Version history: */
24 /* 0.1 "Ophiuchus" - Initial Alpha release */
25 /* 0.5 "Stalingrad" - Message length overflow corrected. */
26 /* 0.6 "Kharkov" - Message and Write correctly redefined. */
27 /* 0.7 "Koursk" - Setting informations implemented. */
28 /* 1.0a "Petersburg" - Last "old-fashioned" version, never submitted to CVS.*/
29 /* 2.0 "Arkangelsk" - First release of the 2.x series. */
30 /*****************************************************************************/
31 /* Version: 2.0beta8 (also known as "Alexander") */
32 /* Contact: yann.chachkoff@myrealbox.com */
33 /*****************************************************************************/
34 /* That code is placed under the GNU General Public Licence (GPL) */
35 /* (C)2001-2005 by Chachkoff Yann (Feel free to deliver your complaints) */
36 /*****************************************************************************/
37 /* CrossFire, A Multiplayer game for X-windows */
38 /* */
39 /* Copyright (C) 2000 Mark Wedel */
40 /* Copyright (C) 1992 Frank Tore Johansen */
41 /* */
42 /* This program is free software; you can redistribute it and/or modify */
43 /* it under the terms of the GNU General Public License as published by */
44 /* the Free Software Foundation; either version 2 of the License, or */
45 /* (at your option) any later version. */
46 /* */
47 /* This program is distributed in the hope that it will be useful, */
48 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
49 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
50 /* GNU General Public License for more details. */
51 /* */
52 /* You should have received a copy of the GNU General Public License */
53 /* along with this program; if not, write to the Free Software */
54 /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
55 /* */
56 /*****************************************************************************/
57 
58 /* First let's include the header file needed */
59 
60 #include <cfpython.h>
61 #include <stdarg.h>
62 #include <node.h>
63 #include <svnversion.h>
64 
65 CF_PLUGIN char SvnRevPlugin[] = SVN_REV;
66 
67 #define PYTHON_DEBUG /* give us some general infos out */
68 #define PYTHON_CACHE_SIZE 16 /* number of python scripts to store the bytecode of at a time */
69 
73 typedef struct {
75  PyCodeObject *code;
76  time_t cached_time,
77  used_time;
79 
80 /* This structure is used to define one python-implemented crossfire command.*/
81 typedef struct PythonCmdStruct {
82  sstring name; /* The name of the command, as known in the game. */
83  sstring script; /* The name of the script file to bind. */
84  double speed; /* The speed of the command execution. */
85 } PythonCmd;
86 
87 /* This plugin allows up to 1024 custom commands. */
88 #define NR_CUSTOM_CMD 1024
89 
92 
95 
96 static PyObject *CFPythonError;
97 
99 static void set_exception(const char *fmt, ...) {
100  char buf[1024];
101  va_list arg;
102 
103  va_start(arg, fmt);
104  vsnprintf(buf, sizeof(buf), fmt, arg);
105  va_end(arg);
106 
107  PyErr_SetString(PyExc_ValueError, buf);
108 }
109 
111 
113 
114 static int current_command = -999;
115 
116 static PyObject *shared_data = NULL;
117 
118 static PyObject *private_data = NULL;
119 
120 static PyObject *registerGEvent(PyObject *self, PyObject *args) {
121  int eventcode;
122 
123  if (!PyArg_ParseTuple(args, "i", &eventcode))
124  return NULL;
125 
127 
128  Py_INCREF(Py_None);
129  return Py_None;
130 }
131 
132 static PyObject *unregisterGEvent(PyObject *self, PyObject *args) {
133  int eventcode;
134 
135  if (!PyArg_ParseTuple(args, "i", &eventcode))
136  return NULL;
137 
139 
140  Py_INCREF(Py_None);
141  return Py_None;
142 }
143 
144 static PyObject *createCFObject(PyObject *self, PyObject *args) {
145  object *op;
146 
147  op = cf_create_object();
148 
149  return Crossfire_Object_wrap(op);
150 }
151 
152 static PyObject *createCFObjectByName(PyObject *self, PyObject *args) {
153  char *obname;
154  object *op;
155 
156  if (!PyArg_ParseTuple(args, "s", &obname))
157  return NULL;
158 
159  op = cf_create_object_by_name(obname);
160 
161  return Crossfire_Object_wrap(op);
162 }
163 
164 static PyObject *getCFPythonVersion(PyObject *self, PyObject *args) {
165  int i = 2044;
166 
167  return Py_BuildValue("i", i);
168 }
169 
170 static PyObject *getReturnValue(PyObject *self, PyObject *args) {
171  return Py_BuildValue("i", current_context->returnvalue);
172 }
173 
174 static PyObject *setReturnValue(PyObject *self, PyObject *args) {
175  int i;
176 
177  if (!PyArg_ParseTuple(args, "i", &i))
178  return NULL;
179  current_context->returnvalue = i;
180  Py_INCREF(Py_None);
181  return Py_None;
182 }
183 
184 static PyObject *matchString(PyObject *self, PyObject *args) {
185  char *premiere;
186  char *seconde;
187  const char *result;
188 
189  if (!PyArg_ParseTuple(args, "ss", &premiere, &seconde))
190  return NULL;
191 
192  result = cf_re_cmp(premiere, seconde);
193  if (result != NULL)
194  return Py_BuildValue("i", 1);
195  else
196  return Py_BuildValue("i", 0);
197 }
198 
199 static PyObject *findPlayer(PyObject *self, PyObject *args) {
200  player *foundpl;
201  char *txt;
202 
203  if (!PyArg_ParseTuple(args, "s", &txt))
204  return NULL;
205 
206  foundpl = cf_player_find(txt);
207 
208  if (foundpl != NULL)
209  return Py_BuildValue("O", Crossfire_Object_wrap(foundpl->ob));
210  else {
211  Py_INCREF(Py_None);
212  return Py_None;
213  }
214 }
215 
216 static PyObject *readyMap(PyObject *self, PyObject *args) {
217  char *mapname;
218  mapstruct *map;
219  int flags = 0;
220 
221  if (!PyArg_ParseTuple(args, "s|i", &mapname, &flags))
222  return NULL;
223 
224  map = cf_map_get_map(mapname, flags);
225 
226  return Crossfire_Map_wrap(map);
227 }
228 
229 static PyObject *createMap(PyObject *self, PyObject *args) {
230  int sizex, sizey;
231  mapstruct *map;
232 
233  if (!PyArg_ParseTuple(args, "ii", &sizex, &sizey))
234  return NULL;
235 
236  map = cf_get_empty_map(sizex, sizey);
237 
238  return Crossfire_Map_wrap(map);
239 }
240 
241 static PyObject *getMapDirectory(PyObject *self, PyObject *args) {
242  return Py_BuildValue("s", cf_get_directory(0));
243 }
244 
245 static PyObject *getUniqueDirectory(PyObject *self, PyObject *args) {
246  return Py_BuildValue("s", cf_get_directory(1));
247 }
248 
249 static PyObject *getTempDirectory(PyObject *self, PyObject *args) {
250  return Py_BuildValue("s", cf_get_directory(2));
251 }
252 
253 static PyObject *getConfigDirectory(PyObject *self, PyObject *args) {
254  return Py_BuildValue("s", cf_get_directory(3));
255 }
256 
257 static PyObject *getLocalDirectory(PyObject *self, PyObject *args) {
258  return Py_BuildValue("s", cf_get_directory(4));
259 }
260 
261 static PyObject *getPlayerDirectory(PyObject *self, PyObject *args) {
262  return Py_BuildValue("s", cf_get_directory(5));
263 }
264 
265 static PyObject *getDataDirectory(PyObject *self, PyObject *args) {
266  return Py_BuildValue("s", cf_get_directory(6));
267 }
268 
269 static PyObject *getWhoAmI(PyObject *self, PyObject *args) {
270  if (!current_context->who) {
271  Py_INCREF(Py_None);
272  return Py_None;
273  }
274  Py_INCREF(current_context->who);
275  return current_context->who;
276 }
277 
278 static PyObject *getWhoIsActivator(PyObject *self, PyObject *args) {
279  if (!current_context->activator) {
280  Py_INCREF(Py_None);
281  return Py_None;
282  }
283  Py_INCREF(current_context->activator);
284  return current_context->activator;
285 }
286 
287 static PyObject *getWhoIsThird(PyObject *self, PyObject *args) {
288  if (!current_context->third) {
289  Py_INCREF(Py_None);
290  return Py_None;
291  }
292  Py_INCREF(current_context->third);
293  return current_context->third;
294 }
295 
296 static PyObject *getWhatIsMessage(PyObject *self, PyObject *args) {
297  if (*current_context->message == '\0')
298  return Py_BuildValue("");
299  else
300  return Py_BuildValue("s", current_context->message);
301 }
302 
303 static PyObject *getScriptName(PyObject *self, PyObject *args) {
304  return Py_BuildValue("s", current_context->script);
305 }
306 
307 static PyObject *getScriptParameters(PyObject *self, PyObject *args) {
308  if (!*current_context->options) {
309  Py_INCREF(Py_None);
310  return Py_None;
311  }
312  return Py_BuildValue("s", current_context->options);
313 }
314 
315 static PyObject *getEvent(PyObject *self, PyObject *args) {
316  if (!current_context->event) {
317  Py_INCREF(Py_None);
318  return Py_None;
319  }
320  Py_INCREF(current_context->event);
321  return current_context->event;
322 }
323 
324 static PyObject *getPrivateDictionary(PyObject *self, PyObject *args) {
325  PyObject *data;
326 
327  data = PyDict_GetItemString(private_data, current_context->script);
328  if (!data) {
329  data = PyDict_New();
330  PyDict_SetItemString(private_data, current_context->script, data);
331  Py_DECREF(data);
332  }
333  Py_INCREF(data);
334  return data;
335 }
336 
337 static PyObject *getSharedDictionary(PyObject *self, PyObject *args) {
338  Py_INCREF(shared_data);
339  return shared_data;
340 }
341 
342 static PyObject *getArchetypes(PyObject *self, PyObject *args) {
343  PyObject *list;
344  archetype *arch;
345 
346  list = PyList_New(0);
347  arch = cf_archetype_get_first();
348  while (arch) {
349  PyList_Append(list, Crossfire_Archetype_wrap(arch));
350  arch = cf_archetype_get_next(arch);
351  }
352  return list;
353 }
354 
355 static PyObject *getPlayers(PyObject *self, PyObject *args) {
356  PyObject *list;
357  object *pl;
358 
359  list = PyList_New(0);
361  while (pl) {
362  PyList_Append(list, Crossfire_Object_wrap(pl));
364  }
365  return list;
366 }
367 
368 static PyObject *getMaps(PyObject *self, PyObject *args) {
369  PyObject *list;
370  mapstruct *map;
371 
372  list = PyList_New(0);
373  map = cf_map_get_first();
374  while (map) {
375  PyList_Append(list, Crossfire_Map_wrap(map));
377  }
378  return list;
379 }
380 
381 static PyObject *getParties(PyObject *self, PyObject *args) {
382  PyObject *list;
383  partylist *party;
384 
385  list = PyList_New(0);
386  party = cf_party_get_first();
387  while (party) {
388  PyList_Append(list, Crossfire_Party_wrap(party));
389  party = cf_party_get_next(party);
390  }
391  return list;
392 }
393 
394 static PyObject *getRegions(PyObject *self, PyObject *args) {
395  PyObject *list;
396  region *reg;
397 
398  list = PyList_New(0);
399  reg = cf_region_get_first();
400  while (reg) {
401  PyList_Append(list, Crossfire_Region_wrap(reg));
402  reg = cf_region_get_next(reg);
403  }
404  return list;
405 }
406 
407 static PyObject *getFriendlyList(PyObject *self, PyObject *args) {
408  PyObject *list;
409  object *ob;
410 
411  list = PyList_New(0);
413  while (ob) {
414  PyList_Append(list, Crossfire_Object_wrap(ob));
415  ob = cf_friendlylist_get_next(ob);
416  }
417  return list;
418 }
419 
420 static PyObject *registerCommand(PyObject *self, PyObject *args) {
421  char *cmdname;
422  char *scriptname;
423  double cmdspeed;
424  int i;
425 
426  if (!PyArg_ParseTuple(args, "ssd", &cmdname, &scriptname, &cmdspeed))
427  return NULL;
428 
429  if (cmdspeed < 0) {
430  set_exception("speed must not be negative");
431  return NULL;
432  }
433 
434  for (i = 0; i < NR_CUSTOM_CMD; i++) {
435  if (CustomCommand[i].name != NULL) {
436  if (!strcmp(CustomCommand[i].name, cmdname)) {
437  set_exception("command '%s' is already registered", cmdname);
438  return NULL;
439  }
440  }
441  }
442  for (i = 0; i < NR_CUSTOM_CMD; i++) {
443  if (CustomCommand[i].name == NULL) {
444  CustomCommand[i].name = cf_add_string(cmdname);
445  CustomCommand[i].script = cf_add_string(scriptname);
446  CustomCommand[i].speed = cmdspeed;
447  break;
448  }
449  }
450 
451  Py_INCREF(Py_None);
452  return Py_None;
453 }
454 
455 static PyObject *getTime(PyObject *self, PyObject *args) {
456  PyObject *list;
457  timeofday_t tod;
458 
459  cf_get_time(&tod);
460 
461  list = PyList_New(0);
462  PyList_Append(list, Py_BuildValue("i", tod.year));
463  PyList_Append(list, Py_BuildValue("i", tod.month));
464  PyList_Append(list, Py_BuildValue("i", tod.day));
465  PyList_Append(list, Py_BuildValue("i", tod.hour));
466  PyList_Append(list, Py_BuildValue("i", tod.minute));
467  PyList_Append(list, Py_BuildValue("i", tod.dayofweek));
468  PyList_Append(list, Py_BuildValue("i", tod.weekofmonth));
469  PyList_Append(list, Py_BuildValue("i", tod.season));
470  PyList_Append(list, Py_BuildValue("i", tod.periodofday));
471 
472  return list;
473 }
474 
475 static PyObject *destroyTimer(PyObject *self, PyObject *args) {
476  int id;
477 
478  if (!PyArg_ParseTuple(args, "i", &id))
479  return NULL;
480  return Py_BuildValue("i", cf_timer_destroy(id));
481 }
482 
483 static PyObject *getMapHasBeenLoaded(PyObject *self, PyObject *args) {
484  char *name;
485 
486  if (!PyArg_ParseTuple(args, "s", &name))
487  return NULL;
489 }
490 
491 static PyObject *findFace(PyObject *self, PyObject *args) {
492  char *name;
493 
494  if (!PyArg_ParseTuple(args, "s", &name))
495  return NULL;
496  return Py_BuildValue("i", cf_find_face(name, 0));
497 }
498 
499 static PyObject *log_message(PyObject *self, PyObject *args) {
500  LogLevel level;
501  int intLevel;
502  char *message;
503 
504  if (!PyArg_ParseTuple(args, "is", &intLevel, &message))
505  return NULL;
506 
507  switch (intLevel) {
508  case llevError:
509  level = llevError;
510  break;
511 
512  case llevInfo:
513  level = llevInfo;
514  break;
515 
516  case llevDebug:
517  level = llevDebug;
518  break;
519 
520  case llevMonster:
521  level = llevMonster;
522  break;
523 
524  default:
525  return NULL;
526  }
527  if ((message != NULL) && (message[strlen(message)] == '\n'))
528  cf_log(level, "CFPython: %s", message);
529  else
530  cf_log(level, "CFPython: %s\n", message);
531  Py_INCREF(Py_None);
532  return Py_None;
533 }
534 
535 static PyObject *findAnimation(PyObject *self, PyObject *args) {
536  char *name;
537 
538  if (!PyArg_ParseTuple(args, "s", &name))
539  return NULL;
540  return Py_BuildValue("i", cf_find_animation(name));
541 }
542 
543 static PyObject *getSeasonName(PyObject *self, PyObject *args) {
544  int i;
545 
546  if (!PyArg_ParseTuple(args, "i", &i))
547  return NULL;
548  return Py_BuildValue("s", cf_get_season_name(i));
549 }
550 
551 static PyObject *getMonthName(PyObject *self, PyObject *args) {
552  int i;
553 
554  if (!PyArg_ParseTuple(args, "i", &i))
555  return NULL;
556  return Py_BuildValue("s", cf_get_month_name(i));
557 }
558 
559 static PyObject *getWeekdayName(PyObject *self, PyObject *args) {
560  int i;
561 
562  if (!PyArg_ParseTuple(args, "i", &i))
563  return NULL;
564  return Py_BuildValue("s", cf_get_weekday_name(i));
565 }
566 
567 static PyObject *getPeriodofdayName(PyObject *self, PyObject *args) {
568  int i;
569 
570  if (!PyArg_ParseTuple(args, "i", &i))
571  return NULL;
572  return Py_BuildValue("s", cf_get_periodofday_name(i));
573 }
574 
575 static PyObject *addReply(PyObject *self, PyObject *args) {
576  char *word, *reply;
577  talk_info *talk;
578 
579  if (current_context->talk == NULL) {
580  set_exception("not in a dialog context");
581  return NULL;
582  }
583  talk = current_context->talk;
584 
585  if (!PyArg_ParseTuple(args, "ss", &word, &reply)) {
586  return NULL;
587  }
588 
589  if (talk->replies_count == MAX_REPLIES) {
590  set_exception("too many replies");
591  return NULL;
592  }
593 
594  talk->replies_words[talk->replies_count] = cf_add_string(word);
595  talk->replies[talk->replies_count] = cf_add_string(reply);
596  talk->replies_count++;
597  Py_INCREF(Py_None);
598  return Py_None;
599 
600 }
601 
602 static PyObject *setPlayerMessage(PyObject *self, PyObject *args) {
603  char *message;
604  int type = rt_reply;
605 
606  if (current_context->talk == NULL) {
607  set_exception("not in a dialog context");
608  return NULL;
609  }
610 
611  if (!PyArg_ParseTuple(args, "s|i", &message, &type)) {
612  return NULL;
613  }
614 
615  if (current_context->talk->message != NULL)
616  cf_free_string(current_context->talk->message);
617  current_context->talk->message = cf_add_string(message);
618  current_context->talk->message_type = type;
619 
620  Py_INCREF(Py_None);
621  return Py_None;
622 }
623 
624 static PyObject *npcSay(PyObject *self, PyObject *args) {
625  Crossfire_Object *npc = NULL;
626  char *message, buf[2048];
627 
628  if (!PyArg_ParseTuple(args, "O!s", &Crossfire_ObjectType, &npc, &message))
629  return NULL;
630 
631  if (current_context->talk == NULL) {
632  set_exception("not in a dialog context");
633  return NULL;
634  }
635 
636  if (current_context->talk->npc_msg_count == MAX_NPC) {
637  set_exception("too many NPCs");
638  return NULL;
639  }
640 
641  if (strlen(message) >= sizeof(buf) - 1)
642  cf_log(llevError, "warning, too long message in npcSay, will be truncated");
644  snprintf(buf, sizeof(buf), "%s says: %s", npc->obj->name, message);
645 
646  current_context->talk->npc_msgs[current_context->talk->npc_msg_count] = cf_add_string(buf);
647  current_context->talk->npc_msg_count++;
648 
649  Py_INCREF(Py_None);
650  return Py_None;
651 }
652 
653 static PyObject *costStringFromValue(PyObject *self, PyObject *args) {
654  uint64_t value;
655  char buf[2048];
656  int largest_coin = 0;
657 
658  if (!PyArg_ParseTuple(args, "L|i", &value, &largest_coin))
659  return NULL;
660 
661  cf_cost_string_from_value(value, largest_coin, buf, sizeof(buf));
662  return Py_BuildValue("s", buf);
663 }
664 
665 static PyMethodDef CFPythonMethods[] = {
666  { "WhoAmI", getWhoAmI, METH_NOARGS, NULL },
667  { "WhoIsActivator", getWhoIsActivator, METH_NOARGS, NULL },
668  { "WhoIsOther", getWhoIsThird, METH_NOARGS, NULL },
669  { "WhatIsMessage", getWhatIsMessage, METH_NOARGS, NULL },
670  { "ScriptName", getScriptName, METH_NOARGS, NULL },
671  { "ScriptParameters", getScriptParameters, METH_NOARGS, NULL },
672  { "WhatIsEvent", getEvent, METH_NOARGS, NULL },
673  { "MapDirectory", getMapDirectory, METH_NOARGS, NULL },
674  { "UniqueDirectory", getUniqueDirectory, METH_NOARGS, NULL },
675  { "TempDirectory", getTempDirectory, METH_NOARGS, NULL },
676  { "ConfigDirectory", getConfigDirectory, METH_NOARGS, NULL },
677  { "LocalDirectory", getLocalDirectory, METH_NOARGS, NULL },
678  { "PlayerDirectory", getPlayerDirectory, METH_NOARGS, NULL },
679  { "DataDirectory", getDataDirectory, METH_NOARGS, NULL },
680  { "ReadyMap", readyMap, METH_VARARGS, NULL },
681  { "CreateMap", createMap, METH_VARARGS, NULL },
682  { "FindPlayer", findPlayer, METH_VARARGS, NULL },
683  { "MatchString", matchString, METH_VARARGS, NULL },
684  { "GetReturnValue", getReturnValue, METH_NOARGS, NULL },
685  { "SetReturnValue", setReturnValue, METH_VARARGS, NULL },
686  { "PluginVersion", getCFPythonVersion, METH_NOARGS, NULL },
687  { "CreateObject", createCFObject, METH_NOARGS, NULL },
688  { "CreateObjectByName", createCFObjectByName, METH_VARARGS, NULL },
689  { "GetPrivateDictionary", getPrivateDictionary, METH_NOARGS, NULL },
690  { "GetSharedDictionary", getSharedDictionary, METH_NOARGS, NULL },
691  { "GetPlayers", getPlayers, METH_NOARGS, NULL },
692  { "GetArchetypes", getArchetypes, METH_NOARGS, NULL },
693  { "GetMaps", getMaps, METH_NOARGS, NULL },
694  { "GetParties", getParties, METH_NOARGS, NULL },
695  { "GetRegions", getRegions, METH_NOARGS, NULL },
696  { "GetFriendlyList", getFriendlyList, METH_NOARGS, NULL },
697  { "RegisterCommand", registerCommand, METH_VARARGS, NULL },
698  { "RegisterGlobalEvent", registerGEvent, METH_VARARGS, NULL },
699  { "UnregisterGlobalEvent", unregisterGEvent, METH_VARARGS, NULL },
700  { "GetTime", getTime, METH_NOARGS, NULL },
701  { "DestroyTimer", destroyTimer, METH_VARARGS, NULL },
702  { "MapHasBeenLoaded", getMapHasBeenLoaded, METH_VARARGS, NULL },
703  { "Log", log_message, METH_VARARGS, NULL },
704  { "FindFace", findFace, METH_VARARGS, NULL },
705  { "FindAnimation", findAnimation, METH_VARARGS, NULL },
706  { "GetSeasonName", getSeasonName, METH_VARARGS, NULL },
707  { "GetMonthName", getMonthName, METH_VARARGS, NULL },
708  { "GetWeekdayName", getWeekdayName, METH_VARARGS, NULL },
709  { "GetPeriodofdayName", getPeriodofdayName, METH_VARARGS, NULL },
710  { "AddReply", addReply, METH_VARARGS, NULL },
711  { "SetPlayerMessage", setPlayerMessage, METH_VARARGS, NULL },
712  { "NPCSay", npcSay, METH_VARARGS, NULL },
713  { "CostStringFromValue", costStringFromValue, METH_VARARGS, NULL },
714  { NULL, NULL, 0, NULL }
715 };
716 
717 static void initContextStack(void) {
718  current_context = NULL;
719  context_stack = NULL;
720 }
721 
722 static void pushContext(CFPContext *context) {
723  if (current_context == NULL) {
724  context_stack = context;
725  context->down = NULL;
726  } else {
727  context->down = current_context;
728  }
729  current_context = context;
730 }
731 
732 static CFPContext *popContext(void) {
733  CFPContext *oldcontext;
734 
735  if (current_context != NULL) {
736  oldcontext = current_context;
737  current_context = current_context->down;
738  return oldcontext;
739  }
740  else
741  return NULL;
742 }
743 
744 static void freeContext(CFPContext *context) {
745  Py_XDECREF(context->event);
746  Py_XDECREF(context->third);
747  Py_XDECREF(context->who);
748  Py_XDECREF(context->activator);
749  free(context);
750 }
751 
755 static PyObject* cfpython_openpyfile(char *filename) {
756  PyObject *scriptfile;
757 #ifdef IS_PY3K
758  {
759  int fd;
760  fd = open(filename, O_RDONLY);
761  if (fd == -1)
762  return NULL;
763  scriptfile = PyFile_FromFd(fd, filename, "r", -1, NULL, NULL, NULL, 1);
764  }
765 #else
766  if (!(scriptfile = PyFile_FromString(filename, "r"))) {
767  return NULL;
768  }
769 #endif
770  return scriptfile;
771 }
772 
777 static FILE* cfpython_pyfile_asfile(PyObject* obj) {
778 #ifdef IS_PY3K
779  return fdopen(PyObject_AsFileDescriptor(obj), "r");
780 #else
781  return PyFile_AsFile(obj);
782 #endif
783 }
784 
789 static PyObject *catcher = NULL;
790 
797 static void log_python_error(void) {
798 
799  PyErr_Print();
800 
801  if (catcher != NULL) {
802  PyObject *output = PyObject_GetAttrString(catcher, "value"); //get the stdout and stderr from our catchOutErr object
803  PyObject* empty = PyString_FromString("");
804 
805  cf_log_plain(llevError, PyString_AsString(output));
806  Py_DECREF(output);
807 
808  PyObject_SetAttrString(catcher, "value", empty);
809  Py_DECREF(empty);
810  }
811 
812  return;
813 }
814 
815 
817 static PyCodeObject *compilePython(char *filename) {
818  PyObject *scriptfile = NULL;
819  sstring sh_path;
820  struct stat stat_buf;
821  struct _node *n;
822  int i;
823  pycode_cache_entry *replace = NULL, *run = NULL;
824 
825  if (stat(filename, &stat_buf)) {
826  cf_log(llevDebug, "cfpython - The Script file %s can't be stat:ed\n", filename);
827  return NULL;
828  }
829 
830  sh_path = cf_add_string(filename);
831 
832  /* Search through cache. Three cases:
833  * 1) script in cache, but older than file -> replace cached
834  * 2) script in cache and up to date -> use cached
835  * 3) script not in cache, cache not full -> add to end of cache
836  * 4) script not in cache, cache full -> replace least recently used
837  */
838  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
839  if (pycode_cache[i].file == NULL) { /* script not in cache, cache not full */
840  replace = &pycode_cache[i]; /* add to end of cache */
841  break;
842  } else if (pycode_cache[i].file == sh_path) {
843  /* script in cache */
844  if (pycode_cache[i].code == NULL || (pycode_cache[i].cached_time < stat_buf.st_mtime)) {
845  /* cache older than file, replace cached */
846  replace = &pycode_cache[i];
847  } else {
848  /* cache uptodate, use cached*/
849  replace = NULL;
850  run = &pycode_cache[i];
851  }
852  break;
853  } else if (replace == NULL || pycode_cache[i].used_time < replace->used_time)
854  /* if we haven't found it yet, set replace to the oldest cache */
855  replace = &pycode_cache[i];
856  }
857 
858  /* replace a specific cache index with the file */
859  if (replace) {
860  Py_XDECREF(replace->code); /* safe to call on NULL */
861  replace->code = NULL;
862 
863  /* Need to replace path string? */
864  if (replace->file != sh_path) {
865  if (replace->file) {
866  cf_free_string(replace->file);
867  }
868  replace->file = cf_add_string(sh_path);
869  }
870 
871  /* Load, parse and compile. Note: because Pyhon may have been built with a
872  * different library than Crossfire, the FILE* it uses may be incompatible.
873  * Therefore we use PyFile to open the file, then convert to FILE* and get
874  * Python's own structure. Messy, but can't be helped... */
875  if (!(scriptfile = cfpython_openpyfile(filename))) {
876  cf_log(llevDebug, "cfpython - The Script file %s can't be opened\n", filename);
877  cf_free_string(sh_path);
878  return NULL;
879  } else {
880  /* Note: FILE* being opaque, it works, but the actual structure may be different! */
881  FILE* pyfile = cfpython_pyfile_asfile(scriptfile);
882  if ((n = PyParser_SimpleParseFile(pyfile, filename, Py_file_input))) {
883  replace->code = PyNode_Compile(n, filename);
884  PyNode_Free(n);
885  }
886 
887  if (PyErr_Occurred())
889  else
890  replace->cached_time = stat_buf.st_mtime;
891  run = replace;
892  }
893  }
894 
895  cf_free_string(sh_path);
896 
897  if (scriptfile) {
898  Py_DECREF(scriptfile);
899  }
900 
901  assert(run != NULL);
902  run->used_time = time(NULL);
903  return run->code;
904 }
905 
906 static int do_script(CFPContext *context, int silent) {
907  PyCodeObject *pycode;
908  PyObject *dict;
909  PyObject *ret;
910 #if 0
911  PyObject *list;
912  int item;
913 #endif
914 
915  pycode = compilePython(context->script);
916  if (pycode) {
917  pushContext(context);
918  dict = PyDict_New();
919  PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins());
920  ret = PyEval_EvalCode(pycode, dict, NULL);
921  if (PyErr_Occurred()) {
923  }
924  Py_XDECREF(ret);
925 #if 0
926  printf("cfpython - %d items in heap\n", PyDict_Size(dict));
927  list = PyDict_Values(dict);
928  for (item = PyList_Size(list)-1; item >= 0; item--) {
929  dict = PyList_GET_ITEM(list, item);
930  ret = PyObject_Str(dict);
931  printf(" ref %s = %d\n", PyString_AsString(ret), dict->ob_refcnt);
932  Py_XDECREF(ret);
933  }
934  Py_DECREF(list);
935 #endif
936  Py_DECREF(dict);
937  return 1;
938  } else
939  return 0;
940 }
941 
942 typedef struct {
943  const char *name;
944  const int value;
945 } CFConstant;
946 
947 static void addConstants(PyObject *module, const char *name, const CFConstant *constants) {
948  int i = 0;
949  char tmp[1024];
950  PyObject *new;
951  PyObject *dict;
952 
953  snprintf(tmp, sizeof(tmp), "Crossfire_%s", name);
954 
955  new = PyModule_New(tmp);
956  dict = PyDict_New();
957 
958  while (constants[i].name != NULL) {
959  PyModule_AddIntConstant(new, (char *)constants[i].name, constants[i].value);
960 #ifdef IS_PY3K
961  PyDict_SetItem(dict, PyLong_FromLong(constants[i].value), PyUnicode_FromString(constants[i].name));
962 #else
963  PyDict_SetItem(dict, PyLong_FromLong(constants[i].value), PyString_FromString(constants[i].name));
964 #endif
965  i++;
966  }
967  PyDict_SetItemString(PyModule_GetDict(module), name, new);
968 
969  snprintf(tmp, sizeof(tmp), "%sName", name);
970  PyDict_SetItemString(PyModule_GetDict(module), tmp, dict);
971  Py_DECREF(dict);
972 }
979 static void addSimpleConstants(PyObject *module, const char *name, const CFConstant *constants) {
980  int i = 0;
981  char tmp[1024];
982  PyObject *new;
983 
984  snprintf(tmp, sizeof(tmp), "Crossfire_%s", name);
985 
986  new = PyModule_New(tmp);
987 
988  while (constants[i].name != NULL) {
989  PyModule_AddIntConstant(new, (char *)constants[i].name, constants[i].value);
990  i++;
991  }
992  PyDict_SetItemString(PyModule_GetDict(module), name, new);
993 }
994 
995 static void initConstants(PyObject *module) {
996  static const CFConstant cstDirection[] = {
997  { "NORTH", 1 },
998  { "NORTHEAST", 2 },
999  { "EAST", 3 },
1000  { "SOUTHEAST", 4 },
1001  { "SOUTH", 5 },
1002  { "SOUTHWEST", 6 },
1003  { "WEST", 7 },
1004  { "NORTHWEST", 8 },
1005  { NULL, 0 }
1006  };
1007 
1008  static const CFConstant cstType[] = {
1009  { "PLAYER", PLAYER },
1010  { "TRANSPORT", TRANSPORT },
1011  { "ROD", ROD },
1012  { "TREASURE", TREASURE },
1013  { "POTION", POTION },
1014  { "FOOD", FOOD },
1015  { "POISON", POISON },
1016  { "BOOK", BOOK },
1017  { "CLOCK", CLOCK },
1018  { "ARROW", ARROW },
1019  { "BOW", BOW },
1020  { "WEAPON", WEAPON },
1021  { "ARMOUR", ARMOUR },
1022  { "PEDESTAL", PEDESTAL },
1023  { "ALTAR", ALTAR },
1024  { "LOCKED_DOOR", LOCKED_DOOR },
1025  { "SPECIAL_KEY", SPECIAL_KEY },
1026  { "MAP", MAP },
1027  { "DOOR", DOOR },
1028  { "KEY", KEY },
1029  { "TIMED_GATE", TIMED_GATE },
1030  { "TRIGGER", TRIGGER },
1031  { "GRIMREAPER", GRIMREAPER },
1032  { "MAGIC_EAR", MAGIC_EAR },
1033  { "TRIGGER_BUTTON", TRIGGER_BUTTON },
1034  { "TRIGGER_ALTAR", TRIGGER_ALTAR },
1035  { "TRIGGER_PEDESTAL", TRIGGER_PEDESTAL },
1036  { "SHIELD", SHIELD },
1037  { "HELMET", HELMET },
1038  { "MONEY", MONEY },
1039  { "CLASS", CLASS },
1040  { "AMULET", AMULET },
1041  { "PLAYERMOVER", PLAYERMOVER },
1042  { "TELEPORTER", TELEPORTER },
1043  { "CREATOR", CREATOR },
1044  { "SKILL", SKILL },
1045  { "EARTHWALL", EARTHWALL },
1046  { "GOLEM", GOLEM },
1047  { "THROWN_OBJ", THROWN_OBJ },
1048  { "BLINDNESS", BLINDNESS },
1049  { "GOD", GOD },
1050  { "DETECTOR", DETECTOR },
1051  { "TRIGGER_MARKER", TRIGGER_MARKER },
1052  { "DEAD_OBJECT", DEAD_OBJECT },
1053  { "DRINK", DRINK },
1054  { "MARKER", MARKER },
1055  { "HOLY_ALTAR", HOLY_ALTAR },
1056  { "PLAYER_CHANGER", PLAYER_CHANGER },
1057  { "BATTLEGROUND", BATTLEGROUND },
1058  { "PEACEMAKER", PEACEMAKER },
1059  { "GEM", GEM },
1060  { "FIREWALL", FIREWALL },
1061  { "CHECK_INV", CHECK_INV },
1062  { "MOOD_FLOOR", MOOD_FLOOR },
1063  { "EXIT", EXIT },
1064  { "ENCOUNTER", ENCOUNTER },
1065  { "SHOP_FLOOR", SHOP_FLOOR },
1066  { "SHOP_MAT", SHOP_MAT },
1067  { "RING", RING },
1068  { "FLOOR", FLOOR },
1069  { "FLESH", FLESH },
1070  { "INORGANIC", INORGANIC },
1071  { "SKILL_TOOL", SKILL_TOOL },
1072  { "LIGHTER", LIGHTER },
1073  { "WALL", WALL },
1074  { "MISC_OBJECT", MISC_OBJECT },
1075  { "MONSTER", MONSTER },
1076  { "LAMP", LAMP },
1077  { "DUPLICATOR", DUPLICATOR },
1078  { "SPELLBOOK", SPELLBOOK },
1079  { "CLOAK", CLOAK },
1080  { "SPINNER", SPINNER },
1081  { "GATE", GATE },
1082  { "BUTTON", BUTTON },
1083  { "CF_HANDLE", CF_HANDLE },
1084  { "HOLE", HOLE },
1085  { "TRAPDOOR", TRAPDOOR },
1086  { "SIGN", SIGN },
1087  { "BOOTS", BOOTS },
1088  { "GLOVES", GLOVES },
1089  { "SPELL", SPELL },
1090  { "SPELL_EFFECT", SPELL_EFFECT },
1091  { "CONVERTER", CONVERTER },
1092  { "BRACERS", BRACERS },
1093  { "POISONING", POISONING },
1094  { "SAVEBED", SAVEBED },
1095  { "WAND", WAND },
1096  { "SCROLL", SCROLL },
1097  { "DIRECTOR", DIRECTOR },
1098  { "GIRDLE", GIRDLE },
1099  { "FORCE", FORCE },
1100  { "POTION_RESIST_EFFECT", POTION_RESIST_EFFECT },
1101  { "EVENT_CONNECTOR", EVENT_CONNECTOR },
1102  { "CLOSE_CON", CLOSE_CON },
1103  { "CONTAINER", CONTAINER },
1104  { "ARMOUR_IMPROVER", ARMOUR_IMPROVER },
1105  { "WEAPON_IMPROVER", WEAPON_IMPROVER },
1106  { "SKILLSCROLL", SKILLSCROLL },
1107  { "DEEP_SWAMP", DEEP_SWAMP },
1108  { "IDENTIFY_ALTAR", IDENTIFY_ALTAR },
1109  { "SHOP_INVENTORY", SHOP_INVENTORY },
1110  { "RUNE", RUNE },
1111  { "TRAP", TRAP },
1112  { "POWER_CRYSTAL", POWER_CRYSTAL },
1113  { "CORPSE", CORPSE },
1114  { "DISEASE", DISEASE },
1115  { "SYMPTOM", SYMPTOM },
1116  { "BUILDER", BUILDER },
1117  { "MATERIAL", MATERIAL },
1118  { NULL, 0 }
1119  };
1120 
1121  static const CFConstant cstMove[] = {
1122  { "WALK", MOVE_WALK },
1123  { "FLY_LOW", MOVE_FLY_LOW },
1124  { "FLY_HIGH", MOVE_FLY_HIGH },
1125  { "FLYING", MOVE_FLYING },
1126  { "SWIM", MOVE_SWIM },
1127  { "BOAT", MOVE_BOAT },
1128  { "ALL", MOVE_ALL },
1129  { NULL, 0 }
1130  };
1131 
1132  static const CFConstant cstMessageFlag[] = {
1133  { "NDI_BLACK", NDI_BLACK },
1134  { "NDI_WHITE", NDI_WHITE },
1135  { "NDI_NAVY", NDI_NAVY },
1136  { "NDI_RED", NDI_RED },
1137  { "NDI_ORANGE", NDI_ORANGE },
1138  { "NDI_BLUE", NDI_BLUE },
1139  { "NDI_DK_ORANGE", NDI_DK_ORANGE },
1140  { "NDI_GREEN", NDI_GREEN },
1141  { "NDI_LT_GREEN", NDI_LT_GREEN },
1142  { "NDI_GREY", NDI_GREY },
1143  { "NDI_BROWN", NDI_BROWN },
1144  { "NDI_GOLD", NDI_GOLD },
1145  { "NDI_TAN", NDI_TAN },
1146  { "NDI_UNIQUE", NDI_UNIQUE },
1147  { "NDI_ALL", NDI_ALL },
1148  { "NDI_ALL_DMS", NDI_ALL_DMS },
1149  { NULL, 0 }
1150  };
1151 
1152  static const CFConstant cstAttackType[] = {
1153  { "PHYSICAL", AT_PHYSICAL },
1154  { "MAGIC", AT_MAGIC },
1155  { "FIRE", AT_FIRE },
1156  { "ELECTRICITY", AT_ELECTRICITY },
1157  { "COLD", AT_COLD },
1158  { "CONFUSION", AT_CONFUSION },
1159  { "ACID", AT_ACID },
1160  { "DRAIN", AT_DRAIN },
1161  { "WEAPONMAGIC", AT_WEAPONMAGIC },
1162  { "GHOSTHIT", AT_GHOSTHIT },
1163  { "POISON", AT_POISON },
1164  { "SLOW", AT_SLOW },
1165  { "PARALYZE", AT_PARALYZE },
1166  { "TURN_UNDEAD", AT_TURN_UNDEAD },
1167  { "FEAR", AT_FEAR },
1168  { "CANCELLATION", AT_CANCELLATION },
1169  { "DEPLETE", AT_DEPLETE },
1170  { "DEATH", AT_DEATH },
1171  { "CHAOS", AT_CHAOS },
1172  { "COUNTERSPELL", AT_COUNTERSPELL },
1173  { "GODPOWER", AT_GODPOWER },
1174  { "HOLYWORD", AT_HOLYWORD },
1175  { "BLIND", AT_BLIND },
1176  { "INTERNAL", AT_INTERNAL },
1177  { "LIFE_STEALING", AT_LIFE_STEALING },
1178  { "DISEASE", AT_DISEASE },
1179  { NULL, 0 }
1180  };
1181 
1182  static const CFConstant cstAttackTypeNumber[] = {
1183  { "PHYSICAL", ATNR_PHYSICAL },
1184  { "MAGIC", ATNR_MAGIC },
1185  { "FIRE", ATNR_FIRE },
1186  { "ELECTRICITY", ATNR_ELECTRICITY },
1187  { "COLD", ATNR_COLD },
1188  { "CONFUSION", ATNR_CONFUSION },
1189  { "ACID", ATNR_ACID },
1190  { "DRAIN", ATNR_DRAIN },
1191  { "WEAPONMAGIC", ATNR_WEAPONMAGIC },
1192  { "GHOSTHIT", ATNR_GHOSTHIT },
1193  { "POISON", ATNR_POISON },
1194  { "SLOW", ATNR_SLOW },
1195  { "PARALYZE", ATNR_PARALYZE },
1196  { "TURN_UNDEAD", ATNR_TURN_UNDEAD },
1197  { "FEAR", ATNR_FEAR },
1198  { "CANCELLATION", ATNR_CANCELLATION },
1199  { "DEPLETE", ATNR_DEPLETE },
1200  { "DEATH", ATNR_DEATH },
1201  { "CHAOS", ATNR_CHAOS },
1202  { "COUNTERSPELL", ATNR_COUNTERSPELL },
1203  { "GODPOWER", ATNR_GODPOWER },
1204  { "HOLYWORD", ATNR_HOLYWORD },
1205  { "BLIND", ATNR_BLIND },
1206  { "INTERNAL", ATNR_INTERNAL },
1207  { "LIFE_STEALING", ATNR_LIFE_STEALING },
1208  { "DISEASE", ATNR_DISEASE },
1209  { NULL, 0 }
1210  };
1211 
1212  static const CFConstant cstEventType[] = {
1213  { "APPLY", EVENT_APPLY },
1214  { "ATTACK", EVENT_ATTACKED },
1215  { "ATTACKS", EVENT_ATTACKS },
1216  { "DEATH", EVENT_DEATH },
1217  { "DROP", EVENT_DROP },
1218  { "PICKUP", EVENT_PICKUP },
1219  { "SAY", EVENT_SAY },
1220  { "STOP", EVENT_STOP },
1221  { "TIME", EVENT_TIME },
1222  { "THROW", EVENT_THROW },
1223  { "TRIGGER", EVENT_TRIGGER },
1224  { "CLOSE", EVENT_CLOSE },
1225  { "TIMER", EVENT_TIMER },
1226  { "DESTROY", EVENT_DESTROY },
1227  { "BORN", EVENT_BORN },
1228  { "CLOCK", EVENT_CLOCK },
1229  { "CRASH", EVENT_CRASH },
1230  { "PLAYER_DEATH", EVENT_PLAYER_DEATH },
1231  { "GKILL", EVENT_GKILL },
1232  { "LOGIN", EVENT_LOGIN },
1233  { "LOGOUT", EVENT_LOGOUT },
1234  { "MAPENTER", EVENT_MAPENTER },
1235  { "MAPLEAVE", EVENT_MAPLEAVE },
1236  { "MAPRESET", EVENT_MAPRESET },
1237  { "REMOVE", EVENT_REMOVE },
1238  { "SHOUT", EVENT_SHOUT },
1239  { "TELL", EVENT_TELL },
1240  { "MUZZLE", EVENT_MUZZLE },
1241  { "KICK", EVENT_KICK },
1242  { "MAPUNLOAD", EVENT_MAPUNLOAD },
1243  { "MAPLOAD", EVENT_MAPLOAD },
1244  { "USER", EVENT_USER },
1245  { NULL, 0 }
1246  };
1247 
1248  static const CFConstant cstTime[] = {
1249  { "HOURS_PER_DAY", HOURS_PER_DAY },
1250  { "DAYS_PER_WEEK", DAYS_PER_WEEK },
1251  { "WEEKS_PER_MONTH", WEEKS_PER_MONTH },
1252  { "MONTHS_PER_YEAR", MONTHS_PER_YEAR },
1253  { "SEASONS_PER_YEAR", SEASONS_PER_YEAR },
1254  { "PERIODS_PER_DAY", PERIODS_PER_DAY },
1255  { NULL, 0 }
1256  };
1257 
1258  static const CFConstant cstReplyTypes[] = {
1259  { "SAY", rt_say },
1260  { "REPLY", rt_reply },
1261  { "QUESTION", rt_question },
1262  { NULL, 0 }
1263  };
1264 
1265  static const CFConstant cstAttackMovement[] = {
1266  { "DISTATT", DISTATT },
1267  { "RUNATT", RUNATT },
1268  { "HITRUN", HITRUN },
1269  { "WAITATT", WAITATT },
1270  { "RUSH", RUSH },
1271  { "ALLRUN", ALLRUN },
1272  { "DISTHIT", DISTHIT },
1273  { "WAIT2", WAIT2 },
1274  { "PETMOVE", PETMOVE },
1275  { "CIRCLE1", CIRCLE1 },
1276  { "CIRCLE2", CIRCLE2 },
1277  { "PACEH", PACEH },
1278  { "PACEH2", PACEH2 },
1279  { "RANDO", RANDO },
1280  { "RANDO2", RANDO2 },
1281  { "PACEV", PACEV },
1282  { "PACEV2", PACEV2 },
1283  { NULL, 0 }
1284  };
1285 
1286  addConstants(module, "Direction", cstDirection);
1287  addConstants(module, "Type", cstType);
1288  addConstants(module, "Move", cstMove);
1289  addConstants(module, "MessageFlag", cstMessageFlag);
1290  addConstants(module, "AttackType", cstAttackType);
1291  addConstants(module, "AttackTypeNumber", cstAttackTypeNumber);
1292  addConstants(module, "EventType", cstEventType);
1293  addSimpleConstants(module, "Time", cstTime);
1294  addSimpleConstants(module, "ReplyType", cstReplyTypes);
1295  addSimpleConstants(module, "AttackMovement", cstAttackMovement);
1296 }
1297 
1298 /*
1299  * Set up the main module and handle misc plugin loading stuff and such.
1300  */
1301 
1306 static void cfpython_init_types(PyObject* m) {
1307  PyObject *d = PyModule_GetDict(m);
1308 
1309  Crossfire_ObjectType.tp_new = PyType_GenericNew;
1310  Crossfire_MapType.tp_new = PyType_GenericNew;
1311  Crossfire_PlayerType.tp_new = PyType_GenericNew;
1312  Crossfire_ArchetypeType.tp_new = PyType_GenericNew;
1313  Crossfire_PartyType.tp_new = PyType_GenericNew;
1314  Crossfire_RegionType.tp_new = PyType_GenericNew;
1315  PyType_Ready(&Crossfire_ObjectType);
1316  PyType_Ready(&Crossfire_MapType);
1317  PyType_Ready(&Crossfire_PlayerType);
1318  PyType_Ready(&Crossfire_ArchetypeType);
1319  PyType_Ready(&Crossfire_PartyType);
1320  PyType_Ready(&Crossfire_RegionType);
1321 
1322  Py_INCREF(&Crossfire_ObjectType);
1323  Py_INCREF(&Crossfire_MapType);
1324  Py_INCREF(&Crossfire_PlayerType);
1325  Py_INCREF(&Crossfire_ArchetypeType);
1326  Py_INCREF(&Crossfire_PartyType);
1327  Py_INCREF(&Crossfire_RegionType);
1328 
1329  PyModule_AddObject(m, "Object", (PyObject *)&Crossfire_ObjectType);
1330  PyModule_AddObject(m, "Map", (PyObject *)&Crossfire_MapType);
1331  PyModule_AddObject(m, "Player", (PyObject *)&Crossfire_PlayerType);
1332  PyModule_AddObject(m, "Archetype", (PyObject *)&Crossfire_ArchetypeType);
1333  PyModule_AddObject(m, "Party", (PyObject *)&Crossfire_PartyType);
1334  PyModule_AddObject(m, "Region", (PyObject *)&Crossfire_RegionType);
1335 
1336  PyModule_AddObject(m, "LogError", Py_BuildValue("i", llevError));
1337  PyModule_AddObject(m, "LogInfo", Py_BuildValue("i", llevInfo));
1338  PyModule_AddObject(m, "LogDebug", Py_BuildValue("i", llevDebug));
1339  PyModule_AddObject(m, "LogMonster", Py_BuildValue("i", llevMonster));
1340 
1341  CFPythonError = PyErr_NewException("Crossfire.error", NULL, NULL);
1342  PyDict_SetItemString(d, "error", CFPythonError);
1343 }
1344 
1345 #ifdef IS_PY3K
1346 extern PyObject* PyInit_cjson(void);
1347 #else
1348 extern PyMODINIT_FUNC initcjson(void);
1349 #endif
1350 
1351 #ifdef IS_PY3K
1352 static PyModuleDef CrossfireModule = {
1353  PyModuleDef_HEAD_INIT,
1354  "Crossfire", /* m_name */
1355  NULL, /* m_doc */
1356  -1, /* m_size */
1357  CFPythonMethods, /* m_methods */
1358  NULL, /* m_reload */
1359  NULL, /* m_traverse */
1360  NULL, /* m_clear */
1361  NULL /* m_free */
1362 };
1363 
1364 static PyObject* PyInit_Crossfire(void)
1365 {
1366  PyObject *m = PyModule_Create(&CrossfireModule);
1367  Py_INCREF(m);
1368  return m;
1369 }
1370 #endif
1371 
1372 CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) {
1373  PyObject *m;
1374  int i;
1375  /* Python code to redirect stdouts/stderr. */
1376  const char *stdOutErr =
1377 "import sys\n\
1378 class CatchOutErr:\n\
1379  def __init__(self):\n\
1380  self.value = ''\n\
1381  def write(self, txt):\n\
1382  self.value += txt\n\
1383 catchOutErr = CatchOutErr()\n\
1384 sys.stdout = catchOutErr\n\
1385 sys.stderr = catchOutErr\n\
1386 ";
1387 
1388  cf_init_plugin(gethooksptr);
1389  cf_log(llevDebug, "CFPython 2.0a init\n");
1390 
1393 
1394 #ifdef IS_PY26
1395  Py_Py3kWarningFlag++;
1396 #endif
1397 
1398 #ifdef IS_PY3K
1399  PyImport_AppendInittab("Crossfire", &PyInit_Crossfire);
1400  PyImport_AppendInittab("cjson", &PyInit_cjson);
1401 #endif
1402 
1403  Py_Initialize();
1404 
1405 #ifdef IS_PY3K
1406  m = PyImport_ImportModule("Crossfire");
1407 #else
1408  m = Py_InitModule("Crossfire", CFPythonMethods);
1409 #endif
1410 
1412 
1413  for (i = 0; i < NR_CUSTOM_CMD; i++) {
1414  CustomCommand[i].name = NULL;
1415  CustomCommand[i].script = NULL;
1416  CustomCommand[i].speed = 0.0;
1417  }
1418  initConstants(m);
1419  private_data = PyDict_New();
1420  shared_data = PyDict_New();
1421 
1422  /* Redirect Python's stderr to a special object so it can be put to
1423  * the Crossfire log. */
1424  m = PyImport_AddModule("__main__");
1425  PyRun_SimpleString(stdOutErr);
1426  catcher = PyObject_GetAttrString(m, "catchOutErr");
1427 
1428 #ifndef IS_PY3K
1429  /* add cjson module*/
1430  initcjson();
1431 #endif
1432  return 0;
1433 }
1434 
1435 CF_PLUGIN void *getPluginProperty(int *type, ...) {
1436  va_list args;
1437  const char *propname;
1438  int i, size;
1439  command_array_struct *rtn_cmd;
1440  char *buf;
1441 
1442  va_start(args, type);
1443  propname = va_arg(args, const char *);
1444 
1445  if (!strcmp(propname, "command?")) {
1446  const char *cmdname;
1447  cmdname = va_arg(args, const char *);
1448  rtn_cmd = va_arg(args, command_array_struct *);
1449  va_end(args);
1450 
1451  for (i = 0; i < NR_CUSTOM_CMD; i++) {
1452  if (CustomCommand[i].name != NULL) {
1453  if (!strcmp(CustomCommand[i].name, cmdname)) {
1454  rtn_cmd->name = CustomCommand[i].name;
1455  rtn_cmd->time = (float)CustomCommand[i].speed;
1456  rtn_cmd->func = cfpython_runPluginCommand;
1457  current_command = i;
1458  return rtn_cmd;
1459  }
1460  }
1461  }
1462  return NULL;
1463  } else if (!strcmp(propname, "Identification")) {
1464  buf = va_arg(args, char *);
1465  size = va_arg(args, int);
1466  va_end(args);
1467  snprintf(buf, size, PLUGIN_NAME);
1468  return NULL;
1469  } else if (!strcmp(propname, "FullName")) {
1470  buf = va_arg(args, char *);
1471  size = va_arg(args, int);
1472  va_end(args);
1473  snprintf(buf, size, PLUGIN_VERSION);
1474  return NULL;
1475  }
1476  va_end(args);
1477  return NULL;
1478 }
1479 
1480 CF_PLUGIN void cfpython_runPluginCommand(object *op, const char *params) {
1481  char buf[1024], path[1024];
1482  CFPContext *context;
1483 
1484  if (current_command < 0) {
1485  cf_log(llevError, "Illegal call of cfpython_runPluginCommand, call find_plugin_command first.\n");
1486  return;
1487  }
1488  snprintf(buf, sizeof(buf), "%s.py", cf_get_maps_directory(CustomCommand[current_command].script, path, sizeof(path)));
1489 
1490  context = malloc(sizeof(CFPContext));
1491  context->message[0] = 0;
1492 
1493  context->who = Crossfire_Object_wrap(op);
1494  context->activator = NULL;
1495  context->third = NULL;
1496  context->fix = 0;
1497  snprintf(context->script, sizeof(context->script), "%s", buf);
1498  if (params)
1499  snprintf(context->options, sizeof(context->options), "%s", params);
1500  else
1501  context->options[0] = 0;
1502  context->returnvalue = 1; /* Default is "command successful" */
1503 
1504  current_command = -999;
1505  if (!do_script(context, 0)) {
1506  freeContext(context);
1507  return;
1508  }
1509 
1510  context = popContext();
1511  freeContext(context);
1512 /* printf("Execution complete"); */
1513 }
1514 
1515 static int GECodes[] = {
1516  EVENT_BORN,
1517  EVENT_CLOCK,
1519  EVENT_GKILL,
1520  EVENT_LOGIN,
1521  EVENT_LOGOUT,
1525  EVENT_REMOVE,
1526  EVENT_SHOUT,
1527  EVENT_TELL,
1528  EVENT_MUZZLE,
1529  EVENT_KICK,
1531  EVENT_MAPLOAD,
1532  0
1533 };
1534 
1535 static const char* GEPaths[] = {
1536  "born",
1537  "clock",
1538  "death",
1539  "gkill",
1540  "login",
1541  "logout",
1542  "mapenter",
1543  "mapleave",
1544  "mapreset",
1545  "remove",
1546  "shout",
1547  "tell",
1548  "muzzle",
1549  "kick",
1550  "mapunload",
1551  "mapload",
1552  NULL
1553 };
1554 
1556  PyObject *scriptfile;
1557  char path[1024];
1558  int i;
1559 
1560  cf_log(llevDebug, "CFPython 2.0a post init\n");
1561  initContextStack();
1562  for (i = 0; GECodes[i] != 0; i++)
1564 
1565  scriptfile = cfpython_openpyfile(cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)));
1566  if (scriptfile != NULL) {
1567  FILE* pyfile = cfpython_pyfile_asfile(scriptfile);
1568  PyRun_SimpleFile(pyfile, cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)));
1569  Py_DECREF(scriptfile);
1570  }
1571 
1572  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
1573  pycode_cache[i].code = NULL;
1574  pycode_cache[i].file = NULL;
1575  pycode_cache[i].cached_time = 0;
1576  pycode_cache[i].used_time = 0;
1577  }
1578 
1579  return 0;
1580 }
1581 
1582 static const char *getGlobalEventPath(int code) {
1583  for (int i = 0; GECodes[i] != 0; i++) {
1584  if (GECodes[i] == code)
1585  return GEPaths[i];
1586  }
1587  return "";
1588 }
1589 
1591  va_list args;
1592  int rv = 0;
1593  CFPContext *context;
1594  char *buf;
1595  player *pl;
1596  object *op;
1597  context = malloc(sizeof(CFPContext));
1598 
1599  va_start(args, type);
1600  context->event_code = va_arg(args, int);
1601 
1602  context->message[0] = 0;
1603 
1604  context->who = NULL;
1605  context->activator = NULL;
1606  context->third = NULL;
1607  context->event = NULL;
1608  context->talk = NULL;
1609  rv = context->returnvalue = 0;
1610  cf_get_maps_directory("python/events/python_event.py", context->script, sizeof(context->script));
1611  snprintf(context->options, sizeof(context->options), "%s", getGlobalEventPath(context->event_code));
1612  switch (context->event_code) {
1613  case EVENT_CRASH:
1614  cf_log(llevDebug, "Unimplemented for now\n");
1615  break;
1616 
1617  case EVENT_BORN:
1618  op = va_arg(args, object *);
1619  context->activator = Crossfire_Object_wrap(op);
1620  break;
1621 
1622  case EVENT_PLAYER_DEATH:
1623  op = va_arg(args, object *);
1624  context->who = Crossfire_Object_wrap(op);
1625  op = va_arg(args, object *);
1626  context->activator = Crossfire_Object_wrap(op);
1627  break;
1628 
1629  case EVENT_GKILL:
1630  op = va_arg(args, object *);
1631  object* hitter = va_arg(args, object *);
1632  context->who = Crossfire_Object_wrap(op);
1633  context->activator = Crossfire_Object_wrap(hitter);
1634  break;
1635 
1636  case EVENT_LOGIN:
1637  pl = va_arg(args, player *);
1638  context->activator = Crossfire_Object_wrap(pl->ob);
1639  buf = va_arg(args, char *);
1640  if (buf != NULL)
1641  snprintf(context->message, sizeof(context->message), "%s", buf);
1642  break;
1643 
1644  case EVENT_LOGOUT:
1645  pl = va_arg(args, player *);
1646  context->activator = Crossfire_Object_wrap(pl->ob);
1647  buf = va_arg(args, char *);
1648  if (buf != NULL)
1649  snprintf(context->message, sizeof(context->message), "%s", buf);
1650  break;
1651 
1652  case EVENT_REMOVE:
1653  op = va_arg(args, object *);
1654  context->activator = Crossfire_Object_wrap(op);
1655  break;
1656 
1657  case EVENT_SHOUT:
1658  op = va_arg(args, object *);
1659  context->activator = Crossfire_Object_wrap(op);
1660  buf = va_arg(args, char *);
1661  if (buf != NULL)
1662  snprintf(context->message, sizeof(context->message), "%s", buf);
1663  break;
1664 
1665  case EVENT_MUZZLE:
1666  op = va_arg(args, object *);
1667  context->activator = Crossfire_Object_wrap(op);
1668  buf = va_arg(args, char *);
1669  if (buf != NULL)
1670  snprintf(context->message, sizeof(context->message), "%s", buf);
1671  break;
1672 
1673  case EVENT_KICK:
1674  op = va_arg(args, object *);
1675  context->activator = Crossfire_Object_wrap(op);
1676  buf = va_arg(args, char *);
1677  if (buf != NULL)
1678  snprintf(context->message, sizeof(context->message), "%s", buf);
1679  break;
1680 
1681  case EVENT_MAPENTER:
1682  op = va_arg(args, object *);
1683  context->activator = Crossfire_Object_wrap(op);
1684  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1685  break;
1686 
1687  case EVENT_MAPLEAVE:
1688  op = va_arg(args, object *);
1689  context->activator = Crossfire_Object_wrap(op);
1690  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1691  break;
1692 
1693  case EVENT_CLOCK:
1694  break;
1695 
1696  case EVENT_MAPRESET:
1697  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1698  break;
1699 
1700  case EVENT_TELL:
1701  op = va_arg(args, object *);
1702  buf = va_arg(args, char *);
1703  context->activator = Crossfire_Object_wrap(op);
1704  if (buf != NULL)
1705  snprintf(context->message, sizeof(context->message), "%s", buf);
1706  op = va_arg(args, object *);
1707  context->third = Crossfire_Object_wrap(op);
1708  break;
1709 
1710  case EVENT_MAPUNLOAD:
1711  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1712  break;
1713 
1714  case EVENT_MAPLOAD:
1715  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1716  break;
1717  }
1718  va_end(args);
1719  context->returnvalue = 0;
1720 
1721  if (!do_script(context, 1)) {
1722  freeContext(context);
1723  return rv;
1724  }
1725 
1726  context = popContext();
1727  rv = context->returnvalue;
1728 
1729  /* Invalidate freed map wrapper. */
1730  if (context->event_code == EVENT_MAPUNLOAD)
1732 
1733  freeContext(context);
1734 
1735  return rv;
1736 }
1737 
1738 CF_PLUGIN int eventListener(int *type, ...) {
1739  int rv = 0;
1740  va_list args;
1741  char *buf;
1742  CFPContext *context;
1743  object *event;
1744 
1745  context = malloc(sizeof(CFPContext));
1746 
1747  context->message[0] = 0;
1748 
1749  va_start(args, type);
1750 
1751  context->who = Crossfire_Object_wrap(va_arg(args, object *));
1752  context->activator = Crossfire_Object_wrap(va_arg(args, object *));
1753  context->third = Crossfire_Object_wrap(va_arg(args, object *));
1754  buf = va_arg(args, char *);
1755  if (buf != NULL)
1756  snprintf(context->message, sizeof(context->message), "%s", buf);
1757  context->fix = va_arg(args, int);
1758  event = va_arg(args, object *);
1759  context->talk = va_arg(args, talk_info *);
1760  context->event_code = event->subtype;
1761  context->event = Crossfire_Object_wrap(event);
1762  cf_get_maps_directory(event->slaying, context->script, sizeof(context->script));
1763  snprintf(context->options, sizeof(context->options), "%s", event->name);
1764  context->returnvalue = 0;
1765 
1766  va_end(args);
1767 
1768  if (!do_script(context, 0)) {
1769  freeContext(context);
1770  return rv;
1771  }
1772 
1773  context = popContext();
1774  rv = context->returnvalue;
1775  freeContext(context);
1776  return rv;
1777 }
1778 
1780  int i;
1781 
1782  cf_log(llevDebug, "CFPython 2.0a closing\n");
1783 
1784  for (i = 0; i < NR_CUSTOM_CMD; i++) {
1785  if (CustomCommand[i].name != NULL)
1786  cf_free_string(CustomCommand[i].name);
1787  if (CustomCommand[i].script != NULL)
1788  cf_free_string(CustomCommand[i].script);
1789  }
1790 
1791  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
1792  Py_XDECREF(pycode_cache[i].code);
1793  if (pycode_cache[i].file != NULL)
1794  cf_free_string(pycode_cache[i].file);
1795  }
1796 
1797  Py_Finalize();
1798 
1799  return 0;
1800 }
#define DAYS_PER_WEEK
Definition: tod.h:15
CF_PLUGIN void * getPluginProperty(int *type,...)
Definition: cfpython.c:1435
#define AT_HOLYWORD
Definition: attack.h:97
Definition: object.h:274
Definition: player.h:92
int npc_msg_count
Definition: dialog.h:59
#define MOVE_WALK
Definition: define.h:407
PyObject_HEAD object * obj
CFPContext * current_context
Definition: cfpython.c:112
static PyObject * private_data
Definition: cfpython.c:118
PyObject * third
Definition: cfpython.h:118
#define EVENT_REMOVE
Definition: plugin.h:93
#define AT_ELECTRICITY
Definition: attack.h:79
sstring name
Definition: cfpython.c:82
static void cfpython_init_types(PyObject *m)
Definition: cfpython.c:1306
#define AT_COUNTERSPELL
Definition: attack.h:95
#define EVENT_SHOUT
Definition: plugin.h:94
static PyObject * getRegions(PyObject *self, PyObject *args)
Definition: cfpython.c:394
Definition: object.h:127
static PyObject * cfpython_openpyfile(char *filename)
Definition: cfpython.c:755
Definition: object.h:185
PyObject * Crossfire_Party_wrap(partylist *what)
#define AT_DEPLETE
Definition: attack.h:92
#define RANDO
Definition: define.h:550
#define AT_GHOSTHIT
Definition: attack.h:85
Definition: object.h:125
object * cf_create_object(void)
void cf_get_time(timeofday_t *tod)
static PyObject * getUniqueDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:245
int event_code
Definition: cfpython.h:122
#define ATNR_TURN_UNDEAD
Definition: attack.h:62
static PyObject * getReturnValue(PyObject *self, PyObject *args)
Definition: cfpython.c:170
void cf_free_string(sstring str)
const char * cf_get_month_name(int index)
PyObject * Crossfire_Region_wrap(region *what)
#define EVENT_KICK
Definition: plugin.h:97
PyObject * Crossfire_Map_wrap(mapstruct *what)
Definition: cfpython_map.c:427
static void addConstants(PyObject *module, const char *name, const CFConstant *constants)
Definition: cfpython.c:947
#define NDI_ALL
Definition: newclient.h:246
static PyObject * getParties(PyObject *self, PyObject *args)
Definition: cfpython.c:381
CF_PLUGIN int cfpython_globalEventListener(int *type,...)
Definition: cfpython.c:1590
Definition: object.h:221
static PyObject * getSeasonName(PyObject *self, PyObject *args)
Definition: cfpython.c:543
#define EVENT_DEATH
Definition: plugin.h:67
static PyObject * getTime(PyObject *self, PyObject *args)
Definition: cfpython.c:455
#define NDI_WHITE
Definition: newclient.h:222
static void initContextStack(void)
Definition: cfpython.c:717
static void initConstants(PyObject *module)
Definition: cfpython.c:995
#define AT_INTERNAL
Definition: attack.h:99
int message_type
Definition: dialog.h:55
mapstruct * cf_get_empty_map(int sizex, int sizey)
#define EVENT_DESTROY
Definition: plugin.h:77
Definition: object.h:204
static PyObject * getMapHasBeenLoaded(PyObject *self, PyObject *args)
Definition: cfpython.c:483
Definition: object.h:112
#define EVENT_LOGIN
Definition: plugin.h:88
PyObject * activator
Definition: cfpython.h:117
#define NDI_ORANGE
Definition: newclient.h:225
Definition: object.h:117
#define PACEV2
Definition: define.h:559
sstring message
Definition: dialog.h:54
static PyObject * setPlayerMessage(PyObject *self, PyObject *args)
Definition: cfpython.c:602
#define NDI_BROWN
Definition: newclient.h:233
static PyObject * getSharedDictionary(PyObject *self, PyObject *args)
Definition: cfpython.c:337
#define ATNR_DEPLETE
Definition: attack.h:65
const int value
Definition: cfpython.c:944
#define AT_CANCELLATION
Definition: attack.h:91
static PyObject * getArchetypes(PyObject *self, PyObject *args)
Definition: cfpython.c:342
int minute
Definition: tod.h:40
partylist * cf_party_get_first(void)
#define EVENT_MAPLEAVE
Definition: plugin.h:91
Definition: object.h:137
#define NDI_BLUE
Definition: newclient.h:226
sstring replies[MAX_REPLIES]
Definition: dialog.h:58
region * cf_region_get_first(void)
char options[1024]
Definition: cfpython.h:124
#define ATNR_SLOW
Definition: attack.h:60
static PyObject * getLocalDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:257
static PyObject * registerGEvent(PyObject *self, PyObject *args)
Definition: cfpython.c:120
#define EVENT_LOGOUT
Definition: plugin.h:89
Definition: object.h:240
Definition: object.h:119
static PyObject * findPlayer(PyObject *self, PyObject *args)
Definition: cfpython.c:199
Definition: object.h:136
const char * slaying
Definition: object.h:319
Definition: object.h:138
PyTypeObject Crossfire_PartyType
sstring replies_words[MAX_REPLIES]
Definition: dialog.h:57
Definition: object.h:109
#define AT_COLD
Definition: attack.h:80
static PyObject * npcSay(PyObject *self, PyObject *args)
Definition: cfpython.c:624
static PyObject * CFPythonError
Definition: cfpython.c:96
char message[1024]
Definition: cfpython.h:120
mapstruct * cf_map_get_map_property(mapstruct *map, int propcode)
void init_map_assoc_table(void)
Definition: cfpython_map.c:37
archetype * cf_archetype_get_next(archetype *arch)
int cf_timer_destroy(int id)
static PyObject * setReturnValue(PyObject *self, PyObject *args)
Definition: cfpython.c:174
static PyObject * getTempDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:249
Definition: object.h:157
#define EVENT_TIMER
Definition: plugin.h:76
Definition: object.h:223
region * cf_region_get_next(region *reg)
Definition: object.h:139
Definition: object.h:191
#define CIRCLE1
Definition: define.h:532
#define AT_BLIND
Definition: attack.h:98
const char * name
Definition: cfpython.c:943
#define NDI_BLACK
Definition: newclient.h:221
#define EVENT_TELL
Definition: plugin.h:95
player * cf_player_find(const char *plname)
#define EVENT_CRASH
Definition: plugin.h:85
static int do_script(CFPContext *context, int silent)
Definition: cfpython.c:906
#define EVENT_ATTACKS
Definition: plugin.h:66
#define CFAPI_MAP_PROP_NEXT
Definition: plugin.h:310
sstring cf_add_string(const char *str)
Definition: object.h:187
#define PETMOVE
Definition: define.h:517
CF_PLUGIN int closePlugin(void)
Definition: cfpython.c:1779
Definition: object.h:212
#define PERIODS_PER_DAY
Definition: tod.h:19
#define HITRUN
Definition: define.h:509
static PyMethodDef CFPythonMethods[]
Definition: cfpython.c:665
#define ATNR_CONFUSION
Definition: attack.h:54
Definition: object.h:465
#define NDI_DK_ORANGE
Definition: newclient.h:227
static pycode_cache_entry pycode_cache[PYTHON_CACHE_SIZE]
Definition: cfpython.c:94
Definition: object.h:220
int periodofday
Definition: tod.h:43
static PyObject * getPrivateDictionary(PyObject *self, PyObject *args)
Definition: cfpython.c:324
const char * cf_get_weekday_name(int index)
int year
Definition: tod.h:35
static PyObject * getDataDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:265
int cf_find_animation(const char *txt)
partylist * cf_party_get_next(partylist *party)
void cf_log(LogLevel logLevel, const char *format,...)
#define NDI_NAVY
Definition: newclient.h:223
#define AT_TURN_UNDEAD
Definition: attack.h:89
static PyObject * getWhoIsActivator(PyObject *self, PyObject *args)
Definition: cfpython.c:278
PyCodeObject * code
Definition: cfpython.c:75
#define MOVE_ALL
Definition: define.h:413
#define AT_LIFE_STEALING
Definition: attack.h:100
void cf_log_plain(LogLevel logLevel, const char *message)
static PyObject * getMapDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:241
static PyObject * getMonthName(PyObject *self, PyObject *args)
Definition: cfpython.c:551
CF_PLUGIN int eventListener(int *type,...)
Definition: cfpython.c:1738
#define AT_CHAOS
Definition: attack.h:94
Definition: object.h:241
const char * cf_get_season_name(int index)
object * cf_friendlylist_get_first(void)
#define ATNR_WEAPONMAGIC
Definition: attack.h:57
#define RUNATT
Definition: define.h:508
#define NDI_RED
Definition: newclient.h:224
static void set_exception(const char *fmt,...)
Definition: cfpython.c:99
#define AT_GODPOWER
Definition: attack.h:96
static PyObject * createMap(PyObject *self, PyObject *args)
Definition: cfpython.c:229
Definition: object.h:186
Definition: object.h:118
static PyObject * getPlayerDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:261
#define EVENT_MAPENTER
Definition: plugin.h:90
Definition: object.h:211
int replies_count
Definition: dialog.h:56
char script[1024]
Definition: cfpython.h:123
#define ATNR_CANCELLATION
Definition: attack.h:64
int cf_init_plugin(f_plug_api getHooks)
Definition: object.h:114
static void addSimpleConstants(PyObject *module, const char *name, const CFConstant *constants)
Definition: cfpython.c:979
CF_PLUGIN char SvnRevPlugin[]
Definition: cfpython.c:65
Definition: object.h:181
double speed
Definition: cfpython.c:84
#define EVENT_STOP
Definition: plugin.h:71
#define MAX_REPLIES
Definition: dialog.h:44
#define AT_DISEASE
Definition: attack.h:102
PyTypeObject Crossfire_ObjectType
time_t cached_time
Definition: cfpython.c:76
Definition: object.h:158
#define ATNR_PARALYZE
Definition: attack.h:61
#define MOVE_SWIM
Definition: define.h:411
void Handle_Map_Unload_Hook(Crossfire_Map *map)
Definition: cfpython_map.c:422
#define NDI_ALL_DMS
Definition: newclient.h:247
#define MOVE_FLY_LOW
Definition: define.h:408
static PyObject * getWhatIsMessage(PyObject *self, PyObject *args)
Definition: cfpython.c:296
Definition: object.h:115
Definition: map.h:276
static PyObject * getCFPythonVersion(PyObject *self, PyObject *args)
Definition: cfpython.c:164
PyMODINIT_FUNC initcjson(void)
Definition: cjson.c:1389
#define ATNR_LIFE_STEALING
Definition: attack.h:73
#define ATNR_DEATH
Definition: attack.h:66
#define snprintf
Definition: win32.h:46
PyTypeObject Crossfire_ArchetypeType
void cf_cost_string_from_value(uint64_t cost, int largest_coin, char *buffer, int length)
static PyObject * findFace(PyObject *self, PyObject *args)
Definition: cfpython.c:491
static PyObject * getConfigDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:253
mapstruct * cf_map_get_map(const char *name, int flags)
#define EVENT_CLOSE
Definition: plugin.h:75
#define MOVE_FLYING
Definition: define.h:410
static FILE * cfpython_pyfile_asfile(PyObject *obj)
Definition: cfpython.c:777
int month
Definition: tod.h:36
PyObject * event
Definition: cfpython.h:119
#define ATNR_BLIND
Definition: attack.h:71
Definition: object.h:145
#define PLUGIN_NAME
Definition: cfanim.h:32
#define PACEH
Definition: define.h:540
#define NDI_GREEN
Definition: newclient.h:228
const char * name
Definition: object.h:311
#define NR_CUSTOM_CMD
Definition: cfpython.c:88
CF_PLUGIN void cfpython_runPluginCommand(object *op, const char *params)
Definition: cfpython.c:1480
#define EVENT_PICKUP
Definition: plugin.h:69
static PyObject * getMaps(PyObject *self, PyObject *args)
Definition: cfpython.c:368
#define ATNR_INTERNAL
Definition: attack.h:72
#define ATNR_FEAR
Definition: attack.h:63
static PythonCmd CustomCommand[NR_CUSTOM_CMD]
Definition: cfpython.c:91
void cf_system_register_global_event(int event, const char *name, f_plug_event hook)
int weekofmonth
Definition: tod.h:41
static int current_command
Definition: cfpython.c:114
PyObject * Crossfire_Object_wrap(object *what)
int day
Definition: tod.h:37
#define ATNR_MAGIC
Definition: attack.h:50
int dayofweek
Definition: tod.h:38
Definition: object.h:111
static PyObject * unregisterGEvent(PyObject *self, PyObject *args)
Definition: cfpython.c:132
static PyObject * getPeriodofdayName(PyObject *self, PyObject *args)
Definition: cfpython.c:567
#define AT_FIRE
Definition: attack.h:78
#define ATNR_HOLYWORD
Definition: attack.h:70
void cf_system_unregister_global_event(int event, const char *name)
#define NDI_LT_GREEN
Definition: newclient.h:229
time_t used_time
Definition: cfpython.c:76
#define ATNR_PHYSICAL
Definition: attack.h:49
const char * name
Definition: commands.h:38
char * cf_get_maps_directory(const char *name, char *buf, int size)
#define EVENT_SAY
Definition: plugin.h:70
#define ATNR_ELECTRICITY
Definition: attack.h:52
#define ATNR_POISON
Definition: attack.h:59
#define AT_PHYSICAL
Definition: attack.h:76
unsigned __int64 uint64_t
Definition: win32.h:167
Definition: object.h:214
static PyObject * matchString(PyObject *self, PyObject *args)
Definition: cfpython.c:184
object * cf_friendlylist_get_next(object *ob)
#define EVENT_MAPLOAD
Definition: plugin.h:99
#define EVENT_THROW
Definition: plugin.h:73
static PyObject * getPlayers(PyObject *self, PyObject *args)
Definition: cfpython.c:355
Definition: object.h:126
sstring script
Definition: cfpython.c:83
LogLevel
Definition: logger.h:10
#define EVENT_MAPUNLOAD
Definition: plugin.h:98
int cf_find_face(const char *name, int error)
static PyObject * shared_data
Definition: cfpython.c:116
#define ATNR_COUNTERSPELL
Definition: attack.h:68
#define WAITATT
Definition: define.h:510
struct PythonCmdStruct PythonCmd
PyObject * who
Definition: cfpython.h:116
#define ATNR_DRAIN
Definition: attack.h:56
#define ATNR_GHOSTHIT
Definition: attack.h:58
Definition: dialog.h:10
#define EVENT_MAPRESET
Definition: plugin.h:92
Definition: object.h:201
static PyObject * getScriptParameters(PyObject *self, PyObject *args)
Definition: cfpython.c:307
#define ALLRUN
Definition: define.h:512
#define EVENT_DROP
Definition: plugin.h:68
#define AT_DRAIN
Definition: attack.h:83
static const flag_definition flags[]
#define EVENT_GKILL
Definition: plugin.h:87
static PyObject * getWeekdayName(PyObject *self, PyObject *args)
Definition: cfpython.c:559
#define EVENT_TIME
Definition: plugin.h:72
static PyObject * getScriptName(PyObject *self, PyObject *args)
Definition: cfpython.c:303
object * ob
Definition: player.h:158
const char * cf_re_cmp(const char *str, const char *regexp)
object * cf_object_get_object_property(object *op, int propcode)
const char * sstring
Definition: global.h:40
PyTypeObject Crossfire_PlayerType
static PyObject * registerCommand(PyObject *self, PyObject *args)
Definition: cfpython.c:420
static PyObject * readyMap(PyObject *self, PyObject *args)
Definition: cfpython.c:216
#define EVENT_CLOCK
Definition: plugin.h:84
static const char * getGlobalEventPath(int code)
Definition: cfpython.c:1582
Definition: object.h:107
#define CFAPI_PLAYER_PROP_NEXT
Definition: plugin.h:287
PyTypeObject Crossfire_RegionType
archetype * cf_archetype_get_first(void)
Definition: object.h:113
static void log_python_error(void)
Definition: cfpython.c:797
Definition: object.h:135
static PyObject * getWhoAmI(PyObject *self, PyObject *args)
Definition: cfpython.c:269
#define RUSH
Definition: define.h:511
#define AT_POISON
Definition: attack.h:86
command_function func
Definition: commands.h:39
#define vsnprintf
Definition: win32.h:61
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.c:354
#define WAIT2
Definition: define.h:514
Definition: object.h:122
#define CF_PLUGIN
Definition: plugin_common.h:38
#define MAX_NPC
Definition: dialog.h:46
#define PYTHON_CACHE_SIZE
Definition: cfpython.c:68
Definition: object.h:243
Definition: object.h:143
static PyCodeObject * compilePython(char *filename)
Definition: cfpython.c:817
sstring file
Definition: cfpython.c:74
#define EVENT_APPLY
Definition: plugin.h:64
#define HOURS_PER_DAY
Definition: tod.h:14
Definition: object.h:207
Definition: object.h:206
#define RANDO2
Definition: define.h:555
#define AT_FEAR
Definition: attack.h:90
#define ATNR_GODPOWER
Definition: attack.h:69
#define AT_SLOW
Definition: attack.h:87
Definition: tod.h:34
struct talk_info * talk
Definition: cfpython.h:127
static PyObject * getEvent(PyObject *self, PyObject *args)
Definition: cfpython.c:315
#define WEEKS_PER_MONTH
Definition: tod.h:16
mapstruct * cf_map_has_been_loaded(const char *name)
int hour
Definition: tod.h:39
static CFPContext * popContext(void)
Definition: cfpython.c:732
const char * cf_get_directory(int id)
mapstruct * cf_map_get_first(void)
#define NDI_GREY
Definition: newclient.h:232
#define AT_MAGIC
Definition: attack.h:77
void init_object_assoc_table(void)
static void pushContext(CFPContext *context)
Definition: cfpython.c:722
struct _cfpcontext * down
Definition: cfpython.h:115
static int GECodes[]
Definition: cfpython.c:1515
#define DISTATT
Definition: define.h:505
static PyObject * destroyTimer(PyObject *self, PyObject *args)
Definition: cfpython.c:475
static PyObject * createCFObject(PyObject *self, PyObject *args)
Definition: cfpython.c:144
#define EVENT_PLAYER_DEATH
Definition: plugin.h:86
static PyObject * getWhoIsThird(PyObject *self, PyObject *args)
Definition: cfpython.c:287
#define NDI_UNIQUE
Definition: newclient.h:245
PyObject * Crossfire_Archetype_wrap(archetype *what)
Definition: object.h:213
#define MOVE_FLY_HIGH
Definition: define.h:409
int returnvalue
Definition: cfpython.h:125
CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr)
Definition: cfpython.c:1372
sstring npc_msgs[MAX_NPC]
Definition: dialog.h:60
#define PACEH2
Definition: define.h:543
#define NDI_TAN
Definition: newclient.h:235
Definition: object.h:209
#define ATNR_COLD
Definition: attack.h:53
#define PACEV
Definition: define.h:556
#define MONTHS_PER_YEAR
Definition: tod.h:17
#define CIRCLE2
Definition: define.h:539
static PyObject * log_message(PyObject *self, PyObject *args)
Definition: cfpython.c:499
static PyObject * addReply(PyObject *self, PyObject *args)
Definition: cfpython.c:575
static const char * GEPaths[]
Definition: cfpython.c:1535
static PyObject * findAnimation(PyObject *self, PyObject *args)
Definition: cfpython.c:535
Definition: map.h:325
static PyObject * catcher
Definition: cfpython.c:789
const char * cf_get_periodofday_name(int index)
PyTypeObject Crossfire_MapType
Definition: cfpython_map.c:551
#define AT_CONFUSION
Definition: attack.h:81
static void freeContext(CFPContext *context)
Definition: cfpython.c:744
Definition: object.h:167
static PyObject * costStringFromValue(PyObject *self, PyObject *args)
Definition: cfpython.c:653
#define MOVE_BOAT
Definition: define.h:412
Definition: cfpython.c:73
#define NDI_GOLD
Definition: newclient.h:234
Definition: object.h:120
#define AT_ACID
Definition: attack.h:82
static PyObject * getFriendlyList(PyObject *self, PyObject *args)
Definition: cfpython.c:407
#define ATNR_CHAOS
Definition: attack.h:67
#define ATNR_ACID
Definition: attack.h:55
Definition: object.h:148
#define AT_DEATH
Definition: attack.h:93
static PyObject * createCFObjectByName(PyObject *self, PyObject *args)
Definition: cfpython.c:152
#define EVENT_ATTACKED
Definition: plugin.h:65
object * cf_create_object_by_name(const char *name)
#define AT_WEAPONMAGIC
Definition: attack.h:84
#define EVENT_BORN
Definition: plugin.h:83
#define SEASONS_PER_YEAR
Definition: tod.h:18
CFPContext * context_stack
Definition: cfpython.c:110
#define EVENT_TRIGGER
Definition: plugin.h:74
void(* f_plug_api)(int *type,...)
Definition: plugin.h:125
CF_PLUGIN int postInitPlugin(void)
Definition: cfpython.c:1555
#define EVENT_USER
Definition: plugin.h:78
#define DISTHIT
Definition: define.h:513
int season
Definition: tod.h:42
#define AT_PARALYZE
Definition: attack.h:88
#define EVENT_MUZZLE
Definition: plugin.h:96
Definition: object.h:224
#define ATNR_FIRE
Definition: attack.h:51
#define ATNR_DISEASE
Definition: attack.h:74
#define PLUGIN_VERSION
Definition: cfanim.h:33