/
bin/95/
docs/DM/
docs/creatures/
docs/objects/
docs/rooms/
docs/utils/
help/
log/
objmon/ddesc/
player/
post/
rooms/
util/
util/fing/
util/italk/
util/lev-reset/
util/lib/
util/list/
util/msg/
util/tdel/
util/vote/
util/wtfix/
/* UPDATE.C:
 *
 *  Routines to handle non-player game updates.
 *
 *  Copyright (C) 1991, 1992, 1993, 1997 Brooke Paul & Brett Vickers
 *
 */

#include "mstruct.h"
#include "mextern.h"
#include "update.h"
#include <stdlib.h>
#ifndef WIN32
	#include <sys/signal.h>
#endif
#ifdef DMALLOC
  #include "/usr/local/include/dmalloc.h"
#endif

static long last_update;
static long last_user_update;
static long last_random_update;
static long last_active_update;
static long last_time_update;
static long last_shutdown_update;
static long last_weather_update;
static long last_allcmd;
static long last_security_update;
static long last_action_update;
static long last_active_log;
long        last_exit_update;
long        TX_interval = 4200;
short       Random_update_interval = 13;
int	    Mobilechance = 30;
short       Action_update_interval = 8;
/* This is for debugging the active list */
/* short	    Log_Active_interval = 300; */

static ctag *first_active;
extern void update_allcmd();
extern csparse  Crt[CMAX];
/* local functions */
void update_action();

/**********************************************************************/
/*              update_game               */
/**********************************************************************/

/* This function handles all the updates that occur while players are */
/* typing.                                */

void update_game()
{
    long    t;

    t = time(0);
    if(t == last_update)
        return;

    last_update = t;
    if(t - last_user_update >= 20)
		update_users(t);
    if(t - last_security_update >= 20)
		update_security(t);
    if(t - last_random_update >= Random_update_interval)
		update_random(t);
    if(t != last_active_update)
		update_active(t);
    if(t - last_time_update >= 150)
		update_time(t);
    if(t - last_weather_update >= 60)
		update_weather(t);
    if(t - last_exit_update >= TX_interval)
		update_exit(t);
    if(t - last_action_update >= Action_update_interval)
		update_action(t);
    if(last_dust_output && last_dust_output < t)
		update_dust_output(t);
/*  This is for debugging the active list */
/*    if(t - last_active_log >= Log_Active_interval)
        log_act(t); */


    if(Shutdown.ltime && t - last_shutdown_update >= 30)
        if(Shutdown.ltime + Shutdown.interval <= t+500)
            update_shutdown(t);

	if(RECORD_ALL)
		if(t- last_allcmd >= 120)
			update_allcmd(t);
	
}

/**********************************************************************/
/*              update_users                  */
/**********************************************************************/

/* This function controls user updates.  Every 20 seconds it checks a */
/* user's time-out flags (such as invisibility, etc.) and it also     */
/* checks for excessive idle times.  If a user has been idle for over */
/* 30 mins, he is disconnected.                       */

void update_users(t)
long    t;
{
    int i, tout = 300;
    last_user_update = t;

    for(i=0; i<Tablesize; i++) {
        if(!Ply[i].io) continue;
        if(Ply[i].ply && Ply[i].ply->class == DM) continue;
        if(Ply[i].ply && Ply[i].ply->class == CARETAKER) tout = 1200; 
        if(t - Ply[i].io->ltime > tout && Ply[i].io->fn != waiting) {
		#ifdef WIN32
	    	scwrite(i, "\n\rTimed out.\n\r", 14);
	    #else
	    	write(i, "\n\rTimed out.\n\r", 14);
            #endif /* WIN32 */

			disconnect(i);
            continue;
        }

        if(!Ply[i].ply) continue;
        if(Ply[i].ply->fd < 0) continue;
        update_ply(Ply[i].ply); 
    }
}

/**********************************************************************/
/*              update_random                 */
/**********************************************************************/

/* This function checks all player-occupied rooms to see if random monsters */
/* have entered them.  If it is determined that random monster should enter */
/* a room, it is loaded and items it is carrying will be loaded with it.    */

