Crossfire Server, Trunk  R21189
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 #ifdef IS_PY3K
759  {
760  int fd;
761  fd = open(filename, O_RDONLY);
762  if (fd == -1)
763  return NULL;
764  scriptfile = PyFile_FromFd(fd, filename, "r", -1, NULL, NULL, NULL, 1);
765  }
766 #else
767  if (!(scriptfile = PyFile_FromString(filename, "r"))) {
768  return NULL;
769  }
770 #endif
771  return scriptfile;
772 }
773 
778 static FILE* cfpython_pyfile_asfile(PyObject* obj) {
779 #ifdef IS_PY3K
780  return fdopen(PyObject_AsFileDescriptor(obj), "r");
781 #else
782  return PyFile_AsFile(obj);
783 #endif
784 }
785 
790 static PyObject *catcher = NULL;
791 
798 static void log_python_error(void) {
799 
800  PyErr_Print();
801 
802  if (catcher != NULL) {
803  PyObject *output = PyObject_GetAttrString(catcher, "value"); //get the stdout and stderr from our catchOutErr object
804 #ifdef IS_PY3K
805  PyObject* empty = PyUnicode_FromString("");
806 #else
807  PyObject* empty = PyString_FromString("");
808 #endif
809 
810 #ifdef IS_PY3K
811  cf_log_plain(llevError, PyUnicode_AsUTF8(output));
812 #else
813  cf_log_plain(llevError, PyString_AsString(output));
814 #endif
815  Py_DECREF(output);
816 
817  PyObject_SetAttrString(catcher, "value", empty);
818  Py_DECREF(empty);
819  }
820 
821  return;
822 }
823 
824 
826 static PyCodeObject *compilePython(char *filename) {
827  PyObject *scriptfile = NULL;
828  sstring sh_path;
829  struct stat stat_buf;
830  struct _node *n;
831  int i;
832  pycode_cache_entry *replace = NULL, *run = NULL;
833 
834  if (stat(filename, &stat_buf)) {
835  cf_log(llevDebug, "cfpython - The Script file %s can't be stat:ed\n", filename);
836  return NULL;
837  }
838 
839  sh_path = cf_add_string(filename);
840 
841  /* Search through cache. Three cases:
842  * 1) script in cache, but older than file -> replace cached
843  * 2) script in cache and up to date -> use cached
844  * 3) script not in cache, cache not full -> add to end of cache
845  * 4) script not in cache, cache full -> replace least recently used
846  */
847  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
848  if (pycode_cache[i].file == NULL) { /* script not in cache, cache not full */
849  replace = &pycode_cache[i]; /* add to end of cache */
850  break;
851  } else if (pycode_cache[i].file == sh_path) {
852  /* script in cache */
853  if (pycode_cache[i].code == NULL || (pycode_cache[i].cached_time < stat_buf.st_mtime)) {
854  /* cache older than file, replace cached */
855  replace = &pycode_cache[i];
856  } else {
857  /* cache uptodate, use cached*/
858  replace = NULL;
859  run = &pycode_cache[i];
860  }
861  break;
862  } else if (replace == NULL || pycode_cache[i].used_time < replace->used_time)
863  /* if we haven't found it yet, set replace to the oldest cache */
864  replace = &pycode_cache[i];
865  }
866 
867  /* replace a specific cache index with the file */
868  if (replace) {
869  Py_XDECREF(replace->code); /* safe to call on NULL */
870  replace->code = NULL;
871 
872  /* Need to replace path string? */
873  if (replace->file != sh_path) {
874  if (replace->file) {
875  cf_free_string(replace->file);
876  }
877  replace->file = cf_add_string(sh_path);
878  }
879 
880  /* Load, parse and compile. Note: because Pyhon may have been built with a
881  * different library than Crossfire, the FILE* it uses may be incompatible.
882  * Therefore we use PyFile to open the file, then convert to FILE* and get
883  * Python's own structure. Messy, but can't be helped... */
884  if (!(scriptfile = cfpython_openpyfile(filename))) {
885  cf_log(llevDebug, "cfpython - The Script file %s can't be opened\n", filename);
886  cf_free_string(sh_path);
887  return NULL;
888  } else {
889  /* Note: FILE* being opaque, it works, but the actual structure may be different! */
890  FILE* pyfile = cfpython_pyfile_asfile(scriptfile);
891  if ((n = PyParser_SimpleParseFile(pyfile, filename, Py_file_input))) {
892  replace->code = PyNode_Compile(n, filename);
893  PyNode_Free(n);
894  }
895 
896  if (PyErr_Occurred())
898  else
899  replace->cached_time = stat_buf.st_mtime;
900  run = replace;
901  }
902  }
903 
904  cf_free_string(sh_path);
905 
906  if (scriptfile) {
907  Py_DECREF(scriptfile);
908  }
909 
910  assert(run != NULL);
911  run->used_time = time(NULL);
912  return run->code;
913 }
914 
915 static int do_script(CFPContext *context, int silent) {
916  PyCodeObject *pycode;
917  PyObject *dict;
918  PyObject *ret;
919 #if 0
920  PyObject *list;
921  int item;
922 #endif
923 
924  pycode = compilePython(context->script);
925  if (pycode) {
926  pushContext(context);
927  dict = PyDict_New();
928  PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins());
929 #ifdef IS_PY3K
930  ret = PyEval_EvalCode((PyObject *)pycode, dict, NULL);
931 #else
932  ret = PyEval_EvalCode(pycode, dict, NULL);
933 #endif
934  if (PyErr_Occurred()) {
936  }
937  Py_XDECREF(ret);
938 #if 0
939  printf("cfpython - %d items in heap\n", PyDict_Size(dict));
940  list = PyDict_Values(dict);
941  for (item = PyList_Size(list)-1; item >= 0; item--) {
942  dict = PyList_GET_ITEM(list, item);
943  ret = PyObject_Str(dict);
944  printf(" ref %s = %d\n", PyString_AsString(ret), dict->ob_refcnt);
945  Py_XDECREF(ret);
946  }
947  Py_DECREF(list);
948 #endif
949  Py_DECREF(dict);
950  return 1;
951  } else
952  return 0;
953 }
954 
955 typedef struct {
956  const char *name;
957  const int value;
958 } CFConstant;
959 
960 static void addConstants(PyObject *module, const char *name, const CFConstant *constants) {
961  int i = 0;
962  char tmp[1024];
963  PyObject *new;
964  PyObject *dict;
965 
966  snprintf(tmp, sizeof(tmp), "Crossfire_%s", name);
967 
968  new = PyModule_New(tmp);
969  dict = PyDict_New();
970 
971  while (constants[i].name != NULL) {
972  PyModule_AddIntConstant(new, (char *)constants[i].name, constants[i].value);
973 #ifdef IS_PY3K
974  PyDict_SetItem(dict, PyLong_FromLong(constants[i].value), PyUnicode_FromString(constants[i].name));
975 #else
976  PyDict_SetItem(dict, PyLong_FromLong(constants[i].value), PyString_FromString(constants[i].name));
977 #endif
978  i++;
979  }
980  PyDict_SetItemString(PyModule_GetDict(module), name, new);
981 
982  snprintf(tmp, sizeof(tmp), "%sName", name);
983  PyDict_SetItemString(PyModule_GetDict(module), tmp, dict);
984  Py_DECREF(dict);
985 }
992 static void addSimpleConstants(PyObject *module, const char *name, const CFConstant *constants) {
993  int i = 0;
994  char tmp[1024];
995  PyObject *new;
996 
997  snprintf(tmp, sizeof(tmp), "Crossfire_%s", name);
998 
999  new = PyModule_New(tmp);
1000 
1001  while (constants[i].name != NULL) {
1002  PyModule_AddIntConstant(new, (char *)constants[i].name, constants[i].value);
1003  i++;
1004  }
1005  PyDict_SetItemString(PyModule_GetDict(module), name, new);
1006 }
1007 
1008 static void initConstants(PyObject *module) {
1009  static const CFConstant cstDirection[] = {
1010  { "NORTH", 1 },
1011  { "NORTHEAST", 2 },
1012  { "EAST", 3 },
1013  { "SOUTHEAST", 4 },
1014  { "SOUTH", 5 },
1015  { "SOUTHWEST", 6 },
1016  { "WEST", 7 },
1017  { "NORTHWEST", 8 },
1018  { NULL, 0 }
1019  };
1020 
1021  static const CFConstant cstType[] = {
1022  { "PLAYER", PLAYER },
1023  { "TRANSPORT", TRANSPORT },
1024  { "ROD", ROD },
1025  { "TREASURE", TREASURE },
1026  { "POTION", POTION },
1027  { "FOOD", FOOD },
1028  { "POISON", POISON },
1029  { "BOOK", BOOK },
1030  { "CLOCK", CLOCK },
1031  { "ARROW", ARROW },
1032  { "BOW", BOW },
1033  { "WEAPON", WEAPON },
1034  { "ARMOUR", ARMOUR },
1035  { "PEDESTAL", PEDESTAL },
1036  { "ALTAR", ALTAR },
1037  { "LOCKED_DOOR", LOCKED_DOOR },
1038  { "SPECIAL_KEY", SPECIAL_KEY },
1039  { "MAP", MAP },
1040  { "DOOR", DOOR },
1041  { "KEY", KEY },
1042  { "TIMED_GATE", TIMED_GATE },
1043  { "TRIGGER", TRIGGER },
1044  { "GRIMREAPER", GRIMREAPER },
1045  { "MAGIC_EAR", MAGIC_EAR },
1046  { "TRIGGER_BUTTON", TRIGGER_BUTTON },
1047  { "TRIGGER_ALTAR", TRIGGER_ALTAR },
1048  { "TRIGGER_PEDESTAL", TRIGGER_PEDESTAL },
1049  { "SHIELD", SHIELD },
1050  { "HELMET", HELMET },
1051  { "MONEY", MONEY },
1052  { "CLASS", CLASS },
1053  { "AMULET", AMULET },
1054  { "PLAYERMOVER", PLAYERMOVER },
1055  { "TELEPORTER", TELEPORTER },
1056  { "CREATOR", CREATOR },
1057  { "SKILL", SKILL },
1058  { "EARTHWALL", EARTHWALL },
1059  { "GOLEM", GOLEM },
1060  { "THROWN_OBJ", THROWN_OBJ },
1061  { "BLINDNESS", BLINDNESS },
1062  { "GOD", GOD },
1063  { "DETECTOR", DETECTOR },
1064  { "TRIGGER_MARKER", TRIGGER_MARKER },
1065  { "DEAD_OBJECT", DEAD_OBJECT },
1066  { "DRINK", DRINK },
1067  { "MARKER", MARKER },
1068  { "HOLY_ALTAR", HOLY_ALTAR },
1069  { "PLAYER_CHANGER", PLAYER_CHANGER },
1070  { "BATTLEGROUND", BATTLEGROUND },
1071  { "PEACEMAKER", PEACEMAKER },
1072  { "GEM", GEM },
1073  { "FIREWALL", FIREWALL },
1074  { "CHECK_INV", CHECK_INV },
1075  { "MOOD_FLOOR", MOOD_FLOOR },
1076  { "EXIT", EXIT },
1077  { "ENCOUNTER", ENCOUNTER },
1078  { "SHOP_FLOOR", SHOP_FLOOR },
1079  { "SHOP_MAT", SHOP_MAT },
1080  { "RING", RING },
1081  { "FLOOR", FLOOR },
1082  { "FLESH", FLESH },
1083  { "INORGANIC", INORGANIC },
1084  { "SKILL_TOOL", SKILL_TOOL },
1085  { "LIGHTER", LIGHTER },
1086  { "WALL", WALL },
1087  { "MISC_OBJECT", MISC_OBJECT },
1088  { "MONSTER", MONSTER },
1089  { "LAMP", LAMP },
1090  { "DUPLICATOR", DUPLICATOR },
1091  { "SPELLBOOK", SPELLBOOK },
1092  { "CLOAK", CLOAK },
1093  { "SPINNER", SPINNER },
1094  { "GATE", GATE },
1095  { "BUTTON", BUTTON },
1096  { "CF_HANDLE", CF_HANDLE },
1097  { "HOLE", HOLE },
1098  { "TRAPDOOR", TRAPDOOR },
1099  { "SIGN", SIGN },
1100  { "BOOTS", BOOTS },
1101  { "GLOVES", GLOVES },
1102  { "SPELL", SPELL },
1103  { "SPELL_EFFECT", SPELL_EFFECT },
1104  { "CONVERTER", CONVERTER },
1105  { "BRACERS", BRACERS },
1106  { "POISONING", POISONING },
1107  { "SAVEBED", SAVEBED },
1108  { "WAND", WAND },
1109  { "SCROLL", SCROLL },
1110  { "DIRECTOR", DIRECTOR },
1111  { "GIRDLE", GIRDLE },
1112  { "FORCE", FORCE },
1113  { "POTION_RESIST_EFFECT", POTION_RESIST_EFFECT },
1114  { "EVENT_CONNECTOR", EVENT_CONNECTOR },
1115  { "CLOSE_CON", CLOSE_CON },
1116  { "CONTAINER", CONTAINER },
1117  { "ARMOUR_IMPROVER", ARMOUR_IMPROVER },
1118  { "WEAPON_IMPROVER", WEAPON_IMPROVER },
1119  { "SKILLSCROLL", SKILLSCROLL },
1120  { "DEEP_SWAMP", DEEP_SWAMP },
1121  { "IDENTIFY_ALTAR", IDENTIFY_ALTAR },
1122  { "SHOP_INVENTORY", SHOP_INVENTORY },
1123  { "RUNE", RUNE },
1124  { "TRAP", TRAP },
1125  { "POWER_CRYSTAL", POWER_CRYSTAL },
1126  { "CORPSE", CORPSE },
1127  { "DISEASE", DISEASE },
1128  { "SYMPTOM", SYMPTOM },
1129  { "BUILDER", BUILDER },
1130  { "MATERIAL", MATERIAL },
1131  { NULL, 0 }
1132  };
1133 
1134  static const CFConstant cstMove[] = {
1135  { "WALK", MOVE_WALK },
1136  { "FLY_LOW", MOVE_FLY_LOW },
1137  { "FLY_HIGH", MOVE_FLY_HIGH },
1138  { "FLYING", MOVE_FLYING },
1139  { "SWIM", MOVE_SWIM },
1140  { "BOAT", MOVE_BOAT },
1141  { "ALL", MOVE_ALL },
1142  { NULL, 0 }
1143  };
1144 
1145  static const CFConstant cstMessageFlag[] = {
1146  { "NDI_BLACK", NDI_BLACK },
1147  { "NDI_WHITE", NDI_WHITE },
1148  { "NDI_NAVY", NDI_NAVY },
1149  { "NDI_RED", NDI_RED },
1150  { "NDI_ORANGE", NDI_ORANGE },
1151  { "NDI_BLUE", NDI_BLUE },
1152  { "NDI_DK_ORANGE", NDI_DK_ORANGE },
1153  { "NDI_GREEN", NDI_GREEN },
1154  { "NDI_LT_GREEN", NDI_LT_GREEN },
1155  { "NDI_GREY", NDI_GREY },
1156  { "NDI_BROWN", NDI_BROWN },
1157  { "NDI_GOLD", NDI_GOLD },
1158  { "NDI_TAN", NDI_TAN },
1159  { "NDI_UNIQUE", NDI_UNIQUE },
1160  { "NDI_ALL", NDI_ALL },
1161  { "NDI_ALL_DMS", NDI_ALL_DMS },
1162  { NULL, 0 }
1163  };
1164 
1165  static const CFConstant cstAttackType[] = {
1166  { "PHYSICAL", AT_PHYSICAL },
1167  { "MAGIC", AT_MAGIC },
1168  { "FIRE", AT_FIRE },
1169  { "ELECTRICITY", AT_ELECTRICITY },
1170  { "COLD", AT_COLD },
1171  { "CONFUSION", AT_CONFUSION },
1172  { "ACID", AT_ACID },
1173  { "DRAIN", AT_DRAIN },
1174  { "WEAPONMAGIC", AT_WEAPONMAGIC },
1175  { "GHOSTHIT", AT_GHOSTHIT },
1176  { "POISON", AT_POISON },
1177  { "SLOW", AT_SLOW },
1178  { "PARALYZE", AT_PARALYZE },
1179  { "TURN_UNDEAD", AT_TURN_UNDEAD },
1180  { "FEAR", AT_FEAR },
1181  { "CANCELLATION", AT_CANCELLATION },
1182  { "DEPLETE", AT_DEPLETE },
1183  { "DEATH", AT_DEATH },
1184  { "CHAOS", AT_CHAOS },
1185  { "COUNTERSPELL", AT_COUNTERSPELL },
1186  { "GODPOWER", AT_GODPOWER },
1187  { "HOLYWORD", AT_HOLYWORD },
1188  { "BLIND", AT_BLIND },
1189  { "INTERNAL", AT_INTERNAL },
1190  { "LIFE_STEALING", AT_LIFE_STEALING },
1191  { "DISEASE", AT_DISEASE },
1192  { NULL, 0 }
1193  };
1194 
1195  static const CFConstant cstAttackTypeNumber[] = {
1196  { "PHYSICAL", ATNR_PHYSICAL },
1197  { "MAGIC", ATNR_MAGIC },
1198  { "FIRE", ATNR_FIRE },
1199  { "ELECTRICITY", ATNR_ELECTRICITY },
1200  { "COLD", ATNR_COLD },
1201  { "CONFUSION", ATNR_CONFUSION },
1202  { "ACID", ATNR_ACID },
1203  { "DRAIN", ATNR_DRAIN },
1204  { "WEAPONMAGIC", ATNR_WEAPONMAGIC },
1205  { "GHOSTHIT", ATNR_GHOSTHIT },
1206  { "POISON", ATNR_POISON },
1207  { "SLOW", ATNR_SLOW },
1208  { "PARALYZE", ATNR_PARALYZE },
1209  { "TURN_UNDEAD", ATNR_TURN_UNDEAD },
1210  { "FEAR", ATNR_FEAR },
1211  { "CANCELLATION", ATNR_CANCELLATION },
1212  { "DEPLETE", ATNR_DEPLETE },
1213  { "DEATH", ATNR_DEATH },
1214  { "CHAOS", ATNR_CHAOS },
1215  { "COUNTERSPELL", ATNR_COUNTERSPELL },
1216  { "GODPOWER", ATNR_GODPOWER },
1217  { "HOLYWORD", ATNR_HOLYWORD },
1218  { "BLIND", ATNR_BLIND },
1219  { "INTERNAL", ATNR_INTERNAL },
1220  { "LIFE_STEALING", ATNR_LIFE_STEALING },
1221  { "DISEASE", ATNR_DISEASE },
1222  { NULL, 0 }
1223  };
1224 
1225  static const CFConstant cstEventType[] = {
1226  { "APPLY", EVENT_APPLY },
1227  { "ATTACK", EVENT_ATTACKED },
1228  { "ATTACKS", EVENT_ATTACKS },
1229  { "DEATH", EVENT_DEATH },
1230  { "DROP", EVENT_DROP },
1231  { "PICKUP", EVENT_PICKUP },
1232  { "SAY", EVENT_SAY },
1233  { "STOP", EVENT_STOP },
1234  { "TIME", EVENT_TIME },
1235  { "THROW", EVENT_THROW },
1236  { "TRIGGER", EVENT_TRIGGER },
1237  { "CLOSE", EVENT_CLOSE },
1238  { "TIMER", EVENT_TIMER },
1239  { "DESTROY", EVENT_DESTROY },
1240  { "BORN", EVENT_BORN },
1241  { "CLOCK", EVENT_CLOCK },
1242  { "CRASH", EVENT_CRASH },
1243  { "PLAYER_DEATH", EVENT_PLAYER_DEATH },
1244  { "GKILL", EVENT_GKILL },
1245  { "LOGIN", EVENT_LOGIN },
1246  { "LOGOUT", EVENT_LOGOUT },
1247  { "MAPENTER", EVENT_MAPENTER },
1248  { "MAPLEAVE", EVENT_MAPLEAVE },
1249  { "MAPRESET", EVENT_MAPRESET },
1250  { "REMOVE", EVENT_REMOVE },
1251  { "SHOUT", EVENT_SHOUT },
1252  { "TELL", EVENT_TELL },
1253  { "MUZZLE", EVENT_MUZZLE },
1254  { "KICK", EVENT_KICK },
1255  { "MAPUNLOAD", EVENT_MAPUNLOAD },
1256  { "MAPLOAD", EVENT_MAPLOAD },
1257  { "USER", EVENT_USER },
1258  { NULL, 0 }
1259  };
1260 
1261  static const CFConstant cstTime[] = {
1262  { "HOURS_PER_DAY", HOURS_PER_DAY },
1263  { "DAYS_PER_WEEK", DAYS_PER_WEEK },
1264  { "WEEKS_PER_MONTH", WEEKS_PER_MONTH },
1265  { "MONTHS_PER_YEAR", MONTHS_PER_YEAR },
1266  { "SEASONS_PER_YEAR", SEASONS_PER_YEAR },
1267  { "PERIODS_PER_DAY", PERIODS_PER_DAY },
1268  { NULL, 0 }
1269  };
1270 
1271  static const CFConstant cstReplyTypes[] = {
1272  { "SAY", rt_say },
1273  { "REPLY", rt_reply },
1274  { "QUESTION", rt_question },
1275  { NULL, 0 }
1276  };
1277 
1278  static const CFConstant cstAttackMovement[] = {
1279  { "DISTATT", DISTATT },
1280  { "RUNATT", RUNATT },
1281  { "HITRUN", HITRUN },
1282  { "WAITATT", WAITATT },
1283  { "RUSH", RUSH },
1284  { "ALLRUN", ALLRUN },
1285  { "DISTHIT", DISTHIT },
1286  { "WAIT2", WAIT2 },
1287  { "PETMOVE", PETMOVE },
1288  { "CIRCLE1", CIRCLE1 },
1289  { "CIRCLE2", CIRCLE2 },
1290  { "PACEH", PACEH },
1291  { "PACEH2", PACEH2 },
1292  { "RANDO", RANDO },
1293  { "RANDO2", RANDO2 },
1294  { "PACEV", PACEV },
1295  { "PACEV2", PACEV2 },
1296  { NULL, 0 }
1297  };
1298 
1299  addConstants(module, "Direction", cstDirection);
1300  addConstants(module, "Type", cstType);
1301  addConstants(module, "Move", cstMove);
1302  addConstants(module, "MessageFlag", cstMessageFlag);
1303  addConstants(module, "AttackType", cstAttackType);
1304  addConstants(module, "AttackTypeNumber", cstAttackTypeNumber);
1305  addConstants(module, "EventType", cstEventType);
1306  addSimpleConstants(module, "Time", cstTime);
1307  addSimpleConstants(module, "ReplyType", cstReplyTypes);
1308  addSimpleConstants(module, "AttackMovement", cstAttackMovement);
1309 }
1310 
1311 /*
1312  * Set up the main module and handle misc plugin loading stuff and such.
1313  */
1314 
1319 static void cfpython_init_types(PyObject* m) {
1320  PyObject *d = PyModule_GetDict(m);
1321 
1322  Crossfire_ObjectType.tp_new = PyType_GenericNew;
1323  Crossfire_MapType.tp_new = PyType_GenericNew;
1324  Crossfire_PlayerType.tp_new = PyType_GenericNew;
1325  Crossfire_ArchetypeType.tp_new = PyType_GenericNew;
1326  Crossfire_PartyType.tp_new = PyType_GenericNew;
1327  Crossfire_RegionType.tp_new = PyType_GenericNew;
1328  PyType_Ready(&Crossfire_ObjectType);
1329  PyType_Ready(&Crossfire_MapType);
1330  PyType_Ready(&Crossfire_PlayerType);
1331  PyType_Ready(&Crossfire_ArchetypeType);
1332  PyType_Ready(&Crossfire_PartyType);
1333  PyType_Ready(&Crossfire_RegionType);
1334 
1335  Py_INCREF(&Crossfire_ObjectType);
1336  Py_INCREF(&Crossfire_MapType);
1337  Py_INCREF(&Crossfire_PlayerType);
1338  Py_INCREF(&Crossfire_ArchetypeType);
1339  Py_INCREF(&Crossfire_PartyType);
1340  Py_INCREF(&Crossfire_RegionType);
1341 
1342  PyModule_AddObject(m, "Object", (PyObject *)&Crossfire_ObjectType);
1343  PyModule_AddObject(m, "Map", (PyObject *)&Crossfire_MapType);
1344  PyModule_AddObject(m, "Player", (PyObject *)&Crossfire_PlayerType);
1345  PyModule_AddObject(m, "Archetype", (PyObject *)&Crossfire_ArchetypeType);
1346  PyModule_AddObject(m, "Party", (PyObject *)&Crossfire_PartyType);
1347  PyModule_AddObject(m, "Region", (PyObject *)&Crossfire_RegionType);
1348 
1349  PyModule_AddObject(m, "LogError", Py_BuildValue("i", llevError));
1350  PyModule_AddObject(m, "LogInfo", Py_BuildValue("i", llevInfo));
1351  PyModule_AddObject(m, "LogDebug", Py_BuildValue("i", llevDebug));
1352  PyModule_AddObject(m, "LogMonster", Py_BuildValue("i", llevMonster));
1353 
1354  CFPythonError = PyErr_NewException("Crossfire.error", NULL, NULL);
1355  PyDict_SetItemString(d, "error", CFPythonError);
1356 }
1357 
1358 #ifdef IS_PY3K
1359 extern PyObject* PyInit_cjson(void);
1360 #else
1361 extern PyMODINIT_FUNC initcjson(void);
1362 #endif
1363 
1364 #ifdef IS_PY3K
1365 static PyModuleDef CrossfireModule = {
1366  PyModuleDef_HEAD_INIT,
1367  "Crossfire", /* m_name */
1368  NULL, /* m_doc */
1369  -1, /* m_size */
1370  CFPythonMethods, /* m_methods */
1371  NULL, /* m_reload */
1372  NULL, /* m_traverse */
1373  NULL, /* m_clear */
1374  NULL /* m_free */
1375 };
1376 
1377 static PyObject* PyInit_Crossfire(void)
1378 {
1379  PyObject *m = PyModule_Create(&CrossfireModule);
1380  Py_INCREF(m);
1381  return m;
1382 }
1383 #endif
1384 
1385 CF_PLUGIN int initPlugin(const char *iversion, f_plug_api gethooksptr) {
1386  PyObject *m;
1387  int i;
1388  /* Python code to redirect stdouts/stderr. */
1389  const char *stdOutErr =
1390 "import sys\n\
1391 class CatchOutErr:\n\
1392  def __init__(self):\n\
1393  self.value = ''\n\
1394  def write(self, txt):\n\
1395  self.value += txt\n\
1396 catchOutErr = CatchOutErr()\n\
1397 sys.stdout = catchOutErr\n\
1398 sys.stderr = catchOutErr\n\
1399 ";
1400 
1401  cf_init_plugin(gethooksptr);
1402  cf_log(llevDebug, "CFPython 2.0a init\n");
1403 
1406 
1407 #ifdef IS_PY26
1408  Py_Py3kWarningFlag++;
1409 #endif
1410 
1411 #ifdef IS_PY3K
1412  PyImport_AppendInittab("Crossfire", &PyInit_Crossfire);
1413  PyImport_AppendInittab("cjson", &PyInit_cjson);
1414 #endif
1415 
1416  Py_Initialize();
1417 
1418 #ifdef IS_PY3K
1419  m = PyImport_ImportModule("Crossfire");
1420 #else
1421  m = Py_InitModule("Crossfire", CFPythonMethods);
1422 #endif
1423 
1425 
1426  for (i = 0; i < NR_CUSTOM_CMD; i++) {
1427  CustomCommand[i].name = NULL;
1428  CustomCommand[i].script = NULL;
1429  CustomCommand[i].speed = 0.0;
1430  }
1431  initConstants(m);
1432  private_data = PyDict_New();
1433  shared_data = PyDict_New();
1434 
1435  /* Redirect Python's stderr to a special object so it can be put to
1436  * the Crossfire log. */
1437  m = PyImport_AddModule("__main__");
1438  PyRun_SimpleString(stdOutErr);
1439  catcher = PyObject_GetAttrString(m, "catchOutErr");
1440 
1441 #ifndef IS_PY3K
1442  /* add cjson module*/
1443  initcjson();
1444 #endif
1445  return 0;
1446 }
1447 
1448 CF_PLUGIN void *getPluginProperty(int *type, ...) {
1449  va_list args;
1450  const char *propname;
1451  int i, size;
1452  command_array_struct *rtn_cmd;
1453  char *buf;
1454 
1455  va_start(args, type);
1456  propname = va_arg(args, const char *);
1457 
1458  if (!strcmp(propname, "command?")) {
1459  const char *cmdname;
1460  cmdname = va_arg(args, const char *);
1461  rtn_cmd = va_arg(args, command_array_struct *);
1462  va_end(args);
1463 
1464  for (i = 0; i < NR_CUSTOM_CMD; i++) {
1465  if (CustomCommand[i].name != NULL) {
1466  if (!strcmp(CustomCommand[i].name, cmdname)) {
1467  rtn_cmd->name = CustomCommand[i].name;
1468  rtn_cmd->time = (float)CustomCommand[i].speed;
1469  rtn_cmd->func = cfpython_runPluginCommand;
1470  current_command = i;
1471  return rtn_cmd;
1472  }
1473  }
1474  }
1475  return NULL;
1476  } else if (!strcmp(propname, "Identification")) {
1477  buf = va_arg(args, char *);
1478  size = va_arg(args, int);
1479  va_end(args);
1480  snprintf(buf, size, PLUGIN_NAME);
1481  return NULL;
1482  } else if (!strcmp(propname, "FullName")) {
1483  buf = va_arg(args, char *);
1484  size = va_arg(args, int);
1485  va_end(args);
1486  snprintf(buf, size, PLUGIN_VERSION);
1487  return NULL;
1488  }
1489  va_end(args);
1490  return NULL;
1491 }
1492 
1493 CF_PLUGIN void cfpython_runPluginCommand(object *op, const char *params) {
1494  char buf[1024], path[1024];
1495  CFPContext *context;
1496 
1497  if (current_command < 0) {
1498  cf_log(llevError, "Illegal call of cfpython_runPluginCommand, call find_plugin_command first.\n");
1499  return;
1500  }
1501  snprintf(buf, sizeof(buf), "%s.py", cf_get_maps_directory(CustomCommand[current_command].script, path, sizeof(path)));
1502 
1503  context = malloc(sizeof(CFPContext));
1504  context->message[0] = 0;
1505 
1506  context->who = Crossfire_Object_wrap(op);
1507  context->activator = NULL;
1508  context->third = NULL;
1509  context->fix = 0;
1510  snprintf(context->script, sizeof(context->script), "%s", buf);
1511  if (params)
1512  snprintf(context->options, sizeof(context->options), "%s", params);
1513  else
1514  context->options[0] = 0;
1515  context->returnvalue = 1; /* Default is "command successful" */
1516 
1517  current_command = -999;
1518  if (!do_script(context, 0)) {
1519  freeContext(context);
1520  return;
1521  }
1522 
1523  context = popContext();
1524  freeContext(context);
1525 /* printf("Execution complete"); */
1526 }
1527 
1528 static int GECodes[] = {
1529  EVENT_BORN,
1530  EVENT_CLOCK,
1532  EVENT_GKILL,
1533  EVENT_LOGIN,
1534  EVENT_LOGOUT,
1538  EVENT_REMOVE,
1539  EVENT_SHOUT,
1540  EVENT_TELL,
1541  EVENT_MUZZLE,
1542  EVENT_KICK,
1544  EVENT_MAPLOAD,
1545  0
1546 };
1547 
1548 static const char* GEPaths[] = {
1549  "born",
1550  "clock",
1551  "death",
1552  "gkill",
1553  "login",
1554  "logout",
1555  "mapenter",
1556  "mapleave",
1557  "mapreset",
1558  "remove",
1559  "shout",
1560  "tell",
1561  "muzzle",
1562  "kick",
1563  "mapunload",
1564  "mapload",
1565  NULL
1566 };
1567 
1569  PyObject *scriptfile;
1570  char path[1024];
1571  int i;
1572 
1573  cf_log(llevDebug, "CFPython 2.0a post init\n");
1574  initContextStack();
1575  for (i = 0; GECodes[i] != 0; i++)
1577 
1578  scriptfile = cfpython_openpyfile(cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)));
1579  if (scriptfile != NULL) {
1580  FILE* pyfile = cfpython_pyfile_asfile(scriptfile);
1581  PyRun_SimpleFile(pyfile, cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)));
1582  Py_DECREF(scriptfile);
1583  }
1584 
1585  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
1586  pycode_cache[i].code = NULL;
1587  pycode_cache[i].file = NULL;
1588  pycode_cache[i].cached_time = 0;
1589  pycode_cache[i].used_time = 0;
1590  }
1591 
1592  return 0;
1593 }
1594 
1595 static const char *getGlobalEventPath(int code) {
1596  for (int i = 0; GECodes[i] != 0; i++) {
1597  if (GECodes[i] == code)
1598  return GEPaths[i];
1599  }
1600  return "";
1601 }
1602 
1604  va_list args;
1605  int rv = 0;
1606  CFPContext *context;
1607  char *buf;
1608  player *pl;
1609  object *op;
1610  context = malloc(sizeof(CFPContext));
1611 
1612  va_start(args, type);
1613  context->event_code = va_arg(args, int);
1614 
1615  context->message[0] = 0;
1616 
1617  context->who = NULL;
1618  context->activator = NULL;
1619  context->third = NULL;
1620  context->event = NULL;
1621  context->talk = NULL;
1622  rv = context->returnvalue = 0;
1623  cf_get_maps_directory("python/events/python_event.py", context->script, sizeof(context->script));
1624  snprintf(context->options, sizeof(context->options), "%s", getGlobalEventPath(context->event_code));
1625  switch (context->event_code) {
1626  case EVENT_CRASH:
1627  cf_log(llevDebug, "Unimplemented for now\n");
1628  break;
1629 
1630  case EVENT_BORN:
1631  op = va_arg(args, object *);
1632  context->activator = Crossfire_Object_wrap(op);
1633  break;
1634 
1635  case EVENT_PLAYER_DEATH:
1636  op = va_arg(args, object *);
1637  context->who = Crossfire_Object_wrap(op);
1638  op = va_arg(args, object *);
1639  context->activator = Crossfire_Object_wrap(op);
1640  break;
1641 
1642  case EVENT_GKILL:
1643  op = va_arg(args, object *);
1644  object* hitter = va_arg(args, object *);
1645  context->who = Crossfire_Object_wrap(op);
1646  context->activator = Crossfire_Object_wrap(hitter);
1647  break;
1648 
1649  case EVENT_LOGIN:
1650  pl = va_arg(args, player *);
1651  context->activator = Crossfire_Object_wrap(pl->ob);
1652  buf = va_arg(args, char *);
1653  if (buf != NULL)
1654  snprintf(context->message, sizeof(context->message), "%s", buf);
1655  break;
1656 
1657  case EVENT_LOGOUT:
1658  pl = va_arg(args, player *);
1659  context->activator = Crossfire_Object_wrap(pl->ob);
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_REMOVE:
1666  op = va_arg(args, object *);
1667  context->activator = Crossfire_Object_wrap(op);
1668  break;
1669 
1670  case EVENT_SHOUT:
1671  op = va_arg(args, object *);
1672  context->activator = Crossfire_Object_wrap(op);
1673  buf = va_arg(args, char *);
1674  if (buf != NULL)
1675  snprintf(context->message, sizeof(context->message), "%s", buf);
1676  break;
1677 
1678  case EVENT_MUZZLE:
1679  op = va_arg(args, object *);
1680  context->activator = Crossfire_Object_wrap(op);
1681  buf = va_arg(args, char *);
1682  if (buf != NULL)
1683  snprintf(context->message, sizeof(context->message), "%s", buf);
1684  break;
1685 
1686  case EVENT_KICK:
1687  op = va_arg(args, object *);
1688  context->activator = Crossfire_Object_wrap(op);
1689  buf = va_arg(args, char *);
1690  if (buf != NULL)
1691  snprintf(context->message, sizeof(context->message), "%s", buf);
1692  break;
1693 
1694  case EVENT_MAPENTER:
1695  op = va_arg(args, object *);
1696  context->activator = Crossfire_Object_wrap(op);
1697  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1698  break;
1699 
1700  case EVENT_MAPLEAVE:
1701  op = va_arg(args, object *);
1702  context->activator = Crossfire_Object_wrap(op);
1703  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1704  break;
1705 
1706  case EVENT_CLOCK:
1707  break;
1708 
1709  case EVENT_MAPRESET:
1710  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1711  break;
1712 
1713  case EVENT_TELL:
1714  op = va_arg(args, object *);
1715  buf = va_arg(args, char *);
1716  context->activator = Crossfire_Object_wrap(op);
1717  if (buf != NULL)
1718  snprintf(context->message, sizeof(context->message), "%s", buf);
1719  op = va_arg(args, object *);
1720  context->third = Crossfire_Object_wrap(op);
1721  break;
1722 
1723  case EVENT_MAPUNLOAD:
1724  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1725  break;
1726 
1727  case EVENT_MAPLOAD:
1728  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1729  break;
1730  }
1731  va_end(args);
1732  context->returnvalue = 0;
1733 
1734  if (!do_script(context, 1)) {
1735  freeContext(context);
1736  return rv;
1737  }
1738 
1739  context = popContext();
1740  rv = context->returnvalue;
1741 
1742  /* Invalidate freed map wrapper. */
1743  if (context->event_code == EVENT_MAPUNLOAD)
1745 
1746  freeContext(context);
1747 
1748  return rv;
1749 }
1750 
1751 CF_PLUGIN int eventListener(int *type, ...) {
1752  int rv = 0;
1753  va_list args;
1754  char *buf;
1755  CFPContext *context;
1756  object *event;
1757 
1758  context = malloc(sizeof(CFPContext));
1759 
1760  context->message[0] = 0;
1761 
1762  va_start(args, type);
1763 
1764  context->who = Crossfire_Object_wrap(va_arg(args, object *));
1765  context->activator = Crossfire_Object_wrap(va_arg(args, object *));
1766  context->third = Crossfire_Object_wrap(va_arg(args, object *));
1767  buf = va_arg(args, char *);
1768  if (buf != NULL)
1769  snprintf(context->message, sizeof(context->message), "%s", buf);
1770  context->fix = va_arg(args, int);
1771  event = va_arg(args, object *);
1772  context->talk = va_arg(args, talk_info *);
1773  context->event_code = event->subtype;
1774  context->event = Crossfire_Object_wrap(event);
1775  cf_get_maps_directory(event->slaying, context->script, sizeof(context->script));
1776  snprintf(context->options, sizeof(context->options), "%s", event->name);
1777  context->returnvalue = 0;
1778 
1779  va_end(args);
1780 
1781  if (!do_script(context, 0)) {
1782  freeContext(context);
1783  return rv;
1784  }
1785 
1786  context = popContext();
1787  rv = context->returnvalue;
1788  freeContext(context);
1789  return rv;
1790 }
1791 
1793  int i;
1794 
1795  cf_log(llevDebug, "CFPython 2.0a closing\n");
1796 
1797  for (i = 0; i < NR_CUSTOM_CMD; i++) {
1798  if (CustomCommand[i].name != NULL)
1799  cf_free_string(CustomCommand[i].name);
1800  if (CustomCommand[i].script != NULL)
1801  cf_free_string(CustomCommand[i].script);
1802  }
1803 
1804  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
1805  Py_XDECREF(pycode_cache[i].code);
1806  if (pycode_cache[i].file != NULL)
1807  cf_free_string(pycode_cache[i].file);
1808  }
1809 
1810  Py_Finalize();
1811 
1812  return 0;
1813 }
#define DAYS_PER_WEEK
Definition: tod.h:15
CF_PLUGIN void * getPluginProperty(int *type,...)
Definition: cfpython.c:1448
#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:113
static PyObject * private_data
Definition: cfpython.c:119
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:83
static void cfpython_init_types(PyObject *m)
Definition: cfpython.c:1319
#define AT_COUNTERSPELL
Definition: attack.h:95
#define EVENT_SHOUT
Definition: plugin.h:94
static PyObject * getRegions(PyObject *self, PyObject *args)
Definition: cfpython.c:395
Definition: object.h:127
static PyObject * cfpython_openpyfile(char *filename)
Definition: cfpython.c:756
Definition: object.h:185
PyObject * Crossfire_Party_wrap(partylist *what)
#define AT_DEPLETE
Definition: attack.h:92
#define RANDO
Definition: define.h:552
#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: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)
#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:960
#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:1603
Definition: object.h:221
static PyObject * getSeasonName(PyObject *self, PyObject *args)
Definition: cfpython.c:544
#define EVENT_DEATH
Definition: plugin.h:67
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:1008
#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:484
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:561
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:957
#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 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:258
static PyObject * registerGEvent(PyObject *self, PyObject *args)
Definition: cfpython.c:121
#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:200
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:625
static PyObject * CFPythonError
Definition: cfpython.c:97
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:175
static PyObject * getTempDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:250
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:534
#define AT_BLIND
Definition: attack.h:98
const char * name
Definition: cfpython.c:956
#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:915
#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:519
CF_PLUGIN int closePlugin(void)
Definition: cfpython.c:1792
Definition: object.h:212
#define PERIODS_PER_DAY
Definition: tod.h:19
#define HITRUN
Definition: define.h:511
static PyMethodDef CFPythonMethods[]
Definition: cfpython.c:666
#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:95
Definition: object.h:220
int periodofday
Definition: tod.h:43
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:1751
#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:510
#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
Definition: object.h:186
Definition: object.h:118
static PyObject * getPlayerDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:262
#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:992
CF_PLUGIN char SvnRevPlugin[]
Definition: cfpython.c:66
Definition: object.h:181
double speed
Definition: cfpython.c:85
#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:77
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:297
Definition: object.h:115
Definition: map.h:276
static PyObject * getCFPythonVersion(PyObject *self, PyObject *args)
Definition: cfpython.c:165
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:492
static PyObject * getConfigDirectory(PyObject *self, PyObject *args)
Definition: cfpython.c:254
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:778
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:542
#define NDI_GREEN
Definition: newclient.h:228
const char * name
Definition: object.h:311
#define NR_CUSTOM_CMD
Definition: cfpython.c:89
CF_PLUGIN void cfpython_runPluginCommand(object *op, const char *params)
Definition: cfpython.c:1493
#define EVENT_PICKUP
Definition: plugin.h:69
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
Definition: object.h:111
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
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 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:185
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:356
Definition: object.h:126
sstring script
Definition: cfpython.c:84
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:117
#define ATNR_COUNTERSPELL
Definition: attack.h:68
#define WAITATT
Definition: define.h:512
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:308
#define ALLRUN
Definition: define.h:514
#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:560
#define EVENT_TIME
Definition: plugin.h:72
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
#define EVENT_CLOCK
Definition: plugin.h:84
static const char * getGlobalEventPath(int code)
Definition: cfpython.c:1595
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:798
Definition: object.h:135
static PyObject * getWhoAmI(PyObject *self, PyObject *args)
Definition: cfpython.c:270
#define RUSH
Definition: define.h:513
#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:516
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:69
Definition: object.h:243
Definition: object.h:143
static PyCodeObject * compilePython(char *filename)
Definition: cfpython.c:826
sstring file
Definition: cfpython.c:75
#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:557
#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:316
#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: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
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:1528
#define DISTATT
Definition: define.h:507
static PyObject * destroyTimer(PyObject *self, PyObject *args)
Definition: cfpython.c:476
static PyObject * createCFObject(PyObject *self, PyObject *args)
Definition: cfpython.c:145
#define EVENT_PLAYER_DEATH
Definition: plugin.h:86
static PyObject * getWhoIsThird(PyObject *self, PyObject *args)
Definition: cfpython.c:288
#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:1385
sstring npc_msgs[MAX_NPC]
Definition: dialog.h:60
#define PACEH2
Definition: define.h:545
#define NDI_TAN
Definition: newclient.h:235
Definition: object.h:209
#define ATNR_COLD
Definition: attack.h:53
#define PACEV
Definition: define.h:558
#define MONTHS_PER_YEAR
Definition: tod.h:17
#define CIRCLE2
Definition: define.h:541
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:1548
static PyObject * findAnimation(PyObject *self, PyObject *args)
Definition: cfpython.c:536
Definition: map.h:325
static PyObject * catcher
Definition: cfpython.c:790
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:745
Definition: object.h:167
static PyObject * costStringFromValue(PyObject *self, PyObject *args)
Definition: cfpython.c:654
#define MOVE_BOAT
Definition: define.h:412
Definition: cfpython.c:74
#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:408
#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:153
#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:111
#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:1568
#define EVENT_USER
Definition: plugin.h:78
#define DISTHIT
Definition: define.h:515
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