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