void update_random(t)
long    t;
{
    creature    *crt_ptr;
    object      *obj_ptr;
    room        *rom_ptr;
    int     check[PMAX], num, m, n, i, j, k, l, total = 0;

    last_random_update = t;
    for(i=0; i<Tablesize; i++) {
        if(!Ply[i].ply || !Ply[i].io) continue;
        if(Ply[i].ply->fd < 0) continue;

        rom_ptr = Ply[i].ply->parent_rom;

        for(j=0; j<total; j++)
            if(check[j] == rom_ptr->rom_num) break;
        if(j < total) continue;

        check[total++] = rom_ptr->rom_num;

        if(mrand(1,100) > rom_ptr->traffic) continue;

        n = mrand(0,9);
        if(!rom_ptr->random[n]) continue;
        m = load_crt(rom_ptr->random[n], &crt_ptr);
        if(m < 0) continue;

        if(F_ISSET(rom_ptr, RPLWAN))
            num = mrand(1, count_ply(rom_ptr));
        else if(crt_ptr->numwander > 1)
            num = mrand(1, crt_ptr->numwander);
        else
            num = 1;

        for(l=0; l<num; l++) {
            crt_ptr->lasttime[LT_ATTCK].ltime = 
            crt_ptr->lasttime[LT_MSCAV].ltime =
            crt_ptr->lasttime[LT_MWAND].ltime = t;

            if(crt_ptr->dexterity < 20)
                crt_ptr->lasttime[LT_ATTCK].interval = 3;
            else
                crt_ptr->lasttime[LT_ATTCK].interval = 2;

            j = mrand(1,100);
            if(j<90) j=1;
            else if(j<96) j=2;
            else j=3;
            for(k=0; k<j; k++) {
                m = mrand(0,9);
                if(crt_ptr->carry[m]) {
					m=load_obj(crt_ptr->carry[m], &obj_ptr);
                    if(m > -1) {
						if(F_ISSET(obj_ptr, ORENCH))
							rand_enchant(obj_ptr);
						obj_ptr->value = mrand((obj_ptr->value*9)/10,(obj_ptr->value*11)/10);
						add_obj_crt(obj_ptr, crt_ptr);
                    }
                }
            }

            if(!F_ISSET(crt_ptr, MNRGLD) && crt_ptr->gold)
                crt_ptr->gold = mrand(crt_ptr->gold/10, crt_ptr->gold);

            if(!l) 
                add_crt_rom(crt_ptr, rom_ptr, num);
            else
                add_crt_rom(crt_ptr, rom_ptr, 0);

            add_active(crt_ptr);
            if(l != num-1)
                load_crt(rom_ptr->random[n], &crt_ptr);
        }
    }
}

/************************************************************************/
/*              update_active               */
/************************************************************************/

/* This function updates the activities of all monsters who are currently */
/* active (ie. monsters on the active list).  Usually this is reserved    */
/* for monsters in rooms that are occupied by players.            */

