Crossfire Server  1.75.0
cfpython.cpp
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 // node.h is deprecated in python 3.9, and removed in 3.10 due to a new parser for Python.
64 #ifndef IS_PY3K10
65 #include <node.h>
66 #endif
67 #include <svnversion.h>
68 
69 CF_PLUGIN char SvnRevPlugin[] = SVN_REV;
70 
71 //#define PYTHON_DEBUG /**< Give us some general infos out. */
72 #define PYTHON_CACHE_SIZE 256
77 struct pycode_cache_entry {
79  PyCodeObject *code;
80  time_t cached_time,
81  used_time;
82 };
83 
84 #define MAX_COMMANDS 1024
86 
89 
90 static PyObject *CFPythonError;
91 
93 static void set_exception(const char *fmt, ...) {
94  char buf[1024];
95  va_list arg;
96 
97  va_start(arg, fmt);
98  vsnprintf(buf, sizeof(buf), fmt, arg);
99  va_end(arg);
100 
101  PyErr_SetString(PyExc_ValueError, buf);
102 }
103 
105 
107 
108 static PyObject *shared_data = NULL;
109 
110 static PyObject *private_data = NULL;
111 
112 static CFPContext *popContext(void);
113 static void freeContext(CFPContext *context);
114 static int do_script(CFPContext *context);
115 
116 static PyObject *registerGEvent(PyObject *self, PyObject *args) {
117  int eventcode;
118  (void)self;
119 
120  if (!PyArg_ParseTuple(args, "i", &eventcode))
121  return NULL;
122 
124 
125  Py_INCREF(Py_None);
126  return Py_None;
127 }
128 
129 static PyObject *unregisterGEvent(PyObject *self, PyObject *args) {
130  int eventcode;
131  (void)self;
132 
133  if (!PyArg_ParseTuple(args, "i", &eventcode))
134  return NULL;
135 
137 
138  Py_INCREF(Py_None);
139  return Py_None;
140 }
141 
142 static PyObject *createCFObject(PyObject *self, PyObject *args) {
143  object *op;
144  (void)self;
145  (void)args;
146 
147  op = cf_create_object();
148 
149  return Crossfire_Object_wrap(op);
150 }
151 
152 static PyObject *createCFObjectByName(PyObject *self, PyObject *args) {
153  char *obname;
154  object *op;
155  (void)self;
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  (void)self;
168  (void)args;
169 
170  return Py_BuildValue("i", i);
171 }
172 
173 static PyObject *getReturnValue(PyObject *self, PyObject *args) {
174  (void)self;
175  (void)args;
176  return Py_BuildValue("i", current_context->returnvalue);
177 }
178 
179 static PyObject *setReturnValue(PyObject *self, PyObject *args) {
180  int i;
181  (void)self;
182 
183  if (!PyArg_ParseTuple(args, "i", &i))
184  return NULL;
185  current_context->returnvalue = i;
186  Py_INCREF(Py_None);
187  return Py_None;
188 }
189 
190 static PyObject *matchString(PyObject *self, PyObject *args) {
191  char *premiere;
192  char *seconde;
193  const char *result;
194  (void)self;
195 
196  if (!PyArg_ParseTuple(args, "ss", &premiere, &seconde))
197  return NULL;
198 
199  result = cf_re_cmp(premiere, seconde);
200  if (result != NULL)
201  return Py_BuildValue("i", 1);
202  else
203  return Py_BuildValue("i", 0);
204 }
205 
206 static PyObject *findPlayer(PyObject *self, PyObject *args) {
207  player *foundpl;
208  char *txt;
209  (void)self;
210 
211  if (!PyArg_ParseTuple(args, "s", &txt))
212  return NULL;
213 
214  foundpl = cf_player_find(txt);
215 
216  if (foundpl != NULL)
217  return Py_BuildValue("O", Crossfire_Object_wrap(foundpl->ob));
218  else {
219  Py_INCREF(Py_None);
220  return Py_None;
221  }
222 }
223 
224 static PyObject *readyMap(PyObject *self, PyObject *args) {
225  char *mapname;
226  mapstruct *map;
227  int flags = 0;
228  (void)self;
229 
230  if (!PyArg_ParseTuple(args, "s|i", &mapname, &flags))
231  return NULL;
232 
233  map = cf_map_get_map(mapname, flags);
234 
235  return Crossfire_Map_wrap(map);
236 }
237 
238 static PyObject *createMap(PyObject *self, PyObject *args) {
239  int sizex, sizey;
240  mapstruct *map;
241  (void)self;
242 
243  if (!PyArg_ParseTuple(args, "ii", &sizex, &sizey))
244  return NULL;
245 
246  map = cf_get_empty_map(sizex, sizey);
247 
248  return Crossfire_Map_wrap(map);
249 }
250 
251 static PyObject *getMapDirectory(PyObject *self, PyObject *args) {
252  (void)self;
253  (void)args;
254  return Py_BuildValue("s", cf_get_directory(0));
255 }
256 
257 static PyObject *getUniqueDirectory(PyObject *self, PyObject *args) {
258  (void)self;
259  (void)args;
260  return Py_BuildValue("s", cf_get_directory(1));
261 }
262 
263 static PyObject *getTempDirectory(PyObject *self, PyObject *args) {
264  (void)self;
265  (void)args;
266  return Py_BuildValue("s", cf_get_directory(2));
267 }
268 
269 static PyObject *getConfigDirectory(PyObject *self, PyObject *args) {
270  (void)self;
271  (void)args;
272  return Py_BuildValue("s", cf_get_directory(3));
273 }
274 
275 static PyObject *getLocalDirectory(PyObject *self, PyObject *args) {
276  (void)self;
277  (void)args;
278  return Py_BuildValue("s", cf_get_directory(4));
279 }
280 
281 static PyObject *getPlayerDirectory(PyObject *self, PyObject *args) {
282  (void)self;
283  (void)args;
284  return Py_BuildValue("s", cf_get_directory(5));
285 }
286 
287 static PyObject *getDataDirectory(PyObject *self, PyObject *args) {
288  (void)self;
289  (void)args;
290  return Py_BuildValue("s", cf_get_directory(6));
291 }
292 
293 static PyObject *getWhoAmI(PyObject *self, PyObject *args) {
294  (void)self;
295  (void)args;
296  if (!current_context->who) {
297  Py_INCREF(Py_None);
298  return Py_None;
299  }
300  Py_INCREF(current_context->who);
301  return current_context->who;
302 }
303 
304 static PyObject *getWhoIsActivator(PyObject *self, PyObject *args) {
305  (void)self;
306  (void)args;
307  if (!current_context->activator) {
308  Py_INCREF(Py_None);
309  return Py_None;
310  }
311  Py_INCREF(current_context->activator);
312  return current_context->activator;
313 }
314 
315 static PyObject *getWhoIsThird(PyObject *self, PyObject *args) {
316  (void)self;
317  (void)args;
318  if (!current_context->third) {
319  Py_INCREF(Py_None);
320  return Py_None;
321  }
322  Py_INCREF(current_context->third);
323  return current_context->third;
324 }
325 
326 static PyObject *getWhatIsMessage(PyObject *self, PyObject *args) {
327  (void)self;
328  (void)args;
329  if (*current_context->message == '\0')
330  return Py_BuildValue("");
331  else
332  return Py_BuildValue("s", current_context->message);
333 }
334 
335 static PyObject *getScriptName(PyObject *self, PyObject *args) {
336  (void)self;
337  (void)args;
338  return Py_BuildValue("s", current_context->script);
339 }
340 
341 static PyObject *getScriptParameters(PyObject *self, PyObject *args) {
342  (void)self;
343  (void)args;
344  if (!*current_context->options) {
345  Py_INCREF(Py_None);
346  return Py_None;
347  }
348  return Py_BuildValue("s", current_context->options);
349 }
350 
351 static PyObject *getEvent(PyObject *self, PyObject *args) {
352  (void)self;
353  (void)args;
354  if (!current_context->event) {
355  Py_INCREF(Py_None);
356  return Py_None;
357  }
358  Py_INCREF(current_context->event);
359  return current_context->event;
360 }
361 
362 static PyObject *getPrivateDictionary(PyObject *self, PyObject *args) {
363  PyObject *data;
364  (void)self;
365  (void)args;
366 
367  data = PyDict_GetItemString(private_data, current_context->script);
368  if (!data) {
369  data = PyDict_New();
370  PyDict_SetItemString(private_data, current_context->script, data);
371  Py_DECREF(data);
372  }
373  Py_INCREF(data);
374  return data;
375 }
376 
377 static PyObject *getSharedDictionary(PyObject *self, PyObject *args) {
378  (void)self;
379  (void)args;
380  Py_INCREF(shared_data);
381  return shared_data;
382 }
383 
384 static PyObject *getArchetypes(PyObject *self, PyObject *args) {
385  PyObject *list;
386  std::vector<archetype *> archs;
387  (void)self;
388  (void)args;
389 
391  list = PyList_New(0);
392  for (auto arch : archs) {
393  PyList_Append(list, Crossfire_Archetype_wrap(arch));
394  }
395  return list;
396 }
397 
398 static PyObject *getPlayers(PyObject *self, PyObject *args) {
399  PyObject *list;
400  std::vector<object *> players;
401  (void)self;
402  (void)args;
403 
405 
406  list = PyList_New(0);
407  for (auto pl : players) {
408  PyList_Append(list, Crossfire_Object_wrap(pl));
409  }
410  return list;
411 }
412 
413 static PyObject *getMaps(PyObject *self, PyObject *args) {
414  PyObject *list;
415  std::vector<mapstruct *> maps;
416  (void)self;
417  (void)args;
418 
420 
421  list = PyList_New(0);
422  for (auto map : maps) {
423  PyList_Append(list, Crossfire_Map_wrap(map));
424  }
425  return list;
426 }
427 
428 static PyObject *getParties(PyObject *self, PyObject *args) {
429  PyObject *list;
430  std::vector<partylist *> parties;
431  (void)self;
432  (void)args;
433 
435  list = PyList_New(0);
436  for (auto party : parties) {
437  PyList_Append(list, Crossfire_Party_wrap(party));
438  }
439  return list;
440 }
441 
442 static PyObject *getRegions(PyObject *self, PyObject *args) {
443  PyObject *list;
444  std::vector<region *> regions;
445  (void)self;
446  (void)args;
447 
449  list = PyList_New(0);
450  for (auto reg : regions) {
451  PyList_Append(list, Crossfire_Region_wrap(reg));
452  }
453  return list;
454 }
455 
456 static PyObject *getFriendlyList(PyObject *self, PyObject *args) {
457  PyObject *list;
458  std::vector<object *> friends;
459  (void)self;
460  (void)args;
461 
463  list = PyList_New(0);
464  for (auto ob : friends) {
465  PyList_Append(list, Crossfire_Object_wrap(ob));
466  }
467  return list;
468 }
469 
470 static void python_command_function(object *op, const char *params, const char *script) {
471  char buf[1024], path[1024];
472  CFPContext *context;
473 
474  snprintf(buf, sizeof(buf), "%s.py", cf_get_maps_directory(script, path, sizeof(path)));
475 
476  context = static_cast<CFPContext *>(malloc(sizeof(CFPContext)));
477  context->message[0] = 0;
478 
479  context->who = Crossfire_Object_wrap(op);
480  context->activator = NULL;
481  context->third = NULL;
482  /* We are not running from an event, so set it to NULL to avoid segfaults. */
483  context->event = NULL;
484  snprintf(context->script, sizeof(context->script), "%s", buf);
485  if (params)
486  snprintf(context->options, sizeof(context->options), "%s", params);
487  else
488  context->options[0] = 0;
489  context->returnvalue = 1; /* Default is "command successful" */
490 
491  if (!do_script(context)) {
492  freeContext(context);
493  return;
494  }
495 
496  context = popContext();
497  freeContext(context);
498 }
499 
500 static PyObject *registerCommand(PyObject *self, PyObject *args) {
501  char *cmdname;
502  char *scriptname;
503  double cmdspeed;
504  int type = COMMAND_TYPE_NORMAL, index;
505  (void)self;
506 
507  if (!PyArg_ParseTuple(args, "ssd|i", &cmdname, &scriptname, &cmdspeed, &type))
508  return NULL;
509 
510  if (cmdspeed < 0) {
511  set_exception("speed must not be negative");
512  return NULL;
513  }
514 
515  if (type < 0 || type > COMMAND_TYPE_WIZARD) {
516  set_exception("type must be between 0 and 2");
517  return NULL;
518  }
519 
520  for (index = 0; index < MAX_COMMANDS; index++) {
521  if (registered_commands[index] == 0) {
522  break;
523  }
524  }
525  if (index == MAX_COMMANDS) {
526  set_exception("too many registered commands");
527  return NULL;
528  }
529 
530  registered_commands[index] = cf_system_register_command_extra(cmdname, scriptname, python_command_function, type, cmdspeed);
531  if (registered_commands[index] == 0) {
532  set_exception("failed to register command (overriding an existing one with a different type?)");
533  return NULL;
534  }
535 
536  Py_INCREF(Py_None);
537  return Py_None;
538 }
539 
540 static PyObject *getTime(PyObject *self, PyObject *args) {
541  PyObject *list;
542  timeofday_t tod;
543  (void)self;
544  (void)args;
545 
546  cf_get_time(&tod);
547 
548  list = PyList_New(0);
549  PyList_Append(list, Py_BuildValue("i", tod.year));
550  PyList_Append(list, Py_BuildValue("i", tod.month));
551  PyList_Append(list, Py_BuildValue("i", tod.day));
552  PyList_Append(list, Py_BuildValue("i", tod.hour));
553  PyList_Append(list, Py_BuildValue("i", tod.minute));
554  PyList_Append(list, Py_BuildValue("i", tod.dayofweek));
555  PyList_Append(list, Py_BuildValue("i", tod.weekofmonth));
556  PyList_Append(list, Py_BuildValue("i", tod.season));
557  PyList_Append(list, Py_BuildValue("i", tod.periodofday));
558 
559  return list;
560 }
561 
562 static PyObject *destroyTimer(PyObject *self, PyObject *args) {
563  int id;
564  (void)self;
565 
566  if (!PyArg_ParseTuple(args, "i", &id))
567  return NULL;
568  return Py_BuildValue("i", cf_timer_destroy(id));
569 }
570 
571 static PyObject *getMapHasBeenLoaded(PyObject *self, PyObject *args) {
572  char *name;
573  (void)self;
574 
575  if (!PyArg_ParseTuple(args, "s", &name))
576  return NULL;
578 }
579 
580 static PyObject *findFace(PyObject *self, PyObject *args) {
581  char *name;
582  (void)self;
583 
584  if (!PyArg_ParseTuple(args, "s", &name))
585  return NULL;
586  return Py_BuildValue("i", cf_find_face(name, 0));
587 }
588 
589 static PyObject *log_message(PyObject *self, PyObject *args) {
590  LogLevel level;
591  int intLevel;
592  char *message;
593  (void)self;
594 
595  if (!PyArg_ParseTuple(args, "is", &intLevel, &message))
596  return NULL;
597 
598  switch (intLevel) {
599  case llevError:
600  level = llevError;
601  break;
602 
603  case llevInfo:
604  level = llevInfo;
605  break;
606 
607  case llevDebug:
608  level = llevDebug;
609  break;
610 
611  case llevMonster:
612  level = llevMonster;
613  break;
614 
615  default:
616  return NULL;
617  }
618  if ((message != NULL) && (message[strlen(message)] == '\n'))
619  cf_log(level, "CFPython: %s", message);
620  else
621  cf_log(level, "CFPython: %s\n", message);
622  Py_INCREF(Py_None);
623  return Py_None;
624 }
625 
626 static PyObject *findAnimation(PyObject *self, PyObject *args) {
627  char *name;
628  (void)self;
629 
630  if (!PyArg_ParseTuple(args, "s", &name))
631  return NULL;
632  return Py_BuildValue("i", cf_find_animation(name));
633 }
634 
635 static PyObject *getSeasonName(PyObject *self, PyObject *args) {
636  int i;
637  (void)self;
638 
639  if (!PyArg_ParseTuple(args, "i", &i))
640  return NULL;
641  return Py_BuildValue("s", cf_get_season_name(i));
642 }
643 
644 static PyObject *getMonthName(PyObject *self, PyObject *args) {
645  int i;
646  (void)self;
647 
648  if (!PyArg_ParseTuple(args, "i", &i))
649  return NULL;
650  return Py_BuildValue("s", cf_get_month_name(i));
651 }
652 
653 static PyObject *getWeekdayName(PyObject *self, PyObject *args) {
654  int i;
655  (void)self;
656 
657  if (!PyArg_ParseTuple(args, "i", &i))
658  return NULL;
659  return Py_BuildValue("s", cf_get_weekday_name(i));
660 }
661 
662 static PyObject *getPeriodofdayName(PyObject *self, PyObject *args) {
663  int i;
664  (void)self;
665 
666  if (!PyArg_ParseTuple(args, "i", &i))
667  return NULL;
668  return Py_BuildValue("s", cf_get_periodofday_name(i));
669 }
670 
671 static PyObject *addReply(PyObject *self, PyObject *args) {
672  char *word, *reply;
673  talk_info *talk;
674  (void)self;
675 
676  if (current_context->talk == NULL) {
677  set_exception("not in a dialog context");
678  return NULL;
679  }
680  talk = current_context->talk;
681 
682  if (!PyArg_ParseTuple(args, "ss", &word, &reply)) {
683  return NULL;
684  }
685 
686  if (talk->replies_count == MAX_REPLIES) {
687  set_exception("too many replies");
688  return NULL;
689  }
690 
691  talk->replies_words[talk->replies_count] = cf_add_string(word);
692  talk->replies[talk->replies_count] = cf_add_string(reply);
693  talk->replies_count++;
694  Py_INCREF(Py_None);
695  return Py_None;
696 
697 }
698 
699 static PyObject *setPlayerMessage(PyObject *self, PyObject *args) {
700  char *message;
701  int type = rt_reply;
702  (void)self;
703 
704  if (current_context->talk == NULL) {
705  set_exception("not in a dialog context");
706  return NULL;
707  }
708 
709  if (!PyArg_ParseTuple(args, "s|i", &message, &type)) {
710  return NULL;
711  }
712 
713  if (current_context->talk->message != NULL)
714  cf_free_string(current_context->talk->message);
715  current_context->talk->message = cf_add_string(message);
716  current_context->talk->message_type = static_cast<reply_type>(type);
717 
718  Py_INCREF(Py_None);
719  return Py_None;
720 }
721 
722 static PyObject *npcSay(PyObject *self, PyObject *args) {
723  Crossfire_Object *npc = NULL;
724  char *message, buf[2048];
725  (void)self;
726 
727  if (!PyArg_ParseTuple(args, "O!s", &Crossfire_ObjectType, &npc, &message))
728  return NULL;
729 
730  if (current_context->talk == NULL) {
731  set_exception("not in a dialog context");
732  return NULL;
733  }
734 
735  if (current_context->talk->npc_msg_count == MAX_NPC) {
736  set_exception("too many NPCs");
737  return NULL;
738  }
739 
740  if (strlen(message) >= sizeof(buf) - 1)
741  cf_log(llevError, "CFPython: warning, too long message in npcSay, will be truncated");
743  snprintf(buf, sizeof(buf), "%s says: %s", npc->obj->name, message);
744 
745  current_context->talk->npc_msgs[current_context->talk->npc_msg_count] = cf_add_string(buf);
746  current_context->talk->npc_msg_count++;
747 
748  Py_INCREF(Py_None);
749  return Py_None;
750 }
751 
752 static PyObject *costStringFromValue(PyObject *self, PyObject *args) {
753  uint64_t value;
754  char buf[2048];
755  int largest_coin = 0;
756  (void)self;
757 
758  if (!PyArg_ParseTuple(args, "L|i", &value, &largest_coin))
759  return NULL;
760 
761  cf_cost_string_from_value(value, largest_coin, buf, sizeof(buf));
762  return Py_BuildValue("s", buf);
763 }
764 
765 PyMethodDef CFPythonMethods[] = {
766  { "WhoAmI", getWhoAmI, METH_NOARGS, NULL },
767  { "WhoIsActivator", getWhoIsActivator, METH_NOARGS, NULL },
768  { "WhoIsOther", getWhoIsThird, METH_NOARGS, NULL },
769  { "WhatIsMessage", getWhatIsMessage, METH_NOARGS, NULL },
770  { "ScriptName", getScriptName, METH_NOARGS, NULL },
771  { "ScriptParameters", getScriptParameters, METH_NOARGS, NULL },
772  { "WhatIsEvent", getEvent, METH_NOARGS, NULL },
773  { "MapDirectory", getMapDirectory, METH_NOARGS, NULL },
774  { "UniqueDirectory", getUniqueDirectory, METH_NOARGS, NULL },
775  { "TempDirectory", getTempDirectory, METH_NOARGS, NULL },
776  { "ConfigDirectory", getConfigDirectory, METH_NOARGS, NULL },
777  { "LocalDirectory", getLocalDirectory, METH_NOARGS, NULL },
778  { "PlayerDirectory", getPlayerDirectory, METH_NOARGS, NULL },
779  { "DataDirectory", getDataDirectory, METH_NOARGS, NULL },
780  { "ReadyMap", readyMap, METH_VARARGS, NULL },
781  { "CreateMap", createMap, METH_VARARGS, NULL },
782  { "FindPlayer", findPlayer, METH_VARARGS, NULL },
783  { "MatchString", matchString, METH_VARARGS, NULL },
784  { "GetReturnValue", getReturnValue, METH_NOARGS, NULL },
785  { "SetReturnValue", setReturnValue, METH_VARARGS, NULL },
786  { "PluginVersion", getCFPythonVersion, METH_NOARGS, NULL },
787  { "CreateObject", createCFObject, METH_NOARGS, NULL },
788  { "CreateObjectByName", createCFObjectByName, METH_VARARGS, NULL },
789  { "GetPrivateDictionary", getPrivateDictionary, METH_NOARGS, NULL },
790  { "GetSharedDictionary", getSharedDictionary, METH_NOARGS, NULL },
791  { "GetPlayers", getPlayers, METH_NOARGS, NULL },
792  { "GetArchetypes", getArchetypes, METH_NOARGS, NULL },
793  { "GetMaps", getMaps, METH_NOARGS, NULL },
794  { "GetParties", getParties, METH_NOARGS, NULL },
795  { "GetRegions", getRegions, METH_NOARGS, NULL },
796  { "GetFriendlyList", getFriendlyList, METH_NOARGS, NULL },
797  { "RegisterCommand", registerCommand, METH_VARARGS, NULL },
798  { "RegisterGlobalEvent", registerGEvent, METH_VARARGS, NULL },
799  { "UnregisterGlobalEvent", unregisterGEvent, METH_VARARGS, NULL },
800  { "GetTime", getTime, METH_NOARGS, NULL },
801  { "DestroyTimer", destroyTimer, METH_VARARGS, NULL },
802  { "MapHasBeenLoaded", getMapHasBeenLoaded, METH_VARARGS, NULL },
803  { "Log", log_message, METH_VARARGS, NULL },
804  { "FindFace", findFace, METH_VARARGS, NULL },
805  { "FindAnimation", findAnimation, METH_VARARGS, NULL },
806  { "GetSeasonName", getSeasonName, METH_VARARGS, NULL },
807  { "GetMonthName", getMonthName, METH_VARARGS, NULL },
808  { "GetWeekdayName", getWeekdayName, METH_VARARGS, NULL },
809  { "GetPeriodofdayName", getPeriodofdayName, METH_VARARGS, NULL },
810  { "AddReply", addReply, METH_VARARGS, NULL },
811  { "SetPlayerMessage", setPlayerMessage, METH_VARARGS, NULL },
812  { "NPCSay", npcSay, METH_VARARGS, NULL },
813  { "CostStringFromValue", costStringFromValue, METH_VARARGS, NULL },
814  { NULL, NULL, 0, NULL }
815 };
816 
817 static void initContextStack(void) {
818  current_context = NULL;
819  context_stack = NULL;
820 }
821 
822 static void pushContext(CFPContext *context) {
823  if (current_context == NULL) {
824  context_stack = context;
825  context->down = NULL;
826  } else {
827  context->down = current_context;
828  }
829  current_context = context;
830 }
831 
832 static CFPContext *popContext(void) {
833  CFPContext *oldcontext;
834 
835  if (current_context != NULL) {
836  oldcontext = current_context;
837  current_context = current_context->down;
838  return oldcontext;
839  }
840  else
841  return NULL;
842 }
843 
844 static void freeContext(CFPContext *context) {
845  Py_XDECREF(context->event);
846  Py_XDECREF(context->third);
847  Py_XDECREF(context->who);
848  Py_XDECREF(context->activator);
849  free(context);
850 }
851 
855 static PyObject* cfpython_openpyfile(char *filename) {
856  PyObject *scriptfile;
857  int fd;
858  fd = open(filename, O_RDONLY);
859  if (fd == -1)
860  return NULL;
861  scriptfile = PyFile_FromFd(fd, filename, "r", -1, NULL, NULL, NULL, 1);
862  return scriptfile;
863 }
864 
869 static FILE* cfpython_pyfile_asfile(PyObject* obj) {
870  return fdopen(PyObject_AsFileDescriptor(obj), "r");
871 }
872 
877 static PyObject *catcher = NULL;
878 
879 #if defined(IS_PY3K9) || defined(IS_PY3K10)
880 
884 static PyObject *io_module = NULL;
885 #endif
886 
893 static void log_python_error(void) {
894 
895  PyErr_Print();
896 
897  if (catcher != NULL) {
898  PyObject *output = PyObject_GetAttrString(catcher, "value"); //get the stdout and stderr from our catchOutErr object
899  PyObject* empty = PyUnicode_FromString("");
900 
901  cf_log_plain(llevError, PyUnicode_AsUTF8(output));
902  Py_DECREF(output);
903 
904  PyObject_SetAttrString(catcher, "value", empty);
905  Py_DECREF(empty);
906  }
907 
908  return;
909 }
910 
911 
913 static PyCodeObject *compilePython(char *filename) {
914  PyObject *scriptfile = NULL;
915  sstring sh_path;
916  struct stat stat_buf;
917  int i;
918  pycode_cache_entry *replace = NULL, *run = NULL;
919 
920  if (stat(filename, &stat_buf)) {
921  cf_log(llevError, "CFPython: script file %s can't be stat'ed\n", filename);
922  return NULL;
923  }
924 
925  sh_path = cf_add_string(filename);
926 
927  /* Search through cache. Four cases:
928  * 1) script in cache, but older than file -> replace cached
929  * 2) script in cache and up to date -> use cached
930  * 3) script not in cache, cache not full -> add to end of cache
931  * 4) script not in cache, cache full -> replace least recently used
932  */
933  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
934  if (pycode_cache[i].file == NULL) { /* script not in cache, cache not full */
935  replace = &pycode_cache[i]; /* add to end of cache */
936  break;
937  } else if (pycode_cache[i].file == sh_path) {
938  /* script in cache */
939  if (pycode_cache[i].code == NULL || (pycode_cache[i].cached_time < stat_buf.st_mtime)) {
940  /* cache older than file, replace cached */
941  replace = &pycode_cache[i];
942  } else {
943  /* cache uptodate, use cached*/
944  replace = NULL;
945  run = &pycode_cache[i];
946  }
947  break;
948  } else if (replace == NULL || pycode_cache[i].used_time < replace->used_time)
949  /* if we haven't found it yet, set replace to the oldest cache */
950  replace = &pycode_cache[i];
951  }
952 
953  /* replace a specific cache index with the file */
954  if (replace) {
955  Py_XDECREF(replace->code); /* safe to call on NULL */
956  replace->code = NULL;
957 
958  /* Need to replace path string? */
959  if (replace->file != sh_path) {
960  if (replace->file) {
961  cf_free_string(replace->file);
962  }
963  replace->file = cf_add_string(sh_path);
964  }
965 #if defined (IS_PY3K9) || defined(IS_PY3K10)
966  /* With the new parser in 3.10, we need to read the file contents into a buffer, and then pass that string to compile it.
967  * The new parser removes the PyNode functions as well as PyParser_SimpleParseFile,
968  * so the code needed to be completely rewritten to work.
969  *
970  * Python's solution to these changes is to import the io module and use Python's read method to read in the file,
971  * and then convert the bytes object into a c-string for Py_CompileString
972  *
973  * Though, if it is more performant than the previous code, Py_CompileString is
974  * available for all Python 3, so it is possible to simplify all of them to this if we need to.
975  */
976  if (!io_module)
977  io_module = PyImport_ImportModule("io");
978  scriptfile = PyObject_CallMethod(io_module, "open", "ss", filename, "rb");
979  if (!scriptfile) {
980  cf_log(llevDebug, "CFPython: script file %s can't be opened\n", filename);
981  cf_free_string(sh_path);
982  return NULL;
983  }
984  PyObject *source_bytes = PyObject_CallMethod(scriptfile, "read", "");
985  (void)PyObject_CallMethod(scriptfile, "close", "");
986  PyObject *code = Py_CompileString(PyBytes_AsString(source_bytes), filename, Py_file_input);
987  if (code) {
988  replace->code = (PyCodeObject *)code;
989  }
990  if (PyErr_Occurred())
992  else
993  replace->cached_time = stat_buf.st_mtime;
994  run = replace;
995 #else
996  /* Load, parse and compile. Note: because Pyhon may have been built with a
997  * different library than Crossfire, the FILE* it uses may be incompatible.
998  * Therefore we use PyFile to open the file, then convert to FILE* and get
999  * Python's own structure. Messy, but can't be helped... */
1000  if (!(scriptfile = cfpython_openpyfile(filename))) {
1001  cf_log(llevDebug, "CFPython: script file %s can't be opened\n", filename);
1002  cf_free_string(sh_path);
1003  return NULL;
1004  } else {
1005  /* Note: FILE* being opaque, it works, but the actual structure may be different! */
1006  FILE* pyfile = cfpython_pyfile_asfile(scriptfile);
1007  struct _node *n;
1008  if ((n = PyParser_SimpleParseFile(pyfile, filename, Py_file_input))) {
1009  replace->code = PyNode_Compile(n, filename);
1010  PyNode_Free(n);
1011  }
1012  if (PyErr_Occurred())
1013  log_python_error();
1014  else
1015  replace->cached_time = stat_buf.st_mtime;
1016  run = replace;
1017  }
1018 #endif
1019  }
1020 
1021  cf_free_string(sh_path);
1022 
1023  if (scriptfile) {
1024  Py_DECREF(scriptfile);
1025  }
1026 
1027  assert(run != NULL);
1028  run->used_time = time(NULL);
1029  return run->code;
1030 }
1031 
1032 static int do_script(CFPContext *context) {
1033  PyCodeObject *pycode;
1034  PyObject *dict;
1035  PyObject *ret;
1036 
1037 #ifdef PYTHON_DEBUG
1038  cf_log(llevDebug, "CFPython: running script %s\n", context->script);
1039 #endif
1040 
1041  pycode = compilePython(context->script);
1042  if (pycode) {
1043  pushContext(context);
1044  dict = PyDict_New();
1045  PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins());
1046  ret = PyEval_EvalCode((PyObject *)pycode, dict, NULL);
1047  if (PyErr_Occurred()) {
1048  log_python_error();
1049  }
1050  Py_XDECREF(ret);
1051  Py_DECREF(dict);
1052  return 1;
1053  } else
1054  return 0;
1055 }
1056 
1064 static void addConstants(PyObject *module, const char *name, const CFConstant *constants) {
1065  int i = 0;
1066  char tmp[1024];
1067  PyObject *cst;
1068  PyObject *dict;
1069 
1070  snprintf(tmp, sizeof(tmp), "Crossfire_%s", name);
1071 
1072  cst = PyModule_New(tmp);
1073  dict = PyDict_New();
1074 
1075  while (constants[i].name != NULL) {
1076  PyModule_AddIntConstant(cst, (char *)constants[i].name, constants[i].value);
1077  PyDict_SetItem(dict, PyLong_FromLong(constants[i].value), PyUnicode_FromString(constants[i].name));
1078  i++;
1079  }
1080  PyDict_SetItemString(PyModule_GetDict(module), name, cst);
1081 
1082  snprintf(tmp, sizeof(tmp), "%sName", name);
1083  PyDict_SetItemString(PyModule_GetDict(module), tmp, dict);
1084  Py_DECREF(dict);
1085 }
1086 
1096 static void addSimpleConstants(PyObject *module, const char *name, const CFConstant *constants) {
1097  int i = 0;
1098  char tmp[1024];
1099  PyObject *cst;
1100 
1101  snprintf(tmp, sizeof(tmp), "Crossfire_%s", name);
1102 
1103  cst = PyModule_New(tmp);
1104 
1105  while (constants[i].name != NULL) {
1106  PyModule_AddIntConstant(cst, (char *)constants[i].name, constants[i].value);
1107  i++;
1108  }
1109  PyDict_SetItemString(PyModule_GetDict(module), name, cst);
1110 }
1111 
1113  { "NORTH", 1 },
1114  { "NORTHEAST", 2 },
1115  { "EAST", 3 },
1116  { "SOUTHEAST", 4 },
1117  { "SOUTH", 5 },
1118  { "SOUTHWEST", 6 },
1119  { "WEST", 7 },
1120  { "NORTHWEST", 8 },
1121  { NULL, 0 }
1122 };
1123 
1124 const CFConstant cstType[] = {
1125  { "PLAYER", PLAYER },
1126  { "TRANSPORT", TRANSPORT },
1127  { "ROD", ROD },
1128  { "TREASURE", TREASURE },
1129  { "POTION", POTION },
1130  { "FOOD", FOOD },
1131  { "POISON", POISON },
1132  { "BOOK", BOOK },
1133  { "CLOCK", CLOCK },
1134  { "DRAGON_FOCUS", DRAGON_FOCUS },
1135  { "ARROW", ARROW },
1136  { "BOW", BOW },
1137  { "WEAPON", WEAPON },
1138  { "ARMOUR", ARMOUR },
1139  { "PEDESTAL", PEDESTAL },
1140  { "ALTAR", ALTAR },
1141  { "LOCKED_DOOR", LOCKED_DOOR },
1142  { "SPECIAL_KEY", SPECIAL_KEY },
1143  { "MAP", MAP },
1144  { "DOOR", DOOR },
1145  { "KEY", KEY },
1146  { "TIMED_GATE", TIMED_GATE },
1147  { "TRIGGER", TRIGGER },
1148  { "GRIMREAPER", GRIMREAPER },
1149  { "MAGIC_EAR", MAGIC_EAR },
1150  { "TRIGGER_BUTTON", TRIGGER_BUTTON },
1151  { "TRIGGER_ALTAR", TRIGGER_ALTAR },
1152  { "TRIGGER_PEDESTAL", TRIGGER_PEDESTAL },
1153  { "SHIELD", SHIELD },
1154  { "HELMET", HELMET },
1155  { "MONEY", MONEY },
1156  { "CLASS", CLASS },
1157  { "AMULET", AMULET },
1158  { "PLAYERMOVER", PLAYERMOVER },
1159  { "TELEPORTER", TELEPORTER },
1160  { "CREATOR", CREATOR },
1161  { "SKILL", SKILL },
1162  { "EARTHWALL", EARTHWALL },
1163  { "GOLEM", GOLEM },
1164  { "THROWN_OBJ", THROWN_OBJ },
1165  { "BLINDNESS", BLINDNESS },
1166  { "GOD", GOD },
1167  { "DETECTOR", DETECTOR },
1168  { "TRIGGER_MARKER", TRIGGER_MARKER },
1169  { "DEAD_OBJECT", DEAD_OBJECT },
1170  { "DRINK", DRINK },
1171  { "MARKER", MARKER },
1172  { "HOLY_ALTAR", HOLY_ALTAR },
1173  { "PLAYER_CHANGER", PLAYER_CHANGER },
1174  { "BATTLEGROUND", BATTLEGROUND },
1175  { "PEACEMAKER", PEACEMAKER },
1176  { "GEM", GEM },
1177  { "FIREWALL", FIREWALL },
1178  { "CHECK_INV", CHECK_INV },
1179  { "MOOD_FLOOR", MOOD_FLOOR },
1180  { "EXIT", EXIT },
1181  { "ENCOUNTER", ENCOUNTER },
1182  { "SHOP_FLOOR", SHOP_FLOOR },
1183  { "SHOP_MAT", SHOP_MAT },
1184  { "RING", RING },
1185  { "FLOOR", FLOOR },
1186  { "FLESH", FLESH },
1187  { "INORGANIC", INORGANIC },
1188  { "SKILL_TOOL", SKILL_TOOL },
1189  { "LIGHTER", LIGHTER },
1190  { "WALL", WALL },
1191  { "MISC_OBJECT", MISC_OBJECT },
1192  { "MONSTER", MONSTER },
1193  { "LAMP", LAMP },
1194  { "DUPLICATOR", DUPLICATOR },
1195  { "SPELLBOOK", SPELLBOOK },
1196  { "CLOAK", CLOAK },
1197  { "SPINNER", SPINNER },
1198  { "GATE", GATE },
1199  { "BUTTON", BUTTON },
1200  { "CF_HANDLE", CF_HANDLE },
1201  { "HOLE", HOLE },
1202  { "TRAPDOOR", TRAPDOOR },
1203  { "SIGN", SIGN },
1204  { "BOOTS", BOOTS },
1205  { "GLOVES", GLOVES },
1206  { "SPELL", SPELL },
1207  { "SPELL_EFFECT", SPELL_EFFECT },
1208  { "CONVERTER", CONVERTER },
1209  { "BRACERS", BRACERS },
1210  { "POISONING", POISONING },
1211  { "SAVEBED", SAVEBED },
1212  { "WAND", WAND },
1213  { "SCROLL", SCROLL },
1214  { "DIRECTOR", DIRECTOR },
1215  { "GIRDLE", GIRDLE },
1216  { "FORCE", FORCE },
1217  { "POTION_RESIST_EFFECT", POTION_RESIST_EFFECT },
1218  { "EVENT_CONNECTOR", EVENT_CONNECTOR },
1219  { "CLOSE_CON", CLOSE_CON },
1220  { "CONTAINER", CONTAINER },
1221  { "ARMOUR_IMPROVER", ARMOUR_IMPROVER },
1222  { "WEAPON_IMPROVER", WEAPON_IMPROVER },
1223  { "SKILLSCROLL", SKILLSCROLL },
1224  { "DEEP_SWAMP", DEEP_SWAMP },
1225  { "IDENTIFY_ALTAR", IDENTIFY_ALTAR },
1226  { "SHOP_INVENTORY", SHOP_INVENTORY },
1227  { "RUNE", RUNE },
1228  { "TRAP", TRAP },
1229  { "POWER_CRYSTAL", POWER_CRYSTAL },
1230  { "CORPSE", CORPSE },
1231  { "DISEASE", DISEASE },
1232  { "SYMPTOM", SYMPTOM },
1233  { "BUILDER", BUILDER },
1234  { "MATERIAL", MATERIAL },
1235  { "MIMIC", MIMIC },
1236  { "LIGHTABLE", LIGHTABLE },
1237  { NULL, 0 }
1238 };
1239 
1240 const CFConstant cstMove[] = {
1241  { "WALK", MOVE_WALK },
1242  { "FLY_LOW", MOVE_FLY_LOW },
1243  { "FLY_HIGH", MOVE_FLY_HIGH },
1244  { "FLYING", MOVE_FLYING },
1245  { "SWIM", MOVE_SWIM },
1246  { "BOAT", MOVE_BOAT },
1247  { "ALL", MOVE_ALL },
1248  { NULL, 0 }
1249 };
1250 
1252  { "NDI_BLACK", NDI_BLACK },
1253  { "NDI_WHITE", NDI_WHITE },
1254  { "NDI_NAVY", NDI_NAVY },
1255  { "NDI_RED", NDI_RED },
1256  { "NDI_ORANGE", NDI_ORANGE },
1257  { "NDI_BLUE", NDI_BLUE },
1258  { "NDI_DK_ORANGE", NDI_DK_ORANGE },
1259  { "NDI_GREEN", NDI_GREEN },
1260  { "NDI_LT_GREEN", NDI_LT_GREEN },
1261  { "NDI_GREY", NDI_GREY },
1262  { "NDI_BROWN", NDI_BROWN },
1263  { "NDI_GOLD", NDI_GOLD },
1264  { "NDI_TAN", NDI_TAN },
1265  { "NDI_UNIQUE", NDI_UNIQUE },
1266  { "NDI_ALL", NDI_ALL },
1267  { "NDI_ALL_DMS", NDI_ALL_DMS },
1268  { NULL, 0 }
1269 };
1270 
1272  { "PHYSICAL", AT_PHYSICAL },
1273  { "MAGIC", AT_MAGIC },
1274  { "FIRE", AT_FIRE },
1275  { "ELECTRICITY", AT_ELECTRICITY },
1276  { "COLD", AT_COLD },
1277  { "CONFUSION", AT_CONFUSION },
1278  { "ACID", AT_ACID },
1279  { "DRAIN", AT_DRAIN },
1280  { "WEAPONMAGIC", AT_WEAPONMAGIC },
1281  { "GHOSTHIT", AT_GHOSTHIT },
1282  { "POISON", AT_POISON },
1283  { "SLOW", AT_SLOW },
1284  { "PARALYZE", AT_PARALYZE },
1285  { "TURN_UNDEAD", AT_TURN_UNDEAD },
1286  { "FEAR", AT_FEAR },
1287  { "CANCELLATION", AT_CANCELLATION },
1288  { "DEPLETE", AT_DEPLETE },
1289  { "DEATH", AT_DEATH },
1290  { "CHAOS", AT_CHAOS },
1291  { "COUNTERSPELL", AT_COUNTERSPELL },
1292  { "GODPOWER", AT_GODPOWER },
1293  { "HOLYWORD", AT_HOLYWORD },
1294  { "BLIND", AT_BLIND },
1295  { "INTERNAL", AT_INTERNAL },
1296  { "LIFE_STEALING", AT_LIFE_STEALING },
1297  { "DISEASE", AT_DISEASE },
1298  { NULL, 0 }
1299 };
1300 
1302  { "PHYSICAL", ATNR_PHYSICAL },
1303  { "MAGIC", ATNR_MAGIC },
1304  { "FIRE", ATNR_FIRE },
1305  { "ELECTRICITY", ATNR_ELECTRICITY },
1306  { "COLD", ATNR_COLD },
1307  { "CONFUSION", ATNR_CONFUSION },
1308  { "ACID", ATNR_ACID },
1309  { "DRAIN", ATNR_DRAIN },
1310  { "WEAPONMAGIC", ATNR_WEAPONMAGIC },
1311  { "GHOSTHIT", ATNR_GHOSTHIT },
1312  { "POISON", ATNR_POISON },
1313  { "SLOW", ATNR_SLOW },
1314  { "PARALYZE", ATNR_PARALYZE },
1315  { "TURN_UNDEAD", ATNR_TURN_UNDEAD },
1316  { "FEAR", ATNR_FEAR },
1317  { "CANCELLATION", ATNR_CANCELLATION },
1318  { "DEPLETE", ATNR_DEPLETE },
1319  { "DEATH", ATNR_DEATH },
1320  { "CHAOS", ATNR_CHAOS },
1321  { "COUNTERSPELL", ATNR_COUNTERSPELL },
1322  { "GODPOWER", ATNR_GODPOWER },
1323  { "HOLYWORD", ATNR_HOLYWORD },
1324  { "BLIND", ATNR_BLIND },
1325  { "INTERNAL", ATNR_INTERNAL },
1326  { "LIFE_STEALING", ATNR_LIFE_STEALING },
1327  { "DISEASE", ATNR_DISEASE },
1328  { NULL, 0 }
1329 };
1330 
1333  { "APPLY", EVENT_APPLY },
1334  { "ATTACK", EVENT_ATTACKED },
1335  { "ATTACKS", EVENT_ATTACKS },
1336  { "BOUGHT", EVENT_BOUGHT },
1337  { "CLOSE", EVENT_CLOSE },
1338  { "DEATH", EVENT_DEATH },
1339  { "DESTROY", EVENT_DESTROY },
1340  { "DROP", EVENT_DROP },
1341  { "PICKUP", EVENT_PICKUP },
1342  { "SAY", EVENT_SAY },
1343  { "SELLING", EVENT_SELLING },
1344  { "STOP", EVENT_STOP },
1345  { "TIME", EVENT_TIME },
1346  { "THROW", EVENT_THROW },
1347  { "TRIGGER", EVENT_TRIGGER },
1348  { "TIMER", EVENT_TIMER },
1349  { "USER", EVENT_USER },
1350 
1352  { "BORN", EVENT_BORN },
1353  { "CLOCK", EVENT_CLOCK },
1354  { "CRASH", EVENT_CRASH },
1355  { "GKILL", EVENT_GKILL },
1356  { "KICK", EVENT_KICK },
1357  { "LOGIN", EVENT_LOGIN },
1358  { "LOGOUT", EVENT_LOGOUT },
1359  { "MAPENTER", EVENT_MAPENTER },
1360  { "MAPLEAVE", EVENT_MAPLEAVE },
1361  { "MAPLOAD", EVENT_MAPLOAD },
1362  { "MAPREADY", EVENT_MAPREADY },
1363  { "MAPRESET", EVENT_MAPRESET },
1364  { "MAPUNLOAD", EVENT_MAPUNLOAD },
1365  { "MUZZLE", EVENT_MUZZLE },
1366  { "PLAYER_DEATH", EVENT_PLAYER_DEATH },
1367  { "REMOVE", EVENT_REMOVE },
1368  { "SHOUT", EVENT_SHOUT },
1369  { "TELL", EVENT_TELL },
1370  { "GBOUGHT", EVENT_GBOUGHT },
1371  { "GSOLD", EVENT_GSOLD },
1372  { NULL, 0 }
1373 };
1374 
1375 const CFConstant cstTime[] = {
1376  { "HOURS_PER_DAY", HOURS_PER_DAY },
1377  { "DAYS_PER_WEEK", DAYS_PER_WEEK },
1378  { "WEEKS_PER_MONTH", WEEKS_PER_MONTH },
1379  { "MONTHS_PER_YEAR", MONTHS_PER_YEAR },
1380  { "SEASONS_PER_YEAR", SEASONS_PER_YEAR },
1381  { "PERIODS_PER_DAY", PERIODS_PER_DAY },
1382  { NULL, 0 }
1383 };
1384 
1386  { "SAY", rt_say },
1387  { "REPLY", rt_reply },
1388  { "QUESTION", rt_question },
1389  { NULL, 0 }
1390 };
1391 
1393  { "DISTATT", DISTATT },
1394  { "RUNATT", RUNATT },
1395  { "HITRUN", HITRUN },
1396  { "WAITATT", WAITATT },
1397  { "RUSH", RUSH },
1398  { "ALLRUN", ALLRUN },
1399  { "DISTHIT", DISTHIT },
1400  { "WAIT2", WAIT2 },
1401  { "PETMOVE", PETMOVE },
1402  { "CIRCLE1", CIRCLE1 },
1403  { "CIRCLE2", CIRCLE2 },
1404  { "PACEH", PACEH },
1405  { "PACEH2", PACEH2 },
1406  { "RANDO", RANDO },
1407  { "RANDO2", RANDO2 },
1408  { "PACEV", PACEV },
1409  { "PACEV2", PACEV2 },
1410  { NULL, 0 }
1411 };
1412 
1413 static void initConstants(PyObject *module) {
1414  addConstants(module, "Direction", cstDirection);
1415  addConstants(module, "Type", cstType);
1416  addConstants(module, "Move", cstMove);
1417  addConstants(module, "MessageFlag", cstMessageFlag);
1418  addConstants(module, "AttackType", cstAttackType);
1419  addConstants(module, "AttackTypeNumber", cstAttackTypeNumber);
1420  addConstants(module, "EventType", cstEventType);
1421  addSimpleConstants(module, "Time", cstTime);
1422  addSimpleConstants(module, "ReplyType", cstReplyTypes);
1423  addSimpleConstants(module, "AttackMovement", cstAttackMovement);
1424 }
1425 
1426 /*
1427  * Set up the main module and handle misc plugin loading stuff and such.
1428  */
1429 
1434 static void cfpython_init_types(PyObject* m) {
1435  PyObject *d = PyModule_GetDict(m);
1436 
1437  Crossfire_ObjectType.tp_new = PyType_GenericNew;
1438  Crossfire_MapType.tp_new = PyType_GenericNew;
1439  Crossfire_PlayerType.tp_new = PyType_GenericNew;
1440  Crossfire_ArchetypeType.tp_new = PyType_GenericNew;
1441  Crossfire_PartyType.tp_new = PyType_GenericNew;
1442  Crossfire_RegionType.tp_new = PyType_GenericNew;
1443  PyType_Ready(&Crossfire_ObjectType);
1444  PyType_Ready(&Crossfire_MapType);
1445  PyType_Ready(&Crossfire_PlayerType);
1446  PyType_Ready(&Crossfire_ArchetypeType);
1447  PyType_Ready(&Crossfire_PartyType);
1448  PyType_Ready(&Crossfire_RegionType);
1449 
1450  Py_INCREF(&Crossfire_ObjectType);
1451  Py_INCREF(&Crossfire_MapType);
1452  Py_INCREF(&Crossfire_PlayerType);
1453  Py_INCREF(&Crossfire_ArchetypeType);
1454  Py_INCREF(&Crossfire_PartyType);
1455  Py_INCREF(&Crossfire_RegionType);
1456 
1457  PyModule_AddObject(m, "Object", (PyObject *)&Crossfire_ObjectType);
1458  PyModule_AddObject(m, "Map", (PyObject *)&Crossfire_MapType);
1459  PyModule_AddObject(m, "Player", (PyObject *)&Crossfire_PlayerType);
1460  PyModule_AddObject(m, "Archetype", (PyObject *)&Crossfire_ArchetypeType);
1461  PyModule_AddObject(m, "Party", (PyObject *)&Crossfire_PartyType);
1462  PyModule_AddObject(m, "Region", (PyObject *)&Crossfire_RegionType);
1463 
1464  PyModule_AddObject(m, "LogError", Py_BuildValue("i", llevError));
1465  PyModule_AddObject(m, "LogInfo", Py_BuildValue("i", llevInfo));
1466  PyModule_AddObject(m, "LogDebug", Py_BuildValue("i", llevDebug));
1467  PyModule_AddObject(m, "LogMonster", Py_BuildValue("i", llevMonster));
1468 
1469  CFPythonError = PyErr_NewException("Crossfire.error", NULL, NULL);
1470  PyDict_SetItemString(d, "error", CFPythonError);
1471 }
1472 
1473 extern PyObject* PyInit_cjson(void);
1474 
1475 static PyModuleDef CrossfireModule = {
1476  PyModuleDef_HEAD_INIT,
1477  "Crossfire", /* m_name */
1478  NULL, /* m_doc */
1479  -1, /* m_size */
1480  CFPythonMethods, /* m_methods */
1481  NULL, /* m_reload */
1482  NULL, /* m_traverse */
1483  NULL, /* m_clear */
1484  NULL /* m_free */
1485 };
1486 
1487 static PyObject* PyInit_Crossfire(void)
1488 {
1489  PyObject *m = PyModule_Create(&CrossfireModule);
1490  Py_INCREF(m);
1491  return m;
1492 }
1493 
1494 extern "C"
1495 int initPlugin(const char *iversion, f_plug_api gethooksptr) {
1496  PyObject *m;
1497  /* Python code to redirect stdouts/stderr. */
1498  const char *stdOutErr =
1499 "import sys\n\
1500 class CatchOutErr:\n\
1501  def __init__(self):\n\
1502  self.value = ''\n\
1503  def write(self, txt):\n\
1504  self.value += txt\n\
1505 catchOutErr = CatchOutErr()\n\
1506 sys.stdout = catchOutErr\n\
1507 sys.stderr = catchOutErr\n\
1508 ";
1509  (void)iversion;
1510 
1511  for (int c = 0; c < MAX_COMMANDS; c++) {
1512  registered_commands[c] = 0;
1513  }
1514 
1515  cf_init_plugin(gethooksptr);
1516  cf_log(llevDebug, "CFPython 2.0a init\n");
1517 
1518  PyImport_AppendInittab("Crossfire", &PyInit_Crossfire);
1519  PyImport_AppendInittab("cjson", &PyInit_cjson);
1520 
1521  Py_Initialize();
1522 
1523  m = PyImport_ImportModule("Crossfire");
1524 
1526 
1527  initConstants(m);
1528  private_data = PyDict_New();
1529  shared_data = PyDict_New();
1530 
1531  /* Redirect Python's stderr to a special object so it can be put to
1532  * the Crossfire log. */
1533  m = PyImport_AddModule("__main__");
1534  PyRun_SimpleString(stdOutErr);
1535  catcher = PyObject_GetAttrString(m, "catchOutErr");
1536  return 0;
1537 }
1538 
1539 CF_PLUGIN void *getPluginProperty(int *type, ...) {
1540  va_list args;
1541  const char *propname;
1542  int size;
1543  char *buf;
1544 
1545  va_start(args, type);
1546  propname = va_arg(args, const char *);
1547  if (!strcmp(propname, "Identification")) {
1548  buf = va_arg(args, char *);
1549  size = va_arg(args, int);
1550  va_end(args);
1551  snprintf(buf, size, PLUGIN_NAME);
1552  return NULL;
1553  } else if (!strcmp(propname, "FullName")) {
1554  buf = va_arg(args, char *);
1555  size = va_arg(args, int);
1556  va_end(args);
1557  snprintf(buf, size, PLUGIN_VERSION);
1558  return NULL;
1559  }
1560  va_end(args);
1561  return NULL;
1562 }
1563 
1564 static int GECodes[] = {
1565  EVENT_BORN,
1566  EVENT_CLOCK,
1568  EVENT_GKILL,
1569  EVENT_LOGIN,
1570  EVENT_LOGOUT,
1574  EVENT_REMOVE,
1575  EVENT_SHOUT,
1576  EVENT_TELL,
1577  EVENT_MUZZLE,
1578  EVENT_KICK,
1580  EVENT_MAPLOAD,
1582  EVENT_GBOUGHT,
1583  EVENT_GSOLD,
1584  0
1585 };
1586 
1587 static const char* GEPaths[] = {
1588  "born",
1589  "clock",
1590  "death",
1591  "gkill",
1592  "login",
1593  "logout",
1594  "mapenter",
1595  "mapleave",
1596  "mapreset",
1597  "remove",
1598  "shout",
1599  "tell",
1600  "muzzle",
1601  "kick",
1602  "mapunload",
1603  "mapload",
1604  "mapready",
1605  "gbought",
1606  "gsold",
1607  NULL
1608 };
1609 
1615 static void freeEventFiles(char **eventFiles) {
1616  assert(eventFiles);
1617  for (int e = 0; eventFiles[e] != NULL; e++) {
1618  free(eventFiles[e]);
1619  }
1620  free(eventFiles);
1621 }
1622 
1628 static char **getEventFiles(CFPContext *context) {
1629  char **eventFiles = static_cast<char **>(calloc(1, sizeof(eventFiles[0])));
1630  eventFiles[0] = NULL;
1631  char name[HUGE_BUF], path[NAME_MAX + 1];
1632 
1633  int allocated = 0, current = 0;
1634  DIR *dp;
1635  struct dirent *d;
1636  struct stat sb;
1637 
1638  snprintf(name, sizeof(name), "python/events/%s/", context->options);
1639  cf_get_maps_directory(name, path, sizeof(path));
1640 
1641  dp = opendir(path);
1642  if (dp == NULL) {
1643  return eventFiles;
1644  }
1645 
1646  while ((d = readdir(dp)) != NULL) {
1647  snprintf(name, sizeof(name), "%s%s", path, d->d_name);
1648  stat(name, &sb);
1649  if (S_ISDIR(sb.st_mode)) {
1650  continue;
1651  }
1652  if (strcmp(d->d_name + strlen(d->d_name) - 3, ".py")) {
1653  continue;
1654  }
1655 
1656  if (allocated == current) {
1657  allocated += 10;
1658  eventFiles = static_cast<char **>(realloc(eventFiles, sizeof(char *) * (allocated + 1)));
1659  for (int i = current; i < allocated + 1; i++) {
1660  eventFiles[i] = NULL;
1661  }
1662  }
1663  eventFiles[current] = strdup(name);
1664  current++;
1665  }
1666  (void)closedir(dp);
1667  return eventFiles;
1668 }
1669 
1671  PyObject *scriptfile;
1672  char path[1024];
1673  int i;
1674 
1675  cf_log(llevDebug, "CFPython 2.0a post init\n");
1676  initContextStack();
1677  for (i = 0; GECodes[i] != 0; i++)
1679 
1680  scriptfile = cfpython_openpyfile(cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)));
1681  if (scriptfile != NULL) {
1682  FILE* pyfile = cfpython_pyfile_asfile(scriptfile);
1683  PyRun_SimpleFile(pyfile, cf_get_maps_directory("python/events/python_init.py", path, sizeof(path)));
1684  Py_DECREF(scriptfile);
1685  }
1686 
1687  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
1688  pycode_cache[i].code = NULL;
1689  pycode_cache[i].file = NULL;
1690  pycode_cache[i].cached_time = 0;
1691  pycode_cache[i].used_time = 0;
1692  }
1693 
1694  return 0;
1695 }
1696 
1697 static const char *getGlobalEventPath(int code) {
1698  for (int i = 0; GECodes[i] != 0; i++) {
1699  if (GECodes[i] == code)
1700  return GEPaths[i];
1701  }
1702  return "";
1703 }
1704 
1706  va_list args;
1707  int rv = 0;
1708  CFPContext *context;
1709  char *buf;
1710  player *pl;
1711  object *op;
1712  context = static_cast<CFPContext *>(calloc(1, sizeof(CFPContext)));
1713  char **files;
1714 
1715  va_start(args, type);
1716  context->event_code = va_arg(args, int);
1717 
1718  context->message[0] = 0;
1719 
1720  rv = context->returnvalue = 0;
1721  switch (context->event_code) {
1722  case EVENT_CRASH:
1723  cf_log(llevDebug, "CFPython: event_crash unimplemented for now\n");
1724  break;
1725 
1726  case EVENT_BORN:
1727  op = va_arg(args, object *);
1728  context->activator = Crossfire_Object_wrap(op);
1729  break;
1730 
1731  case EVENT_PLAYER_DEATH:
1732  op = va_arg(args, object *);
1733  context->who = Crossfire_Object_wrap(op);
1734  op = va_arg(args, object *);
1735  context->activator = Crossfire_Object_wrap(op);
1736  break;
1737 
1738  case EVENT_GKILL:
1739  {
1740  op = va_arg(args, object *);
1741  object* hitter = va_arg(args, object *);
1742  context->who = Crossfire_Object_wrap(op);
1743  context->activator = Crossfire_Object_wrap(hitter);
1744  break;
1745  }
1746 
1747  case EVENT_LOGIN:
1748  pl = va_arg(args, player *);
1749  context->activator = Crossfire_Object_wrap(pl->ob);
1750  buf = va_arg(args, char *);
1751  if (buf != NULL)
1752  snprintf(context->message, sizeof(context->message), "%s", buf);
1753  break;
1754 
1755  case EVENT_LOGOUT:
1756  pl = va_arg(args, player *);
1757  context->activator = Crossfire_Object_wrap(pl->ob);
1758  buf = va_arg(args, char *);
1759  if (buf != NULL)
1760  snprintf(context->message, sizeof(context->message), "%s", buf);
1761  break;
1762 
1763  case EVENT_REMOVE:
1764  op = va_arg(args, object *);
1765  context->activator = Crossfire_Object_wrap(op);
1766  break;
1767 
1768  case EVENT_SHOUT:
1769  op = va_arg(args, object *);
1770  context->activator = Crossfire_Object_wrap(op);
1771  buf = va_arg(args, char *);
1772  if (buf != NULL)
1773  snprintf(context->message, sizeof(context->message), "%s", buf);
1774  break;
1775 
1776  case EVENT_MUZZLE:
1777  op = va_arg(args, object *);
1778  context->activator = Crossfire_Object_wrap(op);
1779  buf = va_arg(args, char *);
1780  if (buf != NULL)
1781  snprintf(context->message, sizeof(context->message), "%s", buf);
1782  break;
1783 
1784  case EVENT_KICK:
1785  op = va_arg(args, object *);
1786  context->activator = Crossfire_Object_wrap(op);
1787  buf = va_arg(args, char *);
1788  if (buf != NULL)
1789  snprintf(context->message, sizeof(context->message), "%s", buf);
1790  break;
1791 
1792  case EVENT_MAPENTER:
1793  op = va_arg(args, object *);
1794  context->activator = Crossfire_Object_wrap(op);
1795  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1796  break;
1797 
1798  case EVENT_MAPLEAVE:
1799  op = va_arg(args, object *);
1800  context->activator = Crossfire_Object_wrap(op);
1801  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1802  break;
1803 
1804  case EVENT_CLOCK:
1805  break;
1806 
1807  case EVENT_MAPRESET:
1808  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1809  break;
1810 
1811  case EVENT_TELL:
1812  op = va_arg(args, object *);
1813  buf = va_arg(args, char *);
1814  context->activator = Crossfire_Object_wrap(op);
1815  if (buf != NULL)
1816  snprintf(context->message, sizeof(context->message), "%s", buf);
1817  op = va_arg(args, object *);
1818  context->third = Crossfire_Object_wrap(op);
1819  break;
1820 
1821  case EVENT_MAPUNLOAD:
1822  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1823  break;
1824 
1825  case EVENT_MAPLOAD:
1826  context->who = Crossfire_Map_wrap(va_arg(args, mapstruct *));
1827  break;
1828 
1829  case EVENT_GBOUGHT:
1830  // fall through: these have the same arguments
1831  case EVENT_GSOLD:
1832  context->who = Crossfire_Object_wrap(va_arg(args, object *)); // op
1833  context->activator = Crossfire_Object_wrap(va_arg(args, object *)); // pl
1834  context->third = PyLong_FromUnsignedLong(va_arg(args, uint64_t)); // price
1835  break;
1836  }
1837  va_end(args);
1838  context->returnvalue = 0;
1839 
1840  if (context->event_code == EVENT_CLOCK) {
1841  // Ignore EVENT_CLOCK. It is not being used in maps, but nevertheless
1842  // runs python_init.py several times per second even while idling.
1843  freeContext(context);
1844  return rv;
1845  }
1846 
1847  snprintf(context->options, sizeof(context->options), "%s", getGlobalEventPath(context->event_code));
1848  files = getEventFiles(context);
1849  for (int file = 0; files[file] != NULL; file++)
1850  {
1851  CFPContext *copy = static_cast<CFPContext *>(malloc(sizeof(CFPContext)));
1852  (*copy) = (*context);
1853  Py_XINCREF(copy->activator);
1854  Py_XINCREF(copy->event);
1855  Py_XINCREF(copy->third);
1856  Py_XINCREF(copy->who);
1857  strncpy(copy->script, files[file], sizeof(copy->script));
1858 
1859  if (!do_script(copy)) {
1860  freeContext(copy);
1861  freeEventFiles(files);
1862  return rv;
1863  }
1864 
1865  copy = popContext();
1866  rv = copy->returnvalue;
1867 
1868  freeContext(copy);
1869  }
1870  freeEventFiles(files);
1871 
1872  /* Invalidate freed map wrapper. */
1873  if (context->event_code == EVENT_MAPUNLOAD)
1875 
1876  free(context);
1877 
1878  return rv;
1879 }
1880 
1881 CF_PLUGIN int eventListener(int *type, ...) {
1882  int rv = 0;
1883  va_list args;
1884  char *buf;
1885  CFPContext *context;
1886  object *event;
1887 
1888  context = static_cast<CFPContext *>(malloc(sizeof(CFPContext)));
1889 
1890  context->message[0] = 0;
1891 
1892  va_start(args, type);
1893 
1894  context->who = Crossfire_Object_wrap(va_arg(args, object *));
1895  context->activator = Crossfire_Object_wrap(va_arg(args, object *));
1896  context->third = Crossfire_Object_wrap(va_arg(args, object *));
1897  buf = va_arg(args, char *);
1898  if (buf != NULL)
1899  snprintf(context->message, sizeof(context->message), "%s", buf);
1900  /* fix = */va_arg(args, int);
1901  event = va_arg(args, object *);
1902  context->talk = va_arg(args, talk_info *);
1903  context->event_code = event->subtype;
1904  context->event = Crossfire_Object_wrap(event);
1905  cf_get_maps_directory(event->slaying, context->script, sizeof(context->script));
1906  snprintf(context->options, sizeof(context->options), "%s", event->name);
1907  context->returnvalue = 0;
1908 
1909  va_end(args);
1910 
1911  if (!do_script(context)) {
1912  freeContext(context);
1913  return rv;
1914  }
1915 
1916  context = popContext();
1917  rv = context->returnvalue;
1918  freeContext(context);
1919  return rv;
1920 }
1921 
1923  int i;
1924 
1925  cf_log(llevDebug, "CFPython 2.0a closing\n");
1926 
1927  for (int c = 0; c < MAX_COMMANDS; c++) {
1928  if (registered_commands[c]) {
1930  }
1931  }
1932 
1933  for (i = 0; i < PYTHON_CACHE_SIZE; i++) {
1934  Py_XDECREF(pycode_cache[i].code);
1935  if (pycode_cache[i].file != NULL)
1936  cf_free_string(pycode_cache[i].file);
1937  }
1938 
1939  Py_Finalize();
1940 
1941  return 0;
1942 }
#define DAYS_PER_WEEK
Definition: tod.h:16
#define ATNR_FEAR
Definition: attack.h:61
See Pedestal.
Definition: object.h:126
Error, serious thing.
Definition: logger.h:11
#define dirent
Definition: global.h:215
static void python_command_function(object *op, const char *params, const char *script)
Definition: cfpython.cpp:470
#define AT_HOLYWORD
Damage based on race and caster&#39;s god.
Definition: attack.h:99
#define EVENT_SAY
Someone speaks.
Definition: events.h:37
static event_registration c
Definition: citylife.cpp:424
int npc_msg_count
How many NPCs reacted to the text being said.
Definition: dialog.h:58
#define MOVE_WALK
Object walks.
Definition: define.h:398
PyObject_HEAD object * obj
#define PYTHON_CACHE_SIZE
Number of python scripts to store the bytecode of at a time.
Definition: cfpython.cpp:72
see doc/Developers/objects
Definition: object.h:113
static PyObject * getSeasonName(PyObject *self, PyObject *args)
Definition: cfpython.cpp:635
#define COMMAND_TYPE_WIZARD
Wizard-only commands.
Definition: commands.h:39
#define AT_ELECTRICITY
Can also ignite objects (8)
Definition: attack.h:81
#define ATNR_ELECTRICITY
Definition: attack.h:50
#define EVENT_REMOVE
A Player character has been removed.
Definition: events.h:67
#define AT_COUNTERSPELL
Cancels magic spells (524288) peterm@soda.berkeley.edu.
Definition: attack.h:97
See Key.
Definition: object.h:132
static command_registration registered_commands[MAX_COMMANDS]
Definition: cfpython.cpp:85
See Ring.
Definition: object.h:190
Information.
Definition: logger.h:12
void Handle_Map_Unload_Hook(Crossfire_Map *map)
static PyObject * setReturnValue(PyObject *self, PyObject *args)
Definition: cfpython.cpp:179
#define AT_DEPLETE
Lose one point from one stat, can be restored (65536) vick@bern.docs.uu.se.
Definition: attack.h:94
#define RANDO
The monster will go in a random direction until it is stopped by an obstacle, then it chooses another...
Definition: define.h:535
#define AT_GHOSTHIT
Attacker dissolves (512)
Definition: attack.h:87
static PyObject * createMap(PyObject *self, PyObject *args)
Definition: cfpython.cpp:238
#define ATNR_SLOW
Definition: attack.h:58
Definition: object.h:130
object * cf_create_object(void)
Wrapper for object_new().
void cf_get_time(timeofday_t *tod)
CFPContext * down
Definition: cfpython.h:95
Eneq((at)csd.uu.se): Id for close_container archetype.
Definition: object.h:234
void cf_free_string(sstring str)
Wrapper for free_string().
static PyObject * getEvent(PyObject *self, PyObject *args)
Definition: cfpython.cpp:351
#define CFAPI_SYSTEM_MAPS
Definition: plugin.h:285
const char * cf_get_month_name(int index)
static int do_script(CFPContext *context)
Definition: cfpython.cpp:1032
static PyObject * getTime(PyObject *self, PyObject *args)
Definition: cfpython.cpp:540
static PyObject * getScriptParameters(PyObject *self, PyObject *args)
Definition: cfpython.cpp:341
static PyObject * addReply(PyObject *self, PyObject *args)
Definition: cfpython.cpp:671
See Bracers.
Definition: object.h:222
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:271
See Scroll.
Definition: object.h:226
#define EVENT_LOGOUT
Player logout.
Definition: events.h:58
#define EVENT_STOP
Thrown object stopped.
Definition: events.h:39
PyObject * Crossfire_Region_wrap(region *what)
#define ATNR_FIRE
Definition: attack.h:49
std::vector< archetype * > players
Definition: player.cpp:501
#define NDI_WHITE
Definition: newclient.h:247
#define ATNR_DISEASE
Definition: attack.h:72
#define EVENT_MAPUNLOAD
A map is freed (includes swapping out)
Definition: events.h:64
#define CFAPI_SYSTEM_FRIENDLY_LIST
Definition: plugin.h:290
void cf_system_unregister_command(command_registration command)
#define AT_INTERNAL
Only used for internal calculations.
Definition: attack.h:101
static void freeContext(CFPContext *context)
Definition: cfpython.cpp:844
static PyObject * getCFPythonVersion(PyObject *self, PyObject *args)
Definition: cfpython.cpp:165
mapstruct * cf_get_empty_map(int sizex, int sizey)
Wrapper for get_empty_map().
static PyModuleDef CrossfireModule
Definition: cfpython.cpp:1475
See Cloak.
Definition: object.h:209
#define ATNR_ACID
Definition: attack.h:53
See Food.
Definition: object.h:117
#define EVENT_PICKUP
Object picked up.
Definition: events.h:36
#define NDI_ORANGE
Definition: newclient.h:250
PyObject * Crossfire_Map_wrap(mapstruct *what)
See Projectile.
Definition: object.h:122
int day
Definition: tod.h:41
static std::vector< std::pair< object *, tag_t > > friends
List of all friendly objects, object and its count.
Definition: friend.cpp:23
#define PACEV2
The monster will pace as above but the length of the pace area is longer and the monster stops before...
Definition: define.h:544
PyTypeObject Crossfire_MapType
sstring message
If not NULL, what the player will be displayed as said.
Definition: dialog.h:53
#define ATNR_WEAPONMAGIC
Definition: attack.h:55
#define NDI_BROWN
Sienna.
Definition: newclient.h:258
See Holy Altar.
Definition: object.h:166
#define AT_CANCELLATION
Removes magic from items (32768) ylitalo@student.docs.uu.se.
Definition: attack.h:93
int level
Definition: readable.cpp:1561
static void freeEventFiles(char **eventFiles)
Clear the list of event files.
Definition: cfpython.cpp:1615
#define ATNR_CONFUSION
Definition: attack.h:52
PyObject * PyInit_cjson(void)
Definition: cjson.cpp:1165
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
See Spellbook.
Definition: object.h:208
static PyObject * getWhoIsActivator(PyObject *self, PyObject *args)
Definition: cfpython.cpp:304
See Money.
Definition: object.h:142
sstring slaying
Which race to do double damage to.
Definition: object.h:327
void cf_system_get_map_vector(int property, std::vector< mapstruct *> *list)
static PyObject * getUniqueDirectory(PyObject *self, PyObject *args)
Definition: cfpython.cpp:257
#define NDI_BLUE
Actually, it is Dodger Blue.
Definition: newclient.h:251
sstring replies[MAX_REPLIES]
Description for replies_words.
Definition: dialog.h:57
#define EVENT_SELLING
Object is being sold by another one.
Definition: events.h:38
See Rune.
Definition: object.h:245
See Creator.
Definition: object.h:147
See Weapon.
Definition: object.h:124
const CFConstant cstMove[]
Definition: cfpython.cpp:1240
See Helmet.
Definition: object.h:141
PyObject * Crossfire_Archetype_wrap(archetype *what)
DIR * opendir(const char *)
Object for applying character class modifications to someone.
Definition: object.h:143
#define ATNR_CHAOS
Definition: attack.h:65
static PyObject * costStringFromValue(PyObject *self, PyObject *args)
Definition: cfpython.cpp:752
static void initConstants(PyObject *module)
Definition: cfpython.cpp:1413
sstring replies_words[MAX_REPLIES]
Available reply words.
Definition: dialog.h:56
See Altar Trigger.
Definition: object.h:138
See Rod.
Definition: object.h:114
#define EVENT_LOGIN
Player login.
Definition: events.h:57
#define AT_COLD
Can freeze objects into ice cubes (16)
Definition: attack.h:82
PyObject * activator
Definition: cfpython.h:97
static PyObject * private_data
Definition: cfpython.cpp:110
int month
Definition: tod.h:40
See Power Crystal.
Definition: object.h:247
See Button Trigger.
Definition: object.h:137
int cf_timer_destroy(int id)
Destroys specified timer, equivalent of calling cftimer_destroy().
Represents the ingame time.
Definition: tod.h:38
PyObject * Crossfire_Object_wrap(object *what)
Python initialized.
See Drink.
Definition: object.h:162
See Girdle.
Definition: object.h:228
static PyObject * findPlayer(PyObject *self, PyObject *args)
Definition: cfpython.cpp:206
#define EVENT_KICK
A player was Kicked by a DM.
Definition: events.h:56
#define ATNR_PARALYZE
Definition: attack.h:59
See Amulet.
Definition: object.h:144
Definition: object.h:254
Wall.
Definition: object.h:196
#define CFAPI_SYSTEM_ARCHETYPES
Definition: plugin.h:287
Duplicator/multiplier object.
Definition: object.h:207
int initPlugin(const char *iversion, f_plug_api gethooksptr)
The server calls this function after loading the plugin.
Definition: cfpython.cpp:1495
#define CIRCLE1
If the upper four bits of move_type / attack_movement are set to this number, the monster will move i...
Definition: define.h:517
#define AT_BLIND
Blinds victim (4194304) thomas@astro.psu.edu.
Definition: attack.h:100
PyTypeObject Crossfire_PlayerType
#define NDI_BLACK
Definition: newclient.h:246
player * cf_player_find(const char *plname)
Wrapper for find_player_partial_name().
sstring cf_add_string(const char *str)
Wrapper for add_string().
animal &#39;body parts&#39; -b.t.
Definition: object.h:192
#define PETMOVE
If the upper four bits of attack_movement are set to this number, the monster follows a player until ...
Definition: define.h:502
static std::unordered_map< std::string, Region * > regions
All defined regions.
Definition: cfcitybell.cpp:44
See Boots.
Definition: object.h:217
#define PERIODS_PER_DAY
Definition: tod.h:20
#define HITRUN
Run to then hit player then run away cyclicly.
Definition: define.h:494
peterm: detector is an object which notices the presense of another object and is triggered like butt...
Definition: object.h:154
static PyObject * registerCommand(PyObject *self, PyObject *args)
Definition: cfpython.cpp:500
#define NDI_DK_ORANGE
DarkOrange2.
Definition: newclient.h:252
See Mover.
Definition: object.h:145
See Wand & Staff.
Definition: object.h:225
PyObject * who
Definition: cfpython.h:96
static PyObject * destroyTimer(PyObject *self, PyObject *args)
Definition: cfpython.cpp:562
CF_PLUGIN int postInitPlugin(void)
The server calls this function to actually initialize the plugin here, after object handlers are regi...
Definition: cfpython.cpp:1670
const CFConstant cstAttackTypeNumber[]
Definition: cfpython.cpp:1301
const char * cf_get_weekday_name(int index)
#define EVENT_ATTACKED
Object attacked, with weapon or spell.
Definition: events.h:29
int cf_find_animation(const char *txt)
Wrapper for find_animation().
void cf_log(LogLevel logLevel, const char *format,...)
Wrapper for LOG().
See Magic Ear.
Definition: object.h:136
#define NDI_NAVY
Definition: newclient.h:248
#define AT_TURN_UNDEAD
Like Fear, but for undead only (8192)
Definition: attack.h:91
static PyObject * getWhoAmI(PyObject *self, PyObject *args)
Definition: cfpython.cpp:293
PyCodeObject * code
Compiled code, NULL if there was an error.
Definition: cfpython.cpp:79
static void log_python_error(void)
Trace a Python error to the Crossfire log.
Definition: cfpython.cpp:893
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:404
#define AT_LIFE_STEALING
16777216 for hp drain
Definition: attack.h:102
Used during character creation.
Definition: object.h:121
Allows the use of a skill.
Definition: object.h:194
void cf_log_plain(LogLevel logLevel, const char *message)
Wrapper for LOG() that uses directly a buffer, without format.
int minute
Definition: tod.h:44
#define ATNR_TURN_UNDEAD
Definition: attack.h:60
#define AT_CHAOS
None by itself, uses random other types (262144) peterm@soda.berkeley.edu.
Definition: attack.h:96
Generic item builder, see subtypes below.
Definition: object.h:251
See Trap.
Definition: object.h:246
const char * cf_get_season_name(int index)
#define RUNATT
Run but attack if player catches up to object.
Definition: define.h:493
#define ATNR_DEATH
Definition: attack.h:64
const CFConstant cstTime[]
Definition: cfpython.cpp:1375
CF_PLUGIN int eventListener(int *type,...)
Handles an object-related event.
Definition: cfpython.cpp:1881
#define NDI_RED
Definition: newclient.h:249
#define AT_GODPOWER
Adds relevant god&#39;s attacktype (1048576) peterm@soda.berkeley.edu.
Definition: attack.h:98
reply_type
Various kind of messages a player or NPC can say.
Definition: dialog.h:7
Floor tile -> native layer 0.
Definition: object.h:191
See Shooting Weapon.
Definition: object.h:123
int periodofday
Definition: tod.h:47
static PyObject * getSharedDictionary(PyObject *self, PyObject *args)
Definition: cfpython.cpp:377
PyObject * Crossfire_Party_wrap(partylist *what)
See Sign & Magic Mouth.
Definition: object.h:216
#define EVENT_CRASH
Triggered when the server crashes.
Definition: events.h:54
Asking a question.
Definition: dialog.h:10
int replies_count
How many items in replies_words and replies.
Definition: dialog.h:55
const CFConstant cstAttackType[]
Definition: cfpython.cpp:1271
int cf_init_plugin(f_plug_api getHooks)
See Book.
Definition: object.h:119
static PyObject * getMonthName(PyObject *self, PyObject *args)
Definition: cfpython.cpp:644
#define ATNR_COLD
Definition: attack.h:51
static PyObject * getPrivateDictionary(PyObject *self, PyObject *args)
Definition: cfpython.cpp:362
See Exit.
Definition: object.h:186
static void addConstants(PyObject *module, const char *name, const CFConstant *constants)
Add constants and a reverse dictionary to get the name from the value.
Definition: cfpython.cpp:1064
#define MAX_REPLIES
How many NPC replies maximum to tell the player.
Definition: dialog.h:43
#define AT_DISEASE
33554432 disease attacktypes
Definition: attack.h:104
static PyObject * setPlayerMessage(PyObject *self, PyObject *args)
Definition: cfpython.cpp:699
time_t cached_time
Time this cache entry was created.
Definition: cfpython.cpp:80
static PyObject * findFace(PyObject *self, PyObject *args)
Definition: cfpython.cpp:580
battleground, by Andreas Vogl
Definition: object.h:168
inserts an invisible, weightless force into a player with a specified string.
Definition: object.h:163
#define MOVE_SWIM
Swimming object.
Definition: define.h:402
See Treasure.
Definition: object.h:115
const CFConstant cstDirection[]
Definition: cfpython.cpp:1112
CF_PLUGIN int closePlugin(void)
called before the plugin gets unloaded from memory.
Definition: cfpython.cpp:1922
See Special Key.
Definition: object.h:129
static PyObject * getParties(PyObject *self, PyObject *args)
Definition: cfpython.cpp:428
#define NDI_ALL_DMS
Inform all logged in DMs.
Definition: newclient.h:272
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:399
Structure used to build up dialog information when a player says something.
Definition: dialog.h:50
A real, living creature.
Definition: object.h:205
static PyObject * findAnimation(PyObject *self, PyObject *args)
Definition: cfpython.cpp:626
inserts an invisible, weightless force into a player with a specified string WHEN TRIGGERED...
Definition: object.h:158
See Clock.
Definition: object.h:120
int dayofweek
Definition: tod.h:42
static PyObject * readyMap(PyObject *self, PyObject *args)
Definition: cfpython.cpp:224
static PyObject * CFPythonError
Definition: cfpython.cpp:90
#define EVENT_MAPRESET
A map is resetting.
Definition: events.h:63
uint64_t command_registration
Identifier when registering a command.
Definition: commands.h:32
void cf_cost_string_from_value(uint64_t cost, int largest_coin, char *buffer, int length)
Wrapper for cost_string_from_value modified to take a char* and length instead of a StringBuffer...
#define ATNR_INTERNAL
Definition: attack.h:70
mapstruct * cf_map_get_map(const char *name, int flags)
Wrapper for ready_map_name().
void cf_system_get_object_vector(int property, std::vector< object *> *list)
#define EVENT_BORN
A new character has been created.
Definition: events.h:52
#define EVENT_GKILL
Triggered when anything got killed by anyone.
Definition: events.h:55
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:401
CF_PLUGIN int cfpython_globalEventListener(int *type,...)
Definition: cfpython.cpp:1705
#define EVENT_CLOCK
Global time event.
Definition: events.h:53
#define ATNR_GODPOWER
Definition: attack.h:67
Reply to something.
Definition: dialog.h:9
#define MAX_COMMANDS
Definition: cfpython.cpp:84
static int GECodes[]
Definition: cfpython.cpp:1564
const CFConstant cstAttackMovement[]
Definition: cfpython.cpp:1392
This is a game-map.
Definition: map.h:320
Definition: object.h:150
#define PLUGIN_NAME
Definition: cfanim.h:32
#define PACEH
The monster will pace back and forth until attacked.
Definition: define.h:525
static PyObject * log_message(PyObject *self, PyObject *args)
Definition: cfpython.cpp:589
#define NDI_GREEN
SeaGreen.
Definition: newclient.h:253
static PyObject * unregisterGEvent(PyObject *self, PyObject *args)
Definition: cfpython.cpp:129
#define ATNR_BLIND
Definition: attack.h:69
#define EVENT_TRIGGER
Button pushed, lever pulled, etc.
Definition: events.h:42
#define EVENT_DESTROY
Object destroyed (includes map reset/swapout)
Definition: events.h:34
void cf_system_register_global_event(int event, const char *name, f_plug_event hook)
#define EVENT_MAPREADY
A map is ready, either first load or after reload.
Definition: events.h:62
static PyObject * getMapHasBeenLoaded(PyObject *self, PyObject *args)
Definition: cfpython.cpp:571
int hour
Definition: tod.h:43
static PyObject * getPlayers(PyObject *self, PyObject *args)
Definition: cfpython.cpp:398
object * ob
The object representing the player.
Definition: player.h:179
int weekofmonth
Definition: tod.h:45
#define EVENT_TELL
A player &#39;tell&#39; something.
Definition: events.h:69
#define EVENT_TIMER
Timer connected triggered it.
Definition: events.h:43
#define EVENT_MAPLEAVE
A player left a map.
Definition: events.h:60
static PyObject * getScriptName(PyObject *self, PyObject *args)
Definition: cfpython.cpp:335
See Trapdoor.
Definition: object.h:215
See Potion.
Definition: object.h:116
#define AT_FIRE
Can ignite objects (4)
Definition: attack.h:80
struct talk_info * talk
Definition: cfpython.h:105
void cf_system_unregister_global_event(int event, const char *name)
See Shop Mat.
Definition: object.h:189
#define NDI_LT_GREEN
DarkSeaGreen, which is actually paler than seagreen - also background color.
Definition: newclient.h:254
static PyObject * PyInit_Crossfire(void)
Definition: cfpython.cpp:1487
time_t used_time
Last use of this cache entry.
Definition: cfpython.cpp:80
char * cf_get_maps_directory(const char *name, char *buf, int size)
Wrapper for create_pathname().
void cf_system_get_party_vector(int property, std::vector< partylist *> *list)
#define AT_PHYSICAL
Basic attack (1)
Definition: attack.h:78
static void cfpython_init_types(PyObject *m)
Set up the various types (map, object, archetype and so on) as well as some constants, and Crossfire.error.
Definition: cfpython.cpp:1434
See Spell.
Definition: object.h:219
#define EVENT_PLAYER_DEATH
Global Death event.
Definition: events.h:66
static PyCodeObject * compilePython(char *filename)
Outputs the compiled bytecode for a given python file, using in-memory caching of bytecode...
Definition: cfpython.cpp:913
See Handle Trigger.
Definition: object.h:134
See Locked Door.
Definition: object.h:128
static const char * getGlobalEventPath(int code)
Definition: cfpython.cpp:1697
static FILE * cfpython_pyfile_asfile(PyObject *obj)
Return a file object from a Python file (as needed for compilePython() and postInitPlugin()) ...
Definition: cfpython.cpp:869
PyTypeObject Crossfire_PartyType
static PyObject * getReturnValue(PyObject *self, PyObject *args)
Definition: cfpython.cpp:173
See Spinner.
Definition: object.h:210
#define ATNR_POISON
Definition: attack.h:57
static PyObject * createCFObjectByName(PyObject *self, PyObject *args)
Definition: cfpython.cpp:152
See Door.
Definition: object.h:131
Many many details.
Definition: logger.h:14
#define ATNR_COUNTERSPELL
Definition: attack.h:66
LogLevel
Log levels for the LOG() function.
Definition: logger.h:10
See Magic Wall.
Definition: object.h:173
#define EVENT_USER
User-defined event.
Definition: events.h:44
static void pushContext(CFPContext *context)
Definition: cfpython.cpp:822
Object owned by a player which can convert a monster into a peaceful being incapable of attack...
Definition: object.h:169
See Converter.
Definition: object.h:221
int cf_find_face(const char *name, int error)
Wrapper for find_face().
static void addSimpleConstants(PyObject *module, const char *name, const CFConstant *constants)
Do half the job of addConstants.
Definition: cfpython.cpp:1096
void cf_system_get_region_vector(int property, std::vector< region *> *list)
can add a skill to player&#39;s inventory -bt.
Definition: object.h:239
#define WAITATT
Wait for player to approach then hit, move if hit.
Definition: define.h:495
static PyObject * getPeriodofdayName(PyObject *self, PyObject *args)
Definition: cfpython.cpp:662
Basic sentence.
Definition: dialog.h:8
Lamp.
Definition: object.h:206
PyObject * third
Definition: cfpython.h:98
#define EVENT_ATTACKS
Weapon or arrow hitting something.
Definition: events.h:30
static PyObject * getTempDirectory(PyObject *self, PyObject *args)
Definition: cfpython.cpp:263
#define EVENT_BOUGHT
Object is being bought by player.
Definition: events.h:31
#define ALLRUN
Always run, never attack good for sim.
Definition: define.h:497
static char ** getEventFiles(CFPContext *context)
Get the list of script files to run for the specified global event context.
Definition: cfpython.cpp:1628
See Container.
Definition: object.h:236
#define EVENT_GSOLD
Player sold object in shop, but global.
Definition: events.h:71
See Player Changer.
Definition: object.h:167
#define AT_DRAIN
Victim loses 2% exp, attacker gains half of that (128)
Definition: attack.h:85
static const flag_definition flags[]
Flag mapping.
static void initContextStack(void)
Definition: cfpython.cpp:817
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Replace in string src all occurrences of key by replacement.
Definition: utils.cpp:327
#define EVENT_CLOSE
Container closed.
Definition: events.h:32
const char * cf_re_cmp(const char *str, const char *regexp)
Wrapper for re_cmp().
static PyObject * getConfigDirectory(PyObject *self, PyObject *args)
Definition: cfpython.cpp:269
See Player.
Definition: object.h:112
See Poison Food.
Definition: object.h:118
static PyObject * getMapDirectory(PyObject *self, PyObject *args)
Definition: cfpython.cpp:251
See Shield.
Definition: object.h:140
#define CFAPI_SYSTEM_PLAYERS
Definition: plugin.h:286
#define EVENT_MAPENTER
A player entered a map.
Definition: events.h:59
See Floor (Encounter).
Definition: object.h:187
#define RUSH
Rush toward player blindly, similiar to dumb monster.
Definition: define.h:496
#define AT_POISON
Some damage each turn thereafter (1024)
Definition: attack.h:88
#define WAIT2
Monster does not try to move towards player if far.
Definition: define.h:499
static PyObject * shared_data
Definition: cfpython.cpp:108
Mark Wedel (mark@pyramid.com) Shop inventories.
Definition: object.h:243
See Altar.
Definition: object.h:127
static event_registration m
Definition: citylife.cpp:424
#define CF_PLUGIN
Definition: plugin_common.h:38
#define MAX_NPC
How many NPCs maximum will reply to the player.
Definition: dialog.h:45
Definition: object.h:248
char message[1024]
Definition: cfpython.h:100
CF_PLUGIN void * getPluginProperty(int *type,...)
The server calls this function to get information about the plugin, notably the name and version...
Definition: cfpython.cpp:1539
Also see SKILL_TOOL (74) below.
Definition: object.h:148
static PyObject * getLocalDirectory(PyObject *self, PyObject *args)
Definition: cfpython.cpp:275
sstring file
Script full path.
Definition: cfpython.cpp:78
#define ATNR_DRAIN
Definition: attack.h:54
sstring name
The name of the object, obviously...
Definition: object.h:319
See Shop Floor.
Definition: object.h:188
#define ATNR_GHOSTHIT
Definition: attack.h:56
#define HOURS_PER_DAY
Definition: tod.h:15
See Button.
Definition: object.h:212
Only for debugging purposes.
Definition: logger.h:13
static PyObject * getWhoIsThird(PyObject *self, PyObject *args)
Definition: cfpython.cpp:315
See Gate.
Definition: object.h:211
#define RANDO2
Constantly move in a different random direction.
Definition: define.h:540
#define AT_FEAR
(16384)
Definition: attack.h:92
misc.
Definition: object.h:198
#define AT_SLOW
Speed is reduced (2048)
Definition: attack.h:89
int year
Definition: tod.h:39
Material for building.
Definition: object.h:253
static PyObject * getWeekdayName(PyObject *self, PyObject *args)
Definition: cfpython.cpp:653
static PyObject * getArchetypes(PyObject *self, PyObject *args)
Definition: cfpython.cpp:384
int season
Definition: tod.h:46
char script[1024]
Definition: cfpython.h:102
PyTypeObject Crossfire_ArchetypeType
#define ATNR_CANCELLATION
Definition: attack.h:62
const CFConstant cstMessageFlag[]
Definition: cfpython.cpp:1251
See Handle.
Definition: object.h:213
struct dirent * readdir(DIR *)
See Timed Gate.
Definition: object.h:133
#define ATNR_MAGIC
Definition: attack.h:48
#define WEEKS_PER_MONTH
Definition: tod.h:17
static PyObject * cfpython_openpyfile(char *filename)
Open a file in the way we need it for compilePython() and postInitPlugin().
Definition: cfpython.cpp:855
mapstruct * cf_map_has_been_loaded(const char *name)
Wrapper for has_been_loaded().
reply_type message_type
A reply_type value for message.
Definition: dialog.h:54
const char * cf_get_directory(int id)
Gets a directory Crossfire uses.
#define EVENT_TIME
Triggered each time the object can react/move.
Definition: events.h:40
static PyObject * getPlayerDirectory(PyObject *self, PyObject *args)
Definition: cfpython.cpp:281
#define NDI_GREY
Definition: newclient.h:257
#define ATNR_HOLYWORD
Definition: attack.h:68
const CFConstant cstReplyTypes[]
Definition: cfpython.cpp:1385
#define AT_MAGIC
All magic spells, but not prayers (2)
Definition: attack.h:79
static PyObject * getWhatIsMessage(PyObject *self, PyObject *args)
Definition: cfpython.cpp:326
PyTypeObject Crossfire_ObjectType
static const char * GEPaths[]
Definition: cfpython.cpp:1587
Lauwenmark: an invisible object holding a plugin event hook.
Definition: object.h:232
static PyObject * matchString(PyObject *self, PyObject *args)
Definition: cfpython.cpp:190
#define DISTATT
Move toward a player if far, but maintain some space, attack from a distance - good for missile users...
Definition: define.h:490
static PyObject * getDataDirectory(PyObject *self, PyObject *args)
Definition: cfpython.cpp:287
PyObject * event
Definition: cfpython.h:99
int closedir(DIR *)
See Monster (Grimreaper).
Definition: object.h:135
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
char options[1024]
Definition: cfpython.h:103
command_registration cf_system_register_command_extra(const char *name, const char *extra, command_function_extra func, uint8_t command_type, float time)
#define EVENT_MAPLOAD
A map is loaded (pristine state)
Definition: events.h:61
See Gloves.
Definition: object.h:218
#define MOVE_FLY_HIGH
High flying object.
Definition: define.h:400
sstring npc_msgs[MAX_NPC]
What the NPCs will say.
Definition: dialog.h:59
One player.
Definition: player.h:107
A force, holding the effect of a resistance potion.
Definition: object.h:230
#define EVENT_APPLY
Object applied-unapplied.
Definition: events.h:28
CF_PLUGIN char SvnRevPlugin[]
Definition: cfpython.cpp:69
static pycode_cache_entry pycode_cache[PYTHON_CACHE_SIZE]
Cached compiled scripts.
Definition: cfpython.cpp:88
static PyObject * registerGEvent(PyObject *self, PyObject *args)
Definition: cfpython.cpp:116
#define PACEH2
The monster will pace as above but the length of the pace area is longer and the monster stops before...
Definition: define.h:528
#define EVENT_MUZZLE
A player was Muzzled (no_shout set).
Definition: events.h:65
StringBuffer * buf
Definition: readable.cpp:1563
metals, minerals, dragon scales
Definition: object.h:193
#define ATNR_DEPLETE
Definition: attack.h:63
static void set_exception(const char *fmt,...)
Set up an Python exception object.
Definition: cfpython.cpp:93
int returnvalue
Definition: cfpython.h:104
#define NDI_TAN
Khaki.
Definition: newclient.h:260
See Pit.
Definition: object.h:214
CFPContext * current_context
Definition: cfpython.cpp:106
#define PACEV
The monster will pace back and forth until attacked.
Definition: define.h:541
#define CFAPI_SYSTEM_PARTIES
Definition: plugin.h:289
#define MONTHS_PER_YEAR
Definition: tod.h:18
#define CIRCLE2
Same as CIRCLE1 but a larger circle is used.
Definition: define.h:524
See Swamp.
Definition: object.h:241
#define CFAPI_SYSTEM_REGIONS
Definition: plugin.h:288
CFPContext * context_stack
Definition: cfpython.cpp:104
const char * sstring
Definition: sstring.h:2
const CFConstant cstEventType[]
Definition: cfpython.cpp:1331
const char * cf_get_periodofday_name(int index)
#define AT_CONFUSION
Movement/attack directions become random (32)
Definition: attack.h:83
#define EVENT_SHOUT
A player &#39;shout&#39; something.
Definition: events.h:68
See Jewel.
Definition: object.h:172
static PyObject * getRegions(PyObject *self, PyObject *args)
Definition: cfpython.cpp:442
PyTypeObject Crossfire_RegionType
void cf_system_get_archetype_vector(int property, std::vector< archetype *> *list)
#define MOVE_BOAT
Boats/sailing.
Definition: define.h:403
One compiled script, cached in memory.
Definition: cfpython.cpp:77
static std::unordered_map< std::string, mapzone * > maps
All defined maps, with the path as key.
Definition: citylife.cpp:91
#define COMMAND_TYPE_NORMAL
Standard commands.
Definition: commands.h:35
#define NDI_GOLD
Definition: newclient.h:259
See Breastplate Armor.
Definition: object.h:125
static PyObject * getMaps(PyObject *self, PyObject *args)
Definition: cfpython.cpp:413
#define AT_ACID
Random equipped item might corrode when hit (64)
Definition: attack.h:84
const CFConstant cstType[]
Definition: cfpython.cpp:1124
Definition: object.h:153
#define AT_DEATH
Chance of instant death, otherwise nothing (131072) peterm@soda.berkeley.edu.
Definition: attack.h:95
See Disease.
Definition: object.h:249
#define EVENT_THROW
Object is thrown.
Definition: events.h:41
object * cf_create_object_by_name(const char *name)
Wrapper for create_archetype() and create_archetype_by_object_name().
static CFPContext * popContext(void)
Definition: cfpython.cpp:832
See Director.
Definition: object.h:227
See Teleporter.
Definition: object.h:146
#define AT_WEAPONMAGIC
Direct damage, very special, use with care (256)
Definition: attack.h:86
#define SEASONS_PER_YEAR
Definition: tod.h:19
static PyObject * npcSay(PyObject *self, PyObject *args)
Definition: cfpython.cpp:722
int event_code
Definition: cfpython.h:101
#define ATNR_LIFE_STEALING
Definition: attack.h:71
void(* f_plug_api)(int *type,...)
General API function.
Definition: plugin.h:79
static PyObject * catcher
A Python object receiving the contents of Python&#39;s stderr, and used to output to the Crossfire log in...
Definition: cfpython.cpp:877
static PyObject * createCFObject(PyObject *self, PyObject *args)
Definition: cfpython.cpp:142
b.t.
Definition: object.h:175
#define DISTHIT
Attack from a distance if hit as recommended by Frank.
Definition: define.h:498
#define ATNR_PHYSICAL
Definition: attack.h:47
#define AT_PARALYZE
Speed is reduced to zero (4096)
Definition: attack.h:90
PyMethodDef CFPythonMethods[]
Definition: cfpython.cpp:765
#define EVENT_DROP
Object dropped on the floor.
Definition: events.h:35
See Savebed.
Definition: object.h:224
static PyObject * getFriendlyList(PyObject *self, PyObject *args)
Definition: cfpython.cpp:456
#define EVENT_GBOUGHT
Player bought object in shop, but global.
Definition: events.h:70
b.t.
Definition: object.h:174
Definition: object.h:229
#define NAME_MAX
NAME_MAX used by random maps may not be defined on pure ansi systems.
Definition: define.h:30
#define EVENT_DEATH
Player or monster dead.
Definition: events.h:33
#define PLUGIN_VERSION
Definition: cfanim.h:33