/*
 * spells.c: code for player and creature spells, breaths, wands, scrolls,
 * etc. 
 *
 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke 
 *
 * This software may be copied and distributed for educational, research, and
 * not for profit purposes provided that this copyright and statement are
 * included in all such copies. 
 */

#include "constant.h"
#include "config.h"
#include "types.h"
#include "monster.h"
#include "externs.h"

#ifdef USG
#ifndef ATARIST_MWC
#include <string.h>
#endif
#else
#ifndef VMS
#include <strings.h>
#endif
#endif

#ifndef NO_LINT_ARGS
#ifdef __STDC__
static char bolt_shape(int);
static void ball_destroy(int, int (**) ());
static void pause_if_screen_full(int *, int);
static void spell_hit_monster(monster_type *, int, int *, int, int *, int *);
static void replace_spot(int, int, int);
#else
static char         bolt_shape();
static void         ball_destroy();
static void         pause_if_screen_full();
static void         spell_hit_monster();
static void         replace_spot();
#endif
#endif

extern int          set_plasma_destroy();
extern int          set_meteor_destroy();
extern int          set_mana_destroy();
extern int          set_holy_destroy();


/* Following are spell procedure/functions			-RAK-	 */
/* These routines are commonly used in the scroll, potion, wands, and	 */
/* staves routines, and are occasionally called from other areas.	  */
/* Now included are creature spells also.		       -RAK    */

static char 
bolt_shape(dir)			   /* added for bolts, minor nicety... -CFT */
    int                 dir;
{
    switch (dir) {
      case 1:
      case 9:
	return '/';
      case 2:
      case 8:
	return '|';
      case 3:
      case 7:
	return '\\';
      case 4:
      case 6:
	return '-';
    }
    return '*';			   /* should never happen... -CFT */
}

/*
 * return the appropriate item destroy test to the typ.  All that's left of
 * get_flags().  -CFT 
 */
/*
 * add new destroys?  maybe GF_FORCE destroy potions, GF_PLASMA as lightning,
 * GF_SHARDS and GF_ICE maybe break things (potions?), and GF_METEOR breaks
 * potions and burns scrolls?  not yet, but it's an idea... -CFT 
 */
static void 
ball_destroy(typ, destroy)
    int                 typ;
    int                 (**destroy) ();

{
    switch (typ) {
      case GF_FIRE:
	*destroy = set_fire_destroy;
	break;
      case GF_ACID:
	*destroy = set_acid_destroy;
	break;
      case GF_FROST:
      case GF_SHARDS:
      case GF_ICE:
      case GF_FORCE:
      case GF_SOUND:
	*destroy = set_frost_destroy;	/* just potions and flasks -DGK */
	break;
      case GF_LIGHTNING:
	*destroy = set_lightning_destroy;
	break;
      case GF_PLASMA:		   /* DGK */
	*destroy = set_plasma_destroy;	/* fire+lightning -DGK */
	break;
      case GF_METEOR:		   /* DGK */
	*destroy = set_meteor_destroy;	/* fire+shards -DGK */
	break;
      case GF_MANA:		   /* DGK */
	*destroy = set_mana_destroy;	/* everything -DGK */
	break;
      case GF_HOLY_ORB:	   /* DGK */
	*destroy = set_holy_destroy;	/* cursed stuff -DGK */
	break;
      case GF_MAGIC_MISSILE:
      case GF_POISON_GAS:
      case GF_ARROW:
      case GF_NETHER:
      case GF_WATER:
      case GF_CHAOS:
      case GF_CONFUSION:
      case GF_DISENCHANT:
      case GF_NEXUS:
      case GF_INERTIA:
      case GF_LIGHT:
      case GF_DARK:
      case GF_TIME:
      case GF_GRAVITY:
	*destroy = set_null;
	break;
      default:
	msg_print("Unknown typ in ball_destroy().  This may mean trouble.");
	*destroy = set_null;
	break;
    }
}

void 
monster_name(m_name, m_ptr, r_ptr)
    char               *m_name;
    monster_type       *m_ptr;
    creature_type      *r_ptr;
{
    if (!m_ptr->ml)
	(void)strcpy(m_name, "It");
    else {
	if (r_ptr->cdefense & UNIQUE)
	    (void)sprintf(m_name, "%s", r_ptr->name);
	else
	    (void)sprintf(m_name, "The %s", r_ptr->name);
    }
}

void 
lower_monster_name(m_name, m_ptr, r_ptr)
    char               *m_name;
    monster_type       *m_ptr;
    creature_type      *r_ptr;
{
    if (!m_ptr->ml)
	(void)strcpy(m_name, "it");
    else {
	if (r_ptr->cdefense & UNIQUE)
	    (void)sprintf(m_name, "%s", r_ptr->name);
	else
	    (void)sprintf(m_name, "the %s", r_ptr->name);
    }
}

/* teleport you a level (or three:-) */
void 
tele_level()
{
    if (dun_level == Q_PLANE)
	dun_level = 0;
    else if (is_quest(dun_level))
	dun_level -= 1;
    else
	dun_level += (-3) + 2 * randint(2);
    if (dun_level < 0)
	dun_level = 0;
    new_level_flag = TRUE;
}

/* Sleep creatures adjacent to player			-RAK-	 */
int 
sleep_monsters1(y, x)
    int                 y, x;
{
    register int        i, j;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    int                 sleep;
    vtype               out_val, m_name;

    sleep = FALSE;
    for (i = y - 1; i <= y + 1; i++)
	for (j = x - 1; j <= x + 1; j++) {
	    c_ptr = &cave[i][j];
	    if (c_ptr->cptr > 1) {
		m_ptr = &m_list[c_ptr->cptr];
		r_ptr = &c_list[m_ptr->mptr];

		monster_name(m_name, m_ptr, r_ptr);
		if ((r_ptr->level >
		     randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
		    (CHARM_SLEEP & r_ptr->cdefense) || (r_ptr->cdefense & UNIQUE)) {
		    if (m_ptr->ml && (r_ptr->cdefense & CHARM_SLEEP))
			c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
		    (void)sprintf(out_val, "%s is unaffected.", m_name);
		    msg_print(out_val);
		} else {
		    sleep = TRUE;
		    m_ptr->csleep = 500;
		    (void)sprintf(out_val, "%s falls asleep.", m_name);
		    msg_print(out_val);
		}
	    }
	}
    return (sleep);
}

int 
lose_all_info()
{
    int                 i;

    for (i = 0; i <= INVEN_AUX; i++) {
	if (inventory[i].tval != TV_NOTHING)
	    inventory[i].ident &= ~(ID_KNOWN2);
    }
    wizard_light(-1);
    return (0);
}

void 
identify_pack()
{
    int                 i;
    inven_type         *i_ptr;

    for (i = 0; i <= INVEN_AUX; i++) {
	if (inventory[i].tval != TV_NOTHING)
	    identify(&i);
	i_ptr = &inventory[i];
	known2(i_ptr);
    }
}

/* Detect any treasure on the current panel		-RAK-	 */
int 
detect_treasure()
{
    register int        i, j, detect;
    register cave_type *c_ptr;

    detect = FALSE;
    for (i = panel_row_min; i <= panel_row_max; i++)
	for (j = panel_col_min; j <= panel_col_max; j++) {
	    c_ptr = &cave[i][j];
	    if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval == TV_GOLD) &&
		!test_light(i, j)) {
		c_ptr->fm = TRUE;
		lite_spot(i, j);
		detect = TRUE;
	    }
	}
    return (detect);
}

int                 special_check();


/*
 * This will light up all spaces with "magic" items, including potions,
 * scrolls, rods, wands, staves, amulets, rings, and "enchanted" items. This
 * excludes all foods and spell books. -- JND  
 */
int 
detect_magic()
{
    register int        i, j, detect;
    register cave_type *c_ptr;
    register inven_type *t_ptr;
    int                 Tval;

    detect = FALSE;
    for (i = panel_row_min; i <= panel_row_max; i++)
	for (j = panel_col_min; j <= panel_col_max; j++) {
	    c_ptr = &cave[i][j];
	    if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval < TV_MAX_OBJECT)
		&& !test_light(i, j)) {
		t_ptr = &t_list[c_ptr->tptr];
		Tval = t_ptr->tval;
		if (((Tval > 9) && (Tval < 39)) &&	/* Is it a weapon or
							 * armor or light? */
		    (((t_ptr->tohit > 0) || (t_ptr->todam) || (t_ptr->toac)
	    /* If so, check for plusses on weapons and armor ... */
		      || (t_ptr->flags2 & TR_ARTIFACT))
	    /* ... and check whether it is an artifact! ;)  */
		     || ((Tval > 39) && (Tval < 77)))){	/* Is it otherwise
							 * magical? */
		    c_ptr->fm = TRUE;
		    lite_spot(i, j);
		    detect = TRUE;
		}
	    }
	}
    return (detect);
}



int 
detect_enchantment()
{
    register int        i, j, detect;
    register cave_type *c_ptr;

    detect = FALSE;
    for (i = panel_row_min; i <= panel_row_max; i++)
	for (j = panel_col_min; j <= panel_col_max; j++) {
	    c_ptr = &cave[i][j];
	    if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval < TV_MAX_OBJECT)
		&& !test_light(i, j)) {
		if (special_check(&(t_list[c_ptr->tptr]))) {
		    c_ptr->fm = TRUE;
		    lite_spot(i, j);
		    detect = TRUE;
		}
	    }
	}
    return (detect);
}

int 
detection()
{
    register int        i, detect;
    register monster_type *m_ptr;

    detect_treasure();
    detect_object();
    detect_trap();
    detect_sdoor();

    detect = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx)) {
	    m_ptr->ml = TRUE;
	/* works correctly even if hallucinating */
	    print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
		  (int)m_ptr->fx);
	    detect = TRUE;
	}
    }
    if (detect) {
	msg_print("You sense the presence of monsters!");
	msg_print(NULL);
    /* must unlight every monster just lighted */
	creatures(FALSE);
    }
    return (detect);
}

/* Detect all objects on the current panel		-RAK-	 */
int 
detect_object()
{
    register int        i, j, detect;
    register cave_type *c_ptr;

    detect = FALSE;
    for (i = panel_row_min; i <= panel_row_max; i++)
	for (j = panel_col_min; j <= panel_col_max; j++) {
	    c_ptr = &cave[i][j];
	    if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval < TV_MAX_OBJECT)
		&& !test_light(i, j)) {
		c_ptr->fm = TRUE;
		lite_spot(i, j);
		detect = TRUE;
	    }
	}
    return (detect);
}


/* Locates and displays traps on current panel		-RAK-	 */
int 
detect_trap()
{
    register int        i, j;
    int                 detect;
    register cave_type *c_ptr;
    register inven_type *t_ptr;

    detect = FALSE;
    for (i = panel_row_min; i <= panel_row_max; i++)
	for (j = panel_col_min; j <= panel_col_max; j++) {
	    c_ptr = &cave[i][j];
	    if (c_ptr->tptr != 0)
		if (t_list[c_ptr->tptr].tval == TV_INVIS_TRAP) {
		    c_ptr->fm = TRUE;
		    change_trap(i, j);
		    detect = TRUE;
		} else if (t_list[c_ptr->tptr].tval == TV_CHEST) {
		    t_ptr = &t_list[c_ptr->tptr];
		    known2(t_ptr);
		}
	}
    return (detect);
}

void 
stair_creation()
{
    register cave_type *c_ptr;
    register int        cur_pos;

    c_ptr = &cave[char_row][char_col];

    if ((c_ptr->tptr == 0) ||
	((t_list[c_ptr->tptr].tval != TV_STORE_DOOR) &&	/* if not store, or */
	 ((t_list[c_ptr->tptr].tval < TV_MIN_WEAR) ||	/* if no artifact here
							 * -CFT */
	  (t_list[c_ptr->tptr].tval > TV_MAX_WEAR) ||
	  !(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)))) {
	if (c_ptr->tptr != 0)
	    (void)delete_object(char_row, char_col);
	cur_pos = popt();
	c_ptr->tptr = cur_pos;
	if ((randint(2) == 1 || is_quest(dun_level)) && (dun_level > 0))
	    invcopy(&t_list[cur_pos], OBJ_UP_STAIR);
	else
	    invcopy(&t_list[cur_pos], OBJ_DOWN_STAIR);
    } else
	msg_print("The object resists the spell.");
}

/* Surround the player with doors.			-RAK-	 */
int 
door_creation()
{
    register int        i, j, door;
    int                 k;
    register cave_type *c_ptr;

    door = FALSE;
    for (i = char_row - 1; i <= char_row + 1; i++)
	for (j = char_col - 1; j <= char_col + 1; j++)
	    if ((i != char_row) || (j != char_col)) {
		c_ptr = &cave[i][j];
		if (c_ptr->fval <= MAX_CAVE_FLOOR) {
		    if ((c_ptr->tptr == 0) ||
			((t_list[c_ptr->tptr].tval != TV_UP_STAIR) 
				/* if not stairs or a store */
			 &&(t_list[c_ptr->tptr].tval != TV_DOWN_STAIR)
			 && (t_list[c_ptr->tptr].tval != TV_STORE_DOOR)) ||
			(t_list[c_ptr->tptr].tval < TV_MIN_WEAR) ||
			(t_list[c_ptr->tptr].tval > TV_MAX_WEAR) ||
			!(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) {
				/* if no artifact here -CFT */
			door = TRUE;
			if (c_ptr->tptr != 0)
			    (void)delete_object(i, j);
			k = popt();
			c_ptr->fval = BLOCKED_FLOOR;
			c_ptr->tptr = k;
			invcopy(&t_list[k], OBJ_CLOSED_DOOR);
			lite_spot(i, j);
		    } else
			msg_print("The object resists the spell.");
		}
	    }
    return (door);
}

/* Locates and displays all secret doors on current panel -RAK-	 */
int 
detect_sdoor()
{
    register int        i, j, detect;
    register cave_type *c_ptr;

    detect = FALSE;
    for (i = panel_row_min; i <= panel_row_max; i++)
	for (j = panel_col_min; j <= panel_col_max; j++) {
	    c_ptr = &cave[i][j];
	    if (c_ptr->tptr != 0)
	    /* Secret doors  */
		if (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR) {
		    c_ptr->fm = TRUE;
		    change_trap(i, j);
		    detect = TRUE;
		}
	/* Staircases	 */
		else if (((t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
			  (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR)) &&
			 !c_ptr->fm) {
		    c_ptr->fm = TRUE;
		    lite_spot(i, j);
		    detect = TRUE;
		}
	}
    return (detect);
}


/* Locates and displays all invisible creatures on current panel -RAK- */
int 
detect_invisible()
{
    register int        i, flag;
    register monster_type *m_ptr;

    flag = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
	    (CM_INVISIBLE & c_list[m_ptr->mptr].cmove)) {
	    m_ptr->ml = TRUE;
	/* works correctly even if hallucinating */
	    print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
		  (int)m_ptr->fx);
	    flag = TRUE;
	}
    }
    if (flag) {
	msg_print("You sense the presence of invisible creatures!");
	msg_print(NULL);
    /* must unlight every monster just lighted */
	creatures(FALSE);
    }
    return (flag);
}


/* Split out of light_line.       -DGK */
void 
mon_light_dam(y, x, dam)
    int                 y, x, dam;
{
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;
    int                 i;

    c_ptr = &cave[y][x];
    if (c_ptr->cptr > 1) {
	m_ptr = &m_list[c_ptr->cptr];
	r_ptr = &c_list[m_ptr->mptr];
	monster_name(m_name, m_ptr, r_ptr);
	m_ptr->csleep = 0;
	if (HURT_LIGHT & r_ptr->cdefense) {
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= HURT_LIGHT;
	    i = mon_take_hit((int)c_ptr->cptr, dam, FALSE);
	    if (i >= 0) {
		(void)sprintf(out_val, "%s shrivels away in the light!", m_name);
		msg_print(out_val);
		prt_experience();
	    } else {
		(void)sprintf(out_val, "%s cringes from the light!", m_name);
		msg_print(out_val);
	    }
	}
    }
}


int 
light_area(y, x, dam, rad)	   /* Expanded -DGK */
    register int        y, x, dam, rad;
{
    register int        i, j;
    int                 min_i, max_i, min_j, max_j;

    if (rad < 1) rad = 1;	/* sanity check -CWS */
    if (py.flags.blind < 1)
	msg_print("You are surrounded by a white light.");

    if ((cave[y][x].fval == LIGHT_FLOOR) && (panel_contains(y, x)))
	light_room(y, x);

    if (cave[y][x].lr && (dun_level > 0) && !(cave[y][x].pl))
		light_room(y, x); /* dbd - fix lighting radius */

    /* replace a check for in_bounds2 every loop with 4 quick computations -CWS */
    min_i = MY_MAX(0, (y - rad));
    max_i = MY_MIN(cur_height, (y + rad));
    min_j = MY_MAX(0, (x - rad));
    max_j = MY_MIN(cur_width, (x + rad));

    for (i = min_i; i <= max_i; i++)
	for (j = min_j; j <= max_j; j++)
	    if (los(y, x, i, j) && (distance(y, x, i, j) <= rad)) {
		if (cave[y][x].lr && (dun_level > 0))
		    light_room(y, x);
		cave[i][j].pl = TRUE;
		lite_spot(i, j);
		if (dam)
		    mon_light_dam(i, j, dam / (rad == 0 ? 1 : rad));
	    }
    return (TRUE);
}


/* Darken an area, opposite of light area		-RAK-	 */
int 
unlight_area(y, x)
    int                 y, x;
{
    register int        i, j, unlight;
    register cave_type *c_ptr;
    int                 min_i, max_i, min_j, max_j;

    unlight = FALSE;
    if (cave[y][x].lr && (dun_level > 0)) {
	darken_room(y, x);
	unlight = TRUE;		   /* this isn't really good, as it returns
				    * true, even if rm was already dark, but
				    * at least scrolls of darkness will be
				    * IDed when used -CFT */
    } else {
	min_i = MY_MAX(0, (y - 3));
	max_i = MY_MIN(cur_height, (y + 3));
	min_j = MY_MAX(0, (x - 3));
	max_j = MY_MIN(cur_width, (x + 3));
	
	/* replace a check for in_bounds2 every loop with 4 quick computations -CWS */
	
	for (i = min_i; i <= max_i; i++)
	    for (j = min_j; j <= max_j; j++) {
		c_ptr = &cave[i][j];
		if ((c_ptr->fval == CORR_FLOOR) && (c_ptr->pl || c_ptr->lr)) {
		    /* pl could have been set by star-lite wand, etc */
		    c_ptr->pl = FALSE;
		    c_ptr->tl = FALSE;
		    unlight = TRUE;
		}
	    }
    }
    if (unlight && py.flags.blind <= 0)
	msg_print("Darkness surrounds you.");

    return (unlight);
}


