/*
 * COMMAND8.C:
 *
 *	Additional user routines.
 *
 *	Copyright (C) 1991, 1992, 1993 Brett J. Vickers
 *
 */

#include "mstruct.h"
#include "mextern.h"
#ifdef DMALLOC
  #include "/usr/local/include/dmalloc.h"
#endif

/**********************************************************************/
/*				give				      */
/**********************************************************************/

/* This function allows a player to give an item in his inventory to */
/* another player or monster.					     */

int give(ply_ptr, cmnd)
creature	*ply_ptr;
cmd		*cmnd;
{
	object		*obj_ptr;
	creature	*crt_ptr;
	room		*rom_ptr;
	int		fd;

	fd = ply_ptr->fd;
	rom_ptr = ply_ptr->parent_rom;

	if(cmnd->num < 3) {
		print(fd, "Give what to whom?\n");
		return(0);
	}

	if(cmnd->str[1][0] == '$') {
		give_money(ply_ptr, cmnd);
		return(0);
	}

	obj_ptr = find_obj(ply_ptr, ply_ptr->first_obj,
			   cmnd->str[1], cmnd->val[1]);

	if(!obj_ptr) {
		print(fd, "You don't have that.\n");
		return(0);
	}

	F_CLR(ply_ptr, PHIDDN);

	cmnd->str[2][0] = up(cmnd->str[2][0]);
	crt_ptr = find_crt(ply_ptr, rom_ptr->first_ply,
			   cmnd->str[2], cmnd->val[2]);

	if(!crt_ptr) {
		cmnd->str[2][0] = low(cmnd->str[2][0]);
		crt_ptr = find_crt(ply_ptr, rom_ptr->first_mon,
				   cmnd->str[2], cmnd->val[2]);
		if(!crt_ptr) {
			print(fd, "I don't see that person here.\n");
			return(0);
		}
	}

	if(crt_ptr == ply_ptr) {
		print(fd, "You can't give something to yourself.\n");
		return(0);
	}

	if(obj_ptr->questnum) {
		print(fd, "You can't give away a quest object.\n");
		return(0);
	}

	if(crt_ptr->type == PLAYER && (weight_ply(crt_ptr) + 
	   weight_obj(obj_ptr) > max_weight(crt_ptr))) {
		print(fd, "%s can't hold anymore.\n", crt_ptr->name);
		return(0);
	}

	del_obj_crt(obj_ptr, ply_ptr);
	add_obj_crt(obj_ptr, crt_ptr);

	print(fd, "You give %1i to %m.\n", obj_ptr, crt_ptr);
	print(crt_ptr->fd, "%M gave %1i to you.\n", ply_ptr, obj_ptr);
	broadcast_rom2(fd, crt_ptr->fd, ply_ptr->rom_num, "%M gave %1i to %m.",
		       ply_ptr, obj_ptr, crt_ptr);

	return(0);

}

/**********************************************************************/
/*				give_money			      */
/**********************************************************************/

/* This function allows a player to give gold to another player.  Gold */
/* is interpreted as gold if it is preceded by a dollar sign.	       */

void give_money(ply_ptr, cmnd)
creature	*ply_ptr;
cmd		*cmnd;
{
	creature	*crt_ptr;
	room		*rom_ptr;
	long		amt;
	int		fd;

	rom_ptr = ply_ptr->parent_rom;
	fd = ply_ptr->fd;

	amt = atol(&cmnd->str[1][1]);
	if(amt < 1) {
		print(fd, "Get real.\n");
		return;
	}
	if(amt > ply_ptr->gold) {
		print(fd, "You don't have that much gold.\n");
		return;
	}

	cmnd->str[2][0] = up(cmnd->str[2][0]);
	crt_ptr = find_crt(ply_ptr, rom_ptr->first_ply,
			   cmnd->str[2], cmnd->val[2]);

	if(!crt_ptr || crt_ptr == ply_ptr) {
		cmnd->str[2][0] = low(cmnd->str[2][0]);
		crt_ptr = find_crt(ply_ptr, rom_ptr->first_mon,
			  cmnd->str[2], cmnd->val[2]);

		if(!crt_ptr) {
			print(fd, "That person is not here.\n");
			return;
		}
	}

	crt_ptr->gold += amt;
	ply_ptr->gold -= amt;

	print(fd, "Ok.\n");
	
	print(crt_ptr->fd, "%M gave you %ld gold pieces.\n", 
	      ply_ptr, amt);
	broadcast_rom2(fd, crt_ptr->fd, ply_ptr->rom_num, 
		       "%M gave %m %ld gold pieces.", ply_ptr, crt_ptr, amt);

}