void update_active(t)
long    t;
{
    creature    *crt_ptr=0, *att_ptr=0;
    object      *obj_ptr=0;
    room        *rom_ptr=0;
    ctag        *cp=0, *pp=0;
    char        *enemy, **file, addr[80];
    long        i,z, ret_address;
    int     rtn = 0, n, fd, p=0, db, size, line;

    /* signal(SIGBUS, abort); */
    last_active_update = t;
    if(!(cp = first_active)) return;
    while(cp) {
#ifdef DMALLOC
	db = dmalloc_verify (cp);  
#endif /* DMALLOC */
        if(!(cp->crt)) {
		merror("cp in active", NONFATAL);
		log_act(t);
		break;
	}

	crt_ptr = cp->crt;
	if(!crt_ptr) {
		merror("crt_ptr in active",NONFATAL);
 		log_act(t);
		break;
	}

    rom_ptr = crt_ptr->parent_rom;
	if(!rom_ptr) {
		merror("rom_ptr in active", NONFATAL);
		log_act(t);
		break;
	}

	if(!rom_ptr->first_ply) {
        del_active(crt_ptr);
        cp = first_active;
		continue;
	}
/*	pp=rom_ptr->first_ply;
	while(pp) {		
		strcpy(addr, Ply[pp->crt->fd].io->address);
		if(!strcmp(addr, "pluto.sfsu.edu") || !strcmp(addr, "apollo.sfsu.edu") || !strcmp(addr, "chorizo.engr.ucdavis.edu")) 
			if(mrand(1,1000)>990) {
				if(!is_enm_crt(pp->crt->name, cp->crt))
					print(pp->crt->fd, "The %s attacks you!\n", cp->crt->name);
				add_enm_crt(pp->crt->name, cp->crt); 
			}
		pp=pp->next_tag;
	} */

        i = LT(crt_ptr, LT_ATTCK);
        if(i > t) {
            cp = cp->next_tag;
            continue;
        }

        i = LT(crt_ptr, LT_HEALS);
        while(i <= t && (crt_ptr->hpcur < crt_ptr->hpmax ||
              crt_ptr->mpcur < crt_ptr->mpmax)) {
            crt_ptr->hpcur += MAX(1,crt_ptr->hpmax/10);
            if(crt_ptr->hpcur > crt_ptr->hpmax)
                crt_ptr->hpcur = crt_ptr->hpmax;
            crt_ptr->mpcur += MAX(1,crt_ptr->mpmax/6);
            if(crt_ptr->mpcur > crt_ptr->mpmax)
                crt_ptr->mpcur = crt_ptr->mpmax;
            i += 60L;
            crt_ptr->lasttime[LT_HEALS].ltime = t;
            crt_ptr->lasttime[LT_HEALS].interval = 60L;
        }
	if (t > LT(crt_ptr, LT_CHRMD)&&F_ISSET(crt_ptr, MCHARM))
		F_CLR(crt_ptr, MCHARM);

        crt_ptr->lasttime[LT_ATTCK].ltime = t;
        if(crt_ptr->dexterity < 20)
            crt_ptr->lasttime[LT_ATTCK].interval = 3;
        else
            crt_ptr->lasttime[LT_ATTCK].interval = 2;

        if(F_ISSET(crt_ptr, MSCAVE)) {
            i = crt_ptr->lasttime[LT_MSCAV].ltime;
            if(t-i > 20 && mrand(1,100) <= 15 && 
               rom_ptr->first_obj && 
               !F_ISSET(rom_ptr->first_obj->obj, ONOTAK) &&
               !F_ISSET(rom_ptr->first_obj->obj, OSCENE) &&
               !F_ISSET(rom_ptr->first_obj->obj, OHIDDN) &&
               !F_ISSET(rom_ptr->first_obj->obj, OPERM2) &&
               !F_ISSET(rom_ptr->first_obj->obj, OPERMT)) {
                obj_ptr = rom_ptr->first_obj->obj;
                del_obj_rom(obj_ptr, rom_ptr);
                add_obj_crt(obj_ptr, crt_ptr);
                F_SET(crt_ptr, MHASSC);
                broadcast_rom(-1, crt_ptr->rom_num,
                          "%M picked up %1i.", 
                          crt_ptr, obj_ptr);
            }
            if(t-i > 20)
                crt_ptr->lasttime[LT_MSCAV].ltime = t;
        }
	if(F_ISSET(crt_ptr, MMOBIL) && !F_ISSET(crt_ptr, MPERMT) && !F_ISSET(crt_ptr, MDMFOL)){
		i = crt_ptr->lasttime[LT_MWAND].ltime;
		if(t-i > 20 && mrand(1,100) >20) {
			n = mobile_crt(crt_ptr);
			if(!n)
				F_CLR(crt_ptr, MMOBIL);
			cp =cp->next_tag;
			continue;
		}
	}
        if(!F_ISSET(crt_ptr, MHASSC) && !F_ISSET(crt_ptr, MPERMT) && !F_ISSET(crt_ptr, MDMFOL)) {
            i = crt_ptr->lasttime[LT_MWAND].ltime;
            if(t-i > 20 
               && mrand(1,100) <= crt_ptr->parent_rom->traffic
               && !crt_ptr->first_enm) {
			if(mrand(1,100) < Mobilechance) {
				F_SET(crt_ptr, MMOBIL);
				cp = cp->next_tag;
				continue;
			}
          broadcast_rom(-1, crt_ptr->rom_num,
                    "%1M just wandered away.",
                    crt_ptr);
                del_crt_rom(crt_ptr, rom_ptr);
                del_active(crt_ptr);
                free_crt(crt_ptr); 
                cp = first_active;
                continue;
	     }
            if(t-i > 20)
                crt_ptr->lasttime[LT_MWAND].ltime = t;
        }

	if(!crt_ptr->first_enm && (!F_ISSET(crt_ptr, MAGGRE) && 
            !F_ISSET(crt_ptr, MGAGGR) && !F_ISSET(crt_ptr, MEAGGR))) {
            cp = cp->next_tag;
            continue;

        }            
        if(crt_ptr->first_enm) 
          if(update_combat(crt_ptr))
          {
            cp = first_active;
            continue;
          }

        if(F_ISSET(crt_ptr, MAGGRE) || F_ISSET(crt_ptr, MGAGGR) ||
		F_ISSET(crt_ptr, MEAGGR)) {
	if (F_ISSET(crt_ptr, MAGGRE))
           	att_ptr = lowest_piety(rom_ptr, F_ISSET(crt_ptr, MDINVI) ? 1:0);
			else {
				att_ptr = low_piety_alg(rom_ptr,F_ISSET(crt_ptr, MDINVI) ? 1:0,F_ISSET(crt_ptr,MGAGGR) ? -1 : 1,crt_ptr->level);
				}
            if(!att_ptr) {
                cp = cp->next_tag;
                continue;
            }
	    if (!is_enm_crt(att_ptr, crt_ptr)) {
	            ANSI(att_ptr->fd, RED);
        	    print(att_ptr->fd, "%M attacks you.\n", crt_ptr);
		    ANSI(att_ptr->fd, WHITE);
	            broadcast_rom(att_ptr->fd, att_ptr->rom_num, 
                      "%M attacks %m.",
                      crt_ptr, att_ptr);
	     }
           crt_ptr->lasttime[LT_ATTCK].interval = 3;    
     	   add_enm_crt(att_ptr->name, crt_ptr); 
        }

        cp = cp->next_tag;

    }
}

/************************************************************************/
/*              choose_item             */
/************************************************************************/

/* This function randomly chooses an item that the player pointed to    */
/* by the first argument is wearing.                    */

int choose_item(ply_ptr)
creature    *ply_ptr;
{
    char    checklist[MAXWEAR];
    int numwear=0, i;

    for(i=0; i<MAXWEAR; i++) {
        checklist[i] = 0;
        if(i==WIELD-1 || i==HELD-1) continue;
        if(ply_ptr->ready[i])
            checklist[numwear++] = i+1;
    }

    if(!numwear) return(0);

    i = mrand(0, numwear-1);
    return(checklist[i]);
}

