/
help/
log/
player/
post/
rooms/
util/
util/italk/
util/list/
util/msg/
util/muddle/
/*
 * PLAYER.C:
 *
 *	Player routines.
 *
 *	Copyright (C) 1991, 1992, 1993 Brett J. Vickers
 *
 */

#include "mstruct.h"
#include "mextern.h"

/**********************************************************************/
/*				init_ply			      */
/**********************************************************************/

/* This function initializes a player's stats and loads up the room he */
/* should be in.  This should only be called when the player first     */
/* logs on. 							       */

void init_ply(ply_ptr)
creature	*ply_ptr;
{
	char	file[80], str[50];
	room	*rom_ptr;
	object	*obj_ptr;
	otag	*op, *otemp;
	long	t, tdiff;
	int	n, wf, i;

	F_CLR(ply_ptr, PSPYON);
	F_CLR(ply_ptr, PREADI);

	if(ply_ptr->class == DM && strcmp(ply_ptr->name, DMNAME) &&
	   strcmp(ply_ptr->name, DMNAME2) && strcmp(ply_ptr->name, DMNAME3) &&
	   strcmp(ply_ptr->name, DMNAME4) && strcmp(ply_ptr->name, DMNAME5) &&
	   strcmp(ply_ptr->name, DMNAME6) && strcmp(ply_ptr->name, DMNAME7))
		ply_ptr->class = CARETAKER;

	if(!strcmp(ply_ptr->name, DMNAME) || !strcmp(ply_ptr->name, DMNAME2) ||
	  !strcmp(ply_ptr->name, DMNAME3) || !strcmp(ply_ptr->name, DMNAME4) ||
	  !strcmp(ply_ptr->name, DMNAME5) || !strcmp(ply_ptr->name, DMNAME6) ||
	  !strcmp(ply_ptr->name, DMNAME7))
		ply_ptr->class = DM;

	if(ply_ptr->class < CARETAKER) {
		ply_ptr->daily[DL_BROAD].max = 5 + ply_ptr->level/2;
		ply_ptr->daily[DL_ENCHA].max = 3;
		ply_ptr->daily[DL_FHEAL].max = MAX(3, 3 + (ply_ptr->level-5)/3);
		ply_ptr->daily[DL_TRACK].max = MAX(3, 3 + (ply_ptr->level-5)/4);
		ply_ptr->daily[DL_DEFEC].max = 1;
	}

	F_SET(ply_ptr, PNOSUM);
	if(ply_ptr->class < CARETAKER)
		F_SET(ply_ptr, PPROMP);

	if(!F_ISSET(ply_ptr, PDMINV))
		broadcast("### %s the %s %s just logged in.", ply_ptr->name,
			race_adj[ply_ptr->race], title_ply(ply_ptr));

	t = time(0);
	strcpy(str, (char *)ctime(&t));
	str[strlen(str)-1] = 0;
		logf("%s: %s (%s) logged on.\n", str, ply_ptr->name, 
			Ply[ply_ptr->fd].io->address);

	ply_ptr->lasttime[LT_PSAVE].ltime = t;
	ply_ptr->lasttime[LT_PSAVE].interval = SAVEINTERVAL;

	if(load_rom(ply_ptr->rom_num, &rom_ptr) < 0)
		load_rom(1, &rom_ptr);

	n = count_vis_ply(rom_ptr);
	if((F_ISSET(rom_ptr, RONEPL) && n > 0) ||
	  (F_ISSET(rom_ptr, RTWOPL) && n > 1) ||
	  (F_ISSET(rom_ptr, RTHREE) && n > 2) ||
      (F_ISSET(rom_ptr, RNOLOG)))
		load_rom(1, &rom_ptr);

	add_ply_rom(ply_ptr, rom_ptr);

	tdiff = t -  ply_ptr->lasttime[LT_HOURS].ltime;
	for(i=0; i<45; i++) {
		ply_ptr->lasttime[i].ltime += tdiff;
		ply_ptr->lasttime[i].ltime =
			MIN(t, ply_ptr->lasttime[i].ltime);
	}

	op = ply_ptr->first_obj;
	while(op) {
		otemp = op->next_tag;
		obj_ptr = op->obj;
		if(F_ISSET(obj_ptr, OWEARS)) {
			wf = obj_ptr->wearflag;
			if(wf == FINGER) {
				for(i=FINGER1-1; i<=FINGER8-1; i++)
					if(!ply_ptr->ready[i]) {
						ply_ptr->ready[i] = obj_ptr;
						del_obj_crt(obj_ptr, ply_ptr);
						break;
					}
			}
			else if(wf == NECK) {
				for(i=NECK1-1; i<=NECK2-1; i++)
					if(!ply_ptr->ready[i]) {
						ply_ptr->ready[i] = obj_ptr;
						del_obj_crt(obj_ptr, ply_ptr);
						break;
					}
			}
			else {
				if(!ply_ptr->ready[wf-1]) {
					ply_ptr->ready[wf-1] = obj_ptr;
					del_obj_crt(obj_ptr, ply_ptr);
				}
			}
		}
		op = otemp;
	}

	compute_ac(ply_ptr);
	compute_thaco(ply_ptr);
	update_ply(ply_ptr);

	sprintf(file, "%s/dialin", DOCPATH);
	if (!strcmp(Ply[ply_ptr->fd].io->address, "128.200.142.2"))
		view_file(ply_ptr->fd, 1, file);

	if (ply_ptr->class < DM) {
	sprintf(file, "%s/news", LOGPATH);
	view_file(ply_ptr->fd, 1, file);
	}
	sprintf(str, "%s/%s", POSTPATH, ply_ptr->name);
	if(file_exists(str))
		print(ply_ptr->fd, "\n*** You have mail in the post office.\n");

}

