phantasia4/
phantasia4/conf/
phantasia4/phantasia/bin/
phantasia4/phantasia/src/utilities/
phantasia4/public_html/cgi-bin/
/*
 * misc.c       Multiple small utility procedures
 */

#include "include.h"
extern randData;
extern server_hook;

/***************************************************************************
/ FUNCTION NAME: Do_init_mutex(pthread_mutex_t *the_mutex)
/
/ FUNCTION: Initializes the passed mutex
/
/ AUTHOR:  Brian Kelly, 4/19/99
/
/ ARGUMENTS: 
/	pthread_mutex_t the_mutex - The mutex to be initialized
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Procedure handles errors from mutex operations.
/
****************************************************************************/

Do_init_mutex(pthread_mutex_t *the_mutex)
{
    char error_msg[SZ_ERROR_MESSAGE];
    int error;

	/* initialize the passed mutex */
    error = pthread_mutex_init(the_mutex, NULL);
    if (error) {

	sprintf(error_msg, "[0.0.0.0:?] pthread_mutex_init failed with %d return code in Do_init_mutex.\n", error);

	Do_log_error(error_msg);
	exit(MUTEX_INIT_ERROR);
    }
}


/***************************************************************************
/ FUNCTION NAME: Do_destroy_mutex(pthread_mutex_t *the_mutex)
/
/ FUNCTION: Initializes the passed mutex
/
/ AUTHOR:  Brian Kelly, 4/19/99
/
/ ARGUMENTS: 
/	pthread_mutex_t the_mutex - The mutex to be destroyed
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Procedure handles errors from mutex operations.
/
****************************************************************************/

void Do_destroy_mutex(pthread_mutex_t *the_mutex)
{
    char error_msg[SZ_ERROR_MESSAGE];
    int error;

	/* destroy the passed mutex */
    error = pthread_mutex_destroy(the_mutex);
    if (error) {

	sprintf(error_msg, "[0.0.0.0:?] pthread_mutex_destroy failed with %d return code in Do_destroy_mutex.\n", error);

	Do_log_error(error_msg);
	exit(MUTEX_DESTROY_ERROR);
    }
}


/***************************************************************************
/ FUNCTION NAME: Do_lock_mutex(pthread_mutex_t *the_mutex)
/
/ FUNCTION: Locks the passed mutex
/
/ AUTHOR:  Brian Kelly, 4/19/99
/
/ ARGUMENTS: 
/	pthread_mutex_t the_mutex - The mutex to be locked
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Procedure handles errors from mutex operations.
/
****************************************************************************/

void Do_lock_mutex(pthread_mutex_t *the_mutex)
{
    char error_msg[SZ_ERROR_MESSAGE];
    int error;

#ifdef MUTEX_DEBUG
sprintf(error_msg, "Request mutex %x lock.\n", the_mutex);
Do_log(DEBUG_LOG, error_msg);
#endif

	/* lock the passed mutex */
    error = pthread_mutex_lock(the_mutex);
    if (error) {

	sprintf(error_msg, "[?:?] pthread_mutex_lock failed with %d return code in Do_lock_mutex.\n", error);

	Do_log_error(error_msg);
	exit(MUTEX_LOCK_ERROR);
    }
#ifdef MUTEX_DEBUG
sprintf(error_msg, "Mutex %x locked.\n", the_mutex);
Do_log(DEBUG_LOG, error_msg);
#endif
}


/***************************************************************************
/ FUNCTION NAME: Do_unlock_mutex(pthread_mutex_t *the_mutex)
/
/ FUNCTION: Unlocks the passed mutex
/
/ AUTHOR:  Brian Kelly, 4/19/99
/
/ ARGUMENTS: 
/	pthread_mutex_t the_mutex - The mutex to be unlocked
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Procedure handles errors from mutex operations.
/
****************************************************************************/

void Do_unlock_mutex(pthread_mutex_t *the_mutex)
{
    char error_msg[SZ_ERROR_MESSAGE];
    int error;

	/* unlock the passed mutex */
    error = pthread_mutex_unlock(the_mutex);
    if (error) {

	sprintf(error_msg, "[?:?] pthread_mutex_unlock failed with a %d return code in Do_unlock_mutex.\n", error);

	Do_log_error(error_msg);
	exit(MUTEX_UNLOCK_ERROR);
    }
#ifdef MUTEX_DEBUG
sprintf(error_msg, "Mutex %x unlocked.\n", the_mutex);
Do_log(DEBUG_LOG, error_msg);
#endif
}


/***************************************************************************
/ FUNCTION NAME: void *Do_malloc(struct size_t the_size)
/
/ FUNCTION: Returns the pointer to a new memory space
/
/ AUTHOR:  Brian Kelly, 4/20/99
/
/ ARGUMENTS:
/	struct size_t the_size - The size of the memory space to allocate
/
/ RETURN VALUE: 
/	void * - pointer to the new memory space
/
/ DESCRIPTION:
/       Procedure handles errors for malloc calls.
/
****************************************************************************/

void *Do_malloc(size_t the_size)
{
    void *void_ptr;
    char error_msg[SZ_ERROR_MESSAGE];

	/* create the new memory space */
    void_ptr = malloc(the_size);
    if (void_ptr == NULL) {

	sprintf(error_msg, "[?:?] malloc failed on size %d in Do_malloc.\n",
		the_size);

	Do_log_error(error_msg);
	exit(MALLOC_ERROR);
    }
}


/************************************************************************
/
/ FUNCTION NAME: int Do_random(void)
/
/ FUNCTION: return a random floating point number from 0.0 < 1.0
/
/ AUTHOR: E. A. Estes, 2/7/86
/	  Brian Kelly, 4/20/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: random()
/
/ GLOBAL INPUTS: none
/
/ GLOBAL OUTPUTS: none
/
/ DESCRIPTION:
/       Convert random integer from library routine into a floating
/       point number, and divide by the largest possible random number.
/       We mask large integers with 32767 to handle sites that return
/       31 bit random integers.
/
*************************************************************************/

int Do_random()
{
    char error_msg[SZ_ERROR_MESSAGE];
    int error, result;

    if (error = random_r((struct random_data *)&randData, &result)) {

	sprintf(error_msg,
		"[?:?] random_r failed with error code of %d in Do_random.\n",
		error);

	Do_log_error(error_msg);
    }

	/* return an unsigned 4 byte number */
    return result;
}

/************************************************************************
/
/ FUNCTION NAME: Do_name_location(struct client_t *c)
/
/ FUNCTION: return a formatted description of location
/
/ AUTHOR: E. A. Estes, 12/4/85
/
/ ARGUMENTS:
/       struct player playerp - pointer to player structure
/       bool shortflag - set if short form is desired
/
/ RETURN VALUE: pointer to string containing result
/
/ MODULES CALLED: fabs(), floor(), sprintf(), distance()
/
/ DESCRIPTION:
/       Look at coordinates and return an appropriately formatted
/       string.
/
*************************************************************************/

Do_name_location(struct client_t *c)
{
int    quadrant;       /* quandrant of grid */
char	error_msg[SZ_ERROR_MESSAGE];
char     *nametable[4][4] =   /* names of places */
        {
        "Anorien",      "Ithilien",     "Rohan",        "Lorien",
        "Gondor",       "Mordor",       "Dunland",      "Rovanion",
        "South Gondor", "Khand",        "Eriador",      "The Iron Hills",
        "Far Harad",    "Near Harad",   "The Northern Waste", "Rhun"
        };

    if (c->player.location == PL_REALM) {

        if (c->player.beyond) {
            strcpy(c->player.area, "The Point of No Return");
	}
	else if (c->player.circle >= 400.0) 
            strcpy(c->player.area, "The Ashen Mountains");
        else if (c->player.circle >= 100)
            strcpy(c->player.area, "Kennaquahir");
        else if (c->player.circle >= 36)
            strcpy(c->player.area, "Morannon");
        else if ((c->player.circle == 27) || (c->player.circle == 28)) 
            strcpy(c->player.area, "The Cracks of Doom");
        else if ((c->player.circle > 24) && (c->player.circle < 31)) 
            strcpy(c->player.area, "The Plateau of Gorgoroth");
        else if (c->player.circle >= 20)
            strcpy(c->player.area, "The Dead Marshes");
        else if (c->player.circle >= 10)
            strcpy(c->player.area, "The Outer Waste");
        else if (c->player.circle >= 5)
            strcpy(c->player.area, "The Moors Adventurous");
        else {

    /* this expression is split to prevent compiler loop with some compilers */
            quadrant = ((c->player.x > 0.0) ? 1 : 0);
            quadrant += ((c->player.y >= 0.0) ? 2 : 0);

            strcpy(c->player.area,
		    nametable[((int) c->player.circle) - 1][quadrant]);
        }
    }
    else if (c->player.location == PL_THRONE) {
        strcpy(c->player.area, "The Lord's Chamber");
    }
    else if (c->player.location == PL_EDGE) {
        strcpy(c->player.area, "Edge Of The Realm");
    }
    else if (c->player.location == PL_VALHALLA) {
        strcpy(c->player.area, "Valhalla");
    }
    else if (c->player.location == PL_PURGATORY) {
        strcpy(c->player.area, "Purgatory");
    }
	/* no other places to be */
    else {
        strcpy(c->player.area, "State Of Insanity");

        sprintf(error_msg,
		"[%s] Bad c->player.area of %hd in Do_name_location.\n",
		c->connection_id, c->player.area);
    }
}


/************************************************************************
/
/ FUNCTION NAME: Do_truncstring()
/
/ FUNCTION: truncate trailing blanks off a string
/
/ AUTHOR: E. A. Estes, 12/4/85
/	  Brian Kelly, 5/4/99
/
/ ARGUMENTS:
/       char *string - pointer to null terminated string
/
/ RETURN VALUE: none
/
/ MODULES CALLED: strlen()
/
/ DESCRIPTION:
/       Put nul characters in place of spaces at the end of the string.
/
*************************************************************************/