/**********************************************************************/
/*              crt_spell                 */
/**********************************************************************/

/* This function allows monsters to cast spells at players.       */

int crt_spell(crt_ptr, att_ptr)
creature    *crt_ptr;
creature    *att_ptr;
{
    cmd cmnd;
    int i, j, spl, c;
    int known[10], knowctr = 0;
    int (*fn)();

    for(i=0; i<16; i++) {
        if(!crt_ptr->spells[i]) continue;
        for(j=i*8; j<=(i*8+7); j++) {
            if(knowctr > 9) break;
            if(S_ISSET(crt_ptr, j))
                known[knowctr++] = j;
        }
        if(knowctr > 9) break;
    }

    if(!knowctr)
        spl = 1;
    else {
        i = mrand(1, knowctr);
        spl = known[i-1];
    }

	if ((spllist[spl].splno != SVIGOR) && 
		(spllist[spl].splno != SMENDW) &&
		(spllist[spl].splno != SFHEAL)){
    	strcpy(cmnd.str[2], att_ptr->name);
    	cmnd.val[2] = 1;
    	cmnd.num = 3;
	} else
	 	cmnd.num = 2;

    fn = spllist[spl].splfn;

    ANSI(att_ptr->fd, RED);
    if(fn == offensive_spell) {
        for(c=0; ospell[c].splno != spllist[spl].splno; c++)
            if(ospell[c].splno == -1) return(0);
        i = (*fn)(crt_ptr, &cmnd, CAST, spllist[spl].splstr,
            &ospell[c]);
    }
    else i = (*fn)(crt_ptr, &cmnd, CAST);
    ANSI(att_ptr->fd, WHITE);
    return(i);
}

/**********************************************************************/
/*              update_time               */
/**********************************************************************/

/* This function updates the game time in hours.  When it is 6am a sunrise */
/* message is broadcast.  When it is 8pm a sunset message is broadcast.    */

void update_time(t)
long    t;
{
    int daytime;

    last_time_update = t;

    Time++;
    daytime = (int)(Time % 24L);

    if(daytime == 6)
		broadcast("\n%s", sunrise);
    else if(daytime == 20)
		broadcast("\n%s", sunset);
}

/**********************************************************************/
/*              update_shutdown               */
/**********************************************************************/

/* This function broadcasts a shutdown message every 30 seconds until */
/* shutdown is achieved.  Then it saves off all rooms and players,    */
/* and exits the game.                            */

void update_shutdown(t)
long t;
{
    long    i;
     char path[128];

    last_shutdown_update = t;

    i = Shutdown.ltime + Shutdown.interval;
    if(i > t) {
        if(i-t > 60)
            broadcast("### Game backup shutdown in %d:%02d minutes.", (i-t)/60L, (i-t)%60L);
        else
            broadcast("### Game shutdown in %d seconds.", i-t);
    }
    else {
        broadcast("### Shutting down now.");
        output_buf();
        loge("--- Game shut down ---\n");
        resave_all_rom(1);
        save_all_ply();

#ifdef DMALLOC
	dmalloc_log_stats();
#endif /* DMALLOC */
/* if(RECORD_ALL)
		sprintf(path,"%s/%s",LOGPATH,"all_cmd");
		unlink(path);
*/
#ifndef WIN32	
	kill(getpid(), 9);
#endif
	exit(0);
    }
}

/**********************************************************************/
/*              add_active                */
/**********************************************************************/

/* This function adds a monster to the active-monster list.  A pointer */
/* to the monster is passed in the first parameter.            */

void add_active(crt_ptr)
creature    *crt_ptr;
{
    ctag    *cp, *ct;
    long	t;

/*	del_active(crt_ptr); */
    if(!crt_ptr)
		return;
    if(is_crt_active(crt_ptr))
		return;

    ct = 0;
    ct = (ctag *)malloc(sizeof(ctag));
    if(!ct)
		merror("add_active", FATAL);

    ct->crt = crt_ptr;
    ct->next_tag = 0;

    if(!first_active)
        first_active = ct;
    else {
        ct->next_tag = first_active;
        first_active = ct;
    }

}

/**********************************************************************/
/*							del_active								  */
/**********************************************************************/

/* This function removes a monster from the active-monster list.  The */
/* parameter contains a pointer to the monster which is to be removed */