/* Map the current area plus some			-RAK-	 */
void 
map_area()
{
    register cave_type *c_ptr;
    register int        i7, i8, n, m;
    int                 i, j, k, l;

    i = panel_row_min - randint(10);
    j = panel_row_max + randint(10);
    k = panel_col_min - randint(20);
    l = panel_col_max + randint(20);
    for (m = i; m <= j; m++)
	for (n = k; n <= l; n++)
	    if (in_bounds(m, n) && (cave[m][n].fval <= MAX_CAVE_FLOOR))
		for (i7 = m - 1; i7 <= m + 1; i7++)
		    for (i8 = n - 1; i8 <= n + 1; i8++) {
			c_ptr = &cave[i7][i8];
			if (c_ptr->fval >= MIN_CAVE_WALL)
			    c_ptr->pl = TRUE;
			else if ((c_ptr->tptr != 0) &&
			     (t_list[c_ptr->tptr].tval >= TV_MIN_VISIBLE) &&
			       (t_list[c_ptr->tptr].tval <= TV_MAX_VISIBLE))
			    c_ptr->fm = TRUE;
		    }
    prt_map();
}


/* Identify an object					-RAK-	 */
int 
ident_spell()
{
    int                 item_val;
    bigvtype            out_val, tmp_str;
    register int        ident;
    register inven_type *i_ptr;

    ident = FALSE;
    if (get_item(&item_val, "Item you wish identified?", 0, INVEN_ARRAY_SIZE, 0)) {
	ident = TRUE;
	identify(&item_val);
	i_ptr = &inventory[item_val];
	known2(i_ptr);
	objdes(tmp_str, i_ptr, TRUE);
	if (item_val >= INVEN_WIELD) {
	    calc_bonuses();
	    (void)sprintf(out_val, "%s: %s", describe_use(item_val), tmp_str);
	} else
	    (void)sprintf(out_val, "%c %s", item_val + 97, tmp_str);
	msg_print(out_val);
    }
    return (ident);
}


/* Get all the monsters on the level pissed off.	-RAK-	 */
int 
aggravate_monster(dis_affect)
    int                 dis_affect;
{
    register int        i, aggravate;
    register monster_type *m_ptr;

    aggravate = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	m_ptr->csleep = 0;
	if ((m_ptr->cdis <= dis_affect) && (m_ptr->cspeed < 2)) {
	    m_ptr->cspeed++;
	    aggravate = TRUE;
	}
    }
    if (aggravate)
	msg_print("You hear a sudden stirring in the distance!");
    return (aggravate);
}


/* Surround the fool with traps (chuckle)		-RAK-	 */
int 
trap_creation()
{
    register int        i, j, trap;
    register cave_type *c_ptr;

    trap = FALSE;
    for (i = char_row - 1; i <= char_row + 1; i++)
	for (j = char_col - 1; j <= char_col + 1; j++) {
	    if ((i == char_row) && (j == char_col))
		continue;	   /* no trap under player, from um55 -CFT */
	    c_ptr = &cave[i][j];
	    if (c_ptr->fval <= MAX_CAVE_FLOOR) {
		if ((c_ptr->tptr == 0) ||
		    ((t_list[c_ptr->tptr].tval != TV_UP_STAIR)
		     /* if not stairs or a store */
		     &&(t_list[c_ptr->tptr].tval != TV_DOWN_STAIR)
		     && (t_list[c_ptr->tptr].tval != TV_STORE_DOOR)) ||
		    (t_list[c_ptr->tptr].tval < TV_MIN_WEAR) ||
		    (t_list[c_ptr->tptr].tval > TV_MAX_WEAR) ||
		    !(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) {
				/* if no artifact here -CFT */
		    trap = TRUE;
		    if (c_ptr->tptr != 0)
			(void)delete_object(i, j);
		    place_trap(i, j, randint(MAX_TRAP) - 1);
		/* don't let player gain exp from the newly created traps */
		    t_list[c_ptr->tptr].p1 = 0;
		/* open pits are immediately visible, so call lite_spot */
		    lite_spot(i, j);
		} else
		    msg_print("The object resists the spell.");
	    }
	}
    return (trap);
}


/* Destroys any adjacent door(s)/trap(s)		-RAK-	 */
int 
td_destroy()
{
    register int        i, j, destroy;
    register cave_type *c_ptr;

    destroy = FALSE;
    for (i = char_row - 1; i <= char_row + 1; i++)
	for (j = char_col - 1; j <= char_col + 1; j++) {
	    c_ptr = &cave[i][j];
	    if (c_ptr->tptr != 0) {
		if (((t_list[c_ptr->tptr].tval >= TV_INVIS_TRAP) &&
		     (t_list[c_ptr->tptr].tval <= TV_CLOSED_DOOR) &&
		     (t_list[c_ptr->tptr].tval != TV_RUBBLE)) ||
		    (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR)) {
		    if (delete_object(i, j))
			destroy = TRUE;
		} else if (t_list[c_ptr->tptr].tval == TV_CHEST) {
		/* destroy traps on chest and unlock */
		    t_list[c_ptr->tptr].flags &= ~(CH_TRAPPED | CH_LOCKED);
		    t_list[c_ptr->tptr].name2 = SN_DISARMED;
		    msg_print("You have disarmed the chest.");
		    known2(&t_list[c_ptr->tptr]);
		    destroy = TRUE;
		}
	    }
	}
    return (destroy);
}


/* Display all creatures on the current panel		-RAK-	 */
int 
detect_monsters()
{
    register int        i, detect;
    register monster_type *m_ptr;

    detect = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
	    ((CM_INVISIBLE & c_list[m_ptr->mptr].cmove) == 0)) {
	    m_ptr->ml = TRUE;
	/* works correctly even if hallucinating */
	    print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
		  (int)m_ptr->fx);
	    detect = TRUE;
	}
    }
    if (detect) {
	msg_print("You sense the presence of monsters!");
	msg_print(NULL);
    /* must unlight every monster just lighted */
	creatures(FALSE);
    }
    return (detect);
}


/* Leave a line of light in given dir, blue light can sometimes	 */
/* hurt creatures.				       -RAK-   */
void 
light_line(dir, y, x)
    int                 dir, y, x;
{
    register cave_type *c_ptr;
    int                 dist, flag;

    dist = (-1);
    flag = FALSE;
    do {
    /* put mmove at end because want to light up current spot */
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	if (!c_ptr->pl && !c_ptr->tl) {
	/* set pl so that lite_spot will work */
	    c_ptr->pl = TRUE;
	    if (c_ptr->fval == LIGHT_FLOOR) {
		if (panel_contains(y, x))
		    light_room(y, x);
	    } else
		lite_spot(y, x);
	}
    /* set pl in case tl was true above */
	c_ptr->pl = TRUE;
	mon_light_dam(y, x, damroll(6, 8));
	(void)mmove(dir, &y, &x);
    }
    while (!flag);
}


