phantasia4/
phantasia4/conf/
phantasia4/phantasia/bin/
phantasia4/phantasia/src/utilities/
phantasia4/public_html/cgi-bin/
/*
 * init.c - startup/shutdown routines for Phantasia
 */

#include "include.h"

extern int server_hook;
extern randomStateBuffer;
extern randData;

/************************************************************************
/
/ FUNCTION NAME: Do_initialize(struct server_t *server)
/
/ FUNCTION: To initialize the program's variables
/
/ AUTHOR: Brian Kelly, 4/6/99
/
/ ARGUMENTS:
/       struct server_t *s - address of the server's main data strcture
/
/ RETURN VALUE: short error
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
/
/ GLOBAL OUTPUTS: _iob[]
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

Init_server(struct server_t *s)
{
    char error_msg[SZ_ERROR_MESSAGE];
    int error;
    struct realm_object_t *object_ptr;

	/* seed the random number generator */
    initstate_r (time(NULL), (char *)&randomStateBuffer, STATELEN,
	    (struct random_data *)&randData);

	/* initialize realm variables */
    server_hook = s->run_level;
    s->realm.serverPid = getpid();
    s->realm.objects = NULL;
    s->realm.games = NULL;
    s->realm.king = NULL;
    s->realm.valar = NULL;
    s->realm.king_flag = FALSE;
    s->realm.king_name[0] = '\0';
    s->realm.valar_name[0] = '\0';
    s->realm.name_limbo = NULL;
    s->realm.email_limbo = NULL;
    s->realm.connections = NULL;
    s->realm.steward_gold = 0;

	/* initialize all the realm mutexes */
    Do_init_mutex(&s->realm.realm_lock);

    Do_init_mutex(&s->realm.backup_lock);
    Do_init_mutex(&s->realm.scoreboard_lock);
    Do_init_mutex(&s->realm.account_lock);
    Do_init_mutex(&s->realm.character_file_lock);
    Do_init_mutex(&s->realm.log_file_lock);
    Do_init_mutex(&s->realm.network_file_lock);
    Do_init_mutex(&s->realm.tag_file_lock);
    Do_init_mutex(&s->realm.tagged_file_lock);
    Do_init_mutex(&s->realm.history_file_lock);

    Do_init_mutex(&s->realm.monster_lock);
    Do_init_mutex(&s->realm.object_lock);
    Do_init_mutex(&s->realm.kings_gold_lock);
    Do_init_mutex(&s->realm.hack_lock);
    Do_init_mutex(&s->realm.connections_lock);

	/* set the number to tags to the time */
    s->realm.nextTagNumber = Do_get_next_tag();

	/* load the realm objects and the king's gold */
    s->realm.objects = NULL;
    error = Do_load_data_file(&s->realm);

	/* if there's an error, we can continue, just with no objects */
    if (error) {

        sprintf(error_msg, "[0.0.0.0:%d] Phantasia will continue with no objects from previous games.\n", s->realm.serverPid);

        Do_log_error(error_msg);

	    /* set kings and stewards gold to zero */
        s->realm.kings_gold = 0;

	    /* only the grail should exist */
	while (s->realm.objects != NULL) {
	    object_ptr = s->realm.objects;
	    s->realm.objects = object_ptr->next_object;
	    free((void *)object_ptr);
	}

        Do_hide_grail(&s->realm, 5000);
        Do_hide_trove(&s->realm);
    }

	/* load the monsters into the realm array */
    Do_load_monster_file(&s->realm);

	/* load the charstats into the realm array */
    Do_load_charstats_file(&s->realm);
	
	/* load the shop items into the realm array */
    Do_load_shopitems_file(&s->realm);

	/* restore any characters in the backup file */
    Do_backup_restore();
	
	/* initialize the server variables */
    s->num_games = 0;

	/* start up the socket connection */
    s->the_socket = Do_init_server_socket();

	/* no problems */
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_load_data_file(struct *realm_t)
/
/ FUNCTION: To load saved configuration information
/
/ AUTHOR: Brian Kelly, 4/8/99
/
/ ARGUMENTS:
/       struct realm_t *the_realm - pointer to the realm
/
/ RETURN VALUE: short error
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