Do_truncstring(char *string)
{
    int length;         /* length of string */

    length = strlen(string);
    while (length && !isgraph(string[--length]))
        string[length] = '\0';
}


/************************************************************************
/
/ FUNCTION NAME: Do_distance()
/
/ FUNCTION: calculate distance between two points
/
/ AUTHOR: E. A. Estes, 12/4/85
/         Brian Kelly, 6/20/99
/
/ ARGUMENTS:
/       double x1, y1 - x, y coordinates of first point
/       double x2, y2 - x, y coordinates of second point
/
/ RETURN VALUE: distance between the two points
/
/ MODULES CALLED: sqrt()
/
/ GLOBAL INPUTS: none
/
/ GLOBAL OUTPUTS: none
/
/ DESCRIPTION:
/       This function is provided because someone's hypot() library function
/       fails if x1 == x2 && y1 == y2.
/
*************************************************************************/

Do_distance(double x1, double x2, double y1, double y2, double *answer)
{
    double  deltax, deltay;

    deltax = x1 - x2;
    deltay = y1 - y2;

    *answer = sqrt(deltax * deltax + deltay * deltay);
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_move(struct client_t c, float new_x, float new_y, int operation)
/
/ FUNCTION: truncate trailing blanks off a string
/
/ AUTHOR: E. A. Estes, 12/4/85
/	  Brian Kelly, 5/8/99
/
/ ARGUMENTS:
/       char *string - pointer to null terminated string
/
/ RETURN VALUE: none
/
/ MODULES CALLED: strlen()
/
/ DESCRIPTION:
/       Put nul characters in place of spaces at the end of the string.
/
*************************************************************************/

Do_move(struct client_t *c, struct event_t *the_event)
{
    struct event_t *event_ptr, *event_ptr_two, **event_ptr_ptr;
    struct realm_object_t *object_ptr, **object_ptr_ptr;
    struct game_t *game_ptr;
    double dtemp, x = 0, y = 0;
    double distance;
    bool pause = FALSE;
    char error_msg[SZ_ERROR_MESSAGE];
    long answer;
    short oldLocation;

	/* determine the destination coordinates */
    switch (the_event->arg3) {

    case A_NEAR:
	the_event->arg1 = c->player.x;
	the_event->arg2 = c->player.y;
	dtemp = (double) Do_maxmove(c);
	Do_move_close(&the_event->arg1, &the_event->arg2, dtemp);
        break;

    case A_FAR:     /* pick random coordinates far */

	the_event->arg1 = SGN(c->player.x) * (D_CIRCLE + fabs(c->player.x)) *
		(2 * RND() + 2);

	the_event->arg2 = SGN(c->player.y) * (D_CIRCLE + fabs(c->player.y)) *
		(2 * RND() + 2);
        break;

    case A_TRANSPORT:	/* send out aways */

	Do_move_close(&x, &y, 2000 * RND());

	    /* use whichever x is larger of old and new */
	if (fabs(c->player.x) > fabs(x)) {
	    the_event->arg1 = c->player.x;
        }
        else {
	    the_event->arg1 = x;
        }

	    /* use whichever y is larger of old and new */
	if (fabs(c->player.y) > fabs(y)) {
	    the_event->arg2 = c->player.y;
        }
        else {
	    the_event->arg2 = y;
        }

	break;

    case A_OUST:	/* send out aways more */

	Do_move_close(&x, &y, 50000 * RND());

	    /* use whichever x is larger of old and new */
	if (fabs(c->player.x) > fabs(x)) {
	    the_event->arg1 = c->player.x;
        }
        else {
	    the_event->arg1 = x;
        }

	    /* use whichever y is larger of old and new */
	if (fabs(c->player.y) > fabs(y)) {
	    the_event->arg2 = c->player.y;
        }
        else {
	    the_event->arg2 = y;
        }

	break;

	/* send beyond */
    case A_BANISH:

        if (fabs(c->player.x) > fabs(c->player.y)) {

            the_event->arg1 = c->player.x;
	    the_event->arg2 = c->player.y;

	    if (fabs(c->player.x) < D_BEYOND) {
                the_event->arg1 = SGN(c->player.x) * D_BEYOND;
	    }

	}
        else {

            the_event->arg1 = c->player.x;
	    the_event->arg2 = c->player.y;

	    if (fabs(c->player.y) < D_BEYOND) {
                the_event->arg2 = SGN(c->player.y) * D_BEYOND;
	    }
        }
	break;
    }

	/* round the new location down */
    the_event->arg1 = floor(the_event->arg1);
    the_event->arg2 = floor(the_event->arg2);

	/* lock the realm */
    Do_lock_mutex(&c->realm->realm_lock);

	/* check to make sure there are no it_combat events not received */
    if (Do_check_encountered(c)) {
	Do_unlock_mutex(&c->realm->realm_lock);
	c->stuck = TRUE;
	return;
    }

	/* the move is successful - handle any events in the queue */
	/* only orphan events if the player is leaving the square -
	this closes the king safe send through deliberate itcombat */
    if (the_event->arg1 != c->player.x || the_event->arg2 != c->player.y) {
	Do_orphan_events(c);
    }

	/* if returning from beyond */
    if (the_event->arg3 != A_FORCED && c->player.beyond &&
	    fabs(the_event->arg1) < D_BEYOND && fabs(the_event->arg2)
	    < D_BEYOND) {

            /* cannot move back from point of no return */
            /* pick the largest coordinate to remain unchanged */
        if (fabs(c->player.x) > fabs(c->player.y)) {

	    the_event->arg1 = SGN(c->player.x) * D_BEYOND;
/*
	    if (fabs(c->player.x) < D_BEYOND) {
		the_event->arg1 = SGN(c->player.x) * D_BEYOND;
	    }
*/
	}
        else {

	    the_event->arg2 = SGN(c->player.y) * D_BEYOND;
/*
	    if (fabs(c->player.y) < D_BEYOND) {
		the_event->arg2 = SGN(c->player.y) * D_BEYOND;
	    }
*/
        }
    }

	/* see if the player is beyond */
    c->player.beyond = FALSE;
    oldLocation = c->player.location;

    if (fabs(the_event->arg1) >= D_BEYOND || fabs(the_event->arg2)
	    >= D_BEYOND) {

        c->player.beyond = TRUE;
    }

	/* if moving off the board's edge */
    if (fabs(the_event->arg1) >= D_EDGE || fabs(the_event->arg2) >= D_EDGE) {

	        /* stop a character at the edge */
	        /* send over if they move that way again */
        if ((fabs(the_event->arg1) > D_EDGE || fabs(the_event->arg2) > D_EDGE)
		&& c->player.location == PL_EDGE && 
                (the_event->arg3 == A_SPECIFIC || 
                 the_event->arg3 == A_TELEPORT)) {

	    Do_unlock_mutex(&c->realm->realm_lock);
	    event_ptr = (struct event_t *) Do_create_event();
	    event_ptr->type = DEATH_EVENT;
	    event_ptr->arg3 = K_FELL_OFF;
	    Do_file_event(c, event_ptr);
	    return;
	}

	c->player.location = PL_EDGE;

	if (fabs(the_event->arg1) > D_EDGE) {
	    the_event->arg1 = SGN(the_event->arg1) * D_EDGE;
	}

	if (fabs(the_event->arg2) > D_EDGE) {
	    the_event->arg2 = SGN(the_event->arg2) * D_EDGE;
	}
    }
    else {
	c->player.location = PL_REALM;
    }

	/* see if we're in the throne room */
    if (the_event->arg1 == 0 && the_event->arg2 == 0) {

	    /* if this player is not the king/steward */
	if (c->game != c->realm->king) {

		/* if this player believes himself to be, quit */
		/* we will have an event pending */
	    if (c->player.special_type == SC_STEWARD || c->player.special_type
		    == SC_KING) {

	        Do_unlock_mutex(&c->realm->realm_lock);
	        return;
	    }

		/* if this character is to be steward */
	    if (c->player.level >= 10 && c->player.level < 200) {

		    /* and if this player has a staff */
	        if (c->player.crowns) {

			    /* and there is no king */
		    if (!c->realm->king_flag) {

		            /* enter the throne room */
		        c->player.location = PL_THRONE;

 		            /* if there is a steward currently on the throne */
	                if (c->realm->king != NULL && c->realm->king->x == 0 &&
			    c->realm->king->y == 0) {

		        /* do nothing.  If victorious, he'll be crowned in
				the it_combat routines */
		        }
		        else {

		                /* become steward */
		            Do_send_self_event(c, STEWARD_EVENT);
	                }
		    }

			/* there is a king when we're trying to be steward */
		    else {

		        Do_send_line(c,
		    "There is no need for a steward while a king presides!\n");

		        pause = TRUE;

		        Do_move_close(&the_event->arg1, &the_event->arg2,
			        Do_maxmove(c));
		    }
		}

		    /* if the (10-200) player has no staff */
	        else {

		    Do_send_line(c,
			 "You require a staff to enter The Lord's Chamber.\n");

		    pause = TRUE;

		    Do_move_close(&the_event->arg1, &the_event->arg2,
			    Do_maxmove(c));
		}
	    }

		/* if this character is to be king */
	    else if (c->player.level >= MIN_KING && c->player.level < MAX_KING) {

		    /* and if this player has a crown */
	        if (c->player.crowns) {

		        /* enter the throne room */
		    c->player.location = PL_THRONE;

 		        /* if there is a king currently on the throne */
	            if (c->realm->king != NULL && c->realm->king->x == 0 &&
			c->realm->king->y == 0) {

				/* if that character is a king */
			    if (c->realm->king_flag) {

		                /* do nothing.  If victorious, he'll be crowned
				in the it_combat routines */
			    }
			    else {

				    /* make the curent steward virtual */
				c->realm->king->virtual = TRUE;

				    /* take the throne */
		         	Do_send_self_event(c, KING_EVENT);
			    }
		    }
		    else {

		            /* become king */
		        Do_send_self_event(c, KING_EVENT);
	            }
		}

		    /* if the (1000-2000) player has no crown */
	        else {

		    Do_send_line(c,
			 "You require a crown to enter The Lord's Chamber.\n");

		    pause = TRUE;

		    Do_move_close(&the_event->arg1, &the_event->arg2,
			    Do_maxmove(c));
		}
	    }

		/* the character is above the king level */
	    else if (c->player.level >= 2000) {

		Do_send_line(c, "The head page says, 'Get out of here, you greedy bastard.' and throws you out of The Lord's Chamber.\n");

		pause = TRUE;
		Do_move_close(&the_event->arg1, &the_event->arg2, Do_maxmove(c));
	    }

		/* the character is of the wrong level */
	    else {

		Do_send_line(c, "The head page stops you and says, 'Characters of your level may not enter The Lord's Chamber.'\n");

		pause = TRUE;
		Do_move_close(&the_event->arg1, &the_event->arg2, Do_maxmove(c));
	    }
	}
	    /* if the player already is king or steward */
	else {
	    c->player.location = PL_THRONE;
	}
    }

	/* check for possible combat */
    dtemp = FALSE;
    game_ptr = c->realm->games;
    while (game_ptr != NULL) {

	if (game_ptr->description != NULL && !game_ptr->virtual &&
		game_ptr->x == the_event->arg1 && game_ptr->y ==
		the_event->arg2 && game_ptr != c->game) {

	    dtemp = TRUE;
	    break;
	}
	game_ptr = game_ptr->next_game;
    }

	/* if we've encountered someone */
    if (dtemp) {

	    /* confirm the move if player moved under own power */
	if (event_ptr->arg3 == A_SPECIFIC || event_ptr->arg3 == A_TELEPORT) {

	        /* release the realm */
            Do_unlock_mutex(&c->realm->realm_lock);
	    pause = FALSE;

	    Do_send_line(c, "The square you're moving into is currently occupied by another player.  Do you still wish to move there?\n");

	    if (Do_yes_no(c, &answer) != S_NORM || answer == 1) {

		    /* abort the move if the player says "no" */
                Do_send_clear(c);
	        c->player.location = oldLocation;
                return;
	    }

            Do_send_clear(c);

	        /* relock the realm */
	    Do_lock_mutex(&c->realm->realm_lock);

	        /* see if someone else has attacked this player */
            if (Do_check_encountered(c)) {
	        Do_unlock_mutex(&c->realm->realm_lock);
	        c->stuck = TRUE;
	        return;
	    }

	        /* make sure a player is still there */
	    dtemp = 0;
            game_ptr = c->realm->games;
            while (game_ptr != NULL) {

	        if (game_ptr->description != NULL && !game_ptr->virtual &&
		        game_ptr->x == the_event->arg1 && game_ptr->y ==
		        the_event->arg2 && game_ptr != c->game) {

	            dtemp = 1;
	            break;
		}

	        game_ptr = game_ptr->next_game;
	    }
	}
    }

	/* set public and private variables to the new coordinates */
    if (c->wizard > 2) {
	c->player.location = PL_VALHALLA;
    }

    Do_location(c, the_event->arg1, the_event->arg2, FALSE);

        /* move the grail if player teleported close to it */
/*
    if (the_event->arg3 == A_TELEPORT) {
	object_ptr = c->realm->objects;

	while (object_ptr != NULL) {

	    if (object_ptr->type == HOLY_GRAIL) {
		break;
	    }

	    object_ptr = object_ptr->next_object;
	}

	if (object_ptr == NULL) {

	    Do_unlock_mutex(&c->realm->realm_lock);

	    sprintf(error_msg,
		    "[%s] No grail found in realm objects in Do_move.\n",
		    c->connection_id);

	    Do_log_error(error_msg);

	    return;
	}

	Do_distance(c->player.x, object_ptr->x, c->player.y, object_ptr->y,
		&distance);


        if (distance <= c->player.level / 500.0) {

	    sprintf(error_msg,
		    "Teleporting grail.\n");

	    Do_log_error(error_msg);

            free((void *)object_ptr);
	    Do_hide_grail(c->realm, c->player.level);
        }

    }
*/
        

	/* look for realm objects if destination has no players */
    if (dtemp == 0) {

            /* if a player is cloaked, he/she can't find realm objects */
        if (!c->player.cloaked) {

	        /* check for realm objects in the new location */
            object_ptr_ptr = &c->realm->objects;

            while(*object_ptr_ptr != NULL) {

	        if ((*object_ptr_ptr)->x == c->player.x && (*object_ptr_ptr)->y
			== c->player.y) {

	            object_ptr = *object_ptr_ptr;
	            *object_ptr_ptr = object_ptr->next_object;

	            event_ptr = (struct event_t *) Do_create_event();
	    
	            switch (object_ptr->type) {

	            case CORPSE:
		        event_ptr->type = CORPSE_EVENT;

			    /* the corpse can be cursed */
		        event_ptr->arg1 = TRUE;
		        event_ptr->arg4 = object_ptr->arg1;
		        break;

	            case HOLY_GRAIL:
		        event_ptr->type = GRAIL_EVENT;
		        Do_hide_grail(c->realm, c->player.level);
		        break;

	            case ENERGY_VOID:
		        event_ptr->type = ENERGY_VOID_EVENT;
		        break;

		    case TREASURE_TROVE:
		        event_ptr->type = TROVE_EVENT;
			Do_hide_trove(c->realm);
			break;

	            default:

	                sprintf(error_msg,
		      "[%s] encountered realm object of type %d in Do_move.\n",
	    	      c->connection_id, object_ptr->type);

		        Do_log_error(error_msg);	
	            }

	            Do_file_event(c, event_ptr);

	            free((void *)object_ptr);
	        }
	        else {
	            object_ptr_ptr = &((*object_ptr_ptr)->next_object);
	        }
	    }
        }

	Do_unlock_mutex(&c->realm->realm_lock);

        if (pause) {
	    Do_more(c);
            Do_send_clear(c);
        }
    }

	/* else we have found a player to fight */
    else {
 
	    /* pass this function with realm locked! */
	Do_setup_it_combat(c, game_ptr);
    }

    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_check_weight(c)
/
/ FUNCTION: truncate trailing blanks off a string
/
/ AUTHOR: E. A. Estes, 12/4/85
/	  Brian Kelly, 5/16/99
/
/ ARGUMENTS:
/       char *string - pointer to null terminated string
/
/ RETURN VALUE: none
/
/ MODULES CALLED: strlen()
/
/ DESCRIPTION:
/       Put nul characters in place of spaces at the end of the string.
/
*************************************************************************/

Do_check_weight(struct client_t *c)
{
    Do_speed(c, c->player.max_quickness, c->player.quicksilver,
	    c->battle.speedSpell, FALSE);
}


/************************************************************************
/
/ FUNCTION NAME: Do_medic(struct client_t *c)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: E. A. Estes, 3/3/86
/         Brian Kelly, 6/20/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

Do_medic(struct client_t *c)
{
    double gold;
    char string_buffer[SZ_LINE];
    float ftemp;

    if (c->player.blind) {

        Do_send_line(c, "You've found a medic!\n");

	if (Do_double_dialog(c, &gold,
		"How much will you offer to heal your blindness?\n")) {

            Do_send_clear(c);
	    return;
	}

                /* negative gold, or more than available */
        if (gold < 0.0 || gold > c->player.gold) {
            Do_send_line(c, "He was not amused, and gave you a disease.\n");
            Do_adjusted_poison(c, 1.0);
	    Do_strength(c, c->player.max_strength, c->player.sword, 0, FALSE);
        }
        else if (gold < c->player.level * 10) {
            Do_send_line(c, "Sorry, he thinks you're too powerful an adventurer to be offering him so little.\n");
	} 
        else if (RND() > (gold + 1.0) / (c->player.gold + 4.0)) {

                /* medic wants nearly all of available gold */
            Do_send_line(c, "Sorry, he wasn't interested.\n");
	}
        else {
            Do_send_line(c, "He accepted.\n");
	    c->player.blind = FALSE;
	    Do_gold(c, -gold, FALSE);
        }
        Do_more(c);
        Do_send_clear(c);
    }
    else if (c->player.poison > 0.0) {

        Do_send_line(c, "You've found a medic!\n");

	if (Do_double_dialog(c, &gold,
		"How much will you offer to be cured?\n")) {

            Do_send_clear(c);
	    return;
	}

                /* negative gold, or more than available */
        if (gold < 0.0 || gold > c->player.gold) {
            Do_send_line(c, "He was not amused, and made you worse.\n");
            Do_adjusted_poison(c, 1.0);
	    Do_strength(c, c->player.max_strength, c->player.sword, 0, FALSE);
        }
                /* medic needs at least a certain amount of gold to cure */
        else if (gold < c->player.level) {
            Do_send_line(c, "Sorry, he thinks you're too powerful an adventurer to be offering him so little.\n");
	} 
        else if (gold < pow(c->player.poison, 2.5)) {
            Do_send_line(c, "Sorry, you didn't offer enough to treat your virulent poison.\n");
	} 
        else if (RND() > (1 / c->player.poison) * sqrt(c->player.circle)) {
            Do_send_line(c, "Sorry, the medic says the poison is beyond his ability to cure.  Find a better one.\n");
	} 
        else if (RND() > (1 + MAX(0, (1 - .1 * c->player.poison))) 
                          * (gold + 1.0) / 
                          (c->player.gold + 2.0)) {

                /* medic wants 1/2 of available gold for 1 poison */
                /* as poison goes to infinity, the medic will only cure
                   25% of the time when player gives all gold */

            Do_send_line(c, "Sorry, he wasn't interested.\n");
	}
        else {
            Do_send_line(c, "He accepted.\n");
	    Do_poison(c, (double) -c->player.poison);
	    Do_gold(c, -gold, FALSE);
        }
        Do_more(c);
        Do_send_clear(c);
    }
}