/* Leave a line of frost in given dir -DGK */
void 
frost_line(dir, y, x, dam)
    int                 dir, y, x, dam;
{
    register int        i;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    int                 dist, flag, d;
    vtype               out_val, cdesc;
    int                 xx, yy;

    xx = x;
    yy = y;
    dist = (-1);
    flag = FALSE;
    do {
    /* put mmove at end because want to damage current spot */
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else {
	/* print a blue * at y,x */
	    if (panel_contains(y, x)) {
#ifdef TC_COLOR
		if (!no_color_flag)
		    textcolor(bolt_color(GF_FROST));
#endif
		print('*', y, x);
#ifdef TC_COLOR
		if (!no_color_flag)
		    textcolor(LIGHTGRAY);	/* prob don't need here,
						 * but... -CFT */
#endif
	    }
	    if (c_ptr->cptr > 1) {
		m_ptr = &m_list[c_ptr->cptr];
		r_ptr = &c_list[m_ptr->mptr];
	    /* light up and draw monster */
		update_mon((int)c_ptr->cptr);
		m_ptr->csleep = 0;
		if (m_ptr->ml) {
		    if (r_ptr->cdefense & UNIQUE)
			sprintf(cdesc, "%s", r_ptr->name);
		    else
			sprintf(cdesc, "The %s", r_ptr->name);
		} else
		    strcpy(cdesc, "It");
		if (r_ptr->cdefense & IM_FROST) {
		    if (!(py.flags.status & PY_BLIND)) {
			sprintf(out_val, "%s resists.", cdesc);
			msg_print(out_val);
		    }
		    d = dam / 9;
		    if (m_ptr->ml)
			c_recall[m_ptr->mptr].r_cdefense |= IM_FROST;
		} else
		    d = dam;
		i = mon_take_hit((int)c_ptr->cptr, d, TRUE);
		if (i >= 0) {
		    (void)sprintf(out_val,
				  "%s dies in a fit of agony.", cdesc);
		    msg_print(out_val);
		    prt_experience();
		} else {
		    (void)sprintf(out_val,
				  pain_message((int)c_ptr->cptr, d), cdesc);
		    msg_print(out_val);
		}
	    }
	}
	(void)mmove(dir, &y, &x);
    }
    while (!flag);

#ifdef MSDOS
    delay(30 * delay_spd);	   /* millisecs */
#else
    usleep(30000 * delay_spd);	   /* useconds */
#endif

/* Now go through and erase the line. */
    dist = (-1);
    flag = FALSE;
    do {
    /* put mmove at end because want to damage current spot */
	dist++;
	c_ptr = &cave[yy][xx];
	if ((dist >= OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else
	    lite_spot(yy, xx);
	(void)mmove(dir, &yy, &xx);
    }
    while (!flag);
}


/* Light line in all directions				-RAK-	 */
void 
starlite(y, x)
    register int        y, x;
{
    register int        i;

    if (py.flags.blind < 1)
	msg_print("The end of the staff bursts into a blue shimmering light.");
    for (i = 1; i <= 9; i++)
	if (i != 5)
	    light_line(i, y, x);
}

/* Disarms all traps/chests in a given direction	-RAK-	 */
int 
disarm_all(dir, y, x)
    int                 dir, y, x;
{
    register cave_type *c_ptr;
    register inven_type *t_ptr;
    register int        disarm, dist;

    disarm = FALSE;
    dist = (-1);
    do {
    /* put mmove at end, in case standing on a trap */
	dist++;
	c_ptr = &cave[y][x];
    /*
     * note, must continue upto and including the first non open space,
     * because secret doors have fval greater than MAX_OPEN_SPACE 
     */
	if (c_ptr->tptr != 0) {
	    t_ptr = &t_list[c_ptr->tptr];
	    if ((t_ptr->tval == TV_INVIS_TRAP) || (t_ptr->tval == TV_VIS_TRAP)) {
		if (delete_object(y, x))
		    disarm = TRUE;
	    } else if (t_ptr->tval == TV_CLOSED_DOOR)
		t_ptr->p1 = 0;	   /* Locked or jammed doors become merely
				    * closed. */
	    else if (t_ptr->tval == TV_SECRET_DOOR) {
		c_ptr->fm = TRUE;
		change_trap(y, x);
		disarm = TRUE;
	    } else if ((t_ptr->tval == TV_CHEST) && (t_ptr->flags != 0)) {
		msg_print("Click!");
		t_ptr->flags &= ~(CH_TRAPPED | CH_LOCKED);
		disarm = TRUE;
		t_ptr->name2 = SN_UNLOCKED;
		known2(t_ptr);
	    }
	}
	(void)mmove(dir, &y, &x);
    }
    while ((dist <= OBJ_BOLT_RANGE) && c_ptr->fval <= MAX_OPEN_SPACE);
    return (disarm);
}


/* Shoot a bolt in a given direction			-RAK-	 */
void 
fire_bolt(typ, dir, y, x, dam_hp, bolt_typ)
    int                 typ, dir, y, x, dam_hp;
    const char               *bolt_typ;
{
    int                 i, oldy, oldx, dist, flag;
/*    int32u              harm_type = 0; */
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;
    int                 dam = dam_hp;
    int                 ny, nx;
    char                bolt_char;

    flag = FALSE;
    oldy = y;
    oldx = x;
    dist = 0;
    do {
	ny = y;
	nx = x;
	(void)mmove(dir, &y, &x);
    /* choose the right shape for the bolt... -CFT */
	if (ny == y)
	    bolt_char = '-';
	else if (nx == x)
	    bolt_char = '|';
	else if ((ny - y) == (nx - x))
	    bolt_char = '\\';
	else
	    bolt_char = '/';

	dist++;
	c_ptr = &cave[y][x];
	lite_spot(oldy, oldx);
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else {
	    if (c_ptr->cptr > 1) {
		flag = TRUE;
		m_ptr = &m_list[c_ptr->cptr];
		r_ptr = &c_list[m_ptr->mptr];
	    /*
	     * light up monster and draw monster, temporarily set pl so that
	     * update_mon() will work 
	     */
		i = c_ptr->pl;
		c_ptr->pl = TRUE;
		update_mon((int)c_ptr->cptr);
		c_ptr->pl = i;
	    /* draw monster and clear previous bolt */
		put_qio();

		spell_hit_monster(m_ptr, typ, &dam, 0, &ny, &nx);
		c_ptr = &cave[ny][nx];	/* may be new location if teleported
					 * by gravity warp... */
		m_ptr = &m_list[c_ptr->cptr];	/* and even if not, may be
						 * new monster if chaos
						 * polymorphed */
		r_ptr = &c_list[m_ptr->mptr];
		monster_name(m_name, m_ptr, r_ptr);
		i = mon_take_hit((int)c_ptr->cptr, dam, TRUE);

		if (i >= 0) {
		    if ((r_ptr->cdefense & (DEMON|UNDEAD|MINDLESS)) ||
			(r_ptr->cchar == 'E') ||
			(r_ptr->cchar == 'v') ||
			(r_ptr->cchar == 'g'))
			(void)sprintf(out_val, "%s is destroyed.",
				      m_name);
		    else
			(void)sprintf(out_val, "%s dies in a fit of agony.",
				      m_name);
		    msg_print(out_val);
		    prt_experience();
		} else if (dam > 0) {
		    (void)sprintf(out_val,
			       pain_message((int)c_ptr->cptr, dam), m_name);
		    msg_print(out_val);
		}
	    } else if (panel_contains(y, x) && (py.flags.blind < 1)) {
		print(bolt_char, y, x);
	    /* show the bolt */
		put_qio();
#ifdef MSDOS
		delay(8 * delay_spd);	/* milliseconds */
#else
		usleep(8000 * delay_spd);	/* useconds */
#endif
	    }
	}
	oldy = y;
	oldx = x;
#ifdef TARGET
	if (target_mode && at_target(y,x))
	    flag = TRUE; /* must have hit "targeted" area -CFT */
#endif
    }
    while (!flag);
    lite_spot(oldy, oldx);	   /* just in case, clear any leftover bolt
				    * images -CFT */
}


/* Shoot a bolt in a given direction                    -RAK-   */
/* heavily modified to include exotic bolts -CFT */
void 
bolt(typ, y, x, dam_hp, ddesc, ptr, monptr)
    int                 typ, y, x, dam_hp;
    char               *ddesc;
    monster_type       *ptr;
    int                 monptr;
{
    int                 i = ptr->fy, j = ptr->fx;
    int                 dam;
    int32u              tmp, treas;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    char                bolt_char;
    int                 blind = (py.flags.status & PY_BLIND) ? 1 : 0;
    int                 ny, nx, sourcey, sourcex, dist;
    vtype               m_name, out_val;

    sourcey = i;
    sourcex = j;
    dist = 0;
    do {
    /* This is going along a badly angled line so call mmove2 direct */
	ny = i;
	nx = j;
	mmove2(&i, &j, sourcey, sourcex, char_row, char_col);
	dist++;

    /* choose the right shape for the bolt... -CFT */
	if (ny == i)
	    bolt_char = '-';
	else if (nx == j)
	    bolt_char = '|';
	else if ((ny - i) == (nx - j))
	    bolt_char = '\\';
	else
	    bolt_char = '/';

	if (in_bounds(i, j) && los(y, x, i, j)) {
	    c_ptr = &cave[i][j];
	    if (c_ptr->fval <= MAX_OPEN_SPACE) {
		if (panel_contains(i, j) && !(py.flags.status & PY_BLIND)) {
		    print(bolt_char, i, j);
		    put_qio();
#ifdef MSDOS
		    delay(8 * delay_spd);	/* milliseconds */
#else
		    usleep(8000 * delay_spd);	/* useconds */
#endif
		    lite_spot(i, j);
		}
		if (c_ptr->cptr > 1 && c_ptr->cptr != monptr) {
		    m_ptr = &m_list[c_ptr->cptr];
		    dam = dam_hp;

		    spell_hit_monster(m_ptr, typ, &dam, 0, &ny, &nx);
				/* process hit effects */
		    c_ptr = &cave[ny][nx];	/* may be new location if
						 * teleported by gravity
						 * warp... */
		    m_ptr = &m_list[c_ptr->cptr];	/* and even if not, may
							 * be new monster if
							 * chaos polymorphed */
		    r_ptr = &c_list[m_ptr->mptr];
		    monster_name(m_name, m_ptr, r_ptr);

		    if (dam < 1)
			dam = 1;   /* protect vs neg damage -CFT */
		    m_ptr->hp = m_ptr->hp - dam;
		    m_ptr->csleep = 0;
		    if ((r_ptr->cdefense & UNIQUE) && (m_ptr->hp < 0))
			m_ptr->hp = 0;	/* prevent unique monster from death
					 * by other monsters.  It causes
					 * trouble (monster not marked as
					 * dead, quest monsters don't satisfy
					 * quest, etc).  So, we let then
					 * live, but extremely wimpy. -CFT */
		    if (m_ptr->hp < 0) {
			if ((r_ptr->cdefense & (DEMON|UNDEAD|MINDLESS)) ||
			    (r_ptr->cchar == 'E') ||
			    (r_ptr->cchar == 'v') ||
			    (r_ptr->cchar == 'g'))
			    (void)sprintf(out_val, "%s is destroyed.",
					  m_name);
			else
			    (void)sprintf(out_val, "%s dies in a fit of agony.",
					  m_name);
			msg_print(out_val);
			object_level = (dun_level + r_ptr->level) >> 1;
			treas = monster_death((int)m_ptr->fy, (int)m_ptr->fx,
					      r_ptr->cmove, 0, 0);
			if (m_ptr->ml || (c_list[m_ptr->mptr].cdefense & UNIQUE)) {
			    tmp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE)
				>> CM_TR_SHIFT;
			    if (tmp > ((treas & CM_TREASURE) >> CM_TR_SHIFT))
				treas = (treas & ~CM_TREASURE) | (tmp << CM_TR_SHIFT);
			    c_recall[m_ptr->mptr].r_cmove = treas |
				(c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE);
			}
			if (monptr < c_ptr->cptr)
			    delete_monster((int)c_ptr->cptr);
			else
			    fix1_delete_monster((int)c_ptr->cptr);
		    } else {
			(void)sprintf(out_val, pain_message((int)c_ptr->cptr, dam),
				      m_name);
			msg_print(out_val);
		    }
		    break;
		} else if (c_ptr->cptr == 1) {
		    if (dam_hp < 1)
			dam_hp = 1;
		    m_ptr = &m_list[monptr];
		    switch (typ) {
		      case GF_LIGHTNING:
			if (blind)
			    msg_print("You are hit by electricity!");
			light_dam(dam_hp, ddesc);
			break;
		      case GF_POISON_GAS:
			if (blind)
			    msg_print("You are hit by a blast of noxious gases!");
			poison_gas(dam_hp, ddesc);
			break;
		      case GF_ACID:
			if (blind)
			    msg_print("You are hit by a jet of acidic fluid!");
			acid_dam(dam_hp, ddesc);
			break;
		      case GF_FROST:
			if (blind)
			    msg_print("You are hit by something cold!");
			cold_dam(dam_hp, ddesc);
			break;
		      case GF_FIRE:
			if (blind)
			    msg_print("You are hit by something hot!");
			fire_dam(dam_hp, ddesc);
			break;
		      case GF_MAGIC_MISSILE:
			if (blind)
			    msg_print("You are hit by something!");
			take_hit(dam_hp, ddesc);
			break;
		      case GF_HOLY_ORB:
			if (blind)
			    msg_print("You are hit by something!");
			dam_hp /= 2;	/* player should take less damage
					 * -CFT */
			take_hit(dam_hp, ddesc);
			break;
		      case GF_ARROW:	/* maybe can miss? */
			if (blind)
			    msg_print("You are hit by something!");
			take_hit(dam_hp, ddesc);
			break;
		      case GF_PLASMA:	/* no resist to plasma? */
			if (blind)
			    msg_print("You are hit by something!");
			take_hit(dam_hp, ddesc);
			break;
		      case GF_NETHER:
			if (blind)
			    msg_print("You are hit by an unholy blast!");
			if (py.flags.nether_resist) {
			    dam_hp *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
			    dam_hp /= (randint(6) + 6);	/* .858 to .5 -CFT */
			} else {   /* no resist */
			    if (py.flags.hold_life && randint(5) > 1)
				msg_print("You keep hold of your life force!");
			    else if (py.flags.hold_life) {
				msg_print("You feel your life slipping away!");
				lose_exp(200 + (py.misc.exp / 1000) * MON_DRAIN_LIFE);
			    } else {
				msg_print("You feel your life draining away!");
				lose_exp(200 + (py.misc.exp / 100) * MON_DRAIN_LIFE);
			    }
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_WATER:
			if (blind)
			    msg_print("You are hit by a jet of water!");
			if (!py.flags.sound_resist)
			    stun_player(randint(15));
			take_hit(dam_hp, ddesc);
			break;
		      case GF_CHAOS:
			if (blind)
			    msg_print("You are hit by wave of entropy!");
			if (py.flags.chaos_resist) {
			    dam_hp *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
			    dam_hp /= (randint(6) + 6);	/* .858 to .5 -CFT */
			}
			if ((!py.flags.confusion_resist) && (!py.flags.chaos_resist)) {
			    if (py.flags.confused > 0)
				py.flags.confused += 12;
			    else
				py.flags.confused = randint(20) + 10;
			}
			if (!py.flags.chaos_resist)
			    py.flags.image += randint(10);
			take_hit(dam_hp, ddesc);
			break;
		      case GF_SHARDS:
			if (blind)
			    msg_print("You are cut by sharp fragments!");
			if (py.flags.shards_resist) {
			    dam_hp *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
			    dam_hp /= (randint(6) + 6);	/* .858 to .5 -CFT */
			} else {
			    cut_player(dam_hp);	/* ouch! */
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_SOUND:
			if (blind)
			    msg_print("You are deafened by a blast of noise!");
			if (py.flags.sound_resist) {
			    dam_hp *= 5;
			    dam_hp /= (randint(6) + 6);
			} else {
			    stun_player(randint((dam_hp > 60) ? 25 : (dam_hp / 3 + 5)));
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_CONFUSION:
			if (blind)
			    msg_print("You are hit by a wave of dizziness!");
			if (py.flags.confusion_resist) {
			    dam_hp *= 5;
			    dam_hp /= (randint(6) + 6);
			}
			if (!py.flags.confusion_resist && !py.flags.chaos_resist) {
			    if (py.flags.confused > 0)
				py.flags.confused += 8;
			    else
				py.flags.confused = randint(15) + 5;
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_DISENCHANT:
			if (blind)
			    msg_print("You are hit by something!");
			if (py.flags.disenchant_resist) {
			    dam_hp *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
			    dam_hp /= (randint(6) + 6);	/* .858 to .5 -CFT */
			} else {
			    int8u               disenchant = FALSE;
			    int8u               chance;
			    int                 t = 0;
			    inven_type         *i_ptr;

			    switch (randint(7)) {
			      case 1:
				t = INVEN_BODY;
				break;
			      case 2:
				t = INVEN_BODY;
				break;
			      case 3:
				t = INVEN_ARM;
				break;
			      case 4:
				t = INVEN_OUTER;
				break;
			      case 5:
				t = INVEN_HANDS;
				break;
			      case 6:
				t = INVEN_HEAD;
				break;
			      case 7:
				t = INVEN_FEET;
				break;
			    }
			    i_ptr = &inventory[t];
			    chance = 1;
			    if (i_ptr->flags2 & TR_ARTIFACT)	/* Artifacts have 2/3 */
				chance = randint(3);	/* chance to resist -DGK */
			    if ((i_ptr->tohit > 0) && (chance == 1)) {
				i_ptr->tohit -= randint(2);
			    /* don't send it below zero */
				if (i_ptr->tohit < 0)
				    i_ptr->tohit = 0;
				disenchant = TRUE;
			    }
			    if ((i_ptr->todam > 0) && (chance == 1)) {
				i_ptr->todam -= randint(2);
			    /* don't send it below zero */
				if (i_ptr->todam < 0)
				    i_ptr->todam = 0;
				disenchant = TRUE;
			    }
			    if ((i_ptr->toac > 0) && (chance == 1)) {
				i_ptr->toac -= randint(2);
			    /* don't send it below zero */
				if (i_ptr->toac < 0)
				    i_ptr->toac = 0;
				disenchant = TRUE;
			    }
			    if (disenchant || (chance != 1)) {
				vtype               t1, t2;

				objdes(t1, &inventory[t], FALSE);
				if (chance != 1)
				    sprintf(t2, "Your %s (%c) %s disenchanted!", t1,
					    i + 'a' - INVEN_WIELD,
					    (inventory[i].number != 1) ? "were" : "was");
				else
				    sprintf(t2, "Your %s (%c) %s disenchantment!", t1,
					    i + 'a' - INVEN_WIELD,
					    (inventory[i].number != 1) ?
					    "resist" : "resists");
				msg_print(t2);
				calc_bonuses();
			    }
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_NEXUS:	/* no spec. effects from nexus bolt,
					 * only breath -CFT */
			if (blind)
			    msg_print("You are hit by something strange!");
			if (py.flags.nexus_resist) {
			    dam_hp *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
			    dam_hp /= (randint(6) + 6);	/* .858 to .5 -CFT */
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_FORCE:
			if (blind)
			    msg_print("You are hit hard by a sudden force!");
			if (!py.flags.sound_resist)
			    stun_player(randint(15) + 1);
			take_hit(dam_hp, ddesc);
			break;
		      case GF_INERTIA:
			if (blind)
			    msg_print("You are hit by something!");
			if ((py.flags.slow > 0) && (py.flags.slow < 32000))
			    py.flags.slow += randint(5);
			else {
			    msg_print("You feel less able to move.");
			    py.flags.slow = randint(5) + 3;
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_LIGHT:
			if (blind)
			    msg_print("You are hit by something!");
			if (py.flags.light_resist) {
			    dam_hp *= 4;	/* these 2 lines give avg dam
						 * of .444, ranging from */
			    dam_hp /= (randint(6) + 6);	/* .556 to .333 -CFT */
			} else if (!blind && !py.flags.blindness_resist) {
			    msg_print("You are blinded by the flash!");
			    py.flags.blind += randint(5) + 2;
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_DARK:
			if (blind)
			    msg_print("You are hit by something!");
			if (py.flags.dark_resist) {
			    dam_hp *= 4;	/* these 2 lines give avg dam
						 * of .444, ranging from */
			    dam_hp /= (randint(6) + 6);	/* .556 to .333 -CFT */
			} else {
			    if (!blind) 
				msg_print("The darkness prevents you from seeing!");
			    py.flags.blind += randint(5) + 2;
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_TIME:	/* only some effects from time bolt
					 * -CFT */
			if (blind)
			    msg_print("You are hit by something!");
			if (randint(2) == 1) {
			    msg_print("You feel life has clocked back.");
			    lose_exp(m_ptr->hp + (py.misc.exp / 300) * MON_DRAIN_LIFE);
			} else {
			    int                 t = 0;

			    switch (randint(6)) {
			      case 1:
				t = A_STR;
				msg_print("You're not as strong as you used to be...");
				break;
			      case 2:
				t = A_INT;
				msg_print("You're not as bright as you used to be...");
				break;
			      case 3:
				t = A_WIS;
				msg_print("You're not as wise as you used to be...");
				break;
			      case 4:
				t = A_DEX;
				msg_print("You're not as agile as you used to be...");
				break;
			      case 5:
				t = A_CON;
				msg_print("You're not as hale as you used to be...");
				break;
			      case 6:
				t = A_CHR;
				msg_print("You're not as beautiful as you used to be...");
				break;
			    }
			    py.stats.cur_stat[t] = (py.stats.cur_stat[t] * 3) / 4;
			    if (py.stats.cur_stat[t] < 3)
				py.stats.cur_stat[t] = 3;
			    set_use_stat(t);
			    prt_stat(t);
			}
			take_hit(dam_hp, ddesc);
			break;
		      case GF_GRAVITY:
			if (blind)
			    msg_print("You are hit by a surge of gravity!");
			if ((!py.flags.sound_resist) && (!py.flags.ffall))	/* DGK */
			    stun_player(randint(15) + 1);
			if (py.flags.ffall) {	/* DGK */
			    dam_hp *= 3;	/* these 2 lines give avg dam
						 * of .25, ranging from */
			    dam_hp /= (randint(6) + 6);	/* .427 to .25 -CFT */
			} else {   /* DGK */
			    if ((py.flags.slow > 0) && (py.flags.slow < 32000))
				py.flags.slow += randint(5);
			    else {
				msg_print("You feel less able to move.");
				py.flags.slow = randint(5) + 3;
			    }
			} /* DGK */
			take_hit(dam_hp, ddesc);
			break;
		      case GF_MANA:
			if (blind)
			    msg_print("You are hit by a beam of power!");
			take_hit(dam_hp, ddesc);
			break;
		      case GF_METEOR:
			if (blind)
			    msg_print("You are hit by something!");
			take_hit(dam_hp, ddesc);
			break;
		      case GF_ICE:
			if (blind)
			    msg_print("You are hit by something cold and sharp!");
			cold_dam(dam_hp, ddesc);
			if (!py.flags.sound_resist)
			    stun_player(randint(15) + 1);
			if (!py.flags.shards_resist)
			    cut_player(damroll(8, 10));
			break;
		      default:
			msg_print("Unknown typ in bolt().  This may mean trouble.");
		    }
		    disturb(1, 0);
		    break;
		}
	    }
	}
    } while ((i != char_row) || (j != char_col));
}

/* Shoot a ball in a given direction.  Note that balls have an  */
/* area affect.                                       -RAK-   */
void 
fire_ball(typ, dir, y, x, dam_hp, max_dis, descrip)
    int                 typ, dir, y, x, dam_hp, max_dis;
    const char          *descrip;
{
    register int        i, j;
    int                 dam, thit, tkill, k, tmp, monptr;
    int                 oldy, oldx, dist, flag;
    int                 (*destroy) ();
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    int                 ny, nx;
    char                bolt_char;

    thit = 0;
    tkill = 0;

    ball_destroy(typ, &destroy);

    flag = FALSE;
    oldy = y;
    oldx = x;
    dist = 0;
    do {
	ny = y;
	nx = x;
	(void)mmove(dir, &y, &x);

    /* choose the right shape for the bolt... -CFT */
	if (ny == y)
	    bolt_char = '-';
	else if (nx == x)
	    bolt_char = '|';
	else if ((ny - y) == (nx - x))
	    bolt_char = '\\';
	else
	    bolt_char = '/';

	dist++;
	lite_spot(oldy, oldx);
	if (dist > OBJ_BOLT_RANGE)
	    flag = TRUE;
	else {
	    c_ptr = &cave[y][x];
	/* targeting code stolen from Morgul -CFT */

	/*
	 * This test has been overhauled (twice):  basically, it now says: if
	 * ((spell hits a wall) OR ((spell hits a creature) and ((not
	 * targetting) or (at the target anyway) or (no line-of-sight to
	 * target, so aiming unusable) or ((aiming at a monster) and (that
	 * monster is unseen, so aiming unusable)))) OR ((we are targetting)
	 * and (at the target location))) THEN the ball explodes...                     
	 * -CFT  
	 */
#ifndef TARGET
	    if ((c_ptr->fval >= MIN_CLOSED_SPACE) ||
		((c_ptr->cptr > 1))) {
		flag = TRUE;	   /* THEN we decide to explode here. -CFT */
		if (c_ptr->fval >= MIN_CLOSED_SPACE) {
		    y = oldy;
		    x = oldx;
		}
#else
	    if ((c_ptr->fval >= MIN_CLOSED_SPACE) ||
		((c_ptr->cptr > 1) &&
		 (!target_mode || at_target(y, x) ||
		  !los(target_row, target_col, char_row, char_col) ||
		  ((target_mon < MAX_MALLOC) && !m_list[target_mon].ml))) ||
		(target_mode && at_target(y, x))) {
	        flag = TRUE;	   /* THEN we decide to explode here. -CFT */
	        if (c_ptr->fval >= MIN_CLOSED_SPACE) {
		    y = oldy;
		    x = oldx;
	        }
#endif
	    /* The ball hits and explodes.               */
	    /* The explosion.                            */
		for (i = y - max_dis; i <= y + max_dis; i++)
		    for (j = x - max_dis; j <= x + max_dis; j++)
			if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) &&
			 los(char_row, char_col, i, j) && los(y, x, i, j) &&
			    (cave[i][j].fval <= MAX_OPEN_SPACE) &&
			    panel_contains(i, j) && (py.flags.blind < 1)) {
#ifdef TC_COLOR
			    if (!no_color_flag)
				textcolor(bolt_color(typ));
#endif
			    print('*', i, j);
#ifdef TC_COLOR
			    if (!no_color_flag)
				textcolor(LIGHTGRAY);	/* prob don't need here,
							 * but... -CFT */
#endif
			}
		if (py.flags.blind < 1) {
		    put_qio();
#ifdef MSDOS
		    delay(25 * delay_spd);	/* milliseconds */
#else
		    usleep(25000 * delay_spd);	/* useconds */
#endif
		}
	    /*
	     * now erase the ball, since effects below may use msg_print, and
	     * pause indefinitely, so we want ball gone before then -CFT 
	     */
		for (i = y - max_dis; i <= y + max_dis; i++)
		    for (j = x - max_dis; j <= x + max_dis; j++)
			if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) &&
			 los(char_row, char_col, i, j) && los(y, x, i, j) &&
			    (cave[i][j].fval <= MAX_OPEN_SPACE) &&
			    panel_contains(i, j) && (py.flags.blind < 1)) {
			    lite_spot(i, j);	/* draw what is below the '*' */
			}
		put_qio();
	    /*
	     * First go over the area of effect, and destroy items...  Any
	     * preexisting items will be affected, but items dropped by
	     * killed monsters are assummed to have been "shielded" from the
	     * effects the the monster's corpse.  This means that you no
	     * longer have to be SO paranoid about using fire/frost/acid
	     * balls. -CFT 
	     */
		for (i = y - max_dis; i <= y + max_dis; i++)
		    for (j = x - max_dis; j <= x + max_dis; j++)
			if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
			    && los(y, x, i, j) && (cave[i][j].tptr != 0) &&
			    (*destroy) (&t_list[cave[i][j].tptr]))
			    (void)delete_object(i, j);	/* burn/corrode or OW
							 * destroy items in area
							 * of effect */
	    /* now go over area of affect and DO something to monsters... */
		for (i = y - max_dis; i <= y + max_dis; i++)
		    for (j = x - max_dis; j <= x + max_dis; j++)
			if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
			    && los(y, x, i, j)) {
			    c_ptr = &cave[i][j];
			    if (c_ptr->fval <= MAX_OPEN_SPACE) {
				if (c_ptr->cptr > 1) {
				    dam = dam_hp;
				    m_ptr = &m_list[c_ptr->cptr];
				    spell_hit_monster(m_ptr, typ, &dam,
				      (distance(i, j, y, x) + 1), &ny, &nx);
				    c_ptr = &cave[ny][nx];
			/* may be new location if teleported by gravity warp... */
				    m_ptr = &m_list[c_ptr->cptr];
			/* and even if not, may be new monster if chaos polymorphed */
				    r_ptr = &c_list[m_ptr->mptr];
				    monptr = c_ptr->cptr;

				/*
				 * lite up creature if visible, temp set pl
				 * so that update_mon works 
				 */
				    tmp = c_ptr->pl;
				    c_ptr->pl = TRUE;
				    update_mon((int)c_ptr->cptr);

				    thit++;
				    if (dam < 1)
					dam = 1;	/* protect vs neg damage
							 * -CFT */
				    k = mon_take_hit((int)c_ptr->cptr, dam, TRUE);
				    if (k >= 0)
					tkill++;
				    c_ptr->pl = tmp;
				}
				lite_spot(i, j);	/* erase the ball... */
			    }
			}
	    /* show ball of whatever */
		put_qio();

	    /* End  explosion.                   */
		if (tkill == 1) {
		    msg_print("There is a scream of agony!");
		} else if (tkill > 1) {
		    msg_print("There are several screams of agony!");
		}
		if (tkill >= 0)
		    prt_experience();
	    /* End ball hitting.                 */
	    } else if (panel_contains(y, x) && (py.flags.blind < 1)) {
#ifdef TC_COLOR
		if (!no_color_flag)
		    textcolor(bolt_color(typ));
#endif
		print(bolt_char, y, x);
		put_qio();
#ifdef TC_COLOR
		if (!no_color_flag)
		    textcolor(LIGHTGRAY);
#endif
#ifdef MSDOS
		delay(8 * delay_spd);	/* milliseconds */
#else
		usleep(8000 * delay_spd);	/* useconds */
#endif
	    }
	    oldy = y;
	    oldx = x;
#ifdef TARGET
	    if (target_mode && at_target(y,x))
		flag = TRUE; /* must have hit "targetted" area -CFT */
#endif
	}
    } while (!flag);
}

/* Lightning ball in all directions                        SM   */
void 
starball(y, x)
    register int        y, x;
{
    register int        i;

    for (i = 1; i <= 9; i++)
	if (i != 5)
	    fire_ball(GF_LIGHTNING, i, y, x, 150, 3,
		      "massive storm of Electricity");
}

/* Breath weapon works like a fire_ball, but affects the player. */
/* Note the area affect.                              -RAK-   */
void 
breath(typ, y, x, dam_hp, ddesc, monptr)
    int                 typ, y, x, dam_hp;
    char               *ddesc;
    int                 monptr;
{
    register int        i, j;
    int                 dam, max_dis;
    int32u              tmp, treas;
    int                 (*destroy) ();
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    int                 ny, nx;
    int                 blind = (py.flags.status & PY_BLIND) ? 1 : 0;
    char                ch;

    m_ptr = &m_list[monptr];
    r_ptr = &c_list[m_ptr->mptr];
    ch = r_ptr->cchar;
    if ((ch == 'v' || ch == 'D' || ch == 'E' || ch == '&' || ch == 'A') ||
	((ch == 'd' || ch == 'R') && r_ptr->cdefense & UNIQUE))
	max_dis = 3;
    else
	max_dis = 2;

    ball_destroy(typ, &destroy);

    if (!(py.flags.status & PY_BLIND)) { /* only bother if the player can see */
	for (i = y - max_dis; i <= y + max_dis; i++)
	    for (j = x - max_dis; j <= x + max_dis; j++)
		if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) &&
		    los(y, x, i, j) && (cave[i][j].fval <= MAX_OPEN_SPACE) &&
		    panel_contains(i, j)) {
#ifdef TC_COLOR
		    if (!no_color_flag)
			textcolor(bolt_color(typ));
#endif
		    print('*', i, j);
#ifdef TC_COLOR
		    if (!no_color_flag)
			textcolor(LIGHTGRAY);	/* prob don't need here,
						 * but... -CFT */
#endif
		}
	put_qio();
#ifdef MSDOS
	delay(25 * delay_spd);	   /* milliseconds */
#else
	usleep(25000 * delay_spd); /* useconds */
#endif
 
/*
 * now erase the ball, since effects below may use msg_print, and pause
 * indefinitely, so we want ball gone before then -CFT 
 */
	for (i = y - max_dis; i <= y + max_dis; i++)
	    for (j = x - max_dis; j <= x + max_dis; j++)
		if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) &&
		    los(y, x, i, j) && (cave[i][j].fval <= MAX_OPEN_SPACE) &&
		    panel_contains(i, j))
		    lite_spot(i, j);   /* draw what is below the '*' */
	put_qio();
    }
/*
 * first, go over area of affect and destroy preexisting items. This change
 * means that any treasure dropped by killed monsters is safe from the effects
 * of this ball (but not from any later balls/breathes, even if they happen
 * before the player gets a chance to pick up that scroll of *Acquirement*). 
 * The assumption is made that this treasure was shielded from the effects by
 * the corpse of the killed monster. -CFT 
 */
    for (i = y - max_dis; i <= y + max_dis; i++)
	for (j = x - max_dis; j <= x + max_dis; j++)
	    if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
		&& los(y, x, i, j) && (cave[i][j].tptr != 0)
		&& (*destroy) (&t_list[cave[i][j].tptr]))
		delete_object(i, j);

/* now go over area of affect and DO something to monsters */
    for (i = y - max_dis; i <= y + max_dis; i++)
	for (j = x - max_dis; j <= x + max_dis; j++)
	    if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
		&& los(y, x, i, j)) {

		c_ptr = &cave[i][j];
		if ((c_ptr->tptr != 0) && (*destroy) (&t_list[c_ptr->tptr]))
		    (void)delete_object(i, j);
		if (c_ptr->fval <= MAX_OPEN_SPACE) {
		    if ((c_ptr->cptr > 1) && (c_ptr->cptr != monptr)) {
			dam = dam_hp;
			m_ptr = &m_list[c_ptr->cptr];
			spell_hit_monster(m_ptr, typ, &dam, distance(i, j, y, x) + 1,
					  &ny, &nx);
			c_ptr = &cave[ny][nx];	/* may be new location if teleported
                                                 * by gravity warp... */
			m_ptr = &m_list[c_ptr->cptr];	/* and even if not, may be new
							 * monster if chaos polymorphed */
			r_ptr = &c_list[m_ptr->mptr];

		    /*
		     * can not call mon_take_hit here, since player does not
		     * get experience for kill 
		     */
			if (dam < 1)
			    dam = 1;
			m_ptr->hp = m_ptr->hp - dam;
			m_ptr->csleep = 0;
			if ((r_ptr->cdefense & UNIQUE) && (m_ptr->hp < 0))
			    m_ptr->hp = 0;	/* prevent unique monster
						 * from death by other
						 * monsters.  It causes
						 * trouble (monster not
						 * marked as dead, quest
						 * monsters don't satisfy
						 * quest, etc).  So, we let
						 * then live, but extremely
						 * wimpy.  This isn't great,
						 * because monster might heal
						 * itself before player's
						 * next swing... -CFT */
			if (m_ptr->hp < 0) {
			    object_level = (dun_level + r_ptr->level) >> 1;
			    treas = monster_death((int)m_ptr->fy, (int)m_ptr->fx,
						  r_ptr->cmove, 0, 0);
				/* recall even invisible uniques -CWS */
			    if (m_ptr->ml || (c_list[m_ptr->mptr].cdefense & UNIQUE)) {
				tmp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE)
				    >> CM_TR_SHIFT;
				if (tmp > ((treas & CM_TREASURE) >> CM_TR_SHIFT))
				    treas = (treas & ~CM_TREASURE) | (tmp << CM_TR_SHIFT);
				c_recall[m_ptr->mptr].r_cmove = treas |
				    (c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE);
			    }
			/*
			 * It ate an already processed monster.Handle
			 * normally. 
			 */
			    if (monptr < c_ptr->cptr)
				delete_monster((int)c_ptr->cptr);
			/*
			 * If it eats this monster, an already processed
			 * monster will take its place, causing all kinds of
			 * havoc. Delay the kill a bit. 
			 */
			    else
				fix1_delete_monster((int)c_ptr->cptr);
			}
		    } else if (c_ptr->cptr == 1) {
			dam = (dam_hp / (distance(i, j, y, x) + 1));
			m_ptr = &m_list[monptr];
		    /* let's do at least one point of damage */
		    /* prevents randint(0) problem with poison_gas, also */
			if (dam <= 0)
			    dam = 1;
			if (dam > 1600)
			    dam = 1600;
			switch (typ) {
			  case GF_LIGHTNING:
			    light_dam(dam, ddesc);
			    break;
			  case GF_POISON_GAS:
			    poison_gas(dam, ddesc);
			    break;
			  case GF_ACID:
			    acid_dam(dam, ddesc);
			    break;
			  case GF_FROST:
			    cold_dam(dam, ddesc);
			    break;
			  case GF_FIRE:
			    fire_dam(dam, ddesc);
			    break;
			  case GF_MAGIC_MISSILE:
			    take_hit(dam, ddesc);
			    break;
			  case GF_HOLY_ORB:
			    dam /= 2;	/* player should take less damage
					 * from "good" power-CFT */
			    take_hit(dam, ddesc);
			    break;
			  case GF_ARROW:	/* maybe can miss? */
			    take_hit(dam, ddesc);
			    break;
			  case GF_PLASMA:	/* no resist to plasma? */
			    take_hit(dam, ddesc);
			    if (!py.flags.sound_resist)
				stun_player(randint(
				(dam_hp > 40) ? 35 : (dam_hp * 3 / 4 + 5)));
			    break;
			  case GF_NETHER:
			    if (py.flags.nether_resist) {
				dam *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
				dam /= (randint(5) + 6);	/* .858 to .5 -CFT */
			    } else {	/* no resist */
				if (py.flags.hold_life && randint(3) > 1)
				    msg_print("You keep hold of your life force!");
				else if (py.flags.hold_life) {
				    msg_print("You feel your life slipping away!");
				    lose_exp(200 + (py.misc.exp/1000) * MON_DRAIN_LIFE);
				} else {
				    msg_print("You feel your life draining away!");
				    lose_exp(200 + (py.misc.exp/100) * MON_DRAIN_LIFE);
				}
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_WATER:
			    if (!py.flags.sound_resist)
				stun_player(randint(55));
			    if (!player_saves() && !py.flags.confusion_resist
				&& !py.flags.chaos_resist) {
				if ((py.flags.confused > 0) &&
				    (py.flags.confused < 32000))
				    py.flags.confused += 6;
				else
				    py.flags.confused = randint(8) + 6;
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_CHAOS:
			    if (py.flags.chaos_resist) {
				dam *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
				dam /= (randint(6) + 6);	/* .858 to .5 -CFT */
			    }
			    if ((!py.flags.confusion_resist) &&
				(!py.flags.chaos_resist)) {
				if (py.flags.confused > 0)
				    py.flags.confused += 12;
				else
				    py.flags.confused = randint(20) + 10;
			    }
			    if (!py.flags.chaos_resist)
				py.flags.image += randint(10);
			    if (!py.flags.nether_resist && !py.flags.chaos_resist) {
				if (py.flags.hold_life && randint(3) > 1)
				    msg_print("You keep hold of your life force!");
				else if (py.flags.hold_life) {
				    msg_print("You feel your life slipping away!");
				    lose_exp(500 + (py.misc.exp/1000) * MON_DRAIN_LIFE);
				} else {
				    msg_print("You feel your life draining away!");
				    lose_exp(5000 + (py.misc.exp/100) * MON_DRAIN_LIFE);
				}
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_SHARDS:
			    if (py.flags.shards_resist) {
				dam *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
				dam /= (randint(6) + 6);	/* .858 to .5 -CFT */
			    } else {
				cut_player(dam);	/* ouch! */
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_SOUND:
			    if (py.flags.sound_resist) {
				dam *= 5;
				dam /= (randint(6) + 6);
			    } else {
				stun_player(randint((dam > 90) ? 35 : (dam / 3 + 5)));
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_CONFUSION:
			    if (py.flags.confusion_resist) {
				dam *= 5;	/* these 2 lines give avg dam
						 * of .655, ranging from */
				dam /= (randint(6) + 6);	/* .858 to .5 -CFT */
			    }
			    if (!py.flags.confusion_resist && !py.flags.chaos_resist) {
				if (py.flags.confused > 0)
				    py.flags.confused += 12;
				else
				    py.flags.confused = randint(20) + 10;
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_DISENCHANT:
			    if (py.flags.disenchant_resist) {
				dam *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
				dam /= (randint(6) + 6);	/* .858 to .5 -CFT */
			    } else {
				int8u               disenchant = FALSE;
				int8u               chance;
				int                 t = 0;
				inven_type         *i_ptr;

				switch (randint(7)) {
				  case 1:
				    t = INVEN_BODY;
				    break;
				  case 2:
				    t = INVEN_BODY;
				    break;
				  case 3:
				    t = INVEN_ARM;
				    break;
				  case 4:
				    t = INVEN_OUTER;
				    break;
				  case 5:
				    t = INVEN_HANDS;
				    break;
				  case 6:
				    t = INVEN_HEAD;
				    break;
				  case 7:
				    t = INVEN_FEET;
				    break;
				}
				i_ptr = &inventory[t];
				chance = 1;
				/* Artifacts have 2/3 chance to resist -DGK */
				if (i_ptr->flags2 & TR_ARTIFACT)
				    chance = randint(3);
				if ((i_ptr->tohit > 0) && (chance == 1)) {
				    i_ptr->tohit -= randint(2);
				/* don't send it below zero */
				    if (i_ptr->tohit < 0)
					i_ptr->tohit = 0;
				    disenchant = TRUE;
				}
				if ((i_ptr->todam > 0) && (chance == 1)) {
				    i_ptr->todam -= randint(2);
				/* don't send it below zero */
				    if (i_ptr->todam < 0)
					i_ptr->todam = 0;
				    disenchant = TRUE;
				}
				if ((i_ptr->toac > 0) && (chance == 1)) {
				    i_ptr->toac -= randint(2);
				/* don't send it below zero */
				    if (i_ptr->toac < 0)
					i_ptr->toac = 0;
				    disenchant = TRUE;
				}
				if (disenchant || (chance != 1)) {
				    vtype               t1, t2;

				    objdes(t1, &inventory[t], FALSE);
				    if (chance != 1)
					sprintf(t2, "Your %s (%c) %s disenchanted!", t1,
						i + 'a' - INVEN_WIELD,
						(inventory[i].number != 1) ?
						"were" : "was");
				    else
					sprintf(t2, "Your %s (%c) %s disenchantment!",
						t1,
						i + 'a' - INVEN_WIELD,
						(inventory[i].number != 1) ?
						"resist" : "resists");
				    msg_print(t2);
				    calc_bonuses();
				}
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_NEXUS:	/* no spec. effects from
						 * nexus bolt, only breath
						 * -CFT */
			    if (py.flags.nexus_resist) {
				dam *= 6;	/* these 2 lines give avg dam
						 * of .655, ranging from */
				dam /= (randint(6) + 6);	/* .858 to .5 -CFT */
			    } else {	/* special effects */
				switch (randint(7)) {
				  case 1:
				  case 2:
				  case 3:
				    teleport(200);
				    break;
				  case 4:
				  case 5:
				    teleport_to((int)m_ptr->fy, (int)m_ptr->fx);
				    break;
				  case 6:
				    if (player_saves())
					msg_print("You resist the effects.");
				    else {
					int                 k = dun_level;

					if (dun_level == Q_PLANE)
					    dun_level = 0;
					else if (is_quest(dun_level))
					    dun_level -= 1;
					else
					    dun_level += (-3) + 2 * randint(2);
					if (dun_level < 0)
					    dun_level = 0;
					if (k == Q_PLANE)
			    msg_print("You warp through a cross-dimension gate.");
					else if (k < dun_level)
					    msg_print("You sink through the floor.");
					else
				    msg_print("You rise up through the ceiling.");
					new_level_flag = TRUE;
				    }
				    break;
				  case 7:
				    if (player_saves() && randint(2) == 1)
					msg_print("You resist the effects.");
				    else {
					int      max1, cur1, max2, cur2, ii, jj;

					msg_print("Your body starts to scramble...");
					ii = randint(6) - 1;
					do {
					    jj = randint(6) - 1;
					} while (ii == jj);
					max1 = py.stats.max_stat[ii];
					cur1 = py.stats.cur_stat[ii];
					max2 = py.stats.max_stat[jj];
					cur2 = py.stats.cur_stat[jj];
					py.stats.max_stat[ii] = max2;
					py.stats.cur_stat[ii] = cur2;
					py.stats.max_stat[jj] = max1;
					py.stats.cur_stat[jj] = cur1;
					set_use_stat(ii);
					set_use_stat(jj);
					prt_stat(ii);
					prt_stat(jj);
				    }
				} /* switch for effects */
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_FORCE:
			    if (!py.flags.sound_resist)
				stun_player(randint(20));
			    take_hit(dam, ddesc);
			    break;
			  case GF_INERTIA:
			    if ((py.flags.slow > 0) && (py.flags.slow < 32000))
				py.flags.slow += randint(5);
			    else {
				msg_print("You feel less able to move.");
				py.flags.slow = randint(5) + 3;
			    }
			    take_hit(dam, ddesc);
			    break;
			  case GF_LIGHT:
			    if (py.flags.light_resist) {
				dam *= 4;
				dam /= (randint(6) + 6);
			    } else if (!blind && !py.flags.blindness_resist) {
				msg_print("You are blinded by the flash!");
				py.flags.blind += randint(6) + 3;
			    }
			    light_area(char_row, char_col, 0, max_dis);
			    take_hit(dam, ddesc);
			    break;
			  case GF_DARK:
			    if (py.flags.dark_resist) {
				dam *= 4;
				dam /= (randint(6) + 6);
			    } else {
				if (!blind) 
				    msg_print("The darkness prevents you from seeing!");
				py.flags.blind += randint(5) + 2;
			    }
			    unlight_area(char_row, char_col);
			    take_hit(dam, ddesc);
			    break;
			  case GF_TIME:	/* only some effects from
						 * time bolt -CFT */
			    switch (randint(10)) {
			      case 1:
			      case 2:
			      case 3:
			      case 4:
			      case 5:
				msg_print("You feel life has clocked back.");
				lose_exp(m_ptr->hp + (py.misc.exp / 300) * MON_DRAIN_LIFE);
				break;
			      case 6:
			      case 7:
			      case 8:
			      case 9:
				{
				    int                 t = 0;

				    switch (randint(6)) {
				      case 1:
					t = A_STR;
				msg_print("You're not as strong as you used to be...");
					break;
				      case 2:
					t = A_INT;
				msg_print("You're not as bright as you used to be...");
					break;
				      case 3:
					t = A_WIS;
				msg_print("You're not as wise as you used to be...");
					break;
				      case 4:
					t = A_DEX;
				msg_print("You're not as agile as you used to be...");
					break;
				      case 5:
					t = A_CON;
				msg_print("You're not as hale as you used to be...");
					break;
				      case 6:
					t = A_CHR;
			msg_print("You're not as beautiful as you used to be...");
					break;
				    }
			    py.stats.cur_stat[t] = (py.stats.cur_stat[t] * 3) / 4;
				    if (py.stats.cur_stat[t] < 3)
					py.stats.cur_stat[t] = 3;
				    set_use_stat(t);
				    prt_stat(t);
				}
				break;
			      case 10:
				{
				    int                 ii;

				    for (ii = 0; ii < 6; ii++) {
				py.stats.cur_stat[ii] = (py.stats.cur_stat[ii] * 3) / 4;
					if (py.stats.cur_stat[ii] < 3)
					    py.stats.cur_stat[ii] = 3;
					set_use_stat(ii);
					prt_stat(ii);
				    }
				}
				msg_print("You're not as strong as you used to be...");
				msg_print("You're not as bright as you used to be...");
				msg_print("You're not as wise as you used to be...");
				msg_print("You're not as agile as you used to be...");
				msg_print("You're not as hale as you used to be...");
			msg_print("You're not as beautiful as you used to be...");
				break;
			    } /* randint(10) for effects */
			    take_hit(dam, ddesc);
			    break;
			  case GF_GRAVITY:
			    if ((!py.flags.sound_resist) && (!py.flags.ffall))	/* DGK */
				stun_player(randint((dam > 90) ? 35 : (dam / 3 + 5)));
			    if (py.flags.ffall) {	/* DGK */
				dam_hp *= 3;	/* these 2 lines give avg dam
						 * of .33, ranging from */
				dam_hp /= (randint(6) + 6);	/* .427 to .25 -CFT */
			    } else {	/* DGK */
				if ((py.flags.slow > 0) && (py.flags.slow < 32000))
				    py.flags.slow += randint(5);
				else {
				    msg_print("You feel less able to move.");
				    py.flags.slow = randint(5) + 3;
				}
			    } /* DGK */
			    msg_print("Gravity warps around you.");
			    teleport(5);
			    take_hit(dam, ddesc);
			    break;
			  case GF_MANA:
			    take_hit(dam, ddesc);
			    break;
			  case GF_METEOR:
			    take_hit(dam, ddesc);
			    break;
			  case GF_ICE:
			    cold_dam(dam, ddesc);
			    if (!py.flags.sound_resist)
				stun_player(randint(25));
			    if (!py.flags.shards_resist)
				cut_player(damroll(8, 10));
			    break;
			  default:
		    msg_print("Unknown typ in breath().  This may mean trouble.");
			}
		    }
		}
	    }
/* show the ball of gas */
    put_qio();

/* erase ball and redraw */
    for (i = (y - max_dis); i <= (y + max_dis); i++)
	for (j = (x - max_dis); j <= (x + max_dis); j++)
	    if (in_bounds(i, j) && panel_contains(i, j) &&
		(distance(y, x, i, j) <= max_dis))
		lite_spot(i, j);
}


int 
recharge(num)
    register int        num;
{
    int                 i, j, k, l, item_val;
    register int        res;
    register inven_type *i_ptr;
    int                 found = FALSE;

    res = FALSE;
    if (find_range(TV_STAFF, TV_WAND, &i, &j))
	found = TRUE;
    if (find_range(TV_ROD, TV_NEVER, &k, &l))
	found = TRUE;

    if (!found)
	msg_print("You have nothing to recharge.");
    else if (get_item(&item_val, "Recharge which item?",
		      (k > -1) ? k : i, (j > -1) ? j : l, 0)) {
	i_ptr = &inventory[item_val];
	res = TRUE;
	if (i_ptr->tval == TV_ROD) {	/* now allow players to speed up
					 * recharge time of rods -CFT */
	    int16u              t_o = i_ptr->timeout, t;

	    if (randint((100 - i_ptr->level + num) / 5) == 1) {	/* not today... */
		msg_print("The recharge backfires, and drains the rod further!");
		if (t_o < 32000)   /* don't overflow... */
		    i_ptr->timeout = (t_o + 100) * 2;
	    } else {
		t = (int16u) (num * damroll(2, 4));	/* rechange amount */
		if (t_o < t)
		    i_ptr->timeout = 0;
		else
		    i_ptr->timeout = t_o - t;
	    }
	}
	 /* if recharge rod... */ 
	else {			   /* recharge wand/staff */
	/* recharge I = recharge(20) = 1/6 failure for empty 10th level wand */
	/*
	 * recharge II = recharge(60) = 1/10 failure for empty 10th level
	 * wand 
	 */
	/* make it harder to recharge high level, and highly charged wands */
	    if (randint((num + 100 - (int)i_ptr->level - (10 * i_ptr->p1)) / 15) == 1) {
		msg_print("There is a bright flash of light.");
		inven_destroy(item_val);
	    } else {
		num = (num / (i_ptr->level + 2)) + 1;
		i_ptr->p1 += 2 + randint(num);
		if (known2_p(i_ptr))
		    clear_known2(i_ptr);
		clear_empty(i_ptr);
	    }
	}
    }
    return (res);
}

/* Increase or decrease a creatures hit points		-RAK-	 */
int 
hp_monster(dir, y, x, dam)
    int                 dir, y, x, dam;
{
    register int        i;
    int                 flag, dist, monster;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    monster = FALSE;
    flag = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    flag = TRUE;
	    m_ptr = &m_list[c_ptr->cptr];
	    r_ptr = &c_list[m_ptr->mptr];
	    monster_name(m_name, m_ptr, r_ptr);
	    monster = TRUE;
	    i = mon_take_hit((int)c_ptr->cptr, dam, TRUE);
	    if (i >= 0) {
		(void)sprintf(out_val, "%s dies in a fit of agony.", m_name);
		msg_print(out_val);
		prt_experience();
	    } else if (dam > 0) {
		(void)sprintf(out_val,
			      pain_message((int)c_ptr->cptr, dam), m_name);
		msg_print(out_val);
	    }
	}
    }
    while (!flag);
    return (monster);
}


/* Drains life; note it must be living.		-RAK-	 */
int 
drain_life(dir, y, x, dam)
    int                 dir, y, x, dam;
{
    register int        i;
    int                 flag, dist, drain;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    drain = FALSE;
    flag = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    flag = TRUE;
	    m_ptr = &m_list[c_ptr->cptr];
	    r_ptr = &c_list[m_ptr->mptr];
	    if (((r_ptr->cdefense & UNDEAD) == 0) &&
		((r_ptr->cdefense & DEMON) == 0) &&
		(r_ptr->cchar != 'E' && r_ptr->cchar != 'g' && r_ptr->cchar != 'v')) {
		drain = TRUE;
		monster_name(m_name, m_ptr, r_ptr);
		i = mon_take_hit((int)c_ptr->cptr, dam, TRUE);
		if (i >= 0) {
		    (void)sprintf(out_val, "%s dies in a fit of agony.", m_name);
		    msg_print(out_val);
		    prt_experience();
		} else {
		    (void)sprintf(out_val,
			       pain_message((int)c_ptr->cptr, dam), m_name);
		    msg_print(out_val);
		}
	    } else {
		if (r_ptr->cdefense & UNDEAD)
		    c_recall[m_ptr->mptr].r_cdefense |= UNDEAD;
		else
		    c_recall[m_ptr->mptr].r_cdefense |= DEMON;
	    }
	}
    }
    while (!flag);
    return (drain);
}


/* Increase or decrease a creatures speed		-RAK-	 */
/* NOTE: cannot slow a winning creature (BALROG)		 */
int 
speed_monster(dir, y, x, spd)
    int                 dir, y, x, spd;
{
    int                 flag, dist, speed;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    speed = FALSE;
    flag = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    flag = TRUE;
	    m_ptr = &m_list[c_ptr->cptr];
	    r_ptr = &c_list[m_ptr->mptr];
	    monster_name(m_name, m_ptr, r_ptr);
	    if (spd > 0) {
		m_ptr->cspeed += spd;
		m_ptr->csleep = 0;
		(void)sprintf(out_val, "%s starts moving faster.", m_name);
		msg_print(out_val);
		speed = TRUE;
	    } else if ((r_ptr->level >
			randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
		       (r_ptr->cdefense & UNIQUE)) {
		(void)sprintf(out_val, "%s is unaffected.", m_name);
		msg_print(out_val);
		m_ptr->csleep = 0;
	    } else {
		m_ptr->cspeed += spd;
		m_ptr->csleep = 0;
		(void)sprintf(out_val, "%s starts moving slower.", m_name);
		msg_print(out_val);
		speed = TRUE;
	    }
	}
    }
    while (!flag);
    return (speed);
}


/* Confuse a creature					-RAK-	 */
int 
confuse_monster(dir, y, x, lvl)
    int                 dir, y, x, lvl;
{
    int                 flag, dist, confuse;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    confuse = FALSE;
    flag = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    m_ptr = &m_list[c_ptr->cptr];
	    r_ptr = &c_list[m_ptr->mptr];
	    monster_name(m_name, m_ptr, r_ptr);
	    flag = TRUE;
	    if ((r_ptr->level >
	    randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
		(r_ptr->cdefense & UNIQUE ||
		 r_ptr->spells2 & (BREATH_CO | BREATH_CH))) {
		if (m_ptr->ml && (r_ptr->cdefense & CHARM_SLEEP))
		    c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
		(void)sprintf(out_val, "%s is unaffected.", m_name);
		msg_print(out_val);
		m_ptr->csleep = 0;
	    } else {
		if (m_ptr->confused < 175)
		    m_ptr->confused += (int8u) (damroll(3, (lvl / 2)) + 1);
		confuse = TRUE;
		m_ptr->csleep = 0;
		(void)sprintf(out_val, "%s appears confused.", m_name);
		msg_print(out_val);
	    }
	}
    }
    while (!flag);
    return (confuse);
}


