phantasia4/
phantasia4/conf/
phantasia4/phantasia/bin/
phantasia4/phantasia/src/utilities/
phantasia4/public_html/cgi-bin/
/*
 * Phantasia 4 -- Interterminal fantasy game
 *
 * Edward A. Estes
 * AT&T, March 12, 1986
 *
 * Client-Server port for internet web use:
 * Brian Kelly
 * bkelly@dimensional.com
 * April 7, 1999
 */

/* DISCLAIMER:
 *
 * This game is distributed for free as is.  It is not guaranteed to work
 * in every conceivable environment.  It is not even guaranteed to work
 * in ANY environment.
 *
 * This game is distributed without notice of copyright, therefore it
 * may be used in any manner the recipient sees fit.  However, the
 * author assumes no responsibility for maintaining or revising this
 * game, in its original form, or any derivitives thereof.
 *
 * The author shall not be responsible for any loss, cost, or damage,
 * including consequential damage, caused by reliance on this material.
 *
 * The author makes no warranties, express or implied, including warranties
 * of merchantability or fitness for a particular purpose or use.
 *
 * AT&T is in no way connected with this game.
 * (Nor is any company Brian Kelly was pretending to work for while working
 * on this game)
 */

/* Phantasia 4 is a complete rewrite of the Phantasia 3 code put together by
 * Edward Estes.  I played Phantasia quite a bit back at the Colorado School
 * of Mines, and thought it would make a great internet game as I became
 * more invoved with the web.  I believe the main advantage this game has
 * over others is that each player, although interacting, are independent
 * and one slow player over a 300 baud connection will not affect another
 * player going at top speed.
 *
 * Detailed changes can be found in the attached document, CHANGES, but
 * for this release, most of the changes center around the problems and
 * advantages of client-server connections.
*/

/*
 * All source files are set up for 'vi' with shiftwidth=4, tabstop=8.
 */

/**/

#include "include.h"

/* global variables */
int server_hook;
char randomStateBuffer[STATELEN];
struct random_data randData;

/*
 * main.c       Main entry point for Phantasia
 */

/***************************************************************************
/ FUNCTION NAME: main()
/
/ FUNCTION: initialize state, and call main process
/
/ AUTHOR: E. A. Estes, 12/4/85
/ MODIFIED:  Brian Kelly, 4/6/99
/
/ ARGUMENTS:
/       int     argc - argument count
/       char    **argv - argument vector
/
/ RETURN VALUE: none
/
/ MODULES CALLED: monstlist(), checkenemy(), activelist(),
/       throneroom(), checkbattle(), readmessage(), changestats(), writerecord()
,
/       tradingpost(), adjuststats(), recallplayer(), displaystats(), checktampe
red(),
/       fabs(), rollnewplayer(), time(), exit(), sqrt(), floor(), wmove(),
/       signal(), strcat(), purgeoldplayers(), getuid(), isatty(), wclear(),
/       strcpy(), system(), altercoordinates(), cleanup(), waddstr(), procmain()
,
/       playinit(), leavegame(), localtime(), getanswer(), neatstuff(), initials
tate(),
/       scorelist(), titlelist()
/
/ GLOBAL INPUTS: *Login, Throne, Wizard, Player, *stdscr, Changed, Databuf[],
/       Fileloc, Stattable[]
/
/ GLOBAL OUTPUTS: Wizard, Player, Changed, Fileloc, Timeout, *Statptr
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

main(argc, argv)
int     argc;
char    *argv[];
{
    	/* set up the main server structure */
    struct server_t server;

	/* set up a signal structre */
    struct sigaction sigAct;

	/* set the program to run */
    server.run_level = RUN_SERVER;

        /* process arguments */
    while (--argc && (*++argv)[0] == '-')
    {
        switch ((*argv)[1])
        {

	    /* purge character file */
        case 'c':
            Do_purge_characters();
            break;

            /* initialize, then bring down server */
        case 'q':
            server.run_level = FAST_SHUTDOWN;
            break;

	    /* purge scoreboard file */
        case 's':
            Do_purge_scoreboard();
            break;

        default:    /* for all other answers */
            printf("usage: phantasia [-c][-q][-s]\n");
            printf("  -c: Purge character roster\n");
            printf("  -q: Quit as soon as possible\n");
            printf("  -s: Purge scoreboard\n");
            exit(1);
        }
    }

	/* block SIGINT, SIGTERM, SIGIO, SIGALRM and SIGUSR1 til we're ready */
    sigemptyset(&sigAct.sa_mask);
    sigaddset(&sigAct.sa_mask, SIGINT);
    sigaddset(&sigAct.sa_mask, SIGTERM);
    sigaddset(&sigAct.sa_mask, SIGIO);
    sigaddset(&sigAct.sa_mask, SIGALRM);
    sigaddset(&sigAct.sa_mask, SIGUSR1);

	/* this routine will block for created threads as well */
    if (pthread_sigmask(SIG_BLOCK, &sigAct.sa_mask, NULL) < 0) {
        printf("Error blocking signals.\n");
        exit(1);
    }

	/* set up structures, variables and files */
    Init_server(&server);

	/* run the main loop */
    Do_main_loop(&server);

	/* destroy structures and close files */
    Do_close(&server);

    Do_log(SERVER_LOG, "Server is shut down.\n");
    exit(0);	/* thanks for playing */
}