int Do_load_data_file(the_realm)

    struct realm_t *the_realm;

{
    FILE *data_file;
    struct realm_object_t *object_ptr;
    struct realm_state_t *state_ptr;
    char error_msg[SZ_ERROR_MESSAGE];
    int error;
    int grailCount = 0, troveCount = 0;

    state_ptr = (struct realm_state_t *) Do_malloc(SZ_REALM_STATE);

	/* open the data file - for king's gold and corpses */
    errno = 0;
    if ((data_file = fopen(DATA_FILE, "r")) == NULL) {

        sprintf(error_msg,
		"[0.0.0.0:%d] fopen of %s failed in Do_load_data_file: %s\n",
		the_realm->serverPid, DATA_FILE, strerror(errno));

        Do_log_error(error_msg);
        return DATA_FILE_ERROR;
    }

    if (fread((void *) state_ptr, SZ_REALM_STATE, 1, data_file) != 1) {

        sprintf(error_msg,
		"[0.0.0.0:%d] fread of %s failed in Do_load_data_file: %d\n",
		the_realm->serverPid, DATA_FILE, ferror(data_file));

        Do_log_error(error_msg);
        fclose(data_file);
        return DATA_FILE_ERROR;
    }

    the_realm->kings_gold = state_ptr->kings_gold;
    strcpy(the_realm->king_name, state_ptr->king_name);
    strcpy(the_realm->valar_name, state_ptr->valar_name);

	/* destroy the temporary realm state object */
    free((void *)state_ptr);

	/* first entry is king's gold as double float */
/*
    if (fread((void *) &the_realm->kings_gold, sizeof(the_realm->kings_gold),
	    1, data_file) != 1) {

        sprintf(error_msg,
		"[0.0.0.0:%d] fread of %s failed in Do_load_data_file: %d\n",
		the_realm->serverPid, DATA_FILE, ferror(data_file));

        Do_log_error(error_msg);
        fclose(data_file);
        return DATA_FILE_ERROR;
    }
*/

	/* all remaining items are realm objects */
	/* create a structure to read into */
    object_ptr = (struct realm_object_t *) Do_malloc(SZ_REALM_OBJECT);

	/* read next object while not at EOF */
    while (fread((void *) object_ptr, SZ_REALM_OBJECT, 1, data_file) == 1) {

        switch (object_ptr->type) {

        case CORPSE:

                /* create an strcture to hold the character information */
            object_ptr->arg1 = (void *) malloc(SZ_PLAYER);

	        /* and read in the dead player's information */
            if (fread(object_ptr->arg1, SZ_PLAYER, 1, data_file) == 0) {

                sprintf(error_msg,
	       "[0.0.0.0:%d] fread of %s failed in Do_load_data_file(2): %d\n",
	       the_realm->serverPid, DATA_FILE, ferror(data_file));

                Do_log_error(error_msg);
                fclose(data_file);
		free((void *)object_ptr->arg1);
		free((void *)object_ptr);
                return DATA_FILE_ERROR;
	    }

                /* used to be CORPSE_LIFE */
	    if (86400 * sqrt(((struct player_t *) object_ptr->arg1)->level) 
                < time(NULL) - ((struct player_t *)object_ptr->arg1)->last_load) {

		    /* delete the object */
		free((void *)object_ptr->arg1);
		free((void *)object_ptr);
            }
	    else {
	            /* put the new corpse in the realm object list */
        	object_ptr->next_object = the_realm->objects;
        	the_realm->objects = object_ptr;
	    }

            break;

            /* if the object is the holy grail, we do nothing special */
        case HOLY_GRAIL:

	        /* put the item in the realm object list */
            object_ptr->next_object = the_realm->objects;
            the_realm->objects = object_ptr;
	    ++grailCount;
            break;

            /* if the object is the treasure trove, we do nothing special */
        case TREASURE_TROVE:

	        /* put the item in the realm object list */
            object_ptr->next_object = the_realm->objects;
            the_realm->objects = object_ptr;
	    ++troveCount;
            break;

            /* anything else is an error */
        default:

            sprintf(error_msg,
      "[0.0.0.0:%d] bad realm object of type %hd read in Do_load_data_file.\n",
      the_realm->serverPid, object_ptr->type);

            Do_log_error(error_msg);
            fclose(data_file);
	    free((void *)object_ptr);
            return DATA_FILE_ERROR;
        }

	    /* create a new temporary realm object */        
        object_ptr = (struct realm_object_t *)malloc(SZ_REALM_OBJECT);
    }