/**********************************************************************/
/*				uninit_ply			      */
/**********************************************************************/

/* This function de-initializes a player who has left the game.  This  */
/* is called whenever a player quits or disconnects, right before save */
/* is called.							       */

void uninit_ply(ply_ptr)
creature	*ply_ptr;
{
	creature	*crt_ptr;
	ctag		*cp, *prev;
	int		i;

	if(ply_ptr->parent_rom)
		del_ply_rom(ply_ptr, ply_ptr->parent_rom);

	cp = ply_ptr->first_fol;
	while(cp) {
		cp->crt->following = 0;
		print(cp->crt->fd, "You stop following %s.\n", ply_ptr->name);
		prev = cp->next_tag;
		free(cp);
		cp = prev;
	}
	ply_ptr->first_fol = 0;
		
	if(ply_ptr->following) {
		crt_ptr = ply_ptr->following;
		cp = crt_ptr->first_fol;
		if(cp->crt == ply_ptr) {
			crt_ptr->first_fol = cp->next_tag;
			free(cp);
		}
		else while(cp) {
			if(cp->crt == ply_ptr) {
				prev->next_tag = cp->next_tag;
				free(cp);
				break;
			}
			prev = cp;
			cp = cp->next_tag;
		}
		ply_ptr->following = 0;

		if(!F_ISSET(ply_ptr, PDMINV))
			print(crt_ptr->fd, "%s stops following you.\n", 
			      ply_ptr->name);
	}

	for(i=0; i<MAXWEAR; i++)
		if(ply_ptr->ready[i]) {
			add_obj_crt(ply_ptr->ready[i], ply_ptr);
			ply_ptr->ready[i] = 0;
		}

	update_ply(ply_ptr);
	if(!F_ISSET(ply_ptr, PDMINV))
		broadcast("### %s just logged off.", ply_ptr->name);
}

/**********************************************************************/
/*				update_ply			      */
/**********************************************************************/

/* This function checks up on all a player's time-expiring flags to see */
/* if some of them have expired.  If so, flags are set accordingly.     */