/************************************************************************
/
/ FUNCTION NAME: Do_tax(struct client_t *c)
/
/ FUNCTION: Tax time!
/
/ AUTHOR: Eugene Hung, 6/16/01
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: none
/
/ GLOBAL INPUTS: none
/
/ GLOBAL OUTPUTS: none
/
/ DESCRIPTION:
/       Handle tax collecting
/
*************************************************************************/

Do_tax(struct client_t *c)
{
    double gold, gems;
    char error_msg[SZ_ERROR_MESSAGE];

    /* no tax collectors in the PoNR */
    if (c->player.beyond) {
        return;
    }

    Do_send_line(c, "You've encountered a tax collector!\n");

    if ((c->player.special_type == SC_VALAR) || (c->wizard >= 3)) {
        Do_send_line(c, "He takes one look at you, screams, and tries to run away!\n");
	Do_more(c);
        Do_send_line(c, "You reach out, and squish him with your little finger!\n");
	Do_more(c);
	Do_send_clear(c);
        return;
    }
    else if (c->player.special_type >= SC_COUNCIL) {
        Do_send_line(c, "He takes one look at you and runs away screaming in terror!\n");
	Do_more(c);
	Do_send_clear(c);
        return;
    }
    else if (c->player.special_type >= SC_STEWARD) {
        Do_send_line(c, "He bows before you and walks off.\n");
	Do_more(c);
	Do_send_clear(c);
        return;
    }

	/* at 7% we'll only take if there's at least 15 of something */
    if (c->player.gems >= 15.0) {

	Do_send_line(c, "His eyes glow at the sight of your gems.  He swipes a portion of your wealth and disappears!\n");

    }
	/* at 10% we'll only take if there's at least 10 of something */
    else if (c->player.gold >= 10.0) {

	Do_send_line(c, "He cackles gleefully and takes some of your gold before disappearing!\n");

    }
    else if (c->player.gems == 0.0) {

	Do_send_line(c, "'Ah,' he says, 'A candidate for our welfare program.'  He flips you a gold piece, gives a satisfied smile, and disappears!\n");

	Do_more(c);
	Do_send_clear(c);
	Do_gold(c, 1.0, FALSE);
        return;
    }
    else {

	Do_send_line(c, "He lectures, 'How can our kingdom survive when you are making such a pittance?  Work harder!' then disappears!\n");

	Do_more(c);
	Do_send_clear(c);
        return;
    }

    Do_more(c);
    Do_send_clear(c);

    gold = floor(c->player.gold * 0.1);
    Do_gold(c, -gold, FALSE);

    gems = floor(c->player.gems * 0.07);
    Do_gems(c, -gems, FALSE);

    gold += gems * N_GEMVALUE;

	/* see if there is a steward */
    /*
    Do_lock_mutex(&c->realm->realm_lock);

    if (c->realm->king != NULL && c->realm->king_flag) {
    */

	Do_unlock_mutex(&c->realm->realm_lock);
        Do_lock_mutex(&c->realm->kings_gold_lock);

	    /* steward coffers are capped at 40K */
	if (RND() > c->realm->steward_gold / 40000.0) {

		/* stewards get a maximum of 1K donation */
	    if (gold > 1000.0) {
		c->realm->steward_gold += 1000.0;
		gold -= 1000.0;
	    }
	    else {
	        c->realm->steward_gold += gold;
	        Do_unlock_mutex(&c->realm->kings_gold_lock);
	        return;
	    }
	}

	Do_unlock_mutex(&c->realm->kings_gold_lock);
    /*
    }
    else {
	Do_unlock_mutex(&c->realm->realm_lock);
    }
    */

	/* add to the king's coffers */
    Do_lock_mutex(&c->realm->kings_gold_lock);

	/* kings coffers are capped at 2M */
    if (RND() > c->realm->kings_gold / 2000000.0) {

	    /* maximum contribution of 20K */
	if (gold > 20000.0) {
	    c->realm->kings_gold += 20000.0;
	    gold -= 20000.0;
	}
	else {
	    c->realm->kings_gold += gold;
	    gold = 0.0;
	}
    }

    Do_unlock_mutex(&c->realm->kings_gold_lock);

if (gold > 0.0) {
sprintf(error_msg, "[%s] Do_tax did not allocate %lf in wealth.\n", c->connection_id, gold);
Do_log(DEBUG_LOG, error_msg);
}

    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_guru(struct client_t *c)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: E. A. Estes, 3/3/86
/         Brian Kelly, 6/20/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

Do_guru(struct client_t *c)
{
    float ftemp;

    Do_send_line(c, "You've met a Guru. . .\n");

    if (RND() * c->player.sin > 1.0) {
        Do_send_line(c, "You disgusted him with your sins!\n");
        Do_more(c);
        Do_send_clear(c);

    }
    else if (c->player.poison > 0.0) {
        Do_send_line(c, "He looked kindly upon you, and cured you.\n");
        Do_more(c);
        Do_send_clear(c);
	Do_poison(c, (double) -c->player.poison);
    }
    else if ((RND() / 10 > c->player.sin) && (c->player.circle > 1)) {
        Do_send_line(c, "He slips something into your charm pouch as a reward for your saintly behavior!\n");
	Do_mana(c, 40.0 + 15 * c->player.circle, FALSE);
	Do_more(c);
        Do_send_clear(c);

        c->player.charms += 1 + (c->player.circle / 20);
           } else {
        Do_send_line(c, "He rewarded you for your virtue.\n");
	Do_more(c);
        Do_send_clear(c);
	Do_mana(c, 40.0 + 10 * c->player.circle, FALSE);

	Do_energy(c, c->player.energy + 2 + c->player.circle / 5,
		c->player.max_energy, c->player.shield + 2 + c->player.circle
		/ 5, 0, FALSE);
    }
}


/************************************************************************
/
/ FUNCTION NAME: Do_village(struct client_t *c)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: E. A. Estes, 3/3/86
/         Brian Kelly, 6/20/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

Do_village(struct client_t *c)
{
    struct event_t *event_ptr;
    long answer;
    float ftemp;

    if (c->player.beyond || (c->player.level + 1 < c->player.circle)) {
       Do_send_line(c, "You have found a village.  But the inhabitants are too strong for you!\n");
       Do_more(c);
       Do_send_clear(c);
       return;
    }

       
    Do_send_line(c, "You have found a village.  Do you wish to pillage it?\n");

    if (Do_yes_no(c, &answer) != S_NORM || answer == 1) {

	    /* return if the player says no */
        Do_send_clear(c);
        return;
    }

    Do_send_clear(c);

    Do_sin(c, 0.5);
    Do_experience(c, (.75 + RND() / 2) * 1000.0 * c->player.circle, FALSE);
    Do_gold(c, (.75 + RND() / 2) * 50.0 * c->player.circle, FALSE);
}