	/* destroy the remaining temporary realm object */
    free((void *)object_ptr);

	/* if we found no grail, hide a new one */
    if (grailCount == 0) {

	sprintf(error_msg,
     "[0.0.0.0:%d] No grail found in Do_load_data_file. Creating a new one.\n",
     the_realm->serverPid);

	Do_log_error(error_msg);
        Do_hide_grail(the_realm, 5000);
    }
    else if (grailCount != 1) {

	sprintf(error_msg,
	   "[0.0.0.0:%d] Read in %d grails in Do_load_data_file.\n",
	   the_realm->serverPid, grailCount);

	Do_log_error(error_msg);
	return DATA_FILE_ERROR;
    }
    
	/* if we found no treasure trove, hide a new one */
    if (troveCount == 0) {

	sprintf(error_msg, "[0.0.0.0:%d] No treasure trove found in Do_load_data_file. Creating a new one.\n", the_realm->serverPid);

	Do_log_error(error_msg);
        Do_hide_trove(the_realm);
    }
    else if (troveCount != 1) {

	sprintf(error_msg,
	   "[0.0.0.0:%d] Read in %d treasure troves in Do_load_data_file.\n",
	   the_realm->serverPid, troveCount);

	Do_log_error(error_msg);
	return DATA_FILE_ERROR;
    }

    return 0;	/* no problems */
}


/************************************************************************
/
/ FUNCTION NAME: Do_load_monster_file(struct realm_t *the_realm)
/
/ FUNCTION: To load saved configuration information
/
/ AUTHOR: Brian Kelly, 4/8/99
/
/ ARGUMENTS:
/       struct realm_t *the_realm - pointer to the realm strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

Do_load_monster_file(struct realm_t *the_realm)
{
    FILE *monster_file;
    char error_msg[SZ_ERROR_MESSAGE];
    int i;

	/* load monster information */
    errno = 0;

	/* open the monster file */
    if ((monster_file = fopen(MONSTER_FILE, "r")) == NULL) {

        sprintf(error_msg,
	       "[0.0.0.0:%d] fopen of %s failed in Do_load_monster_file: %s\n",
	       the_realm->serverPid, MONSTER_FILE, strerror(errno));

        Do_log_error(error_msg);
        exit(MONSTER_FILE_ERROR);
    }

	/* read each line of the monster file */
    for (i = 0; i < NUM_MONSTERS; i++) {

	    /* read the monster name which is on its own line */
        if (fgets(the_realm->monster[i].name, SZ_MONSTER_NAME, monster_file)
		== NULL) {

            sprintf(error_msg, "[0.0.0.0:%d] fgets of %s failed on call number %d in Do_load_monster_file.\n", the_realm->serverPid, MONSTER_FILE, i);

            Do_log_error(error_msg);
            exit(MONSTER_FILE_ERROR);
        }

             /* reEmove trailing blanks */
        Do_truncstring(the_realm->monster[i].name);

	    /* read the stat line for each monster */
        if (fscanf(monster_file, "%lf %lf %lf %lf %lf %hd %hd %hd\n",
		&the_realm->monster[i].strength, &the_realm->monster[i].brains,
		&the_realm->monster[i].speed, &the_realm->monster[i].energy,
		&the_realm->monster[i].experience,
		&the_realm->monster[i].treasure_type,
		&the_realm->monster[i].special_type,
		&the_realm->monster[i].flock_percent) != 8) {

		/* exit if we didn't read 8 items */
            sprintf(error_msg, "[0.0.0.0:%d] fscanf of %s failed on call number %d in Do_load_monster_file.\n", the_realm->serverPid, MONSTER_FILE, i);

            Do_log_error(error_msg);
            exit(MONSTER_FILE_ERROR);
        }
    }

	/* close the monster file */
    fclose(monster_file);

	/* all done here */
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_load_charstats_file(struct realm_t *the_realm)
/
/ FUNCTION: To load saved configuration information
/
/ AUTHOR: Brian Kelly, 5/7/99
/
/ ARGUMENTS:
/       struct realm_t *the_realm - pointer to the realm strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

