/* * character.c Routines to create a character */ #include "include.h" /************************************************************************ / / FUNCTION NAME: Do_player_special_type() / / FUNCTION: return a char specifying player type / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 4/26/99 / / ARGUMENTS: / struct client_t c - pointer to the main client strcture / / RETURN VALUE: / char - character the describes the character / / MODULES CALLED: strcpy() / / DESCRIPTION: / Return a string describing the player type. / King, council, valar, supercedes other types. / The first character of the string is '*' if the player / has a crown. / If 'shortflag' is TRUE, return a 3 character string. / *************************************************************************/ char Do_player_special_type(short special_type, bool sex) { /* character descriptions */ char results[] = { ' ', 'N', 'S', 'K', 'C', 'X', 'V' }; if (sex == FEMALE) { results[SC_KING] = 'Q'; } return results[special_type]; } /************************************************************************ / / FUNCTION NAME: Do_character_playing(struct client_t *c, char *the_name) / / FUNCTION: find location in player file of given name / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 5/4/99 / / ARGUMENTS: / char *name - name of character to look for / struct player *playerp - pointer of structure to fill / / RETURN VALUE: location of player if found, -1 otherwise / / MODULES CALLED: fread(), fseek(), strcmp() / / GLOBAL INPUTS: Wizard, *Playersfp / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Search the player file for the player of the given name. / If player is found, fill structure with player data. / *************************************************************************/ int Do_character_playing(struct client_t *c, char *the_name) { struct game_t *game_ptr; Do_lock_mutex(&c->realm->realm_lock); /* run though all the games and check the names */ game_ptr = c->realm->games; while (game_ptr != NULL) { /* check for a name match */ if (game_ptr->description != NULL && !strcmp(the_name, game_ptr->description->lcname)) { Do_unlock_mutex(&c->realm->realm_lock); return TRUE; } game_ptr = game_ptr->next_game; } Do_unlock_mutex(&c->realm->realm_lock); return FALSE; } /*************************************************************************** / FUNCTION NAME: struct player_t Do_copy_record(struct player_t *orig) / / FUNCTION: Makes a copy of a character record / / AUTHOR: Brian Kelly 4/24/99 / / ARGUMENTS: / struct player_t *orig - the original player struct / bool wizard - true if the wizard requested the info / / RETURN VALUE: / struct player_t * - a pointer to a copy of the player structure / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ struct player_t *Do_copy_record(struct player_t *orig) { struct player_t *player_ptr; /* create a new player record */ player_ptr = (struct player_t *) Do_malloc(SZ_PLAYER); /* copy the information */ memcpy((void *)player_ptr, (void *)orig, SZ_PLAYER); /* return the pointer */ return player_ptr; } /*************************************************************************** / FUNCTION NAME: struct player_desc_t *Do_make_description(struct client_t *c) / / FUNCTION: Makes a character description record / / AUTHOR: Brian Kelly 4/26/99 / / ARGUMENTS: / struct player_t *orig - the original player struct / / RETURN VALUE: / struct describe_t * - pointer to the new description / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ struct player_desc_t *Do_make_description(struct client_t *c) { struct player_desc_t *desc_ptr; /* allocate for the new description */ desc_ptr = (struct player_desc_t *) Do_malloc(SZ_PLAYER_DESC); /* copy the information */ strcpy(desc_ptr->name, c->modifiedName); strcpy(desc_ptr->lcname, c->player.lcname); strcpy(desc_ptr->parent_account, c->player.parent_account); desc_ptr->type = c->player.type; desc_ptr->special_type = c->player.special_type; desc_ptr->gender = c->player.gender; desc_ptr->level = c->player.level; desc_ptr->channel = c->channel; desc_ptr->cloaked = c->player.cloaked; desc_ptr->palantir = c->player.palantir; desc_ptr->blind = c->player.blind; desc_ptr->wizard = c->wizard; /* if (c->wizard > 2) { desc_ptr->wizard = TRUE; } else { desc_ptr->wizard = FALSE; } */ return desc_ptr; } /*************************************************************************** / FUNCTION NAME: Do_player_description(struct client_t *c) / / FUNCTION: Makes a character description record / / AUTHOR: Brian Kelly 4/26/99 / / ARGUMENTS: / struct player_t *orig - the original player struct / / RETURN VALUE: / struct describe_t * - pointer to the new description / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ Do_player_description(struct client_t *c) { /* WARNING: Realm should be locked before calling this function */ /* free the old description, if necessary */ if (c->game->description != NULL) { free(c->game->description); } /* create a new one */ c->game->description = Do_make_description(c); return; } /*************************************************************************** / FUNCTION NAME: struct player_spec_t *Do_make_spec(struct client_t *c) / / FUNCTION: Makes a character spec record / / AUTHOR: Brian Kelly 4/26/99 / / ARGUMENTS: / struct client_t *c - the main client strcture / / RETURN VALUE: / struct player_spec_t * - pointer to the new specifications / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ struct player_spec_t *Do_make_specification(struct client_t *c) { struct player_spec_t *spec_ptr; /* allocate for the new description */ spec_ptr = (struct player_spec_t *) Do_malloc(SZ_PLAYER_SPEC); /* copy the information */ strcpy(spec_ptr->name, c->modifiedName); strcat(spec_ptr->name, "\n"); spec_ptr->type[0] = c->realm->charstats[c->player.type].short_class_name; if (c->wizard > 2) { spec_ptr->type[1] = 'W'; spec_ptr->type[2] = ' '; spec_ptr->type[3] = '-'; spec_ptr->type[4] = c->channel + 48; spec_ptr->type[5] = '\n'; spec_ptr->type[6] = '\0'; } else if (c->player.special_type == SC_NONE) { if (c->wizard == 2) { spec_ptr->type[1] = 'A'; spec_ptr->type[2] = ' '; spec_ptr->type[3] = '-'; spec_ptr->type[4] = c->channel + 48; spec_ptr->type[5] = '\n'; spec_ptr->type[6] = '\0'; } else { spec_ptr->type[1] = ' '; spec_ptr->type[2] = '-'; spec_ptr->type[3] = c->channel + 48; spec_ptr->type[4] = '\n'; spec_ptr->type[5] = '\0'; } } else { spec_ptr->type[1] = Do_player_special_type(c->player.special_type, c->player.gender); spec_ptr->type[2] = ' '; spec_ptr->type[3] = '-'; spec_ptr->type[4] = c->channel + 48; spec_ptr->type[5] = '\n'; spec_ptr->type[6] = '\0'; } /* return the pointer */ return spec_ptr; } /*************************************************************************** / FUNCTION NAME: Do_send_spec(struct client_t *c) / / FUNCTION: Makes a character spec record / / AUTHOR: Brian Kelly 5/16/99 / / ARGUMENTS: / struct client_t *c - the main client strcture / / RETURN VALUE: / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ Do_send_specification(struct client_t *c, long int type) { struct event_t *event_ptr; /* create a new event */ event_ptr = (struct event_t *) Do_create_event(); /* fill it out */ event_ptr->type = type; event_ptr->arg3 = (long) SZ_PLAYER_SPEC; event_ptr->arg4 = (void *) Do_make_specification(c); event_ptr->from = c->game; /* send the event to everyone */ Do_broadcast_event(c, event_ptr); return; } /*************************************************************************** / FUNCTION NAME: Do_starting_spec(struct client_t *c) / / FUNCTION: Makes a character spec record / / AUTHOR: Brian Kelly 8/15/99 / / ARGUMENTS: / struct client_t *c - the main client strcture / / RETURN VALUE: / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ Do_starting_spec(struct client_t *c) { /* WARNING: the realm should be locked before calling this function */ char string_buffer[SZ_LINE]; struct game_t *game_ptr; struct player_spec_t *spec_ptr; struct event_t *event_ptr; /* run through the list of games */ game_ptr = c->realm->games; while (game_ptr != NULL) { /* see if the game is currently playing */ if (game_ptr->description != NULL) { /* create a spec for this player */ spec_ptr = (struct player_spec_t *) Do_malloc(SZ_PLAYER_SPEC); /* copy the information */ strcpy(spec_ptr->name, game_ptr->description->name); strcat(spec_ptr->name, "\n"); spec_ptr->type[0] = c->realm->charstats[game_ptr->description->type].short_class_name; if (game_ptr->description->wizard > 2) { spec_ptr->type[1] = 'W'; spec_ptr->type[2] = ' '; spec_ptr->type[3] = '-'; spec_ptr->type[4] = game_ptr->description->channel + 48; spec_ptr->type[5] = '\n'; spec_ptr->type[6] = '\0'; } else if (game_ptr->description->special_type) { spec_ptr->type[1] = Do_player_special_type( game_ptr->description->special_type, game_ptr->description->gender); spec_ptr->type[2] = ' '; spec_ptr->type[3] = '-'; spec_ptr->type[4] = game_ptr->description->channel + 48; spec_ptr->type[5] = '\n'; spec_ptr->type[6] = '\0'; } else if (game_ptr->description->wizard == 2) { spec_ptr->type[1] = 'A'; spec_ptr->type[2] = ' '; spec_ptr->type[3] = '-'; spec_ptr->type[4] = game_ptr->description->channel + 48; spec_ptr->type[5] = '\n'; spec_ptr->type[6] = '\0'; } else { spec_ptr->type[1] = ' '; spec_ptr->type[2] = '-'; spec_ptr->type[3] = game_ptr->description->channel + 48; spec_ptr->type[4] = '\n'; spec_ptr->type[5] = '\0'; } /* create a new event */ event_ptr = (struct event_t *) Do_create_event(); /* fill it out */ event_ptr->type = ADD_PLAYER_EVENT; event_ptr->arg3 = (long) SZ_PLAYER_SPEC; event_ptr->arg4 = (void *) spec_ptr; event_ptr->from = game_ptr; /* send the event */ Do_file_event(c, event_ptr); } /* move to the next game */ game_ptr = game_ptr->next_game; } return; } /*************************************************************************** / FUNCTION NAME: Do_get_character(struct client_t *c) / / FUNCTION: initialize state, and call main process / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly 4/23/99 / / ARGUMENTS: / struct client_t *c - the main client strcture / / RETURN VALUE: none / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ Do_get_character(struct client_t *c) { struct button_t buttons; char error_msg[SZ_ERROR_MESSAGE]; int i, rc; long answer; for (;;) { /* see if the player has a saved game */ Do_send_line(c, "What do you wish to do?\n"); strcpy(buttons.button[0], "New Char\n"); strcpy(buttons.button[1], "Load Char\n"); Do_clear_buttons(&buttons, 2); strcpy(buttons.button[3], "Characters\n"); strcpy(buttons.button[4], "Account\n"); strcpy(buttons.button[6], "Scoreboard\n"); strcpy(buttons.button[7], "Quit\n"); rc = Do_buttons(c, &answer, &buttons); Do_send_clear(c); if (rc != S_NORM) { answer = 7; } /* switch on the player's answer */ switch (answer) { /* if the player has a character to run */ case 1: /* go recall the player */ Do_recall_player(c); break; /* if the player does not have a character to run */ case 0: /* create a new character */ Do_roll_new_player(c); break; /* character options */ case 3: Do_character_options(c); break; /* account options */ case 4: Do_account_options(c); break; /* show the character the scoreboard */ case 6: Do_scoreboard(c, 0); break; /* exit if requested */ case 7: c->run_level = EXIT_THREAD; break; /* since it's a push button interface, any other answer is a hacker */ default: sprintf(error_msg, "[%s] Returned non-option in Do_get_character.\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); } return; } } /************************************************************************ / / FUNCTION NAME: Do_roll_new_player(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 5/4/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw(), / getanswer(), getstring() / / DESCRIPTION: / Prompt player, and roll up new character. / *************************************************************************/ Do_roll_new_player(struct client_t *c) { struct charstats_t *stat_ptr; struct game_t *game_ptr; int i, theMask, suffixFlag; double x, y; char answer, string_buffer[SZ_LINE], string_buffer2[SZ_LINE]; struct button_t buttons; char error_msg[SZ_ERROR_MESSAGE]; long theAnswer; FILE *liar_file; struct in_addr theNetwork; /* muted characters would make characters with message names */ if (c->muteUntil > time(NULL)) { Do_send_line(c, "Muted players may not create characters.\n"); Do_more(c); Do_send_clear(c); return; } /* get the character type */ Do_send_line(c, "Which type of character do you want?\n"); for (i = 0; i < NUM_CHARS; i++) { /* copy over the class name */ sprintf(buttons.button[i], "%s\n", c->realm->charstats[i].class_name); } Do_clear_buttons(&buttons, NUM_CHARS); strcpy(buttons.button[7], "Cancel\n"); /* send the information */ if (Do_buttons(c, &theAnswer, &buttons) != S_NORM || theAnswer == 7) { Do_send_clear(c); return; } Do_send_clear(c); c->player.type = theAnswer; /* if the information is out of range, we have a hacker */ if (c->player.type < 0 && c->player.type >= NUM_CHARS) { sprintf(error_msg, "[%s] Returned non-option in Do_roll_new_player.\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); return; } stat_ptr = &c->realm->charstats[c->player.type]; for (;;) { /* give a random x and y */ x = 0; y = 0; Do_move_close(&x, &y, D_CIRCLE - 1); if (c->player.type != C_EXPER) { Do_location(c, x, y, FALSE); } c->player.energy = ROLL(stat_ptr->energy.base, stat_ptr->energy.interval); Do_energy(c, c->player.energy, c->player.energy, 0.0, 0.0, FALSE); Do_strength(c, ROLL(stat_ptr->strength.base, stat_ptr->strength.interval), 0.0, 0.0, FALSE); Do_speed(c, ROLL(stat_ptr->quickness.base, stat_ptr->quickness.interval), 0.0, 0.0, FALSE); Do_mana(c, ROLL(stat_ptr->mana.base, stat_ptr->mana.interval) - c->player.mana, FALSE); /* set the gold manually so no taxes are taken */ c->player.gold = ROLL(50.0, 75.0); Do_gold(c, 0.0, TRUE); c->player.brains = ROLL(stat_ptr->brains.base, stat_ptr->brains.interval); c->player.magiclvl = ROLL(stat_ptr->magiclvl.base, stat_ptr->magiclvl.interval); /* experimento's have fixed stats */ if (c->player.type == C_EXPER) break; sprintf(string_buffer, "Brains : %2.0f\n", c->player.brains); Do_send_line(c, string_buffer); sprintf(string_buffer, "Magic Level : %2.0f\n", c->player.magiclvl); Do_send_line(c, string_buffer); if (c->player.type == C_HALFLING) { /* give halfling some experience */ c->player.experience = 0; Do_experience(c, ROLL(600.0, 200.0), FALSE); sprintf(string_buffer, "Experience : %2.0f\n", c->player.experience); Do_send_line(c, string_buffer); } /* see if the player wants to keep the character */ Do_send_line(c, "Do you wish to keep these stats?\n"); strcpy(buttons.button[0], "Reroll\n"); strcpy(buttons.button[1], "Keep\n"); Do_clear_buttons(&buttons, 2); strcpy(buttons.button[7], "Cancel\n"); /* see if the game is shutting down */ Do_shutdown_check(c); if (Do_buttons(c, &theAnswer, &buttons) != S_NORM || theAnswer == 7) { Do_send_clear(c); return; } else if (theAnswer == 1) { Do_send_clear(c); break; } else if (theAnswer != 0) { Do_send_clear(c); sprintf(error_msg, "[%s] Returned non-option in Do_roll_new_player(2).\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); return; } Do_send_clear(c); } /* get coordinates for experimento */ if (c->player.type == C_EXPER) { for (;;) { if (Do_coords_dialog(c, &x, &y, "Enter the approximate X Y coordinates of your experimento?\n")) { return; } if (fabs(x) > D_EXPER || fabs(y) > D_EXPER) { Do_send_line(c, "Experimento starting coordinates must be between -2000 and 2000. Please try again.\n"); Do_more(c); Do_send_clear(c); } else { break; } } /* experimentos never quite start where they wish */ Do_move_close(&x, &y, 5); if (x == 0 && y == 0) { Do_move_close(&x, &y, 0); } Do_location(c, x, y, FALSE); } for (;;) { /* name the new character */ sprintf(string_buffer, "Give your character a name. [up to %d characters]\n", MAX_NAME_LEN); if (Do_string_dialog(c, c->player.name, SZ_NAME - 1, string_buffer)) return; /* see if the name is approved */ Do_lowercase(&c->player.lcname, &c->player.name); if (Do_approve_name(c, &c->player.lcname, &c->player.name, &theAnswer) != S_NORM) { return; } if (theAnswer) { break; } } strcpy(c->modifiedName, c->player.name); Do_name(c); /* determine the sex of the charcter */ Do_send_line(c, "Is the character male or female?\n"); strcpy(buttons.button[0], "Male\n"); strcpy(buttons.button[1], "Female\n"); Do_clear_buttons(&buttons, 2); strcpy(buttons.button[7], "Cancel\n"); if (Do_buttons(c, &theAnswer, &buttons) != S_NORM || theAnswer == 7) { Do_release_name(c, c->player.lcname); Do_send_clear(c); return; } Do_send_clear(c); if (theAnswer == 1) c->player.gender = FEMALE; else c->player.gender = MALE; /* get a password for character */ if (!Do_new_password(c, c->player.password, "character")) { Do_release_name(c, c->player.lcname); return; } /* creation complete */ c->run_level = PLAY_GAME; c->player.date_created = time(NULL); /* put a description in place */ Do_lock_mutex(&c->realm->realm_lock); Do_player_description(c); Do_unlock_mutex(&c->realm->realm_lock); /* remove the name in limbo now the description is in place */ Do_release_name(c, c->player.lcname); /* log the creation */ sprintf(string_buffer, "[%s] %s created by %s\n", c->connection_id, c->player.lcname, c->lcaccount); Do_log(GAME_LOG, &string_buffer); sprintf(string_buffer, "%s, %s, 0 age, 0 seconds, level 0\n", c->player.lcname, c->realm->charstats[c->player.type].class_name); Do_log(LEVEL_LOG, &string_buffer); return; } /************************************************************************ / / FUNCTION NAME: Do_recall_player() / / FUNCTION: find a character on file / / AUTHOR: E. A. Estes, 12/4/85 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: writerecord(), truncstring(), more(), death(), wmove(), / wclear(), strcmp(), printw(), cleanup(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / GLOBAL INPUTS: Player, *stdscr, Databuf[] / / GLOBAL OUTPUTS: Echo, Player / / DESCRIPTION: / Search for a character of a certain name, and check password. / *************************************************************************/ Do_recall_player(struct client_t *c) { char characterName[SZ_NAME], string_buffer[SZ_LINE]; char lcCharacterName[SZ_NAME]; char error_msg[SZ_ERROR_MESSAGE]; struct player_mod_t theMod; long answer; int exceptionFlag, wizType = 0; char wizNetwork[SZ_FROM], wizAccount[SZ_NAME], wizCharacter[SZ_NAME]; FILE *wizard_file; /* open the wizard file to see if this person is one */ if ((wizard_file=fopen(WIZARD_FILE, "r")) == NULL) { sprintf(string_buffer, "[%s] fopen of %s failed in Do_recall_player: %s\n", c->connection_id, WIZARD_FILE, strerror(errno)); Do_log_error(string_buffer); } else { /* loop through the the names */ while (fscanf(wizard_file, "%ld %s %s %s %d\n", &answer, &wizNetwork, &wizAccount, &wizCharacter, &exceptionFlag) == 5) { /* put down the highest wizType */ if (!strcmp(wizAccount, c->lcaccount) && !strcmp(wizNetwork, c->network)) { if (answer > wizType) { wizType = answer; } } } fclose(wizard_file); } for (;;) { /* prompt for the character */ if (Do_string_dialog(c, characterName, SZ_NAME - 1, "What is the name of the character?\n")) { return; } /* load the character information */ Do_lowercase(&lcCharacterName, &characterName); Do_send_line(c, "Looking up character information...\n"); Do_send_buffer(c); if (strcmp("", lcCharacterName) == 0) { } else if (Do_look_character(c, lcCharacterName, &c->player)) { Do_send_clear(c); break; } Do_send_clear(c); /* see if the character is playing */ if (Do_character_playing(c, lcCharacterName)) { Do_send_line(c, "That character is currently in the game. If you were just playing this character and was disconnected, wait a minute and the character will either be saved or killed.\n"); } else { sprintf(string_buffer, "I can not find a character named \"%s\". Please check the spelling and try again.\n", characterName); Do_send_line(c, string_buffer); } Do_more(c); Do_send_clear(c); } /* if character is faithful, make sure this is parent account */ /* allow wizards to load protected characters */ if (wizType < 3 && c->player.faithful && strcmp(c->player.parent_account, c->lcaccount)) { /* this is a possible hack attempt, so log it */ Do_clear_character_mod(&theMod); theMod.badPassword = TRUE; Do_modify_character(c, lcCharacterName, &theMod); sprintf(string_buffer, "The character named \"%s\" can only be loaded from the account that created it.\n", characterName); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } /* found character - now get the password */ if (!Do_request_character_password(c, c->player.password, c->player.name, c->player.lcname, wizType)) { return; } /* put a description in place - now so nobody can use the name */ Do_lock_mutex(&c->realm->realm_lock); Do_player_description(c); Do_unlock_mutex(&c->realm->realm_lock); /* load the character */ Do_send_line(c, "Loading the character...\n"); Do_send_buffer(c); if (!Do_load_character(c, lcCharacterName)) { /* if false returns, the character was not loaded */ Do_send_clear(c); /* erase the description just put in */ Do_lock_mutex(&c->realm->realm_lock); free(c->game->description); c->game->description = NULL; Do_unlock_mutex(&c->realm->realm_lock); /* inform the user */ sprintf(string_buffer, "The character %s is no longer in the character file. This is normally because the character was just loaded by someone else.\n", c->player.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } Do_send_clear(c); /* backup the character */ Do_backup_save(c, TRUE); /* import the character to this account if none */ if (c->player.parent_account[0] == '\0') { strcpy(c->player.parent_account, c->lcaccount); strcpy(c->player.parent_network, c->network); c->player.faithful = TRUE; sprintf(string_buffer, "The character %s has been imported into account %s. Future modifications to this character must be done through this account.\n", c->player.name, c->account); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); } c->run_level = PLAY_GAME; /* log the load */ sprintf(string_buffer, "[%s] %s loaded by %s\n", c->connection_id, c->player.lcname, c->lcaccount); Do_log(GAME_LOG, &string_buffer); return; } /************************************************************************ / / FUNCTION NAME: Do_look_character(struct client_t *c, char *the_name, struct player_t *thePlayer) / / FUNCTION: find location in player file of given name / / AUTHOR: Brian Kelly, 1/3/01 / / ARGUMENTS: / char *name - name of character to look for / struct player *playerp - pointer of structure to fill / / RETURN VALUE: location of player if found, -1 otherwise / / MODULES CALLED: fread(), fseek(), strcmp() / / GLOBAL INPUTS: Wizard, *Playersfp / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Search the player file for the player of the given name. / If player is found, fill structure with player data. / *************************************************************************/ int Do_look_character(struct client_t *c, char *the_name, struct player_t *thePlayer) { FILE *character_file; char error_msg[SZ_ERROR_MESSAGE]; Do_lock_mutex(&c->realm->character_file_lock); errno = 0; if ((character_file=fopen(CHARACTER_FILE, "r")) == NULL) { Do_unlock_mutex(&c->realm->character_file_lock); sprintf(error_msg, "[%s] fopen of %s failed in Do_look_character: %s\n", c->connection_id, CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); return FALSE; } /* loop through the the files */ while (fread((void *)thePlayer, SZ_PLAYER, 1, character_file) == 1) { if (strcmp(thePlayer->lcname, the_name) == 0) { fclose(character_file); Do_unlock_mutex(&c->realm->character_file_lock); return TRUE; } } fclose(character_file); Do_unlock_mutex(&c->realm->character_file_lock); return FALSE; } /************************************************************************ / / FUNCTION NAME: Do_load_character(struct client_t *c, char *the_name) / / FUNCTION: find location in player file of given name / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 5/4/99 / / ARGUMENTS: / char *name - name of character to look for / struct player *playerp - pointer of structure to fill / / RETURN VALUE: location of player if found, -1 otherwise / / MODULES CALLED: fread(), fseek(), strcmp() / / GLOBAL INPUTS: Wizard, *Playersfp / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Search the player file for the player of the given name. / If player is found, fill structure with player data. / *************************************************************************/ int Do_load_character(struct client_t *c, char *the_name) { struct player_t readPlayer; FILE *character_file, *temp_file; char error_msg[SZ_ERROR_MESSAGE]; time_t timeNow; bool char_flag; Do_lock_mutex(&c->realm->character_file_lock); errno = 0; if ((character_file=fopen(CHARACTER_FILE, "r")) == NULL) { Do_unlock_mutex(&c->realm->character_file_lock); sprintf(error_msg, "[%s] fopen of %s failed in Do_load_character: %s\n", c->connection_id, CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); return FALSE; } /* create a temporary file */ errno = 0; if ((temp_file=fopen(TEMP_CHARACTER_FILE, "w")) == NULL) { sprintf(error_msg, "[%s] fopen of %s failed in Do_load_character(2): %s\n", c->connection_id, TEMP_CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); fclose(character_file); Do_unlock_mutex(&c->realm->character_file_lock); return FALSE; } char_flag = FALSE; timeNow = time(NULL); /* read each line of the character file */ while (fread((void *)&readPlayer, SZ_PLAYER, 1, character_file) == 1) { /* if we find our character, copy it over */ if (strcmp(readPlayer.lcname, the_name) == 0) { memcpy(&c->player, &readPlayer, SZ_PLAYER); char_flag = TRUE; continue; } /* see if the character has expired */ else if ((readPlayer.level < 2) && (timeNow - readPlayer.last_load > NEWBIE_KEEP_TIME)) { /* log the deletion of the account */ sprintf(error_msg, "[%s] %s deleted\n", c->connection_id, readPlayer.lcname); Do_log(GAME_LOG, &error_msg); continue; } else if ((readPlayer.level >= 2) && (timeNow - readPlayer.last_load > KEEP_TIME + (readPlayer.degenerated * 172800))) { /* log the deletion of the account */ sprintf(error_msg, "[%s] %s deleted\n", c->connection_id, readPlayer.lcname); Do_log(GAME_LOG, &error_msg); continue; } /* delete characters that are from the future */ if (timeNow < readPlayer.last_load) { /* log the deletion of the account */ sprintf(error_msg, "[%s] %s from the future and deleted\n", c->connection_id, readPlayer.lcname); Do_log(GAME_LOG, &error_msg); continue; } errno = 0; if (fwrite((void *)&readPlayer, SZ_PLAYER, 1, temp_file) != 1) { sprintf(error_msg, "[%s] fwrite of %s failed in Do_load_character: %s\n", c->connection_id, TEMP_CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); fclose(character_file); fclose(temp_file); remove(TEMP_CHARACTER_FILE); Do_unlock_mutex(&c->realm->character_file_lock); return FALSE; } } /* delete the old character record */ remove(CHARACTER_FILE); /* replace it with the temporary file */ rename(TEMP_CHARACTER_FILE, CHARACTER_FILE); /* close the file handles */ fclose(temp_file); fclose(character_file); Do_unlock_mutex(&c->realm->character_file_lock); /* if the character was found */ if (char_flag) { /* There's an overflow with the mute count somewhere -- EH & BK - 1/6/02 */ if (c->player.muteCount > 6 || c->player.muteCount < 0) { c->player.muteCount = 0; } return TRUE; } return FALSE; } /************************************************************************ / / FUNCTION NAME: Do_save_character(struct client_t *c, struct player_t *thePlayer) / / FUNCTION: find location in player file of given name / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 5/4/99 / / ARGUMENTS: / char *name - name of character to look for / struct player *playerp - pointer of structure to fill / / RETURN VALUE: location of player if found, -1 otherwise / / MODULES CALLED: fread(), fseek(), strcmp() / / GLOBAL INPUTS: Wizard, *Playersfp / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Search the player file for the player of the given name. / If player is found, fill structure with player data. / *************************************************************************/ int Do_save_character(struct client_t *c, struct player_t *thePlayer) { FILE *character_file; char error_msg[SZ_ERROR_MESSAGE]; char string_buffer[SZ_LINE]; Do_lock_mutex(&c->realm->character_file_lock); errno = 0; if ((character_file=fopen(CHARACTER_FILE, "a")) == NULL) { Do_unlock_mutex(&c->realm->character_file_lock); sprintf(error_msg, "[%s] fopen of %s failed in Do_save_character: %s\n", c->connection_id, CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); Do_send_line(c, "There was an error opening the character file to save your character. Please contact the game administrator with this problem.\n"); Do_more(c); Do_send_clear(c); return; } /* write the player record to the end of the character file */ errno = 0; if (fwrite((void *)thePlayer, SZ_PLAYER, 1, character_file) != 1) { fclose(character_file); Do_unlock_mutex(&c->realm->character_file_lock); sprintf(error_msg, "[%s] fwrite of %s failed in Do_save_character: %s\n", c->connection_id, CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); Do_send_line(c, "There was an error opening the character file to save your character. Please contact the game administrator with this problem.\n"); Do_more(c); Do_send_clear(c); return; } /* close the character file */ fclose(character_file); Do_unlock_mutex(&c->realm->character_file_lock); } /************************************************************************ / / FUNCTION NAME: Do_backup_save(struct client_t *c) / / FUNCTION: find location in player file of given name / / AUTHOR: Brian Kelly, 11/25/99 / / ARGUMENTS: / char *name - name of character to look for / struct player *playerp - pointer of structure to fill / / RETURN VALUE: location of player if found, -1 otherwise / / MODULES CALLED: fread(), fseek(), strcmp() / / GLOBAL INPUTS: Wizard, *Playersfp / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Search the player file for the player of the given name. / If player is found, fill structure with player data. / *************************************************************************/ Do_backup_save(struct client_t *c, int backup) { FILE *backup_file; FILE *temp_backup_file; struct player_t the_player; char error_msg[SZ_ERROR_MESSAGE]; Do_lock_mutex(&c->realm->backup_lock); errno = 0; if ((temp_backup_file=fopen(TEMP_BACKUP_FILE, "w")) == NULL) { Do_unlock_mutex(&c->realm->backup_lock); sprintf(error_msg, "[%s] fopen of %s failed in Do_backup_save: %s\n", c->connection_id, TEMP_BACKUP_FILE, strerror(errno)); Do_log_error(error_msg); return; } /* if we're supposed to back up our charcter */ if (backup) { /* write the player record to the end of the character file */ errno = 0; if (fwrite((void *)&c->player, SZ_PLAYER, 1, temp_backup_file) != 1) { sprintf(error_msg, "[%s] fwrite of %s failed in Do_backup_save: %s\n", c->connection_id, TEMP_BACKUP_FILE, strerror(errno)); Do_log_error(error_msg); fclose(temp_backup_file); Do_unlock_mutex(&c->realm->backup_lock); return; } } /* open the real backup file */ errno = 0; if ((backup_file=fopen(BACKUP_FILE, "r")) == NULL) { sprintf(error_msg, "[%s] fopen of %s failed in Do_backup_save: %s\n", c->connection_id, BACKUP_FILE, strerror(errno)); Do_log_error(error_msg); } else { /* read each line of the old backup file */ errno = 0; while (fread((void *)&the_player, SZ_PLAYER, 1, backup_file) == 1) { /* if its anyone elses character, copy it over */ if (strcmp(the_player.lcname, c->player.lcname)) { if (fwrite((void *)&the_player, SZ_PLAYER, 1, temp_backup_file) != 1) { sprintf(error_msg, "[%s] fwrite of %s failed in Do_backup_save(2): %s\n", c->connection_id, TEMP_BACKUP_FILE, strerror(errno)); Do_log_error(error_msg); fclose(backup_file); fclose(temp_backup_file); Do_unlock_mutex(&c->realm->backup_lock); return; } } } remove(BACKUP_FILE); fclose(backup_file); } /* remove and replace the old backup file */ rename(TEMP_BACKUP_FILE, BACKUP_FILE); fclose(temp_backup_file); Do_unlock_mutex(&c->realm->backup_lock); return; } /************************************************************************ / / FUNCTION NAME: Do_approve_name(struct client_t *c, char *lcname, char *name, int *answer) / / FUNCTION: return a char specifying player type / / AUTHOR: Brian Kelly, 1/1/01 / / ARGUMENTS: / struct client_t c - pointer to the main client strcture / / RETURN VALUE: / char - character the describes the character / / MODULES CALLED: strcpy() / / DESCRIPTION: / Return a string describing the player type. / King, council, valar, supercedes other types. / The first character of the string is '*' if the player / has a crown. / If 'shortflag' is TRUE, return a 3 character string. / *************************************************************************/ int Do_approve_name(struct client_t *c, char *lcname, char *name, int *answer) { int len, i, underscore_count; bool space_flag, double_underscore; char string_buffer[SZ_LINE]; struct account_t readAccount; struct player_t readPlayer; struct game_t *game_ptr; struct linked_list_t *list_ptr; FILE *the_file; /* just stop right now if the name is null */ len = strlen(lcname); if (len == 0) { sprintf(string_buffer, "Please enter the name you would like into the dialog box.\n", lcname); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } /* see if the name is too long */ if (len > MAX_NAME_LEN) { sprintf(string_buffer, "\"%s\" is too long. Please use %d characters or less.\n", name, MAX_NAME_LEN); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } /* see if we have this name reserved */ if (c->previousName[0] != '\0') { /* see if this name is reserved for us */ if (strcmp(c->previousName, lcname) == 0) { c->previousName[0] = '\0'; *answer = TRUE; return S_NORM; } /* remove the reserved name from limbo */ Do_release_name(c, c->previousName); c->previousName[0] = '\0'; } /* see if the name looks okay */ space_flag = FALSE; double_underscore = FALSE; underscore_count = 0; for (i = 0; i < len ; i++) { if (isalnum(lcname[i])) { double_underscore = FALSE; } else { if (lcname[i] == '_') { ++underscore_count; if (double_underscore) { sprintf(string_buffer, "\"%s\" uses underscores together. Please use only one underscore to represent a space.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } else { double_underscore = TRUE; } } else { /* An error, but hold off in case of other bad chars */ if (lcname[i] == ' ') { space_flag = TRUE; } else { sprintf(string_buffer, "\"%s\" contains invalid characters. You may only use letters, numbers and underscores. Please use a different name.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } } } } if (space_flag) { sprintf(string_buffer, "\"%s\" uses spaces which is not permitted. Please use underscores instead of spaces.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } if (lcname[0] == '_' || lcname[len] == '_') { sprintf(string_buffer, "\"%s\" is not using underscores to separate characters. Please remove them if they are not going to be used as a space.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } if ((double)underscore_count / (double)len >= .25) { sprintf(string_buffer, "\"%s\" contains too many underscores. Please use underscores only to separate words.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } /* the name is of an acceptable format - see if it is profane */ if (Do_profanity_check(lcname)) { sprintf(string_buffer, "\"%s\" does not get past the profanity checker. Please choose a different name.\n", lcname); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } /* start checking accounts to lock the realm as little as possible */ errno = 0; Do_lock_mutex(&c->realm->account_lock); if ((the_file=fopen(ACCOUNT_FILE, "r")) == NULL) { sprintf(string_buffer, "[%s] fopen of %s failed Do_approve_name: %s\n", c->connection_id, ACCOUNT_FILE, strerror(errno)); Do_log_error(string_buffer); } else { /* run through each entry and compare */ while (fread((void *)&readAccount, SZ_ACCOUNT, 1, the_file) == 1) { if (strcmp(readAccount.lcname, lcname) == 0) { fclose(the_file); Do_unlock_mutex(&c->realm->account_lock); sprintf(string_buffer, "The name \"%s\" has already been taken. Please choose another.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } } fclose(the_file); } /* We have to lock the realm now */ Do_lock_mutex(&c->realm->realm_lock); /* start looking through the games in play */ game_ptr = c->realm->games; /* run through all addresses in limbo */ while (game_ptr != NULL) { if (game_ptr->description != NULL && strcmp(lcname, game_ptr->description->lcname) == 0) { Do_unlock_mutex(&c->realm->realm_lock); Do_unlock_mutex(&c->realm->account_lock); sprintf(string_buffer, "The name \"%s\" has already been taken. Please choose another.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } game_ptr = game_ptr->next_game; } /* now look through the character file */ errno = 0; Do_lock_mutex(&c->realm->character_file_lock); if ((the_file=fopen(CHARACTER_FILE, "r")) == NULL) { sprintf(string_buffer, "[%s] fopen of %s failed in Do_approve_name: %s\n", c->connection_id, CHARACTER_FILE, strerror(errno)); Do_log_error(string_buffer); } else { /* run through each entry and compare */ while (fread((void *)&readPlayer, SZ_PLAYER, 1, the_file) == 1) { if (strcmp(readPlayer.lcname, lcname) == 0) { fclose(the_file); Do_unlock_mutex(&c->realm->character_file_lock); Do_unlock_mutex(&c->realm->realm_lock); Do_unlock_mutex(&c->realm->account_lock); sprintf(string_buffer, "The name \"%s\" has already been taken. Please choose another.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } } fclose(the_file); } /* start looking through names in limbo */ list_ptr = c->realm->name_limbo; /* run through all addresses in limbo */ while (list_ptr != NULL) { if (strcmp(list_ptr->name, lcname) == 0) { Do_unlock_mutex(&c->realm->character_file_lock); Do_unlock_mutex(&c->realm->realm_lock); Do_unlock_mutex(&c->realm->account_lock); sprintf(string_buffer, "The name \"%s\" is currently being registered by another player. Please choose another.\n", name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); *answer = FALSE; return S_NORM; } list_ptr = list_ptr->next; } /* name address checks out. Put ours in limbo */ list_ptr = (struct linked_list_t *) Do_malloc(SZ_LINKED_LIST); strcpy(list_ptr->name, lcname); list_ptr->next = c->realm->name_limbo; c->realm->name_limbo = list_ptr; Do_unlock_mutex(&c->realm->character_file_lock); Do_unlock_mutex(&c->realm->realm_lock); Do_unlock_mutex(&c->realm->account_lock); *answer = TRUE; return S_NORM; } /************************************************************************ / / FUNCTION NAME: Do_release_name(struct client_t *c, char *name); / / FUNCTION: return a char specifying player type / / AUTHOR: Brian Kelly, 1/1/01 / / ARGUMENTS: / struct client_t c - pointer to the main client strcture / / RETURN VALUE: / char - character the describes the character / / MODULES CALLED: strcpy() / / DESCRIPTION: / Return a string describing the player type. / King, council, valar, supercedes other types. / The first character of the string is '*' if the player / has a crown. / If 'shortflag' is TRUE, return a 3 character string. / *************************************************************************/ Do_release_name(struct client_t *c, char *name) { char error_msg[SZ_ERROR_MESSAGE]; struct linked_list_t *list_ptr, **list_ptr_ptr; Do_lock_mutex(&c->realm->character_file_lock); /* start at the first pointer */ list_ptr_ptr = &c->realm->name_limbo; /* run through all addresses in limbo */ while (*list_ptr_ptr != NULL) { if (strcmp((*list_ptr_ptr)->name, name) == 0) { /* remove this section of linked list */ list_ptr = *list_ptr_ptr; *list_ptr_ptr = list_ptr->next; free((void *)list_ptr); Do_unlock_mutex(&c->realm->character_file_lock); return; } list_ptr_ptr = &((*list_ptr_ptr)->next); } Do_unlock_mutex(&c->realm->character_file_lock); sprintf(error_msg, "[%s] The name %s was not found in limbo by Do_release_name.\n", c->connection_id, name); Do_log_error(error_msg); return; } /************************************************************************ / / FUNCTION NAME: Do_clear_character_mod(struct player_mod_t *theMod) / / FUNCTION: find location in player file of given name / / AUTHOR: Brian Kelly, 01/03/01 / / ARGUMENTS: / char *name - name of character to look for / struct player *playerp - pointer of structure to fill / / RETURN VALUE: location of player if found, -1 otherwise / / MODULES CALLED: fread(), fseek(), strcmp() / / GLOBAL INPUTS: Wizard, *Playersfp / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Search the player file for the player of the given name. / If player is found, fill structure with player data. / *************************************************************************/ Do_clear_character_mod(struct player_mod_t *theMod) { theMod->newName = FALSE; theMod->newPassword = FALSE; theMod->passwordReset = FALSE; theMod->newPermissions = FALSE; theMod->badPassword = FALSE; return; } /************************************************************************ / / FUNCTION NAME: Do_modify_character(struct client_t *c, char *the_name, struct player_mod_t *theMod) / / FUNCTION: find location in player file of given name / / AUTHOR: Brian Kelly, 01/03/01 / / ARGUMENTS: / char *name - name of character to look for / struct player *playerp - pointer of structure to fill / / RETURN VALUE: location of player if found, -1 otherwise / / MODULES CALLED: fread(), fseek(), strcmp() / / GLOBAL INPUTS: Wizard, *Playersfp / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Search the player file for the player of the given name. / If player is found, fill structure with player data. / *************************************************************************/ int Do_modify_character(struct client_t *c, char *the_name, struct player_mod_t *theMod) { struct player_t readPlayer; FILE *character_file; char error_msg[SZ_ERROR_MESSAGE]; long loc = 0; Do_lock_mutex(&c->realm->character_file_lock); errno = 0; if ((character_file=fopen(CHARACTER_FILE, "r+")) == NULL) { Do_unlock_mutex(&c->realm->character_file_lock); sprintf(error_msg, "[%s] fopen of %s failed in Do_modify_character: %s\n", c->connection_id, CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); return FALSE; } /* read each line of the character file */ while (fread((void *)&readPlayer, SZ_PLAYER, 1, character_file) == 1) { /* if we find our character, make the mods and save */ if (strcmp(readPlayer.lcname, the_name) == 0) { /* are we changing the character name? */ if (theMod->newName) { strcpy(readPlayer.name, theMod->name); strcpy(readPlayer.lcname, theMod->lcName); } /* are we putting in a new password? */ if (theMod->newPassword) { memcpy(readPlayer.password, theMod->password, SZ_PASSWORD); } /* is this a password reset? */ if (theMod->passwordReset) { readPlayer.last_reset = time(NULL); } /* change permissions? */ if (theMod->newPermissions) { readPlayer.faithful = theMod->faithful; } /* if someone has typrd in a bad password */ if (theMod->badPassword) { ++readPlayer.bad_passwords; } /* now, write over the previous entry */ fseek(character_file, loc, 0); errno = 0; if (fwrite((void *)&readPlayer, SZ_PLAYER, 1, character_file) != 1) { sprintf(error_msg, "[%s] fwrite over %s failed in Do_modify_character: %s\n", c->connection_id, CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); } fclose(character_file); Do_unlock_mutex(&c->realm->character_file_lock); return TRUE; } loc += SZ_PLAYER; } Do_unlock_mutex(&c->realm->character_file_lock); sprintf(error_msg, "[%s] The character %s was not found by Do_modify_character.\n", c->connection_id, the_name); Do_log_error(error_msg); return FALSE; } /************************************************************************ / / FUNCTION NAME: Do_character_options(struct client_t *c) / / FUNCTION: find location in player file of given name / / AUTHOR: Brian Kelly, 1/4/01 / / ARGUMENTS: / char *name - name of character to look for / struct player *playerp - pointer of structure to fill / / RETURN VALUE: location of player if found, -1 otherwise / / MODULES CALLED: fread(), fseek(), strcmp() / / GLOBAL INPUTS: Wizard, *Playersfp / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Search the player file for the player of the given name. / If player is found, fill structure with player data. / *************************************************************************/ Do_character_options(struct client_t *c) { struct player_t readPlayer; struct button_t buttons; struct game_t *game_ptr; FILE *character_file; char string_buffer[SZ_LINE]; char error_msg[SZ_ERROR_MESSAGE]; char theTitle[SZ_ERROR_MESSAGE]; bool found_flag; int rc; long answer; found_flag = FALSE; /* start by looking at games in play */ Do_send_line(c, "Searching for characters assigned to this account...\n"); Do_send_buffer(c); Do_lock_mutex(&c->realm->realm_lock); game_ptr = c->realm->games; while (game_ptr != NULL) { if (game_ptr->description != NULL) { if (!strcmp(c->lcaccount, game_ptr->description->parent_account)) { /* do we need to put up a header? */ if (!found_flag) { Do_send_clear(c); Do_send_line(c, "Character Name - Level - Date Last Loaded\n"); found_flag = TRUE; } Do_make_character_title(c, game_ptr, theTitle); /* put everything together */ sprintf(string_buffer, "%s - %.0lf - Currently Playing\n", theTitle, game_ptr->description->level); Do_send_line(c, string_buffer); } } game_ptr = game_ptr->next_game; } Do_lock_mutex(&c->realm->character_file_lock); errno = 0; if ((character_file=fopen(CHARACTER_FILE, "r")) == NULL) { sprintf(error_msg, "[%s] fopen of %s failed in Do_character_options: %s\n", c->connection_id, CHARACTER_FILE, strerror(errno)); Do_log_error(error_msg); } else { /* loop through the the characters */ while (fread((void *)&readPlayer, SZ_PLAYER, 1, character_file) == 1) { if (strcmp(c->lcaccount, readPlayer.parent_account) == 0) { /* do we need to put up a header? */ if (!found_flag) { Do_send_clear(c); Do_send_line(c, "Character Name - Level - Date Last Loaded\n"); found_flag = TRUE; } /* no carriage return, provided by ctime */ ctime_r(&readPlayer.last_load, error_msg); /* put everything together */ sprintf(string_buffer, "%s the %s - %.0lf - %s", readPlayer.name, c->realm->charstats[readPlayer.type].class_name, readPlayer.level, error_msg); Do_send_line(c, string_buffer); } } fclose(character_file); } Do_unlock_mutex(&c->realm->realm_lock); Do_unlock_mutex(&c->realm->character_file_lock); if (!found_flag) { Do_send_clear(c); Do_send_line(c, "No characters from this account were found.\n"); } strcpy(buttons.button[0], "Change Pass\n"); strcpy(buttons.button[1], "Reset Pass\n"); Do_clear_buttons(&buttons, 2); if (c->wizard > 2) { strcpy(buttons.button[3], "Change Name\n"); } strcpy(buttons.button[4], "Sharing\n"); strcpy(buttons.button[7], "Go Back\n"); rc = Do_buttons(c, &answer, &buttons); Do_send_clear(c); if (rc != S_NORM) { answer = 7; } /* switch on the player's answer */ switch (answer) { /* The player wishes to change a character password */ case 0: Do_change_character_password(c); break; /* The user wants a password reset */ case 1: Do_reset_character_password(c); break; /* Rename the character */ /* case 3: Do_rename_character(c); break; */ /* Change character sharing permissions */ case 4: Do_character_sharing(c); break; /* Return to previous state */ case 7: return; default: sprintf(error_msg, "[%s] Returned non-option in Do_character_options.\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); return; } return; } /************************************************************************ / / FUNCTION NAME: Do_change_character_password(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: Brian Kelly, 1/4/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / DESCRIPTION: / Prompt player, and roll up new character. / *************************************************************************/ Do_change_character_password(struct client_t *c) { char error_msg[SZ_ERROR_MESSAGE], characterName[SZ_NAME]; char string_buffer[SZ_LINE], lcCharacterName[SZ_NAME]; struct button_t theButtons; struct player_mod_t theMod; int rc; long answer; Do_send_line(c, "This option allows you to change the password of one of your characters. Do you wish to continue?\n"); strcpy(theButtons.button[0], "Continue\n"); Do_clear_buttons(&theButtons, 1); strcpy(theButtons.button[7], "Go Back\n"); rc = Do_buttons(c, &answer, &theButtons); Do_send_clear(c); if (rc != S_NORM) { answer = 7; } /* switch on the player's answer */ switch (answer) { /* Continiue */ case 0: break; /* Go Back */ case 7: return; default: sprintf(error_msg, "[%s] Returned non-option in Do_change_character_password.\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); return; } for (;;) { /* prompt for the character */ if (Do_string_dialog(c, characterName, SZ_NAME - 1, "Which character's password do you wish to change?\n")) { return; } /* load the character information */ Do_lowercase(&lcCharacterName, &characterName); if (Do_look_character(c, lcCharacterName, &c->player)) { break; } /* see if the character is playing */ if (Do_character_playing(c, lcCharacterName)) { Do_send_line(c, "That character is currently in the game. You can not modify the passwords of characters in play.\n"); Do_more(c); Do_send_clear(c); return; } sprintf(string_buffer, "I can not find a character named \"%s\". Please check the spelling and try again.\n", characterName); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); } /* make sure we're on this character's parent account */ if (strcmp(c->player.parent_account, c->lcaccount)) { Do_send_line(c, "This character was not created from this account. You can only modify the passwords of characters you created.\n"); Do_more(c); Do_send_clear(c); return; } /* found character - confirm player by asking for password */ if (!Do_request_character_password(c, c->player.password, c->player.name, c->player.lcname, 0)) { return; } Do_clear_character_mod(&theMod); /* Get the new password from the player */ if (!Do_new_password(c, &theMod.password, "character")) { return; } theMod.newPassword = TRUE; if (!Do_modify_character(c, lcCharacterName, &theMod)) { /* if false returns, the character was not modified */ sprintf(string_buffer, "The character named \"%s\" is not in the character file. This could be because the character was just loaded by someone else. The password has NOT been changed.\n", c->player.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } sprintf(string_buffer, "[%s] Changed the password to character %s.\n", c->connection_id, c->player.lcname); Do_log(CONNECTION_LOG, string_buffer); sprintf(string_buffer, "The password to the character \"%s\" has been successfully changed.\n", c->player.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } /************************************************************************ / / FUNCTION NAME: Do_rename_character(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: Brian Kelly, 01/18/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / DESCRIPTION: / Prompt player, and roll up new character. / *************************************************************************/ Do_rename_character(struct client_t *c) { char error_msg[SZ_ERROR_MESSAGE], characterName[SZ_NAME]; char string_buffer[SZ_LINE], lcCharacterName[SZ_NAME]; struct button_t theButtons; struct player_mod_t theMod; int rc, theAnswer; long answer; Do_send_line(c, "You are asking to change the name of one of your characters. Do you wish to continue?\n"); strcpy(theButtons.button[0], "Continue\n"); Do_clear_buttons(&theButtons, 1); strcpy(theButtons.button[7], "Go Back\n"); rc = Do_buttons(c, &answer, &theButtons); Do_send_clear(c); if (rc != S_NORM) { answer = 7; } /* switch on the player's answer */ switch (answer) { /* Continue */ case 0: break; /* Go Back */ case 7: return; default: sprintf(error_msg, "[%s] Returned non-option in Do_rename_character.\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); return; } for (;;) { /* prompt for the character */ if (Do_string_dialog(c, characterName, SZ_NAME - 1, "What is the name of the character you wish to change?\n")) { return; } /* load the character information */ Do_lowercase(&lcCharacterName, &characterName); if (Do_look_character(c, lcCharacterName, &c->player)) { break; } /* see if the character is playing */ if (Do_character_playing(c, lcCharacterName)) { Do_send_line(c, "That character is currently in the game. You can not modifiy the passwords of characters in play.\n"); Do_more(c); Do_send_clear(c); return; } sprintf(string_buffer, "I can not find a character named \"%s\". Please check the spelling and try again.\n", characterName); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); } /* make sure we're on this character's parent account */ /* if (strcmp(c->player.parent_account, c->lcaccount)) { Do_send_line(c, "This character was not created from this account. You can only modify the passwords of characters you created.\n"); Do_more(c); Do_send_clear(c); return; } */ /* found character - confirm player by asking for password */ /* if (!Do_request_character_password(c, c->player.password, c->player.name, c->player.lcname, 0)) { return; } */ Do_clear_character_mod(&theMod); for (;;) { /* get the new character name */ if (Do_string_dialog(c, &theMod.name, SZ_NAME - 1, "What name would you like your character to have?\n")) { return; } /* see if the name is approved */ Do_lowercase(&theMod.lcName, &theMod.name); if (Do_approve_name(c, theMod.lcName, theMod.name, &theAnswer) != S_NORM) { return; } if (theAnswer) { break; } } theMod.newName = TRUE; if (!Do_modify_character(c, lcCharacterName, &theMod)) { /* if false returns, the character was not modified */ sprintf(string_buffer, "The character named \"%s\" is not in the character file so the name was not changed. This could be because the character was just loaded by someone else.\n", c->player.name); Do_release_name(c, theMod.lcName); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } Do_release_name(c, theMod.lcName); sprintf(string_buffer, "[%s] Changed character name %s to %s.\n", c->connection_id, c->player.lcname, theMod.lcName); Do_log(CONNECTION_LOG, string_buffer); sprintf(string_buffer, "[%s] %s renamed %s.\n", c->connection_id, c->player.lcname, theMod.lcName); Do_log(GAME_LOG, string_buffer); sprintf(string_buffer, "The character \"%s\" is now called \"%s\".\n", c->player.name, theMod.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } /************************************************************************ / / FUNCTION NAME: Do_reset_character_password(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: Brian Kelly, 1/4/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / DESCRIPTION: / Prompt player, and roll up new character. / *************************************************************************/ Do_reset_character_password(struct client_t *c) { char error_msg[SZ_ERROR_MESSAGE], characterName[SZ_NAME]; char string_buffer[SZ_LINE], lcCharacterName[SZ_NAME]; char newPassword[SZ_PASSWORD]; struct player_mod_t theMod; struct button_t theButtons; int rc; long answer; MD5_CTX context; unsigned int len; Do_send_line(c, "With this option a random password will be created for one of your characters and e-mailed to your account address. This is the only way to gain access to a character whose password you've forgotten.\n"); strcpy(theButtons.button[0], "Continue\n"); Do_clear_buttons(&theButtons, 1); strcpy(theButtons.button[7], "Go Back\n"); rc = Do_buttons(c, &answer, &theButtons); Do_send_clear(c); if (rc != S_NORM) { answer = 7; } /* switch on the player's answer */ switch (answer) { /* Continiue */ case 0: break; /* Go Back */ case 7: return; default: sprintf(error_msg, "[%s] Returned non-option in Do_reset_character_password.\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); return; } for (;;) { /* prompt for the character */ if (Do_string_dialog(c, characterName, SZ_NAME - 1, "Which character's password do you wish to reset?\n")) { return; } /* load the character information */ Do_lowercase(&lcCharacterName, &characterName); if (Do_look_character(c, lcCharacterName, &c->player)) { break; } /* see if the character is playing */ if (Do_character_playing(c, lcCharacterName)) { Do_send_line(c, "That character is currently in the game. You can not modifiy the passwords of characters in play.\n"); Do_more(c); Do_send_clear(c); return; } sprintf(string_buffer, "I can not find a character named \"%s\". Please check the spelling and try again.\n", characterName); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); } /* make sure we're on this character's parent account */ if (strcmp(c->player.parent_account, c->lcaccount)) { Do_send_line(c, "This character was not created from this account. You can only modify the passwords of characters you created.\n"); Do_more(c); Do_send_clear(c); return; } /* see if it's been longer than 24 hours since last reset */ if (time(NULL) - c->player.last_reset < 86400) { sprintf(string_buffer, "The password to the character named \"%s\" has been reset within the last 24 hours. You must wait before resetting it again.\n", c->player.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } sprintf(string_buffer, "Are you certain you wish to reset the password for the character named \"%s\"?\n", c->player.name); Do_send_line(c, string_buffer); if (Do_yes_no(c, &answer) != S_NORM || answer == 1) { Do_send_clear(c); sprintf(string_buffer, "Password reset aborted. The password to the character named \"%s\" has NOT been changed.\n", c->player.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } Do_send_clear(c); /* create a new password */ Do_create_password(&newPassword); /* call the script to e-mail this new password */ sprintf(string_buffer, "%s %s %s %s\n", CHARACTER_PASSWORD_RESET_SCRIPT, c->player.name, newPassword, c->email); /* if the mail send fails */ if (rc = system(string_buffer)) { sprintf(string_buffer, "[%s] Character password reset e-mail failed with a code of %d.", c->connection_id, rc); Do_log_error(string_buffer); Do_send_line(c, "An error occured while trying to send e-mail containing the new password. The character password has NOT been changed. Please contact the game administrator about this problem.\n"); Do_more(c); Do_send_clear(c); return; } Do_clear_character_mod(&theMod); theMod.newPassword = TRUE; theMod.passwordReset = TRUE; /* run the password through a MD5 hash */ len = strlen(newPassword); MD5Init(&context); MD5Update(&context, newPassword, len); /* put the password hash in place */ MD5Final(theMod.password, &context); /* make the modification */ if (!Do_modify_character(c, lcCharacterName, &theMod)) { /* if false returns, the character was not modified */ sprintf(string_buffer, "The character named \"%s\" is not in the character file. This could be because the character was just loaded by someone else. The password has NOT been changed.\n", c->player.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } sprintf(string_buffer, "[%s] Reset the password to character %s.\n", c->connection_id, c->player.lcname); Do_log(CONNECTION_LOG, string_buffer); sprintf(string_buffer, "The password to the character named \"%s\" has been successfully changed. Your new password has been e-mailed to your account address.\n", c->player.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); } /************************************************************************ / / FUNCTION NAME: Do_character_sharing(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: Brian Kelly, 1/5/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / DESCRIPTION: / Prompt player, and roll up new character. / *************************************************************************/ Do_character_sharing(struct client_t *c) { char error_msg[SZ_ERROR_MESSAGE], characterName[SZ_NAME]; char string_buffer[SZ_LINE], lcCharacterName[SZ_NAME]; struct player_mod_t theMod; struct button_t theButtons; int rc; long answer; Do_send_line(c, "By default, characters can only be loaded by the account that created them. Here you can remove or replace that restriction.\n"); strcpy(theButtons.button[0], "Continue\n"); Do_clear_buttons(&theButtons, 1); strcpy(theButtons.button[7], "Go Back\n"); rc = Do_buttons(c, &answer, &theButtons); Do_send_clear(c); if (rc != S_NORM) { answer = 7; } /* switch on the player's answer */ switch (answer) { /* Continiue */ case 0: break; /* Go Back */ case 7: return; default: sprintf(error_msg, "[%s] Returned non-option in Do_character_sharing.\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); return; } for (;;) { /* prompt for the character */ if (Do_string_dialog(c, characterName, SZ_NAME - 1, "Which character's sharing options do you wish to modify ?\n")) { return; } /* load the character information */ Do_lowercase(&lcCharacterName, &characterName); if (Do_look_character(c, lcCharacterName, &c->player)) { break; } /* see if the character is playing */ if (Do_character_playing(c, lcCharacterName)) { Do_send_line(c, "That character is currently in the game. You can not modifiy characters in play.\n"); Do_more(c); Do_send_clear(c); return; } sprintf(string_buffer, "I can not find a character named \"%s\". Please check the spelling and try again.\n", characterName); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); } /* make sure we're on this character's parent account */ if (strcmp(c->player.parent_account, c->lcaccount)) { Do_send_line(c, "This character was not created from this account. You can only modify characters you created.\n"); Do_more(c); Do_send_clear(c); return; } /* found character - now get the password */ if (!Do_request_character_password(c, c->player.password, c->player.name, c->player.lcname, 0)) { return; } if (c->player.faithful) { sprintf(string_buffer, "Currently, other accounts can not load the character named \"%s\".\n", c->player.name); } else { sprintf(string_buffer, "Currently, other accounts have permission to load the character named \"%s\".\n", c->player.name); } Do_send_line(c, string_buffer); Do_send_line(c, "\n"); Do_send_line(c, "If another account attempts to load this character, do you wish to allow or deny their request?\n"); Do_clear_character_mod(&theMod); strcpy(theButtons.button[0], "Allow\n"); strcpy(theButtons.button[1], "Deny\n"); Do_clear_buttons(&theButtons, 2); strcpy(theButtons.button[7], "Cancel\n"); rc = Do_buttons(c, &answer, &theButtons); Do_send_clear(c); if (rc != S_NORM) { answer = 7; } /* switch on the player's answer */ switch (answer) { /* Allow */ case 0: theMod.faithful = FALSE; break; /* Deny */ case 1: theMod.faithful = TRUE; break; /* Cancel */ case 7: return; default: sprintf(error_msg, "[%s] Returned non-option in Do_character_sharing(2).\n", c->connection_id); Do_log_error(error_msg); Do_caught_hack(c, H_SYSTEM); return; } theMod.newPermissions = TRUE; if (!Do_modify_character(c, lcCharacterName, &theMod)) { /* if false returns, the character was not modified */ sprintf(string_buffer, "The character named \"%s\" is not in the character file. This could be because the character was just loaded by someone else. The permissions have NOT been changed.\n", c->player.name); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); return; } if (answer) { sprintf(error_msg, "[%s] Faithful permissions set on character %s.\n", c->connection_id, c->player.lcname); sprintf(string_buffer, "Permissions have been set so other accounts will be denied access to the character named \"%s\".\n", c->player.name); } else { sprintf(error_msg, "[%s] Faithful permissions removed on character %s.\n", c->connection_id, c->player.lcname); sprintf(string_buffer, "Permissions have been set so other accounts may load the character named \"%s\".\n", c->player.name); } Do_log(CONNECTION_LOG, error_msg); Do_send_line(c, string_buffer); Do_more(c); Do_send_clear(c); } /************************************************************************ / / FUNCTION NAME: Do_approve_entrance(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: Brian Kelly, 1/14/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / DESCRIPTION: / / *************************************************************************/ Do_approve_entrance(struct client_t *c) { struct event_t *event_ptr; /* Mark this thread as with character */ c->characterLoaded = TRUE; /* assume the name is not modified */ strcpy(c->modifiedName, c->player.name); /* if the character was knight after crash */ if (c->player.special_type == SC_KNIGHT) { Do_dethrone(c); } if (c->player.special_type == SC_STEWARD) { Do_dethrone(c); } /* if the character was king after crash */ if (c->player.special_type == SC_KING) { Do_lock_mutex(&c->realm->realm_lock); /* check to see if we're the old king */ if (! strcmp(c->realm->king_name, c->modifiedName)) { Do_unlock_mutex(&c->realm->realm_lock); if (c->player.level >= MIN_KING && c->player.level < MAX_KING) { Do_king(c); } else { Do_dethrone(c); c->player.special_type = SC_NONE; } } else { /* there has been a new king */ Do_unlock_mutex(&c->realm->realm_lock); Do_send_line(c, "You are no longer the ruler!\n"); c->player.special_type = SC_NONE; } } /* handle if the character was valar after crash */ else if (c->player.special_type == SC_VALAR) { Do_lock_mutex(&c->realm->realm_lock); /* check for a current valar */ if (! strcmp (c->realm->valar_name, c->modifiedName)) { /* no valar, put ourselves */ Do_unlock_mutex(&c->realm->realm_lock); c->realm->valar = c->game; strcpy(c->realm->valar_name, c->modifiedName); } else { /* there is a valar, bow out */ Do_unlock_mutex(&c->realm->realm_lock); Do_valar(c); } } /* check for tags to this address, connection or character */ Do_check_tags(c); /* done here */ return; } /************************************************************************ / / FUNCTION NAME: Do_entering_character(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: Brian Kelly, 1/4/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / DESCRIPTION: / / *************************************************************************/ Do_entering_character(struct client_t *c) { char string_buffer[SZ_LINE], error_msg[SZ_ERROR_MESSAGE]; FILE *wizard_file, *motd_file; char theNetwork[SZ_FROM], theAccount[SZ_NAME], theCharacter[SZ_NAME]; short wizType; char *char_ptr; int minutes; struct event_t *event_ptr; int exceptionFlag; /* pull death name out of limbo if necessary */ if (c->previousName[0] != '\0') { Do_release_name(c, c->previousName); c->previousName[0] = '\0'; } /* open the wizard file to see if this person is one */ if ((wizard_file=fopen(WIZARD_FILE, "r")) == NULL) { sprintf(error_msg, "[%s] fopen of %s failed in Do_entering_character: %s\n", c->connection_id, WIZARD_FILE, strerror(errno)); Do_log_error(error_msg); } else { /* loop through the the names */ while (fscanf(wizard_file, "%d %s %s %s %d\n", &wizType, &theNetwork, &theAccount, &theCharacter, &exceptionFlag) == 5) { if (!strcmp(theCharacter, c->player.lcname) && !strcmp( theAccount, c->lcaccount) && (!strcmp(theNetwork, c->network) || exceptionFlag)) { c->wizard = wizType; break; } } fclose(wizard_file); } /* if appearing in ch 8 with a palantir, make them hear ch 1 */ if (c->channel == 8) { if (!c->player.palantir) { c->channel = 1; } else { c->game->hearAllChannels = HEAR_ONE; } } /* send everyone your spec */ Do_send_specification(c, ADD_PLAYER_EVENT); /* put characters in their proper area */ if (c->wizard > 2) { c->player.location = PL_VALHALLA; } else if (c->player.purgatoryFlag) { c->player.location = PL_PURGATORY; } else { c->player.location = PL_REALM; } /* force the loaded values to the players status window */ Do_update_stats(c); /* log the entry */ sprintf(string_buffer, "[%s] Entering realm with character %s.\n", c->connection_id, c->player.lcname); Do_log(CONNECTION_LOG, string_buffer); /* set the player's timeout */ if (c->wizard > 2) { c->timeout = 900; } else if (c->player.level < 80) { c->timeout = 60 - c->player.level / 2; } else { c->timeout = 20; } /* show the player last load stats and update */ Do_last_load_info(c); Do_send_line(c, "\n"); /* show the player the message of the day */ /* try to open the MOTD file */ errno = 0; if ((motd_file = fopen(MOTD_FILE, "r")) != NULL && fgets(string_buffer, SZ_LINE, motd_file) != NULL) { if (((char_ptr = (char *) strstr(string_buffer, "TESTING ")) != NULL) && c->wizard < 1) { char_ptr += sizeof("TESTING "); /* send a message to the user */ if (sscanf(char_ptr, "%d", &minutes) != 0) { sprintf(string_buffer, "The game is currently down for testing. Try back in 15 minutes.\n"); } else { sprintf(string_buffer, "The game is currently down for testing. Try back in %d minutes.\n", minutes); } Do_send_error(c, string_buffer); if (c->characterLoaded == TRUE) { c->run_level = SAVE_AND_EXIT; } else { c->run_level = EXIT_THREAD; } fclose(motd_file); return; } else { /* print message of the day */ Do_send_line(c, string_buffer); } fclose(motd_file); } else { /* log an error message */ sprintf(error_msg, "[%s] fopen of %s failed in Do_entering_character: %s.\n", c->connection_id, MOTD_FILE, strerror(errno)); Do_log_error(error_msg); } Do_send_buffer(c); if (c->wizard < 1) { sleep(3); } Do_more(c); Do_send_clear(c); /* announce the player entrance */ if (c->wizard > 2) { sprintf(string_buffer, "In a brilliant flash, Wizard %s appears in the realm!\n", c->modifiedName); } else if (c->wizard == 2) { sprintf(string_buffer, "In a puff of smoke, Apprentice %s the %s appears in the realm!\n", c->modifiedName, c->realm->charstats[c->player.type].class_name); } else if (c->player.special_type == SC_VALAR) { sprintf(string_buffer, "Tremble, for the Valar %s has arrived!\n", c->modifiedName); } else { sprintf(string_buffer, "A new player appears in the realm, %s the %s.\n", c->modifiedName, c->realm->charstats[c->player.type].class_name); } c->characterAnnounced = TRUE; Do_broadcast(c, string_buffer); /* It's okay to chat now */ Do_send_int(c, ACTIVATE_CHAT_PACKET); if (c->player.energy <= 0.0) { event_ptr = (struct event_t *) Do_create_event(); event_ptr->type = DEATH_EVENT; event_ptr->arg1 = (double) c->battle.ring_in_use; event_ptr->arg3 = K_NO_ENERGY; Do_handle_event(c, event_ptr); } /* handle purgatory */ if (c->player.purgatoryFlag) { Do_send_line(c, "This character was in combat previously when the connection was interrupted. You will now re-encounter that monster.\n"); Do_more(c); Do_send_clear(c); c->player.purgatoryFlag = FALSE; /* Throw the monster at the player */ event_ptr = (struct event_t *) Do_create_event(); event_ptr->type = MONSTER_EVENT; event_ptr->arg1 = MONSTER_PURGATORY; event_ptr->arg3 = (long) c->player.monsterNumber; Do_handle_event(c, event_ptr); /* return the player to the realm */ c->player.location = PL_REALM; Do_location(c, c->player.x, c->player.y, TRUE); } } /************************************************************************ / / FUNCTION NAME: Do_handle_save(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: Brian Kelly, 01/18/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / DESCRIPTION: / Prompt player, and roll up new character. / *************************************************************************/ Do_handle_save(struct client_t *c) { char string_buffer[SZ_LINE]; Do_save_character(c, &c->player); /* remove the character's backup */ Do_backup_save(c, FALSE); c->characterLoaded = FALSE; /* log the saving */ sprintf(string_buffer, "[%s] %s saved\n", c->connection_id, c->player.lcname); Do_log(GAME_LOG, &string_buffer); /* if server is shutting down or socket error */ if (c->run_level == SAVE_AND_CONTINUE) { c->run_level = GO_AGAIN; } else { c->run_level = EXIT_THREAD; } return; } /************************************************************************ / / FUNCTION NAME: Do_leaving_character(struct client_t *c) / / FUNCTION: roll up a new character / / AUTHOR: Brian Kelly, 1/4/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw (), / getanswer(), getstring() / / DESCRIPTION: / Prompt player, and roll up new character. / *************************************************************************/ Do_leaving_character(struct client_t *c) { char string_buffer[SZ_LINE]; struct event_t *event_ptr; float ftemp; /* handle remaining events */ Do_orphan_events(c); while (c->events != NULL) { /* remove the next event */ event_ptr = c->events; c->events = event_ptr->next_event; /* take care of it */ if (event_ptr->type > GAME_MARKER) { free((void *)event_ptr); } else { Do_handle_event(c, event_ptr); } } /* if the character is steward, knight, or king, de-throne him first */ if (c->player.special_type == SC_STEWARD || c->player.special_type == SC_KNIGHT || c->player.special_type == SC_KING) { Do_dethrone(c); } ftemp = pow(fabs(c->player.x) / 100, .5); /* if the character is on a post, boot him off */ if ((fabs(c->player.x) == fabs(c->player.y)) && (floor(ftemp) == ftemp)) { /* if the player can not leave the chamber now, return */ if (c->stuck) { Do_send_line(c, "Another player is arriving...'\n"); Do_more(c); Do_send_clear(c); return; } /* Kick live players off of posts, dead characters off of door steps */ if ((c->player.energy <= 0.0) || (c->player.strength <= 0.0)) { Do_send_line(c, "The merchant scowls, and kicks your corpse off the steps of his shop!'\n"); } else { event_ptr = (struct event_t *) Do_create_event(); event_ptr->type = MOVE_EVENT; event_ptr->arg3 = A_NEAR; Do_handle_event(c, event_ptr); Do_send_line(c, "The merchant scowls, says 'No loitering!, and throws you out!'\n"); } } /* if the character is valar, remove from the realm */ if (c->player.special_type == SC_VALAR) { Do_lock_mutex(&c->realm->realm_lock); c->realm->valar = NULL; Do_unlock_mutex(&c->realm->realm_lock); } /* turn off palantir */ if (c->channel == 8) { c->game->hearAllChannels = HEAR_SELF; } /* announce the player's departure */ if (c->run_level == SAVE_AND_CONTINUE || c->run_level == SAVE_AND_EXIT) { if (c->wizard > 2) { sprintf(string_buffer, "%s slowly fades from the realm!\n", c->modifiedName); } else { sprintf(string_buffer, "%s retires from the realm.\n", c->modifiedName); } Do_broadcast(c, string_buffer); } /* kill the character if leaving quickly */ else if (c->run_level == EXIT_THREAD) { /* kill the player */ event_ptr = (struct event_t *) Do_create_event(); event_ptr->type = DEATH_EVENT; event_ptr->arg1 = FALSE; event_ptr->arg3 = K_SUICIDE; Do_handle_event(c, event_ptr); } /* erase the player description */ Do_lock_mutex(&c->realm->realm_lock); free(c->game->description); c->game->description = NULL; Do_unlock_mutex(&c->realm->realm_lock); /* remove the player specification */ Do_send_specification(c, REMOVE_PLAYER_EVENT); c->characterAnnounced = FALSE; c->timeout = 120; /* chat no more */ Do_send_int(c, DEACTIVATE_CHAT_PACKET); /* log the entry */ sprintf(string_buffer, "[%s] Leaving realm.\n", c->connection_id); Do_log(CONNECTION_LOG, string_buffer); /* record time character has been playing */ c->player.time_played += time(NULL) - c->player.last_load; if (c->wizaccount[0] != '\0') { strcpy(c->account, c->wizaccount); c->wizaccount[0] = '\0'; } if (c->wizIP[0] != '\0') { strcpy(c->IP, c->wizIP); c->wizIP[0] = '\0'; } }