/***************************************************************************
/ FUNCTION NAME: Do_main_loop(struct server_t *server)
/
/ FUNCTION: initialize state, and call main process
/
/ AUTHOR:  Brian Kelly, 4/12/99
/
/ ARGUMENTS: 
/	struct server_t *s - address of the sever's main data structure
/
/ RETURN VALUE: none
/
/ MODULES CALLED: monstlist(), checkenemy(), activelist(),
/       throneroom(), checkbattle(), readmessage(), changestats(), writerecord()
,
/       tradingpost(), adjuststats(), recallplayer(), displaystats(), checktampe
red(),
/       fabs(), rollnewplayer(), time(), exit(), sqrt(), floor(), wmove(),
/       signal(), strcat(), purgeoldplayers(), getuid(), isatty(), wclear(),
/       strcpy(), system(), altercoordinates(), cleanup(), waddstr(), procmain()
,
/       playinit(), leavegame(), localtime(), getanswer(), neatstuff(), initials
tate(),
/       scorelist(), titlelist()
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_main_loop(struct server_t *s)
{
    sigset_t sigMask;
    struct it_combat_t *combat_ptr;
    struct game_t *game_ptr, **game_ptr_ptr;
    struct event_t *event_ptr;
    int error, theSignal;
    time_t shutdownStart;
    char error_msg[SZ_ERROR_MESSAGE];

    sprintf(error_msg, "Server started up.  pid=%d\n",
            s->realm.serverPid);

    Do_log(SERVER_LOG, error_msg);

    sigemptyset(&sigMask);
    sigaddset(&sigMask, SIGINT);
    sigaddset(&sigMask, SIGTERM);
    sigaddset(&sigMask, SIGIO);
/*
    sigaddset(&sigMask, SIGALRM);
*/
    sigaddset(&sigMask, SIGUSR1);

    while (s->run_level != FAST_SHUTDOWN) {

	    /* wait for a signal to do anything */
	sigwait(&sigMask, &theSignal);
/*
	sleep(.1);
	theSignal = SIGIO;
*/

	    /* on SIGIO, check for new connections and inactive games */
	if (theSignal == SIGIO) {

	        /* if we're not shutting down check for new connections */
	    if (s->run_level == RUN_SERVER) {
                error = Do_accept_connections(s);
	        if (error) {

		    sprintf(error_msg,
	       "[0.0.0.0:%d] Do_accept_connections returned an error of %d.\n",
	       s->realm.serverPid, error);

		    Do_log_error(error_msg);
	            server_hook = SHUTDOWN;
	        }
            }
	}

	    /* a SIGUSER says to clean up a thread */
	else if (theSignal == SIGUSR1) {

	        /* check for inactive games */
	    Do_lock_mutex(&s->realm.realm_lock);
	    game_ptr_ptr = &s->realm.games;

	    while (*game_ptr_ptr != NULL) {

	        if ((*game_ptr_ptr)->cleanup_thread) {

		    game_ptr = *game_ptr_ptr; 
		    *game_ptr_ptr = game_ptr->next_game;

		    close(game_ptr->the_socket);
		    pthread_join(game_ptr->the_thread, NULL);
	            Do_destroy_mutex(&game_ptr->events_in_lock);

		    free((void *)game_ptr);
        	    --s->num_games;
	        }
	        else {
	            game_ptr_ptr = &((*game_ptr_ptr)->next_game);
	        }
	    }

	    Do_unlock_mutex(&s->realm.realm_lock);
	}

	    /* SIGTERM shuts the server down quickly */
	else if (theSignal == SIGTERM) {
	    server_hook = FAST_SHUTDOWN;
	}

	    /* SIGIO is a normal shutdown */
	else if (theSignal == SIGINT) {
	    server_hook = SHUTDOWN;
	}
	else {
	    sprintf(error_msg,
	        "[0.0.0.0:%d] sigwait caught bad signal %d in Do_main_loop.\n",
	        s->realm.serverPid, theSignal);

	    Do_log_error(error_msg);
	}

	    /* check to see if a thread wants the server down */
	if (server_hook != s->run_level) {

	    if (server_hook == LEISURE_SHUTDOWN && s->num_games == 0) {

		Do_log(SERVER_LOG, "Starting a leisure shutdown.\n");
		server_hook = SHUTDOWN;
		shutdownStart = time(NULL);
	    }

		/* if requested to die now */
	    else if (server_hook == HARD_SHUTDOWN) {

		Do_log(SERVER_LOG, "Hard shutdown ordered.  Exiting Now.\n");
		    /* hasta la vista, baby */
		exit(0);
	    }

		/* check for a quick shutdown */
	    else if (server_hook == FAST_SHUTDOWN) {

		Do_log(SERVER_LOG, "Starting a fast shutdown.\n");
	        s->run_level = FAST_SHUTDOWN;
	    }

		/* normal shutdown */
	    else if (server_hook == SHUTDOWN) {

		Do_log(SERVER_LOG, "Starting a normal shutdown.\n");

	        s->run_level = SHUTDOWN;
		shutdownStart = time(NULL);
	    }
	}

	    /* If shutting down,  quit if nobody's on or time's expired */
        if (s->run_level == SHUTDOWN && (s->num_games == 0 ||
		time(NULL) - shutdownStart > 300)) {

	    s->run_level = FAST_SHUTDOWN;
	}
    }

    return;
}