void update_ply(ply_ptr)
creature	*ply_ptr;
{
	long 	t;
	int	item;
	char 	ill, prot = 1; 	/*character is prot in a pharm room */

	t = time(0);
	ply_ptr->lasttime[LT_HOURS].interval +=
		(t - ply_ptr->lasttime[LT_HOURS].ltime);
	ply_ptr->lasttime[LT_HOURS].ltime = t;

	if(F_ISSET(ply_ptr, PHASTE)) {
		if(t > LT(ply_ptr, LT_HASTE)) {
			ANSI(ply_ptr->fd, GREEN);
			print(ply_ptr->fd, "You feel slower.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PHASTE);
			ply_ptr->dexterity -= 5;
		}
	}
	if(F_ISSET(ply_ptr, PPRAYD)) {
		if(t > LT(ply_ptr, LT_PRAYD)) {
			ANSI(ply_ptr->fd, YELLOW);
			print(ply_ptr->fd, "You feel less pious.\n");
			F_CLR(ply_ptr, PPRAYD);
			ANSI(ply_ptr->fd, WHITE);
			ply_ptr->piety -= 5;
		}
	}
	if(F_ISSET(ply_ptr, PINVIS)) {
		if(t > LT(ply_ptr, LT_INVIS) && ply_ptr->class < DM) {
			ANSI(ply_ptr->fd, MAGENTA);
			print(ply_ptr->fd, "Your invisibility wears off.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PINVIS);
		}
	}
	if(F_ISSET(ply_ptr, PDINVI)) {
		if(t > LT(ply_ptr, LT_DINVI)  && ply_ptr->class < DM) {
			ANSI(ply_ptr->fd, MAGENTA);
			print(ply_ptr->fd, "Your detect-invis wears off.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PDINVI);
		}
	}
	if(F_ISSET(ply_ptr, PDMAGI)) {
		if(t > LT(ply_ptr, LT_DMAGI) && ply_ptr->class < DM) {
			ANSI(ply_ptr->fd, MAGENTA);
			print(ply_ptr->fd, "Your detect-magic wears off.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PDMAGI);
		}
	}
	if(F_ISSET(ply_ptr, PHIDDN)) {
		if(t-ply_ptr->lasttime[LT_HIDES].ltime > 300L)
			F_CLR(ply_ptr, PHIDDN);
	}
	if(F_ISSET(ply_ptr, PPROTE)) {
		if(t > LT(ply_ptr, LT_PROTE)) {
			ANSI(ply_ptr->fd, YELLOW);
			print(ply_ptr->fd, "You feel less protected.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PPROTE);
			compute_ac(ply_ptr);
		}
	}
	if(F_ISSET(ply_ptr, PLEVIT)) {
		if(t > LT(ply_ptr, LT_LEVIT) && ply_ptr->class < DM) {
			ANSI(ply_ptr->fd, MAGENTA);
			print(ply_ptr->fd, "Your feet hit the ground.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PLEVIT);
		}
	}
	if(F_ISSET(ply_ptr, PBLESS)) {
		if(t > LT(ply_ptr, LT_BLESS)) {
			ANSI(ply_ptr->fd, YELLOW);
			print(ply_ptr->fd, "You feel less holy.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PBLESS);
			compute_thaco(ply_ptr);
		}
	}

	if(F_ISSET(ply_ptr, PRFIRE)) {
		if(t > LT(ply_ptr, LT_RFIRE)) {
			ANSI(ply_ptr->fd, YELLOW);
			print(ply_ptr->fd, "Your skin returns to normal.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PRFIRE);
		}
	}


	if(F_ISSET(ply_ptr, PRCOLD)) {
		if(t > LT(ply_ptr, LT_RCOLD)) {
			ANSI(ply_ptr->fd, BOLD);
			ANSI(ply_ptr->fd, YELLOW);
			print(ply_ptr->fd, "A cold chill runs through your body.\n");
			ANSI(ply_ptr->fd, NORMAL);
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PRCOLD);
		}
	}


	if(F_ISSET(ply_ptr, PBRWAT)) {
		if(t > LT(ply_ptr, LT_BRWAT)) {
			ANSI(ply_ptr->fd, BOLD);
			ANSI(ply_ptr->fd, BLUE);
			print(ply_ptr->fd, "Your lungs contract in size.\n");
			ANSI(ply_ptr->fd, WHITE);
			ANSI(ply_ptr->fd, NORMAL);
			F_CLR(ply_ptr, PBRWAT);
		}
	}

	if(F_ISSET(ply_ptr, PSSHLD)) {
		if(t > LT(ply_ptr, LT_SSHLD)) {
			ANSI(ply_ptr->fd, BOLD);
			ANSI(ply_ptr->fd, GREEN);
			print(ply_ptr->fd, "Your skin softens.\n");
			ANSI(ply_ptr->fd, WHITE);
			ANSI(ply_ptr->fd, NORMAL);
			F_CLR(ply_ptr, PSSHLD);
		}
	}
	if(F_ISSET(ply_ptr, PFLYSP)) {
		if(t > LT(ply_ptr, LT_FLYSP)  && ply_ptr->class < DM) {
			ANSI(ply_ptr->fd, YELLOW);
			print(ply_ptr->fd, "You can no longer fly.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PFLYSP);
		}
	}
	if(F_ISSET(ply_ptr, PRMAGI)) {
		if(t > LT(ply_ptr, LT_RMAGI)) {
			ANSI(ply_ptr->fd, BOLD);
			ANSI(ply_ptr->fd, MAGENTA);
			print(ply_ptr->fd,
				"Your magical shield dissipates.\n");
			ANSI(ply_ptr->fd, WHITE);
			ANSI(ply_ptr->fd, NORMAL);
			F_CLR(ply_ptr, PRMAGI);
		}
	}
	if(F_ISSET(ply_ptr, PSILNC)) {
		if(t > LT(ply_ptr, LT_SILNC)) {
			ANSI(ply_ptr->fd, GREEN);
			print(ply_ptr->fd,
				"You voice returns!\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PSILNC);
		}
	}
	if(F_ISSET(ply_ptr, PFEARS)) {
		if(t > LT(ply_ptr, LT_FEARS)) {
			ANSI(ply_ptr->fd, YELLOW);
			print(ply_ptr->fd,
				"You feel your courage return.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PFEARS);
		}
	}
	if(F_ISSET(ply_ptr, PKNOWA)) {
		if(t > LT(ply_ptr, LT_KNOWA) && ply_ptr->class < DM) {
			ANSI(ply_ptr->fd, CYAN);
			print(ply_ptr->fd,
				"Your perception is diminshed.\n");
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PKNOWA);
		}
	}
	if(F_ISSET(ply_ptr, PLIGHT)) {
		if(t > LT(ply_ptr, LT_LIGHT)  && ply_ptr->class < DM) {
			ANSI(ply_ptr->fd, YELLOW);
			print(ply_ptr->fd, "Your magical light fades.\n");
			broadcast_rom(ply_ptr->fd, ply_ptr->rom_num,
				      "%M's magical light fades.", ply_ptr);
			ANSI(ply_ptr->fd, WHITE);
			F_CLR(ply_ptr, PLIGHT);
		}
	}
	if(t > LT(ply_ptr, LT_CHRMD) && F_ISSET(ply_ptr, PCHARM)) {
                        ANSI(ply_ptr->fd, YELLOW);
                        print(ply_ptr->fd, "Your demeanor returns to normal.\n");
                        F_CLR(ply_ptr, PCHARM);
			ANSI(ply_ptr->fd, WHITE);
                }

/* check if player is suffering from any  aliment */
if(F_ISSET(ply_ptr, PPOISN) || F_ISSET(ply_ptr, PDISEA))
	ill = 1;
else
	ill =0;

/* handle normal healing for non posioned or harm room */
if(ply_ptr->parent_rom && (t > LT(ply_ptr, LT_HEALS)))
	if(!F_ISSET(ply_ptr->parent_rom, RPHARM) && (!ill)) {
		ply_ptr->hpcur += MAX(1, 3 + bonus[ply_ptr->constitution] +
				(ply_ptr->class == BARBARIAN ? 2:0));
		ply_ptr->mpcur += MAX(1, 2+(ply_ptr->intelligence > 17 ? 1:0)+
				(ply_ptr->class == MAGE ? 2:0));
		ply_ptr->lasttime[LT_HEALS].ltime = t;
		ply_ptr->lasttime[LT_HEALS].interval = 45 - 
						       5*bonus[ply_ptr->piety];
/* handle quick healing */
			if(F_ISSET(ply_ptr->parent_rom, RHEALR)) {
				ply_ptr->hpcur += 3;
				ply_ptr->mpcur += 2;
				ply_ptr->lasttime[LT_HEALS].interval /= 2;
			}

		ply_ptr->hpcur = MIN(ply_ptr->hpcur, ply_ptr->hpmax);
		ply_ptr->mpcur = MIN(ply_ptr->mpcur, ply_ptr->mpmax);
	}
/* handle poison  */

	else if(!F_ISSET(ply_ptr->parent_rom, RPHARM) && ill) {
	   if(F_ISSET(ply_ptr, PPOISN)){
		ANSI(ply_ptr->fd, BLINK);
		ANSI(ply_ptr->fd, RED);
		print(ply_ptr->fd, "Poison courses through your veins.\n");
		ply_ptr->hpcur -= MAX(1,mrand(1,4)-bonus[ply_ptr->constitution]);
		ply_ptr->lasttime[LT_HEALS].ltime = t;
		ply_ptr->lasttime[LT_HEALS].interval = 65 + 
				    5*bonus[ply_ptr->constitution];
		ANSI(ply_ptr->fd, WHITE);
		ANSI(ply_ptr->fd, NORMAL);
		if(ply_ptr->hpcur < 1)
			die(ply_ptr, ply_ptr);
	   }
	   if (F_ISSET(ply_ptr, PDISEA)){
		ANSI(ply_ptr->fd, BLINK);
		ANSI(ply_ptr->fd, RED);
		print(ply_ptr->fd, "Fever grips your mind.\n");
        	ply_ptr->lasttime[LT_ATTCK].ltime = time(0);
		ANSI(ply_ptr->fd, BLUE);
		print(ply_ptr->fd, "You feel nauseous.\n");
        	ply_ptr->lasttime[LT_ATTCK].interval= dice(1,6,3);
		ply_ptr->hpcur -= MAX(1,mrand(1,6)-bonus[ply_ptr->constitution]);
		ply_ptr->lasttime[LT_HEALS].ltime = t;
		ply_ptr->lasttime[LT_HEALS].interval = 65 + 
				    5*bonus[ply_ptr->constitution];
		ANSI(ply_ptr->fd, WHITE);
		ANSI(ply_ptr->fd, NORMAL);
		if(ply_ptr->hpcur < 1)
			die(ply_ptr, ply_ptr);
	   }
	}


/* handle player harm rooms */
else {

if (F_ISSET(ply_ptr->parent_rom, RPPOIS))
{
  ANSI(ply_ptr->fd, BLINK);
  ANSI(ply_ptr->fd, GREEN);
  print(ply_ptr->fd, "The toxic air poisoned you.\n");
  ANSI(ply_ptr->fd, WHITE);
  ANSI(ply_ptr->fd, NORMAL);
  F_SET(ply_ptr, PPOISN);    
}

if (F_ISSET(ply_ptr->parent_rom, RPBEFU)) 
{
	print(ply_ptr->fd, "The room starts to spin around you.\nYou feel confused.\n");
        ply_ptr->lasttime[LT_ATTCK].ltime = time(0);
        ply_ptr->lasttime[LT_ATTCK].interval= MAX(dice(2,6,0),6);
}

if (F_ISSET(ply_ptr, PPOISN)){
	ANSI(ply_ptr->fd, BLINK);
	ANSI(ply_ptr->fd, RED);
  	print(ply_ptr->fd, "Poison courses through your veins.\n");
	ANSI(ply_ptr->fd, NORMAL);
	ANSI(ply_ptr->fd, WHITE);
	ply_ptr->hpcur -= MAX(1,mrand(1,4)-bonus[ply_ptr->constitution]);
  	if(ply_ptr->hpcur < 1) die(ply_ptr, ply_ptr);
}
if (F_ISSET(ply_ptr, PDISEA)){
			ANSI(ply_ptr->fd, BLINK);
			ANSI(ply_ptr->fd, RED);
        print(ply_ptr->fd, "Fever grips your mind.\n");
        ply_ptr->lasttime[LT_ATTCK].ltime = time(0);
			ANSI(ply_ptr->fd, BLUE);
        print(ply_ptr->fd, "You feel nauseous.\n");
        ply_ptr->lasttime[LT_ATTCK].interval= dice(1,6,3);
        ply_ptr->hpcur -= MAX(1,mrand(1,6)-bonus[ply_ptr->constitution]);
        ply_ptr->lasttime[LT_HEALS].ltime = t;
        ply_ptr->lasttime[LT_HEALS].interval = 65 + 
                            5*bonus[ply_ptr->constitution];
			ANSI(ply_ptr->fd, NORMAL);
			ANSI(ply_ptr->fd, WHITE);
        if(ply_ptr->hpcur < 1)
                die(ply_ptr, ply_ptr);
}                                   

if (F_ISSET(ply_ptr->parent_rom,RPMPDR))
 	ply_ptr->mpcur -= MIN(ply_ptr->mpcur,3); 
else if (!ill) {
  ply_ptr->mpcur += MAX(1, 2+(ply_ptr->intelligence > 17 ? 1:0)+
                                (ply_ptr->class == MAGE ? 2:0));
		ply_ptr->mpcur = MIN(ply_ptr->mpcur, ply_ptr->mpmax);
}
    
if (F_ISSET(ply_ptr->parent_rom, RFIRER) && !F_ISSET(ply_ptr,PRFIRE)) {
    	print(ply_ptr->fd, "The searing heat burns your flesh.\n");
	prot = 0;
}
else if (F_ISSET(ply_ptr->parent_rom, RWATER) && !F_ISSET(ply_ptr,PBRWAT)) {
	print(ply_ptr->fd, "Water fills your lungs.\n");
        prot = 0;
}
else if (F_ISSET(ply_ptr->parent_rom, REARTH) && !F_ISSET(ply_ptr,PSSHLD)) {
	print(ply_ptr->fd, "The earth swells up around you and smothers you.\n");
        prot = 0;
}
else if (F_ISSET(ply_ptr->parent_rom, RWINDR) && !F_ISSET(ply_ptr,PRCOLD)) {
			ANSI(ply_ptr->fd, BLUE);
	print(ply_ptr->fd, "The freezing air chills you to the bone.\n");
			ANSI(ply_ptr->fd, WHITE);
	prot = 0;
}
else  if(!F_ISSET(ply_ptr->parent_rom, RWINDR) &&
	 !F_ISSET(ply_ptr->parent_rom, REARTH) &&
	 !F_ISSET(ply_ptr->parent_rom, RFIRER) &&
	 !F_ISSET(ply_ptr->parent_rom, RWATER) &&
	 !F_ISSET(ply_ptr->parent_rom, RPPOIS) &&
	 !F_ISSET(ply_ptr->parent_rom, RPBEFU) &&
	 !F_ISSET(ply_ptr->parent_rom, RPMPDR)) {
			ANSI(ply_ptr->fd, BOLD);
			ANSI(ply_ptr->fd, MAGENTA);
	print(ply_ptr->fd, "An invisible force saps your life force.\n");
			ANSI(ply_ptr->fd, NORMAL);
			ANSI(ply_ptr->fd, WHITE);
	prot = 0;
}
	if (!prot) {
		ply_ptr->hpcur -= 8 - MIN(bonus[ply_ptr->constitution],2);
        	if(ply_ptr->hpcur < 1) die(ply_ptr, ply_ptr);      
	}
	else if (!ill)
	{
		ply_ptr->hpcur += MAX(1, 3 + bonus[ply_ptr->constitution] +
				(ply_ptr->class == BARBARIAN ? 2:0));
		ply_ptr->hpcur = MIN(ply_ptr->hpcur, ply_ptr->hpmax);
	}

ply_ptr->lasttime[LT_HEALS].ltime = t;
ply_ptr->lasttime[LT_HEALS].interval = 45 +  5*bonus[ply_ptr->piety];

}
/*******************************/


	if(t > LT(ply_ptr, LT_PSAVE)) {
		ply_ptr->lasttime[LT_PSAVE].ltime = t;
		savegame(ply_ptr, 0);
	}

	item = has_light(ply_ptr);
	if(item && item != MAXWEAR+1) {
		if(ply_ptr->ready[item-1]->type == LIGHTSOURCE)
			if(--(ply_ptr->ready[item-1]->shotscur) < 1) {
				print(ply_ptr->fd, "Your %s died out.\n",
				      ply_ptr->ready[item-1]->name);
				broadcast_rom(ply_ptr->fd, ply_ptr->rom_num,
					      "%M's %s died out.", 
					      ply_ptr,
					      ply_ptr->ready[item-1]->name);
			}
	}

}

/**********************************************************************/
/*				up_level			      */
/**********************************************************************/

/* This function should be called whenever a player goes up a level.  */
/* It raises her hit points and magic points appropriately, and if    */
/* it is initializing a new character, it sets up the character.      */

void up_level(ply_ptr)
creature	*ply_ptr;
{
	int	index;

	ply_ptr->level++;
	ply_ptr->hpmax += class_stats[ply_ptr->class].hp;
	ply_ptr->mpmax += class_stats[ply_ptr->class].mp;
	if(ply_ptr->level == 1) {
		ply_ptr->hpmax = class_stats[ply_ptr->class].hpstart;
		ply_ptr->mpmax = class_stats[ply_ptr->class].mpstart;
		ply_ptr->hpcur = ply_ptr->hpmax;
		ply_ptr->mpcur = ply_ptr->mpmax;
		ply_ptr->ndice = class_stats[ply_ptr->class].ndice;
		ply_ptr->sdice = class_stats[ply_ptr->class].sdice;
		ply_ptr->pdice = class_stats[ply_ptr->class].pdice;
	}
	else {
		index = (ply_ptr->level-2) % 10;
		switch(level_cycle[ply_ptr->class][index]) {
		case STR: ply_ptr->strength++; break;
		case DEX: ply_ptr->dexterity++; break;
		case CON: ply_ptr->constitution++; break;
		case INT: ply_ptr->intelligence++; break;
		case PTY: ply_ptr->piety++; break;
		}
	}

}

/**********************************************************************/
/*				down_level			      */
/**********************************************************************/

/* This function is called when a player loses a level due to dying or */
/* for some other reason.  The appropriate stats are downgraded.       */

void down_level(ply_ptr)
creature	*ply_ptr;
{
	int	index;

	ply_ptr->level--;
	ply_ptr->hpmax -= class_stats[ply_ptr->class].hp;
	ply_ptr->mpmax -= class_stats[ply_ptr->class].mp;
	ply_ptr->hpcur = ply_ptr->hpmax;
	ply_ptr->mpcur = ply_ptr->mpmax;
	index = (ply_ptr->level-1) % 10;
	switch(level_cycle[ply_ptr->class][index]) {
	case STR: ply_ptr->strength--; break;
	case DEX: ply_ptr->dexterity--; break;
	case CON: ply_ptr->constitution--; break;
	case INT: ply_ptr->intelligence--; break;
	case PTY: ply_ptr->piety--; break;
	}

}

/**********************************************************************/
/*				add_obj_crt			      */
/**********************************************************************/

/* This function adds the object pointer to by the first parameter to */
/* the inventory of the player pointed to by the second parameter.    */

void add_obj_crt(obj_ptr, ply_ptr)
object		*obj_ptr;
creature	*ply_ptr;
{
	otag	*op, *temp, *prev;

	obj_ptr->parent_crt = ply_ptr;
	obj_ptr->parent_obj = 0;
	obj_ptr->parent_rom = 0;

	op = (otag *)malloc(sizeof(otag));
	if(!op)
		merror("add_obj_crt", FATAL);
	op->obj = obj_ptr;
	op->next_tag = 0;

	if(!ply_ptr->first_obj) {
		ply_ptr->first_obj = op;
		return;
	}

	temp = ply_ptr->first_obj;
	if(strcmp(temp->obj->name, obj_ptr->name) > 0 ||
	   (!strcmp(temp->obj->name, obj_ptr->name) &&
	   temp->obj->adjustment > obj_ptr->adjustment)) {
		op->next_tag = temp;
		ply_ptr->first_obj = op;
		return;
	}

	while(temp) {
		if(strcmp(temp->obj->name, obj_ptr->name) > 0 ||
		   (!strcmp(temp->obj->name, obj_ptr->name) &&
		   temp->obj->adjustment > obj_ptr->adjustment))
			break;
		prev = temp;
		temp = temp->next_tag;
	}
	op->next_tag = prev->next_tag;
	prev->next_tag = op;

}

/**********************************************************************/
/*				del_obj_crt			      */
/**********************************************************************/

/* This function removes the object pointer to by the first parameter */
/* from the player pointed to by the second.			      */

void del_obj_crt(obj_ptr, ply_ptr)
object		*obj_ptr;
creature	*ply_ptr;
{
	otag 	*temp, *prev;

	if(!obj_ptr->parent_crt) {
		ply_ptr->ready[obj_ptr->wearflag-1] = 0;
		return;
	}

	obj_ptr->parent_crt = 0;
	if(ply_ptr->first_obj->obj == obj_ptr) {
		temp = ply_ptr->first_obj->next_tag;
		free(ply_ptr->first_obj);
		ply_ptr->first_obj = temp;
		return;
	}

	prev = ply_ptr->first_obj;
	temp = prev->next_tag;
	while(temp) {
		if(temp->obj == obj_ptr) {
			prev->next_tag = temp->next_tag;
			free(temp);
			return;
		}
		prev = temp;
		temp = temp->next_tag;
	}
}

/**********************************************************************/
/*				title_ply			      */
/**********************************************************************/

/* This function returns a string with the player's character title in */
/* it.  The title is determined by looking at the player's class and   */
/* level.							       */

char *title_ply(ply_ptr)
creature	*ply_ptr;
{
	int	titlnum;

	titlnum = (ply_ptr->level-1)/3;
	if(titlnum > 7)
		titlnum = 7;
	return(lev_title[ply_ptr->class][titlnum]);
}

/**********************************************************************/
/*				compute_ac			      */
/**********************************************************************/

/* This function computes a player's (or a monster's) armor class by  */
/* examining its stats and the items it is holding.		      */

void compute_ac(ply_ptr)
creature	*ply_ptr;
{
	int	ac, i;

	ac = 100;

	ac -= 5*bonus[ply_ptr->dexterity];

	for(i=0; i<MAXWEAR; i++)
		if(ply_ptr->ready[i])
			ac -= ply_ptr->ready[i]->armor;

	if(F_ISSET(ply_ptr, PPROTE))
		ac -= 10;

	ac = MAX(-127,MIN(127,ac));

	ply_ptr->armor = ac;
}

/**********************************************************************/
/*				compute_thaco			      */
/**********************************************************************/

/* This function computes a player's THAC0 by looking at his class, */
/* level, weapon adjustment and strength bonuses.		    */

void compute_thaco(ply_ptr)
creature	*ply_ptr;
{
	int	thaco, n;

	n = ply_ptr->level > 20 ? 19:ply_ptr->level-1;

	thaco = thaco_list[ply_ptr->class][n];
	if(ply_ptr->ready[WIELD-1])
		thaco -= ply_ptr->ready[WIELD-1]->adjustment;
	thaco -= mod_profic(ply_ptr);
 	thaco -= bonus[ply_ptr->strength];

	if(F_ISSET(ply_ptr, PBLESS))
		thaco -= 1;

	ply_ptr->thaco = MAX(0, thaco);

}

/**********************************************************************/
/*				mod_profic			      */
/**********************************************************************/

/* This function returns the player's currently-used proficiency div 20 */

int mod_profic(ply_ptr)
creature	*ply_ptr;
{
	int	amt;
	switch(ply_ptr->class) {
		case FIGHTER:
		case BARBARIAN:
			amt = 20;
			break;
		case RANGER:
		case PALADIN:
			amt = 25;
			break;
		case THIEF:
		case ASSASSIN:
		case CLERIC:
			amt = 30;
			break;
		default:
			amt = 40;
			break;
	}

	if(ply_ptr->ready[WIELD-1] && 
		ply_ptr->ready[WIELD-1]->type <= MISSILE)
		return(profic(ply_ptr, ply_ptr->ready[WIELD-1]->type)/amt);
	else
		return(profic(ply_ptr, BLUNT)/amt);
}

/**********************************************************************/
/*				weight_ply			      */
/**********************************************************************/

/* This function calculates the total weight that a player (or monster) */
/* is carrying in his inventory.					*/

int weight_ply(ply_ptr)
creature	*ply_ptr;
{
	int	i, n = 0;
	otag	*op;

	op = ply_ptr->first_obj;
	while(op) {
		if(!F_ISSET(op->obj, OWTLES))
			n += weight_obj(op->obj);
		op = op->next_tag;
	}

	for(i=0; i<MAXWEAR; i++)
		if(ply_ptr->ready[i])
			n += weight_obj(ply_ptr->ready[i]);

	return(n);

}

/**********************************************************************/
/*				max_weight			      */
/**********************************************************************/

/* This function returns the maximum weight a player can be allowed to */
/* hold in his inventory.					       */

int max_weight(ply_ptr)
creature	*ply_ptr;
{
	int	n;

	n = 20 + ply_ptr->strength*10;
	if(ply_ptr->class == BARBARIAN)
		n += ply_ptr->level*10;

	return(n);
}
	
/**********************************************************************/
/*				profic				      */
/**********************************************************************/

/* This function determines a weapons proficiency percentage.  The first */
/* parameter contains a pointer to the player whose percentage is being  */
/* determined.  The second is an integer containing the proficiency      */
/* number.								 */

int profic(ply_ptr, index)
creature	*ply_ptr;
int		index;
{
	long	prof_array[12];
	int	i, n, prof;

	switch (ply_ptr->class){
	case FIGHTER:
		prof_array[0] = 0L;		prof_array[1] = 768L;
		prof_array[2] = 1024L;		prof_array[3] = 1440L;
		prof_array[4] = 1910L;		prof_array[5] = 16000L;
		prof_array[6] = 31214L;		prof_array[7] = 167000L;
		prof_array[8] = 268488L;	prof_array[9] = 695000L;
		prof_array[10] = 934808L;
		prof_array[11] = 500000000L;
		break;

	case BARBARIAN: 
	case PALADIN: 
	case RANGER:
	case DM:
	case CARETAKER:
		prof_array[0] = 0L;		prof_array[1] = 768L;
		prof_array[2] = 1024L;		prof_array[3] = 1800L;
		prof_array[4] = 2388L;		prof_array[5] = 20000L;
		prof_array[6] = 37768L;		prof_array[7] = 205000L;
		prof_array[8] = 325610L;	prof_array[9] = 895000L;
		prof_array[10] = 1549760L;
		prof_array[11] = 500000000L;
		break;

	case CLERIC:
	case THIEF:
	case ASSASSIN:
		prof_array[0] = 0L;		prof_array[1] = 768L;
		prof_array[2] = 1024L;		prof_array[3] = 1800L;
		prof_array[4] = 2388L;		prof_array[5] = 20000L;
		prof_array[6] = 42768L;		prof_array[7] = 220000L;
		prof_array[8] = 355610L;	prof_array[9] = 950000L;
		prof_array[10] = 1949760L;
		prof_array[11] = 500000000L;
		break;

	case MAGE:
		prof_array[0] = 0L;		prof_array[1] = 768L;
		prof_array[2] = 1024L;		prof_array[3] = 1800L;
		prof_array[4] = 2388L;		prof_array[5] = 25000L;
		prof_array[6] = 50768L;		prof_array[7] = 215000L;
		prof_array[8] = 385610L;	prof_array[9] = 1005000L;
		prof_array[10] = 2344760L;
		prof_array[11] = 500000000L;
		break;
	}
	
	n = ply_ptr->proficiency[index];
	for(i=0; i<11; i++)
		if(n < prof_array[i+1]) {
			prof = 10*i;
			break;
		}

	prof += ((n - prof_array[i])*10) / (prof_array[i+1] - prof_array[i]);

	return(prof);
}

/************************************************************************/
/*				mprofic					*/
/************************************************************************/

/* This function returns the magical realm proficiency as a percentage	*/

int mprofic(ply_ptr, index)
creature	*ply_ptr;
int		index;
{
	long	prof_array[12];
	int	i, n, prof;

        switch(ply_ptr->class){
        case MAGE:
                prof_array[0] = 0L;       prof_array[1] = 1024L;
                prof_array[2] = 2048L;    prof_array[3] = 4096L;
                prof_array[4] = 8192L;    prof_array[5] = 16384L;
                prof_array[6] = 35768L;   prof_array[7] = 85536L;
                prof_array[8] = 140000L;  prof_array[9] = 459410L;
                prof_array[10] = 2073306L; prof_array[11] = 500000000L;
                break;
        case CLERIC:
                prof_array[0] = 0L;       prof_array[1] = 1024L;
                prof_array[2] = 4092L;    prof_array[3] = 8192L;
                prof_array[4] = 16384L;   prof_array[5] = 32768L;
                prof_array[6] = 70536L;   prof_array[7] = 119000L;
                prof_array[8] = 226410L;  prof_array[9] = 709410L;
                prof_array[10] = 2973307L; prof_array[11] = 500000000L;
                break;
        case PALADIN:
        case RANGER:    
                prof_array[0] = 0L;       prof_array[1] = 1024L;
                prof_array[2] = 8192L;    prof_array[3] = 16384L;
                prof_array[4] = 32768L;   prof_array[5] = 65536L;
                prof_array[6] = 105000L;  prof_array[7] = 165410L;
                prof_array[8] = 287306L;  prof_array[9] = 809410L;
                prof_array[10] = 3538232L; prof_array[11] = 500000000L;
                break;  
        default:
                prof_array[0] = 0L;       prof_array[1] = 1024L;
                prof_array[2] = 40000L;   prof_array[3] = 80000L;
                prof_array[4] = 120000L;  prof_array[5] = 160000L;
                prof_array[6] = 205000L;  prof_array[7] = 222000L;
                prof_array[8] = 380000L;  prof_array[9] = 965410L;
                prof_array[10] = 5495000; prof_array[11] = 500000000L;
                break;
        } 

	n = ply_ptr->realm[index-1];
	for(i=0; i<11; i++)
		if(n < prof_array[i+1]) {
			prof = 10*i;
			break;
		}

	prof += ((n - prof_array[i])*10) / (prof_array[i+1] - prof_array[i]);

	return(prof);
}

/**********************************************************************/
/*				fall_ply			      */
/**********************************************************************/

/* This function computes a player's bonus (or susceptibility) to falling */
/* while climbing.							  */

int fall_ply(ply_ptr)
creature	*ply_ptr;
{
	int	fall, j;

	fall = bonus[ply_ptr->dexterity]*5;
	for(j=0; j<MAXWEAR; j++)
		if(ply_ptr->ready[j])
			if(F_ISSET(ply_ptr->ready[j], OCLIMB))
				fall += ply_ptr->ready[j]->pdice*3;
	return(fall);
}

/**********************************************************************/
/*				find_who			      */
/**********************************************************************/

/* This function searches through the players who are currently logged */
/* on for a given player name.  If that player is on, a pointer to him */
/* is returned.							       */

creature *find_who(name)
char	*name;
{
	int i;

	for(i=0; i<Tablesize; i++) {
		if(!Ply[i].ply || !Ply[i].io || Ply[i].ply->fd < 0) continue;
		if(!strcmp(Ply[i].ply->name, name))
			return(Ply[i].ply);
	}

	return(0);

}

/**********************************************************************/
/*				lowest_piety			      */
/**********************************************************************/

/* This function finds the player with the lowest piety in a given room. */
/* The pointer to that player is returned.  In the case of a tie, one of */
/* them is randomly chosen.						 */

creature *lowest_piety(rom_ptr, invis)
room	*rom_ptr;
int	invis;
{
	creature	*ply_ptr = 0;
	ctag		*cp;
	int		totalpiety, pick;

	cp = rom_ptr->first_ply;
	totalpiety = 0;
	if(!cp)
		return(0);

	while(cp) {
		if(F_ISSET(cp->crt, PHIDDN) ||
		   (F_ISSET(cp->crt, PINVIS) && !invis) ||
		   F_ISSET(cp->crt, PDMINV)) {
			cp = cp->next_tag;
			continue;
		}
		totalpiety += MAX(1, (25 - cp->crt->piety));
		cp = cp->next_tag;
	}

	if(!totalpiety)
		return(0);
	pick = mrand(1, totalpiety);

	cp = rom_ptr->first_ply;
	totalpiety = 0;
	while(cp) {
		if(F_ISSET(cp->crt, PHIDDN) ||
		   (F_ISSET(cp->crt, PINVIS) && !invis) ||
		   F_ISSET(cp->crt, PDMINV)) {
			cp = cp->next_tag;
			continue;
		}
		totalpiety += MAX(1, (25 - cp->crt->piety));
		if(totalpiety >= pick) {
			ply_ptr = cp->crt;
			break;
		}
		cp = cp->next_tag;
	}

	return(ply_ptr);
}

/**********************************************************************/
/*				has_light			      */
/**********************************************************************/

/* This function returns true if the player in the first parameter is */
/* holding or wearing anything that generates light.		      */

int has_light(crt_ptr)
creature	*crt_ptr;
{
	int	i, light = 0;

	for(i=0; i<MAXWEAR; i++) {
		if(!crt_ptr->ready[i]) continue;
		if(F_ISSET(crt_ptr->ready[i], OLIGHT)) {
			if((crt_ptr->ready[i]->type == LIGHTSOURCE &&
			   crt_ptr->ready[i]->shotscur > 0) ||
			   crt_ptr->ready[i]->type != LIGHTSOURCE) {
				light = 1;
				break;
			}
		}
	}

	if(F_ISSET(crt_ptr, PLIGHT)) {
		light = 1;
		i = MAXWEAR;
	}

	if(light) 
		return(i+1);
	else 
		return(0);

}

/************************************************************************/
/*				ply_prompt				*/
/************************************************************************/

/* This function returns the prompt that the player should be seeing	*/

char *ply_prompt(ply_ptr)
creature	*ply_ptr;
{
	static char prompt[40];
	int fd;

	fd = ply_ptr->fd;

	if(fd < 0 || F_ISSET(ply_ptr, PSPYON) || F_ISSET(ply_ptr, PREADI))
		prompt[0] = 0;

	else if(F_ISSET(ply_ptr, PPROMP))
		sprintf(prompt, "(%d H %d M): ", ply_ptr->hpcur,
		    ply_ptr->mpcur);

	else
		strcpy(prompt, ": ");

	return prompt;
}

 
/**********************************************************************/
/*                            low_piety_alg                          */
/**********************************************************************/
/* This function is a varation on the lowest piety function.  The    *
 * searchs the given player list, totally up all the player's piety  *
 * (30 - ply piety), and then randomly picking a player from the     *
 * based on the player's piety.  Players with lower piety have a     *
 * greater chance of being attacked.  The alg, parameter tells the   *
 * whether to ignore a given player alignemnt (alg=1, only consider  *
 * good players, -1 only consider evil players).  The invis param    *
 * tells if the monster can detect invisible. */

creature *low_piety_alg(rom_ptr, invis, alg,lvl)
room    *rom_ptr;
int     invis;
int		alg;
int  	lvl;
{
    creature    *ply_ptr = 0;
    ctag        *cp;
    int        total, pick;
 
        cp = rom_ptr->first_ply;
        total = 0;

       if(!cp)
                return(NULL);
 
        while(cp) {
            if(F_ISSET(cp->crt, PHIDDN) || 
				(F_ISSET(cp->crt, PINVIS) && !invis) || 
				F_ISSET(cp->crt, PDMINV) ||
				(cp->crt->level < lvl) ||
				((alg == 1) && (cp->crt->alignment > -100)) ||
				((alg == -1) && (cp->crt->alignment < 100))) {
	                cp = cp->next_tag;
                    continue;
         	}
            total += MAX(1, (30 - cp->crt->piety));
            cp = cp->next_tag;
        }
 
        if(!total)
                return(NULL);

        pick = mrand(1, total);
 
        cp = rom_ptr->first_ply;
        total = 0;
        while(cp) {
            if(F_ISSET(cp->crt, PHIDDN) ||
               (F_ISSET(cp->crt, PINVIS) && !invis) ||
				F_ISSET(cp->crt, PDMINV) ||
				((alg == 1) && (cp->crt->alignment > -100)) ||
				((alg == -1) && (cp->crt->alignment < 100))) {
                    cp = cp->next_tag;
                    continue;
                }

            total += MAX(1, (30 - cp->crt->piety));
            if(total >= pick) {
                    ply_ptr = cp->crt;
                    break;
            }
            cp = cp->next_tag;
        }
 
        return(ply_ptr);
}