/************************************************************************
/
/ FUNCTION NAME: Do_plague(struct client_t *c, struct event_t *the_event)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: E. A. Estes, 3/3/86
/         Brian Kelly, 6/20/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle plague.  event->arg3 contains 1000x the amount of poison to
/       increase the player by.
/
*************************************************************************/

Do_plague(struct client_t *c, struct event_t *the_event)
{
    float ftemp;

    if (the_event->arg3 == 0) {
        if (c->player.poison < sqrt(c->player.circle)) {
            Do_send_line(c, "You've been hit with a plague!\n");

            if (c->player.type == C_ELF) {
                Do_send_line(c, "But as an elf, you are unaffected!\n");
            } else if (c->player.charms > 0) { 
                Do_send_line(c, "But your charm saved you!\n");
                --c->player.charms;
            } else {
                Do_adjusted_poison(c, 1.0);
            } 

            if (c->player.virgin && RND() < 0.2) {
                Do_send_line(c, "Your virgin catches it and perishes!\n");
                Do_virgin(c, FALSE, FALSE);
            } 

            Do_more(c);
            Do_send_clear(c);
        }
    } else {
        Do_send_line(c, "You absorb some of the poison you cured!\n");
        Do_poison(c, (double) the_event->arg3 / 1000);
    }

}


/************************************************************************
/
/ FUNCTION NAME: Do_volcano(struct client_t *c)
/
/ FUNCTION: generate a place for the One Ring to be thrown into
/
/ AUTHOR: Eugene Hung, 8/2/01
/
/ ARGUMENTS: c
/
/ RETURN VALUE: none
/
/ MODULES CALLED: 
/
/ GLOBAL INPUTS: 
/
/ GLOBAL OUTPUTS: 
/
/ DESCRIPTION:
/       Gives crowns
/
*************************************************************************/

Do_volcano(struct client_t *c)
{
    long answer;
    float ftemp;
    char string_buffer[SZ_LINE];


    Do_send_line(c, "You've come upon a pool of lava!\n");

    if (c->player.ring_type != R_NONE) {
        Do_send_line(c, "Do you wish to destroy your ring?\n");
    } else {
        Do_send_line(c, "It bubbles and hisses, and you wisely avoid it.\n");
        Do_more(c);
        Do_send_clear(c);
        return;
    }

    if (Do_yes_no(c, &answer) != S_NORM || answer == 1) {

	    /* return if the player says no */
        Do_send_line(c, "You hang on to Your Precious Ring.  You hear a roar of evil laughter in the distance.\n");
        Do_sin(c, 2.5);
        Do_more(c);
        Do_send_clear(c);
        return;
    } 

    Do_send_line(c, "Sweating, you attempt to throw the Ring in . . .\n");

    Do_send_buffer(c);
    sleep(3);

    ftemp = RND();


        /* certain races have more willpower */
    if (((c->player.type == C_HALFLING) && (c->player.sin <= ftemp + .25)) ||
        ((c->player.type == C_DWARF)    && (c->player.sin * 2 <= ftemp + .25)) ||
        ((c->player.type == C_ELF)      && (c->player.sin * 3 <= ftemp + .25)) ||
        (c->player.sin * 4 <= ftemp + .25)
       )
         {

        Do_send_line(c, "You throw the ring into the pool...\n");
        Do_more(c);
        Do_send_clear(c);
        
        
        if (c->player.ring_type == R_DLREG) {
		Do_send_line(c, "and watch as the symbol of ultimate evil melts in its birth place!\n");
        Do_more(c);
        Do_send_line(c, "Having rid yourself of the One Ring, you feel a great burden lift from your heart!\n");
        Do_more(c);
        Do_send_clear(c);
        
        
            Do_sin(c, -c->player.sin);
            Do_experience(c, 50000.0 * c->player.circle, FALSE);
            sprintf(string_buffer, "%s has thrown the One Ring into the Fire!  Praise %s with great praise!\n", 
                    c->modifiedName, (c->player.gender ? "her" : "him"));
            Do_broadcast(c, string_buffer);
            Do_ring(c, R_NONE, FALSE);
          
            if ((c->player.level > MIN_KING) && (c->player.level < MAX_KING)) {
                Do_send_line(c, "For your great deed, you have been given a golden crown!\n");
                Do_crowns(c, 1, FALSE);
                Do_more(c);
            }
        } else {
            Do_send_line(c, "Unfortunately, nothing else seems to happen.\n");
            Do_ring(c, R_NONE, FALSE);
            Do_more(c);
        }

    } else {
        Do_send_line(c, "You lack the willpower to do so!  You hear a sinister cackle in the distance.\n");
        Do_sin(c, 1.0);

        if (c->player.ring_type == R_BAD) {
            c->player.ring_duration = 0;
            Do_ring(c, R_SPOILED, FALSE);
        }
        Do_more(c);
    }

    Do_send_clear(c);

    return;
}