/* Scare a creature -DGK */
int 
fear_monster(dir, y, x, lvl)
    int                 dir, y, x, lvl;
{
    int                 flag, dist, fear;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    fear = FALSE;
    flag = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    m_ptr = &m_list[c_ptr->cptr];
	    r_ptr = &c_list[m_ptr->mptr];
	    monster_name(m_name, m_ptr, r_ptr);
	    flag = TRUE;
	    if ((r_ptr->level >
	    randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
		(r_ptr->cdefense & UNIQUE)) {
		if (m_ptr->ml && (r_ptr->cdefense & CHARM_SLEEP))
		    c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
		(void)sprintf(out_val, "%s is unaffected.", m_name);
		msg_print(out_val);
		m_ptr->csleep = 0;
	    } else {
		if (m_ptr->monfear < 175)
		    m_ptr->monfear += (int8u) (damroll(3, (lvl / 2)) + 1);
		fear = TRUE;
		m_ptr->csleep = 0;
		(void)sprintf(out_val, "%s flees in terror!", m_name);
		msg_print(out_val);
	    }
	}
    }
    while (!flag);
    return (fear);
}

/* Sleep a creature.					-RAK-	 */
int 
sleep_monster(dir, y, x)
    int                 dir, y, x;
{
    int                 flag, dist, sleep;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    sleep = FALSE;
    flag = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    m_ptr = &m_list[c_ptr->cptr];
	    r_ptr = &c_list[m_ptr->mptr];



	    flag = TRUE;
	    monster_name(m_name, m_ptr, r_ptr);
	    if ((r_ptr->level >
	    randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
	    (r_ptr->cdefense & UNIQUE) || (r_ptr->cdefense & CHARM_SLEEP)) {
		if (m_ptr->ml && (r_ptr->cdefense & CHARM_SLEEP))
		    c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
		(void)sprintf(out_val, "%s is unaffected.", m_name);
		msg_print(out_val);
	    } else {
		m_ptr->csleep = 500;
		sleep = TRUE;
		(void)sprintf(out_val, "%s falls asleep.", m_name);
		msg_print(out_val);
	    }
	}
    }
    while (!flag);
    return (sleep);
}