/***************************************************************************
/ FUNCTION NAME: Do_start_thread(struct client_t *c)
/
/ FUNCTION: Handle thread startup
/
/ AUTHOR:  Brian Kelly, 4/23/99
/
/ ARGUMENTS: 
/	struct client_t *c - structure containing all thread info
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_start_thread(struct client_t *c)
{
    int error;
    char error_msg[SZ_ERROR_MESSAGE], string_buffer[SZ_LINE];
    char *out;
    struct sigaction sigAct;
    struct event_t *eventPtr;

	/* set the thread's process id */
    Do_lock_mutex(&c->realm->realm_lock);
    c->game->clientPid = getpid();
    Do_unlock_mutex(&c->realm->realm_lock);

	/* record this connection */
    sprintf(c->connection_id, "?:%s:%d", c->IP, c->game->clientPid);

    sprintf(error_msg, "[%s] Connection on socket %d.\n",
	    c->connection_id, c->socket);

    Do_log(CONNECTION_LOG, error_msg);

	/* set the socket so I/O notifies this thread */
    if (fcntl(c->socket, F_SETOWN, c->game->clientPid) < 0) {

	sprintf(error_msg,
		"Thread %d returned an error on fcntl F_SETOWN.\n",
		c->socket);

	Do_log_error(error_msg);
	Do_send_error(c, error_msg);
	c->run_level = EXIT_THREAD;
	c->socket_up = FALSE;
    }

    if (fcntl(c->socket, F_SETFL, O_ASYNC) < 0) {

	sprintf(error_msg,
		"Thread %d returned an error on fcntl F_SETFL.\n",
		c->socket);

	Do_log_error(error_msg);
	Do_send_error(c, error_msg);
	c->run_level = EXIT_THREAD;
	c->socket_up = FALSE;
    }

	/* handshake the client */
    Do_handshake(c);

	/* see if this socket should be rejected */
    Do_check_tags(c);

	/* modify stats from this ip - (checks for excessive connections) */
    Do_tally_ip(c, TRUE, 0);

	    /* find all the current players and list them */
    Do_lock_mutex(&c->realm->realm_lock);
    Do_starting_spec(c);
    c->game->sendEvents = TRUE;
    Do_unlock_mutex(&c->realm->realm_lock);

	/* call the main thread loop */
    Do_thread_loop(c);

	/* clean up any events we may have */
    Do_lock_mutex(&c->realm->realm_lock);
    c->game->sendEvents = FALSE;
    Do_unlock_mutex(&c->realm->realm_lock);
    Do_check_events_in(c);

	/* pull death name out of limbo if necessary */
    if (c->previousName[0] != '\0') {
	Do_release_name(c, c->previousName);
    }

	/* clean up socket connection */
    if (c->socket_up) {
        Do_send_int(c, CLOSE_CONNECTION_PACKET);
        Do_send_buffer(c);
    }

        /* log the connection */
    sprintf(error_msg, "[%s] Leaving the game after %d seconds.\n",
	    c->connection_id, time(NULL) - c->date_connected);

    Do_log(CONNECTION_LOG, &error_msg);

	/* tell the server to clean up */
    c->game->cleanup_thread = TRUE;
    free((void *) c);
    kill(c->realm->serverPid, SIGUSR1);

        /* leave the game */
    pthread_exit(0);
}