/************************************************************************
/
/ FUNCTION NAME: Do_shutdown_check(struct client_t *c)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: E. A. Estes, 3/3/86
/         Brian Kelly, 6/20/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

Do_shutdown_check(struct client_t *c)
{
    if (server_hook != RUN_SERVER && server_hook != LEISURE_SHUTDOWN) {
        Do_send_int(c, SHUTDOWN_PACKET);
        Do_send_buffer(c);
	c->socket_up = FALSE;
    }
}


/************************************************************************
/
/ FUNCTION NAME: Do_information(struct client_t *c)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: Brian Kelly, 11/8/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

Do_information(struct client_t *c)
{
    struct event_t *event_ptr;
    struct button_t buttons;
    long answer;
    char error_msg[SZ_ERROR_MESSAGE];
    char string_buffer[SZ_LINE];

    Do_clear_buttons(&buttons, 0);

    strcpy(buttons.button[0], "Stats\n");
    strcpy(buttons.button[1], "Examine\n");
    strcpy(buttons.button[2], "Players\n");
    strcpy(buttons.button[3], "Scoreboard\n");
    strcpy(buttons.button[4], "Channel\n");

    if (c->hearBroadcasts) {
        strcpy(buttons.button[5], "No Announce\n");
    }
    else {
        strcpy(buttons.button[5], "Announce\n");
    }


    if (c->game->chatFilter) {
        strcpy(buttons.button[6], "Filter Off\n");
    }
    else {
        strcpy(buttons.button[6], "Filter On\n");
    }
	
    strcpy(buttons.button[7], "Cancel\n");

    if (Do_buttons(c, &answer, &buttons) != S_NORM || answer == 7) {
        Do_send_clear(c);
	return;
    }

    Do_send_clear(c);

    event_ptr = (struct event_t *) Do_create_event();
    event_ptr->to = c->game;
    event_ptr->from = c->game;

    switch (answer) {

	/* see this player's stats */
    case 0:
	event_ptr->type = EXAMINE_EVENT;
	event_ptr->arg3 = FALSE;
	break;

    case 1:
	event_ptr->type = EXAMINE_EVENT;
	event_ptr->arg3 = TRUE;
	break;

    case 2:
	event_ptr->type = LIST_PLAYER_EVENT;
	break;

    case 3:
	Do_scoreboard(c, 0, TRUE);
	break;

    case 4:

	sprintf(string_buffer, "You are currently on channel %d.\n",
		c->channel);

	Do_send_line(c, string_buffer);

	Do_send_line(c, "Channel 8 is reserved for players with a palantir.\n");
	Do_send_line(c, "Which channel do you want to change to?\n");

        Do_clear_buttons(&buttons, 0);

        strcpy(buttons.button[0], "1\n");
        strcpy(buttons.button[1], "2\n");
        strcpy(buttons.button[2], "3\n");
        strcpy(buttons.button[3], "4\n");
        strcpy(buttons.button[4], "5\n");
        strcpy(buttons.button[5], "6\n");
        strcpy(buttons.button[6], "7\n");

        if (c->player.palantir || c->wizard > 3) {
            strcpy(buttons.button[7], "8\n");
        } 

        if (Do_buttons(c, &answer, &buttons) != S_NORM) {
	    Do_send_clear(c);
	    free((void *)event_ptr);
	    return;
        }

	Do_send_clear(c);

	    /* update the player info, if necessary */
	if (c->channel != (int)answer +1) {
	
                /* if we were palantiring, turn off snooping  */
            if (c->channel == 8) {
                c->game->hearAllChannels = HEAR_SELF;
            } 


	    c->channel = (int)answer + 1;

                /* if we used our palantir, turn on snooping */
            if (c->channel == 8) {
                c->game->hearAllChannels = HEAR_ONE;
            } 

            Do_lock_mutex(&c->realm->realm_lock);
            Do_player_description(c);
            Do_unlock_mutex(&c->realm->realm_lock);

	    Do_send_specification(c, CHANGE_PLAYER_EVENT);
        }

	break;

/*
    case 5:
	free((void *)event_ptr);

	sprintf(string_buffer, "/var/phantasia/backup2/%s", c->player.lcname);

	errno = 0;
        if ((character_file=fopen(string_buffer, "w")) == NULL) {

            sprintf(error_msg,
		    "[%s] fopen of %s failed in Do_information: %s\n",
		    c->connection_id, string_buffer, strerror(errno));

            Do_log_error(error_msg);
	    return;
        }

        errno = 0;
        if (fwrite((void *)&c->player, SZ_PLAYER, 1, character_file) != 1) {

            sprintf(error_msg,
		    "[%s] fwrite of %s failed in Do_information: %s\n",
                    c->connection_id, string_buffer, strerror(errno));

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

        fclose(character_file);

        sprintf(string_buffer, "%s has been backed up for a server crash.\n",
		c->modifiedName);

	Do_send_line(c, string_buffer);
	Do_send_line(c,
	    "Backing up this character again will destroy the old backup.\n");

	Do_more(c);
	return;
*/

    case 5:
	free((void *)event_ptr);

	if (c->hearBroadcasts) {
	    Do_send_line(c, "Server announcements are now blocked.\n");
	    c->hearBroadcasts = FALSE;
	}
	else {
	    Do_send_line(c, "You will now hear server announcements.\n");
	    c->hearBroadcasts = TRUE;
	}

	Do_more(c);
	Do_send_clear(c);
	return;

    case 6:
	c->game->chatFilter = !c->game->chatFilter;
        return;

    default:

	sprintf(error_msg,
		"[%s] Returned non-option %ld in Do_information.\n",
		c->connection_id, answer);
		
	Do_log_error(error_msg);
	free((void *)event_ptr);
	Do_caught_hack(c, H_SYSTEM);
	return;
    }

    if (event_ptr->type != NULL_EVENT) {
        Do_handle_event(c, event_ptr);
    }
    else {
	free((void *)event_ptr);
    }
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_scoreboard(struct client_t *c)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: Brian Kelly, 12/30/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

Do_scoreboard(struct client_t *c, int start, int new)
{
    char string_buffer[SZ_LINE];
    char error_msg[SZ_ERROR_MESSAGE];
    struct scoreboard_t scoreboard;
    FILE *scoreboard_file;
    long theEOF; 
    int i, records, EOF_flag;

    Do_send_int(c, SCOREBOARD_DIALOG_PACKET);

    Do_lock_mutex(&c->realm->scoreboard_lock);

        /* open the scoreboard file */
    errno = 0;
    
    if (new) {
      if ((scoreboard_file=fopen(SCOREBOARD_FILE, "r")) == NULL) {

        sprintf(error_msg, "[%s] fopen of %s failed in Do_scoreboard: %s\n",
		c->connection_id, SCOREBOARD_FILE, strerror(errno));

        Do_log_error(error_msg);

        Do_send_line(c,
		"1\nCurrently, there is nobody on the scoreboard.\n"); 
        Do_unlock_mutex(&c->realm->scoreboard_lock);
        return;
      } else {

        /* drop to next part */
      }

    } else {
      if ((scoreboard_file=fopen(OLD_SCOREBOARD_FILE, "r")) == NULL) {

        sprintf(error_msg, "[%s] fopen of %s failed in Do_scoreboard: %s\n",
		c->connection_id, OLD_SCOREBOARD_FILE, strerror(errno));

        Do_log_error(error_msg);

        Do_send_line(c,
		"1\nCurrently, there is nobody on the scoreboard.\n"); 

        Do_unlock_mutex(&c->realm->scoreboard_lock);
        return;
      } else {

        /* drop to next part */
      }
    }


	    /* find the end of the scoreboard file */
	fseek(scoreboard_file, 0, SEEK_END);
	theEOF = ftell(scoreboard_file);

	    /* calculate how many records are in the file */
	records = theEOF / SZ_SCOREBOARD;

	    /* the earliest we can start is the beginning */
	if (start < 0) {
	    start = 0;
	}

	   /* we'll only show 50 records maximum */
	records = 50;

	    /* tell the client number of records and their start */
	Do_send_int(c, start);
	Do_send_int(c, records);

	    /* move to the starting record */
        EOF_flag = FALSE;
        fseek(scoreboard_file, SZ_SCOREBOARD * start, SEEK_SET);

	    /* read the next 50 or so records */
        for (i = start + 1; i < records + start + 1; i++) {

            if (!EOF_flag && fread((void *)&scoreboard, SZ_SCOREBOARD, 1,
		    scoreboard_file) == 1) {

/*
	        sprintf(string_buffer,
			"%d> %s, the level %0.lf %s, was %s at ", i,
		        scoreboard.name, scoreboard.level, scoreboard.class,
		        scoreboard.how_died);
*/
	        if (scoreboard.level == 9999) {

	            sprintf(string_buffer,
	         "%d> %s the %s ascended to the position of Valar on ",
		 i, scoreboard.name, scoreboard.class);
		    
	            Do_send_string(c, string_buffer);

		    ctime_r(&scoreboard.time, string_buffer);
		    Do_truncstring(string_buffer);
	            strcat(string_buffer, ".\n");
	            Do_send_string(c, string_buffer);
		}
		else {
	            sprintf(string_buffer,
			"%d> %s, the level %0.lf %s, %s on ", i,
		        scoreboard.name, scoreboard.level, scoreboard.class,
		        scoreboard.how_died);
/*
	            sprintf(string_buffer,
			    "%d> %s, the level %0.lf %s,", i,
		            scoreboard.name, scoreboard.level,
			    scoreboard.class);
*/

	            Do_send_string(c, string_buffer);

		    ctime_r(&scoreboard.time, string_buffer);
		    Do_truncstring(string_buffer);
	            strcat(string_buffer, ".\n");
	            Do_send_string(c, string_buffer);
		}
	    }
	    else {
		EOF_flag = TRUE;
	        sprintf(string_buffer, "%d> No entry.\n", i);
                Do_send_string(c, string_buffer);
	    }
        } 

            /* close the file handles */
        fclose(scoreboard_file);
	Do_send_buffer(c);

    Do_unlock_mutex(&c->realm->scoreboard_lock);
}