/**********************************************************************/
/*				repair				      */
/**********************************************************************/

/* This function allows a player to repair a weapon or armor if he is */
/* in a repair shoppe.  There is a chance of breakage.		      */

int repair(ply_ptr, cmnd)
creature	*ply_ptr;
cmd		*cmnd;
{
	object	*obj_ptr;
	room	*rom_ptr;
	long	cost;
	int	fd, broke;

	fd = ply_ptr->fd;
	rom_ptr = ply_ptr->parent_rom;

	if(cmnd->num < 2) {
		print(fd, "Repair what?\n");
		return(0);
	}

	if(!F_ISSET(rom_ptr, RREPAI)) {
		print(fd, "This is not a repair shop.\n");
		return(0);
	}

	obj_ptr = find_obj(ply_ptr, ply_ptr->first_obj,
			   cmnd->str[1], cmnd->val[1]);

	if(!obj_ptr) {
		print(fd, "You don't have that.\n");
		return(0);
	}

	F_CLR(ply_ptr, PHIDDN);

	if(F_ISSET(obj_ptr, ONOFIX)) {
		print(fd, "The smithy cannot repair that.\n");
		return(0);
	}

	if(obj_ptr->type > MISSILE && obj_ptr->type != ARMOR) {
		print(fd, "You can only repair weapons and armor.\n");
		return(0);
	}

	if(obj_ptr->shotscur > MAX(3, obj_ptr->shotsmax/10)) {
		print(fd, "It's not broken yet.\n");
		return(0);
	}

	cost = obj_ptr->value / 2;

	if(ply_ptr->gold < cost) {
		print(fd, "You don't have enough money.\n");
		return(0);
	}

	print(fd, "The smithy takes %ld gold pieces from you.\n", cost);
	ply_ptr->gold -= cost;

	broadcast_rom(fd, ply_ptr->rom_num, "%M has the smithy repair %1i.",
		      ply_ptr, obj_ptr);

	broke = mrand(1,100) + bonus[ply_ptr->piety];
	if((broke <= 15 && obj_ptr->shotscur < 1) ||
	   (broke <= 5 && obj_ptr->shotscur > 0)) {
		print(fd, "\"Darnitall!\" shouts the smithy, \"I broke another. Sorry %s.\"\n", F_ISSET(ply_ptr, PMALES) ? "lad":"lass");
		broadcast_rom(fd, ply_ptr->rom_num, "Oops!  He broke it.");
		if(obj_ptr->shotscur > 0) {
			print(fd, "He gives your money back.\n");
			ply_ptr->gold += cost;
		}
		del_obj_crt(obj_ptr, ply_ptr);
		free_obj(obj_ptr);
		return(0);
	}

	if((F_ISSET(obj_ptr, OENCHA) || obj_ptr->adjustment) &&
		mrand(1,50) > ply_ptr->piety) {
		print(fd, "\"It lost that nice glow,\" says the smithy.\n");
		if(obj_ptr->type == ARMOR && obj_ptr->wearflag == BODY)
			obj_ptr->armor =
				MAX(obj_ptr->armor - obj_ptr->adjustment*2, 0);
		else if(obj_ptr->type == ARMOR)
			obj_ptr->armor =
				MAX(obj_ptr->armor - obj_ptr->adjustment, 0);
		else if(obj_ptr->type <= MISSILE) {
			obj_ptr->shotsmax -= obj_ptr->adjustment*10;
			obj_ptr->pdice =
				MAX(obj_ptr->pdice - obj_ptr->adjustment, 0);
		}
		obj_ptr->adjustment = 0;
		F_CLR(obj_ptr, OENCHA);
	}

	obj_ptr->shotscur = (obj_ptr->shotsmax * mrand(5,9)) / 10;

	print(fd, "The smithy hands %i back to you, almost good as new.\n", 
		obj_ptr);

	return(0);

}