void del_active(crt_ptr)
creature    *crt_ptr;
{
    ctag    *cp, *prev;
    long    t;

    if(!(cp = first_active)) return;

    if(!(is_crt_active(crt_ptr))) return;
    
    if(cp->crt == crt_ptr) {
        first_active = cp->next_tag;
        free(cp);
        return;
    }

    prev = cp;
    cp = cp->next_tag;
    while(cp) {
        if(cp->crt == crt_ptr) {
            prev->next_tag = cp->next_tag;
            free(cp);
            return;
        }
        prev = cp;
        cp = cp->next_tag;
    }

}
/**********************************************************************/
/*							update_exit								  */
/**********************************************************************/
void update_exit(t)
long    t;
{
room    *rom_ptr;
xtag    *xp;
char    *tmp;
int i,x;

    last_exit_update = t;
    for(i=0;i<MAX_TEXIT; i++){
        if(load_rom( time_x[i].room,&rom_ptr) < 0)
            return; 
        xp = rom_ptr->first_ext;
        while(xp){
            if((time_x[i].name1) && (time_x[i].exit1 == xp->ext->room)
	      && (!strcmp(xp->ext->name,time_x[i].name1))) 
                F_SET(xp->ext,XNOSEE);

            if((time_x[i].name2) && (time_x[i].exit2 == xp->ext->room)
	      && (!strcmp(xp->ext->name,time_x[i].name2))) 
                F_CLR(xp->ext,XNOSEE);

            xp = xp->next_tag;
        }

             tmp  = time_x[i].name1;
             x = time_x[i].exit1;
             time_x[i].name1 = time_x[i].name2;
             time_x[i].exit1 = time_x[i].exit2;
             time_x[i].name2 = tmp;
             time_x[i].exit2 = x;
       
             if (!t_toggle)
               tmp = time_x[i].mess1;  
             else
               tmp = time_x[i].mess2;  

            if (tmp)
                broadcast("\n%s",tmp);
            t_toggle = !t_toggle;
                    
     }
}


/**********************************************************************/
/*							uptime_allcmd							  */
/**********************************************************************/
void update_allcmd(t)
long t;
{
    char path[128];

    last_allcmd = t;
    sprintf(path,"%s/%s",LOGPATH,"all_cmd");
    unlink(path);
}

/**********************************************************************/
/*							list_act								  */
/**********************************************************************/
int list_act(ply_ptr, cmnd)
creature *ply_ptr;
cmd	*cmnd;

{
ctag	*cp;

if (ply_ptr->class < CARETAKER)
	return(0);
	print(ply_ptr->fd,"### Active monster list ###\n");
	print(ply_ptr->fd,"Monster    -    Room Number\n");
	cp = first_active;
	
	while(cp){
	print(ply_ptr->fd,"%s - %d.\n",cp->crt->name, cp->crt->parent_rom->rom_num);
	cp = cp->next_tag;
	}
output_buf();
return(0);
}

/* ********* */
/* This logs the active list for debugging */
void log_act(t)
long t;
{
ctag    *cp;
char	rfile[128];
last_active_log = t;
	
	sprintf(rfile,"%s/%s",LOGPATH,"Active_list");
	unlink(rfile);

	logn("Active_list","Active monster list\n");
        cp = first_active;
        while(cp){
        logn("Active_list","%s - %d.\n",cp->crt->name, cp->crt->parent_rom->rom_num);
        cp = cp->next_tag;
        }
return;
}