/************************************************************************
/
/ FUNCTION NAME: int Do_profanity_check(char *theString)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: Brian Kelly, 1/2/01
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

int Do_profanity_check(char *theString)
{
    char *swears[] = { "shit", "fuck", "fuc", "fuk", "fock", "piss", "cunt", "cock", "ass", "dick", "penis", "pussy", "clit", "bitch", "butt", "twat", "vagina", "dork", "dildo", "masturbat", "fag", "homo", "lesbian", "screw", "anal", "poo", "nigger", "nigga", "chink", "jap", "wop", "kike", "bitch", "whore", "crap", "hell", "damn", "rape", "suck", "abortion", "mute", "sex", "kkk", "balls", "bush", "tits", "dammit", "snatch", "sauron", "morgoth", "osama", "alatar", "stfu", "wtf", "" };

    char currentChar;
    int stringPtr, currentSwear, swearPtr, wordBeginning, swearBeginning, spaceCount;

    if (theString[0] == '\0') {
	return FALSE;
    }

    currentSwear = 0;

	/* loop through all the swear words */
    while (swears[currentSwear][0] != '\0') {

	stringPtr = swearPtr = wordBeginning = swearBeginning = spaceCount = 0;

	    /* look for the next letter in the swear */
	while (theString[stringPtr] != '\0') {

	    currentChar = theString[stringPtr];

		/* replace numbers that could be letters */
	    if (currentChar == '1' && swears[currentSwear][swearPtr] ==
		    'i') {

		currentChar = 'i';
	    }

	    else if (currentChar == '1' && swears[currentSwear][swearPtr] ==
		    'l') {

		currentChar = 'l';
	    }
	    else if (currentChar == 'z' && swears[currentSwear][swearPtr] ==
		    's') {

		currentChar = 's';
	    }
	    else if (currentChar == '5' && swears[currentSwear][swearPtr] ==
		    's') {

		currentChar = 's';
	    }
	    else if (currentChar == '0' && swears[currentSwear][swearPtr] ==
		    'o') {

		currentChar = 'o';
	    }
	    else if (currentChar == '$' && swears[currentSwear][swearPtr] ==
		    's') {

		currentChar = 's';
	    }
	    else if (currentChar == '@' && swears[currentSwear][swearPtr] ==
		    'a') {

		currentChar = 'a';
	    }

		/* Is this character a space? */
            if (currentChar == '_') {

		if (swearPtr == 0) {
		    wordBeginning = stringPtr + 1;
		}
		else {
		    ++spaceCount;
		}
	    }

		/* If the character is not a letter, skip it */
	    else if (isalpha(currentChar)) {

	        if (currentChar == swears[currentSwear][swearPtr]) {
		    ++swearPtr;

		        /* See if we've found a complete swear */
		    if (swears[currentSwear][swearPtr] == '\0') {

			    /* if the swear did not start at the beginning
			    of a word and contains one space, let it pass.
			    "is_hit" would be caught */
			if (wordBeginning != swearBeginning || spaceCount
				!= 1) {

			    return TRUE;
			}

		        swearPtr = 0;
		        spaceCount = 0;
		        stringPtr = swearBeginning;
			++swearBeginning;
		    }
		}

		    /* Start over if anything but previous swear letter */
		    /* This is to catch "ffuucckk" */
	        else if (swearPtr == 0 || currentChar !=
		        swears[currentSwear][swearPtr - 1]) {

		    swearPtr = 0;
		    spaceCount = 0;
		    stringPtr = swearBeginning;
		    ++swearBeginning;
	        }
	    }

		/* move to the next letter */
	    ++stringPtr;
	}

        ++currentSwear;
    }

    return FALSE;
}
		
		
/************************************************************************
/
/ FUNCTION NAME: Do_replace_profanity(struct client_t *c, char *theString)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: Brian Kelly, 10/11/00
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

int Do_replace_profanity(char *theString)
{
    char *swears[] = { "shit", "fock", "fuk", "fuc", "cunt", "nigger", "crap", "damn", "dammit", "@ss", "a$$", "" };
    char replacements[] = "smurf ";
    char currentChar;
    int stringPos, currentSwear, swearPos, wordStart, swearStart, smurfPos;
    int spaceCount, bleepPos;
    bool profane, spaceExceptionPossible;

    if (theString[0] == '\0') {
	return FALSE;
    }

    profane = FALSE;
    currentSwear = 0;

	/* loop through all the swear words */
    while (swears[currentSwear][0] != '\0') {

	stringPos = swearPos = wordStart = swearStart = 0;
        spaceExceptionPossible = FALSE;

	    /* look until the we reach the end of the string */
	while (theString[stringPos] != '\0') {

	    currentChar = tolower(theString[stringPos]);

		/* Convert similar symbols */
	    if (currentChar == '!' && swears[currentSwear][swearPos] == 'i') {
		currentChar = 'i';
	    }

	    else if (currentChar == '!' && swears[currentSwear][swearPos] ==
		    'l') {

		currentChar = 'l';
	    }

	    else if (currentChar == '1' && swears[currentSwear][swearPos] ==
		    'i') {

		currentChar = 'i';
	    }

	    else if (currentChar == '1' && swears[currentSwear][swearPos] ==
		    'l') {

		currentChar = 'l';
	    }

	    else if (currentChar == '#' && swears[currentSwear][swearPos] ==
		    'h') {

		currentChar = 'h';
	    }

	    else if (currentChar == '$' && swears[currentSwear][swearPos] ==
		    's') {

		currentChar = 's';
	    }

	    else if (currentChar == '(' && swears[currentSwear][swearPos] ==
		    'c') {

		currentChar = 'c';
	    }


		/* Is this character a space? */
            if (currentChar == ' ') {

		    /* if this space is within a possible swear */
		if (swearPos > 0) {

			/* count the space for possible exception */
		    ++spaceCount;
		}

		    /* if we've found no swear letters */
		else {

			/* we won't find anything before this */
		    wordStart = stringPos + 1;
		    swearStart = wordStart;

			/* since the swear starts a word, no exception */
		    spaceExceptionPossible = FALSE;
		}

		    /* move to the next letter of the string */
		++stringPos;
		continue;
	    }

		/* If the character is not a letter, skip it */
	    else if (! isalpha(currentChar)) {
		++stringPos;
		continue;
	    }

		/* Is this character the next of this swear? */
	    else if (currentChar == swears[currentSwear][swearPos]) {

		    /* start looking for the next letter */
		++swearPos;

		    /* have we found all the swear letters? */
		if (swears[currentSwear][swearPos] == '\0') {

			/* we don't want to bleep "is hit" or "if u c", 
                        so pass over if swear didn't start a word and there 
                        was 1 or 2 spaces */

		    if (!spaceExceptionPossible || spaceCount != 1) {

			    /* bleep out the whole word */
			bleepPos = wordStart;
		        profane = TRUE;
		    
			    /* loop until space past current location */
		        while (bleepPos < stringPos ||
			        (theString[bleepPos] != ' ' &&
			        theString[bleepPos] != '\0')) {

			        /* replace the letter */
                            
                            smurfPos = bleepPos - wordStart;
                            if (smurfPos > 4) {
                                smurfPos = 5;
                            } 

			    theString[bleepPos++] =
				    replacements[smurfPos];
			}

                        if (smurfPos == 3) {
                            theString[bleepPos + 1] = theString[bleepPos];
                            theString[bleepPos] =
				    replacements[smurfPos + 1];
                        }

			    /* start again at the last replacement */
			    /* bleepPos is a space or null, so the
			    spaceExceptionPossible will be handled */
			stringPos = bleepPos;
			swearPos = 0;
			continue;
		    }

			/* this is a swear, but we're passing it over */
		    else {

			    /* start one after where we did last time */
			stringPos = swearStart + 1;
			swearPos = 0;
			continue;
		    }
		}

		    /* found the next swear letter */
		++stringPos;
		continue;
	    }

		/* See if this letter is the same as the last */
		/* This is to catch "ffuucckk" */
	    else if (swearPos != 0 && currentChar ==
		    swears[currentSwear][swearPos - 1]) {

		    /* move to the next letter */
		++stringPos;
		continue;
	    }

		/* different letter - start one after where we started before */
	    stringPos = swearStart = swearStart + 1;
	    swearPos = 0;
	    spaceExceptionPossible = TRUE;
	    spaceCount = 0;
	}

	++currentSwear;
    }

    return profane;
}