/***************************************************************************
/ FUNCTION NAME: Do_thread_loop(struct client_t *c)
/
/ FUNCTION: The main loop for threads
/
/ AUTHOR:  Brian Kelly, 4/23/99
/
/ ARGUMENTS: 
/	struct client_t *c - structure containing all thread info
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_thread_loop(struct client_t *c)
{
    char error_msg[SZ_ERROR_MESSAGE];

	/* start the main loop */
    while (c->run_level != EXIT_THREAD) {

 	    /* make characters log in first */
	if (c->run_level == SIGNING_IN) {

	        /* print out the title page */
	    Do_title_page(c);

		/* have the user log in */
	    Do_get_account(c);

		/* see if the game is shutting down */
	    Do_shutdown_check(c);
	}

 	    /* if the player has no character - get one */
	if (c->run_level == CHAR_SELECTION) {

		/* empty out the player strcture */
	    Do_init_player(c);

		/* Get a character */
	    Do_get_character(c);
	}

	if (c->run_level == PLAY_GAME) {

		/* approve the entrance */
	    Do_approve_entrance(c);
	}

		/* if ready to play, enter the game */
	if (c->run_level == PLAY_GAME) {

		/* announce character entrance */
	    Do_entering_character(c);

		/* play the game */
	    Do_play_loop(c);

		/* remove the character from play */
	    Do_leaving_character(c);
	}

	    /* see if the character needs to be saved */
	if (c->run_level == SAVE_AND_CONTINUE ||
		c->run_level == SAVE_AND_EXIT) {

	    Do_handle_save(c);
	}

	    /* regardless, remove the backup */
	else {
	    Do_backup_save(c, FALSE);
	}

	    /* ask if player wishes to go again */
	if (c->run_level == GO_AGAIN) {

		/* ask if the player wants to continue */
	    Do_ask_continue(c);
	}

	    /* see if the game is shutting down */
	Do_shutdown_check(c);
    }
    return;
}


/***************************************************************************
/ FUNCTION NAME: Do_play_loop(struct client_t *c)
/
/ FUNCTION: Default activity when no events are pending
/
/ AUTHOR:  Brian Kelly, 4/23/99
/
/ ARGUMENTS: 
/	struct client_t *c - structure containing all thread info
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_play_loop(struct client_t *c)
{
    struct event_t *event_ptr;

    while (c->run_level == PLAY_GAME 
           || (c->events != NULL && c->player.energy > 0)) {

	    /* age the player */
	Do_age(c);

	    /* if there are events to handle */
	if (c->events != NULL) {

		/* remove the next event */
	    event_ptr = c->events;
	    c->events = event_ptr->next_event;

		/* take care of it */
	    Do_handle_event(c, event_ptr);
	}
	else {

		/* If no events, start a new turn */
	    Do_game_turn(c);

	        /* check for monsters, guru's, etc. */
	    if (!c->player.cloaked 
                && (c->wizard < 3) 
                && (c->player.location == PL_REALM || c->player.location == PL_EDGE)
                && (c->run_level == PLAY_GAME))

	        Do_random_events(c);
        }

	    /* file any events from outside the thread */
	Do_check_events_in(c);

	    /* see if the game is shutting down */
	Do_shutdown_check(c);

	    /* if the socket is down, leave the game */
	if (!c->socket_up && c->run_level == PLAY_GAME) {
	    c->run_level = SAVE_AND_EXIT;
	}
    }

    return;
}