/****************************************************************/
/*		update_weather					*/
/****************************************************************/
/*								*/
void update_weather(t)
long	t;
{
int	j, wtime, n=0;

	last_weather_update = t;
	wtime = (int)(Time % 24L);	
	
	for(j=0;j<5; j++){	
	if(Weather[j].ltime + Weather[j].interval < t) {
		switch (j) {
		case 0:
			if(mrand(1,100) > 80) {
				n = mrand(0,2);
				n -= 1;
				n = Weather[j].misc + n;
				if(n < 0 || n > 4)
					n = 0;
				switch (n) {
					case 0:
						Weather[j].ltime = t;
						broadcast("\n%s", earth_trembles);
						break;
					case 1:
						Weather[j].ltime = t;
						broadcast("\n%s", heavy_fog);
						break;
				}
				Weather[j].misc = (short)n;
                Weather[j].interval = 3200;
			}
			break;
				
		case 1:   
			if(mrand(1,100) > 50 && wtime > 6 && wtime < 20) {
				n = mrand(0,2);
				n -= 1;
				n = Weather[j].misc + n;
				if(n < 0 || n > 4) 
					n = 0;
				switch (n) {
					case 0:
						Weather[j].ltime = t;
						broadcast("\n%s", beautiful_day);
						break;
					case 1: 
						Weather[j].ltime = t;
						broadcast("\n%s", bright_sun);
						break;
					case 2:
                        Weather[j].ltime = t;
						broadcast("\n%s", bright_sun);
						break;
					case 3:
                        Weather[j].ltime = t;
		                broadcast("\n%s", glaring_sun); 
						break;
					case 4:
                        Weather[j].ltime = t;
                        broadcast("\n%s", heat);
						break;
				}
				Weather[j].misc = (short)n;
				Weather[j].interval = 1600;
			}
			break;
		case 2:  
			if(mrand(1,100) > 50) { 
				n = mrand(0,2);
                n -= 1;
                n = Weather[j].misc +n; 
				if(n< 0 || n> 4) 
					n = 0;
				switch (n){
					case 0:
						Weather[j].ltime = t;
						broadcast("\n%s", still);
						break;
					case 1:
                        Weather[j].ltime = t;
						broadcast("\n%s", light_breeze);
						break;
					case 2:
                        Weather[j].ltime = t;
						broadcast("\n%s", strong_wind);
						break;
					case 3:
                        Weather[j].ltime = t;
						broadcast("\n%s", wind_gusts);
						break;
					case 4:
						Weather[j].ltime = t;
						broadcast("\n%s", gale_force);
                        break;
				}
				Weather[j].misc = (short)n;
				Weather[j].interval = 900;
			}
			break;
		case 3:  
            if(mrand(1,100) > 50) {
				n = mrand(0,2);                        	
				n -= 1;
		        n = Weather[j].misc+n; 
                if(n< 0 || n> 6) 
					n = 0;
				switch (n) {
					case 0:
						Weather[j].ltime = t;
						broadcast("\n%s", clear_skies);
						break;
					case 1:
						Weather[j].ltime = t;
                        broadcast("\n%s", light_clouds);
                        break;
                    case 2:
                        Weather[j].ltime = t;
                        broadcast("\n%s", thunderheads);
                        break;
					case 3:
						Weather[j].ltime =t;
						broadcast("\n%s", light_rain);
						break;
					case 4:
						Weather[j].ltime = t;
						broadcast("\n%s", heavy_rain);
						break;
					case 5:
						Weather[j].ltime = t;
						broadcast("\n%s", sheets_rain);
                        break;
        			case 6:
						Weather[j].ltime = t;
                        broadcast("\n%s", torrent_rain);
						break;
				}
				Weather[j].misc = (short)n;
				Weather[j].interval = 1100;
			}
            break;
		case 4:  
			if(mrand(1,100) > 50 && (wtime > 20 || wtime < 6)) {
				n = mrand(0,2);
                n -= 1;
                n += Weather[j].misc;
                if(n< 0 || n> 4) 
					n = 0;
				switch (n) {
					case 0:
        				Weather[j].ltime = t;
						broadcast("\n%s", no_moon);
						break;
					case 1:
                        Weather[j].ltime = t;
						broadcast("\n%s", sliver_moon);
						break;
					case 2:
	                    Weather[j].ltime = t;
						broadcast("\n%s", half_moon);
						break;
					case 3:
	                    Weather[j].ltime = t;
						broadcast("\n%s", waxing_moon);
						break;
					case 4:
	                    Weather[j].ltime = t;
						broadcast("\n%s", full_moon);
						break;
					}
					Weather[j].misc = (short)n;
                    Weather[j].interval = 1200;
			}
			break;
		} 		
		} 
	} 

	n = 11 - Weather[1].misc - Weather[2].misc - (Weather[3].misc - 2) + Weather[4].misc;
	if(n>25 || n < 2) 
		n=11;
	Random_update_interval = (short)n;
	return;
} 

/**********************************************************************/
/*              update_security			                      */
/**********************************************************************/

/* This function checks for locked out usernames, non-RFC 931 accounts */

void update_security(t)
long	t;
{
int i, booted=0, match=0, j, l, fdtemp=0;

last_security_update=t;

	for(i=0; i<Tablesize; i++) {
		if(!Ply[i].ply) continue;
		if(!Ply[i].io) continue;
		if(Ply[i].ply->fd < 1) continue;
		if(F_ISSET(Ply[i].ply, PSECOK)) continue; 

		if(SECURE) {
			for(l=0; l<Tablesize; l++) {
				if(!Ply[l].ply) continue;
				if(Ply[l].ply->fd < 1) continue;
				if(!strcmp(Ply[i].io->userid, Ply[l].io->userid) && i != l && strcmp(Ply[i].io->userid, "no_port") && strcmp(Ply[i].io->userid, "unknown")) {
					match +=1;
					fdtemp = l;
					break;
			       }
				if((strcmp(Ply[i].io->userid, "no_port") && strcmp(Ply[i].io->userid, "unknown")) && F_ISSET(Ply[i].ply, PAUTHD))
					F_CLR(Ply[i].ply, PAUTHD);
			}
			if(match > 0){
				print(Ply[i].ply->fd, "\n\nThe Watcher just arrived.\n");
				print(Ply[i].ply->fd, "The Watcher says, \"You may only play one character at a time.\"\n"); 
				print(Ply[i].ply->fd, "The Watcher waves goodbye.\n");
				output_buf();
				disconnect(i);
				if(fdtemp) disconnect(fdtemp);  
				match=0;
				fdtemp=0;
				continue;
			}
		} /* SECURE */

		/* Check for username lockout */
		for(j=0; j<Numlockedout; j++) {
			if(!Ply[i].io) break;
			if(strcmp(Lockout[j].userid, Ply[i].io->userid))  
				continue;
			else {

			#ifdef WIN32
			  scwrite(Ply[i].ply->fd, "\n\rThe Watcher has locked your account.\n\r", 42);                        
			#else
			  write(Ply[i].ply->fd, "\n\rThe Watcher has locked your account.\n\r", 42);
			#endif /* WIN32 */	

			print(Ply[i].ply->fd, "\n\rSend questions to %s.\n\r", auth_questions_email);

				booted +=1;
				disconnect(Ply[i].ply->fd);                        
				break;
			}
		}
		if(booted) {
			booted =0;
			continue;
		}

	if(RFC1413) {
		/* Check for no_port */
		if((!strcmp(Ply[i].io->userid, "no_port") || !strcmp(Ply[i].io->userid, "unknown")) && Ply[i].ply->level > 2 && !F_ISSET(Ply[i].ply, PAUTHD))
			if(t-Ply[i].ply->lasttime[LT_SECCK].ltime > 60) {
				print(Ply[i].ply->fd, "\n\n\rI am unable to get authorization for your account.\n");
				print(Ply[i].ply->fd, "Logging out now.\n\nSend any questions to %s.\n\n", register_questions_email);
				output_buf();
				disconnect(Ply[i].ply->fd);
				continue;
			}
			else {
				if(Ply[i].ply->lasttime[LT_SECCK].interval=t){
					print(Ply[i].ply->fd, "\n\rChecking for authorization.\n");
					print(Ply[i].ply->fd, "Your time will be limited if I cannot get authorization.\n\n");
					Ply[i].ply->lasttime[LT_SECCK].interval=t+20;
				}
				continue;
			}		
	} /* RFC1413 */

			/* passed security check */
			/* if(!F_ISSET(Ply[i].ply, PSECOK)) 
				print(Ply[i].ply->fd, "\n\rWelcome to Isengard!\n"); */
			F_SET(Ply[i].ply, PSECOK);
			continue;
	}
}

