diff arogue5/fight.c @ 63:0ed67132cf10

Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 09 Aug 2012 22:58:48 +0000
parents
children 56e748983fa8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arogue5/fight.c	Thu Aug 09 22:58:48 2012 +0000
@@ -0,0 +1,1579 @@
+/*
+ * All the fighting gets done here
+ *
+ * Advanced Rogue
+ * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
+ * All rights reserved.
+ *
+ * Based on "Rogue: Exploring the Dungeons of Doom"
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+ * All rights reserved.
+ *
+ * See the file LICENSE.TXT for full copyright and licensing information.
+ */
+
+#include "curses.h"
+#include <ctype.h>
+#include <string.h>
+#include "rogue.h"
+
+#define CONF_DAMAGE	-1
+#define PARAL_DAMAGE	-2
+#define DEST_DAMAGE	-3
+
+static const struct matrix att_mat[5] = {
+/* Base		Max_lvl,	Factor,		Offset,		Range */
+{  10,		25,		2,		1,		2 },
+{  9,		18,		2,		1,		5 },
+{  10,		19,		2,		1,		3 },
+{  10,		21,		2,		1,		4 },
+{   7,		25,		1,		0,		2 }
+};
+
+/*
+ * fight:
+ *	The player attacks the monster.
+ */
+
+fight(mp, weap, thrown)
+register coord *mp;
+struct object *weap;
+bool thrown;
+{
+    register struct thing *tp;
+    register struct linked_list *item;
+    register bool did_hit = TRUE;
+    bool back_stab = FALSE;
+
+    /*
+     * Find the monster we want to fight
+     */
+    if ((item = find_mons(mp->y, mp->x)) == NULL) {
+	return(FALSE); /* must have killed him already */
+    }
+    tp = THINGPTR(item);
+    /*
+     * Since we are fighting, things are not quiet so no healing takes
+     * place.
+     */
+    player.t_quiet = 0;
+    tp->t_quiet = 0;
+
+    /*
+     * if its in the wall, we can't hit it
+     */
+    if (on(*tp, ISINWALL) && off(player, CANINWALL))
+	return(FALSE);
+
+    /*
+     * Let him know it was really a mimic (if it was one).
+     */
+    if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise) &&
+	off(player, ISBLIND))
+    {
+	msg("Wait! That's a %s!", monsters[tp->t_index].m_name);
+	turn_off(*tp, ISDISGUISE);
+	did_hit = thrown;
+    }
+    if (on(*tp, CANSURPRISE) && off(player, ISBLIND) && !ISWEARING(R_ALERT)) {
+	msg("Wait! There's a %s!", monsters[tp->t_index].m_name);
+	turn_off(*tp, CANSURPRISE);
+	did_hit = thrown;
+    }
+    /*
+     * if he's a thief and the creature is asleep then he gets a chance
+     * for a backstab
+     */
+    if (player.t_ctype == C_THIEF			 	 && 
+	(!on(*tp, ISRUN) || on(*tp, ISHELD) || tp->t_no_move > 0)&&
+	!on(*tp, NOSTAB))
+	back_stab = TRUE;
+
+    runto(tp, &hero);
+
+    if (did_hit)
+    {
+	register const char *mname;
+
+	did_hit = FALSE;
+	mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name;
+	if (!can_blink(tp) &&
+	    ( ((weap != NULL) && (weap->o_type == RELIC)) ||
+	     ((off(*tp, MAGICHIT)  || ((weap != NULL) && (weap->o_hplus > 0 || weap->o_dplus > 0)) ) &&
+	      (off(*tp, BMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 1 || weap->o_dplus > 1)) ) &&
+	      (off(*tp, CMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 2 || weap->o_dplus > 2)) ) ) )
+	    && roll_em(&player, tp, weap, thrown, cur_weapon, back_stab))
+	{
+	    did_hit = TRUE;
+
+	    if (on(*tp, NOMETAL) && weap != NULL &&
+		weap->o_type != RELIC && weap->o_flags & ISMETAL) {
+		sprintf(outstring,"Your %s passes right through the %s!",
+		    weaps[weap->o_which].w_name, mname);
+		msg(outstring);
+	    }
+	    else if (thrown) {
+		tp->t_wasshot = TRUE;
+		thunk(weap, tp, mname);
+	    }
+	    else
+		hit(weap, tp, NULL, mname, back_stab);
+
+	    /* If the player hit a rust monster, he better have a + weapon */
+	    if (on(*tp, CANRUST) && !thrown && (weap != NULL) &&
+		weap->o_type != RELIC &&
+		(weap->o_flags & ISMETAL) &&
+		!(weap->o_flags & ISPROT) &&
+		(weap->o_hplus < 1) && (weap->o_dplus < 1)) {
+		if (rnd(100) < 50) weap->o_hplus--;
+		else weap->o_dplus--;
+		msg(terse ? "Your %s weakens!"
+			  : "Your %s appears to be weaker now!",
+		    weaps[weap->o_which].w_name);
+	    }
+		
+	    /* If the player hit something that shrieks, wake the dungeon */
+	    if (on(*tp, CANSHRIEK)) {
+		turn_off(*tp, CANSHRIEK);
+		msg("The %s emits a piercing shriek.", mname);
+		aggravate();
+	    }
+
+	    /* If the player hit something that can surprise, it can't now */
+	    if (on(*tp, CANSURPRISE)) turn_off(*tp, CANSURPRISE);
+
+
+	    /* 
+	     * Can the player confuse? 
+	     */
+	    if (on(player, CANHUH) && !thrown) {
+		msg("Your hands stop glowing red");
+		msg("The %s appears confused.", mname);
+		turn_on(*tp, ISHUH);
+		turn_off(player, CANHUH);
+	    }
+	    /*
+	     * does the creature explode when hit?
+	     */
+	    if (on(*tp, CANEXPLODE))
+		explode(tp);
+
+	    /* 
+	     * Merchants just disappear if hit 
+	     */
+	    if (on(*tp, CANSELL)) {
+		msg("The %s disappears with his wares in a flash.",mname);
+		killed(item, FALSE, FALSE);
+	    }
+
+	    else if (tp->t_stats.s_hpt <= 0)
+		killed(item, TRUE, TRUE);
+
+	    /* If the monster is fairly intelligent and about to die, it
+	     * may turn tail and run.
+	     */
+	    else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/10)) &&
+		     (rnd(25) < tp->t_stats.s_intel)) {
+		turn_on(*tp, ISFLEE);
+
+		/* If monster was suffocating, stop it */
+		if (on(*tp, DIDSUFFOCATE)) {
+		    turn_off(*tp, DIDSUFFOCATE);
+		    extinguish(suffocate);
+		}
+
+		/* If monster held us, stop it */
+		if (on(*tp, DIDHOLD) && (--hold_count == 0))
+			turn_off(player, ISHELD);
+		turn_off(*tp, DIDHOLD);
+	    }
+	}
+	else {
+	    if (thrown)
+		bounce(weap, tp, mname);
+	    else
+		miss(weap, tp, NULL, mname);
+	}
+    }
+    count = 0;
+    return did_hit;
+}
+
+/*
+ * attack:
+ *	The monster attacks the player
+ */
+
+attack(mp, weapon, thrown)
+register struct thing *mp;
+register struct object *weapon;
+bool thrown;
+{
+    register const char *mname;
+    register bool did_hit = FALSE;
+    register struct object *wielded;	/* The wielded weapon */
+
+    /*
+     * Since this is an attack, stop running and any healing that was
+     * going on at the time.
+     */
+    running = FALSE;
+    player.t_quiet = 0;
+    mp->t_quiet = 0;
+
+    if (on(*mp, ISDISGUISE) && off(player, ISBLIND))
+	turn_off(*mp, ISDISGUISE);
+    mname = on(player, ISBLIND) ? "it" : monsters[mp->t_index].m_name;
+
+    /*
+     * Try to find a weapon to wield.  Wield_weap will return a
+     * projector if weapon is a projectile (eg. bow for arrow).
+     * If weapon is NULL, it will try to find a suitable weapon.
+     */
+    wielded = wield_weap(weapon, mp);
+    if (weapon == NULL) weapon = wielded;
+
+    if (roll_em(mp, &player, weapon, thrown, wielded, FALSE)) {
+	did_hit = TRUE;
+
+	if (thrown) m_thunk(weapon, mp, mname);
+	else hit(weapon, mp, mname, NULL, FALSE);
+
+	if (pstats.s_hpt <= 0)
+	    death(mp->t_index);	/* Bye bye life ... */
+
+	/*
+	 * suprising monsters appear after they shoot at you 
+	 */
+	if (thrown) {
+	    if (on(*mp, CANSURPRISE)) 
+		turn_off(*mp, CANSURPRISE);
+	}
+	if (!thrown) {
+	    /*
+	     * If a vampire hits, it may take half your hit points
+	     */
+	    if (on(*mp, CANSUCK) && !save(VS_MAGIC, &player, 0)) {
+		if (pstats.s_hpt == 1) death(mp->t_index);
+		else {
+		  pstats.s_hpt /= 2;
+		  msg("You feel your life force being drawn from you.");
+		}
+	    }
+
+	    /*
+	     * Stinking monsters make player weaker (to hit)
+	     */
+	    if (on(*mp, CANSTINK)) {
+		turn_off(*mp, CANSTINK);
+		if (!save(VS_POISON, &player, 0)) {
+		    msg("The stench of the %s sickens you.", mname);
+		    if (on(player, HASSTINK)) lengthen(unstink, STINKTIME);
+		    else {
+			turn_on(player, HASSTINK);
+			fuse(unstink, 0, STINKTIME, AFTER);
+		    }
+		}
+	    }
+
+	    /*
+	     * Chilling monster reduces strength each time
+	     */
+	    if (on(*mp, CANCHILL)) {
+		if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, &player, 0)) {
+		    msg("You cringe at the %s's chilling touch.", mname);
+		    chg_str(-1);
+		    if (lost_str++ == 0)
+			fuse(res_strength, 0, CHILLTIME, AFTER);
+		    else lengthen(res_strength, CHILLTIME);
+		}
+	    }
+
+	    /*
+	     * itching monsters reduce dexterity (temporarily)
+	     */
+	    if (on(*mp, CANITCH) && !save(VS_POISON, &player, 0)) {
+		msg("The claws of the %s scratch you", mname);
+		if(ISWEARING(R_SUSABILITY)) {
+		    msg("The scratch has no effect");
+		}
+		else {
+		    turn_on(player, HASITCH);
+		    add_dexterity(TRUE);
+		    lost_dext++;
+		    fuse(un_itch, 0, roll(HEALTIME,SICKTIME), AFTER);
+		}
+	    }
+
+
+	    /*
+	     * If a hugging monster hits, it may SQUEEEEEEEZE
+	     */
+	    if (on(*mp, CANHUG)) {
+		if (roll(1,20) >= 18 || roll(1,20) >= 18) {
+		    msg("The %s squeezes you against itself.", mname);
+		    if ((pstats.s_hpt -= roll(2,8)) <= 0)
+			death(mp->t_index);
+		}
+	    }
+
+	    /*
+	     * If a disease-carrying monster hits, there is a chance the
+	     * player will catch the disease
+	     */
+	    if (on(*mp, CANDISEASE) &&
+		(rnd(pstats.s_const) < mp->t_stats.s_lvl) &&
+		off(player, HASDISEASE)) {
+		if (ISWEARING(R_HEALTH)) msg("The wound heals quickly.");
+		else {
+		    turn_on(player, HASDISEASE);
+		    fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER);
+		    msg(terse ? "You have been diseased."
+			: "You have contracted a disease!");
+		}
+	    }
+
+	    /*
+	     * If a rust monster hits, you lose armor
+	     */
+	    if (on(*mp, CANRUST)) { 
+		if (cur_armor != NULL				&&
+		    cur_armor->o_which != LEATHER		&&
+		    cur_armor->o_which != STUDDED_LEATHER	&&
+		    cur_armor->o_which != PADDED_ARMOR		&&
+		    !(cur_armor->o_flags & ISPROT)		&&
+		    cur_armor->o_ac < pstats.s_arm+1		) {
+			msg(terse ? "Your armor weakens"
+			    : "Your armor appears to be weaker now. Oh my!");
+			cur_armor->o_ac++;
+	        }
+		if (cur_misc[WEAR_BRACERS] != NULL		&&
+		    cur_misc[WEAR_BRACERS]->o_ac > 0		&&
+		    !(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) {
+			cur_misc[WEAR_BRACERS]->o_ac--;
+			if (cur_misc[WEAR_BRACERS]->o_ac == 0) {
+			    register struct linked_list *item;
+
+			    for (item=pack; item!=NULL; item=next(item)) {
+				if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) {
+				    detach(pack, item);
+				    o_discard(item);
+				    break;
+				}
+			    }
+			    msg ("Your bracers crumble and fall off!");
+			    cur_misc[WEAR_BRACERS] = NULL;
+			    inpack--;
+			}
+			else {
+			    msg("Your bracers weaken!");
+			}
+		}
+	    }
+	    /*
+	     * If can dissolve and hero has leather type armor
+	     */
+	    if (on(*mp, CANDISSOLVE) && cur_armor != NULL &&
+		(cur_armor->o_which == LEATHER		  ||
+		 cur_armor->o_which == STUDDED_LEATHER	  ||
+		 cur_armor->o_which == PADDED_ARMOR)	  &&
+		!(cur_armor->o_flags & ISPROT) &&
+		cur_armor->o_ac < pstats.s_arm+1) {
+		msg(terse ? "Your armor dissolves"
+		    : "Your armor appears to dissolve. Oh my!");
+		cur_armor->o_ac++;
+	    }
+
+	    /* If a surprising monster hit you, you can see it now */
+	    if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE);
+
+	    /*
+	     * If an infesting monster hits you, you get a parasite or rot
+	     */
+	    if (on(*mp, CANINFEST) && rnd(pstats.s_const) < mp->t_stats.s_lvl) {
+		if (ISWEARING(R_HEALTH)) msg("The wound quickly heals.");
+		else {
+		    turn_off(*mp, CANINFEST);
+		    msg(terse ? "You have been infested."
+			: "You have contracted a parasitic infestation!");
+		    infest_dam++;
+		    turn_on(player, HASINFEST);
+		}
+	    }
+
+	    /*
+	     * Ants have poisonous bites
+	     */
+	    if (on(*mp, CANPOISON) && !save(VS_POISON, &player, 0)) {
+		if (ISWEARING(R_SUSABILITY))
+		    msg(terse ? "Sting has no effect"
+			      : "A sting momentarily weakens you");
+		else {
+		    chg_str(-1);
+		    msg(terse ? "A sting has weakened you" :
+		    "You feel a sting in your arm and now feel weaker");
+		}
+	    }
+	    /*
+	     * does it take wisdom away?
+	     */
+	    if (on(*mp, TAKEWISDOM)		&& 
+		!save(VS_MAGIC, &player, 0)	&&
+		!ISWEARING(R_SUSABILITY)) {
+			add_wisdom(TRUE);
+	    }
+	    /*
+	     * does it take intelligence away?
+	     */
+	    if (on(*mp, TAKEINTEL)		&& 
+		!save(VS_MAGIC, &player, 0)	&&
+		!ISWEARING(R_SUSABILITY)) {
+			add_intelligence(TRUE);
+	    }
+	    /*
+	     * Cause fear by touching
+	     */
+	    if (on(*mp, TOUCHFEAR)) {
+		turn_off(*mp, TOUCHFEAR);
+		if (!ISWEARING(R_HEROISM)	&&
+		    !save(VS_WAND, &player, 0)	&&
+		    !(on(player, ISFLEE) && (player.t_dest == &mp->t_pos))) {
+			turn_on(player, ISFLEE);
+			player.t_dest = &mp->t_pos;
+			msg("The %s's touch terrifies you.", mname);
+		}
+	    }
+
+	    /*
+	     * make the hero dance (as in otto's irresistable dance)
+	     */
+	    if (on(*mp, CANDANCE) 	&& 
+		!on(player, ISDANCE)	&&
+		!save(VS_MAGIC, &player, -4)) {
+		    turn_off(*mp, CANDANCE);
+		    turn_on(player, ISDANCE);
+		    msg("You begin to dance uncontrollably!");
+		    fuse(undance, 0, roll(2,4), AFTER);
+	    }
+
+	    /*
+	     * Suffocating our hero
+	     */
+	    if (on(*mp, CANSUFFOCATE) && (rnd(100) < 15) &&
+		(find_slot(suffocate) == FALSE)) {
+		turn_on(*mp, DIDSUFFOCATE);
+		msg("The %s is beginning to suffocate you.", mname);
+		fuse(suffocate, 0, roll(4,2), AFTER);
+	    }
+
+	    /*
+	     * Turning to stone
+	     */
+	    if (on(*mp, TOUCHSTONE)) {
+		turn_off(*mp, TOUCHSTONE);
+		if (on(player, CANINWALL))
+			msg("The %s's touch has no effect.", mname);
+		else {
+		    if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 15) {
+		        msg("Your body begins to solidify.");
+		        msg("You are turned to stone !!! --More--");
+		        wait_for(cw,' ');
+			death(D_PETRIFY);
+		    }
+		    else {
+			msg("The %s's touch stiffens your limbs.", mname);
+			no_command += STONETIME;
+		    }
+		}
+	    }
+
+	    /*
+	     * Wraiths might drain energy levels
+	     */
+	    if ((on(*mp, CANDRAIN) || on(*mp, DOUBLEDRAIN)) && rnd(100) < 15) {
+		lower_level(mp->t_index);
+		if (on(*mp, DOUBLEDRAIN)) lower_level(mp->t_index);
+		turn_on(*mp, DIDDRAIN);  
+	    }
+
+	    /*
+	     * Violet fungi stops the poor guy from moving
+	     */
+	    if (on(*mp, CANHOLD) && off(*mp, DIDHOLD)) {
+		turn_on(player, ISHELD);
+		turn_on(*mp, DIDHOLD);
+		hold_count++;
+	    }
+
+	    /*
+	     * Sucker will suck blood and run
+	     */
+	    if (on(*mp, CANDRAW)) {
+		turn_off(*mp, CANDRAW);
+		turn_on(*mp, ISFLEE);
+		msg("The %s sates itself with your blood.", mname);
+		if ((pstats.s_hpt -= 12) <= 0) death(mp->t_index);
+	    }
+
+	    /*
+	     * Bad smell will force a reduction in strength
+	     */
+	    if (on(*mp, CANSMELL)) {
+		turn_off(*mp, CANSMELL);
+		if (save(VS_MAGIC, &player, 0) || ISWEARING(R_SUSABILITY))
+		    msg("You smell an unpleasant odor.");
+		else {
+		    int odor_str = -(rnd(6)+1);
+
+		    msg("You are overcome by a foul odor.");
+		    if (lost_str == 0) {
+			chg_str(odor_str);
+			fuse(res_strength, 0, SMELLTIME, AFTER);
+			lost_str -= odor_str;
+		    }
+		    else lengthen(res_strength, SMELLTIME);
+		}
+	    }
+
+	    /*
+	     * Paralyzation
+	     */
+	    if (on(*mp, CANPARALYZE)) {
+		turn_off(*mp, CANPARALYZE);
+		if (!save(VS_PARALYZATION, &player, 0)) {
+		    if (on(player, CANINWALL))
+			msg("The %s's touch has no effect.", mname);
+		    else {
+			msg("The %s's touch paralyzes you.", mname);
+			no_command += FREEZETIME;
+		    }
+		}
+	    }
+
+	    /*
+	     * Painful wounds make you faint
+	     */
+	     if (on(*mp, CANPAIN)) {
+		turn_off(*mp, CANPAIN);
+		if (!ISWEARING(R_ALERT) && !save(VS_POISON, &player, 0)) {
+			msg("You faint from the painful wound");
+			no_command += PAINTIME;
+		}
+	    }
+
+	    /*
+	     * The monsters touch slows the hero down
+	     */
+	     if (on(*mp, CANSLOW)) {
+		turn_off(*mp, CANSLOW);
+		if (!save(VS_PARALYZATION, &player, 0)) 
+			add_slow();
+	    }
+
+	    /*
+	     * Rotting
+	     */
+	    if (on(*mp, CANROT)) {
+		if (!ISWEARING(R_HEALTH) && 
+		    !save(VS_POISON, &player, 0)     && 
+		    off(player, DOROT)) {
+		    turn_on(player, DOROT);
+		    msg("You feel your skin starting to rot away!");
+		}
+	    }
+
+	    if (on(*mp, STEALGOLD)) {
+		/*
+		 * steal some gold
+		 */
+		register long lastpurse;
+		register struct linked_list *item;
+		register struct object *obj;
+
+		lastpurse = purse;
+		purse -= GOLDCALC + GOLDCALC;
+		if (!save(VS_MAGIC, &player, mp->t_stats.s_lvl/10)) {
+		    if (on(*mp, ISUNIQUE))
+			purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
+		    purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
+		}
+		if (purse < 0)
+		    purse = 0;
+		if (purse != lastpurse) {
+		    msg("Your purse feels lighter");
+
+		    /* Give the gold to the thief */
+		    for (item=mp->t_pack; item != NULL; item=next(item)) {
+			obj = OBJPTR(item);
+			if (obj->o_type == GOLD) {
+			    obj->o_count += lastpurse - purse;
+			    break;
+			}
+		    }
+
+		    /* Did we do it? */
+		    if (item == NULL) {	/* Then make some */
+			item = new_item(sizeof *obj);
+			obj = OBJPTR(item);
+			obj->o_type = GOLD;
+			obj->o_count = lastpurse - purse;
+			obj->o_hplus = obj->o_dplus = 0;
+			strcpy(obj->o_damage,"0d0");
+                        strcpy(obj->o_hurldmg,"0d0");
+			obj->o_ac = 11;
+			obj->contents = NULL;
+			obj->o_group = 0;
+			obj->o_flags = 0;
+			obj->o_mark[0] = '\0';
+			obj->o_pos = mp->t_pos;
+
+			attach(mp->t_pack, item);
+		    }
+		}
+
+		turn_on(*mp, ISFLEE);
+		turn_on(*mp, ISINVIS);
+	    }
+
+	    if (on(*mp, STEALMAGIC)) {
+		register struct linked_list *list, *steal;
+		register struct object *obj;
+		register int nobj;
+
+		/*
+		 * steal a magic item, look through the pack
+		 * and pick out one we like.
+		 */
+		steal = NULL;
+		for (nobj = 0, list = pack; list != NULL; list = next(list))
+		{
+		    obj = OBJPTR(list);
+		    if (!is_current(obj) &&
+			is_magic(obj)	 && 
+			rnd(++nobj) == 0)
+			    steal = list;
+		}
+		if (steal != NULL)
+		{
+		    register struct object *obj;
+		    struct linked_list *item;
+
+		    obj = OBJPTR(steal);
+		    if (on(*mp, ISUNIQUE))
+			monsters[mp->t_index].m_normal = TRUE;
+		    item = find_mons(mp->t_pos.y, mp->t_pos.x);
+		    killed(item, FALSE, FALSE);
+		    if (obj->o_count > 1 && obj->o_group == 0) {
+			register int oc;
+
+			oc = --(obj->o_count);
+			obj->o_count = 1;
+			sprintf(outstring,"The %s stole %s!", mname, inv_name(obj, TRUE));
+			msg(outstring);
+			obj->o_count = oc;
+		    }
+		    else {
+			sprintf(outstring,"The %s stole %s!", mname, inv_name(obj, TRUE));
+			msg(outstring);
+			detach(pack, steal);
+
+			/* If this is a relic, clear its holding field */
+			if (obj->o_type == RELIC)
+			    cur_relic[obj->o_which] = 0;
+
+			o_discard(steal);
+		        inpack--;
+		    }
+		    updpack(FALSE);
+		}
+	    }
+	}
+    }
+    else {
+	/* If the thing was trying to surprise, no good */
+	if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE);
+
+	else if (thrown) m_bounce(weapon, mp, mname);
+	else miss(weapon, mp, mname, NULL);
+    }
+    if (fight_flush)
+	md_flushinp();
+    count = 0;
+    status(FALSE);
+    return(did_hit);
+}
+
+/*
+ * swing:
+ *	returns true if the swing hits
+ */
+
+swing(class, at_lvl, op_arm, wplus)
+short class;
+int at_lvl, op_arm, wplus;
+{
+    register int res = rnd(20)+1;
+    register int need;
+
+    need = att_mat[class].base -
+	   att_mat[class].factor *
+	   ((min(at_lvl, att_mat[class].max_lvl) -
+	    att_mat[class].offset)/att_mat[class].range) +
+	   (10 - op_arm);
+    if (need > 20 && need <= 25) need = 20;
+
+    return (res+wplus >= need);
+}
+
+/*
+ * roll_em:
+ *	Roll several attacks
+ */
+
+roll_em(att_er, def_er, weap, hurl, cur_weapon, back_stab)
+struct thing *att_er, *def_er;
+struct object *weap;
+bool hurl;
+struct object *cur_weapon;
+bool back_stab;
+{
+    register struct stats *att, *def;
+    register char *cp = NULL;
+    register int ndice, nsides, nplus, def_arm;
+    bool did_hit = FALSE;
+    int prop_hplus, prop_dplus;
+    int vampiric_damage;
+
+    /* Get statistics */
+    att = &att_er->t_stats;
+    def = &def_er->t_stats;
+
+    prop_hplus = prop_dplus = 0;
+    if (weap == NULL)
+	cp = att->s_dmg;
+    else if (hurl) {
+	if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
+	  cur_weapon->o_which == weap->o_launch)
+	{
+	    cp = weap->o_hurldmg;
+	    prop_hplus = cur_weapon->o_hplus;
+	    prop_dplus = cur_weapon->o_dplus;
+	}
+	else
+	    cp = (weap->o_flags&ISMISL ? weap->o_damage : weap->o_hurldmg);
+    }
+    else {
+	if (weap->o_type == RELIC) {
+	    switch (weap->o_which) {
+		case MUSTY_DAGGER:	cp = "1d4+1/1d4+1";
+		when YEENOGHU_FLAIL:	cp = "3d6/paralyze/confuse";
+		when HRUGGEK_MSTAR:	cp = "3d10";
+		when MING_STAFF:	cp = "1d8";
+		when ASMO_ROD:		cp = "2d8+1";
+		when ORCUS_WAND:	cp = "destroy";
+	    }
+	}
+	else cp = weap->o_damage;
+	/*
+	 * Drain a staff of striking
+	 */
+	if (weap->o_type == STICK && weap->o_which == WS_HIT
+	    && weap->o_charges == 0)
+		{
+		    strcpy(weap->o_damage,"0d0");
+		    weap->o_hplus = weap->o_dplus = 0;
+		}
+    }
+    for (;;)
+    {
+	int damage;
+	int hplus = prop_hplus;
+	int dplus = prop_dplus;
+
+	if (weap != NULL && weap->o_type == RELIC) {
+	    switch (weap->o_which) {
+		case MUSTY_DAGGER:
+		    if (att != &pstats || /* Not player or good stats */
+			(str_compute() > 15 && dex_compute() > 15)) {
+
+			hplus += 6;
+			dplus += 6;
+
+			/* Give an additional strength and dex bonus */
+			if (att == &pstats) {
+			    hplus += str_plus(str_compute()) +
+				     dext_plus(dex_compute());
+			    dplus += dext_plus(dex_compute()) +
+				     add_dam(str_compute());
+			}
+			else {
+			    hplus += str_plus(att->s_str) +
+				     dext_plus(att->s_dext);
+			    dplus += dext_plus(att->s_dext) +
+				     add_dam(att->s_str);
+			}
+		    }
+		    else {
+			hplus -= 3;
+			dplus -= 3;
+		    }
+		when YEENOGHU_FLAIL:
+		case HRUGGEK_MSTAR:
+		    hplus += 3;
+		    dplus += 3;
+		when MING_STAFF:
+		    hplus += 2;
+		    dplus += 2;
+	    }
+	}
+	else if (weap != NULL) {
+	    hplus += weap->o_hplus;
+	    dplus += weap->o_dplus;
+	}
+
+	/* Is attacker weak? */
+	if (on(*att_er, HASSTINK)) hplus -= 2;
+
+	if (att == &pstats)	/* Is the attacker the player? */
+	{
+	    hplus += hitweight();	/* adjust for encumberence */
+	    dplus += hung_dam();	/* adjust damage for hungry player */
+	    dplus += ring_value(R_ADDDAM);
+	}
+	if (back_stab || (weap && att != &pstats && on(*att_er, CANBSTAB)))
+	    hplus += 4;	/* add in pluses for backstabbing */
+
+	/* Get the damage */
+	while (isspace(*cp)) cp++;
+	if (!isdigit(*cp)) {
+	    if (strncmp(cp, "confuse", 7) == 0) ndice = CONF_DAMAGE;
+	    else if (strncmp(cp, "paralyze", 8) == 0) ndice = PARAL_DAMAGE;
+	    else if (strncmp(cp, "destroy", 7) == 0) ndice = DEST_DAMAGE;
+	    else ndice = 0;
+	    nsides = 0;
+	    nplus = 0;
+	}
+	else {
+	    char *oldcp;
+
+	    /* Get the number of damage dice */
+	    ndice = atoi(cp);
+	    if ((cp = strchr(cp, 'd')) == NULL)
+		break;
+
+	    /* Skip the 'd' and get the number of sides per die */
+	    nsides = atoi(++cp);
+
+	    /* Check for an addition -- save old place in case none is found */
+	    oldcp = cp;
+	    if ((cp = strchr(cp, '+')) != NULL) nplus = atoi(++cp);
+	    else {
+		nplus = 0;
+		cp = oldcp;
+	    }
+	}
+
+	if (def == &pstats) { /* Monster attacks player */
+	    def_arm = ac_compute() - dext_prot(dex_compute());
+	    hplus += str_plus(att->s_str)+dext_plus(att->s_dext);
+	}
+	else {	/* Player attacks monster */
+	    def_arm = def->s_arm - dext_prot(def->s_dext);
+	    hplus += str_plus(str_compute())+dext_plus(dex_compute());
+	}
+
+	if (swing(att_er->t_ctype, att->s_lvl, def_arm, hplus)) {
+	    register int proll;
+
+	    /* Take care of special effects */
+	    switch (ndice) {
+	      case CONF_DAMAGE:
+		if (def == &pstats) { /* Monster attacks player */
+		    if (!save(VS_MAGIC, &player, 0) && off(player, ISCLEAR)) {
+			msg("You feel disoriented.");
+			if (find_slot(unconfuse))
+			    lengthen(unconfuse, rnd(8)+HUHDURATION);
+			else
+			    fuse(unconfuse, 0, rnd(8)+HUHDURATION, AFTER);
+			turn_on(player, ISHUH);
+		    }
+		    else msg("You feel dizzy, but it quickly passes.");
+		}
+		/* Player hits monster */
+		else if (!save(VS_MAGIC, def_er, 0) && off(*def_er, ISCLEAR)) { 
+		    msg("The artifact warms with pleasure.");
+		    turn_on(*def_er, ISHUH);
+		}
+		did_hit = TRUE;
+	      when PARAL_DAMAGE:
+		if (def == &pstats) { /* Monster attacks player */
+		    if (!save(VS_MAGIC, &player, 0) && off(player, CANINWALL)) {
+			msg("You stiffen up.");
+			no_command += FREEZETIME;
+		    }
+		}
+		else if (!save(VS_MAGIC, def_er, 0)) { /* Player hits monster */
+		    msg("The artifact hums happily.");
+		    turn_off(*def_er, ISRUN);
+		    turn_on(*def_er, ISHELD);
+		}
+		did_hit = TRUE;
+	      when DEST_DAMAGE:
+		if (def == &pstats) { /* Monster attacks player */
+		    msg("You feel a tug at your life force.");
+		    if (!save(VS_MAGIC, &player, -4)) {
+			msg("The wand devours your soul.");
+			def->s_hpt = 0;
+		    }
+		}
+		/* Player hits monster */
+		else if (!save(VS_MAGIC, def_er, -4)) {
+		    msg("The artifact draws energy.");
+
+		    /* Give the player half the monster's hits */
+		    att->s_hpt += def->s_hpt/2;
+		    if (att->s_hpt > att_er->maxstats.s_hpt)
+			att->s_hpt = att_er->maxstats.s_hpt;
+
+		    /* Kill the monster */
+		    def->s_hpt = 0;
+		}
+		did_hit = TRUE;
+	      otherwise:
+		/* Heil's ankh always gives maximum damage */
+		if (att == &pstats && cur_relic[HEIL_ANKH])
+		    proll = ndice * nsides;
+		else proll = roll(ndice, nsides);
+
+		if (ndice + nsides > 0 && proll < 1)
+		    debug("Damage for %dd%d came out %d.",
+				ndice, nsides, proll);
+		damage = dplus + proll + nplus;
+		if (def == &pstats)
+		    damage += add_dam(att->s_str);
+		else
+		    damage += add_dam(str_compute());
+
+		/* Check for half damage monsters */
+		if (on(*def_er, HALFDAMAGE)) damage /= 2;
+
+		/* add in multipliers for backstabbing */
+		if (back_stab || 
+		    (weap && att != &pstats && on(*att_er, CANBSTAB))) {
+		    int mult = 2 + (att->s_lvl-1)/4; /* Normal multiplier */
+
+		    if (mult > 5 && att != &pstats) 
+			mult = 5;/*be nice with maximum of 5x for monsters*/
+		    if (weap->o_type == RELIC && weap->o_which == MUSTY_DAGGER)
+			mult++;
+		    damage *= mult;
+		}
+
+		/* Check for no-damage and division */
+		if (on(*def_er, BLOWDIVIDE)) {
+		    damage = 0;
+		    creat_mons(def_er, def_er->t_index, FALSE);
+		    light(&hero);
+		}
+		/* check for immunity to metal -- RELICS are always bad */
+		if (on(*def_er, NOMETAL) && weap != NULL &&
+		    weap->o_type != RELIC && weap->o_flags & ISMETAL) {
+		    damage = 0;
+		}
+
+		/*
+		 * If defender is wearing a cloak of displacement -- no damage
+		 * the first time. (unless its a hurled magic missile)
+		 */
+		if ( ((weap == NULL) || weap->o_type != MISSILE) &&
+		    def == &pstats				 &&	
+		    cur_misc[WEAR_CLOAK] != NULL		 &&
+		    cur_misc[WEAR_CLOAK]->o_which == MM_DISP &&
+		    off(*att_er, MISSEDDISP)) {
+		    damage = 0;
+		    did_hit = FALSE;
+		    turn_on(*att_er, MISSEDDISP);
+		    if (cansee(att_er->t_pos.y, att_er->t_pos.x) &&
+			!invisible(att_er))
+			msg("The %s looks amazed",
+				monsters[att_er->t_index].m_name);
+		}
+		else {
+		    def->s_hpt -= max(0, damage);	/* Do the damage */
+		    did_hit = TRUE;
+		}
+
+		vampiric_damage = damage;
+		if (def->s_hpt < 0)	/* only want REAL damage inflicted */
+		    vampiric_damage += def->s_hpt;
+                if (vampiric_damage < 0)
+                    vampiric_damage = 0;
+		if (att == &pstats && ISWEARING(R_VAMPREGEN) && !hurl) {
+		    if ((pstats.s_hpt += vampiric_damage/2) > max_stats.s_hpt)
+			pstats.s_hpt = max_stats.s_hpt;
+		}
+		debug ("hplus=%d dmg=%d", hplus, damage);
+	    }
+	}
+	if ((cp = strchr(cp, '/')) == NULL)
+	    break;
+	cp++;
+    }
+    return did_hit;
+}
+
+/*
+ * prname:
+ *	The print name of a combatant
+ */
+
+char *
+prname(who, upper)
+register char *who;
+bool upper;
+{
+    static char tbuf[LINELEN];
+
+    *tbuf = '\0';
+    if (who == 0)
+	strcpy(tbuf, "you"); 
+    else if (on(player, ISBLIND))
+	strcpy(tbuf, "it");
+    else
+    {
+	strcpy(tbuf, "the ");
+	strcat(tbuf, who);
+    }
+    if (upper)
+	*tbuf = toupper(*tbuf);
+    return tbuf;
+}
+
+/*
+ * hit:
+ *	Print a message to indicate a succesful hit
+ */
+
+hit(weapon, tp, er, ee, back_stab)
+register struct object *weapon;
+register struct thing *tp;
+register char *er, *ee;
+bool back_stab;
+{
+    register char *s = NULL;
+    char 
+    	          att_name[80],	/* Name of attacker */
+		  def_name[80];/* Name of defender */
+    bool see_monst = !invisible(tp);	/* Can the player see the monster? */
+
+    /* What do we call the attacker? */
+    if (er == NULL) {	/* Player is attacking */
+	strcpy(att_name, prname(er, TRUE));
+	strcpy(def_name, see_monst ? prname(ee, FALSE) : "something");
+    }
+    else {
+	strcpy(att_name, see_monst ? prname(er, TRUE) : "Something");
+
+	/* If the monster is using a weapon and we can see it, report it */
+	if (weapon != NULL && see_monst) {
+	    strcat(att_name, "'s ");
+	    strcat(att_name, weap_name(weapon));
+	}
+
+	strcpy(def_name, prname(ee, FALSE));
+    }
+
+    addmsg(att_name);
+    if (terse) {
+	if (back_stab)
+	    s = " backstab!";
+	else
+	    s = " hit.";
+    }
+    else {
+	if (back_stab)
+	    s = (er == 0 ? " have backstabbed " : " has backstabbed ");
+	else {
+	    switch (rnd(4))
+	    {
+		case 0: s = " scored an excellent hit on ";
+		when 1: s = " hit ";
+		when 2: s = (er == 0 ? " have injured " : " has injured ");
+		when 3: s = (er == 0 ? " swing and hit " : " swings and hits ");
+	    }
+	}
+    }
+    addmsg(s);
+    if (!terse)
+	addmsg(def_name);
+    endmsg();
+}
+
+/*
+ * miss:
+ *	Print a message to indicate a poor swing
+ */
+
+miss(weapon, tp, er, ee)
+register struct object *weapon;
+register struct thing *tp;
+register char *er, *ee;
+{
+    register char *s = NULL;
+    char
+    	          att_name[80],	/* Name of attacker */
+		  def_name[80];/* Name of defender */
+    bool see_monst = !invisible(tp);	/* Can the player see the monster? */
+
+    /* What do we call the attacker? */
+    if (er == NULL) {	/* Player is attacking */
+	strcpy(att_name, prname(er, TRUE));
+	strcpy(def_name, see_monst ? prname(ee, FALSE) : "something");
+    }
+    else {
+	strcpy(att_name, see_monst ? prname(er, TRUE) : "Something");
+
+	/* If the monster is using a weapon and we can see it, report it */
+	if (weapon != NULL && see_monst) {
+	    strcat(att_name, "'s ");
+	    strcat(att_name, weap_name(weapon));
+	}
+
+	strcpy(def_name, prname(ee, FALSE));
+    }
+
+    addmsg(att_name);
+    switch (terse ? 0 : rnd(4))
+    {
+	case 0: s = (er == 0 ? " miss" : " misses");
+	when 1: s = (er == 0 ? " swing and miss" : " swings and misses");
+	when 2: s = (er == 0 ? " barely miss" : " barely misses");
+	when 3: s = (er == 0 ? " don't hit" : " doesn't hit");
+    }
+    addmsg(s);
+    if (!terse)
+	addmsg(" %s", def_name);
+    endmsg();
+}
+
+/*
+ * dext_plus:
+ *	compute to-hit bonus for dexterity
+ */
+
+dext_plus(dexterity)
+register int dexterity;
+{
+	return (dexterity > 10 ? (dexterity-13)/3 : (dexterity-10)/3);
+}
+
+
+/*
+ * dext_prot:
+ *	compute armor class bonus for dexterity
+ */
+
+dext_prot(dexterity)
+register int dexterity;
+{
+    return ((dexterity-10)/2);
+}
+/*
+ * str_plus:
+ *	compute bonus/penalties for strength on the "to hit" roll
+ */
+
+str_plus(str)
+register short str;
+{
+    return((str-10)/3);
+}
+
+/*
+ * add_dam:
+ *	compute additional damage done for exceptionally high or low strength
+ */
+
+add_dam(str)
+register short str;
+{
+    return((str-9)/2);
+}
+
+/*
+ * hung_dam:
+ *	Calculate damage depending on players hungry state
+ */
+hung_dam()
+{
+	reg int howmuch = 0;
+
+	switch(hungry_state) {
+		case F_OKAY:
+		case F_HUNGRY:	howmuch = 0;
+		when F_WEAK:	howmuch = -1;
+		when F_FAINT:	howmuch = -2;
+	}
+	return howmuch;
+}
+
+/*
+ * thunk:
+ *	A missile hits a monster
+ */
+
+thunk(weap, tp, mname)
+register struct object *weap;
+register struct thing *tp;	/* Defender */
+register char *mname;
+{
+    char *def_name;	/* Name of defender */
+
+    /* What do we call the defender? */
+    if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp))
+	def_name = "something";
+    else def_name = prname(mname, FALSE);
+
+    if (weap->o_type == WEAPON){
+	sprintf(outstring,"The %s hits %s", weaps[weap->o_which].w_name, def_name);
+	msg(outstring);
+    }
+    else if (weap->o_type == MISSILE){
+	sprintf(outstring,"The %s hits %s",ws_magic[weap->o_which].mi_name, def_name);
+	msg(outstring);
+    }
+    else
+	msg("You hit %s.", def_name);
+}
+
+/*
+ * mthunk:
+ *	 A missile from a monster hits the player
+ */
+
+m_thunk(weap, tp, mname)
+register struct object *weap;
+register struct thing *tp;
+register char *mname;
+{
+    char *att_name;	/* Name of attacker */
+
+    /* What do we call the attacker? */
+    if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp))
+	att_name = "Something";
+    else att_name = prname(mname, TRUE);
+
+    if (weap->o_type == WEAPON){
+	sprintf(outstring,"%s's %s hits you.", att_name, weaps[weap->o_which].w_name);
+	msg(outstring);
+    }
+    else if (weap->o_type == MISSILE){
+	sprintf(outstring,"%s's %s hits you.", att_name, ws_magic[weap->o_which].mi_name);
+	msg(outstring);
+    }
+    else
+	msg("%s hits you.", att_name);
+}
+
+/*
+ * bounce:
+ *	A missile misses a monster
+ */
+
+bounce(weap, tp, mname)
+register struct object *weap;
+register struct thing *tp;	/* Defender */
+register char *mname;
+{
+    char *def_name;	/* Name of defender */
+
+    /* What do we call the defender? */
+    if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp))
+	def_name = "something";
+    else def_name = prname(mname, FALSE);
+
+    if (weap->o_type == WEAPON){
+	sprintf(outstring,"The %s misses %s",weaps[weap->o_which].w_name, def_name);
+	msg(outstring);
+    }
+    else if (weap->o_type == MISSILE){
+	sprintf(outstring,"The %s misses %s",ws_magic[weap->o_which].mi_name, def_name);
+	msg(outstring);
+    }
+    else
+	msg("You missed %s.", def_name);
+}
+
+/*
+ * m_bounce:
+	  A missle from a monster misses the player
+ */
+
+m_bounce(weap, tp, mname)
+register struct object *weap;
+register struct thing *tp;
+register char *mname;
+{
+    char *att_name;	/* Name of attacker */
+
+    /* What do we call the attacker? */
+    if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp))
+	att_name = "Something";
+    else att_name = prname(mname, TRUE);
+
+    if (weap->o_type == WEAPON){
+	sprintf(outstring,"%s's %s misses you.", att_name, weaps[weap->o_which].w_name);
+	msg(outstring);
+    }
+    else if (weap->o_type == MISSILE){
+	sprintf(outstring,"%s's %s misses you.", att_name, ws_magic[weap->o_which].mi_name);
+	msg(outstring);
+    }
+    else
+	msg("%s misses you.", att_name);
+}
+
+
+/*
+ * is_magic:
+ *	Returns true if an object radiates magic
+ */
+
+is_magic(obj)
+register struct object *obj;
+{
+    switch (obj->o_type)
+    {
+	case ARMOR:
+	    return obj->o_ac != armors[obj->o_which].a_class;
+	when WEAPON:
+	    return obj->o_hplus != 0 || obj->o_dplus != 0;
+	when POTION:
+	case SCROLL:
+	case STICK:
+	case RING:
+	case MM:
+	case RELIC:
+	    return TRUE;
+    }
+    return FALSE;
+}
+
+/*
+ * killed:
+ *	Called to put a monster to death
+ */
+
+killed(item, pr, points)
+register struct linked_list *item;
+bool pr, points;
+{
+    register struct thing *tp;
+    register struct linked_list *pitem, *nexti;
+    const char *monst;
+
+    tp = THINGPTR(item);
+
+    if (pr)
+    {
+	addmsg(terse ? "Defeated " : "You have defeated ");
+	if (on(player, ISBLIND))
+	    msg("it.");
+	else
+	{
+	    if (cansee(tp->t_pos.y, tp->t_pos.x) && !invisible(tp))
+		monst = monsters[tp->t_index].m_name;
+	    else {
+		if (terse) monst = "something";
+		else monst = "thing";
+	    }
+	    if (!terse)
+		addmsg("the ");
+	    msg("%s.", monst);
+	}
+    }
+
+    /* Take care of any residual effects of the monster */
+    check_residue(tp);
+
+    if (points) {
+	unsigned long test;	/* For overflow check */
+
+	test = pstats.s_exp + tp->t_stats.s_exp;
+
+	/* Do an overflow check before increasing experience */
+	if (test > pstats.s_exp) pstats.s_exp = test;
+
+	/*
+	 * Do adjustments if he went up a level
+	 */
+	check_level(TRUE);
+    }
+
+    /*
+     * Empty the monsters pack
+     */
+    pitem = tp->t_pack;
+
+    /*
+     * Get rid of the monster.
+     */
+    mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' ');
+    mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); 
+    detach(mlist, item);
+    /*
+     * empty his pack
+     */
+    while (pitem != NULL)
+    {
+	nexti = next(tp->t_pack);
+	(OBJPTR(pitem))->o_pos = tp->t_pos;
+	detach(tp->t_pack, pitem);
+	if (points) 
+	    fall(pitem, FALSE);
+	else 
+	    o_discard(pitem);
+	pitem = nexti;
+    }
+    turn_on(*tp, ISDEAD);
+    attach(monst_dead, item);
+}
+
+
+/*
+ * Returns a pointer to the weapon the monster is wielding corresponding to
+ * the given thrown weapon.  If no thrown item is given, try to find any
+ * decent weapon.
+ */
+
+struct object *
+wield_weap(thrown, mp)
+struct object *thrown;
+struct thing *mp;
+{
+    int look_for = 0,	/* The projectile weapon we are looking for */
+	new_rate,	/* The rating of a prospective weapon */
+        cand_rate = -1; /* Rating of current candidate -- higher is better */
+    register struct linked_list *pitem;
+    register struct object *obj, *candidate = NULL;
+
+    if (thrown != NULL) {	/* Using a projectile weapon */
+      switch (thrown->o_which) {
+	case BOLT:	look_for = CROSSBOW;	/* Find the crossbow */
+	when ARROW:	look_for = BOW;		/* Find the bow */
+	when ROCK:	look_for = SLING;	/* find the sling */
+	otherwise:	return(NULL);
+      }
+    }
+    else if (off(*mp, ISUNIQUE) && off(*mp, CARRYWEAPON)) return(NULL);
+
+    for (pitem=mp->t_pack; pitem; pitem=next(pitem)) {
+	obj = OBJPTR(pitem);
+
+	/*
+	 * If we have a thrown weapon, just return the first match
+	 * we come to.
+	 */
+	if (thrown != NULL && obj->o_type == WEAPON && obj->o_which == look_for)
+	    return(obj);
+
+	/* If we have a usable RELIC, return it */
+	if (thrown == NULL && obj->o_type == RELIC) {
+	    switch (obj->o_which) {
+		case MUSTY_DAGGER:
+		case YEENOGHU_FLAIL:
+		case HRUGGEK_MSTAR:
+		case MING_STAFF:
+		case ASMO_ROD:
+		case ORCUS_WAND:
+		    return(obj);
+	    }
+	}
+
+	/* Otherwise if it's a usable weapon, it is a good candidate */
+	else if (thrown == NULL && obj->o_type == WEAPON) {
+	    switch (obj->o_which) {
+		case DAGGER:
+		    new_rate = 0;
+		when BATTLEAXE:
+		    new_rate = 1;
+		when MACE:
+		    new_rate = 2;
+		when SWORD:
+		    new_rate = 3;
+		when PIKE:
+		    new_rate = 4;
+		when HALBERD:
+		case SPETUM:
+		    new_rate = 6;
+		when BARDICHE:
+		    new_rate = 7;
+		when TRIDENT:
+		    new_rate = 8;
+		when BASWORD:
+		    new_rate = 9;
+		when TWOSWORD:
+		    new_rate = 10;
+		otherwise:
+		    new_rate = -1;
+	    }
+
+	    /* Only switch if this is better than the current candidate */
+	    if (new_rate > cand_rate) {
+		cand_rate = new_rate;
+		candidate = obj;
+	    }
+	}
+    }
+
+    return(candidate);
+}
+
+explode(tp)
+register struct thing *tp;
+{
+
+    register int x,y, damage;
+    struct linked_list *item;
+    struct thing *th;
+
+    msg("the %s explodes!", monsters[tp->t_index].m_name);
+    /*
+     * check to see if it got the hero
+     */
+     if (DISTANCE(hero.x, hero.y, tp->t_pos.x, tp->t_pos.y) <= 25) {
+	msg("the explosion hits you");
+	damage = roll(6,6);
+	if (save(VS_WAND, &player, 0))
+	    damage /= 2;
+	if ((pstats.s_hpt -= damage) <= 0)
+	    death(tp->t_index);
+    }
+
+    /*
+     * now check for monsters in vicinity
+     */
+     for (x = tp->t_pos.x-5; x<=tp->t_pos.x+5; x++) {
+	 if (x < 0 || x > COLS - 1) 
+	     continue;
+	 for (y = tp->t_pos.y-5; y<=tp->t_pos.y+5; y++) {
+	    if (y < 1 || y > LINES - 3)
+		continue;
+	    if (isalpha(mvwinch(mw, y, x))) {
+		if ((item = find_mons(y, x)) != NULL) {
+		    th = THINGPTR(item);
+		    if (th == tp) /* don't count gas spore */
+			continue;
+		    damage = roll(6, 6);
+		    if (save(VS_WAND, th, 0))
+			damage /= 2;
+		    if ((tp->t_stats.s_hpt -= damage) <= 0) {
+			msg("the explosion kills the %s",
+				monsters[th->t_index].m_name);
+			killed(item, FALSE, FALSE);
+		    }
+		}
+	    }
+	}
+    }
+}