/************************************************************************
/
/ FUNCTION NAME: Do_censor(char *destString, char *sourceString)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: Brian Kelly, 06/25/02
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/


int Do_censor(char *destString, char *sourceString)
{
    char *swears[] = { "shit", "fuck", "cunt", "nigger", "cock", "dick", "penis", "pussy", "clit", "vagina", "dildo", "masturbate", "masturbation", "anal", "chink", "kike", "tits", "" };

    char substitute[8][5] = {
	    { 'a', '@', '\0' },
	    { 'c', '(', '\0' },
	    { 'h', '#', '\0' },
	    { 'i', 'l', '!', '1', '\0' },
	    { 'l', 'i', '!', '1', '\0' },
	    { 'o', '0', '\0' },
	    { 's', '$', '5', 'z', '\0' },
	    { '\0' } };

    int sourceLetter, swearNumber, swearLetter, letterPtr, row, column, count;
    bool newWordFlag, matchFlag, spaceFlag, swearFlag;
    char lcSource[SZ_CHAT + 64], currentLetter;

	/* make a lowercase version of the string */
    sourceLetter = 0;
    do {
      lcSource[sourceLetter] = tolower(sourceString[sourceLetter]);
    }
    while (sourceString[sourceLetter++] != '\0');

        /* start at the first letter of the source */
    sourceLetter = 0;
    newWordFlag = TRUE;
    count = 0;

        /* run through all the characters of the source string */
    while (sourceString[sourceLetter] != '\0') {

	/* if this character is a space */
      if (sourceString[sourceLetter] == ' ') {

	  /* no swears start with a space */
	*destString++ = ' ';
        newWordFlag = TRUE;
	++sourceLetter;
	continue;
      }

        /* start at the front of the list of swears */
      swearFlag = FALSE;
      swearNumber = 0; 

        /* loop through all the swear words */
      while (swears[swearNumber][0] != '\0') {

          /* start with the first letter of this swear */
        swearLetter = 0;

	  /* we start checking from our current position */
        letterPtr = sourceLetter;
        spaceFlag = FALSE;

	  /* check the swear from this letter */
        do {

	    /* assume no match */
          matchFlag = FALSE;

	    /* convert the current character to lowercase */
          currentLetter = lcSource[letterPtr];

	    /* if the current letter is a space and
		we're in the middle of a swear */
	  if (currentLetter == ' ' && swears[swearNumber][swearLetter] != '\0') {

	      /* set the space flag */
	    spaceFlag = TRUE;

	      /* increment to the next string character and re-loop */
	    ++letterPtr;
	    continue;
	  }

	    /* if the letter is the next in the swear */
          if (swears[swearNumber][swearLetter] == currentLetter) {

	      /* swear matches */
	    matchFlag = TRUE;
	  }

	      /* see if a substitute character was used (swear isn't NULL) */
	  else if (swears[swearNumber][swearLetter] != '\0') {

            row = 0;

	      /* run through the substitute list */
	    while (substitute[row][0] != '\0') {

	        /* if this sub char is the next in the swear */
	      if (substitute[row][0] == swears[swearNumber][swearLetter]) {

	        column = 1;

		  /* run through the list */
	        while (substitute[row][column] != '\0') {

		    /* is the string letter this replacement character? */
		  if (currentLetter == substitute[row][column]) {

	              /* swear matches */
	            matchFlag = TRUE;
		    break;
		  }

		  ++column;
		}

		  /* a letter is only listed as a sub once */
		break;
	      }

	      ++row;
	    }
          }

	    /* if this letter matches the next in the swear */
	  if (matchFlag) {

	      /* move to the next letter of the string and swear */
	    ++letterPtr;
	    ++swearLetter;
	  }

	    /* otherwise, if we're in the middle of a swear */
	  else if (swearLetter) {

	      /* if the letter is a repeat of the last */
            if (swears[swearNumber][swearLetter - 1] == currentLetter) {

	        /* swear is a repeat */
	      matchFlag = TRUE;
	    }

	      /* see if it could be a substitute character repeat */
	    else {

              row = 0;

	        /* run through the substitute list */
	      while (substitute[row][0] != '\0') {

	          /* if this sub char is the previous one in the swear */
	        if (substitute[row][0] ==
		    swears[swearNumber][swearLetter - 1]) {

	          column = 1;

		    /* run through the list */
	          while (substitute[row][column] != '\0') {

		      /* is the string letter this replacement character? */
		    if (currentLetter == substitute[row][column]) {

	                /* swear matches */
	              matchFlag = TRUE;
		      break;
		    }

		    ++column;
		  }

		    /* a letter is only listed as a sub once */
		  break;
	        }

	        ++row;
	      }
            }

	      /* if this letter matches the previous in the swear */
	    if (matchFlag) {

	        /* move to the next letter of the string only */
	      ++letterPtr;
	    }
	  }
        }
        while (matchFlag);

	  /* see if a complete swear was found */
	if (swears[swearNumber][swearLetter] == '\0') {

	    /* if the swear contains spaces and didn't start a word */
	  if (!newWordFlag && spaceFlag) {

	      /* reject the word for replacement */
	    swearLetter = 0;
	  }

	    /* if the swear is valid */
	  else {

	    swearFlag = TRUE;

	      /* break out of the search, we'll replace it below */
	    break;
	  }
	}

	++swearNumber;
      }

	/* if a complete swear was found */
      if (swearFlag) {

	  /* if the original was capitalized */
	if (isupper(sourceString[sourceLetter])) {

	    /* if the second letter was uppercase */
	  if (isupper(sourceString[sourceLetter + 1])) {

	      /* assume it was all uppercase */
	    strcpy(destString, "SMURF");
	  }
	  else {

	      /* just capitalize it */
	    strcpy(destString, "Smurf");
	  }
	}
	  /* the word was lowercase */
	else {

	    /* replace the word */
	  strcpy(destString, "smurf");
	}

	  /* move the pointer over the replacement */
	destString += 5;

	  /* the we continue from the end of the swear */
	sourceLetter = letterPtr;

	  /* the next character is never the start of a new word */
	newWordFlag = FALSE;

	  /* increment the counter */
	++count;
      }

	/* no swear was found */
      else {

	  /* if this letter is a space */
	if (sourceString[sourceLetter] == ' ') {

	    /* the next character will be the start of a new word */
	  newWordFlag = TRUE;
	}
	else {
	  newWordFlag = FALSE;
	}

	  /* copy over this letter and move to the next letter */
	*destString++ = sourceString[sourceLetter++];
	  
      }

    }

      /* add a null */
    *destString = '\0';

        /* see if this was an buffer overflow attempt */
    if (count > 20) {

	return TRUE;
    }

    return FALSE;
}


/************************************************************************
/
/ FUNCTION NAME: int Do_spam_check(struct client_t *c, char *message)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/25/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

int Do_spam_check(struct client_t *c, char *message)
{
    int i, count;

        /* move up all the previous chat times and length */
    for (i = 8; i >= 0; i--) {
        c->chatTimes[i + 1] = c->chatTimes[i];
        c->chatLength[i + 1] = c->chatLength[i];
    }

        /* add the current moment into the lists */
    c->chatTimes[0] = time(NULL);
    c->chatLength[0] = (int) floor(strlen(message) / 80.0);

        /* see if we can find a chat infraction */
    for (i = 3; i < 9; i++) {

             /* player can send 3 + n messages every n^2 seconds */
        if (c->chatTimes[0] - c->chatTimes[i] <= (i - 2) * (i - 2)) {

                /* tag this player as muted */
            Do_caught_spam(c, H_SPAM);
            return TRUE;
        }
    }

        /* add up the lines of text from the last nine messages */
    count = 0;
    for (i = 0; i <= 9; i++) {
        count += c->chatLength[i];
    }

printf("count check: %d.\n", count);
        /* if the number of lines exceeds 14 */
    if (count >= 14) {

            /* clear the history so we don't nail them forever */
        for (i = 0; i <= 9; i++) {
            c->chatLength[i] = 0;
        }

            /* tag this player as muted */
        Do_caught_spam(c, H_FLOOD);
        return TRUE;
    }

        /* no problems */
    return FALSE;
}


/******************************************************************
/
/ FUNCTION NAME: Do_title_page(struct client_t *c)
/
/ FUNCTION: print title page
/
/ AUTHOR: E. A. Estes, 12/4/85
/	  Brian Kelly, 5/3/99
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: fread(), fseek(), fopen(), fgets(), wmove(), strcpy(),
/       fclose(), strlen(), waddstr(), sprintf(), wrefresh()
/
/ DESCRIPTION:
/       Print important information about game, players, etc.
/
*************************************************************************/