/* Turn stone to mud, delete wall.			-RAK-	 */
int 
wall_to_mud(dir, y, x)
    int                 dir, y, x;
{
    int                 i, wall, dist;
    bigvtype            out_val, tmp_str;
    register int        flag;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               m_name;

    wall = FALSE;
    flag = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
    /* note, this ray can move through walls as it turns them to mud */
	if (dist == OBJ_BOLT_RANGE)
	    flag = TRUE;
	if (c_ptr->fval == BOUNDARY_WALL) {
	    flag = TRUE;
	    if (test_light(y, x))
		msg_print("The wall resists your spell.");
	} else if ((c_ptr->fval >= MIN_CAVE_WALL)) {
	    flag = TRUE;
	    (void)twall(y, x, 1, 0);
	    if (test_light(y, x)) {
		msg_print("The wall turns into mud.");
		check_view();
		wall = TRUE;
	    }
	} else if ((c_ptr->tptr != 0) && (c_ptr->fval >= MIN_CLOSED_SPACE)) {
	    flag = TRUE;
	    if (panel_contains(y, x) && test_light(y, x)) {
		objdes(tmp_str, &t_list[c_ptr->tptr], FALSE);
		(void)sprintf(out_val, "The %s turns into mud.", tmp_str);
		msg_print(out_val);
		wall = TRUE;
	    }
	    (void)delete_object(y, x);
	    check_view();
	}
	if (c_ptr->cptr > 1) {
	    m_ptr = &m_list[c_ptr->cptr];
	    r_ptr = &c_list[m_ptr->mptr];
	    if (HURT_ROCK & r_ptr->cdefense) {
		monster_name(m_name, m_ptr, r_ptr);
		flag = m_ptr->ml;
		i = mon_take_hit((int)c_ptr->cptr, (20 + randint(30)), TRUE);
		if (flag) {
		    if (i >= 0) {
			c_recall[i].r_cdefense |= HURT_ROCK;
			(void)sprintf(out_val, "%s dissolves!", m_name);
			msg_print(out_val);
			prt_experience();	/* print msg before calling
						 * prt_exp */
		    } else {
			c_recall[m_ptr->mptr].r_cdefense |= HURT_ROCK;
			(void)sprintf(out_val, "%s grunts in pain!", m_name);
			msg_print(out_val);
		    }
		}
		flag = TRUE;
	    }
	}
    }
    while (!flag);
    return (wall);
}


/* Destroy all traps and doors in a given direction	-RAK-	 */
int 
td_destroy2(dir, y, x)
    int                 dir, y, x;
{
    register int        destroy2, dist;
    register cave_type *c_ptr;
    register inven_type *t_ptr;

    destroy2 = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
    /* must move into first closed spot, as it might be a secret door */
	if (c_ptr->tptr != 0) {
	    t_ptr = &t_list[c_ptr->tptr];
	    if (t_ptr->tval == TV_CHEST) /* let's untrap it instead -CWS */
		t_ptr->flags &= ~(CH_TRAPPED | CH_LOCKED);
	    else if ((t_ptr->tval == TV_INVIS_TRAP) || (t_ptr->tval == TV_VIS_TRAP) ||
		     (t_ptr->tval == TV_OPEN_DOOR) || (t_ptr->tval == TV_CLOSED_DOOR)
		     || (t_ptr->tval == TV_SECRET_DOOR)) {
		if (delete_object(y, x)) {
		    msg_print("There is a bright flash of light!");
		    destroy2 = TRUE;
		}
	    }
	}
    }
    while ((dist <= OBJ_BOLT_RANGE) || c_ptr->fval <= MAX_OPEN_SPACE);
    return (destroy2);
}


/* Polymorph a monster					-RAK-	 */
/* NOTE: cannot polymorph a unique creature                     */
int 
poly_monster(dir, y, x)
    int                 dir, y, x;
{
    int                 dist, flag, poly;
    register cave_type *c_ptr;
    register creature_type *r_ptr;
    register monster_type *m_ptr;
    vtype               out_val, m_name;
    int                 i, j, k;

    poly = FALSE;
    flag = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    m_ptr = &m_list[c_ptr->cptr];
	    r_ptr = &c_list[m_ptr->mptr];
	    if ((r_ptr->level <
	    randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) &&
		!(r_ptr->cdefense & UNIQUE)) {
		i = (randint(20) / randint(9)) + 1;
		j = r_ptr->level - i;	/* get range of levels... */
		k = r_ptr->level + i;
		if (j < 0)
		    j = 0;
		if (k > MAX_MONS_LEVEL)
		    k = MAX_MONS_LEVEL;
		delete_monster(cave[y][x].cptr);
		do {
		    i = randint(m_level[k] - m_level[j]) - 1 + m_level[j];
		/* monster index */
		    if ((c_list[i].cdefense & UNIQUE) == 0)
			place_monster(y, x, i, FALSE);
		} while (cave[y][x].cptr <= MIN_MONIX);
	    /* don't test c_ptr->fm here, only pl/tl */
		if (panel_contains(y, x) && (c_ptr->tl || c_ptr->pl))
		    poly = TRUE;
	    } else {
		monster_name(m_name, m_ptr, r_ptr);
		(void)sprintf(out_val, "%s is unaffected.", m_name);
		msg_print(out_val);
	    }
	}
    }
    while (!flag);
    return (poly);
}


/* Create a wall.					-RAK-	 */
int 
build_wall(dir, y, x)
    int                 dir, y, x;
{
    register int        i;
    int                 build, damage, dist, flag;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               m_name, out_val;

    build = FALSE;
    dist = 0;
    flag = FALSE;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else {
	    if (c_ptr->cptr > 1) {
	    /* stop the wall building */
		flag = TRUE;
		m_ptr = &m_list[c_ptr->cptr];
		r_ptr = &c_list[m_ptr->mptr];

		if (!(r_ptr->cmove & CM_PHASE)) {
		/* monster does not move, can't escape the wall */
		    if (r_ptr->cmove & CM_ATTACK_ONLY)
			damage = 32000;	/* this will kill everything */
		    else
			damage = damroll(4, 8);

		    monster_name(m_name, m_ptr, r_ptr);
		    (void)sprintf(out_val, "%s wails out in pain!", m_name);
		    msg_print(out_val);
		    i = mon_take_hit((int)c_ptr->cptr, damage, TRUE);
		    if (i >= 0) {
			(void)sprintf(out_val, "%s is embedded in the rock.",
				      m_name);
			msg_print(out_val);
		    /* prt_experience(); */
		    }
		} else if (r_ptr->cchar == 'E' || r_ptr->cchar == 'X') {
		/*
		 * must be an earth elemental or an earth spirit, or a Xorn
		 * increase its hit points 
		 */
		    m_ptr->hp += damroll(4, 8);
		}
	    }
	    if (c_ptr->tptr != 0)
		if (((t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
		     (t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
		     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT))
		    || (t_list[c_ptr->tptr].tval == TV_UP_STAIR)
		    || (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR)
		    || (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
		    continue;	   /* don't bury the artifact/stair/store */
		else
		    (void)delete_object(y, x);
	    c_ptr->fval = MAGMA_WALL;
	    c_ptr->fm = FALSE;
	    lite_spot(y, x);
	    i++;
	    build = TRUE;
	}
    }
    while (!flag);
    return (build);
}


/* Replicate a creature					-RAK-	 */
int 
clone_monster(dir, y, x)
    int                 dir, y, x;
{
    register cave_type *c_ptr;
    register int        dist, flag;

    dist = 0;
    flag = FALSE;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    m_list[c_ptr->cptr].csleep = 0;
	/* monptr of 0 is safe here, since can't reach here from creatures */
	    return multiply_monster(y, x, (int)m_list[c_ptr->cptr].mptr, 0);
	}
    }
    while (!flag);
    return (FALSE);
}


/* Move the creature record to a new location		-RAK-	 */
void 
teleport_away(monptr, dis)
    int                 monptr, dis;
{
    register int        yn, xn, ctr;
    register monster_type *m_ptr;

    m_ptr = &m_list[monptr];
    ctr = 0;
    do {
	do {
	    yn = m_ptr->fy + (randint(2 * dis + 1) - (dis + 1));
	    xn = m_ptr->fx + (randint(2 * dis + 1) - (dis + 1));
	}
	while (!in_bounds(yn, xn));
	ctr++;
	if (ctr > 9) {
	    ctr = 0;
	    dis += 5;
	}
    }
    while ((cave[yn][xn].fval >= MIN_CLOSED_SPACE) || (cave[yn][xn].cptr != 0));
    move_rec((int)m_ptr->fy, (int)m_ptr->fx, yn, xn);
    lite_spot((int)m_ptr->fy, (int)m_ptr->fx);
    m_ptr->fy = yn;
    m_ptr->fx = xn;
/*
 * this is necessary, because the creature is not currently visible in its
 * new position 
 */
    m_ptr->ml = FALSE;
    m_ptr->cdis = distance(char_row, char_col, yn, xn);
    update_mon(monptr);
}


/* Teleport player to spell casting creature		-RAK-	 */
void 
teleport_to(ny, nx)
    int                 ny, nx;
{
    int                 dis, ctr, y, x, min_i, max_i, min_j, max_j;
    register int        i, j;
    register cave_type *c_ptr;

    dis = 1;
    ctr = 0;
    do {
	do {			   /* bounds check added -CFT */
	    y = ny + (randint(2 * dis + 1) - (dis + 1));
	    x = nx + (randint(2 * dis + 1) - (dis + 1));
	} while (!in_bounds(y, x));
	ctr++;
	if (ctr > (4 * dis * dis + 4 * dis + 1)) {
	    ctr = 0;
	    dis++;
	}
    }
    while ((cave[y][x].fval >= MIN_CLOSED_SPACE) || (cave[y][x].cptr >= 2));
    move_rec(char_row, char_col, y, x);

    min_i = MY_MAX(0, (char_row - light_rad));
    max_i = MY_MIN(cur_height, (char_row + light_rad));
    min_j = MY_MAX(0, (char_col - light_rad));
    max_j = MY_MIN(cur_width, (char_col + light_rad));

    for (i = min_i; i <= max_i; i++)
	for (j = min_j; j <= max_j; j++) {
	    c_ptr = &cave[i][j];
	    c_ptr->tl = FALSE;
	    lite_spot(i, j);
	}
    lite_spot(char_row, char_col);
    char_row = y;
    char_col = x;
    check_view();
/* light creatures */
    creatures(FALSE);
}