Do_load_charstats_file(struct realm_t *the_realm)
{
    FILE *charstats_file;
    char error_msg[SZ_ERROR_MESSAGE];
    int i;

	/* load charstats information */
    errno = 0;

	/* open the charstats file */
    if ((charstats_file = fopen(CHARSTATS_FILE, "r")) == NULL) {

        sprintf(error_msg,
		"[0.0.0.0:%d] fopen of %s failed Do_load_charstats_file: %s\n",
		the_realm->serverPid, CHARSTATS_FILE, strerror(errno));

        Do_log_error(error_msg);
        exit(CHARSTATS_FILE_ERROR);
    }

	/* read each line of the monster file */
    for (i = 0; i < NUM_CHARS; i++) {

	    /* read the character name which is on its own line */
        if (fgets(the_realm->charstats[i].class_name, SZ_CLASS_NAME,
		charstats_file) == NULL) {

            sprintf(error_msg, "[0.0.0.0:%d] fgets of %s failed on call number %d in Do_load_charstats_file.\n", the_realm->serverPid, CHARSTATS_FILE, i);

            Do_log_error(error_msg);
            exit(CHARSTATS_FILE_ERROR);
        }

             /* reEmove trailing blanks */
        Do_truncstring(the_realm->charstats[i].class_name);

	    /* read the stat line for each monster */
        if (fscanf(charstats_file, "%c %lf %lf %lf %lf %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
		&the_realm->charstats[i].short_class_name,
		&the_realm->charstats[i].max_brains,
		&the_realm->charstats[i].max_mana,
		&the_realm->charstats[i].weakness,
		&the_realm->charstats[i].goldtote,
		&the_realm->charstats[i].ring_duration,
		&the_realm->charstats[i].quickness.base,
		&the_realm->charstats[i].quickness.interval,
		&the_realm->charstats[i].quickness.increase,
		&the_realm->charstats[i].strength.base,
		&the_realm->charstats[i].strength.interval,
		&the_realm->charstats[i].strength.increase,
		&the_realm->charstats[i].mana.base,
		&the_realm->charstats[i].mana.interval,
		&the_realm->charstats[i].mana.increase,
		&the_realm->charstats[i].energy.base,
		&the_realm->charstats[i].energy.interval,
		&the_realm->charstats[i].energy.increase,
		&the_realm->charstats[i].brains.base,
		&the_realm->charstats[i].brains.interval,
		&the_realm->charstats[i].brains.increase,
		&the_realm->charstats[i].magiclvl.base,
		&the_realm->charstats[i].magiclvl.interval,
		&the_realm->charstats[i].magiclvl.increase) != 24) {

		/* exit if we didn't read 24 items */
            sprintf(error_msg, "[0.0.0.0:%d] fscanf of %s failed on call number %d in Do_load_charstats_file.\n", the_realm->serverPid, CHARSTATS_FILE, i);

            Do_log_error(error_msg);
            exit(CHARSTATS_FILE_ERROR);
        }
    }

	/* close the charstats file */
    fclose(charstats_file);

	/* all done here */
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_load_shopitems_file(struct realm_t *the_realm)
/
/ FUNCTION: To load saved configuration information
/
/ AUTHOR: Brian Kelly, 6/29/99
/
/ ARGUMENTS:
/       struct realm_t *the_realm - pointer to the realm strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

Do_load_shopitems_file(struct realm_t *the_realm)
{
    FILE *shopitems_file;
    char error_msg[SZ_ERROR_MESSAGE];
    int i;

	/* load shopitems information */
    errno = 0;

	/* open the shopitems file */
    if ((shopitems_file = fopen(SHOPITEMS_FILE, "r")) == NULL) {

        sprintf(error_msg,
	     "[0.0.0.0:%d] fopen of %s failed in Do_load_shopitems_file: %s\n",
	     the_realm->serverPid, SHOPITEMS_FILE, strerror(errno));

        Do_log_error(error_msg);
        exit(SHOPITEMS_FILE_ERROR);
    }

	/* read each line of the monster file */
    for (i = 0; i < NUM_ITEMS; i++) {

	    /* read the character name which is on its own line */
        if (fgets(the_realm->shop_item[i].item, SZ_ITEMS, shopitems_file)
		== NULL) {

            sprintf(error_msg, "[0.0.0.0:%d] fgets of %s failed on call number %d in Do_load_shopitems_file.\n", the_realm->serverPid, SHOPITEMS_FILE, i);

            Do_log_error(error_msg);
            exit(SHOPITEMS_FILE_ERROR);
        }

             /* reEmove trailing blanks */
        Do_truncstring(the_realm->shop_item[i].item);

	    /* read the stat line for each item */
        if (fscanf(shopitems_file, "%lf\n", &the_realm->shop_item[i].cost)
		!= 1) {

		/* exit if we didn't read 24 items */
            sprintf(error_msg, "[0.0.0.0:%d] fscanf of %s failed on call number %d in Do_load_shopitems_file.\n", the_realm->serverPid, SHOPITEMS_FILE, i);

            Do_log_error(error_msg);
            exit(SHOPITEMS_FILE_ERROR);
        }
    }

	/* close the charstats file */
    fclose(shopitems_file);

	/* all done here */
    return;
}


/************************************************************************
/
/ FUNCTION NAME: void Do_close(struct server_t *server)
/
/ FUNCTION: To close the program's data files 
/
/ AUTHOR: Brian Kelly, 4/22/99
/
/ ARGUMENTS:
/       struct server_t *s - address of the server's main data strcture
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

void Do_close(struct server_t *s)
{
    FILE *data_file;
    struct realm_object_t *object_ptr, *object_ptr2;
    struct realm_state_t *state_ptr;
    char error_msg[SZ_ERROR_MESSAGE];
    int error;

    state_ptr = (struct realm_state_t *) Do_malloc(SZ_REALM_STATE);

    state_ptr->kings_gold = s->realm.kings_gold;
    strcpy(state_ptr->king_name, s->realm.king_name);
    strcpy(state_ptr->valar_name, s->realm.valar_name);
    
	/* open the data file - for saving kings, valars, and corpses */
    errno = 0;
    if ((data_file = fopen(DATA_FILE, "w")) == NULL) {

        sprintf(error_msg, "[0.0.0.0:%d] fopen of %s failed in Do_close: %s\n",
		s->realm.serverPid, DATA_FILE, strerror(errno));

        Do_log_error(error_msg);
        exit(DATA_FILE_ERROR);
    }

    if (fwrite((void *) state_ptr, SZ_REALM_STATE, 1, data_file)
            != 1) {

        sprintf(error_msg,
		"[0.0.0.0:%d] fwrite of %s's realm state failed in Do_close: %d\n",
		s->realm.serverPid, DATA_FILE, ferror(data_file));

        Do_log_error(error_msg);
        fclose(data_file);
        exit(DATA_FILE_ERROR);
    }

	/* destroy the temporary realm state object */
    free((void *)state_ptr);

	/* first entry is king's gold as double float */
/*
    if (fwrite((void *)&s->realm.kings_gold, sizeof(double), 1, data_file)
            != 1) {

        sprintf(error_msg,
		"[0.0.0.0:%d] fwrite of %s failed in Do_close: %d\n",
		s->realm.serverPid, DATA_FILE, ferror(data_file));

        Do_log_error(error_msg);
        fclose(data_file);
        exit(DATA_FILE_ERROR);
    }
*/

	/* all remaining items are realm objects */
    object_ptr = s->realm.objects;

	/* while there is an item in the list of realm objects */
    while (object_ptr != NULL) {

	    /* write the object if it is a corpse, holy grail or treasure */
	if (object_ptr->type == HOLY_GRAIL || object_ptr->type == CORPSE ||
		object_ptr->type == TREASURE_TROVE) {	

		/* write the object to the data file */
            if (fwrite((void *)object_ptr, SZ_REALM_OBJECT, 1, data_file) !=
		    1) {

                sprintf(error_msg,
		       "[0.0.0.0:%d] fwrite of %s failed in Do_close(2): %d\n",
		       s->realm.serverPid, DATA_FILE, ferror(data_file));

                Do_log_error(error_msg);
                fclose(data_file);
                exit(DATA_FILE_ERROR);
	    }

	        /* if the object is a corpse object */
	    if (object_ptr->type == CORPSE) {

		    /* write the character record with it */
                if (fwrite((void *)object_ptr->arg1, SZ_PLAYER, 1, data_file)
			!= 1) {

                    sprintf(error_msg,
		       "[0.0.0.0:%d] fwrite of %s failed in Do_close(3): %d\n",
		       s->realm.serverPid, DATA_FILE, ferror(data_file));

                    Do_log_error(error_msg);
                    fclose(data_file);
                    exit(DATA_FILE_ERROR);
		}

		free((void *)object_ptr->arg1);
	    }
	}

	    /* point to the next realm object */
	object_ptr2 = object_ptr;
	object_ptr = object_ptr->next_object;
	free((void*)object_ptr2);
    }

	/* close the data file */
    fclose(data_file);

    return; /* no problems */
}