/**********************************************************************/
/*				prt_time			      */
/**********************************************************************/

/* This function outputs the time of day (realtime) to the player.    */

int prt_time(ply_ptr)
creature	*ply_ptr;
{
	char	*str;
	long	t;
	int	fd, daytime;

	fd = ply_ptr->fd;

	daytime = (int)(Time % 24L);
	print(fd, "Game-Time: %d o'clock %s.\n", daytime%12 == 0 ? 12 :
	      daytime%12, daytime > 11 ? "PM":"AM");

	t = time(0);
	str = ctime(&t);
	str[strlen(str)-1] = 0;
	
	print(fd, "Real-Time: %s (PST).\n", str);

	return(0);

}

/**********************************************************************/
/*				circle				      */
/**********************************************************************/

/* This function allows fighters and barbarians to run circles about an */
/* enemy, confusing it for several seconds.				*/

int circle(ply_ptr, cmnd)
creature	*ply_ptr;
cmd		*cmnd;
{
	creature	*crt_ptr;
	room		*rom_ptr;
	long		i, t;
	int		chance, delay, fd;

	fd = ply_ptr->fd;
	rom_ptr = ply_ptr->parent_rom;

	if(cmnd->num < 2) {
		print(fd, "Circle whom?\n");
		return(0);
	}

	if(ply_ptr->class != FIGHTER && ply_ptr->class != BARBARIAN &&
	   ply_ptr->class < CARETAKER) {
		print(fd, "Only barbarians and fighters may circle.\n");
		return(0);
	}

	crt_ptr = find_crt(ply_ptr, rom_ptr->first_mon,
			   cmnd->str[1], cmnd->val[1]);

	if(!crt_ptr) {
		cmnd->str[1][0] = up(cmnd->str[1][0]);
		crt_ptr = find_crt(ply_ptr, rom_ptr->first_ply,
				   cmnd->str[1], cmnd->val[1]);

		if(!crt_ptr || crt_ptr == ply_ptr || strlen(cmnd->str[1]) < 3) {
			print(fd, "That is not here.\n");
			return(0);
		}
	}

	if(crt_ptr->type == PLAYER) {
		if(F_ISSET(rom_ptr, RNOKIL) && ply_ptr->class < DM) {
			print(fd, "No killing allowed in this room.\n");
			return(0);
		}
 
            if((!F_ISSET(ply_ptr,PPLDGK) || !F_ISSET(crt_ptr,PPLDGK)) ||
                (BOOL(F_ISSET(ply_ptr,PKNGDM)) == BOOL(F_ISSET(crt_ptr,PKNGDM))) ||
                (! AT_WAR)) {
                if(!F_ISSET(ply_ptr, PCHAOS) && ply_ptr->class < DM) {
                    print(fd, "Sorry, you're lawful.\n");
                    return (0);
                }
                if(!F_ISSET(crt_ptr, PCHAOS) && ply_ptr->class < DM) {
                    print(fd, "Sorry, that player is lawful.\n");
                    return (0);
                }     
            }
	if(is_charm_crt(ply_ptr->name, crt_ptr) && F_ISSET(crt_ptr, PCHARM)) {
                print(fd, "You are too fond of %s to do that.\n", crt_ptr->name);
                return(0);
            }

	}

	i = LT(ply_ptr, LT_ATTCK);
	t = time(0);

	if(i > t) {
		please_wait(fd, i-t);
		return(0);
	}

	F_CLR(ply_ptr, PHIDDN);
	if(F_ISSET(ply_ptr, PINVIS)) {
		F_CLR(ply_ptr, PINVIS);
		print(fd, "Your invisibility fades.\n");
		broadcast_rom(fd, ply_ptr->rom_num, "%M fades into view.",
			      ply_ptr);
	}

	chance = 50 + (ply_ptr->level-crt_ptr->level)*10 +
		 (bonus[ply_ptr->dexterity] -bonus[crt_ptr->dexterity])*2;
	if (crt_ptr->type == MONSTER && F_ISSET(crt_ptr, MUNDED))
		chance -= (5 + crt_ptr->level*2);
	chance = MIN(80, chance);
	if(F_ISSET(crt_ptr, MNOCIR) || F_ISSET(ply_ptr, PBLIND))
		chance=1;
		
	if(crt_ptr->type != PLAYER) {
		if(F_ISSET(crt_ptr, MUNKIL)) {
			print(fd, "You cannot harm %s.\n",
				F_ISSET(crt_ptr, MMALES) ? "him":"her");
			return(0);
		}
		/* if(is_charm_crt(crt_ptr->name, ply_ptr))
			del_charm_crt(crt_ptr, ply_ptr); */

		add_enm_crt(ply_ptr->name, crt_ptr);
	}

	if(mrand(1,100) <= chance) {
		if(ply_ptr->class == BARBARIAN)
			delay = mrand(6,9);
		else
			delay = mrand(6,12);
		crt_ptr->lasttime[LT_ATTCK].ltime = t;
		crt_ptr->lasttime[LT_ATTCK].interval = delay;

		print(fd, "You circle %m.\n", crt_ptr);

		print(crt_ptr->fd, "%M circles you.\n", ply_ptr);
		broadcast_rom2(fd, crt_ptr->fd, ply_ptr->rom_num, 
			       "%M circles %m.", ply_ptr, crt_ptr);
		ply_ptr->lasttime[LT_ATTCK].interval = 2;
	}
	else {
		print(fd, "You failed to circle it.\n");
		print(crt_ptr->fd, "%M tried to circle you.\n", ply_ptr);
		broadcast_rom2(fd, crt_ptr->fd, ply_ptr->rom_num,
			       "%M tried to circle %m.", ply_ptr, crt_ptr);
		ply_ptr->lasttime[LT_ATTCK].interval = 3;
	}

	ply_ptr->lasttime[LT_ATTCK].ltime = t;

	return(0);

}