/***************************************************************************
/ FUNCTION NAME: Do_game_turn(struct client_t *c)
/
/ FUNCTION: Default activity when no events are pending
/
/ AUTHOR:  E. A. Estes, 12/4/85
/	   Brian Kelly, 5/8/99
/
/ ARGUMENTS: 
/	struct client_t *c - structure containing all thread info
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_game_turn(struct client_t *c)
{
    struct event_t *event_ptr;
    struct button_t buttons;                     /* input */
    long ch;
    int rc;
    int loop;
    char string_buffer[SZ_LINE];
    double dtemp;
    bool postFlag;
    float ftemp;

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

	Do_send_line(c,
	   "An old wooden sign here says, 'This is the edge of the realm.\n");

	Do_send_line(c, "I would strongly advise going no further.'\n");
    }

	/* see if the player is on a trading post  and not cloaked */
    postFlag = FALSE;
    if (fabs(c->player.x) == fabs(c->player.y) && c->player.location !=
                PL_THRONE && !c->player.cloaked) {

        dtemp = sqrt(fabs(c->player.x)/100.0);

        if (floor(dtemp) == dtemp) {
	    postFlag = TRUE;
	    Do_send_line(c, "You stand in front of a trading post.\n");
        }
    }

    Do_clear_buttons(&buttons, 0);

/*
    if (c->player.special_type != SC_VALAR) {
*/
	strcpy(buttons.button[0], "Rest\n");
/*
    }
*/

        /* print status line */
    strcpy(buttons.button[1], "Move To\n");
    buttons.compass = TRUE;
    strcpy(buttons.button[2], "Info\n");
    strcpy(buttons.button[7], "Quit\n");
/*
examine
rest
do nothing
*/
    if (postFlag) {
        strcpy(buttons.button[3], "Enter Post\n");
    } else if (!c->player.cloaked && c->player.location == PL_REALM) {
        strcpy(buttons.button[3], "Hunt\n");
    }

    if (c->player.cloaked) {
        strcpy(buttons.button[4], "Uncloak\n");
    }
    else if (c->player.level >= MEL_CLOAK && c->player.magiclvl >= ML_CLOAK) {
        strcpy(buttons.button[4], "Cloak\n");
    }

/*
    if (c->player.level >= MEL_TELEPORT && c->player.magiclvl >= ML_TELEPORT &&
	    c->player.special_type != SC_VALAR) {
*/
    if (c->player.level >= MEL_TELEPORT && c->player.magiclvl >= ML_TELEPORT &&
	    !c->player.cloaked) {

        strcpy(buttons.button[5], "Teleport\n");
    }


    if (c->wizard == 2) {
        strcpy(buttons.button[6], "Cantrip\n");
    }
    else if (c->wizard > 3) {
        strcpy(buttons.button[6], "Administrate\n");
    }
    else if (c->wizard) {
        strcpy(buttons.button[6], "Moderate\n");
    }
    else if (c->player.location == PL_THRONE && c->player.special_type
	    == SC_STEWARD && !c->player.cloaked) {

        strcpy(buttons.button[6], "Enact\n");
    }
    else if (c->player.location == PL_THRONE && c->player.special_type
	    == SC_KING && !c->player.cloaked) {

        strcpy(buttons.button[6], "Decree\n");
    }
    else if ((c->player.special_type == SC_COUNCIL || c->player.special_type
	== SC_EXVALAR) && !c->player.cloaked) {

        strcpy(buttons.button[6], "Intervene\n");
    }
    else if (c->player.special_type == SC_VALAR && !c->player.cloaked) {
        strcpy(buttons.button[6], "Command\n");
    }
    else if (c->player.level < 10) {
        strcpy(buttons.button[6], "Help\n");
    }

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

    Do_send_clear(c);


	/* if the valar asks to move, change his request to a null */