/************************************************************************
/
/ FUNCTION NAME: Do_hide_grail(struct *realm_t, int level)
/
/ FUNCTION: To load saved configuration information
/
/ AUTHOR: E. A. Estes, 12/4/85
/	  Brian Kelly, 8/17/99
/
/ ARGUMENTS:
/       struct realm_t *the_realm - pointer to the realm
/
/ RETURN VALUE: short error
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

int Do_hide_grail(the_realm, level)

    struct realm_t *the_realm;
    int level;

{
    double distance;
    char error_msg[SZ_ERROR_MESSAGE];

/* WARNING: Realm should already be locked when function is called */
/* or it shouldn't matter (startup) */

    struct realm_object_t *object_ptr;

    object_ptr = the_realm->objects;

    while (object_ptr != NULL) {

	if (object_ptr->type == HOLY_GRAIL) {

	    sprintf(error_msg,
	 "[0.0.0.0:%d] Do_hide_grail found a holy grail already in the realm.",
	 the_realm->serverPid);

	    Do_log_error(error_msg);
	    return;
	}

        object_ptr = object_ptr->next_object;
    }

    if (level < 3000) {
        level = 3000;
    }

	/* create a holy grail realm object */
    object_ptr = (struct realm_object_t *) Do_malloc(SZ_REALM_OBJECT);
    object_ptr->type = HOLY_GRAIL;

    /* place grail within point of no return */
    for (;;) {
        object_ptr->x = 0.0;
        object_ptr->y = 0.0;
        Do_move_close(&object_ptr->x, &object_ptr->y, 1000000.0);

	Do_distance(0.0, object_ptr->x, 0.0, object_ptr->y, &distance);

	if (distance >= level * 100) {
	    break;
	}
    }

    object_ptr->next_object = the_realm->objects;
    the_realm->objects = object_ptr;
}