/**********************************************************************/
/*				bash				      */
/**********************************************************************/

/* This function allows fighters and barbarians to "bash" an opponent, */
/* doing less damage than a normal attack, but knocking the opponent   */
/* over for a few seconds, leaving him unable to attack back.	       */

int bash(ply_ptr, cmnd)
creature	*ply_ptr;
cmd		*cmnd;
{
	creature	*crt_ptr;
	room		*rom_ptr;
	long		i, t;
	int		m, n, chance, fd, p, addprof;

	fd = ply_ptr->fd;
	rom_ptr = ply_ptr->parent_rom;

	if(cmnd->num < 2) {
		print(fd, "Bash whom?\n");
		return(0);
	}

	if(ply_ptr->class != FIGHTER && ply_ptr->class != BARBARIAN &&
	   ply_ptr->class < CARETAKER) {
		print(fd, "Only barbarians and fighters may bash.\n");
		return(0);
	}

	crt_ptr = find_crt(ply_ptr, rom_ptr->first_mon,
			   cmnd->str[1], cmnd->val[1]);

	if(!crt_ptr) {
		cmnd->str[1][0] = up(cmnd->str[1][0]);
		crt_ptr = find_crt(ply_ptr, rom_ptr->first_ply,
				   cmnd->str[1], cmnd->val[1]);

		if(!crt_ptr || crt_ptr == ply_ptr || strlen(cmnd->str[1])<3) {
			print(fd, "That isn't here.\n");
			return(0);
		}

	}

	if(crt_ptr->type != PLAYER && is_enm_crt(ply_ptr->name, crt_ptr)) {
		print(fd, "Not while you're already fighting %s.\n",
		      F_ISSET(crt_ptr, MMALES) ? "him":"her");
		return(0);
	}
	else if(crt_ptr->type == PLAYER) {
		if(F_ISSET(rom_ptr, RNOKIL)) {
			print(fd, "No killing allowed in this room.\n");
			return(0);
		}
 
            if((!F_ISSET(ply_ptr,PPLDGK) || !F_ISSET(crt_ptr,PPLDGK)) ||
                (BOOL(F_ISSET(ply_ptr,PKNGDM)) == BOOL(F_ISSET(crt_ptr,PKNGDM))) ||
                (! AT_WAR)) {
                if(!F_ISSET(ply_ptr, PCHAOS) && ply_ptr->class < DM) {
                    print(fd, "Sorry, you're lawful.\n");
                    return (0);
                }
                if(!F_ISSET(crt_ptr, PCHAOS) && ply_ptr->class < DM) {
                    print(fd, "Sorry, that player is lawful.\n");
                    return (0);
                }     
            }
	if(is_charm_crt(ply_ptr->name, crt_ptr)&& F_ISSET(crt_ptr, PCHARM)) {
                print(fd, "You like %s too much to do that.\n", crt_ptr->name);
                return(0);
            }

	}

	i = LT(ply_ptr, LT_ATTCK);
	t = time(0);

	if(i > t) {
		please_wait(fd, i-t);
		return(0);
	}

	ply_ptr->lasttime[LT_ATTCK].ltime = t;
	ply_ptr->lasttime[LT_ATTCK].interval = 3;
	ply_ptr->lasttime[LT_SPELL].ltime = t;
        ply_ptr->lasttime[LT_SPELL].interval = 5;
	
	F_CLR(ply_ptr, PHIDDN);
	if(F_ISSET(ply_ptr, PINVIS)) {
		F_CLR(ply_ptr, PINVIS);
		print(fd, "Your invisibility fades.\n");
		broadcast_rom(fd, ply_ptr->rom_num, "%M fades into view.",
			      ply_ptr);
	}

	if(crt_ptr->type != PLAYER) {
		if(F_ISSET(crt_ptr, MUNKIL)) {
			print(fd, "You cannot harm %s.\n",
				F_ISSET(crt_ptr, MMALES) ? "him":"her");
			return(0);
		}
 if(F_ISSET(crt_ptr, MMGONL)) {
            print(fd, "Your weapon has no effect on %m.\n",
                crt_ptr);
            return(0);
        }
        if(F_ISSET(crt_ptr, MENONL)) {
            if(!ply_ptr->ready[WIELD-1] || 
                ply_ptr->ready[WIELD-1]->adjustment < 1) {
                print(fd, "Your weapon has no effect on %m.\n",
                    crt_ptr);
                return(0);
            }
        }  
	/*	if(is_charm_crt(crt_ptr->name, ply_ptr))
			del_charm_crt(crt_ptr, ply_ptr); */
		
		add_enm_crt(ply_ptr->name, crt_ptr);
	}

	chance = 50 + (ply_ptr->level-crt_ptr->level)*10 +
		bonus[ply_ptr->strength]*3 +
		 (bonus[ply_ptr->dexterity] -bonus[crt_ptr->dexterity])*2;
	chance += ply_ptr->class==BARBARIAN ? 5:0;
	chance = MIN(85, chance);
	if(F_ISSET(ply_ptr, PBLIND))
		chance = MIN(20, chance);

	if(mrand(1,100) <= chance) {

		if(ply_ptr->ready[WIELD-1]) {
			if(ply_ptr->ready[WIELD-1]->shotscur < 1) {
				print(fd, "Your %s is broken.\n", 
				      ply_ptr->ready[WIELD-1]->name);
				add_obj_crt(ply_ptr->ready[WIELD-1], ply_ptr);
				ply_ptr->ready[WIELD-1] = 0;
				return(0);
			}
		}

		n = ply_ptr->thaco - crt_ptr->armor/10;
		if(mrand(1,20) >= n) {

			crt_ptr->lasttime[LT_ATTCK].ltime = t;
			crt_ptr->lasttime[LT_ATTCK].interval = mrand(5,8);
			crt_ptr->lasttime[LT_SPELL].ltime = t;
                        crt_ptr->lasttime[LT_SPELL].interval = mrand(7,10);
			
			if(ply_ptr->ready[WIELD-1])
				n = mdice(ply_ptr->ready[WIELD-1]) / 2;
			else
				n = mdice(ply_ptr) / 2;

			if(ply_ptr->class == BARBARIAN && mrand(1,100) > 75)
				n = (n*3)/2;

			m = MIN(crt_ptr->hpcur, n);
			if(crt_ptr->type != PLAYER) {
				/* if(is_charm_crt(crt_ptr->name, ply_ptr))
					del_charm_crt(crt_ptr, ply_ptr); */

				add_enm_dmg(ply_ptr->name, crt_ptr, m);
				if(ply_ptr->ready[WIELD-1]) {
					p = MIN(ply_ptr->ready[WIELD-1]->type,
						4);
					addprof = (m * crt_ptr->experience) /
						MAX(crt_ptr->hpmax, 1);
					addprof = MIN(addprof,
						crt_ptr->experience);
					ply_ptr->proficiency[p] += addprof;
				}
				else if(ply_ptr->class == MONK) {
                                /* give blunt prof for monk barehand */
                                addprof = (m * crt_ptr->experience) /
                                    MAX(crt_ptr->hpmax, 1);
                                addprof = MIN(addprof, crt_ptr->experience);
                                ply_ptr->proficiency[2] += addprof;  
	                        }
			}
			crt_ptr->hpcur -= n;

			print(fd, "You bash for %d damage.\n", n);
			broadcast_rom2(fd, crt_ptr->fd, crt_ptr->rom_num, 
				       "%M bashes %m.", ply_ptr, crt_ptr);
			print(crt_ptr->fd, "%M bashed you for %d damage.\n",
			      ply_ptr, n);

			ply_ptr->lasttime[LT_ATTCK].interval = 2;

			if(crt_ptr->hpcur < 1) {
				print(fd, "You killed %m.\n", crt_ptr);
				broadcast_rom2(fd, crt_ptr->fd, 
					       ply_ptr->rom_num,
					       "%M killed %m.", ply_ptr,
					       crt_ptr);

				die(crt_ptr, ply_ptr);
			}
			else
				check_for_flee(crt_ptr);
		}
		else {
			print(fd, "Your bash failed.\n");
			print(crt_ptr->fd, "%M tried to bash you.\n", ply_ptr);
			broadcast_rom2(fd, crt_ptr->fd, crt_ptr->rom_num, 
				       "%M tried to bash %m.", ply_ptr, 
				       crt_ptr);
		}
	}

	else {
		print(fd, "Your bash failed.\n");
		print(crt_ptr->fd, "%M tried to bash you.\n", ply_ptr);
		broadcast_rom2(fd, crt_ptr->fd, crt_ptr->rom_num, 
			       "%M tried to bash %m.", ply_ptr, crt_ptr);
	}

	return(0);

}

