Go to the documentation of this file.
72 #define PYTHON_CACHE_SIZE 256
77 struct pycode_cache_entry {
84 #define MAX_COMMANDS 1024
98 vsnprintf(
buf,
sizeof(
buf), fmt, arg);
101 PyErr_SetString(PyExc_ValueError,
buf);
120 if (!PyArg_ParseTuple(
args,
"i", &eventcode))
133 if (!PyArg_ParseTuple(
args,
"i", &eventcode))
157 if (!PyArg_ParseTuple(
args,
"s", &obname))
170 return Py_BuildValue(
"i", i);
183 if (!PyArg_ParseTuple(
args,
"i", &i))
196 if (!PyArg_ParseTuple(
args,
"ss", &premiere, &seconde))
201 return Py_BuildValue(
"i", 1);
203 return Py_BuildValue(
"i", 0);
211 if (!PyArg_ParseTuple(
args,
"s", &txt))
243 if (!PyArg_ParseTuple(
args,
"ii", &sizex, &sizey))
330 return Py_BuildValue(
"");
386 std::vector<archetype *> archs;
391 list = PyList_New(0);
392 for (
auto arch : archs) {
406 list = PyList_New(0);
415 std::vector<mapstruct *>
maps;
421 list = PyList_New(0);
430 std::vector<partylist *> parties;
435 list = PyList_New(0);
436 for (
auto party : parties) {
449 list = PyList_New(0);
463 list = PyList_New(0);
481 context->
third = NULL;
483 context->
event = NULL;
507 if (!PyArg_ParseTuple(
args,
"ssd|i", &cmdname, &scriptname, &cmdspeed, &
type))
532 set_exception(
"failed to register command (overriding an existing one with a different type?)");
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));
556 PyList_Append(
list, Py_BuildValue(
"i", tod.
season));
566 if (!PyArg_ParseTuple(
args,
"i", &
id))
575 if (!PyArg_ParseTuple(
args,
"s", &
name))
584 if (!PyArg_ParseTuple(
args,
"s", &
name))
595 if (!PyArg_ParseTuple(
args,
"is", &intLevel, &
message))
630 if (!PyArg_ParseTuple(
args,
"s", &
name))
639 if (!PyArg_ParseTuple(
args,
"i", &i))
648 if (!PyArg_ParseTuple(
args,
"i", &i))
657 if (!PyArg_ParseTuple(
args,
"i", &i))
666 if (!PyArg_ParseTuple(
args,
"i", &i))
682 if (!PyArg_ParseTuple(
args,
"ss", &word, &
reply)) {
741 cf_log(
llevError,
"CFPython: warning, too long message in npcSay, will be truncated");
755 int largest_coin = 0;
758 if (!PyArg_ParseTuple(
args,
"L|i", &
value, &largest_coin))
762 return Py_BuildValue(
"s",
buf);
766 {
"WhoAmI",
getWhoAmI, METH_NOARGS, NULL },
772 {
"WhatIsEvent",
getEvent, 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 },
791 {
"GetPlayers",
getPlayers, METH_NOARGS, NULL },
793 {
"GetMaps",
getMaps, METH_NOARGS, NULL },
794 {
"GetParties",
getParties, METH_NOARGS, NULL },
795 {
"GetRegions",
getRegions, METH_NOARGS, NULL },
800 {
"GetTime",
getTime, METH_NOARGS, NULL },
804 {
"FindFace",
findFace, METH_VARARGS, NULL },
810 {
"AddReply",
addReply, METH_VARARGS, NULL },
812 {
"NPCSay",
npcSay, METH_VARARGS, NULL },
814 { NULL, NULL, 0, NULL }
825 context->
down = NULL;
845 Py_XDECREF(context->
event);
846 Py_XDECREF(context->
third);
847 Py_XDECREF(context->
who);
856 PyObject *scriptfile;
861 scriptfile = PyFile_FromFd(fd,
filename,
"r", -1, NULL, NULL, NULL, 1);
870 return fdopen(PyObject_AsFileDescriptor(
obj),
"r");
884 static PyObject *io_module = NULL;
899 PyObject*
empty = PyUnicode_FromString(
"");
914 PyObject *scriptfile = NULL;
916 struct stat stat_buf;
960 if (
replace->file != sh_path) {
978 io_module = PyImport_ImportModule(
"io");
979 scriptfile = PyObject_CallMethod(io_module,
"open",
"ss",
filename,
"rb");
985 PyObject *source_bytes = PyObject_CallMethod(scriptfile,
"read",
"");
986 (
void)PyObject_CallMethod(scriptfile,
"close",
"");
987 PyObject *
code = Py_CompileString(PyBytes_AsString(source_bytes),
filename, Py_file_input);
991 if (PyErr_Occurred())
994 replace->cached_time = stat_buf.st_mtime;
1008 if ((
n = PyParser_SimpleParseFile(pyfile,
filename, Py_file_input))) {
1012 if (PyErr_Occurred())
1015 replace->cached_time = stat_buf.st_mtime;
1024 Py_DECREF(scriptfile);
1027 assert(run != NULL);
1028 run->used_time =
time(NULL);
1033 PyCodeObject *pycode;
1042 dict = PyDict_New();
1043 PyDict_SetItemString(
dict,
"__builtins__", PyEval_GetBuiltins());
1044 ret = PyEval_EvalCode((PyObject *)pycode,
dict, NULL);
1045 if (PyErr_Occurred()) {
1068 snprintf(
tmp,
sizeof(
tmp),
"Crossfire_%s",
name);
1070 cst = PyModule_New(
tmp);
1071 dict = PyDict_New();
1073 while (constants[i].
name != NULL) {
1074 PyModule_AddIntConstant(cst, (
char *)constants[i].
name, constants[i].
value);
1075 PyDict_SetItem(
dict, PyLong_FromLong(constants[i].
value), PyUnicode_FromString(constants[i].
name));
1078 PyDict_SetItemString(PyModule_GetDict(module),
name, cst);
1081 PyDict_SetItemString(PyModule_GetDict(module),
tmp,
dict);
1099 snprintf(
tmp,
sizeof(
tmp),
"Crossfire_%s",
name);
1101 cst = PyModule_New(
tmp);
1103 while (constants[i].
name != NULL) {
1104 PyModule_AddIntConstant(cst, (
char *)constants[i].
name, constants[i].
value);
1107 PyDict_SetItemString(PyModule_GetDict(module),
name, cst);
1431 PyObject *
d = PyModule_GetDict(
m);
1460 PyModule_AddObject(
m,
"LogError", Py_BuildValue(
"i",
llevError));
1461 PyModule_AddObject(
m,
"LogInfo", Py_BuildValue(
"i",
llevInfo));
1462 PyModule_AddObject(
m,
"LogDebug", Py_BuildValue(
"i",
llevDebug));
1463 PyModule_AddObject(
m,
"LogMonster", Py_BuildValue(
"i",
llevMonster));
1465 CFPythonError = PyErr_NewException(
"Crossfire.error", NULL, NULL);
1472 PyModuleDef_HEAD_INIT,
1494 const char *stdOutErr =
1496 class CatchOutErr:\n\
1497 def __init__(self):\n\
1499 def write(self, txt):\n\
1500 self.value += txt\n\
1501 catchOutErr = CatchOutErr()\n\
1502 sys.stdout = catchOutErr\n\
1503 sys.stderr = catchOutErr\n\
1519 m = PyImport_ImportModule(
"Crossfire");
1529 m = PyImport_AddModule(
"__main__");
1530 PyRun_SimpleString(stdOutErr);
1531 catcher = PyObject_GetAttrString(
m,
"catchOutErr");
1537 const char *propname;
1542 propname = va_arg(
args,
const char *);
1543 if (!strcmp(propname,
"Identification")) {
1545 size = va_arg(
args,
int);
1549 }
else if (!strcmp(propname,
"FullName")) {
1551 size = va_arg(
args,
int);
1609 for (
int e = 0; eventFiles[e] != NULL; e++) {
1610 free(eventFiles[e]);
1621 char **eventFiles = NULL;
1624 int allocated = 0,
current = 0;
1634 eventFiles =
static_cast<char **
>(calloc(1,
sizeof(eventFiles[0])));
1635 eventFiles[0] = NULL;
1639 while ((
d =
readdir(dp)) != NULL) {
1642 if (S_ISDIR(sb.st_mode)) {
1645 if (strcmp(
d->d_name + strlen(
d->d_name) - 3,
".py")) {
1651 eventFiles =
static_cast<char **
>(realloc(eventFiles,
sizeof(
char *) * (allocated + 1)));
1652 for (
int i =
current; i < allocated + 1; i++) {
1653 eventFiles[i] = NULL;
1664 PyObject *scriptfile;
1670 for (i = 0;
GECodes[i] != 0; i++)
1674 if (scriptfile != NULL) {
1677 Py_DECREF(scriptfile);
1691 for (
int i = 0;
GECodes[i] != 0; i++) {
1720 op = va_arg(
args,
object *);
1725 op = va_arg(
args,
object *);
1727 op = va_arg(
args,
object *);
1733 op = va_arg(
args,
object *);
1757 op = va_arg(
args,
object *);
1762 op = va_arg(
args,
object *);
1770 op = va_arg(
args,
object *);
1778 op = va_arg(
args,
object *);
1786 op = va_arg(
args,
object *);
1792 op = va_arg(
args,
object *);
1805 op = va_arg(
args,
object *);
1810 op = va_arg(
args,
object *);
1837 (*copy) = (*context);
1839 Py_XINCREF(copy->
event);
1840 Py_XINCREF(copy->
third);
1841 Py_XINCREF(copy->
who);
1886 event = va_arg(
args,
object *);
void cf_cost_string_from_value(uint64_t cost, int largest_coin, char *buffer, int length)
static PyObject * findPlayer(PyObject *self, PyObject *args)
static PyObject * getMonthName(PyObject *self, PyObject *args)
void cf_log(LogLevel logLevel, const char *format,...)
const CFConstant cstMove[]
#define ATNR_CANCELLATION
static PyObject * getCFPythonVersion(PyObject *self, PyObject *args)
static PyObject * shared_data
const char * cf_get_weekday_name(int index)
sstring cf_add_string(const char *str)
sstring replies[MAX_REPLIES]
static PyObject * getSeasonName(PyObject *self, PyObject *args)
const char * cf_get_directory(int id)
static PyObject * getLocalDirectory(PyObject *self, PyObject *args)
const char * cf_get_season_name(int index)
sstring replies_words[MAX_REPLIES]
static PyCodeObject * compilePython(char *filename)
based on the size of the this randomly makes land number of spaces randomly lower or higher The default is Note that this is run also based on the the altitude amount will likely be less So if you do something like l and n
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
static event_registration c
CF_PLUGIN int postInitPlugin(void)
CF_PLUGIN int eventListener(int *type,...)
object * cf_create_object_by_name(const char *name)
static PyObject * setPlayerMessage(PyObject *self, PyObject *args)
static PyObject * CFPythonError
static CFPContext * popContext(void)
static PyObject * getPrivateDictionary(PyObject *self, PyObject *args)
int cf_timer_destroy(int id)
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
#define CFAPI_SYSTEM_ARCHETYPES
static PyObject * getConfigDirectory(PyObject *self, PyObject *args)
int initPlugin(const char *iversion, f_plug_api gethooksptr)
PyObject * Crossfire_Party_wrap(partylist *what)
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
static const flag_definition flags[]
static PyObject * createCFObject(PyObject *self, PyObject *args)
static PyObject * registerCommand(PyObject *self, PyObject *args)
static pycode_cache_entry pycode_cache[PYTHON_CACHE_SIZE]
static void pushContext(CFPContext *context)
#define COMMAND_TYPE_NORMAL
#define CFAPI_SYSTEM_PLAYERS
static char ** getEventFiles(CFPContext *context)
static std::vector< std::pair< object *, tag_t > > friends
void Handle_Map_Unload_Hook(Crossfire_Map *map)
CFPContext * current_context
PyObject * Crossfire_Object_wrap(object *what)
const CFConstant cstMessageFlag[]
Plugin animator file specs[Config] name
void cf_system_get_region_vector(int property, std::vector< region * > *list)
static PyObject * getDataDirectory(PyObject *self, PyObject *args)
PyTypeObject Crossfire_PlayerType
static event_registration m
CF_PLUGIN void * getPluginProperty(int *type,...)
DIR * opendir(const char *)
static PyObject * setReturnValue(PyObject *self, PyObject *args)
void cf_log_plain(LogLevel logLevel, const char *message)
static PyObject * getArchetypes(PyObject *self, PyObject *args)
static PyObject * getMapHasBeenLoaded(PyObject *self, PyObject *args)
static const char * GEPaths[]
static PyObject * getMapDirectory(PyObject *self, PyObject *args)
int cf_find_face(const char *name, int error)
static PyObject * findFace(PyObject *self, PyObject *args)
void(* f_plug_api)(int *type,...)
const CFConstant cstDirection[]
static PyObject * npcSay(PyObject *self, PyObject *args)
void cf_system_unregister_global_event(int event, const char *name)
const char * cf_get_month_name(int index)
int cf_init_plugin(f_plug_api getHooks)
struct dirent * readdir(DIR *)
mapstruct * cf_get_empty_map(int sizex, int sizey)
static PyObject * unregisterGEvent(PyObject *self, PyObject *args)
static void addSimpleConstants(PyObject *module, const char *name, const CFConstant *constants)
static PyObject * costStringFromValue(PyObject *self, PyObject *args)
CF_PLUGIN char SvnRevPlugin[]
static int do_script(CFPContext *context)
static PyObject * getSharedDictionary(PyObject *self, PyObject *args)
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your message
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the script
static PyObject * createMap(PyObject *self, PyObject *args)
static void set_exception(const char *fmt,...)
static PyObject * catcher
this information may not reflect the current implementation This brief document is meant to describe the operation of the crossfire as well as the form of the data The metaserver listens on port for tcp and on port for udp packets The server sends updates to the metaserver via udp The metaserver only does basic checking on the data that server sends It trusts the server for the ip name it provides The metaserver does add the ip address and also tracks the idle time(time since last packet received). The client gets its information from the metaserver through connecting by means of tcp. The client should retrieve http the body s content type is text plain The current metaserver implementation is in Perl But the metaserver could be in any language perl is fast enough for the amount of data that is being exchanged The response includes zero or more server entries Each entry begins with the line START_SERVER_DATA and ends with the line END_SERVER_DATA Between these lines key value pairs("key=value") may be present. The entries are sent in arbitrary order. A client should apply some ordering when displaying the entries to the user. TODO b additional information outside BEGIN_SERVER_DATA END_SERVER_DATA maps
PyObject * Crossfire_Archetype_wrap(archetype *what)
static PyObject * getFriendlyList(PyObject *self, PyObject *args)
static command_registration registered_commands[MAX_COMMANDS]
#define ATNR_COUNTERSPELL
CF_PLUGIN int closePlugin(void)
static PyObject * getPlayers(PyObject *self, PyObject *args)
#define CFAPI_SYSTEM_MAPS
PyObject * Crossfire_Region_wrap(region *what)
#define CFAPI_SYSTEM_REGIONS
static PyObject * getUniqueDirectory(PyObject *self, PyObject *args)
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for d
static PyObject * matchString(PyObject *self, PyObject *args)
void cf_free_string(sstring str)
const CFConstant cstTime[]
#define COMMAND_TYPE_WIZARD
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
static PyObject * destroyTimer(PyObject *self, PyObject *args)
#define EVENT_PLAYER_DEATH
static FILE * cfpython_pyfile_asfile(PyObject *obj)
const CFConstant cstType[]
command_registration cf_system_register_command_extra(const char *name, const char *extra, command_function_extra func, uint8_t command_type, float time)
static PyObject * getPlayerDirectory(PyObject *self, PyObject *args)
static PyObject * getWeekdayName(PyObject *self, PyObject *args)
static PyObject * getMaps(PyObject *self, PyObject *args)
const CFConstant cstReplyTypes[]
void cf_system_get_object_vector(int property, std::vector< object * > *list)
void cf_system_register_global_event(int event, const char *name, f_plug_event hook)
static PyObject * cfpython_openpyfile(char *filename)
static PyObject * getTempDirectory(PyObject *self, PyObject *args)
int cf_find_animation(const char *txt)
static PyObject * getReturnValue(PyObject *self, PyObject *args)
PyMethodDef CFPythonMethods[]
PyTypeObject Crossfire_PartyType
#define CFAPI_SYSTEM_FRIENDLY_LIST
std::vector< archetype * > players
const char * cf_get_periodofday_name(int index)
static PyObject * getWhatIsMessage(PyObject *self, PyObject *args)
static PyObject * getScriptName(PyObject *self, PyObject *args)
static PyModuleDef CrossfireModule
static void python_command_function(object *op, const char *params, const char *script)
static const char * getGlobalEventPath(int code)
void cf_system_get_map_vector(int property, std::vector< mapstruct * > *list)
static PyObject * createCFObjectByName(PyObject *self, PyObject *args)
const CFConstant cstAttackType[]
const typedef char * sstring
const CFConstant cstAttackTypeNumber[]
PyTypeObject Crossfire_ArchetypeType
mapstruct * cf_map_has_been_loaded(const char *name)
const char * cf_re_cmp(const char *str, const char *regexp)
static PyObject * getRegions(PyObject *self, PyObject *args)
static PyObject * readyMap(PyObject *self, PyObject *args)
static PyObject * getParties(PyObject *self, PyObject *args)
object * cf_create_object(void)
char * cf_get_maps_directory(const char *name, char *buf, int size)
static void freeEventFiles(char **eventFiles)
static void cfpython_init_types(PyObject *m)
static std::unordered_map< std::string, Region * > regions
static PyObject * addReply(PyObject *self, PyObject *args)
static void initConstants(PyObject *module)
static PyObject * getWhoIsThird(PyObject *self, PyObject *args)
static PyObject * getScriptParameters(PyObject *self, PyObject *args)
sstring npc_msgs[MAX_NPC]
PyTypeObject Crossfire_RegionType
void cf_system_get_archetype_vector(int property, std::vector< archetype * > *list)
player * cf_player_find(const char *plname)
void cf_system_unregister_command(command_registration command)
#define PYTHON_CACHE_SIZE
#define CFAPI_SYSTEM_PARTIES
CFPContext * context_stack
event
DIALOGCHECK MINARGS 1 MAXARGS 2
uint64_t command_registration
mapstruct * cf_map_get_map(const char *name, int flags)
Crossfire Architecture the general intention is to enhance the enjoyability and playability of CF In this code
void cf_system_get_party_vector(int property, std::vector< partylist * > *list)
static PyObject * registerGEvent(PyObject *self, PyObject *args)
const CFConstant cstAttackMovement[]
static PyObject * log_message(PyObject *self, PyObject *args)
static PyObject * getWhoAmI(PyObject *self, PyObject *args)
static void log_python_error(void)
static PyObject * getTime(PyObject *self, PyObject *args)
static void addConstants(PyObject *module, const char *name, const CFConstant *constants)
PyObject * Crossfire_Map_wrap(mapstruct *what)
static PyObject * private_data
#define ATNR_LIFE_STEALING
PyTypeObject Crossfire_ObjectType
static PyObject * getPeriodofdayName(PyObject *self, PyObject *args)
const CFConstant cstEventType[]
PyObject * PyInit_cjson(void)
CF_PLUGIN int cfpython_globalEventListener(int *type,...)
static PyObject * getWhoIsActivator(PyObject *self, PyObject *args)
static PyObject * PyInit_Crossfire(void)
static void initContextStack(void)
void cf_get_time(timeofday_t *tod)
static PyObject * findAnimation(PyObject *self, PyObject *args)
static PyObject * getEvent(PyObject *self, PyObject *args)
static void freeContext(CFPContext *context)
PyTypeObject Crossfire_MapType