/************************************************************************
/
/ FUNCTION NAME: Do_hide_trove(struct *realm_t)
/
/ FUNCTION: To load saved configuration information
/
/ AUTHOR: E. A. Estes, 12/4/85
/	  Brian Kelly, 5/9/01
/
/ ARGUMENTS:
/       struct realm_t *the_realm - pointer to the realm
/
/ RETURN VALUE: short error
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

int Do_hide_trove(struct realm_t *the_realm)
{
    double distance;
    char error_msg[SZ_ERROR_MESSAGE];
    struct realm_object_t *object_ptr;

/* WARNING: Realm should already be locked when function is called */
/* or it shouldn't matter (startup) */

    object_ptr = the_realm->objects;

    while(object_ptr != NULL) {

	if (object_ptr->type == TREASURE_TROVE) {

	    sprintf(error_msg,
	 "[0.0.0.0:%d] Do_hide_trove found a trove already in the realm.\n",
	 the_realm->serverPid);

	    Do_log_error(error_msg);
	    return;
	}

        object_ptr = object_ptr->next_object;
    }

	/* create a treasure_trove realm object */
    object_ptr = (struct realm_object_t *) Do_malloc(SZ_REALM_OBJECT);
    object_ptr->type = TREASURE_TROVE;

    for (;;) {

        object_ptr->x = 0.0;
        object_ptr->y = 0.0;
        Do_move_close(&object_ptr->x, &object_ptr->y, 1400.0);

	Do_distance(0.0, object_ptr->x, 0.0, object_ptr->y, &distance);

	if (distance >= 600) {
	    break;
	}
    }

    object_ptr->next_object = the_realm->objects;
    the_realm->objects = object_ptr;

    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_backup_restore()