/**********************************************************************/
/*				savegame			      */
/**********************************************************************/

/* This function saves a player's game.  Since items need to be un-readied */
/* before a player can be saved to a file, this function makes a duplicate */
/* of the player, unreadies everything on the duplicate, and then saves    */
/* the duplicate to the file.  Afterwards, the duplicate is freed from     */
/* memory.								   */

int savegame(ply_ptr, cmnd)
creature	*ply_ptr;
cmd		*cmnd;
{
	creature	*dum_ptr;
	object		*obj[MAXWEAR];
	int		i, n = 0;

	dum_ptr = (creature *)malloc(sizeof(creature));
	if(!dum_ptr)
		merror("savegame", FATAL);

	*dum_ptr = *ply_ptr;

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

	if(!dum_ptr->name[0]) return;

	if(save_ply(dum_ptr->name, dum_ptr) < 0)
		merror("ERROR - savegame", NONFATAL);

	for(i=0; i<n; i++)
		del_obj_crt(obj[i], dum_ptr);

	free(dum_ptr);

	print(ply_ptr->fd, "Player saved.\n");

	return(0);

}

/**********************************************************************/
/*				talk				      */
/**********************************************************************/

/* This function allows players to speak with monsters if the monster */
/* has a talk string set.					      */

int talk(ply_ptr, cmnd)
creature	*ply_ptr;
cmd		*cmnd;
{
	room		*rom_ptr;
	creature	*crt_ptr;
	ttag		*tp;
	char		str[160];
	int		fd;

	fd = ply_ptr->fd;
	rom_ptr = ply_ptr->parent_rom;

	if(cmnd->num < 2) {
		print(fd, "Talk to whom?\n");
		return(0);
	}

	crt_ptr = find_crt(ply_ptr, rom_ptr->first_mon,
			   cmnd->str[1], cmnd->val[1]);

	if(!crt_ptr) {

		print(fd, "I don't see that here.\n");
		return(0);
	}

	F_CLR(ply_ptr, PHIDDN);

	if(cmnd->num == 2 || !F_ISSET(crt_ptr, MTALKS)) {
		broadcast_rom(fd, ply_ptr->rom_num, "%M talks with %m.", 
			ply_ptr, crt_ptr);

		if(crt_ptr->talk[0]) {
			broadcast_rom(fd, ply_ptr->rom_num,
				"%M says to %M, \"%s\".", crt_ptr, ply_ptr,
				crt_ptr->talk);
			print(fd, "%M says to you, \"%s\".\n", crt_ptr,
				crt_ptr->talk);

		}
		else
			broadcast_rom(-1, ply_ptr->rom_num,
				"%M doesn't say anything.", crt_ptr);
		if(F_ISSET(crt_ptr, MTLKAG))
			add_enm_crt(ply_ptr->name, crt_ptr);
	}

	else {
		if(!crt_ptr->first_tlk)
			if(!load_crt_tlk(crt_ptr))
				return(PROMPT);

		broadcast_rom(fd, ply_ptr->rom_num, "%M asks %m about \"%s\".",
			ply_ptr, crt_ptr, cmnd->str[2]);

		tp = crt_ptr->first_tlk;
		while(tp) {
			if(!strcmp(cmnd->str[2], tp->key)) {
				broadcast_rom(fd, ply_ptr->rom_num,
					"%M says to %M, \"%s\".", crt_ptr,
					ply_ptr, tp->response);
				print(fd, "%M says to you, \"%s\"\n",
					crt_ptr, tp->response);
				talk_action(ply_ptr, crt_ptr, tp);
				return(0);
			}
			tp = tp->next_tag;
		}
		broadcast_rom(-1, ply_ptr->rom_num, "%M shrugs.", crt_ptr);
		if(F_ISSET(crt_ptr, MTLKAG))
			add_enm_crt(ply_ptr->name, crt_ptr);
	}

	return(0);

}