/*
    if (c->player.special_type == SC_VALAR && (ch == 0 || (ch >= 8 &&
	    ch != 12))) { 

	ch = 127;	
    }
*/

	/* create an event to handle the player action */
    event_ptr = (struct event_t *) Do_create_event();
    event_ptr->to = c->game;
    event_ptr->from = c->game;

    switch (ch) {

    case 8:               /* move north-west */
	event_ptr->type = MOVE_EVENT;
	event_ptr->arg1 = c->player.x - Do_anglemove(c);
	event_ptr->arg2 = c->player.y + Do_anglemove(c);
	event_ptr->arg3 = A_SPECIFIC;
	break;

    case 9:               /* move up/north */
	event_ptr->type = MOVE_EVENT;
	event_ptr->arg1 = c->player.x;
	event_ptr->arg2 = c->player.y + Do_maxmove(c);
	event_ptr->arg3 = A_SPECIFIC;
	break;

    case 10:               /* move north-east */
	event_ptr->type = MOVE_EVENT;
	event_ptr->arg1 = c->player.x + Do_anglemove(c);
	event_ptr->arg2 = c->player.y + Do_anglemove(c);
	event_ptr->arg3 = A_SPECIFIC;
	break;

    case 11:               /* move left/west */
	event_ptr->type = MOVE_EVENT;
	event_ptr->arg1 = c->player.x - Do_maxmove(c);
	event_ptr->arg2 = c->player.y;
	event_ptr->arg3 = A_SPECIFIC;
	break;

    case 13:               /* move right/east */
	event_ptr->type = MOVE_EVENT;
	event_ptr->arg1 = c->player.x + Do_maxmove(c);
	event_ptr->arg2 = c->player.y;
	event_ptr->arg3 = A_SPECIFIC;
	break;

    case 14:               /* move south-west */
	event_ptr->type = MOVE_EVENT;
	event_ptr->arg1 = c->player.x - Do_anglemove(c);
	event_ptr->arg2 = c->player.y - Do_anglemove(c);
	event_ptr->arg3 = A_SPECIFIC;
	break;

    case 15:               /* move down/south */
	event_ptr->type = MOVE_EVENT;
	event_ptr->arg1 = c->player.x;
	event_ptr->arg2 = c->player.y - Do_maxmove(c);
	event_ptr->arg3 = A_SPECIFIC;
	break;

    case 16:               /* move south-west */
	event_ptr->type = MOVE_EVENT;
	event_ptr->arg1 = c->player.x + Do_anglemove(c);
	event_ptr->arg2 = c->player.y - Do_anglemove(c);
	event_ptr->arg3 = A_SPECIFIC;
	break;

    case 1:               /* move */

        if (Do_coords_dialog(c, &event_ptr->arg1, &event_ptr->arg2,
	    "Where do you wish to move to?\n")) {

	    break;
	}

        Do_distance(c->player.x, event_ptr->arg1, c->player.y,
		event_ptr->arg2, &dtemp);

        if (dtemp > Do_maxmove(c)) {
            Do_send_line(c, "That's too far to move in 1 step.  Get closer by using the compass buttons in the lower-right corner.\n");
	    Do_more(c);
	    Do_send_clear(c);
	}
        else {
	    event_ptr->type = MOVE_EVENT;
	    event_ptr->arg3 = A_SPECIFIC;
        }

        break;

	/* get information */
    case 2:
	event_ptr->type = INFORMATION_EVENT;
	break;

    case 7:               /* good-bye */
	c->run_level = SAVE_AND_CONTINUE;
	break;

    case 4:               /* cloak */

        if (c->player.cloaked || (c->player.level >= MEL_CLOAK &&
		c->player.magiclvl >= ML_CLOAK)) {

	    event_ptr->type = CLOAK_EVENT;
	}
	break;

    case 5:		    /* teleport */
	event_ptr->type = TELEPORT_EVENT;
        event_ptr->arg2 = FALSE;        /* not Gwaihir */
	if (c->player.location == PL_THRONE) {
	    event_ptr->arg3 = FALSE;	/* teleport costs no mana */
	}
	else {
	    event_ptr->arg3 = TRUE;	/* teleport costs mana */
	}
	break;

    case 6:               /* decree and intervention */

            /* cantrips handled first since all other actions are available
               off the cantrip menu */
	if (c->wizard == 2) {
	    event_ptr->type = CANTRIP_EVENT;
	}
	else if (c->wizard > 3) {
	    event_ptr->type = ADMINISTRATE_EVENT;
	}
	else if (c->wizard) {
	    event_ptr->type = MODERATE_EVENT;
	}
	    /* see if the player is allowed to enact */
        else if (c->player.special_type == SC_STEWARD && c->player.location
		== PL_THRONE && !c->player.cloaked) {

	    event_ptr->type = ENACT_EVENT;	
	}
	    /* see if the player is allowed to decree */
        else if (c->player.special_type == SC_KING && c->player.location
		== PL_THRONE && !c->player.cloaked) {

	    event_ptr->type = DECREE_EVENT;	
	}
        else if ((c->player.special_type == SC_COUNCIL || 
	    c->player.special_type == SC_EXVALAR) && !c->player.cloaked) {

	    event_ptr->type = INTERVENE_EVENT;
	}
        else if (c->player.special_type == SC_VALAR && !c->player.cloaked) {
	    event_ptr->type = COMMAND_EVENT;
	}
        else if (c->player.level < 10) {
	    event_ptr->type = HELP_EVENT;
        }
        break;

    case 3:               /* hunt */
	
            /* the valar cannot call monsters and no monsters on throne */
	    /* being cloaked is right out too */
	if (postFlag) {
            event_ptr->type = TRADING_EVENT;
	} else if (!c->player.cloaked && c->player.location == PL_REALM) {

	    Do_sin(c, .001);
            event_ptr->type = MONSTER_EVENT;
	    event_ptr->arg1 = MONSTER_CALL;
	    event_ptr->arg3 = SM_RANDOM;	/* pick a monster normally */
        }
        break;

    case 0:
    case 12:		    /* rest */
	event_ptr->type = REST_EVENT;
        break;

/*    default: NULL_EVENT	stupid people deserve no reward */
    }

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

    return;
}


