Go to the documentation of this file.
48 static const int shutdown_warn_times[] = {120, 90, 60, 45, 30, 15, 10, 5, 4, 3, 2, 1};
51 static const char *
days[] = {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"};
75 #if (defined(__FreeBSD__))
87 static const char *
const c =
88 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
116 if (strlen(crypted) == 0) {
117 return strlen(typed) == 0 ? true :
false;
120 const char *typed_hashed =
crypt_string(typed, crypted);
121 if (typed_hashed != NULL) {
122 return strcmp(typed_hashed, crypted) == 0;
124 LOG(
llevError,
"Could not check password with stored hash %s\n", crypted);
153 if (oldmap ==
op->map && strcmp(
op->contr->savebed_map, oldmap->
path)) {
154 LOG(
llevDebug,
"Player %s savebed location %s is invalid - going to emergency location (%s)\n",
185 if (x < 0 && y >= 0)
x=0;
186 if (y < 0 && x >= 0)
y=0;
189 if (
x != -1 ||
y != -1) {
190 LOG(
llevError,
"enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", newmap->
path,
x,
y);
202 "The exit is closed");
226 LOG(
llevInfo,
"enter_map: Could not find free spot for player - will dump on top of object (%s: %d, %d)\n", newmap->
path,
x,
y);
242 sizeof(
op->contr->maplevel));
243 op->contr->count = 0;
254 op->contr->golem_count = 0;
271 if (oldmap != newmap) {
280 if (oldmap != NULL) {
337 for (cp = newpath; *cp !=
'\0'; cp++) {
364 cp =
const_cast<char *
>(strrchr(src,
'/'));
370 for (cp = newpath; *cp !=
'\0'; cp++) {
389 static int reference_number = 0;
392 memset(&rp, 0,
sizeof(
RMParms));
417 while (isdigit(
buf[strlen(
buf)-1]))
422 snprintf(newmap_name,
sizeof(newmap_name),
"/random/%s%04d", cp+1, reference_number++);
470 sourcemap = strchr(exitpath,
'!');
476 LOG(
llevError,
"enter_fixed_template_map: Exit %s (%d,%d) on map %s has no source template.\n", exit_ob->
name, exit_ob->
x, exit_ob->
y, exit_ob->
map->
path);
487 sourcemap = sourcemap_buf;
493 snprintf(tmpnum,
sizeof(tmpnum),
"%d", exit_ob->
x);
494 replace(exitpath,
"%x", tmpnum, resultname,
sizeof(resultname));
496 snprintf(tmpnum,
sizeof(tmpnum),
"%d", exit_ob->
y);
497 strlcpy(tmpstring, resultname,
sizeof(tmpstring));
498 replace(tmpstring,
"%y", tmpnum, resultname,
sizeof(resultname));
500 strlcpy(tmpstring, resultname,
sizeof(tmpstring));
501 replace(tmpstring,
"%n", exit_ob->
map->
name, resultname,
sizeof(resultname));
525 "Template exit in '%s' (%d, %d) does not reference a valid "
526 "template. Make sure a template exists at '%s'.\n",
559 snprintf(tmpnum,
sizeof(tmpnum),
"%d", exit_ob->
x);
560 replace(
EXIT_PATH(exit_ob)+3,
"%x", tmpnum, resultname,
sizeof(resultname));
562 snprintf(tmpnum,
sizeof(tmpnum),
"%d", exit_ob->
y);
563 strlcpy(tmpstring, resultname,
sizeof(tmpstring));
564 replace(tmpstring,
"%y", tmpnum, resultname,
sizeof(resultname));
566 strlcpy(tmpstring, resultname,
sizeof(tmpstring));
567 replace(tmpstring,
"%n", exit_ob->
map->
name, resultname,
sizeof(resultname));
580 memset(&rp, 0,
sizeof(
RMParms));
633 char* src = strdup(
op->map->path);
634 char* slash = strrchr(src,
'/');
645 if ((cp = strrchr(tmpc,
'_')) != NULL)
659 snprintf(apartment,
sizeof(apartment),
"~%s/%s",
op->name,
clean_path(reldir,
path,
sizeof(
path)));
685 LOG(
llevDebug,
"enter_unique_map: Exit %s (%d,%d) on map %s is leads no where.\n", exit_ob->
name, exit_ob->
x, exit_ob->
y, exit_ob->
map->
path);
703 LOG(
llevError,
"Fatal: Could not load emergency map!\n");
708 "You find yourself somewhere unexpected...");
713 if (
x == -1 &&
y == -1) {
735 #define PORTAL_DESTINATION_NAME "Town portal destination"
743 assert(exit_ob != NULL);
756 "You feel a force fizzling away. You feel a vibration from: %s",
buf);
763 if (
op->contr->transport)
801 if (!newmap && !strncmp(
EXIT_PATH(exit_ob),
"/random/", 8)) {
845 if (
x == -1 &&
y == -1) {
878 exit_copy->
speed = 0;
880 exit_copy->
map = exit_ob->
map;
881 if (
op->contr->last_exit) {
884 op->contr->last_exit = exit_copy;
909 int sx, sy, sx2, sy2;
911 return (
ob->x >=
x+sx2) && (
ob->x <=
x+sx) && (
ob->y >=
y+sy2) && (
ob->y <=
y+sy);
918 assert(
pl->followed_player != NULL);
920 if (followed && followed->
ob && followed->
ob->
map) {
937 "%s stops letting you follow them.",
pl->followed_player);
953 "You stop following %s.",
pl->followed_player);
968 for (flag = 1; flag != 0; ) {
980 if (!flag)
pl->ticks_played++;
982 if (
pl->followed_player) {
986 if (
pl->ob->speed_left > 0) {
1010 pl->last_save_tick += 100;
1023 pl->ob->weapon_speed_left +=
pl->ob->weapon_speed;
1024 if (
pl->ob->weapon_speed_left > 1.0)
1025 pl->ob->weapon_speed_left = 1.0;
1027 pl->socket->sounds_this_tick = 0;
1030 if (
pl->ob->casting_time > 0) {
1031 pl->ob->casting_time--;
1038 if (has_action &&
pl->ob->speed_left > 0) {
1039 pl->ob->last_heal -= 2;
1040 pl->ob->last_sp -= 2;
1041 pl->ob->last_grace -= 2;
1042 pl->ob->last_eat += 2;
1071 }
else if (
pl->ob->speed_left >
pl->ob->speed)
1072 pl->ob->speed_left =
pl->ob->speed;
1079 return op->env != NULL && strcmp(
op->env->arch->name,
"icecube") == 0;
1092 memset(&marker, 0,
sizeof(
object));
1108 if (
op->active_prev)
1109 op->active_prev->active_next =
op;
1118 op->active_next = ▮
1122 LOG(
llevError,
"BUG: process_events(): Free object on list\n");
1145 LOG(
llevError,
"BUG: process_events(): Removed object on list\n");
1156 LOG(
llevError,
"BUG: process_events(): Object %s has no speed, but is on active list\n",
op->arch->name);
1164 &&
op->type !=
MAP) {
1165 LOG(
llevError,
"BUG: process_events(): Object without map or inventory is on active list: %s (%d)\n",
op->name,
op->count);
1179 LOG(
llevError,
"BUG: process_events(): Processing object on swapped out map: %s (%d), map=%s\n",
op->name,
op->count,
op->map->path);
1185 if ((
op->anim_speed &&
op->last_anim >=
op->anim_speed)
1186 || (
op->temp_animation &&
op->last_anim >=
op->temp_anim_speed)) {
1197 if (
op->speed_left > 0) {
1204 op->speed_left -= 10;
1206 op->speed_left -= 1;
1312 LOG(
llevInfo,
"logout: %s from %s\n",
pl->ob->name,
pl->socket->host);
1314 strcpy(
pl->ob->contr->killer,
"left");
1321 if (
pl->transport &&
pl->transport->contr ==
pl) {
1325 if (
pl->transport->inv)
1326 pl->transport->contr =
pl->transport->inv->contr;
1328 pl->transport->contr = NULL;
1330 if (
pl->transport->contr) {
1336 "%s has left. You are now the captain of %s",
1355 "%s left the game.",
1367 #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
1372 int i, start,
stop, forbit = 0;
1375 tm = (
struct tm *)localtime(&clock);
1378 if ((fp = fopen(
buf,
"r")) == NULL)
1381 while (fgets(
buf,
sizeof(
buf), fp)) {
1384 if (!strncmp(
buf,
"msg", 3)) {
1386 while (fgets(
buf,
sizeof(
buf), fp))
1389 }
else if (sscanf(
buf,
"%s %d%*c%d\n", day, &start, &
stop) != 3) {
1390 LOG(
llevDebug,
"Warning: Incomplete line in permission file ignored.\n");
1394 for (i = 0; i < 7; i++) {
1396 && (tm->tm_wday == i)
1397 && (tm->tm_hour >= start)
1398 && (tm->tm_hour <
stop))
1435 LOG(
llevInfo,
"Received SIGINT; shutting down...\n");
1452 LOG(
llevInfo,
"No active players in the last %ld seconds, shutting down...\n", diff);
1480 if (time_left <= 0) {
1498 "This server will shut down when all players leave.");
1508 "This server will shut down in %lu minutes.", time_left / 60);
1589 if (getuid() == 0 || geteuid() == 0) {
1591 "Running crossfire-server as root is a bad idea; aborting!\n"
1592 "Please run it again as a normal, unprivileged user.\n");
1597 #ifdef DEBUG_MALLOC_LEVEL
1598 malloc_debug(DEBUG_MALLOC_LEVEL);
1604 PROFILE_END(diff,
LOG(
llevInfo,
"Initialization complete (%ld ms). Waiting for connections.\n", diff/1000));
void write_book_archive(void)
#define object_was_destroyed(op, old_tag)
static bool check_shutdown(void)
int handle_newcs_player(object *op)
#define FREE_OBJ_NO_DESTROY_CALLBACK
void clean_tmp_files(void)
void tick_the_clock(void)
void remove_friendly_object(object *op)
void pets_terminate_all(object *owner)
void enter_player_savebed(object *op)
#define MSG_TYPE_ADMIN_PLAYER
void LOG(LogLevel logLevel, const char *format,...)
void free_all_readable(void)
void object_free_all_data(void)
static void enter_map(object *op, mapstruct *newmap, int x, int y)
mapstruct * ready_map_name(const char *name, int flags)
#define QUERY_FLAG(xyz, p)
void flush_old_maps(void)
void set_map_timeout(mapstruct *oldmap)
static event_registration c
StringBuffer * stringbuffer_new(void)
void object_set_enemy(object *op, object *enemy)
static void do_follow(player *pl)
int set_random_map_variable(RMParms *rp, const char *buf)
static void enter_random_map(object *pl, object *exit_ob)
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
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
int move_player(object *op, int dir)
void free_all_newserver(void)
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
static const flag_definition flags[]
void object_copy(const object *src_ob, object *dest_ob)
#define MAP_PLAYER_UNIQUE
#define PROFILE_BEGIN(expr)
void free_knowledge(void)
mapstruct * generate_random_map(const char *OutFileName, RMParms *RP, char **use_layout, sstring reset_group)
void cleanupPlugins(void)
void enter_player_maplevel(object *op)
void party_obsolete_parties(void)
void hiscore_check(object *op, int quiet)
static int query_flag(const object *op, int flag)
static int move_towards(object *ob, object *towards, unsigned int mindist)
Plugin animator file specs[Config] name
#define MSG_TYPE_ADMIN_DM
#define PROFILE_END(var, expr)
static event_registration m
char * stringbuffer_finish(StringBuffer *sb)
void apply_auto_fix(mapstruct *m)
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For most everything that is sent is text This is more or less how things worked under except it packed the ints into bytes in a known order In some we handle ints as in they are sent as binary information How any command handles it is detailed below in the command description The S and C represent the direction of the we use MSB as well as any ints or shorts that get sent inside the packets All packets are defined to have at least one word of followed by a space
void login_check_shutdown(object *const op)
void object_free_drop_inventory(object *ob)
void write_todclock(void)
void final_free_player(player *pl)
short freearr_y[SIZEOFFREE]
static char * clean_path(const char *file, char *newpath, int size)
void query_name(const object *op, char *buf, size_t size)
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
void free_all_artifacts(void)
void clean_friendly_list(void)
void object_dump(const object *op, StringBuffer *sb)
void party_leave(object *op)
sstring add_string(const char *str)
#define FOR_OB_AND_BELOW_FINISH()
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
void clean_tmp_map(mapstruct *m)
void process_events(void)
void server_main(int argc, char *argv[])
int out_of_map(mapstruct *m, int x, int y)
static void do_specials(void)
#define PORTAL_DESTINATION_NAME
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
void object_update_speed(object *op)
static bool object_on_exit(object *ob, object *exit)
void enter_exit(object *op, object *exit_ob)
char const * newhash(char const *password)
void object_free(object *ob, int flags)
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 it tries to load all available files in the SHARE plugins directory as plugin libraries It first displays the Initializing the plugin has the opportunity to signal itself by a message on the console Then the server displays an informative message containing both the plugin content and its keyword For the Python the standard load process thus GreenGoblin When a plugin has been it can request to be warned whenever a global event and are named freely by the developer If the directory doesn t nothing will happen< event name > can be init
#define FOR_OB_AND_BELOW_PREPARE(op_)
static void process_players1(void)
void cftimer_process_timers(void)
static bool object_in_icecube(object *op)
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
void create_template_pathname(const char *name, char *buf, size_t size)
volatile sig_atomic_t shutdown_flag
void free_all_recipes(void)
size_t strlcpy(char *dst, const char *src, size_t size)
object * object_new(void)
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
void free_string(sstring str)
#define FREE_AND_CLEAR_STR(xyz)
void free_quest_definitions(void)
static void enter_unique_map(object *op, object *exit_ob)
#define MSG_TYPE_COMMAND_FAILURE
bool can_follow(object *, player *)
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
int find_dir_2(int x, int y)
void pets_attempt_follow(object *for_owner, int force)
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
int swap_map(mapstruct *map)
#define MSG_TYPE_SPELL_FAILURE
void free_style_maps(void)
bool check_password(const char *typed, const char *crypted)
static const int shutdown_warn_times[]
#define ST_CONFIRM_PASSWORD
void metaserver_update(void)
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
static void save_and_kick_all_players(void)
char * create_pathname(const char *name, char *buf, size_t size)
void write_cs_stats(void)
void animate_object(object *op, int dir)
void update_players(void)
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
static void enter_random_template_map(object *pl, object *exit_ob)
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
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 click edit and change the line script options(which currently is "GUILD_TEMPALTE") to the guild you wish to use. And make sure you use the same one for all of them or it won 't work. Here 's a quick HOWTO for using the map editor to make these changes edit the mainfloor map exit(x15, y29 - set to/Edit/This/Exit/Path in the template) back to the world map as well. If you are using the Storage Hall map(storage_hall)
method_ret ob_apply(object *op, object *applier, int aflags)
player * find_player_partial_name(const char *plname)
void map_newmap_cmd(socket_struct *ns)
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
region * get_region_by_map(mapstruct *m)
int save_player(object *op, int flag)
void process_object(object *op)
void object_remove(object *op)
struct shutdown_s shutdown_state
void leave(player *pl, int draw_exit)
void do_some_living(object *op)
int save_map(mapstruct *m, int flag)
void check_active_maps(void)
short freearr_x[SIZEOFFREE]
static const char * days[]
static void do_shutdown(void)
mapstruct * mapfile_load(const char *map, int flags)
static void enter_fixed_template_map(object *pl, object *exit_ob)
void knowledge_process_incremental(void)
void events_execute_global_event(int eventcode,...)
#define SP_WORD_OF_RECALL
static void process_players2(void)
void player_update_bg_music(object *player)
static char * unclean_path(const char *src, char *newpath, int size)
static char const * crypt_string(char const *str, char const *salt)