/
/ FUNCTION: To load saved configuration information
/
/ AUTHOR: Brian Kelly, 11/26/99
/
/ ARGUMENTS:
/       struct realm_t *the_realm - pointer to the realm
/
/ RETURN VALUE: short error
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

Do_backup_restore()
{
    FILE *backup_file;
    FILE *character_file;
    struct player_t the_player;
    char error_msg[SZ_ERROR_MESSAGE];
    int restoreCount = 0;

	/* open the backup file */
    errno = 0;
    if ((backup_file=fopen(BACKUP_FILE, "r")) == NULL) {

	   /* No backup file?  Cool! */
        return;
    }

        /* open the character file */
    errno = 0;
    if ((character_file=fopen(CHARACTER_FILE, "a")) == NULL) {

        sprintf(error_msg,
		"[0.0.0.0:?] fopen of %s failed in Do_backup_restore: %s\n",
		CHARACTER_FILE, strerror(errno));

        Do_log_error(error_msg);
	fclose(backup_file);
        return;
    }

       /* read each line of the backup file */
    errno = 0;
    while (fread((void *)&the_player, SZ_PLAYER, 1, backup_file) == 1) {

	    /* write the character to the charcter file */
        if (fwrite((void *)&the_player, SZ_PLAYER, 1, character_file) != 1) {

            sprintf(error_msg,
                  "[0.0.0.0:?] fwrite of %s failed in Do_backup_restore: %s\n",
                  CHARACTER_FILE, strerror(errno));

            Do_log_error(error_msg);
            fclose(backup_file);
            fclose(character_file);
            return;
        }
	else {

            sprintf(error_msg, "[0.0.0.0:?] %s restored\n", the_player.lcname);
            Do_log(SERVER_LOG, error_msg);
	    Do_log(GAME_LOG, error_msg);

	    ++restoreCount;
	}
    }

        /* delete the old backup file */
    remove(BACKUP_FILE);
    fclose(backup_file);
    fclose(character_file);

    if (restoreCount) {
        sprintf(error_msg, "Server restored %d characters.\n", restoreCount);
        Do_log(SERVER_LOG, error_msg);
    }

    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_get_next_tag()
/
/ FUNCTION: To load saved configuration information
/
/ AUTHOR: Brian Kelly, 01/18/01
/
/ ARGUMENTS:
/       struct realm_t *the_realm - pointer to the realm
/
/ RETURN VALUE: short error
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
/           - strip non-printing characters (unless Wizard)
/           - echo, if desired
/           - redraw the screen if CH_REDRAW is entered
/           - read in only 'mx - 1' characters or less characters
/           - nul-terminate string, and throw away newline
/
/       'mx' is assumed to be at least 2.
/
*************************************************************************/

int Do_get_next_tag()
{
    FILE *the_file;
    char error_msg[SZ_ERROR_MESSAGE];
    struct tag_t readTag;
    struct tagged_t readTagged;
    int lastTagNumber = 0;

    if ((the_file=fopen(TAG_FILE, "r")) != NULL) {

            /* run through the tag entries */
        while (fread((void *)&readTag, SZ_TAG, 1, the_file) == 1) {

	        /* see if this is the highest numbered tag */
	    if (readTag.number > lastTagNumber) {
	        lastTagNumber = readTag.number;
	    }
	}

	fclose(the_file);
    }

    if ((the_file=fopen(TAGGED_FILE, "r")) != NULL) {

            /* run through the tag entries */
        while (fread((void *)&readTagged, SZ_TAGGED, 1, the_file) == 1) {

	        /* see if this is the highest numbered tag */
	    if (readTagged.tagNumber > lastTagNumber) {
	        lastTagNumber = readTagged.tagNumber;
	    }
	}

	fclose(the_file);
    }

    return lastTagNumber + 1;
}