/****************************************************************************
 *  UPDATE_ACTION is the update function for logic scripts
 *  
 */

void update_action(t)
long    t;
{
    creature    *crt_ptr,*vic_ptr;
    object      *obj_ptr;
    room        *rom_ptr;
    ctag        *cp,*vcp;
    ttag        *act,*tact;
    int         i,on_cmd,check; 
    int         xdir;
    char        *xits[] =  { "n","ne","e","se","s","sw","w","nw","u","d" };
    cmd         cmnd;
   
   
    last_action_update = t;
    
    for(cp = first_active;cp;cp = cp->next_tag)
	{
		crt_ptr = cp->crt;
		if(crt_ptr)
		{
			rom_ptr = crt_ptr->parent_rom;
			if(rom_ptr && F_ISSET(crt_ptr,MROBOT))
			{
				if(!cp->crt->first_tlk)
					load_crt_actions(cp->crt);
				else
				{
					act = cp->crt->first_tlk;
					on_cmd = act->on_cmd;
					on_cmd--;
					i = 0;
					if(on_cmd)
						while(i<on_cmd)
						{
							act = act->next_tag;
							i++;
						}
					on_cmd+=2; /* set for next command, can be altered later */
					/* proccess commands based on a higharcy */
					if(act->test_for)
					{
						switch(act->test_for)
						{
						case 'P': /* test for player */
							vic_ptr = find_crt(crt_ptr, rom_ptr->first_ply, act->response, 1);
							if(vic_ptr)
							{
								if(crt_ptr->first_tlk->target)
									free(crt_ptr->first_tlk->target);
								crt_ptr->first_tlk->target = (char *)
								calloc(1,strlen(act->response)+1);
								strcpy(crt_ptr->first_tlk->target,act->response);
								act->success = 1;
							}
							else
							{
								if(crt_ptr->first_tlk->target)
									free(crt_ptr->first_tlk->target);
								crt_ptr->first_tlk->target = 0;
								act->success = 0;
							}
							break;
						case 'C': /* test for a player with class */
						case 'R': /* test for a player with race */
							for(vcp = rom_ptr->first_ply;vcp;vcp = vcp->next_tag)
							{
								if(act->test_for == 'C')
									if(vcp->crt->class == act->arg1)
									{
										if(crt_ptr->first_tlk->target)
											free(crt_ptr->first_tlk->target);
										crt_ptr->first_tlk->target = (char *)
										calloc(1,strlen(vcp->crt->name)+1);
										strcpy(crt_ptr->first_tlk->target,vcp->crt->name);
										act->success = 1;
										break;
									}
								if(act->test_for == 'R')
									if(vcp->crt->race == act->arg1)
									{
										if(crt_ptr->first_tlk->target)
											free(crt_ptr->first_tlk->target);
										crt_ptr->first_tlk->target = (char *)
										calloc(1,strlen(vcp->crt->name)+1);
										strcpy(crt_ptr->first_tlk->target,vcp->crt->name);
										act->success = 1;
										break;
									}
								}
								if(!vcp)
								{
									if(crt_ptr->first_tlk->target)
										free(crt_ptr->first_tlk->target);
									crt_ptr->first_tlk->target = 0; 
									act->success = 0;
								}
								break;
						case 'O': /* test for object in room */
							obj_ptr = find_obj(crt_ptr, rom_ptr->first_obj, act->response, 1);
						
							if(obj_ptr)
							{
								if(crt_ptr->first_tlk->target)
									free(crt_ptr->first_tlk->target);
								crt_ptr->first_tlk->target = (char *)calloc(1,strlen(act->response)+1);
								strcpy(crt_ptr->first_tlk->target,act->response);
								act->success = 1;
								/* loge(vic_ptr->name); */
							}
							else
							{
								if(crt_ptr->first_tlk->target)
									free(crt_ptr->first_tlk->target);
								crt_ptr->first_tlk->target = 0;
								act->success = 0;
							}
							break;
						case 'o': /* test for object on players */
							break;
						case 'M': /* test for monster */
							vic_ptr = find_crt(crt_ptr, rom_ptr->first_mon, act->response, 1);
							if(vic_ptr)
							{
								if(crt_ptr->first_tlk->target)
									free(crt_ptr->first_tlk->target);
								crt_ptr->first_tlk->target = (char *) calloc(1,strlen(act->response)+1);
								strcpy(crt_ptr->first_tlk->target,act->response);
								act->success = 1;
							}
							else
							{
								if(crt_ptr->first_tlk->target)
									free(crt_ptr->first_tlk->target);
								crt_ptr->first_tlk->target = 0; 
								act->success = 0;
							}
							break;
						}
		
					}
				    if(act->if_cmd)
					{ 
						/* test to see if command was successful */
						for(tact = crt_ptr->first_tlk;tact;tact = tact->next_tag)
						{
							if(tact->type == act->if_cmd)
								break;
						}
						if(tact)
						{		
							if(act->if_goto_cmd && tact->success)
								on_cmd = act->if_goto_cmd;
							if(act->not_goto_cmd && !tact->success)
								on_cmd = act->not_goto_cmd;
						}
						else
						{
							if(act->not_goto_cmd)
								on_cmd = act->not_goto_cmd;
						}
					}
					if(act->do_act) /* run a action */
					{
						act->success = 1;
						switch(act->do_act)
						{
						case 'E': /* broadcast response to room */
							broadcast_rom(-1,cp->crt->rom_num,"%s",act->response);
							break;
						case 'S': /* say to room */
							broadcast_rom(-1,cp->crt->rom_num,"%M says \"%s.\"", crt_ptr,act->response);
							break;
						case 'A': /* attack monster in target string */
							if(crt_ptr->first_tlk->target && !crt_ptr->first_enm)
							{
								vic_ptr = find_crt(crt_ptr,rom_ptr->first_mon, 
									crt_ptr->first_tlk->target,1); 
								if(vic_ptr)
									add_enm_crt(vic_ptr->name, crt_ptr);
								broadcast_rom(-1,crt_ptr->rom_num,"%M attacks %s.",crt_ptr,vic_ptr);
								attack_crt(crt_ptr,vic_ptr);
								if(crt_ptr->first_tlk->target)
									free(crt_ptr->first_tlk->target);
								crt_ptr->first_tlk->target = 0;
							}
							break;
						case 'a': /* attack player target */
							break;
						case 'c': /* cast a spell on target */
							break;
						case 'F': /* force target to do somthing */
							break;
					    case '|': /* set a flag on target */
							break;
					    case '&': /* remove flag on target */
					        break;
						case 'P': /* perform social */
							break;
					    case 'O': /* open door */
							break;
					    case 'C': /* close door */
							break;
						case 'D': /* delay action */
							break;
					    case 'G': /* go into a keyword exit */
							break;
					    case '0': /* go n */
					    case '1': /* go ne */
						case '2': /* go e */
						case '3': /* go se */
					    case '4': /* go s */
						case '5': /* go sw */
					    case '6': /* go w */
						case '7': /* go nw */
					    case '8': /* go up */
					    case '9': /* go down */
							xdir = act->do_act - '0';
							strcpy(cmnd.str[0],xits[xdir]);
							move(crt_ptr,&cmnd);
							break;			
					    }
					}
					if(act->goto_cmd) /* unconditional jump */
					{
						act->success = 1;
						cp->crt->first_tlk->on_cmd = act->goto_cmd;
					}
					else
						cp->crt->first_tlk->on_cmd = on_cmd;
				}
			}
		}
    }  
}

/*********************************************************************/
/*			is_crt_active				     */
/*********************************************************************/
/*	This function returns 1 if the parameter passed is in the    */
/*	active list.						     */

int is_crt_active(crt_ptr)
creature    *crt_ptr;
{
	ctag	*cp=0;
	int	  n=0;

	if(!(cp = first_active)) 
		return(0);

	while (cp) {
		if(cp->crt == crt_ptr){
			n = 1;	
			break;
		}
	cp = cp->next_tag;
	}
	return(n);
}		

void update_dust_output(t)
long t;
{
        last_dust_output=0;
        broadcast("Ominous thunder rumbles in the distance.");
}

void crash(sig)
int     sig;
{
	char path[80];

	broadcast("### Quick shutdown now!");
	output_buf();
	loge("--- !CRASH! Game closed ---\n");
	/* resave_all_rom(1); */
	save_all_ply();

#ifdef DMALLOC 
        dmalloc_log_stats();
#endif /* DMALLOC */
        
	if(RECORD_ALL) {
        sprintf(path,"%s/%s",LOGPATH,"all_cmd");
        unlink(path);
	}
        
#ifndef WIN32
        kill(getpid(), 9);
#endif
        exit(0);
}