/******************************************************************/
/*                      talk_action                               */
/******************************************************************/
/* The talk_action function handles a monster's actin when a     *
 * player asks the monster about a key word.  The format for the *
 * is defined in the monster's talk file.  Currently a monster   *
 * can attack, or cast spells on the player who mentions the key *
 * word or preform any of the defined social commands */

void talk_action(ply_ptr, crt_ptr,tt)
creature	*ply_ptr;
creature	*crt_ptr;
ttag		*tt;
{
cmd		cm;
int 	i, n,splno =0;
object  *obj_ptr;
int		(*fn)();

for (i = 0; i < COMMANDMAX;i++){
	cm.str[i][0] = 0;
	cm.str[i][24] = 0;
	cm.val[i]	= 0;
}
	cm.fullstr[0] = 0;
	cm.num = 0;

switch(tt->type){
	case 1: 	/*attack */
		add_enm_crt(ply_ptr->name, crt_ptr);
		broadcast_rom(ply_ptr->fd, ply_ptr->rom_num,
					"%M attacks %M\n",crt_ptr,ply_ptr);
		print(ply_ptr->fd,"%M attacks you.\n",crt_ptr);
		break;

	case 2:				/*action command */
		if(action){
			strncpy(cm.str[0],tt->action,25);
			strcat(cm.fullstr,tt->action);
			cm.val[0]  = 1;
			cm.num = 1;

			if(tt->target)
				if(!strcmp(tt->target,"PLAYER")){
					strcpy(cm.str[1],ply_ptr->name);
					strcat(cm.fullstr," ");
					strcat(cm.fullstr,ply_ptr->name);
					cm.val[1]  = 1;
					cm.num = 2;
				}
			action(crt_ptr,&cm);
		}
		break;
	case 3:			/*cast */
		if(tt->action){
			n =  crt_ptr->mpcur; 
			strcpy(cm.str[0],"cast");
			strncpy(cm.str[1],tt->action,25);
			strcpy(cm.str[2],ply_ptr->name);
			cm.val[0]  = cm.val[1]  = cm.val[2]  = 1;
			cm.num = 3;
			sprintf(cm.fullstr,"cast %s %s",tt->action,ply_ptr->name);

		    i = 0;
			do {
		   		if(!strcmp(tt->action, spllist[i].splstr)) {
           			splno = i;
           	 		break;
        		}
       	 		i++;
    		} while(spllist[i].splno != -1);

			if(spllist[i].splno == -1)
				return;
		 	fn = spllist[splno].splfn;
			if(fn == offensive_spell) {
				for(i=0; ospell[i].splno != spllist[splno].splno; i++)
					if(ospell[i].splno == -1) return;
				 (*fn)(crt_ptr, &cm, CAST, spllist[splno].splstr,
            &ospell[i]);
    		}
			else if(is_enm_crt(ply_ptr->name,crt_ptr)){
				print(ply_ptr->fd,"%M refuses to cast any spells on you.\n",
					crt_ptr);
				return;
			}	
			else
			  (*fn)(crt_ptr, &cm, CAST);
			
			if (spllist[i].splno  != SRESTO && crt_ptr->mpcur == n)
				print(ply_ptr->fd,
			"%M appoligies that %s can not currently cast that spell on you.\n",
			crt_ptr, (F_ISSET(crt_ptr,MMALES)) ? "he" : "she");
		}
		break;
	case 4:
		i = atoi(tt->action);
		if (i > 0){
			n=load_obj(i, &obj_ptr);
            if(n > -1) {
                if(F_ISSET(obj_ptr, ORENCH))
                    rand_enchant(obj_ptr);
 
                if(weight_ply(ply_ptr) + weight_obj(obj_ptr) > 
                   max_weight(ply_ptr)) {
                   print(ply_ptr->fd, "You can't hold anymore.\n");
				   break;
               }    

	            if(obj_ptr->questnum && Q_ISSET(ply_ptr, obj_ptr->questnum-1)) {
                    print(ply_ptr->fd, "You may not get that. %s.\n",
                          "You have already fulfilled that quest");
					break;
                } 
                
	     		if(obj_ptr->questnum) {
   	                 print(ply_ptr->fd, "Quest fulfilled!  Don't drop it.\n");
   	                 Q_SET(ply_ptr, obj_ptr->questnum-1);
   	                 ply_ptr->experience += quest_exp[obj_ptr->questnum-1];
   	                 print(ply_ptr->fd, "%ld experience granted.\n",
                            quest_exp[obj_ptr->questnum-1]);
   	                 add_prof(ply_ptr,quest_exp[obj_ptr->questnum-1]);
   	             	} 
                add_obj_crt(obj_ptr, ply_ptr);
				print(ply_ptr->fd,"%M gives you %i\n",crt_ptr, obj_ptr);
				broadcast_rom(ply_ptr->fd, ply_ptr->rom_num,
					"%M gives %m %i\n", crt_ptr,ply_ptr,obj_ptr);
			}
			else
				print(ply_ptr->fd,"%M has nothing to give you.\n",crt_ptr);
        }  
		break;
	default:
		break;
	}
return;
}