/* Teleport all creatures in a given direction away	-RAK-	 */
int 
teleport_monster(dir, y, x)
    int                 dir, y, x;
{
    register int        flag, result, dist;
    register cave_type *c_ptr;

    flag = FALSE;
    result = FALSE;
    dist = 0;
    do {
	(void)mmove(dir, &y, &x);
	dist++;
	c_ptr = &cave[y][x];
	if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
	    flag = TRUE;
	else if (c_ptr->cptr > 1) {
	    m_list[c_ptr->cptr].csleep = 0;	/* wake it up */
	    teleport_away((int)c_ptr->cptr, MAX_SIGHT * 5);
	    result = TRUE;
	}
    }
    while (!flag);
    return (result);
}


/* Delete all creatures within max_sight distance	-RAK-	 */
/* NOTE : Winning creatures cannot be genocided			 */
int 
mass_genocide(spell)
    int                 spell;
{
    register int        i, result;
    register monster_type *m_ptr;
    register creature_type *r_ptr;

    result = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	r_ptr = &c_list[m_ptr->mptr];
	if (((m_ptr->cdis <= MAX_SIGHT) && ((r_ptr->cmove & CM_WIN) == 0) &&
	     ((r_ptr->cdefense & UNIQUE) == 0)) || (wizard &&
					      (m_ptr->cdis <= MAX_SIGHT))) {
	    delete_monster(i);
	    if (spell) {
		take_hit(randint(3), "the strain of casting Mass Genocide");
		prt_chp();
		put_qio();
#ifdef MSDOS
		delay(20* delay_spd);	/* milliseconds */
#else
		usleep(20000 * delay_spd);	/* useconds */
#endif
	    }
	    result = TRUE;
	}
    }
    return (result);
}

/* Delete all creatures of a given type from level.	-RAK-	 */
/* This does not keep creatures of type from appearing later.	 */
/* NOTE : Winning creatures can not be genocided. */
int 
genocide(spell)
    int                 spell;
{
    register int        i, killed;
    char                typ;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val;

    killed = FALSE;
    if (get_com("Which type of creature do you wish exterminated?", &typ))
	for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	    m_ptr = &m_list[i];
	    r_ptr = &c_list[m_ptr->mptr];
	    if ((unsigned) typ == c_list[m_ptr->mptr].cchar)
		if ((r_ptr->cmove & CM_WIN) == 0) {
		    delete_monster(i);
		    if (spell) {
			take_hit(randint(4), "the strain of casting Genocide");
			prt_chp();
			put_qio();
#ifdef MSDOS
			delay(20 * delay_spd);	/* milliseconds */
#else
			usleep(20000 * delay_spd);	/* useconds */
#endif
		    }
		    killed = TRUE;
		} else {
		/*
		 * genocide is a powerful spell, so we will let the player
		 * know the names of the creatures he did not destroy, this
		 * message makes no sense otherwise 
		 */
		    if (r_ptr->cdefense & UNIQUE)
			(void)sprintf(out_val, "%s is unaffected.", r_ptr->name);
		    else
			(void)sprintf(out_val, "The %s is unaffected.", r_ptr->name);
		    msg_print(out_val);
		}
	}
    return (killed);
}


/* Change speed of any creature .			-RAK-	 */
/* NOTE: cannot slow a winning creature (BALROG)		 */
int 
speed_monsters(spd)
    int                 spd;
{
    register int        i, speed;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    speed = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	r_ptr = &c_list[m_ptr->mptr];
	monster_name(m_name, m_ptr, r_ptr);

	if (!los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))
	/* do nothing */
	    ;
	else if (spd > 0) {
	    m_ptr->cspeed += spd;
	    m_ptr->csleep = 0;
	    if (m_ptr->ml) {
		speed = TRUE;
		(void)sprintf(out_val, "%s starts moving faster.", m_name);
		msg_print(out_val);
	    }
	} else if ((r_ptr->level <
	    randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) &&
		   !(r_ptr->cdefense & UNIQUE)) {
	    m_ptr->cspeed += spd;
	    m_ptr->csleep = 0;
	    if (m_ptr->ml) {
		(void)sprintf(out_val, "%s starts moving slower.", m_name);
		msg_print(out_val);
		speed = TRUE;
	    }
	} else if (m_ptr->ml) {
	    (void)sprintf(out_val, "%s is unaffected.", m_name);
	    msg_print(out_val);
	}
    }
    return (speed);
}


/* Sleep any creature .		-RAK-	 */
int 
sleep_monsters2()
{
    register int        i, sleep;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    sleep = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	r_ptr = &c_list[m_ptr->mptr];
	monster_name(m_name, m_ptr, r_ptr);
	if ((m_ptr->cdis > MAX_SIGHT) ||
	    !los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))
	/* do nothing */
	    ;
	else if ((r_ptr->level >
	    randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
	    (r_ptr->cdefense & UNIQUE) || (r_ptr->cdefense & CHARM_SLEEP)) {
	    if (m_ptr->ml) {
		if (r_ptr->cdefense & CHARM_SLEEP)
		    c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
		(void)sprintf(out_val, "%s is unaffected.", m_name);
		msg_print(out_val);
	    }
	} else {
	    m_ptr->csleep = 500;
	    if (m_ptr->ml) {
		(void)sprintf(out_val, "%s falls asleep.", m_name);
		msg_print(out_val);
		sleep = TRUE;
	    }
	}
    }
    return (sleep);
}

/* Polymorph any creature that player can see.	-RAK-	 */
/* NOTE: cannot polymorph a unique creature             */
int 
mass_poly()
{
    register int        i;
    int                 y, x, mass;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    int                 l, j, k;

    mass = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	if (m_ptr->cdis <= MAX_SIGHT) {
	    r_ptr = &c_list[m_ptr->mptr];
	    if (((r_ptr->cmove & CM_WIN) == 0) && !(r_ptr->cdefense & UNIQUE)) {
		y = m_ptr->fy;
		x = m_ptr->fx;
		l = (randint(20) / randint(9)) + 1;
		j = r_ptr->level - l;	/* get range of levels... */
		k = r_ptr->level + l;
		if (j < 0)
		    j = 0;
		if (k > MAX_MONS_LEVEL)
		    k = MAX_MONS_LEVEL;
		delete_monster(cave[y][x].cptr);
		do {
		    l = randint(m_level[k] - m_level[j]) - 1 + m_level[j];
		/* monster index */
		    if ((c_list[l].cdefense & UNIQUE) == 0)
			place_monster(y, x, l, FALSE);
		} while (cave[y][x].cptr < MIN_MONIX);
		mass = TRUE;
	    }
	}
    }
    return (mass);
}

int 
chaos(m_ptr2)
    monster_type       *m_ptr2;
{
    register int        i;
    int                 y, x, mass;
    register monster_type *m_ptr;
    register creature_type *r_ptr;

    mass = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	if (m_ptr->cdis < MAX_SIGHT) {
	    r_ptr = &c_list[m_ptr->mptr];
	    if (!(r_ptr->cdefense & UNIQUE) && m_ptr != m_ptr2) {
		y = m_ptr->fy;
		x = m_ptr->fx;
		delete_monster(i);
		place_monster(y, x, randint(m_level[MAX_MONS_LEVEL] - m_level[0])
			      - 1 + m_level[0], FALSE);
		mass = TRUE;
	    }
	}
    }
    return (mass);
}

/* Display evil creatures on current panel		-RAK-	 */
int 
detect_evil()
{
    register int        i, flag;
    register monster_type *m_ptr;

    flag = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
	    (EVIL & c_list[m_ptr->mptr].cdefense)) {
	    m_ptr->ml = TRUE;
	/* works correctly even if hallucinating */
	    print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
		  (int)m_ptr->fx);
	    flag = TRUE;
	}
    }
    if (flag) {
	msg_print("You sense the presence of evil!");
	msg_print(NULL);
    /* must unlight every monster just lighted */
	creatures(FALSE);
    }
    return (flag);
}


/* Change players hit points in some manner		-RAK-	 */
int 
hp_player(num)
    int                 num;
{
    register int        res;
    register struct misc *m_ptr;

    res = FALSE;
    m_ptr = &py.misc;
    if (m_ptr->chp < m_ptr->mhp) {
	m_ptr->chp += num;
	if (m_ptr->chp > m_ptr->mhp) {
	    m_ptr->chp = m_ptr->mhp;
	    m_ptr->chp_frac = 0;
	}
	prt_chp();

	num = num / 5;
	if (num < 3) {
	    if (num == 0)
		msg_print("You feel a little better.");
	    else
		msg_print("You feel better.");
	} else {
	    if (num < 7)
		msg_print("You feel much better.");
	    else
		msg_print("You feel very good.");
	}
	res = TRUE;
    }
    return (res);
}


/* Cure players confusion				-RAK-	 */
int 
cure_confusion()
{
    register int        cure;
    register struct flags *f_ptr;

    cure = FALSE;
    f_ptr = &py.flags;
    if (f_ptr->confused > 1) {
	f_ptr->confused = 1;
	cure = TRUE;
    }
    return (cure);
}


/* Cure players blindness				-RAK-	 */
int 
cure_blindness()
{
    register int        cure;
    register struct flags *f_ptr;

    cure = FALSE;
    f_ptr = &py.flags;
    if (f_ptr->blind > 1) {
	f_ptr->blind = 1;
	cure = TRUE;
    }
    return (cure);
}


/* Cure poisoning					-RAK-	 */
int 
cure_poison()
{
    register int        cure;
    register struct flags *f_ptr;

    cure = FALSE;
    f_ptr = &py.flags;
    if (f_ptr->poisoned > 1) {
	f_ptr->poisoned = 1;
	cure = TRUE;
    }
    return (cure);
}


/* Cure the players fear				-RAK-	 */
int 
remove_fear()
{
    register int        result;
    register struct flags *f_ptr;

    result = FALSE;
    f_ptr = &py.flags;
    if (f_ptr->afraid > 1) {
	f_ptr->afraid = 1;
	result = TRUE;
    }
    return (result);
}


/* This is a fun one.  In a given block, pick some walls and	 */
/* turn them into open spots.  Pick some open spots and turn	 */
/* them into walls.  An "Earthquake" effect.	       -RAK-   */
void 
earthquake()
{
    register int        i, j;
    register cave_type *c_ptr;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    int                 kill, damage, tmp, y, x;
    vtype               out_val, m_name;

    for (i = char_row - 8; i <= char_row + 8; i++)
	for (j = char_col - 8; j <= char_col + 8; j++)
	    if (((i != char_row) || (j != char_col)) &&
		in_bounds(i, j) && (randint(8) == 1)) {
		c_ptr = &cave[i][j];
		if (c_ptr->tptr != 0)
		    if (((t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
			 (t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
			 (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT))
			|| (t_list[c_ptr->tptr].tval == TV_UP_STAIR)
			|| (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR)
			|| (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
			continue;  /* don't touch artifacts or stairs or
				    * stores -CFT */
		    else
			(void)delete_object(i, j);
		if (c_ptr->cptr > 1) {
		    m_ptr = &m_list[c_ptr->cptr];
		    r_ptr = &c_list[m_ptr->mptr];

		    if (!(r_ptr->cmove & CM_PHASE) && !(r_ptr->cdefense & BREAK_WALL)) {
			if ((movement_rate(m_ptr->cspeed) == 0) ||
			    (r_ptr->cmove & CM_ATTACK_ONLY))
			/* monster can not move to escape the wall */
			    kill = TRUE;
			else {
			/*
			 * only kill if there is nowhere for the monster to
			 * escape to 
			 */
			    kill = TRUE;
			    for (y = i - 1; y <= i + 1; y++)
				for (x = j - 1; x <= j + 1; x++)
				    if (cave[y][x].fval >= MIN_CLOSED_SPACE)
					kill = FALSE;
			}
			if (kill)
			    damage = 320;
			else
			    damage = damroll(4, 8);
			monster_name(m_name, m_ptr, r_ptr);
			(void)sprintf(out_val, "%s wails out in pain!", m_name);
			msg_print(out_val);
			i = mon_take_hit((int)c_ptr->cptr, damage, TRUE);
			if (i >= 0) {
			    (void)sprintf(out_val, "%s is embedded in the rock.",
					  m_name);
			    msg_print(out_val);
			/* prt_experience(); */
			}
		    }
		}
		if ((c_ptr->fval >= MIN_CAVE_WALL) && (c_ptr->fval != BOUNDARY_WALL)) {
		    c_ptr->fval = CORR_FLOOR;
		    c_ptr->pl = FALSE;
		    c_ptr->fm = FALSE;
		} else if (c_ptr->fval <= MAX_CAVE_FLOOR) {
		    tmp = randint(10);
		    if (tmp < 6)
			c_ptr->fval = QUARTZ_WALL;
		    else if (tmp < 9)
			c_ptr->fval = MAGMA_WALL;
		    else
			c_ptr->fval = GRANITE_WALL;

		    c_ptr->fm = FALSE;
		}
		lite_spot(i, j);
	    }
}


/* Evil creatures don't like this.		       -RAK-   */
int 
protect_evil()
{
    register int        res;
    register struct flags *f_ptr;

    f_ptr = &py.flags;
    if (f_ptr->protevil == 0)
	res = TRUE;
    else
	res = FALSE;
    f_ptr->protevil += randint(25) + 3 * py.misc.lev;
    return (res);
}


/* Create some high quality mush for the player.	-RAK-	 */
void 
create_food()
{
#if 0
    register cave_type *c_ptr;

    c_ptr = &cave[char_row][char_col];
    if (c_ptr->tptr != 0) {
    /* take no action here, don't want to destroy object under player */
	msg_print("There is already an object under you.");
    /* set free_turn_flag so that scroll/spell points won't be used */
	free_turn_flag = TRUE;
    } else {
	int                 cur_pos, tmp;

	cur_pos = popt();
	cave[char_row][char_col].tptr = cur_pos;
	tmp = get_obj_num(dun_level, FALSE);
	invcopy(&t_list[cur_pos], OBJ_MUSH);
	msg_print("You feel something roll beneath your feet.");
    }
#endif

     /* add to food timer rather than create mush - cba */
     add_food(object_list[OBJ_MUSH].p1);
     py.flags.status &= ~(PY_WEAK | PY_HUNGRY);
     prt_hunger();
}

int 
banish_creature(cflag, dist)
    int32u              cflag;
    int                 dist;
{
    register int        i;
    int                 dispel;
    register monster_type *m_ptr;

    dispel = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	if ((cflag & c_list[m_ptr->mptr].cdefense) &&
	    (m_ptr->cdis <= MAX_SIGHT) &&
	    los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) {
	    c_recall[m_ptr->mptr].r_cdefense |= cflag;
	    (void)teleport_away(i, dist);
	    dispel = TRUE;
	}
    }
    return (dispel);
}

int 
probing()
{
    register int        i;
    int                 probe;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    msg_print("Probing...");
    probe = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	r_ptr = &c_list[m_ptr->mptr];
	if ((m_ptr->cdis <= MAX_SIGHT) &&
	    los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) {
	    if (!m_ptr->ml) {
		break;
	    } else {
		if (r_ptr->cdefense & UNIQUE)
		    sprintf(m_name, "%s", r_ptr->name);
		else
		    sprintf(m_name, "The %s", r_ptr->name);
	    }
	    sprintf(out_val, "%s has %d hit points.", m_name, m_ptr->hp);
	    move_cursor_relative(m_ptr->fy, m_ptr->fx);
	    msg_print(out_val);
	    probe = TRUE;
	}
    }
    if (probe)
	msg_print("That's all.");
    else
	msg_print("You find nothing to probe.");
    move_cursor_relative(char_row, char_col);
    return (probe);
}

/* Attempts to destroy a type of creature.  Success depends on	 */
/* the creatures level VS. the player's level		 -RAK-	 */
int 
dispel_creature(cflag, damage)
    int                 cflag;
    int                 damage;
{
    register int        i;
    int                 k, dispel, visible;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    dispel = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	if ((cflag & c_list[m_ptr->mptr].cdefense) &&
	    (m_ptr->cdis <= MAX_SIGHT) &&
	    los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) {
	    r_ptr = &c_list[m_ptr->mptr];
	    c_recall[m_ptr->mptr].r_cdefense |= cflag;
	    visible = m_ptr->ml;   /* set this before call mon_take_hit */
	    k = mon_take_hit(i, randint(damage), FALSE);
	    if (visible)
		monster_name(m_name, m_ptr, r_ptr);
	    else
		strcpy(m_name, "It");
	    if (k >= 0)
		(void)sprintf(out_val, "%s dissolves!", m_name);
	    else
		(void)sprintf(out_val, "%s shudders.", m_name);
	    msg_print(out_val);
	    dispel = TRUE;
	    if (k >= 0)
		prt_experience();
	}
    }
    return (dispel);
}


/* Attempt to turn (confuse) undead creatures.	-RAK-	 */
int 
turn_undead()
{
    register int        i, turn_und;
    register monster_type *m_ptr;
    register creature_type *r_ptr;
    vtype               out_val, m_name;

    turn_und = FALSE;
    for (i = mfptr - 1; i >= MIN_MONIX; i--) {
	m_ptr = &m_list[i];
	r_ptr = &c_list[m_ptr->mptr];
	if ((UNDEAD & r_ptr->cdefense)
	    && (m_ptr->cdis <= MAX_SIGHT)
	    && (los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))) {
	    monster_name(m_name, m_ptr, r_ptr);
	    if (((py.misc.lev + 1) > r_ptr->level) ||
		(randint(5) == 1)) {
		if (m_ptr->ml) {
		    (void)sprintf(out_val, "%s runs frantically!", m_name);
		    msg_print(out_val);
		    turn_und = TRUE;
		    c_recall[m_ptr->mptr].r_cdefense |= UNDEAD;
		}
		m_ptr->monfear = randint(py.misc.lev) * 2;
	    } else if (m_ptr->ml) {
		(void)sprintf(out_val, "%s is unaffected.", m_name);
		msg_print(out_val);
	    }
	}
    }
    return (turn_und);
}


/* Leave a glyph of warding. Creatures will not pass over! -RAK- */
void 
warding_glyph()
{
    register int        i;
    register cave_type *c_ptr;

    c_ptr = &cave[char_row][char_col];
    if (c_ptr->tptr == 0) {
	i = popt();
	c_ptr->tptr = i;
	invcopy(&t_list[i], OBJ_SCARE_MON);
    }
}


/* Lose a strength point.				-RAK-	 */
void 
lose_str()
{
    if (!py.flags.sustain_str) {
	(void)dec_stat(A_STR);
	msg_print("You feel very weak.");
    } else
	msg_print("You feel weak for a moment;  it passes.");
}


/* Lose an intelligence point.				-RAK-	 */
void 
lose_int()
{
    if (!py.flags.sustain_int) {
	(void)dec_stat(A_INT);
	msg_print("You become very dizzy.");
    } else
	msg_print("You become dizzy for a moment;  it passes.");
}