Do_title_page(struct client_t *c)
{
struct game_t *game_ptr, *first_ptr, *second_ptr;
short    councilfound;   /* set if we find a member of the council */
char	string_buffer[SZ_LINE]; 
char	error_msg[SZ_ERROR_MESSAGE];
int	error;

	/* print a header */
    Do_send_line(c,
	    "W e l c o m e   t o   P h a n t a s i a (vers. 4.03)!\n");

	/* lock the realm */
    Do_lock_mutex(&c->realm->realm_lock);

	/* display the current king, if any */
    if (c->realm->king == NULL || !c->realm->king_flag) {

      if (c->realm->king == NULL) {
        Do_send_line(c, "There is no ruler at this time.\n");
      } else {
	if (c->realm->king->description != NULL) {

                sprintf(string_buffer,
		        "The present steward is %s  Level: %.0lf\n",
                        c->realm->king->description->name,
		        c->realm->king->description->level);

	        Do_send_line(c, string_buffer);
	}
	else {
	    sprintf(string_buffer,
	 "[%s] Information on present steward unavailable in Do_title_page.\n",
	   c->connection_id);

	    Do_log_error(string_buffer);
	}
      }
    

    }
    else {
	    /* make sure the character has a description in place */
	if (c->realm->king->description != NULL) {

	        /* print out the present king/queen */
	    if (c->realm->king->description->gender == MALE) {

                sprintf(string_buffer,
		        "The present ruler is King %s  Level: %.0lf\n",
                        c->realm->king->description->name,
		        c->realm->king->description->level);
	    }
	    else {

                sprintf(string_buffer,
		        "The present ruler is Queen %s  Level: %.0lf\n",
                        c->realm->king->description->name,
		        c->realm->king->description->level);
	    }
	}
	else {
	    sprintf(string_buffer,
	   "[%s] Information on present ruler unavailable in Do_title_page.\n",
	   c->connection_id);

	    Do_log_error(string_buffer);
	}

	Do_send_line(c, string_buffer);
    }

	/* display the current valar, in any */
    if (c->realm->valar_name[0] != '\0') {

            sprintf(string_buffer, "The Valar is %s\n",
                    c->realm->valar_name);

/*
	if (c->realm->valar->description != NULL) {

            sprintf(string_buffer, "The Valar is %s   Level:  %.0lf\n",
                    c->realm->valar->description->name,
		    c->realm->valar->description->level);
	}
	else {
	    sprintf(string_buffer,
		   "[%s] Information on valar unavailable in Do_title_page.\n",
		   c->connection_id);

	    Do_log_error(string_buffer);
	}

*/
	Do_send_line(c, string_buffer);
    }


	/* search for council members */
    councilfound = 0;
    game_ptr = c->realm->games;

	/* loop through all the games */
    while (game_ptr != NULL && councilfound < 5) {

	    /* if the player is playing and is on the council */
	if (game_ptr->description != NULL &&
		(game_ptr->description->special_type == SC_COUNCIL ||
		game_ptr->description->special_type == SC_EXVALAR)) {

		/* print a header if this is the first council member */	
            if (councilfound == 0) {
                Do_send_line(c, "Council of the Wise:\n");
            }

		/* print out the member */

            sprintf(string_buffer, "%s  Level: %.0lf\n",
		    game_ptr->description->name,
		    game_ptr->description->level);

	    Do_send_line(c, &string_buffer);

		/* indicate that we've found another member */

	    councilfound++;
	}


	    /* look at the next game */

	game_ptr = game_ptr->next_game;
    }


        /* search for the two highest players */
    first_ptr = NULL;
    second_ptr = NULL;
    game_ptr = c->realm->games;

    while (game_ptr != NULL) {

	    /* if the player is in the game */
	if (game_ptr->description != NULL) {

	        /* see if the current game is higher level than the current */
	    if ((first_ptr == NULL || (game_ptr->description->level > first_ptr->description->level)) && 
              (game_ptr->description->special_type < SC_STEWARD) &&
              (game_ptr->description->wizard < 3)) {
        
          

		    /* put the current game into first position */
	        second_ptr = first_ptr;
	        first_ptr = game_ptr;
	    }
	    else if ((second_ptr == NULL || 
              (game_ptr->description->level > second_ptr->description->level)) && 
              (game_ptr->description->special_type < SC_STEWARD) &&
              (game_ptr->description->wizard < 3)) {

		    /* put the current game as the second */
	        second_ptr = game_ptr;
	    }
	}
	    /* point to the next game */
	game_ptr = game_ptr->next_game;
    }

	/* print out the search results */
    if (first_ptr != NULL) {
	if (second_ptr != NULL) {

	    sprintf(string_buffer, "Highest commoners are: %s  Level: %.0lf  and  %s  Level: %.0lf\n",
		    first_ptr->description->name,
		    first_ptr->description->level,
		    second_ptr->description->name,
		    second_ptr->description->level);
	}
	else {

	    sprintf(string_buffer, "Highest commoner is: %s  Level:%.0lf\n",
		    first_ptr->description->name,
		    first_ptr->description->level);
	}
	Do_send_line(c, &string_buffer);
    }

    /* print last to die */

/*
    if ((fp = fopen(_PATH_LASTDEAD,"r")) != NULL
        && fgets(Databuf, SZ_DATABUF, fp) != NULL)
        {
        mvaddstr(19, 25, "The last character to die was:\n");
        mvaddstr(20, 40 - strlen(Databuf) / 2,Databuf);
        fclose(fp);
        }

*/

    Do_unlock_mutex(&c->realm->realm_lock);

}


/***************************************************************************
/ FUNCTION NAME: Do_lowercase(char *dest, char *source);
/
/ FUNCTION: Handles error messages
/
/ AUTHOR:  Brian Kelly, 1/1/01
/
/ ARGUMENTS: 
/	int error - the error code to be returned
/	char *message - the error message to be printed
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_lowercase(char *dest, char *source)
{
    int len, i;

    len = strlen(source);

    for (i = 0; i< len; i++) {
	dest[i] = tolower(source[i]);
    }

    dest[len] = '\0';
    return;
}


/***************************************************************************
/ FUNCTION NAME: Do_create_password(char *string);
/
/ FUNCTION: Handles error messages
/
/ AUTHOR:  Brian Kelly, 1/1/01
/
/ ARGUMENTS: 
/	int error - the error code to be returned
/	char *message - the error message to be printed
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_create_password(char *string)
{
    int len, i, letter;

	/* choose a password length */
    len = 5 * RND() + 8;

	/* pick a random character */
    for (i = 0; i< len; i++) {
	letter = 50 + RND() * 55;

	    /* skip over non characters and numbers plus "01IOilo" */
	if (letter > 57)
	    letter += 7;
	if (letter > 72)
	    ++letter;
	if (letter > 78)
	    ++letter;
	if (letter > 90)
	    letter += 6;
	if (letter > 104)
	    ++letter;
	if (letter > 107)
	    ++letter;
	if (letter > 110)
	    ++letter;

	string[i] = (char) letter;
    }

    string[len] = '\0';
    return;
}


/***************************************************************************
/ FUNCTION NAME: Do_move_close(double *x, double *y, float distance);
/
/ FUNCTION: Handles error messages
/
/ AUTHOR:  Brian Kelly, 1/5/01
/
/ ARGUMENTS: 
/	int error - the error code to be returned
/	char *message - the error message to be printed
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_move_close(double *x, double *y, double maxDistance) 
{
    double angle, distance;

    angle = RND() * 2 * 3.14159;

    distance = RND() * maxDistance;
    if (distance < 1.0) {
	distance = 1.0;
    }

	/* add half a point because floor(-3.25) = -4 */
    *x += floor(cos(angle) * distance + .5);
    *y += floor(sin(angle) * distance + .5);

    return;
}

/************************************************************************
/
/ FUNCTION NAME: Do_replace_repetition(char *theString)
/
/ FUNCTION: do random stuff
/
/ AUTHOR: Brian Kelly, 1/2/01
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(),
/       waddstr(), mvprintw(), getanswer()
/
/ GLOBAL INPUTS: Player, *stdscr, *Statptr
/
/ GLOBAL OUTPUTS: Player
/
/ DESCRIPTION:
/       Handle gurus, medics, etc.
/
*************************************************************************/

Do_replace_repetition(char *theString)
{
    char previousChar, thisChar;
    char *writePtr, *readPtr;
    int count;

    if (theString[0] == '\0') {
	return;
    }

    writePtr = readPtr = &theString[0];

    while (*readPtr == ' ') {
	++readPtr;
    }

    count = 1;
    previousChar = tolower(*readPtr);
    *writePtr++ = *readPtr++;

    while (*readPtr != '\0') {

	thisChar = tolower(*readPtr);

	    /* if this is the same character */
	if (thisChar == previousChar) {

	    ++count;

		/* see if this is the fourth character that's the same */
	    if (count > 4) {

		    /* skip over it */
		readPtr++;
		continue;
	    }

	}
	else if (thisChar != ' ') {
	    previousChar = thisChar;
	    count = 1;
	}

	    /* copy the character over */
	*writePtr++ = *readPtr++;
    }

	/* add a null */
    *writePtr = '\0';
}


/***************************************************************************
/ FUNCTION NAME: Do_direction(struct client_t *c, double *x, double *y, char *direction)
/
/ FUNCTION: Derives the direction of a target coordinate from current location
/
/ AUTHOR:  Brian Kelly, 5/9/01
/
/ ARGUMENTS: 
/	
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       
/
****************************************************************************/

Do_direction(struct client_t *c, double *x, double *y, char *direction)
{
    double radians;

	/* if we're on the X coordinate, get radians manually */
    if (*x - c->player.x == 0) {

	if (*y - c->player.y > 0) {
	    radians = 1.5708;
	}
	else if (*y - c->player.y < 0) {
	    radians = 4.7124;
	}
	else {
	    strcat(direction, "down");
	    return;
	}
    }
    else {

	    /* find the angle */
        radians = atan((*y - c->player.y)/(*x - c->player.x));

	    /* add 180 degrees if on the other side of the plane */
	if (*x - c->player.x < 0) {
	    radians += 3.1416;
	}
    }

	/* run around the circle */
    if (radians > 4.3197) {
	strcat(direction, "south");
    }
    else if (radians > 3.5343) {
	strcat(direction, "south-west");
    }
    else if (radians > 2.7489) {
	strcat(direction, "west");
    }
    else if (radians > 1.9635) {
	strcat(direction, "north-west");
    }
    else if (radians > 1.1781) {
	strcat(direction, "north");
    }
    else if (radians > .3927) {
	strcat(direction, "north-east");
    }
    else if (radians > -.3927) {
	strcat(direction, "east");
    }
    else if (radians > -1.1781) {
	strcat(direction, "south-east");
    }
    else {
	strcat(direction, "south");
    }
	
    return;
}

int Do_maxmove(struct client_t *c) {
    if ((c->player.circle > 19) && (c->player.circle < 36)) {
        return (int) MIN(ceil(c->player.level / 50.0) + 1.5, 10.0);
    } else {
        return (int) MIN(floor((c->player.level * 1.5) + 1.5), 100.0);
    }
}

int Do_anglemove(struct client_t *c) {
    return (int) MAX(1.0, floor(Do_maxmove(c) * .707106781));
}