/***************************************************************************
/ FUNCTION NAME: Do_random_events(struct client_t *c)
/
/ FUNCTION: Default activity when no events are pending
/
/ AUTHOR:  Brian Kelly, 8/17/99
/
/ ARGUMENTS: 
/	struct client_t *c - structure containing all thread info
/
/ RETURN VALUE: none
/
/ DESCRIPTION:
/       Process arguments, initialize program, and loop forever processing
/       player input.
/
****************************************************************************/

Do_random_events(struct client_t *c)
{
    struct event_t *event_ptr;

        /* to shred "backups" */
        if ((c->player.quickness == 0)
             && (RND() >= .1 * c->player.degenerated)) {
	    event_ptr = (struct event_t *)Do_create_event();
	    event_ptr->type = MONSTER_EVENT;
	    event_ptr->arg1 = MONSTER_RANDOM;
	    event_ptr->arg3 = 16;
	    Do_file_event(c, event_ptr);
        }
            
        if (c->player.blind && RND() <= 0.0075) {
	    Do_send_line(c, "You've regained your sight!\n");
            c->player.blind = FALSE;

	        /* update the player description */
	    Do_lock_mutex(&c->realm->realm_lock);
	    Do_player_description(c);
	    Do_unlock_mutex(&c->realm->realm_lock);

	    Do_more(c);
	    Do_send_clear(c);
        }

        if (RND() <= 0.0133) {
	    Do_send_self_event(c, MEDIC_EVENT);
	}

        if (RND() <= 0.0075) {
	    Do_send_self_event(c, GURU_EVENT);
	}

        if (RND() <= 0.005) {
	    event_ptr = (struct event_t *)Do_create_event();
	    event_ptr->type = PLAGUE_EVENT;
	    event_ptr->arg3 = 0;
	    Do_file_event(c, event_ptr);
	}

        if (RND() <= 0.0075) {
	    Do_send_self_event(c, VILLAGE_EVENT);
	}

        if (c->player.level < 3000) {
            if (RND() <= 0.0033 + (c->player.level * .00000125)) {
	        Do_send_self_event(c, TAX_EVENT);
	    }
        } else if (RND() <= 0.0033) {
	    Do_send_self_event(c, TAX_EVENT);
	}

        if (RND() <= 0.015) {
	    event_ptr = (struct event_t *)Do_create_event();
	    event_ptr->type = TREASURE_EVENT;
	    event_ptr->arg1 = c->player.circle;
	    event_ptr->arg3 = 1;
	    Do_file_event(c, event_ptr);
        }

        if (RND() <= 0.0075) {
	    event_ptr = (struct event_t *)Do_create_event();
	    event_ptr->type = TREASURE_EVENT;
	    event_ptr->arg1 = c->player.circle;
	    event_ptr->arg3 = 2;
	    Do_file_event(c, event_ptr);
        }

        if (RND() <= 0.20) {
	    event_ptr = (struct event_t *)Do_create_event();
	    event_ptr->type = MONSTER_EVENT;
	    event_ptr->arg1 = MONSTER_RANDOM;
	    event_ptr->arg3 = SM_RANDOM;
	    Do_file_event(c, event_ptr);
        }
}