Go to the documentation of this file.
42 #ifndef NO_EMERGENCY_SAVE
62 if (
pl->ob->map != NULL)
70 "Emergency save failed, checking score...");
77 LOG(
llevInfo,
"Emergency saves disabled, no save attempted\n");
116 if (strpbrk(
name,
"/.\\") != NULL) {
138 if (strlen(
buf) >=
sizeof(
buf)-1) {
143 fp = fopen(
buf,
"r");
153 if (!strncmp(
buf,
"password ", 9)) {
184 "Your username cannot be blank.");
190 "That name contains illegal characters. Use letters, hyphens and underscores only. Hyphens and underscores are not allowed as the first character.");
195 "That name is too long. (Max length: %d characters)",
MAX_NAME);
210 while (
op->inv != NULL)
237 #ifdef BACKUP_SAVE_AT_HOME
238 int16_t backup_x, backup_y;
247 if (!
pl->name_changed) {
250 "Your game is not valid, game not saved.");
271 if (
pl->socket->account_name) {
289 "Can't get secure temporary file for save.");
290 LOG(
llevDebug,
"Can't get secure temporary file for save.\n");
294 fprintf(fp,
"password %s\n",
pl->password);
299 fprintf(fp,
"gen_hp %d\n",
pl->gen_hp);
300 fprintf(fp,
"gen_sp %d\n",
pl->gen_sp);
301 fprintf(fp,
"gen_grace %d\n",
pl->gen_grace);
302 fprintf(fp,
"listening %d\n",
pl->listening);
303 fprintf(fp,
"shoottype %d\n",
pl->shoottype);
304 fprintf(fp,
"bowtype %d\n",
pl->bowtype);
305 fprintf(fp,
"petmode %d\n",
pl->petmode);
306 fprintf(fp,
"peaceful %d\n",
pl->peaceful);
307 fprintf(fp,
"no_shout %d\n",
pl->no_shout);
308 fprintf(fp,
"digestion %d\n",
pl->digestion);
309 fprintf(fp,
"pickup %u\n",
pl->mode);
310 fprintf(fp,
"partial_commands %u\n",
pl->partial_commands);
317 fprintf(fp,
"outputs_sync %d\n", 16);
318 fprintf(fp,
"outputs_count %d\n", 1);
320 fprintf(fp,
"usekeys %s\n",
pl->usekeys ==
key_inventory ?
"key_inventory" : (
pl->usekeys ==
keyrings ?
"keyrings" :
"containers"));
323 if (
pl->unarmed_skill) fprintf(fp,
"unarmed_skill %s\n",
pl->unarmed_skill);
325 #ifdef BACKUP_SAVE_AT_HOME
326 if (
op->map != NULL && flag == 0)
330 fprintf(fp,
"map %s\n",
op->map->path);
334 fprintf(fp,
"savebed_map %s\n",
pl->savebed_map);
335 fprintf(fp,
"bed_x %d\nbed_y %d\n",
pl->bed_x,
pl->bed_y);
336 fprintf(fp,
"Str %d\n",
pl->orig_stats.Str);
337 fprintf(fp,
"Dex %d\n",
pl->orig_stats.Dex);
338 fprintf(fp,
"Con %d\n",
pl->orig_stats.Con);
339 fprintf(fp,
"Int %d\n",
pl->orig_stats.Int);
340 fprintf(fp,
"Pow %d\n",
pl->orig_stats.Pow);
341 fprintf(fp,
"Wis %d\n",
pl->orig_stats.Wis);
342 fprintf(fp,
"Cha %d\n",
pl->orig_stats.Cha);
344 fprintf(fp,
"lev_array %d\n",
MIN(
op->level, 10));
345 for (i = 1; i <=
MIN(
op->level, 10) && i <= 10; i++) {
346 fprintf(fp,
"%d\n",
pl->levhp[i]);
347 fprintf(fp,
"%d\n",
pl->levsp[i]);
348 fprintf(fp,
"%d\n",
pl->levgrace[i]);
350 fprintf(fp,
"party_rejoin_mode %d\n",
pl->rejoin_party);
351 if (
pl->party != NULL) {
352 fprintf(fp,
"party_rejoin_name %s\n",
pl->party->partyname);
356 fprintf(fp,
"ticks_played %u\n",
pl->ticks_played);
357 fprintf(fp,
"endplst\n");
361 #ifdef BACKUP_SAVE_AT_HOME
385 "Can't save character!");
398 op->contr->last_skill_ob[i] = NULL;
401 while (
op->inv != NULL)
414 "Can't open file for save.");
419 fprintf(fp,
"checksum %lx\n",
checksum);
425 "Can't close file for save.");
437 if (!
op->contr->has_directory) {
438 op->contr->has_directory = 1;
478 "\nA character with this name already exists. "
479 "Please choose another name, or make sure you entered your "
480 "password correctly.\n");
485 op->contr->socket->password_fails++;
488 "You gave an incorrect password too many times, "
489 "you will now be dropped from the server.");
491 LOG(
llevInfo,
"A player connecting from %s has been dropped for password failure\n",
492 op->contr->socket->host);
519 time_t elapsed_save_time = 0;
521 char *party_name = NULL, party_password[9];
524 party_password[0] = 0;
528 if (pltmp !=
pl && pltmp->ob->name != NULL && !strcmp(pltmp->ob->name,
op->name)) {
538 pltmp->socket->status =
Ns_Dead;
563 if (fstat(fileno(fp), &statbuf)) {
565 elapsed_save_time = 0;
567 elapsed_save_time =
time(NULL)-statbuf.st_mtime;
568 if (elapsed_save_time < 0) {
569 LOG(
llevError,
"Player file %s was saved in the future? (%ld time)\n",
filename, (
long)elapsed_save_time);
570 elapsed_save_time = 0;
574 if (fgets(bufall,
MAX_BUF, fp) != NULL) {
575 if (!strncmp(bufall,
"checksum ", 9)) {
576 if ( fgets(bufall,
MAX_BUF, fp) == NULL ) {
580 if (sscanf(bufall,
"password %s\n",
buf)) {
589 strncpy(
pl->password,
buf, 15);
590 pl->password[15] = 0;
598 if (!correct && password) {
605 pl->last_save_time =
time(NULL);
609 pl->search_str[0] =
'\0';
610 pl->name_changed = 1;
611 pl->orig_stats.Str = 0;
612 pl->orig_stats.Dex = 0;
613 pl->orig_stats.Con = 0;
614 pl->orig_stats.Int = 0;
615 pl->orig_stats.Pow = 0;
616 pl->orig_stats.Wis = 0;
617 pl->orig_stats.Cha = 0;
621 pl->spellparam[0] =
'\0';
624 while (fgets(bufall,
MAX_BUF, fp) != NULL) {
625 char *val_string, *p;
627 sscanf(bufall,
"%s %d\n",
buf, &
value);
629 val_string = bufall + strlen(
buf) +1;
630 p = strchr(val_string,
'\n');
639 uvalue = strtoul(val_string, (
char **)NULL, 10);
641 if (!strcmp(
buf,
"endplst"))
645 else if (!strcmp(
buf,
"unarmed_skill"))
647 else if (!strcmp(
buf,
"explore"))
649 else if (!strcmp(
buf,
"gen_hp"))
651 else if (!strcmp(
buf,
"shoottype"))
653 else if (!strcmp(
buf,
"bowtype"))
655 else if (!strcmp(
buf,
"petmode"))
657 else if (!strcmp(
buf,
"gen_sp"))
659 else if (!strcmp(
buf,
"gen_grace"))
661 else if (!strcmp(
buf,
"listening"))
663 else if (!strcmp(
buf,
"peaceful"))
665 else if (!strcmp(
buf,
"no_shout"))
667 else if (!strcmp(
buf,
"digestion"))
669 else if (!strcmp(
buf,
"pickup")) {
671 }
else if (!strcmp(
buf,
"partial_commands")) {
672 pl->partial_commands = uvalue;
674 else if (!strcmp(
buf,
"map"))
675 strlcpy(
pl->maplevel, val_string,
sizeof(
pl->maplevel));
676 else if (!strcmp(
buf,
"savebed_map"))
677 strlcpy(
pl->savebed_map, val_string,
sizeof(
pl->savebed_map));
678 else if (!strcmp(
buf,
"bed_x"))
680 else if (!strcmp(
buf,
"bed_y"))
682 else if (!strcmp(
buf,
"Str"))
684 else if (!strcmp(
buf,
"Dex"))
686 else if (!strcmp(
buf,
"Con"))
688 else if (!strcmp(
buf,
"Int"))
690 else if (!strcmp(
buf,
"Pow"))
692 else if (!strcmp(
buf,
"Wis"))
694 else if (!strcmp(
buf,
"Cha"))
696 else if (!strcmp(
buf,
"usekeys")) {
697 if (!strcmp(val_string,
"key_inventory"))
699 else if (!strcmp(val_string,
"keyrings"))
701 else if (!strcmp(val_string,
"containers"))
704 LOG(
llevDebug,
"load_player: got unknown usekeys type: %s\n", val_string);
705 }
else if (!strcmp(
buf,
"unapply")) {
706 if (!strcmp(val_string,
"unapply_nochoice"))
708 else if (!strcmp(val_string,
"unapply_never"))
710 else if (!strcmp(val_string,
"unapply_always"))
713 LOG(
llevDebug,
"load_player: got unknown unapply type: %s\n", val_string);
714 }
else if (!strcmp(
buf,
"lev_array")) {
715 for (i = 1; i <=
value; i++) {
719 count = fscanf(fp,
"%d\n", &j);
726 count = fscanf(fp,
"%d\n", &j);
733 count = fscanf(fp,
"%d\n", &j);
741 }
else if (!strcmp(
buf,
"party_rejoin_mode"))
743 else if (!strcmp(
buf,
"party_rejoin_name"))
745 else if (!strcmp(
buf,
"party_rejoin_password")) {
746 strncpy(party_password, val_string,
sizeof(party_password));
747 party_password[
sizeof(party_password) - 1] = 0;
748 }
else if (!strcmp(
buf,
"language")) {
751 else if (!strcmp(
buf,
"ticks_played")) {
752 pl->ticks_played = uvalue;
775 LOG(
llevInfo,
"login: %s from %s\n",
op->name,
op->contr->socket->host);
776 strncpy(
pl->title,
op->arch->clone.name,
sizeof(
pl->title)-1);
777 pl->title[
sizeof(
pl->title)-1] =
'\0';
788 strcpy(
pl->maplevel,
pl->savebed_map);
799 strcpy(
pl->maplevel,
pl->savebed_map);
800 op->x =
pl->bed_x,
op->y =
pl->bed_y;
809 pl->name_changed = 1;
834 "%s has entered the game.",
839 op->contr->socket->update_look = 1;
846 if (
op->stats.hp < 0) {
848 "Your character was dead last time you played.");
877 pl->has_directory = 1;
913 snprintf(
buf,
MAX_BUF,
"Couldn't rejoin party %s: %s.", party_name, party ?
"invalid password." :
"no such party.");
void pets_terminate_all(object *owner)
#define MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_ADMIN_PLAYER
void LOG(LogLevel logLevel, const char *format,...)
int of_close(OutputFile *of)
FILE * of_open(OutputFile *of, const char *fname)
int load_object(FILE *fp, object *op, int bufstate, int map_flags)
#define SAVE_FLAG_NO_REMOVE
char first_map_path[MAX_BUF]
#define QUERY_FLAG(xyz, p)
void login_check_shutdown(object *const op)
mapstruct * has_been_loaded(const char *name)
void esrv_new_player(player *pl, uint32_t weight)
void esrv_send_inventory(object *pl, object *op)
partylist * party_find(const char *partyname)
static void copy_file(const char *filename, FILE *fpout)
void esrv_send_pickup(player *pl)
void player_set_own_title(struct player *pl, const char *title)
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
static unsigned checksum(const mtar_raw_header_t *rh)
void object_reset(object *op)
int player_has_own_title(const struct player *pl)
void fix_object(object *op)
#define PROFILE_BEGIN(expr)
int save_player(object *op, int flag)
int account_link(const char *account_name, const char *player_name)
void esrv_add_spells(player *pl, object *spell)
void hiscore_check(object *op, int quiet)
Plugin animator file specs[Config] name
void party_join(object *op, partylist *party)
void remove_directory(const char *path)
#define PROFILE_END(var, expr)
void object_free_drop_inventory(object *ob)
void final_free_player(player *pl)
int party_confirm_password(const partylist *party, const char *password)
int playername_ok(const char *cp)
sstring i18n_get_language_code(language_t language)
const char * account_get_account_for_char(const char *charname)
void remove_unpaid_objects(object *op, object *env, int free_items)
a copper bar weighs and has a value of
sstring add_string(const char *str)
static void wrong_password(object *op)
int legal_range(object *op, int r)
void enter_player_maplevel(object *op)
long trying_emergency_save
int verify_player(const char *name, char *password)
void delete_character(const char *name)
void object_update_speed(object *op)
#define FREE_AND_COPY(sv, nv)
void party_set_password(partylist *party, const char *password)
void leave(player *pl, int draw_exit)
partylist * party_form(object *op, const char *partyname)
#define MSG_TYPE_ADMIN_LOADSAVE
size_t strlcpy(char *dst, const char *src, size_t size)
void quest_first_player_save(player *pl)
void destroy_object(object *op)
const char * party_get_password(const partylist *party)
language_t i18n_get_language_by_code(const char *code)
int is_dragon_pl(const object *op)
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 me
int check_name(player *me, const char *name)
#define MAX_PASSWORD_FAILURES
#define FLAG_NO_FIX_PLAYER
#define CLEAR_FLAG(xyz, p)
FILE * tempnam_secure(const char *dir, const char *pfx, char **filename)
void check_login(object *op, const char *password)
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
void account_char_add(Account_Chars *chars, player *pl)
#define MSG_TYPE_ADMIN_LOGIN
#define ST_GET_PARTY_PASSWORD
void object_remove(object *op)
void player_set_state(player *pl, uint8_t state)
signed long object_sum_weight(object *op)
bool check_password(const char *typed, const char *crypted)
void make_path_to_file(const char *filename)
void emergency_save(int flag)
void knowledge_send_known(player *pl)
const char * player_get_own_title(const struct player *pl)
void confirm_password(object *op)
void link_player_skills(object *op)
void set_dragon_name(object *pl, const object *abil, const object *skin)
void account_char_save(Account_Chars *chars)
#define SAVE_FLAG_SAVE_UNPAID
int save_object(FILE *fp, object *op, int flag)
void kill_player(object *op, const object *killer)
int check_path(const char *name, int prepend_dir)
void events_execute_global_event(int eventcode,...)
void quest_send_initial_states(player *pl)
void get_name(object *op)
void knowledge_first_player_save(player *pl)