/* Lose a wisdom point.					-RAK-	 */
void 
lose_wis()
{
    if (!py.flags.sustain_wis) {
	(void)dec_stat(A_WIS);
	msg_print("You feel very naive.");
    } else
	msg_print("You feel naive for a moment;  it passes.");
}


/* Lose a dexterity point.				-RAK-	 */
void 
lose_dex()
{
    if (!py.flags.sustain_dex) {
	(void)dec_stat(A_DEX);
	msg_print("You feel very sore.");
    } else
	msg_print("You feel sore for a moment;  it passes.");
}


/* Lose a constitution point.				-RAK-	 */
void 
lose_con()
{
    if (!py.flags.sustain_con) {
	(void)dec_stat(A_CON);
	msg_print("You feel very sick.");
    } else
	msg_print("You feel sick for a moment;  it passes.");
}


/* Lose a charisma point.				-RAK-	 */
void 
lose_chr()
{
    if (!py.flags.sustain_chr) {
	(void)dec_stat(A_CHR);
	msg_print("Your skin starts to itch.");
    } else
	msg_print("Your skin starts to itch, but feels better now.");
}


/* Lose experience					-RAK-	 */
void 
lose_exp(amount)
    int32               amount;
{
    register int        i;
    register struct misc *m_ptr;
    register class_type *c_ptr;

    m_ptr = &py.misc;
    if (amount > m_ptr->exp)
	m_ptr->exp = 0;
    else
	m_ptr->exp -= amount;
    prt_experience();

    i = 0;
    while (((player_exp[i] * m_ptr->expfact / 100) <= m_ptr->exp)
	   && (i < MAX_PLAYER_LEVEL))
	i++;
/* increment i once more, because level 1 exp is stored in player_exp[0] */
    i++;
    if (i > MAX_PLAYER_LEVEL)
	i = MAX_PLAYER_LEVEL;
    if (m_ptr->lev != i) {
	m_ptr->lev = i;

	calc_hitpoints();
	c_ptr = &class[m_ptr->pclass];
	if (c_ptr->spell == MAGE) {
	    calc_spells(A_INT);
	    calc_mana(A_INT);
	} else if (c_ptr->spell == PRIEST) {
	    calc_spells(A_WIS);
	    calc_mana(A_WIS);
	}
	prt_level();
	prt_title();
    }
}


/* Slow Poison						-RAK-	 */
int 
slow_poison()
{
    register int        slow;
    register struct flags *f_ptr;

    slow = FALSE;
    f_ptr = &py.flags;
    if (f_ptr->poisoned > 0) {
	f_ptr->poisoned = f_ptr->poisoned / 2;
	if (f_ptr->poisoned < 1)
	    f_ptr->poisoned = 1;
	slow = TRUE;
	msg_print("The effect of the poison has been reduced.");
    }
    return (slow);
}


/* Bless						-RAK-	 */
void 
bless(amount)
    int                 amount;
{
    py.flags.blessed += amount;
}


/* Detect Invisible for period of time			-RAK-	 */
void 
detect_inv2(amount)
    int                 amount;
{
    py.flags.detect_inv += amount;
}


static void 
replace_spot(y, x, typ)
    int                 y, x, typ;
{
    register cave_type *c_ptr;

    c_ptr = &cave[y][x];
    switch (typ) {
      case 1:
      case 2:
      case 3:
	c_ptr->fval = CORR_FLOOR;
	break;
      case 4:
      case 7:
      case 10:
	c_ptr->fval = GRANITE_WALL;
	break;
      case 5:
      case 8:
      case 11:
	c_ptr->fval = MAGMA_WALL;
	break;
      case 6:
      case 9:
      case 12:
	c_ptr->fval = QUARTZ_WALL;
	break;
    }
    c_ptr->pl = FALSE;
    c_ptr->fm = FALSE;
    c_ptr->lr = FALSE;		   /* this is no longer part of a room */
    if (c_ptr->tptr != 0)
	(void)delete_object(y, x);
    if (c_ptr->cptr > 1)
	delete_monster((int)c_ptr->cptr);
}


/* The spell of destruction.				-RAK-	 */
/* NOTE : Winning creatures that are deleted will be considered	 */
/* as teleporting to another level.  This will NOT win the */
/* game.						       */
void 
destroy_area(y, x)
    register int        y, x;
{
    register int        i, j, k;

    msg_print("There is a searing blast of light!");
    if (!py.flags.blindness_resist && !py.flags.light_resist)
	py.flags.blind += 10 + randint(10);
    if (dun_level > 0) {
	for (i = (y - 15); i <= (y + 15); i++)
	    for (j = (x - 15); j <= (x + 15); j++)
		if (in_bounds(i, j) && (cave[i][j].fval != BOUNDARY_WALL) &&
		    ((cave[i][j].tptr == 0) ||
		     ((t_list[cave[i][j].tptr].tval != TV_UP_STAIR) &&
		      (t_list[cave[i][j].tptr].tval != TV_DOWN_STAIR) &&
		      (!(t_list[cave[i][j].tptr].flags2 & TR_ARTIFACT))))) {	/* DGK */
		    k = distance(i, j, y, x);
		    if (k == 0)	   /* player's spot... */
			replace_spot(i, j, 1);	/* clear player's spot...
						 * from um55 -CFT */
		    else if (k < 13)
			replace_spot(i, j, randint(6));
		    else if (k < 16)
			replace_spot(i, j, randint(9));
		}
    }
    if (py.flags.blindness_resist || py.flags.light_resist) {	/* We need to redraw the
								 * screen. -DGK */
	draw_cave();
	creatures(FALSE);	   /* draw monsters */
    }
}


/* Enchants a plus onto an item.                        -RAK-   */
int 
enchant(plusses, my_limit)
    int16              *plusses;
    int                 my_limit;  /* maximum bonus allowed; usually 10, but
				    * weapon's maximum damage when enchanting
				    * melee weapons to damage */

/* *Enchant Weapon/Armor* increases limit by 5 -DGK */
{
    int16               limit = (int16) my_limit;
    register int        chance, res;

    if (limit <= 0)		   /* avoid randint(0) call */
	return (FALSE);
    if (limit > 25)		   /* Glaives of Pain (+10, +60) are -BAD-!
				    * -DGK */
	limit = 25;
    chance = 0;
    res = FALSE;
    if (*plusses > 0) {
	chance = *plusses;
	if (randint(100) == 1)	   /* very rarely allow enchantment over
				    * limit */
	    chance = randint(chance) - 1;
    }
    if (randint(limit) > chance) {
	*plusses += 1;
	res = TRUE;
    }
    return (res);
}


void 
elemental_brand()
{
    register inven_type *i_ptr;

    i_ptr = &inventory[INVEN_WIELD];
    if (i_ptr->tval != TV_NOTHING && i_ptr->name2 == SN_NULL &&
	i_ptr->tval != TV_BOW) {
	int                 k, l, hot = randint(2) - 1;
	char                tmp_str[100], out_val[100];

	objdes(tmp_str, i_ptr, FALSE);
	if (hot) {
	    if (i_ptr->number == 1)
		sprintf(out_val, "Your %s glows with a fiery aura!", tmp_str);
	    else
		sprintf(out_val, "Your %s glow with a fiery aura!", tmp_str);
	    if (inventory[INVEN_WIELD].tval != TV_NOTHING) {
		i_ptr->name2 = SN_FT;
		i_ptr->flags |= (TR_FLAME_TONGUE | TR_RES_FIRE);
	    } else {
		i_ptr->name2 = SN_FIRE;
		i_ptr->flags |= TR_FLAME_TONGUE;
	    }
	} else {
	    if (i_ptr->number == 1)
		sprintf(out_val, "Your %s glows a deep, icy blue!", tmp_str);
	    else
		sprintf(out_val, "Your %s glow a deep, icy blue!", tmp_str);
	    i_ptr->name2 = SN_FB;
	    if (inventory[INVEN_WIELD].tval != TV_NOTHING)
		i_ptr->flags |= (TR_FROST_BRAND | TR_RES_COLD);
	    else
		i_ptr->flags |= (TR_FROST_BRAND);
	}
	msg_print(out_val);

	k = 3 + randint(3);
	for (l = 0; l < k; l++)	   /* Don't need to check if it's an artifact */
	    enchant(&i_ptr->tohit, 10);	/* since ->name2 is checked -DGK */
	k = 3 + randint(3);
	for (l = 0; l < k; l++)
	    enchant(&i_ptr->todam, ((i_ptr->damage[0]) * (i_ptr->damage[1])));
    /* used to clear TR_CURSED; should remain set -DGK- */
	calc_bonuses();
    } else
	msg_print("The Branding fails.");
}



const char               *
pain_message(monptr, dam)
    int                 monptr, dam;
{
    register monster_type *m_ptr;
    creature_type      *c_ptr;
    int                 percentage, oldhp, newhp;

    if (dam == 0)
	return "%s is unharmed.";  /* avoid potential div by 0 */

    m_ptr = &m_list[monptr];
    c_ptr = &c_list[m_ptr->mptr];
#ifdef MSDOS			   /* more fix -CFT */
    newhp = (int32) (m_ptr->hp);
    oldhp = newhp + (int32) dam;
#else
    newhp = m_ptr->hp;
    oldhp = newhp + dam;
#endif
    percentage = (newhp * 100) / oldhp;

    if ((c_ptr->cchar == 'j') ||   /* Non-verbal creatures like molds */
	(c_ptr->cchar == 'Q') || (c_ptr->cchar == 'v') ||
     (c_ptr->cchar == 'm') || ((c_ptr->cchar == 'e') && stricmp(c_ptr->name,
							     "Beholder"))) {
	if (percentage > 95)
	    return "%s barely notices.";
	if (percentage > 75)
	    return "%s flinches.";
	if (percentage > 50)
	    return "%s squelches.";
	if (percentage > 35) {
	    if (randint(4) == 1) /* thanks to dbd@panacea.phys.utk.edu -CWS */
		return "%s quivers in pain.";
	    else
		return "%s imitates Bill Cosby in pain.";
	}
	if (percentage > 20)
	    return "%s writhes about.";
	if (percentage > 10)
	    return "%s writhes in agony.";
	return "%s jerks limply.";
    } else if (c_ptr->cchar == 'C' || c_ptr->cchar == 'Z') {
	if (percentage > 95)
	    return "%s shrugs off the attack.";
	if (percentage > 75)
	    return "%s snarls with pain.";
	if (percentage > 50)
	    return "%s yelps in pain.";
	if (percentage > 35)
	    return "%s howls in pain.";
	if (percentage > 20)
	    return "%s howls in agony.";
	if (percentage > 10)
	    return "%s writhes in agony.";
	return "%s yelps feebly.";
    } else if (c_ptr->cchar == 'K' || c_ptr->cchar == 'c' || c_ptr->cchar == 'a' ||
	c_ptr->cchar == 'U' || c_ptr->cchar == 'q' || c_ptr->cchar == 'R' ||
	c_ptr->cchar == 'X' || c_ptr->cchar == 'b' || c_ptr->cchar == 'F' ||
	c_ptr->cchar == 'J' || c_ptr->cchar == 'l' || c_ptr->cchar == 'r' ||
	c_ptr->cchar == 's' || c_ptr->cchar == 'S' || c_ptr->cchar == 't') {
	if (percentage > 95)
	    return "%s ignores the attack.";
	if (percentage > 75)
	    return "%s grunts with pain.";
	if (percentage > 50)
	    return "%s squeals in pain.";
	if (percentage > 35)
	    return "%s shrieks in pain.";
	if (percentage > 20)
	    return "%s shrieks in agony.";
	if (percentage > 10)
	    return "%s writhes in agony.";
	return "%s cries out feebly.";
    } else {
	if (percentage > 95)
	    return "%s shrugs off the attack.";
	if (percentage > 75)
	    return "%s grunts with pain.";
	if (percentage > 50)
	    return "%s cries out in pain.";
	if (percentage > 35)
	    return "%s screams in pain.";
	if (percentage > 20)
	    return "%s screams in agony.";
	if (percentage > 10)
	    return "%s writhes in agony.";
	return "%s cries out feebly.";
    }
}

/* Removes curses from items in inventory		-RAK-	 */
int 
remove_curse()
{
    register int        i, result;
    register inven_type *i_ptr;

    result = FALSE;
    for (i = INVEN_WIELD; i <= INVEN_OUTER; i++) {
	i_ptr = &inventory[i];
	if ((TR_CURSED & i_ptr->flags) &&
	    (i_ptr->name2 != SN_MORGUL) &&
	    (i_ptr->name2 != SN_CALRIS) &&
	    (i_ptr->name2 != SN_MORMEGIL)) {
	    if (!(!stricmp(object_list[i_ptr->index].name, "Power") &&
		  (i_ptr->tval == TV_RING))) {
		i_ptr->flags &= ~TR_CURSED;
		i_ptr->ident &= ~ID_DAMD;	/* DGK */
		i_ptr->inscrip[0] = '\0';
		calc_bonuses();
		result = TRUE;
	    }
	}
    }
    return (result);
}

int 
remove_all_curse()
{
    register int        i, result;
    register inven_type *i_ptr;

    result = FALSE;
    for (i = INVEN_WIELD; i <= INVEN_OUTER; i++) {
	i_ptr = &inventory[i];
	if (TR_CURSED & i_ptr->flags) {
	    if (!(!stricmp(object_list[i_ptr->index].name, "Power") &&
		  (i_ptr->tval == TV_RING))) {
		i_ptr->flags &= ~TR_CURSED;
		i_ptr->ident &= ~ID_DAMD;	/* DGK */
		calc_bonuses();
		i_ptr->inscrip[0] = '\0';
		result = TRUE;
	    } else {
		msg_print("The One Ring resists all attempts to remove it!");
	    }
	}
    }
    return (result);
}


/* Restores any drained experience			-RAK-	 */
int 
restore_level()
{
    register int        restore;
    register struct misc *m_ptr;

    restore = FALSE;
    m_ptr = &py.misc;
    if (m_ptr->max_exp > m_ptr->exp) {
	restore = TRUE;
	msg_print("You feel your life energies returning.");
    /* this while loop is not redundant, ptr_exp may reduce the exp level */
	while (m_ptr->exp < m_ptr->max_exp) {
	    m_ptr->exp = m_ptr->max_exp;
	    prt_experience();
	}
    }
    return (restore);
}


/*
 * this fn only exists to avoid duplicating this code in the selfknowledge
 * fn. -CFT 
 */
static void 
pause_if_screen_full(i, j)
    int                *i;
    int                 j;
{
    int                 t;

    if (*i == 22) {		   /* is screen full? */
	prt("-- more --", *i, j);
	inkey();
	for (t = 2; t < 23; t++)
	    erase_line(t, j);	   /* don't forget to erase extra */
	prt("Your Attributes: (continued)", 1, j + 5);
	*i = 2;
    }
}

/*
 * self-knowledge... idea from nethack.  Useful for determining powers and
 * resistences of items.  It saves the screen, clears it, then starts listing
 * attributes, a screenful at a time.  (There are a LOT of attributes to
 * list.  It will probably take 2 or 3 screens for a powerful character whose
 * using several artifacts...) -CFT 
 */

