/* File: effects.c */

/* Purpose: effects of various "objects" */

/*
 * 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 "angband.h"



/*
 * Set "p_ptr->blind", notice observable changes
 *
 * Note the use of "PU_UN_LITE" and "PU_UN_VIEW", which is needed to
 * memorize any terrain features which suddenly become "visible".
 * Note that blindness is currently the only thing which can affect
 * "player_can_see_bold()".
 */
bool set_blind(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->blind)
	{
	  msg_print("You are blind!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->blind)
	{
	  msg_print("You can see again.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->blind = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Forget stuff */
  p_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);

  /* Update stuff */
  p_ptr->update |= (PU_VIEW | PU_LITE);

  /* Update the monsters */
  p_ptr->update |= (PU_MONSTERS);

  /* Redraw map */
  p_ptr->redraw |= (PR_MAP);

  /* Redraw the "blind" */
  p_ptr->redraw |= (PR_BLIND);

  /* Window stuff */
  p_ptr->window |= (PW_OVERHEAD);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->confused", notice observable changes
 */
bool set_confused(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->confused)
	{
	  msg_print("You are confused!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->confused)
	{
	  msg_print("You feel less confused now.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->confused = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Redraw the "confused" */
  p_ptr->redraw |= (PR_CONFUSED);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->poisoned", notice observable changes
 */
bool set_poisoned(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->poisoned)
	{
	  msg_print("You are poisoned!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->poisoned)
	{
	  msg_print("You are no longer poisoned.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->poisoned = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Redraw the "poisoned" */
  p_ptr->redraw |= (PR_POISONED);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->afraid", notice observable changes
 */
bool set_afraid(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->afraid)
	{
	  msg_print("You are terrified!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->afraid)
	{
	  msg_print("You feel bolder now.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->afraid = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Redraw the "afraid" */
  p_ptr->redraw |= (PR_AFRAID);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->paralyzed", notice observable changes
 */
bool set_paralyzed(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->paralyzed)
	{
	  msg_print("You are paralyzed!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->paralyzed)
	{
	  msg_print("You can move again.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->paralyzed = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Redraw the state */
  p_ptr->redraw |= (PR_STATE);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->image", notice observable changes
 *
 * Note that we must redraw the map when hallucination changes.
 */
bool set_image(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->image)
	{
	  msg_print("You feel drugged!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->image)
	{
	  msg_print("You can see clearly again.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->image = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Redraw map */
  p_ptr->redraw |= (PR_MAP);

  /* Update monsters */
  p_ptr->update |= (PU_MONSTERS);

  /* Window stuff */
  p_ptr->window |= (PW_OVERHEAD);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->fast", notice observable changes
 */
bool set_fast(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->fast)
	{
	  msg_print("You feel yourself moving faster!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->fast)
	{
	  msg_print("You feel yourself slow down.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->fast = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->slow", notice observable changes
 */
bool set_slow(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->slow)
	{
	  msg_print("You feel yourself moving slower!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->slow)
	{
	  msg_print("You feel yourself speed up.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->slow = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);
  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->shield", notice observable changes
 */
bool set_shield(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->shield)
	{
	  msg_print("A mystic shield forms around your body!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->shield)
	{
	  msg_print("Your mystic shield crumbles away.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->shield = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}



/*
 * Set "p_ptr->blessed", notice observable changes
 */
bool set_blessed(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->blessed)
	{
	  msg_print("You feel righteous!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->blessed)
	{
	  msg_print("The prayer has expired.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->blessed = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->hero", notice observable changes
 */
bool set_hero(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->hero)
	{
	  msg_print("You feel like a hero!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->hero)
	{
	  msg_print("The heroism wears off.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->hero = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Recalculate hitpoints */
  p_ptr->update |= (PU_HP);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->shero", notice observable changes
 */
bool set_shero(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->shero)
	{
	  msg_print("You feel like a killing machine!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->shero)
	{
	  msg_print("You feel less Berserk.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->shero = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Recalculate hitpoints */
  p_ptr->update |= (PU_HP);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}
/*
 * Set "p_ptr->protevil", notice observable changes
 */
bool set_protevil(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->protevil)
	{
	  msg_print("You feel safe from evil!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->protevil)
	{
	  msg_print("You no longer feel safe from evil.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->protevil = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->invuln", notice observable changes
 */
bool set_invuln(int v)
{
  bool notice = FALSE;
  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->invuln)
	{
	  msg_print("You feel invulnerable!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->invuln)
	{
	  msg_print("You feel vulnerable once more.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->invuln = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->detect_inv", notice observable changes
 */
bool set_detect_inv(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->detect_inv)
	{
	  msg_print("Your eyes feel very sensitive!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->detect_inv)
	{
	  msg_print("Your eyes feel less sensitive.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->detect_inv = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Update the monsters */
  p_ptr->update |= (PU_MONSTERS);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}

/* Set "p_ptr->tim_invis", notice observable changes */
bool set_tim_invis(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->tim_invis)
	{
	  msg_print("You feel your body fade away.");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->tim_invis)
	{
	  msg_print("You are no longer invisible.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->tim_invis = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Redraw invisibility */
  p_ptr->redraw |= (PR_INVIS);

  /* Result */
  return( TRUE);
}


/*
 * Set "p_ptr->tim_infra", notice observable changes
 */
bool set_tim_infra(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->tim_infra)
	{
	  msg_print("Your eyes begin to tingle!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->tim_infra)
	{
	  msg_print("Your eyes stop tingling.");
	  notice = TRUE;
	}
    }
  /* Use the value */
  p_ptr->tim_infra = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Update the monsters */
  p_ptr->update |= (PU_MONSTERS);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->oppose_acid", notice observable changes
 */
bool set_oppose_acid(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->oppose_acid)
	{
	  msg_print("You feel resistant to acid!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->oppose_acid)
	{
	  msg_print("You feel less resistant to acid.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->oppose_acid = v;
  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->oppose_elec", notice observable changes
 */
bool set_oppose_elec(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->oppose_elec)
	{
	  msg_print("You feel resistant to electricity!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->oppose_elec)
	{
	  msg_print("You feel less resistant to electricity.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->oppose_elec = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);
  /* Handle stuff */
  handle_stuff();
  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->oppose_fire", notice observable changes
 */
bool set_oppose_fire(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->oppose_fire)
	{
	  msg_print("You feel resistant to fire!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->oppose_fire)
	{
	  msg_print("You feel less resistant to fire.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->oppose_fire = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}

/*
 * Set "p_ptr->oppose_cold", notice observable changes
 */
bool set_oppose_cold(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->oppose_cold)
	{
	  msg_print("You feel resistant to cold!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->oppose_cold)
	{
	  msg_print("You feel less resistant to cold.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->oppose_cold = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->oppose_pois", notice observable changes
 */
bool set_oppose_pois(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->oppose_pois)
	{
	  msg_print("You feel resistant to poison!");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->oppose_pois)
	{
	  msg_print("You feel less resistant to poison.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->oppose_pois = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}

/*
 * Set "p_ptr->ironwill", notice observable changes
 */
bool set_ironwill(int v)
{
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Open */
  if (v)
    {
      if (!p_ptr->ironwill)
	{
	  msg_print("You feel your will to live strengthen.");
	  notice = TRUE;
	}
    }

  /* Shut */
  else
    {
      if (p_ptr->ironwill)
	{
	  msg_print("You feel your will return to normal.");
	  notice = TRUE;
	}
    }

  /* Use the value */
  p_ptr->ironwill = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->stun", notice observable changes
 *
 * Note the special code to only notice "range" changes.
 */
bool set_stun(int v)
{
  int old_aux, new_aux;

  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Knocked out */
  if (p_ptr->stun > 100)
    {
      old_aux = 3;
    }
  /* Heavy stun */
  else if (p_ptr->stun > 50)
    {
      old_aux = 2;
    }

  /* Stun */
  else if (p_ptr->stun > 0)
    {
      old_aux = 1;
    }

  /* None */
  else
    {
      old_aux = 0;
    }

  /* Knocked out */
  if (v > 100)
    {
      new_aux = 3;
    }

  /* Heavy stun */
  else if (v > 50)
    {
      new_aux = 2;
    }

  /* Stun */
  else if (v > 0)
    {
      new_aux = 1;
    }

  /* None */
  else
    {
      new_aux = 0;
    }

  /* Increase cut */
  if (new_aux > old_aux)
    {
      /* Describe the state */
      switch (new_aux)
	{
	  /* Stun */
	case 1:
	  msg_print("You have been stunned.");
	  break;

	  /* Heavy stun */
	case 2:
	  msg_print("You have been heavily stunned.");
	  break;
	  /* Knocked out */
	case 3:
	  msg_print("You have been knocked out.");
	  break;
	}

      /* Notice */
      notice = TRUE;
    }

  /* Decrease cut */
  else if (new_aux < old_aux)
    {
      /* Describe the state */
      switch (new_aux)
	{
	  /* None */
	case 0:
	  msg_print("You are no longer stunned.");
	  if (disturb_state) disturb(0, 0);
	  break;
	}

      /* Notice */
      notice = TRUE;
    }

  /* Use the value */
  p_ptr->stun = v;

  /* No change */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Redraw the "stun" */
  p_ptr->redraw |= (PR_STUN);

  /* Handle stuff */
  handle_stuff();
  /* Result */
  return (TRUE);
}

/*
 * Set "p_ptr->cut", notice observable changes
 *
 * Note the special code to only notice "range" changes.
 */
bool set_cut(int v)
{
  int old_aux, new_aux;

  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

  /* Mortal wound */
  if (p_ptr->cut > 1000)
    {
      old_aux = 7;
    }

  /* Deep gash */
  else if (p_ptr->cut > 200)
    {
      old_aux = 6;
    }

  /* Severe cut */
  else if (p_ptr->cut > 100)
    {
      old_aux = 5;
    }

  /* Nasty cut */
  else if (p_ptr->cut > 50)
    {
      old_aux = 4;
    }

  /* Bad cut */
  else if (p_ptr->cut > 25)
    {
      old_aux = 3;
    }

  /* Light cut */
  else if (p_ptr->cut > 10)
    {
      old_aux = 2;
    }
  /* Graze */
  else if (p_ptr->cut > 0)
    {
      old_aux = 1;
    }

  /* None */
  else
    {
      old_aux = 0;
    }
  /* Mortal wound */
  if (v > 1000)
    {
      new_aux = 7;
    }

  /* Deep gash */
  else if (v > 200)
    {
      new_aux = 6;
    }

  /* Severe cut */
  else if (v > 100)
    {
      new_aux = 5;
    }

  /* Nasty cut */
  else if (v > 50)
    {
      new_aux = 4;
    }

  /* Bad cut */
  else if (v > 25)
    {
      new_aux = 3;
    }

  /* Light cut */
  else if (v > 10)
    {
      new_aux = 2;
    }

  /* Graze */
  else if (v > 0)
    {
      new_aux = 1;
    }

  /* None */
  else
    {
      new_aux = 0;
    }

  /* Increase cut */
  if (new_aux > old_aux)
    {
      /* Describe the state */
      switch (new_aux)
	{
	  /* Graze */
	case 1:
	  msg_print("You have been given a graze.");
	  break;

	  /* Light cut */
	case 2:
	  msg_print("You have been given a light cut.");
	  break;

	  /* Bad cut */
	case 3:
	  msg_print("You have been given a bad cut.");
	  break;

	  /* Nasty cut */
	case 4:
	  msg_print("You have been given a nasty cut.");
	  break;

	  /* Severe cut */
	case 5:
	  msg_print("You have been given a severe cut.");
	  break;

	  /* Deep gash */
	case 6:
	  msg_print("You have been given a deep gash.");
	  break;

	  /* Mortal wound */
	case 7:
	  msg_print("You have been given a mortal wound.");
	  break;
	}

      /* Notice */
      notice = TRUE;
    }

  /* Decrease cut */
  else if (new_aux < old_aux)
    {
      /* Describe the state */
      switch (new_aux)
	{
	  /* None */
	case 0:
	  msg_print("You are no longer bleeding.");
	  if (disturb_state) disturb(0, 0);
	  break;
	}

      /* Notice */
      notice = TRUE;
    }

  /* Use the value */
  p_ptr->cut = v;

  /* No change */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Redraw the "cut" */
  p_ptr->redraw |= (PR_CUT);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}


/*
 * Set "p_ptr->food", notice observable changes
 *
 * The "p_ptr->food" variable can get as large as 20000, allowing the
 * addition of the most "filling" item, Elvish Waybread, which adds
 * 7500 food units, without overflowing the 32767 maximum limit.
 *
 * Perhaps we should disturb the player with various messages,
 * especially messages about hunger status changes.  XXX XXX XXX
 *
 * Digestion of food is handled in "dungeon.c", in which, normally,
 * the player digests about 20 food units per 100 game turns, more
 * when "fast", more when "regenerating", less with "slow digestion",
 * but when the player is "gorged", he digests 100 food units per 10
 * game turns, or a full 1000 food units per 100 game turns.
 *
 * Note that the player's speed is reduced by 10 units while gorged,
 * so if the player eats a single food ration (5000 food units) when
 * full (15000 food units), he will be gorged for (5000/100)*10 = 500
 * game turns, or 500/(100/5) = 25 player turns (if nothing else is
 * affecting the player speed).
 */
bool set_food(int v)
{
  int old_aux, new_aux;
  bool notice = FALSE;

  /* Hack -- Force good values */
  v = (v > 20000) ? 20000 : (v < 0) ? 0 : v;

  /* Fainting / Starving */
  if (p_ptr->food < PY_FOOD_FAINT)
    {
      old_aux = 0;
    }

  /* Weak */
  else if (p_ptr->food < PY_FOOD_WEAK)
    {
      old_aux = 1;
    }

  /* Hungry */
  else if (p_ptr->food < PY_FOOD_ALERT)
    {
      old_aux = 2;
    }

  /* Normal */
  else if (p_ptr->food < PY_FOOD_FULL)
    {
      old_aux = 3;
    }

  /* Full */
  else if (p_ptr->food < PY_FOOD_MAX)
    {
      old_aux = 4;
    }

  /* Gorged */
  else
    {
      old_aux = 5;
    }

  /* Fainting / Starving */
  if (v < PY_FOOD_FAINT)
    {
      new_aux = 0;
    }
  /* Weak */
  else if (v < PY_FOOD_WEAK)
    {
      new_aux = 1;
    }

  /* Hungry */
  else if (v < PY_FOOD_ALERT)
    {
      new_aux = 2;
    }

  /* Normal */
  else if (v < PY_FOOD_FULL)
    {
      new_aux = 3;
    }

  /* Full */
  else if (v < PY_FOOD_MAX)
    {
      new_aux = 4;
    }

  /* Gorged */
  else
    {
      new_aux = 5;
    }

  /* Food increase */
  if (new_aux > old_aux)
    {
      /* Describe the state */
      switch (new_aux)
	{
	  /* Weak */
	case 1:
	  msg_print("You are still weak.");
	  break;

	  /* Hungry */
	case 2:
	  msg_print("You are still hungry.");
	  break;

	  /* Normal */
	case 3:
	  msg_print("You are no longer hungry.");
	  break;

	  /* Full */
	case 4:
	  msg_print("You are full!");
	  break;
	  /* Bloated */
	case 5:
	  msg_print("You have gorged yourself!");
	  break;
	}

      /* Change */
      notice = TRUE;
    }
  /* Food decrease */
  else if (new_aux < old_aux)
    {
      /* Describe the state */
      switch (new_aux)
	{
	  /* Fainting / Starving */
	case 0:
	  msg_print("You are getting faint from hunger!");
	  break;

	  /* Weak */
	case 1:
	  msg_print("You are getting weak from hunger!");
	  break;

	  /* Hungry */
	case 2:
	  msg_print("You are getting hungry.");
	  break;

	  /* Normal */
	case 3:
	  msg_print("You are no longer full.");
	  break;

	  /* Full */
	case 4:
	  msg_print("You are no longer gorged.");
	  break;
	}

      /* Change */
      notice = TRUE;
    }

  /* Use the value */
  p_ptr->food = v;

  /* Nothing to notice */
  if (!notice) return (FALSE);

  /* Disturb */
  if (disturb_state) disturb(0, 0);

  /* Recalculate bonuses */
  p_ptr->update |= (PU_BONUS);

  /* Redraw hunger */
  p_ptr->redraw |= (PR_HUNGER);

  /* Handle stuff */
  handle_stuff();

  /* Result */
  return (TRUE);
}





/*
 * Advance experience levels and print experience
 */
void check_experience(void)
{
  /* Hack -- lower limit */
  if (p_ptr->exp < 0) p_ptr->exp = 0;

	/* Hack -- lower limit */
  if (p_ptr->max_exp < 0) p_ptr->max_exp = 0;

  /* Hack -- upper limit */
  if (p_ptr->exp > PY_MAX_EXP) p_ptr->exp = PY_MAX_EXP;

  /* Hack -- upper limit */
  if (p_ptr->max_exp > PY_MAX_EXP) p_ptr->max_exp = PY_MAX_EXP;


  /* Hack -- maintain "max" experience */
  if (p_ptr->exp > p_ptr->max_exp) p_ptr->max_exp = p_ptr->exp;

  /* Redraw experience */
  p_ptr->redraw |= (PR_EXP);

  /* Handle stuff */
  handle_stuff();
}


/*
 * Gain experience
 */
void gain_exp(s32b amount)
{
  /* Gain some experience */
  p_ptr->exp += amount;
  p_ptr->tot_exp += amount;
  /* Slowly recover from experience drainage */
  if (p_ptr->exp < p_ptr->max_exp)
    {
      /* Gain max experience (10%) */
      p_ptr->max_exp += amount / 10;
    }
  /* Check Experience */
  check_experience();
}
/*
 * Lose experience
 */
void lose_exp(s32b amount)
{
  int i, sk;
  /* Never drop below zero experience */
  if (amount > p_ptr->exp) amount = p_ptr->exp;

  /* Lose some experience */
  p_ptr->exp -= amount;

  /* Check Experience */
  check_experience();
  msg_print("You feel less skilled!");
  if (!p_ptr->hold_life)
    for(i=1;i<5;i++)
      {
	sk=randint(S_NUM);
	advance(sk,-4);
      }
  else
    {
      sk=randint(S_NUM);
      advance(sk,-2);
    }
}



/*
 * Hack -- Return the "automatic coin type" of a monster race
 * Used to allocate proper treasure when "Creeping coins" die
 *
 * XXX XXX XXX Note the use of actual "monster names"
 */
static int get_coin_type(monster_race *r_ptr)
{
  cptr name = (r_name + r_ptr->name);
  /* Analyze "coin" monsters */
  if (r_ptr->d_char == '$')
    {
      /* Look for textual clues */
      if (strstr(name, " copper ")) return (2);
      if (strstr(name, " silver ")) return (5);
      if (strstr(name, " gold ")) return (10);
      if (strstr(name, " mithril ")) return (16);
      if (strstr(name, " adamantite ")) return (17);

      /* Look for textual clues */
      if (strstr(name, "Copper ")) return (2);
      if (strstr(name, "Silver ")) return (5);
      if (strstr(name, "Gold ")) return (10);
      if (strstr(name, "Mithril ")) return (16);
      if (strstr(name, "Adamantite ")) return (17);
    }

  /* Assume nothing */
  return (0);
}


/*
 * Handle the "death" of a monster.
 *
 * Disperse treasures centered at the monster location based on the
 * various flags contained in the monster flags fields.
 *
 * Check for "Quest" completion when a quest monster is killed.
 *
 * Note that only the player can induce "monster_death()" on Uniques.
 * Thus (for now) all Quest monsters should be Uniques.
 *
 * Note that monsters can now carry objects, and when a monster dies,
 * it drops all of its objects, which may disappear in crowded rooms.
 */
void monster_death(int m_idx)
{
  int i, j, y, x, ny, nx;

  int dump_item = 0;
  int dump_gold = 0;

  int number = 0;
  int total = 0;

  s16b this_o_idx, next_o_idx = 0;

  monster_type *m_ptr = &m_list[m_idx];

  monster_race *r_ptr = &r_info[m_ptr->r_idx];

  bool visible = (m_ptr->ml || (r_ptr->flags1 & (RF1_UNIQUE)));

  bool good = (r_ptr->flags1 & (RF1_DROP_GOOD)) ? TRUE : FALSE;
  bool great = (r_ptr->flags1 & (RF1_DROP_GREAT)) ? TRUE : FALSE;

  bool do_gold = (!(r_ptr->flags1 & (RF1_ONLY_ITEM)));
  bool do_item = (!(r_ptr->flags1 & (RF1_ONLY_GOLD)));

  int force_coin = get_coin_type(r_ptr);

  object_type forge;
  object_type *q_ptr;

  /* Get the location */
  y = m_ptr->fy;
  x = m_ptr->fx;


  /* Drop objects being carried */
  for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
    {
      object_type *o_ptr;
		
      /* Acquire object */
      o_ptr = &o_list[this_o_idx];

      /* Acquire next object */
      next_o_idx = o_ptr->next_o_idx;

      /* Paranoia */
      o_ptr->held_m_idx = 0;

      /* Get local object */
      q_ptr = &forge;

      /* Copy the object */
      object_copy(q_ptr, o_ptr);

      /* Delete the object */
      delete_object_idx(this_o_idx);

      /* Drop it */
      drop_near(q_ptr, -1, y, x);
    }

  /* Forget objects */
  m_ptr->hold_o_idx = 0;


  /* Mega-Hack -- drop "winner" treasures */
  if (r_ptr->flags1 & (RF1_DROP_CHOSEN))
    {
      /* Get local object */
      q_ptr = &forge;

      /* Mega-Hack -- Prepare to make "Grond" */
      object_prep(q_ptr, lookup_kind(TV_HAFTED, SV_GROND));

      /* Mega-Hack -- Mark this item as "Grond" */
      q_ptr->name1 = ART_GROND;

      /* Mega-Hack -- Actually create "Grond" */
      apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);

      /* Drop it in the dungeon */
      drop_near(q_ptr, -1, y, x);
      /* Get local object */
      q_ptr = &forge;

      /* Mega-Hack -- Prepare to make "Morgoth" */
      object_prep(q_ptr, lookup_kind(TV_CROWN, SV_MORGOTH));

      /* Mega-Hack -- Mark this item as "Morgoth" */
      q_ptr->name1 = ART_MORGOTH;

      /* Mega-Hack -- Actually create "Morgoth" */
      apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);

      /* Drop it in the dungeon */
      drop_near(q_ptr, -1, y, x);
    }


  /* Determine how much we can drop */
  if ((r_ptr->flags1 & (RF1_DROP_60)) && (rand_int(100) < 60)) number++;
  if ((r_ptr->flags1 & (RF1_DROP_90)) && (rand_int(100) < 90)) number++;
  if (r_ptr->flags1 & (RF1_DROP_1D2)) number += damroll(1, 2);
  if (r_ptr->flags1 & (RF1_DROP_2D2)) number += damroll(2, 2);
  if (r_ptr->flags1 & (RF1_DROP_3D2)) number += damroll(3, 2);
  if (r_ptr->flags1 & (RF1_DROP_4D2)) number += damroll(4, 2);

  /* Hack -- handle creeping coins */
  coin_type = force_coin;

  /* Average dungeon and monster levels */
  object_level = ((dun_level==-1? 70: dun_level) + r_ptr->level) / 2;

  /* Drop some objects */
  for (j = 0; j < number; j++)
    {
      /* Get local object */
      q_ptr = &forge;

      /* Wipe the object */
      object_wipe(q_ptr);

      /* Make Gold */
      if (do_gold && (!do_item || (rand_int(100) < 50)))
	{
	  /* Make some gold */
	  if (!make_gold(q_ptr)) continue;

	  /* XXX XXX XXX */
	  dump_gold++;
	}

      /* Make Object */
      else
	{
	  /* Make an object */
	  if (!make_object(q_ptr, good, great)) continue;

	  /* XXX XXX XXX */
	  dump_item++;
	}

      /* Drop it in the dungeon */
      drop_near(q_ptr, -1, y, x);
    }

  /* Reset the object level */
  object_level = (dun_level==-1? 70: dun_level);

  /* Reset "coin" type */
  coin_type = 0;


  /* Take note of any dropped treasure */
  if (visible && (dump_item || dump_gold))
    {
      /* Take notes on treasure */
      lore_treasure(m_idx, dump_item, dump_gold);
    }


  /* Only process "Quest Monsters" */
  if (!(r_ptr->flags1 & (RF1_QUESTOR))) return;


  /* Hack -- Mark quests as complete */
  for (i = 0; i < MAX_Q_IDX; i++)
    {
      /* Hack -- note completed quests */
      if (q_list[i].level == r_ptr->level) q_list[i].level = 0;

      /* Count incomplete quests */
      if (q_list[i].level) total++;
    }


  /* Need some stairs */
  if (total)
    {
      /* Stagger around */
      while (!cave_valid_bold(y, x))
	{
	  int d = 1;

	  /* Pick a location */
	  scatter(&ny, &nx, y, x, d, 0);

	  /* Stagger */
	  y = ny; x = nx;
	}
      /* XXX XXX XXX */
      delete_object(y, x);

      /* Explain the stairway */
      msg_print("A magical stairway appears...");

      /* Create stairs down */
      cave_set_feat(y, x, FEAT_MORE);

      /* Remember to update everything */
      p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTERS);
    }


  /* Nothing left, game over... */
  else
    {
      /* Total winner */
      total_winner = TRUE;

      /* Redraw the "title" */
      p_ptr->redraw |= (PR_TITLE);

      /* Congratulations */
      msg_print("*** CONGRATULATIONS ***");
      msg_print("You have won the game!");
      msg_print("You may retire (commit suicide) when you are ready.");
    }
}


/*
 * Decreases monsters hit points, handling monster death.
 *
 * We return TRUE if the monster has been killed (and deleted).
 *
 * We announce monster death (using an optional "death message"
 * if given, and a otherwise a generic killed/destroyed message).
 *
 * Only "physical attacks" can induce the "You have slain" message.
 * Missile and Spell attacks will induce the "dies" message, or
 * various "specialized" messages.  Note that "You have destroyed"
 * and "is destroyed" are synonyms for "You have slain" and "dies".
 *
 * Hack -- unseen monsters yield "You have killed it." message.
 *
 * Added fear (DGK) and check whether to print fear messages -CWS
 *
 * Genericized name, sex, and capitilization -BEN-
 *
 * As always, the "ghost" processing is a total hack.
 *
 * Hack -- we "delay" fear messages by passing around a "fear" flag.
 *
 * XXX XXX XXX Consider decreasing monster experience over time, say,
 * by using "(m_exp * m_lev * (m_lev)) / (p_lev * (m_lev + n_killed))"
 * instead of simply "(m_exp * m_lev) / (p_lev)", to make the first
 * monster worth more than subsequent monsters.  This would also need
 * to induce changes in the monster recall code.
 */
bool mon_take_hit(int m_idx, int dam, bool *fear, cptr note)
{
  monster_type	*m_ptr = &m_list[m_idx];

  monster_race	*r_ptr = &r_info[m_ptr->r_idx];

  s32b		div, new_exp, new_exp_frac;


  /* Redraw (later) if needed */
  if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH);

  /* Wake it up */
  m_ptr->csleep = 0;

  /* Hurt it */
  m_ptr->hp -= dam;

  /* It is dead now */
  if (m_ptr->hp < 0)
    {
      char m_name[80];

      /* Extract monster name */
      monster_desc(m_name, m_ptr, 0);

      /* Make a sound */
      sound(SOUND_KILL);

      /* Death by Missile/Spell attack */
      if (note)
	{
	  msg_format("%^s%s", m_name, note);
	}

      /* Death by physical attack -- invisible monster */
      else if (!m_ptr->ml)
	{
	  msg_format("You have killed %s.", m_name);
	}

      /* Death by Physical attack -- non-living monster */
      else if ((r_ptr->flags3 & (RF3_DEMON)) ||
	       (r_ptr->flags3 & (RF3_UNDEAD)) ||
	       (r_ptr->flags2 & (RF2_STUPID)) ||
	       (strchr("Evg", r_ptr->d_char)))
	{
	  msg_format("You have destroyed %s.", m_name);
	}
      /* Death by Physical attack -- living monster */
      else
	{
	  msg_format("You have slain %s.", m_name);
	}

      /* Maximum player level */
      div = (p_ptr->soulsteal? p_ptr->max_plv*2: p_ptr->max_plv);

      /* Give some experience for the kill */
      new_exp = ((long)r_ptr->mexp * r_ptr->level) / div;

      /* Handle fractional experience */
      new_exp_frac = ((((long)r_ptr->mexp * r_ptr->level) % div)
		      * 0x10000L / div) + p_ptr->exp_frac;

      /* Keep track of experience */
      if (new_exp_frac >= 0x10000L)
	{
	  new_exp++;
	  p_ptr->exp_frac = new_exp_frac - 0x10000L;
	}
      else
	{
	  p_ptr->exp_frac = new_exp_frac;
	}

      /* Gain experience */
      gain_exp(new_exp);

      /* Generate treasure */
      monster_death(m_idx);

      /* When the player kills a Unique, it stays dead */
      if (r_ptr->flags1 & (RF1_UNIQUE)) r_ptr->max_num = 0;

      /* Recall even invisible uniques or winners */
      if (m_ptr->ml || (r_ptr->flags1 & (RF1_UNIQUE)))
	{
	  /* Count kills this life */
	  if (r_ptr->r_pkills < MAX_SHORT) r_ptr->r_pkills++;

	  /* Count kills in all lives */
	  if (r_ptr->r_tkills < MAX_SHORT) r_ptr->r_tkills++;

	  /* Hack -- Auto-recall */
	  monster_race_track(m_ptr->r_idx);
	}

      /* Delete the monster */
      delete_monster_idx(m_idx);

      /* Not afraid */
      (*fear) = FALSE;

      /* Monster is dead */
      return (TRUE);
    }

#ifdef ALLOW_FEAR
  /* Mega-Hack -- Pain cancels fear */
  if (m_ptr->monfear && (dam > 0))
    {
      int tmp = randint(dam);
      /* Cure a little fear */
      if (tmp < m_ptr->monfear)
	{
	  /* Reduce fear */
	  m_ptr->monfear -= tmp;
	}

      /* Cure all the fear */
      else
	{
	  /* Cure fear */
	  m_ptr->monfear = 0;

	  /* No more fear */
	  (*fear) = FALSE;
	}
    }

  /* Sometimes a monster gets scared by damage */
  if (!m_ptr->monfear && !(r_ptr->flags3 & (RF3_NO_FEAR)))
    {
      int		percentage;

      /* Percentage of fully healthy */
      percentage = (100L * m_ptr->hp) / m_ptr->maxhp;

      /*
       * Run (sometimes) if at 10% or less of max hit points,
       * or (usually) when hit for half its current hit points
       */
      if (((percentage <= 10) && (rand_int(10) < percentage)) ||
	  ((dam >= m_ptr->hp) && (rand_int(100) < 80)))
	{
	  /* Hack -- note fear */
	  (*fear) = TRUE;

	  /* XXX XXX XXX Hack -- Add some timed fear */
	  m_ptr->monfear = (randint(10) +
			    (((dam >= m_ptr->hp) && (percentage > 7)) ?
			     20 : ((11 - percentage) * 5)));
	}
    }

#endif

  /* Not dead yet */
  return (FALSE);
}


/*
 * Calculates current boundaries
 * Called below and from "do_cmd_locate()".
 */
void panel_bounds(void)
{
  panel_row_min = panel_row * (SCREEN_HGT / 2);
  panel_row_max = panel_row_min + SCREEN_HGT - 1;
  panel_row_prt = panel_row_min - 1;
  panel_col_min = panel_col * (SCREEN_WID / 2);
  panel_col_max = panel_col_min + SCREEN_WID - 1;
  panel_col_prt = panel_col_min - 13;
}



/*
 * Given an row (y) and col (x), this routine detects when a move
 * off the screen has occurred and figures new borders. -RAK-
 *
 * "Update" forces a "full update" to take place.
 *
 * The map is reprinted if necessary, and "TRUE" is returned.
 */
void verify_panel(void)
{
  int y = py;
  int x = px;

  int prow = panel_row;
  int pcol = panel_col;

  /* Scroll screen when 2 grids from top/bottom edge */
  if ((y < panel_row_min + 2) || (y > panel_row_max - 2))
    {
      prow = ((y - SCREEN_HGT / 4) / (SCREEN_HGT / 2));
      if (prow > max_panel_rows) prow = max_panel_rows;
      else if (prow < 0) prow = 0;
    }

  /* Scroll screen when 4 grids from left/right edge */
  if ((x < panel_col_min + 4) || (x > panel_col_max - 4))
    {
      pcol = ((x - SCREEN_WID / 4) / (SCREEN_WID / 2));
      if (pcol > max_panel_cols) pcol = max_panel_cols;
      else if (pcol < 0) pcol = 0;
    }
  /* Check for "no change" */
  if ((prow == panel_row) && (pcol == panel_col)) return;
  /* Hack -- optional disturb on "panel change" */
  if (disturb_panel) disturb(0, 0);

  /* Save the new panel info */
  panel_row = prow;
  panel_col = pcol;

  /* Recalculate the boundaries */
  panel_bounds();

  /* Update stuff */
  p_ptr->update |= (PU_MONSTERS);

  /* Redraw map */
  p_ptr->redraw |= (PR_MAP);

  /* Window stuff */
  p_ptr->window |= (PW_OVERHEAD);
}



/*
 * Monster health description
 */
cptr look_mon_desc(int m_idx)
{
  monster_type *m_ptr = &m_list[m_idx];
  monster_race *r_ptr = &r_info[m_ptr->r_idx];

  bool          living = TRUE;
  int           perc;


  /* Determine if the monster is "living" (vs "undead") */
  if (r_ptr->flags3 & (RF3_UNDEAD)) living = FALSE;
  if (r_ptr->flags3 & (RF3_DEMON)) living = FALSE;
  if (strchr("Egv", r_ptr->d_char)) living = FALSE;


  /* Healthy monsters */
  if (m_ptr->hp >= m_ptr->maxhp)
    {
      /* No damage */
      return (living ? "unhurt" : "undamaged");
    }


  /* Calculate a health "percentage" */
  perc = 100L * m_ptr->hp / m_ptr->maxhp;

  if (perc >= 60)
    {
      return (living ? "somewhat wounded" : "somewhat damaged");
    }
  if (perc >= 25)
    {
      return (living ? "wounded" : "damaged");
    }

  if (perc >= 10)
    {
      return (living ? "badly wounded" : "badly damaged");
    }

  return (living ? "almost dead" : "almost destroyed");
}

/*
 * Angband sorting algorithm -- quick sort in place
 *
 * Note that the details of the data we are sorting is hidden,
 * and we rely on the "ang_sort_comp()" and "ang_sort_swap()"
 * function hooks to interact with the data, which is given as
 * two pointers, and which may have any user-defined form.
 */
void ang_sort_aux(vptr u, vptr v, int p, int q)
{
  int z, a, b;

  /* Done sort */
  if (p >= q) return;

  /* Pivot */
  z = p;

  /* Begin */
  a = p;
  b = q;

  /* Partition */
  while (TRUE)
    {
      /* Slide i2 */
      while (!(*ang_sort_comp)(u, v, b, z)) b--;

      /* Slide i1 */
      while (!(*ang_sort_comp)(u, v, z, a)) a++;

      /* Done partition */
      if (a >= b) break;

      /* Swap */
      (*ang_sort_swap)(u, v, a, b);

      /* Advance */
      a++, b--;
    }
  /* Recurse left side */
  ang_sort_aux(u, v, p, b);

  /* Recurse right side */
  ang_sort_aux(u, v, b+1, q);
}


/*
 * Angband sorting algorithm -- quick sort in place
 *
 * Note that the details of the data we are sorting is hidden,
 * and we rely on the "ang_sort_comp()" and "ang_sort_swap()"
 * function hooks to interact with the data, which is given as
 * two pointers, and which may have any user-defined form.
 */
void ang_sort(vptr u, vptr v, int n)
{
  /* Sort the array */
  ang_sort_aux(u, v, 0, n-1);
}




/*
 * Determine is a monster makes a reasonable target
 *
 * The concept of "targetting" was stolen from "Morgul" (?)
 *
 * The player can target any location, or any "target-able" monster.
 *
 * Currently, a monster is "target_able" if it is visible, and if
 * the player can hit it with a projection, and the player is not
 * hallucinating.  This allows use of "use closest target" macros.
 *
 * Future versions may restrict the ability to target "trappers"
 * and "mimics", but the semantics is a little bit weird.
 */
bool target_able(int m_idx)
{
  monster_type *m_ptr = &m_list[m_idx];

  /* Monster must be alive */
  if (!m_ptr->r_idx) return (FALSE);

  /* Monster must be visible */
  if (!m_ptr->ml) return (FALSE);
  /* Monster must be projectable */
  if (!projectable(py, px, m_ptr->fy, m_ptr->fx)) return (FALSE);
  /* Hack -- no targeting hallucinations */
  if (p_ptr->image) return (FALSE);
  /* XXX XXX XXX Hack -- Never target trappers */
  /* if (CLEAR_ATTR && CLEAR_CHAR) return (FALSE); */
  /* Assume okay */
  return (TRUE);
}




/*
 * Update (if necessary) and verify (if possible) the target.
 *
 * We return TRUE if the target is "okay" and FALSE otherwise.
 */
bool target_okay(void)
{
  /* Accept stationary targets */
  if (target_who < 0) return (TRUE);

	/* Check moving targets */
  if (target_who > 0)
    {
      /* Accept reasonable targets */
      if (target_able(target_who))
	{
	  monster_type *m_ptr = &m_list[target_who];

	  /* Acquire monster location */
	  target_row = m_ptr->fy;
	  target_col = m_ptr->fx;

	  /* Good target */
	  return (TRUE);
	}
    }

  /* Assume no target */
  return (FALSE);
}



/*
 * Sorting hook -- comp function -- by "distance to player"
 *
 * We use "u" and "v" to point to arrays of "x" and "y" positions,
 * and sort the arrays by double-distance to the player.
 */
static bool ang_sort_comp_distance(vptr u, vptr v, int a, int b)
{
  byte *x = (byte*)(u);
  byte *y = (byte*)(v);

  int da, db, kx, ky;
  /* Absolute distance components */
  kx = x[a]; kx -= px; kx = ABS(kx);
  ky = y[a]; ky -= py; ky = ABS(ky);

  /* Approximate Double Distance to the first point */
  da = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx));

  /* Absolute distance components */
  kx = x[b]; kx -= px; kx = ABS(kx);
  ky = y[b]; ky -= py; ky = ABS(ky);

  /* Approximate Double Distance to the first point */
  db = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx));

  /* Compare the distances */
  return (da <= db);
}


/*
 * Sorting hook -- swap function -- by "distance to player"
 *
 * We use "u" and "v" to point to arrays of "x" and "y" positions,
 * and sort the arrays by distance to the player.
 */
static void ang_sort_swap_distance(vptr u, vptr v, int a, int b)
{
  byte *x = (byte*)(u);
  byte *y = (byte*)(v);

  byte temp;

  /* Swap "x" */
  temp = x[a];
  x[a] = x[b];
  x[b] = temp;

  /* Swap "y" */
  temp = y[a];
  y[a] = y[b];
  y[b] = temp;
}

/*
 * Hack -- help "select" a location (see below)
 */
static s16b target_pick(int y1, int x1, int dy, int dx)
{
  int i, v;

  int x2, y2, x3, y3, x4, y4;

  int b_i = -1, b_v = 9999;

  /* Scan the locations */
  for (i = 0; i < temp_n; i++)
    {
      /* Point 2 */
      x2 = temp_x[i];
      y2 = temp_y[i];

      /* Directed distance */
      x3 = (x2 - x1);
      y3 = (y2 - y1);

      /* Verify quadrant */
      if (dx && (x3 * dx <= 0)) continue;
      if (dy && (y3 * dy <= 0)) continue;

      /* Absolute distance */
      x4 = ABS(x3);
      y4 = ABS(y3);

      /* Verify quadrant */
      if (dy && !dx && (x4 > y4)) continue;
      if (dx && !dy && (y4 > x4)) continue;

      /* Approximate Double Distance */
      v = ((x4 > y4) ? (x4 + x4 + y4) : (y4 + y4 + x4));

      /* XXX XXX XXX Penalize location */

      /* Track best */
      if ((b_i >= 0) && (v >= b_v)) continue;

      /* Track best */
      b_i = i; b_v = v;
    }

  /* Result */
  return (b_i);
}


/*
 * Hack -- determine if a given location is "interesting"
 */
static bool target_set_accept(int y, int x)
{
  cave_type *c_ptr;

  s16b this_o_idx, next_o_idx = 0;


  /* Player grid is always interesting */
  if ((y == py) && (x == px)) return (TRUE);


  /* Handle hallucination */
  if (p_ptr->image) return (FALSE);


  /* Examine the grid */
  c_ptr = &cave[y][x];

  /* Visible monsters */
  if (c_ptr->m_idx)
    {
      monster_type *m_ptr = &m_list[c_ptr->m_idx];

      /* Visible monsters */
      if (m_ptr->ml) return (TRUE);
    }

  /* Scan all objects in the grid */
  for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
    {
      object_type *o_ptr;
		
      /* Acquire object */
      o_ptr = &o_list[this_o_idx];

      /* Acquire next object */
      next_o_idx = o_ptr->next_o_idx;

      /* Memorized object */
      if (o_ptr->marked) return (TRUE);
    }

  /* Interesting memorized features */
  if (c_ptr->info & (CAVE_MARK))
    {
      /* Notice glyphs */
      if (c_ptr->feat == FEAT_GLYPH) return (TRUE);

      /* Notice doors */
      if (c_ptr->feat == FEAT_OPEN) return (TRUE);
      if (c_ptr->feat == FEAT_BROKEN) return (TRUE);

      /* Notice stairs */
      if (c_ptr->feat == FEAT_LESS) return (TRUE);
      if (c_ptr->feat == FEAT_MORE) return (TRUE);

      /* Notice shops */
      if ((c_ptr->feat >= FEAT_SHOP_HEAD) &&
	  (c_ptr->feat <= FEAT_SHOP_TAIL)) return (TRUE);

      /* Notice traps */
      if ((c_ptr->feat >= FEAT_TRAP_HEAD) &&
	  (c_ptr->feat <= FEAT_TRAP_TAIL)) return (TRUE);

      /* Notice doors */
      if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
	  (c_ptr->feat <= FEAT_DOOR_TAIL)) return (TRUE);

      /* Notice rubble */
      if (c_ptr->feat == FEAT_RUBBLE) return (TRUE);

      /* Notice veins with treasure */
      if (c_ptr->feat == FEAT_MAGMA_K) return (TRUE);
      if (c_ptr->feat == FEAT_QUARTZ_K) return (TRUE);
    }

  /* Nope */
  return (FALSE);
}


/*
 * Prepare the "temp" array for "target_set"
 *
 * Return the number of target_able monsters in the set.
 */
static void target_set_prepare(int mode)
{
  int y, x;

  /* Reset "temp" array */
  temp_n = 0;

  /* Scan the current panel */
  for (y = panel_row_min; y <= panel_row_max; y++)
    {
      for (x = panel_col_min; x <= panel_col_max; x++)
	{
	  cave_type *c_ptr = &cave[y][x];

	  /* Require line of sight, unless "look" is "expanded" */
	  if (!expand_look && !player_has_los_bold(y, x)) continue;

	  /* Require "interesting" contents */
	  if (!target_set_accept(y, x)) continue;

	  /* Require target_able monsters for "TARGET_KILL" */
	  if ((mode & (TARGET_KILL)) && !target_able(c_ptr->m_idx)) continue;

	  /* Save the location */
	  temp_x[temp_n] = x;
	  temp_y[temp_n] = y;
	  temp_n++;
	}
    }

  /* Set the sort hooks */
  ang_sort_comp = ang_sort_comp_distance;
  ang_sort_swap = ang_sort_swap_distance;

  /* Sort the positions */
  ang_sort(temp_x, temp_y, temp_n);
}


/*
 * Examine a grid, return a keypress.
 *
 * The "mode" argument contains the "TARGET_LOOK" bit flag, which
 * indicates that the "space" key should scan through the contents
 * of the grid, instead of simply returning immediately.  This lets
 * the "look" command get complete information, without making the
 * "target" command annoying.
 *
 * The "info" argument contains the "commands" which should be shown
 * inside the "[xxx]" text.  This string must never be empty, or grids
 * containing monsters will be displayed with an extra comma.
 *
 * Note that if a monster is in the grid, we update both the monster
 * recall info and the health bar info to track that monster.
 *
 * Eventually, we may allow multiple objects per grid, or objects
 * and terrain features in the same grid. XXX XXX XXX
 *
 * This function must handle blindness/hallucination.
 */
static int target_set_aux(int y, int x, int mode, cptr info)
{
  cave_type *c_ptr = &cave[y][x];

  s16b this_o_idx, next_o_idx = 0;

  cptr s1, s2, s3;

  bool boring;

  int feat;

  int query;

  char out_val[160];


  /* Repeat forever */
  while (1)
    {
      /* Paranoia */
      query = ' ';

      /* Assume boring */
      boring = TRUE;

      /* Default */
      s1 = "You see ";
      s2 = "";
      s3 = "";

      /* Hack -- under the player */
      if ((y == py) && (x == px))
	{
	  /* Description */
	  s1 = "You are ";
			
	  /* Preposition */
	  s2 = "on ";
	}


      /* Hack -- hallucination */
      if (p_ptr->image)
	{
	  cptr name = "something strange";

	  /* Display a message */
	  sprintf(out_val, "%s%s%s%s [%s]", s1, s2, s3, name, info);
	  prt(out_val, 0, 0);
	  move_cursor_relative(y, x);
	  query = inkey();

	  /* Stop on everything but "return" */
	  if ((query != '\r') && (query != '\n')) break;
			
	  /* Repeat forever */
	  continue;
	}


      /* Actual monsters */
      if (c_ptr->m_idx)
	{
	  monster_type *m_ptr = &m_list[c_ptr->m_idx];
	  monster_race *r_ptr = &r_info[m_ptr->r_idx];

	  /* Visible */
	  if (m_ptr->ml)
	    {
	      bool recall = FALSE;

	      char m_name[80];
	      /* Not boring */
	      boring = FALSE;

	      /* Get the monster name ("a kobold") */
	      monster_desc(m_name, m_ptr, 0x08);

	      /* Hack -- track this monster race */
	      monster_race_track(m_ptr->r_idx);

	      /* Hack -- health bar for this monster */
	      health_track(c_ptr->m_idx);

	      /* Hack -- handle stuff */
	      handle_stuff();

	      /* Interact */
	      while (1)
		{
		  /* Recall */
		  if (recall)
		    {
		      /* Save */
		      Term_save();

		      /* Recall on screen */
		      screen_roff(m_ptr->r_idx);

		      /* Hack -- Complete the prompt (again) */
		      Term_addstr(-1, TERM_WHITE, format("  [r,%s]", info));
					
		      /* Command */
		      query = inkey();

		      /* Restore */
		      Term_load();
		    }

		  /* Normal */
		  else
		    {
		      /* Describe, and prompt for recall */
		      sprintf(out_val, "%s%s%s%s (%s) [r,%s]",
			      s1, s2, s3, m_name, look_mon_desc(c_ptr->m_idx), info);
		      prt(out_val, 0, 0);

		      /* Place cursor */
		      move_cursor_relative(y, x);
					
		      /* Command */
		      query = inkey();
		    }

		  /* Normal commands */
		  if (query != 'r') break;

		  /* Toggle recall */
		  recall = !recall;
		}

	      /* Always stop at "normal" keys */
	      if ((query != '\r') && (query != '\n') && (query != ' ')) break;

	      /* Sometimes stop at "space" key */
	      if ((query == ' ') && !(mode & (TARGET_LOOK))) break;

	      /* Change the intro */
	      s1 = "It is ";

	      /* Hack -- take account of gender */
	      if (r_ptr->flags1 & (RF1_FEMALE)) s1 = "She is ";
	      else if (r_ptr->flags1 & (RF1_MALE)) s1 = "He is ";

	      /* Use a preposition */
	      s2 = "carrying ";

	      /* Scan all objects being carried */
	      for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
		{
		  char o_name[80];

		  object_type *o_ptr;
				
		  /* Acquire object */
		  o_ptr = &o_list[this_o_idx];

		  /* Acquire next object */
		  next_o_idx = o_ptr->next_o_idx;

		  /* Obtain an object description */
		  object_desc(o_name, o_ptr, TRUE, 3);

		  /* Describe the object */
		  sprintf(out_val, "%s%s%s%s [%s]", s1, s2, s3, o_name, info);
		  prt(out_val, 0, 0);
		  move_cursor_relative(y, x);
		  query = inkey();

		  /* Always stop at "normal" keys */
		  if ((query != '\r') && (query != '\n') && (query != ' ')) break;

		  /* Sometimes stop at "space" key */
		  if ((query == ' ') && !(mode & (TARGET_LOOK))) break;

		  /* Change the intro */
		  s2 = "also carrying ";
		}

	      /* Double break */
	      if (this_o_idx) break;

	      /* Use a preposition */
	      s2 = "on ";
	    }
	}


      /* Scan all objects in the grid */
      for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
	{
	  object_type *o_ptr;
		
	  /* Acquire object */
	  o_ptr = &o_list[this_o_idx];

	  /* Acquire next object */
	  next_o_idx = o_ptr->next_o_idx;

	  /* Describe it */
	  if (o_ptr->marked)
	    {
	      char o_name[80];

	      /* Not boring */
	      boring = FALSE;

	      /* Obtain an object description */
	      object_desc(o_name, o_ptr, TRUE, 3);

	      /* Describe the object */
	      sprintf(out_val, "%s%s%s%s [%s]", s1, s2, s3, o_name, info);
	      prt(out_val, 0, 0);
	      move_cursor_relative(y, x);
	      query = inkey();

	      /* Always stop at "normal" keys */
	      if ((query != '\r') && (query != '\n') && (query != ' ')) break;

	      /* Sometimes stop at "space" key */
	      if ((query == ' ') && !(mode & (TARGET_LOOK))) break;

	      /* Change the intro */
	      s1 = "It is ";
	      /* Plurals */
	      if (o_ptr->number != 1) s1 = "They are ";

	      /* Preposition */
	      s2 = "on ";
	    }
	}
      /* Double break */
      if (this_o_idx) break;


      /* Feature (apply "mimic") */
      feat = f_info[c_ptr->feat].mimic;

      /* Require knowledge about grid, or ability to see grid */
      if (!(c_ptr->info & (CAVE_MARK)) && !player_can_see_bold(y,x))
	{
	  /* Forget feature */
	  feat = FEAT_NONE;
	}

      /* Terrain feature if needed */
      if (boring || (feat > FEAT_INVIS))
	{
	  cptr name = f_name + f_info[feat].name;

	  /* Hack -- handle unknown grids */
	  if (feat == FEAT_NONE) name = "unknown grid";

	  /* Pick a prefix */
	  if (*s2 && (feat >= FEAT_DOOR_HEAD)) s2 = "in ";

	  /* Pick proper indefinite article */
	  s3 = (is_a_vowel(name[0])) ? "an " : "a ";

	  /* Hack -- special introduction for store doors */
	  if ((feat >= FEAT_SHOP_HEAD) && (feat <= FEAT_SHOP_TAIL))
	    {
	      s3 = "the entrance to the ";
	    }

	  /* Display a message */
	  sprintf(out_val, "%s%s%s%s [%s]", s1, s2, s3, name, info);
	  prt(out_val, 0, 0);
	  move_cursor_relative(y, x);
	  query = inkey();
			
	  /* Always stop at "normal" keys */
	  if ((query != '\r') && (query != '\n') && (query != ' ')) break;
	}
			
      /* Stop on everything but "return" */
      if ((query != '\r') && (query != '\n')) break;
    }

  /* Keep going */
  return (query);
}



/*
 * Handle "target" and "look".
 *
 * Note that this code can be called from "get_aim_dir()".
 *
 * All locations must be on the current panel.  Consider the use of
 * "panel_bounds()" to allow "off-panel" targets, perhaps by using
 * some form of "scrolling" the map around the cursor.  XXX XXX XXX
 * That is, consider the possibility of "auto-scrolling" the screen
 * while the cursor moves around.  This may require changes in the
 * "update_mon()" code to allow "visibility" even if off panel, and
 * may require dynamic recalculation of the "temp" grid set.
 *
 * Hack -- targetting/observing an "outer border grid" may induce
 * problems, so this is not currently allowed.
 *
 * The player can use the direction keys to move among "interesting"
 * grids in a heuristic manner, or the "space", "+", and "-" keys to
 * move through the "interesting" grids in a sequential manner, or
 * can enter "location" mode, and use the direction keys to move one
 * grid at a time in any direction.  The "t" (set target) command will
 * only target a monster (as opposed to a location) if the monster is
 * target_able and the "interesting" mode is being used.
 *
 * The current grid is described using the "look" method above, and
 * a new command may be entered at any time, but note that if the
 * "TARGET_LOOK" bit flag is set (or if we are in "location" mode,
 * where "space" has no obvious meaning) then "space" will scan
 * through the description of the current grid until done, instead
 * of immediately jumping to the next "interesting" grid.  This
 * allows the "target" command to retain its old semantics.
 *
 * The "*", "+", and "-" keys may always be used to jump immediately
 * to the next (or previous) interesting grid, in the proper mode.
 *
 * The "return" key may always be used to scan through a complete
 * grid description (forever).
 *
 * This command will cancel any old target, even if used from
 * inside the "look" command.
 */
bool target_set(int mode)
{
  int		i, d, m;
  int		y = py;
  int		x = px;

  bool	done = FALSE;

  bool	flag = TRUE;

  char	query;

  char	info[80];
	
  cave_type		*c_ptr;


  /* Cancel target */
  target_who = 0;


  /* Cancel tracking */
  /* health_track(0); */


  /* Prepare the "temp" array */
  target_set_prepare(mode);

  /* Start near the player */
  m = 0;

  /* Interact */
  while (!done)
    {
      /* Interesting grids */
      if (flag && temp_n)
	{
	  y = temp_y[m];
	  x = temp_x[m];

	  /* Access */
	  c_ptr = &cave[y][x];

	  /* Allow target */
	  if (target_able(c_ptr->m_idx))
	    {
	      strcpy(info, "q,t,p,o,+,-,<dir>");
	    }

	  /* Dis-allow target */
	  else
	    {
	      strcpy(info, "q,p,o,+,-,<dir>");
	    }

	  /* Describe and Prompt */
	  query = target_set_aux(y, x, mode, info);
	  /* Cancel tracking */
	  /* health_track(0); */

	  /* Assume no "direction" */
	  d = 0;

	  /* Analyze */
	  switch (query)
	    {
	    case ESCAPE:
	    case 'q':
	      {
		done = TRUE;
		break;
	      }

	    case 't':
	    case '.':
	    case '5':
	    case '0':
	      {
		if (target_able(c_ptr->m_idx))
		  {
		    health_track(c_ptr->m_idx);
		    target_who = c_ptr->m_idx;
		    target_row = y;
		    target_col = x;
		    done = TRUE;
		  }
		else
		  {
		    bell();
		  }
		break;
	      }

	    case ' ':
	    case '*':
	    case '+':
	      {
		if (++m == temp_n)
		  {
		    m = 0;
		    if (!expand_list) done = TRUE;
		  }
		break;
	      }

	    case '-':
	      {
		if (m-- == 0)
		  {
		    m = temp_n - 1;
		    if (!expand_list) done = TRUE;
		  }
		break;
	      }

	    case 'p':
	      {
		y = py;
		x = px;
	      }
	    case 'o':
	      {
		flag = !flag;
		break;
	      }

	    case 'm':
	      {
		break;
	      }

	    default:
	      {
		d = keymap_dirs[query & 0x7F];
		if (!d) bell();
		break;
	      }
	    }

	  /* Hack -- move around */
	  if (d)
	    {
	      /* Find a new monster */
	      i = target_pick(temp_y[m], temp_x[m], ddy[d], ddx[d]);

	      /* Use that grid */
	      if (i >= 0) m = i;
	    }
	}

      /* Arbitrary grids */
      else
	{
	  /* Access */
	  c_ptr = &cave[y][x];

	  /* Default prompt */
	  strcpy(info, "q,t,p,m,+,-,<dir>");

	  /* Describe and Prompt (enable "TARGET_LOOK") */
	  query = target_set_aux(y, x, mode | TARGET_LOOK, info);

	  /* Cancel tracking */
	  /* health_track(0); */
	  /* Assume no direction */
	  d = 0;

	  /* Analyze the keypress */
	  switch (query)
	    {
	    case ESCAPE:
	    case 'q':
	      {
		done = TRUE;
		break;
	      }

	    case 't':
	    case '.':
	    case '5':
	    case '0':
	      {
		target_who = -1;
		target_row = y;
		target_col = x;
		done = TRUE;
		break;
	      }

	    case ' ':
	    case '*':
	    case '+':
	    case '-':
	      {
		break;
	      }

	    case 'p':
	      {
		y = py;
		x = px;
	      }

	    case 'o':
	      {
		break;
	      }

	    case 'm':
	      {
		flag = !flag;
		break;
	      }

	    default:
	      {
		d = keymap_dirs[query & 0x7F];
		if (!d) bell();
		break;
	      }
	    }

	  /* Handle "direction" */
	  if (d)
	    {
	      x += ddx[d];
	      y += ddy[d];

	      /* Hack -- Verify x */
	      if ((x>=cur_wid-1) || (x>panel_col_max)) x--;
	      else if ((x<=0) || (x<panel_col_min)) x++;

	      /* Hack -- Verify y */
	      if ((y>=cur_hgt-1) || (y>panel_row_max)) y--;
	      else if ((y<=0) || (y<panel_row_min)) y++;
	    }
	}
    }

  /* Forget */
  temp_n = 0;

  /* Clear the top line */
  prt("", 0, 0);

  /* Failure to set target */
  if (!target_who) return (FALSE);

  /* Success */
  return (TRUE);
}



/*
 * Get an "aiming direction" from the user.
 *
 * The "dir" is loaded with 1,2,3,4,6,7,8,9 for "actual direction", and
 * "0" for "current target", and "-1" for "entry aborted".
 *
 * Note that "Force Target", if set, will pre-empt user interaction,
 * if there is a usable target already set.
 *
 * Note that confusion over-rides any (explicit?) user choice.
 */
bool get_aim_dir(int *dp)
{
  int		dir;

  char	command;

  cptr	p;

  /* Initialize */
  (*dp) = 0;

  /* Global direction */
  dir = command_dir;

  /* Hack -- auto-target if requested */
  if (use_old_target && target_okay()) dir = 5;

  /* Ask until satisfied */
  while (!dir)
    {
      /* Choose a prompt */
      if (!target_okay())
	{
	  p = "Direction ('*' to choose a target, Escape to cancel)? ";
	}
      else
	{
	  p = "Direction ('5' for target, '*' to re-target, Escape to cancel)? ";
	}

      /* Get a command (or Cancel) */
      if (!get_com(p, &command)) break;

      /* Convert various keys to "standard" keys */
      switch (command)
	{
	  /* Use current target */
	case 'T':
	case 't':
	case '.':
	case '5':
	case '0':
	  {
	    dir = 5;
	    break;
	  }

	/* Set new target */
	case '*':
	  {
	    if (target_set(TARGET_KILL)) dir = 5;
	    break;
	  }

	default:
	  {
	    dir = keymap_dirs[command & 0x7F];
	    break;
	  }
	}
      /* Verify requested targets */
      if ((dir == 5) && !target_okay()) dir = 0;

      /* Error */
      if (!dir) bell();
    }

  /* No direction */
  if (!dir) return (FALSE);

  /* Save the direction */
  command_dir = dir;

  /* Check for confusion */
  if (p_ptr->confused)
    {
      /* XXX XXX XXX */
      /* Random direction */
      dir = ddd[rand_int(8)];
    }

  /* Notice confusion */
  if (command_dir != dir)
    {
      /* Warn the user */
      msg_print("You are confused.");
    }

  /* Save direction */
  (*dp) = dir;

  /* A "valid" direction was entered */
  return (TRUE);
}


/*
 * Request a "movement" direction (1,2,3,4,6,7,8,9) from the user,
 * and place it into "command_dir", unless we already have one.
 *
 * This function should be used for all "repeatable" commands, such as
 * run, walk, open, close, bash, disarm, spike, tunnel, etc, as well
 * as all commands which must reference a grid adjacent to the player,
 * and which may not reference the grid under the player.  Note that,
 * for example, it is no longer possible to "disarm" or "open" chests
 * in the same grid as the player.
 *
 * Direction "5" is illegal and will (cleanly) abort the command.
 *
 * This function tracks and uses the "global direction", and uses
 * that as the "desired direction", to which "confusion" is applied.
 */
bool get_rep_dir(int *dp)
{
  int dir;


  /* Initialize */
  (*dp) = 0;

  /* Global direction */
  dir = command_dir;

  /* Get a direction */
  while (!dir)
    {
      char ch;
      /* Get a command (or Cancel) */
      if (!get_com("Direction (Escape to cancel)? ", &ch)) break;

      /* Look up the direction */
      dir = keymap_dirs[ch & 0x7F];

      /* Oops */
      if (!dir) bell();
    }

  /* Keep the given direction */
  *dp = dir;

  /* Aborted */
  if (!dir) return (FALSE);

  /* Save the direction */
  command_dir = dir;

  /* Apply "confusion" */
  if (p_ptr->confused)
    {
      /* Warn the user XXX XXX XXX */
      /* msg_print("You are confused."); */

      /* Standard confusion */
      if (rand_int(100) < 75)
	{
	  /* Random direction */
	  *dp = ddd[rand_int(8)];
	}
    }
  /* A "valid" direction was entered */
  return (TRUE);
}