void 
self_knowledge()
{
    int                 i, j;
    int32u              f = 0L, f2 = 0L;

    for (i = INVEN_WIELD; i <= INVEN_LIGHT; i++) {	/* get flags from items */
	if (inventory[i].tval != TV_NOTHING) {
	    if (inventory[i].p1 < 0) /* don't adjust TR_STATS if p1 is negative -CWS */
		f |= (inventory[i].flags & ~(TR_STATS | TR_SEARCH | TR_STEALTH) );
	    else
		f |= inventory[i].flags;
	    f2 |= inventory[i].flags2;
	}
    }

    save_screen();

    j = 15;			   /* map starts at 13, but I want a couple
				    * of spaces.  This means must start by
				    * erasing map... */
    for (i = 1; i < 23; i++)
	erase_line(i, j - 2);	   /* erase a couple of spaces to left */

    i = 1;
    prt("Your Attributes:", i++, j + 5);

    if (py.flags.blind > 0)
	prt("You cannot see.", i++, j);
    if (py.flags.confused > 0)
	prt("You are confused.", i++, j);
    if (py.flags.afraid > 0)
	prt("You are terrified.", i++, j);
    if (py.flags.cut > 0)
	prt("You are bleeding.", i++, j);
    if (py.flags.stun > 0)
	prt("You are stunned and reeling.", i++, j);
    if (py.flags.poisoned > 0)
	prt("You are poisoned.", i++, j);
    if (py.flags.image > 0)
	prt("You are hallucinating.", i++, j);
    if (py.flags.aggravate)
	prt("You aggravate monsters.", i++, j);
    if (py.flags.teleport)
	prt("Your position is very uncertain.", i++, j);

    if (py.flags.blessed > 0)
	prt("You feel rightous.", i++, j);
    if (py.flags.hero > 0)
	prt("You feel heroic.", i++, j);
    if (py.flags.shero > 0)
	prt("You are in a battle rage.", i++, j);
    if (py.flags.protevil > 0)
	prt("You are protected from evil.", i++, j);
    if (py.flags.shield > 0)
	prt("You are protected by a mystic shield.", i++, j);
    if (py.flags.invuln > 0)
	prt("You are temporarily invulnerable.", i++, j);
    if (py.flags.confuse_monster)
	prt("Your hands are glowing dull red.", i++, j);
    if (py.flags.new_spells > 0)
	prt("You can learn some more spells.", i++, j);
    if (py.flags.word_recall > 0)
	prt("You will soon be recalled.", i++, j);

    if (f & TR_STEALTH)
	prt("You are magically stealthy.", i++, j);
    if (f & TR_SEARCH) {
	prt("You are magically perceptive.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if ((py.flags.see_infra) || (py.flags.tim_infra)) {
	prt("Your eyes are sensitive to infrared light.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if ((py.flags.see_inv) || (py.flags.detect_inv)) {
	prt("You can see invisible creatures.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.ffall) {
	prt("You land gently.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.free_act) {
	prt("You have free action.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.regenerate) {
	prt("You regenerate quickly.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.slow_digest) {
	prt("Your appetite is small.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.telepathy) {
	prt("You have ESP.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.hold_life) {
	prt("You have a firm hold on your life force.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.light) {
	prt("You are carrying a permanent light.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.fear_resist) {
	prt("You are completely fearless.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.blindness_resist) {
	prt("Your eyes are resistant to blindness.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.fire_im) {
	prt("You are completely immune to fire.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.fire_resist) && (py.flags.resist_heat)) {
	prt("You resist fire exceptionally well.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.fire_resist) || (py.flags.resist_heat)) {
	prt("You are resistant to fire.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.cold_im) {
	prt("You are completely immune to cold.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.cold_resist) && (py.flags.resist_cold)) {
	prt("You resist cold exceptionally well.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.cold_resist) || (py.flags.resist_cold)) {
	prt("You are resistant to cold.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.acid_im) {
	prt("You are completely immune to acid.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.acid_resist) && (py.flags.resist_acid)) {
	prt("You resist acid exceptionally well.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.acid_resist) || (py.flags.resist_acid)) {
	prt("You are resistant to acid.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.poison_im) {
	prt("You are completely immune to poison.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.poison_resist) && (py.flags.resist_poison)) {
	prt("You resist poison exceptionally well.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.poison_resist) || (py.flags.resist_poison)) {
	prt("You are resistant to poison.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.light_im) {
	prt("You are completely immune to lightning.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.lght_resist) && (py.flags.resist_light)) {
	prt("You resist lightning exceptionally well.", i++, j);
	pause_if_screen_full(&i, j);
    } else if ((py.flags.lght_resist) || (py.flags.resist_light)) {
	prt("You are resistant to lightning.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.light_resist) {
	prt("You are resistant to bright light.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.dark_resist) {
	prt("You are resistant to darkness.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.confusion_resist) {
	prt("You are resistant to confusion.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.sound_resist) {
	prt("You are resistant to sonic attacks.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.disenchant_resist) {
	prt("You are resistant to disenchantment.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.chaos_resist) {
	prt("You are resistant to chaos.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.shards_resist) {
	prt("You are resistant to blasts of shards.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.nexus_resist) {
	prt("You are resistant to nexus attacks.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.nether_resist) {
	prt("You are resistant to nether forces.", i++, j);
	pause_if_screen_full(&i, j);
    }
/*
 * Are these needed?  The player can see this...  For now, in here for
 * completeness... -CFT 
 */
    if (f & TR_STR) {
	prt("You are magically strong.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_INT) {
	prt("You are magically intelligent.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_WIS) {
	prt("You are magically wise.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_DEX) {
	prt("You are magically agile.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_CON) {
	prt("You are magically tough.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_CHR) {
	prt("You are magically popular.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.sustain_str) {
	prt("You will not become weaker.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.sustain_int) {
	prt("You will not become dumber.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.sustain_wis) {
	prt("You will not become less wise.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.sustain_con) {
	prt("You will not become out of shape.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.sustain_dex) {
	prt("You will not become clumsy.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (py.flags.sustain_chr) {
	prt("You will not become less popular.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (inventory[INVEN_LEFT].flags2 & TR_ATTACK_SPD ||
	inventory[INVEN_RIGHT].flags2 & TR_ATTACK_SPD) {
	prt("You can strike at your foes with uncommon speed.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (inventory[INVEN_WIELD].tval != TV_NOTHING) {	/* this IS a bit
							 * redundant, but it
							 * prevents flags from
							 * other items from
							 * affecting the weapon
							 * stats... -CFT */
	f = inventory[INVEN_WIELD].flags;
	f2 = inventory[INVEN_WIELD].flags2;
    } else {
	f = 0L;
	f2 = 0L;
    }
    if (f & TR_CURSED) {
	if (inventory[INVEN_WIELD].name2 == SN_MORGUL)
	    prt("Your weapon is truly foul.", i++, j);
	else if (inventory[INVEN_WIELD].name2 == SN_CALRIS)
	    prt("Your bastard sword is wickedly accursed.", i++, j);
	else if (inventory[INVEN_WIELD].name2 == SN_MORMEGIL)
	    prt("Your two-handed sword radiates an aura of unspeakable evil.", i++, j);
	else
	    prt("Your weapon is accursed.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_TUNNEL) {
	prt("Your weapon is an effective digging tool.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f2 & TR_BLESS_BLADE) {
	prt("Your weapon has been blessed by the gods.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f2 & TR_ATTACK_SPD) {
	prt("Your weapon strikes with uncommon speed.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f2 & TR_SLAY_ORC) {
	prt("Your weapon is especially deadly against orcs.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f2 & TR_SLAY_TROLL) {
	prt("Your weapon is especially deadly against trolls.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f2 & TR_SLAY_GIANT) {
	prt("Your weapon is especially deadly against giants.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_SLAY_ANIMAL) {
	prt("Your weapon is especially deadly against natural creatures.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_SLAY_X_DRAGON) {
	prt("Your weapon is a great bane of dragons.", i++, j);
	pause_if_screen_full(&i, j);
    } else if (f & TR_SLAY_DRAGON) {
	prt("Your weapon is especially deadly against dragons.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f2 & TR_SLAY_DEMON) {
	prt("Your weapon strikes at demons with holy wrath.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_SLAY_UNDEAD) {
	prt("Your weapon strikes at undead with holy wrath.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_SLAY_EVIL) {
	prt("Your weapon fights against evil with holy fury.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_FROST_BRAND) {
	prt("Your frigid weapon freezes your foes.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f & TR_FLAME_TONGUE) {
	prt("Your flaming weapon burns your foes.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f2 & TR_LIGHTNING) {
	prt("Your weapon electrocutes your foes.", i++, j);
	pause_if_screen_full(&i, j);
    }
    if (f2 & TR_IMPACT)
	prt("The unbelievable impact of your weapon can cause earthquakes.", i++, j);

    pause_line(i);
    restore_screen();
}


/*
 * This function will process a bolt/ball/breath spell hitting a monster. It
 * checks for resistances, and reduces damage accordingly, and also adds in
 * what "special effects" apply to the monsters.  'rad' is used to indicate
 * the distance from "ground 0" for ball spells.  For bolts, rad should be a
 * 0.  dam is changed to reflect resistances and range. -CFT 
 */
static void 
spell_hit_monster(m_ptr, typ, dam, rad, y, x)
    monster_type       *m_ptr;
    int                 typ;
    int                *dam;
    int                 rad;
    int                *y;
    int                *x;
{
    register creature_type *r_ptr;
    int                 blind = (py.flags.status & PY_BLIND) ? 1 : 0;
    vtype               cdesc, outval;

    if (rad > 0)
	*dam /= rad;		   /* adjust damage for range... */

    *y = m_ptr->fy;		   /* these only change if mon gets
				    * teleported */
    *x = m_ptr->fx;
    r_ptr = &c_list[m_ptr->mptr];
    if (m_ptr->ml) {
	if (r_ptr->cdefense & UNIQUE)
	    sprintf(cdesc, "%s ", r_ptr->name);
	else
	    sprintf(cdesc, "The %s ", r_ptr->name);
    } else
	strcpy(cdesc, "It ");

    if (!blind && rad) {	   /* show "hit" msg before doing effects
				    * -CFT */
	sprintf(outval, "%sis hit.", cdesc);
	msg_print(outval);
    }
    switch (typ) {		   /* check for resists... */
      case GF_MAGIC_MISSILE:	   /* pure damage, no resist possible */
	break;
      case GF_LIGHTNING:
	if (r_ptr->cdefense & IM_LIGHTNING) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam /= 9;
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= IM_LIGHTNING;
	}
	break;
      case GF_POISON_GAS:
	if (r_ptr->cdefense & IM_POISON) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam /= 9;
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= IM_POISON;
	}
	break;
      case GF_ACID:
	if (r_ptr->cdefense & IM_ACID) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam /= 9;
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= IM_ACID;
	}
	break;
      case GF_FROST:
	if (r_ptr->cdefense & IM_FROST) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam /= 9;
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= IM_FROST;
	}
	break;
      case GF_FIRE:
	if (r_ptr->cdefense & IM_FIRE) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam /= 9;
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= IM_FIRE;
	}
	break;
      case GF_HOLY_ORB:
	if (r_ptr->cdefense & EVIL) {
	    *dam *= 2;
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= EVIL;
	}
	break;
      case GF_ARROW:		   /* for now, no defense... maybe it should
				    * have a chance of missing? -CFT */
	break;
      case GF_PLASMA:		   /* maybe IM_LIGHTNING (ball lightning is
				    * supposed to be plasma) or IM_FIRE
				    * (since it's hot)? -CFT */
	if (!strncmp("Plasma", r_ptr->name, 6) ||
	    (r_ptr->spells3 & BREATH_PL)) {	/* if is a "plasma" monster,
						 * or can breathe plasma,
						 * then we assume it should
						 * be immune. plasma bolts
						 * don't count, since
						 * mage-types could have
						 * them, and not deserve
						 * plasma-resist -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	}
	break;
      case GF_NETHER:		   /* I assume nether is an evil, necromantic
				    * force, so it doesn't hurt undead, and
				    * hurts evil less -CFT */
	if (r_ptr->cdefense & UNDEAD) {
	    if (!blind) {
		sprintf(outval, "%sseems immune.", cdesc);
		msg_print(outval);
	    }
	    *dam = 0;
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= UNDEAD;
	} else if (r_ptr->spells2 & BREATH_LD) {	/* if can breath nether,
							 * should get good
							 * resist to damage -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	} else if (r_ptr->cdefense & EVIL) {
	    *dam /= 2;		   /* evil takes *2 for holy, so /2 for
				    * this... -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists somewhat.", cdesc);
		msg_print(outval);
	    }
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= EVIL;
	}
	break;
      case GF_WATER:		   /* water elementals should resist.  anyone
				    * else? -CFT */
	if ((r_ptr->cchar == 'E') && (r_ptr->name[0] == 'W')) {
	    if (!blind) {
		sprintf(outval, "%sseems immune.", cdesc);
		msg_print(outval);
	    }
	    *dam = 0;		   /* water spirit, water ele, and Waldern
				    * -CFT */
	}
	break;
      case GF_CHAOS:
	if (r_ptr->spells2 & BREATH_CH) {	/* assume anything that
						 * breathes chaos is chaotic
						 * enough to deserve
						 * resistance... -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	}
	if (*dam > m_ptr->hp)
	    break;		   /* don't bother with special effects...
				    * it's dead! -CFT */
	if (!(r_ptr->spells2 & BREATH_CH) &&
	    !(r_ptr->cdefense & UNIQUE) &&
	    (randint(100) > r_ptr->level)) {	/* then we'll polymorph it
						 * -CFT */
	    int                 i, j, k;

	    if (!blind) {
		sprintf(outval, "%schanges.", cdesc);
		msg_print(outval);
	    }
	    i = (randint(20) / randint(9)) + 1;
	    j = r_ptr->level - i;  /* get range of levels... */
	    k = r_ptr->level + i;
	    if (j < 0)
		j = 0;
	    if (k > MAX_MONS_LEVEL)
		k = MAX_MONS_LEVEL;
	    delete_monster(cave[*y][*x].cptr);
	    do {
		i = randint(m_level[k] - m_level[j]) - 1 + m_level[j];	/* monster index */
		if ((c_list[i].cdefense & UNIQUE) == 0)
		    place_monster(*y, *x, i, FALSE);
	    } while (cave[*y][*x].cptr < MIN_MONIX);	/* until we get
							 * something-CFT */
	}
    /*
     * end of chaos-poly.  If was poly-ed don't bother confuse... it's too
     * hectic to keep track of... -CFT 
	 */ 
	else if (!(r_ptr->cdefense & CHARM_SLEEP) &&
		 !(r_ptr->spells2 & BREATH_CH) &&	/* choatics hard to
							 * confuse */
		 !(r_ptr->spells2 & BREATH_CO))	/* so are bronze dragons */
	    if (m_ptr->confused > 0) {
		if (m_ptr->confused < 240) {	/* make sure not to overflow
						 * -CFT */
		    if (!blind) {
			sprintf(outval, "%sis more confused.", cdesc);
			msg_print(outval);
		    }
		    m_ptr->confused += 7 / (rad > 0 ? rad : 1);
		}
	    } else {
		if (!blind) {
		    sprintf(outval, "%sis confused.", cdesc);
		    msg_print(outval);
		}
		m_ptr->confused = (randint(11) + 5) / (rad > 0 ? rad : 1);
	    }
	break;
      case GF_SHARDS:
	if (r_ptr->spells2 & BREATH_SH) {	/* shard breathers resist
						 * -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	}
	break;
      case GF_SOUND:
	if (r_ptr->spells2 & BREATH_SD) {	/* ditto for sound -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 2;
	    *dam /= (randint(6) + 6);
	}
	if (*dam > m_ptr->hp)
	    break;		   /* don't bother with special effects...
				    * it's dead! -CFT */
	if (!(r_ptr->spells2 & BREATH_SD) &&
	    !(r_ptr->spells3 & BREATH_WA))	/* sound and impact breathers
						 * should not stun -CFT */
	    if (m_ptr->confused > 0) {
		if (m_ptr->confused < 220) {	/* make sure not to overflow
						 * -CFT */
		    if (!blind) {
			sprintf(outval, "%sis more dazed.", cdesc);
			msg_print(outval);
		    }
		    m_ptr->confused += (randint(5) * 2) / (rad > 0 ? rad : 1);
		}
	    } else {
		if (!blind) {
		    sprintf(outval, "%sis dazed.", cdesc);
		    msg_print(outval);
		}
		m_ptr->confused = (randint(15) + 10) / (rad > 0 ? rad : 1);
	    }
	break;
      case GF_CONFUSION:
	if (r_ptr->spells2 & BREATH_CO) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 2;
	    *dam /= (randint(6) + 6);
	} else if (r_ptr->cdefense & CHARM_SLEEP) {
	    if (!blind) {
		sprintf(outval, "%sresists somewhat.", cdesc);
		msg_print(outval);
	    }
	    *dam /= 2;		   /* only some resist, but they also avoid
				    * confuse -CFT */
	}
	if (*dam > m_ptr->hp)
	    break;		   /* don't bother with special effects...
				    * it's dead! -CFT */
	if (!(r_ptr->cdefense & CHARM_SLEEP) &&
	    !(r_ptr->spells2 & BREATH_CH) &&	/* chaotics hard to confuse */
	    !(r_ptr->spells2 & BREATH_CO))	/* so are bronze dragons */
	    if (m_ptr->confused > 0) {
		if (m_ptr->confused < 240) {	/* make sure not to overflow
						 * -CFT */
		    if (!blind) {
			sprintf(outval, "%sis more confused.", cdesc);
			msg_print(outval);
		    }
		    m_ptr->confused += 7 / (rad > 0 ? rad : 1);
		}
	    } else {
		if (!blind) {
		    sprintf(outval, "%sis confused.", cdesc);
		    msg_print(outval);
		}
		m_ptr->confused = (randint(11) + 5) / (rad > 0 ? rad : 1);
	    }
	break;
      case GF_DISENCHANT:
	if ((r_ptr->spells2 & BREATH_DI) ||
	    !strncmp("Disen", r_ptr->name, 5)) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	}
	break;
      case GF_NEXUS:
	if ((r_ptr->spells2 & BREATH_NE) ||
	    !strncmp("Nexus", r_ptr->name, 5)) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	}
	break;
      case GF_FORCE:
	if (r_ptr->spells3 & BREATH_WA) {	/* breath ele force resists
						 * ele force -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	}
	if (*dam > m_ptr->hp)
	    break;		   /* don't bother with special effects...
				    * it's dead! -CFT */
	if (!(r_ptr->spells2 & BREATH_SD) &&
	    !(r_ptr->spells3 & BREATH_WA) &&
	    !(r_ptr->cdefense & CHARM_SLEEP) &&
	    !(r_ptr->cdefense & UNIQUE))	/* sound and impact breathers
						 * should not stun -CFT */
	/* Nor should uniques -DGK */
	    if (m_ptr->confused > 0) {
		if (m_ptr->confused < 220) {	/* make sure not to overflow
						 * -CFT */
		    if (!blind) {
			sprintf(outval, "%sis more dazed.", cdesc);
			msg_print(outval);
		    }
		    m_ptr->confused += ((m_ptr->confused <= 0) ?
				  ((randint(5) + 1) / (rad > 0 ? rad : 1)) :
					(randint(2) / (rad > 0 ? rad : 1)));
		/*
		 * Confuse addition reworked because of Spirit.Hammer prayer
		 * -DGK 
		 */
		}
	    } else {
		if (!blind) {
		    sprintf(outval, "%sis dazed.", cdesc);
		    msg_print(outval);
		}
		m_ptr->confused = randint(15) / (rad > 0 ? rad : 1);
	    }
	break;
      case GF_INERTIA:
	if (r_ptr->spells3 & BREATH_SL) {	/* if can breath inertia,
						 * then resist it. */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	}
	break;
      case GF_LIGHT:
	if (r_ptr->spells3 & BREATH_LT) {	/* breathe light to res light */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 2;
	    *dam /= (randint(6) + 6);
	} else if (r_ptr->cdefense & HURT_LIGHT) {
	    *dam *= 2;		   /* hurt bad by light */
	} else if (r_ptr->spells3 & BREATH_DA) {	/* breathe dark gets
							 * hurt */
	    *dam = (*dam * 3) / 2;
	}
	break;
      case GF_DARK:
	if (r_ptr->spells2 & BREATH_DA) {	/* dark breathers resist -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 2;
	    *dam /= (randint(6) + 6);
	} else if (r_ptr->cdefense & HURT_LIGHT) {
	    *dam /= 2;		   /* hurt bad by light, so not hurt bad by
				    * dark */
	} else if (r_ptr->spells3 & BREATH_LT) {	/* breathe light gets
							 * hurt */
	    *dam = (*dam * 3) / 2;
	}
	break;
      case GF_TIME:
	if (r_ptr->spells3 & BREATH_TI) {	/* time breathers resist -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	}
	break;
      case GF_GRAVITY:
	if (r_ptr->spells3 & BREATH_GR) {	/* breathers resist -CFT */
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam *= 3;		   /* these 2 lines give avg dam of .33,
				    * ranging */
	    *dam /= (randint(6) + 6);	/* from .427 to .25 -CFT */
	} else {
	    if (*dam > m_ptr->hp)
		break;		   /* don't bother with special effects...
				    * it's dead! -CFT */
	    teleport_away(cave[m_ptr->fy][m_ptr->fx].cptr, 5);
	    *y = m_ptr->fy;	   /* teleported, so let outside world know
				    * monster moved! */
	    *x = m_ptr->fx;
	}
	break;
      case GF_MANA:		   /* raw blast of power. no way to resist,
				    * is there? */
	break;
      case GF_METEOR:		   /* GF_METEOR is basically a powerful
				    * magic-missile ball spell.  I only made
				    * it a different type so I could make it
				    * a different color -CFT */
	break;
      case GF_ICE:		   /* ice is basically frost + cuts + stun
				    * -CFT */
	if (r_ptr->cdefense & IM_FROST) {
	    if (!blind) {
		sprintf(outval, "%sresists.", cdesc);
		msg_print(outval);
	    }
	    *dam /= 9;
	    if (m_ptr->ml)
		c_recall[m_ptr->mptr].r_cdefense |= IM_FROST;
	}
	if (*dam > m_ptr->hp)
	    break;		   /* don't bother with special effects...
				    * it's dead! -CFT */
	if (!(r_ptr->spells2 & BREATH_SD) &&
	    !(r_ptr->spells3 & BREATH_WA))	/* sound and impact breathers
						 * should not stun -CFT */
	    if (m_ptr->confused > 0) {
		if (m_ptr->confused < 220) {	/* make sure not to overflow
						 * -CFT */
		    if (!blind) {
			sprintf(outval, "%sis more dazed.", cdesc);
			msg_print(outval);
		    }
		    m_ptr->confused += (randint(5) + 1) / (rad > 0 ? rad : 1);
		}
	    } else {
		if (!blind) {
		    sprintf(outval, "%sis dazed.", cdesc);
		    msg_print(outval);
		}
		m_ptr->confused = randint(15) / (rad > 0 ? rad : 1);
	    }
	break;
      default:
	msg_print("Unknown typ in spell_hit_monster.  This may mean trouble.");
    } /* end switch for saving throws and extra effects */
}
