/* File: cmd2.c */

/* Purpose: Movement commands (part 2) */

/*
 * 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"



/*
 * Go up one level                                      -RAK-   
 */
void do_cmd_go_up(void)
{
    cave_type *c_ptr;

    /* Player grid */
    c_ptr = &cave[py][px];

    /* Verify stairs */
    if (c_ptr->feat != 0x06)
    {
	msg_print("I see no up staircase here.");
	return;
    }

    /* Hack -- take a turn */
    energy_use = 100;

    /* Success */
    msg_print("You enter a maze of up staircases.");

    /* Go up the stairs */
    dun_level--;
    new_level_flag = TRUE;

    /* Create a way back */
    create_down_stair = TRUE;
}


/*
 * Go down one level
 */
void do_cmd_go_down(void)
{
    cave_type *c_ptr;

    /* Player grid */
    c_ptr = &cave[py][px];

    /* Verify stairs */
    if (c_ptr->feat != 0x07)
    {
	msg_print("I see no down staircase here.");
	return;
    }

    /* Hack -- take a turn */
    energy_use = 100;

    /* Success */
    msg_print("You enter a maze of down staircases.");

    /* Go down */
    dun_level++;
    new_level_flag = TRUE;

    /* Create a way back */
    create_up_stair = TRUE;
}



/*
 * Simple command to "search" for one turn
 */
void do_cmd_search(void)
{
    /* Allow repeated command */
    if (command_arg)
    {
	/* Set repeat count */
	command_rep = command_arg - 1;

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

	/* Cancel the arg */
	command_arg = 0;
    }

    /* Take a turn */
    energy_use = 100;

    /* Search */
    search();
}


/*
 * Hack -- toggle search mode
 */
void do_cmd_toggle_search(void)
{
    /* Stop searching */
    if (p_ptr->searching)
    {
	/* Clear the searching flag */
	p_ptr->searching = FALSE;

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

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

    /* Start searching */
    else
    {
	/* Set the searching flag */
	p_ptr->searching = TRUE;

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

	/* Redraw stuff */
	p_ptr->redraw |= (PR_STATE | PR_SPEED);
    }
}



/*
 * Allocates objects upon opening a chest    -BEN-
 * Disperse treasures from the chest "i_ptr", centered at (x,y).
 */
static void chest_death(int y, int x, object_type *i_ptr)
{
    int i, d, ny, nx;
    int number, small;


    /* Must be a chest */
    if (i_ptr->tval != TV_CHEST) return;

    /* Determine if the chest is small */
    small = (i_ptr->sval < SV_CHEST_MIN_LARGE);

    /* Determine how many items to drop */
    number = (i_ptr->sval % SV_CHEST_MIN_LARGE);

    /* Generate some treasure */
    if (i_ptr->pval && (number > 0)) 
 {
	/* Drop some objects (non-chests) */
	for ( ; number > 0; --number) 
 {
	    /* Try 20 times per item */
	    for (i = 0; i < 20; ++i)
	    {
		/* Pick a distance */
		d = ((i + 15) / 15);

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

		/* Must be a clean floor grid */
		if (!clean_stackable_grid_bold(ny, nx)) continue;

		/* Opening a chest */
		opening_chest = TRUE;

		/* Make it better than the current level */
		object_level = dun_level + 5;

		/* Small chests sometimes drop gold */
		if (small && percent(50)) 
 {
		    place_gold(ny, nx);
		}

		/* Otherwise drop an item */
		else 
 {
		    place_object(ny, nx, FALSE, FALSE);
		}

		/* Reset the object level */
		object_level = dun_level;

		/* No longer opening a chest */
		opening_chest = FALSE;

		/* Notice it */
		note_spot(ny, nx);

		/* Display it */
		lite_spot(ny, nx);

		/* Under the player */
		if ((nx == px) && (ny == py)) 
 {
		    msg_print("You feel something roll beneath your feet.");
		}

		/* Successful placement */
		break;
	    }
	}
    }

    /* Empty */
    i_ptr->set_pval(0);

    /* Known */
    i_ptr->object_known();
}


/*
 * Chests have traps too.
 *
 * Exploding chest destroys contents (and traps).
 * Note that the chest itself is never destroyed.
 */
static void chest_trap(int y, int x, object_type *i_ptr)
{
    int  i, trap;


    /* Only analyze chests */
    if (i_ptr->tval != TV_CHEST) return;

    /* Ignore disarmed chests */
    if (i_ptr->pval <= 0) return;

    /* Obtain the traps */
    trap = chest_traps[i_ptr->pval];

    /* Lose strength */
    if (trap & CHEST_LOSE_STR) 
 {
	msg_print("A small needle has pricked you!");
	take_hit(damroll(1, 4), "a poison needle");
	do_dec_stat(A_STR);
    }

    /* Lose constitution */
    if (trap & CHEST_LOSE_CON) 
 {
	msg_print("A small needle has pricked you!");
	take_hit(damroll(1, 4), "a poison needle");
	do_dec_stat(A_CON);
    }

    /* Poison */
    if (trap & CHEST_POISON) 
 {
	msg_print("A puff of green gas surrounds you!");
	if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) 
 {
	    set_poisoned(p_ptr->poisoned + 10 + randint(20));
	}
    }

    /* Paralyze */
    if (trap & CHEST_PARALYZE)
    {
	msg_print("A puff of yellow gas surrounds you!");
	if (!p_ptr->free_act)
	{
	    (void)set_paralyzed(p_ptr->paralyzed + 10 + randint(20));
	}
    }

    /* Summon monsters */
    if (trap & CHEST_SUMMON)
    {
	int num = 2 + randint(3);
	msg_print("You are enveloped in a cloud of smoke!");
	for (i = 0; i < num; i++)
	{
	    (void)summon_specific(y, x, dun_level, 0);
	}
    }

    /* Explode */
    if (trap & CHEST_EXPLODE)
    {
	msg_print("There is a sudden explosion!");
	msg_print("Everything inside the chest is destroyed!");
	i_ptr->set_pval(0);
	take_hit(damroll(5, 8), "an exploding chest");
    }
}





/*
 * Open a closed door or closed chest.
 *
 * Note unlocking a locked door/chest is worth one experience point.
 */
void do_cmd_open()
{
    int                         y, x, i, j, dir;
    int                         flag;

    cave_type           *c_ptr;
    object_type         *i_ptr;

    bool more = FALSE;


    /* Allow repeated command */
    if (command_arg)
    {
	/* Set repeat count */
	command_rep = command_arg - 1;

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

	/* Cancel the arg */
	command_arg = 0;
    }

    /* Get a "repeated" direction */
    if (get_rep_dir(&dir))
    {
	/* Get requested location */
	y = py + ddy[dir];
	x = px + ddx[dir];

	/* Get requested grid */
	c_ptr = &cave[y][x];

	/* Get the object (if any) */
	i_ptr = &i_list[c_ptr->i_idx];

	/* Nothing useful */
	if (((c_ptr->feat < 0x20) ||
	     (c_ptr->feat > 0x2F)) &&
	    (i_ptr->tval != TV_CHEST))
	{
	    /* Message */
	    msg_print("You see nothing there to open.");
	}

	/* Monster in the way */
	else if (c_ptr->m_idx)
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Message */
	    msg_print("There is a monster in the way!");

	    /* Attack */
	    py_attack(y, x);
	}

	/* Open a closed chest. */
	else if (i_ptr->tval == TV_CHEST) 
 {
	    /* Take a turn */
	    energy_use = 100;

	    /* Assume opened successfully */
	    flag = TRUE;

	    /* Attempt to unlock it */
	    if (i_ptr->pval > 0) 
 {
		/* Assume locked, and thus not open */
		flag = FALSE;

		/* Get the "disarm" factor */
		i = p_ptr->skill_dis;

		/* Penalize some conditions */
		if (p_ptr->blind || no_lite()) i = i / 10;
		if (p_ptr->confused || p_ptr->image) i = i / 10;

		/* Extract the difficulty */
		j = i - i_ptr->pval;

		/* Always have a small chance of success */
		if (j < 2) j = 2;

		/* Success -- May still have traps */
		if (rand_int(100) < j)
		{
		    msg_print("You have picked the lock.");
		    gain_exp(1);
		    flag = TRUE;
		}

		/* Failure -- Keep trying */
		else
		{
		    /* We may continue repeating */
		    more = TRUE;
		    if (flush_failure) flush();
		    msg_print("You failed to pick the lock.");
		}
	    }

	    /* Allowed to open */
	    if (flag)
	    {
		/* Apply chest traps, if any */
		chest_trap(y, x, i_ptr);

		/* Let the Chest drop items */
		chest_death(y, x, i_ptr);
	    }
	}

	/* Jammed door */
	else if (c_ptr->feat >= 0x28)
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Stuck */
	    msg_print("The door appears to be stuck.");
	}

	/* Locked door */
	else if (c_ptr->feat >= 0x21)
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Disarm factor */
	    i = p_ptr->skill_dis;

	    /* Penalize some conditions */
	    if (p_ptr->blind || no_lite()) i = i / 10;
	    if (p_ptr->confused || p_ptr->image) i = i / 10;

	    /* Extract the difficulty XXX XXX XXX */
	    j = i - ((int)(c_ptr->feat & 0x07)) * 4;

	    /* Always have a small chance of success */
	    if (j < 2) j = 2;

	    /* Success */
	    if (rand_int(100) < j) 
 {
		/* Message */
		msg_print("You have picked the lock.");

		/* Experience */
		gain_exp(1);

		/* Open the door */
		c_ptr->feat = 0x04;

		/* Notice */
		note_spot(y, x);

		/* Redraw */
		lite_spot(y, x);

		/* Update some things */
		p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
	    }

	    /* Failure */
	    else
	    {
		/* Failure */
		if (flush_failure) flush();

		/* Message */
		msg_print("You failed to pick the lock.");

		/* We may keep trying */
		more = TRUE;
	    }
	}

	/* Closed door */
	else
	{
            /* Use energy */
            energy_use = 100;

	    /* Open the door */
	    c_ptr->feat = 0x04;

	    /* Notice */
	    note_spot(y, x);

	    /* Redraw */
	    lite_spot(y, x);

	    /* Update some things */
	    p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
	}
    }

    /* Cancel repeat unless we may continue */
    if (!more) disturb(0, 0);
}


/*
 * Close an open door.
 */
void do_cmd_close()
{
    int                 y, x, dir;
    cave_type           *c_ptr;

    bool more = FALSE;


    /* Allow repeated command */
    if (command_arg)
    {
	/* Set repeat count */
	command_rep = command_arg - 1;

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

	/* Cancel the arg */
	command_arg = 0;
    }

    /* Get a "repeated" direction */
    if (get_rep_dir(&dir))
    {
	/* Get requested location */
	y = py + ddy[dir];
	x = px + ddx[dir];

	/* Get grid and contents */
	c_ptr = &cave[y][x];

	/* Broken door */
	if (c_ptr->feat == 0x05)
	{
	    /* Message */
	    msg_print("The door appears to be broken.");
	}

	/* Require open door */
	else if (c_ptr->feat != 0x04)
	{
	    /* Message */
	    msg_print("You see nothing there to close.");
	}

	/* Monster in the way */
	else if (c_ptr->m_idx)
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Message */
	    msg_print("There is a monster in the way!");

	    /* Attack */
	    py_attack(y, x);
	}

	/* Close the door */
	else
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Close the door */
	    c_ptr->feat = 0x20;

	    /* Notice */
	    note_spot(y, x);

	    /* Redraw */
	    lite_spot(y, x);

	    /* Update some things */
	    p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
	}
    }

    /* Cancel repeat unless we may continue */
    if (!more) disturb(0, 0);
}



/*
 * Tunnel through wall.  Assumes valid location.
 *
 * Note that it is impossible to "extend" rooms past their
 * outer walls (which are actually part of the room).
 *
 * This will, however, produce grids which are NOT illuminated
 * (or darkened) along with the rest of the room.
 */
static bool twall(int y, int x)
{
    cave_type   *c_ptr = &cave[y][x];

    /* Paranoia -- Require a wall or door or some such */
    if (c_ptr->feat < 0x20) return (FALSE);

    /* Remove the feature */
    c_ptr->feat = 0x01;

    /* Forget the "field mark" */
    c_ptr->info &= ~CAVE_MARK;

    /* Notice */
    note_spot(y, x);

    /* Redisplay the grid */
    lite_spot(y, x);

    /* Update some things */
    p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTERS);

    /* Result */
    return (TRUE);
}



/*
 * Tunnels through "walls" (including rubble and closed doors)
 *
 * Note that tunneling almost always takes time, since otherwise
 * you can use tunnelling to find monsters.  Also note that you
 * must tunnel in order to hit invisible monsters in walls (etc).
 *
 * Digging is very difficult without a "digger" weapon, but can be
 * accomplished by strong players using heavy weapons.
 */
void do_cmd_tunnel()
{
    int                 y, x, dir;

    cave_type           *c_ptr;

    bool old_floor = FALSE;

    bool more = FALSE;


    /* Allow repeated command */
    if (command_arg)
    {
	/* Set repeat count */
	command_rep = command_arg - 1;

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

	/* Cancel the arg */
	command_arg = 0;
    }

    /* Get a direction to tunnel, or Abort */
    if (get_rep_dir(&dir))
    {
	/* Get location */
	y = py + ddy[dir];
	x = px + ddx[dir];

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

	/* Check the floor-hood */
	old_floor = floor_grid_bold(y, x);

	/* No tunnelling through emptiness */
	if (c_ptr->feat < 0x20)
	{
	    /* Message */
	    msg_print("You see nothing there to tunnel through.");
	}

	/* No tunnelling through doors */
	else if (c_ptr->feat < 0x30)
	{
	    /* Message */
	    msg_print("You cannot tunnel through doors.");
	}

	/* A monster is in the way */
	else if (c_ptr->m_idx)
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Message */
	    msg_print("There is a monster in the way!");

	    /* Attack */
	    py_attack(y, x);
	}

	/* Okay, try digging */
	else
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Titanium */
	    if (c_ptr->feat >= 0x3C)
	    {
		msg_print("This seems to be permanent rock.");
	    }

	    /* Granite */
	    else if (c_ptr->feat >= 0x38)
	    {
		/* Tunnel */
		if ((p_ptr->skill_dig > 40 + rand_int(1600)) && twall(y, x))
		{
		    msg_print("You have finished the tunnel.");
		}

		/* Keep trying */
		else
		{
		    /* We may continue tunelling */
		    msg_print("You tunnel into the granite wall.");
		    more = TRUE;
		}
	    }

	    /* Quartz / Magma */
	    else if (c_ptr->feat >= 0x32)
	    {
		bool okay = FALSE;
		bool gold = FALSE;
		bool hard = FALSE;

		/* Found gold */
		if (c_ptr->feat >= 0x34) gold = TRUE;

		/* Quartz */
		if (c_ptr->feat & 0x01) hard = TRUE;

		/* Quartz */
		if (hard)
		{
		    okay = (p_ptr->skill_dig > 20 + rand_int(800));
		}

		/* Magma */
		else
		{
		    okay = (p_ptr->skill_dig > 10 + rand_int(400));
		}

		/* Success */
		if (okay && twall(y,x))
		{
		    /* Found treasure */
		    if (gold)
		    {
			/* Place some gold */
			place_gold(y, x);

			/* Notice it */
			note_spot(y, x);

			/* Display it */
			lite_spot(y, x);

			/* Message */
			msg_print("You have found something!");
		    }

		    /* Found nothing */
		    else
		    {
			/* Message */
			msg_print("You have finished the tunnel.");
		    }
		}

		/* Failure (quartz) */
		else if (hard)
		{
		    /* Message, continue digging */
		    msg_print("You tunnel into the quartz vein.");
		    more = TRUE;
		}

		/* Failure (magma) */
		else
		{
		    /* Message, continue digging */
		    msg_print("You tunnel into the magma vein.");
		    more = TRUE;
		}
	    }

	    /* Rubble */
	    else if (c_ptr->feat == 0x31)
	    {
		/* Remove the rubble */
		if ((p_ptr->skill_dig > rand_int(200)) && twall(y,x))
		{
		    /* Message */
		    msg_print("You have removed the rubble.");

		    /* Hack -- place an object */
		    if (rand_int(100) < 10)
		    {
			place_object(y, x, FALSE, FALSE);
			if (player_can_see_bold(y, x))
			{
			     msg_print("You have found something!");
			}
		    }

		    /* Notice */
		    note_spot(y, x);

		    /* Display */
		    lite_spot(y, x);
		}

		else
		{
		    /* Message, keep digging */
		    msg_print("You dig in the rubble.");
		    more = TRUE;
		}
	    }

	    /* Default to secret doors */
	    else
	    {
		/* Message, keep digging */
		msg_print("You tunnel into the granite wall.");
		more = TRUE;

		/* Hack -- Search */
		search();
	    }
	}

	/* Notice "blockage" changes */
	if (old_floor != floor_grid_bold(y, x))
	{
	    /* Update some things */
	    p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTERS);
	}
    }

    /* Cancel repetition unless we can continue */
    if (!more) disturb(0, 0);
}


/*
 * Disarms a trap, or chest     -RAK-   
 */
void do_cmd_disarm()
{
    int                 y, x, i, j, dir, power;

    cave_type           *c_ptr;
    object_type         *i_ptr;

    bool                more = FALSE;


    /* Allow repeated command */
    if (command_arg)
    {
	/* Set repeat count */
	command_rep = command_arg - 1;

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

	/* Cancel the arg */
	command_arg = 0;
    }

    /* Get a direction (or abort) */
    if (get_rep_dir(&dir))
    {
	/* Get location */
	y = py + ddy[dir];
	x = px + ddx[dir];

	/* Get grid and contents */
	c_ptr = &cave[y][x];

	/* Access the item */
	i_ptr = &i_list[c_ptr->i_idx];

	/* Nothing useful */
	if ((i_ptr->tval != TV_CHEST) &&
	    ((c_ptr->feat < 0x10) ||
	     (c_ptr->feat > 0x1F)))
	{
	    /* Message */
	    msg_print("You see nothing there to disarm.");
	}

	/* Monster in the way */
	else if (c_ptr->m_idx)
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Message */
	    msg_print("There is a monster in the way!");

	    /* Attack */
	    py_attack(y, x);
	}

	/* Normal disarm */
	else if (i_ptr->tval == TV_CHEST)
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Get the "disarm" factor */
	    i = p_ptr->skill_dis;

	    /* Penalize some conditions */
	    if (p_ptr->blind || no_lite()) i = i / 10;
	    if (p_ptr->confused || p_ptr->image) i = i / 10;

	    /* Extract the difficulty */
	    j = i - i_ptr->pval;

	    /* Always have a small chance of success */
	    if (j < 2) j = 2;

	    /* Must find the trap first. */
	    if (!i_ptr->is_known()) 
 {
		msg_print("I don't see any traps.");
	    }

	    /* Already disarmed/unlocked */
	    else if (i_ptr->pval <= 0)
	    {
		msg_print("The chest is not trapped.");
	    }

	    /* No traps to find. */
	    else if (!chest_traps[i_ptr->pval])
	    {
		msg_print("The chest is not trapped.");
	    }

	    /* Success (get a lot of experience) */
	    else if (rand_int(100) < j)
	    {
		msg_print("You have disarmed the chest.");
		gain_exp(i_ptr->pval);
		i_ptr->set_pval(-i_ptr->pval);
	    }

	    /* Failure -- Keep trying */
	    else if ((i > 5) && (randint(i) > 5)) 
 {
		/* We may keep trying */
		more = TRUE;
		if (flush_failure) flush();
		msg_print("You failed to disarm the chest.");
	    }

	    /* Failure -- Set off the trap */
	    else 
 {
		msg_print("You set off a trap!");
		chest_trap(y, x, i_ptr);
	    }
	}

	/* Disarm a trap */
	else 
 {
	    cptr name = (f_name + f_info[c_ptr->feat].name);

	    /* Take a turn */
	    energy_use = 100;

	    /* Get the "disarm" factor */
	    i = p_ptr->skill_dis;

	    /* Penalize some conditions */
	    if (p_ptr->blind || no_lite()) i = i / 10;
	    if (p_ptr->confused || p_ptr->image) i = i / 10;

	    /* XXX XXX XXX Variable power? */

	    /* Extract trap "power" */
	    power = 5;

	    /* Extract the difficulty */
	    j = i - power;

	    /* Always have a small chance of success */
	    if (j < 2) j = 2;

	    /* Success */
	    if (rand_int(100) < j) 
 {
		/* Message */
		msg_format("You have disarmed the %s.", name);

		/* Reward */
		gain_exp(power);

		/* Remove the trap */
		c_ptr->feat = 0x01;

		/* Forget the "field mark" */
		c_ptr->info &= ~CAVE_MARK;

		/* Notice */
		note_spot(y, x);

		/* Redisplay the grid */
		lite_spot(y, x);

		/* move the player onto the trap grid */
		move_player(dir, FALSE);
	    }

	    /* Failure -- Keep trying */
	    else if ((i > 5) && (randint(i) > 5))
	    {
		/* Failure */
		if (flush_failure) flush();

		/* Message */
		msg_format("You failed to disarm the %s.", name);

		/* We may keep trying */
		more = TRUE;
	    }

	    /* Failure -- Set off the trap */
	    else
	    {
		/* Message */
		msg_format("You set off the %s!", name);

		/* Move the player onto the trap */
		move_player(dir, FALSE);
	    }
	}
    }

    /* Cancel repeat unless told not to */
    if (!more) disturb(0, 0);
}


/*
 * Bash open a door, success based on character strength
 *
 * For a closed door, pval is positive if locked; negative if stuck.
 *
 * For an open door, pval is positive for a broken door.
 *
 * A closed door can be opened - harder if locked. Any door might be
 * bashed open (and thereby broken). Bashing a door is (potentially)
 * faster! You move into the door way. To open a stuck door, it must
 * be bashed.
 *
 * Creatures can also open or bash doors, see elsewhere.
 *
 * We need to use character body weight for something, or else we need
 * to no longer give female characters extra starting gold.
 */
void do_cmd_bash()
{
    int y, x, dir;
    int bash, temp;

    cave_type *c_ptr;

    bool more = FALSE;


    /* Allow repeated command */
    if (command_arg) 
 {
	/* Set repeat count */
	command_rep = command_arg - 1;

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

	/* Cancel the arg */
	command_arg = 0;
    }

    /* Get a "repeated" direction */
    if (get_rep_dir(&dir))
    {
	/* Bash location */
	y = py + ddy[dir];
	x = px + ddx[dir];

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

	/* Nothing useful */
	if ((c_ptr->feat < 0x20) || (c_ptr->feat > 0x2F)) 
 {
	    /* Message */
	    msg_print("You see nothing there to bash.");
	}

	/* Monster in the way */
	else if (c_ptr->m_idx) 
 {
	    /* Take a turn */
	    energy_use = 100;

	    /* Message */
	    msg_print("There is a monster in the way!");

	    /* Attack */
	    py_attack(y, x);
	}

	/* Bash a closed door */
	else
	{
	    /* Take a turn */
	    energy_use = 100;

	    /* Message */
	    msg_print("You smash into the door!");

	    /* Hack -- Bash power based on strength */
	    /* (Ranges from 3 to 20 to 100 to 200) */
	    bash = adj_str_blow[p_ptr->stat_ind[A_STR]];

	    /* Compare bash power to door power XXX XXX XXX */
	    temp = (bash - ((int)(c_ptr->feat & 0x07)) * 10);

	    /* Hack -- always have a chance */
	    if (temp < 1) temp = 1;

	    /* Hack -- attempt to bash down the door */
	    if (rand_int(100) < temp)
	    {
		/* Message */
		msg_print("The door crashes open!");

		/* Break down the door */
		if (rand_int(100) < 50) 
 {
		    c_ptr->feat = 0x05;
		}

		/* Open the door */
		else 
 {
		    c_ptr->feat = 0x04;
		}

		/* Notice */
		note_spot(y, x);

		/* Redraw */
		lite_spot(y, x);

		/* Hack -- Fall through the door */
		move_player(dir, FALSE);

		/* Update some things */
		p_ptr->update |= (PU_VIEW | PU_LITE);
		p_ptr->update |= (PU_DISTANCE);
	    }

	    /* Saving throw against stun */
	    else if (rand_int(100) < adj_dex_safe[p_ptr->stat_ind[A_DEX]] +
				     p_ptr->lev)
	    {
		/* Message */
		msg_print("The door holds firm.");

		/* Allow repeated bashing */
		more = TRUE;
	    }

	    /* High dexterity yields coolness */
	    else
	    {
		/* Message */
		msg_print("You are off-balance.");

		/* Hack -- Lose balance ala paralysis */
		set_paralyzed(p_ptr->paralyzed + 2 + rand_int(2));
	    }
	}
    }

    /* Unless valid action taken, cancel bash */
    if (!more) disturb(0, 0);
}



/*
 * Support code for the "Walk" and "Jump" commands
 */
void do_cmd_walk(int pickup)
{
    int dir;

    bool more = FALSE;


    /* Allow repeated command */
    if (command_arg)
    {
	/* Set repeat count */
	command_rep = command_arg - 1;

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

	/* Cancel the arg */
	command_arg = 0;
    }

    /* Get a "repeated" direction */
    if (get_rep_dir(&dir))
    {
	/* Take a turn */
	energy_use = 100;

	/* Actually move the character */
	move_player(dir, pickup);

	/* Allow more walking */
	more = TRUE;
    }

    /* Cancel repeat unless we may continue */
    if (!more) disturb(0, 0);
}



/*
 * Start running.
 */
void do_cmd_run(void)
{
    int dir;

    /* Hack -- no running when confused */
    if (p_ptr->confused)
    {
	msg_print("You are too confused!");
	return;
    }

    /* Get a "repeated" direction */
    if (get_rep_dir(&dir))
    {
	/* Hack -- Set the run counter */
	running = (command_arg ? command_arg : 1000);

	/* First step */
	run_step(dir);
    }
}



/*
 * Stay still.  Search.  Enter stores.
 * Pick up treasure if "pickup" is true.
 */
void do_cmd_stay(int pickup)
{
    cave_type *c_ptr = &cave[py][px];


    /* Allow repeated command */
    if (command_arg)
    {
	/* Set repeat count */
	command_rep = command_arg - 1;

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

	/* Cancel the arg */
	command_arg = 0;
    }


    /* Take a turn */
    energy_use = 100;


    /* Spontaneous Searching */
    if ((p_ptr->skill_fos >= 50) || (0 == rand_int(50 - p_ptr->skill_fos)))
    {
	search();
    }

    /* Continuous Searching */
    if (p_ptr->searching)
    {
	search();
    }


    /* Hack -- enter a store if we are on one */
    if ((c_ptr->feat >= 0x08) &&
	(c_ptr->feat <= 0x0F))
    {
	/* Disturb */
	disturb(0, 0);

	/* Hack -- enter store */
	command_new = '_';
    }


    /* Try to Pick up anything under us */
    carry(pickup);
}






/*
 * Resting allows a player to safely restore his hp     -RAK-   
 */
void do_cmd_rest(void)
{
    /* Prompt for time if needed */
    if (command_arg <= 0)
    {
	cptr p = "Rest (0-9999, '*' for HP/SP, '&' as needed): ";

	char out_val[80];

	/* Default */
	strcpy(out_val, "&");

	/* Ask for duration */
	if (!get_string(p, out_val, 4)) return;

	/* Rest until done */
	if (out_val[0] == '&')
	{
	    command_arg = (-2);
	}

	/* Rest a lot */
	else if (out_val[0] == '*')
	{
	    command_arg = (-1);
	}

	/* Rest some */
	else
	{
	    command_arg = atoi(out_val);
	    if (command_arg <= 0) return;
	}
    }


    /* Paranoia */
    if (command_arg > 9999) command_arg = 9999;


    /* Take a turn XXX XXX XXX (?) */
    energy_use = 100;

    /* Save the rest code */
    resting = command_arg;

    /* Cancel searching */
    p_ptr->searching = FALSE;

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

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

    /* Handle stuff */
    handle_stuff();

    /* Refresh */
    Term_fresh();
}






/*
 * Determines the odds of an object breaking when thrown
 * Note that "impact" is true if the object hit a monster
 * Artifacts never break, see the "drop_near()" function.
 * Assume the object has NOT hit a wall or monster
 * Hitting a monster doubles the breakage chance
 * Hitting a wall less than 3 grids away does too.
 */
static int breakage_chance(object_type *i_ptr)
{
    /* Examine the item type */
    switch (i_ptr->tval) 
 {
	/* Burning flasks */
	case TV_FLASK:
	    return 100;

	/* Very breakable objects */
	case TV_POTION:
	case TV_BOTTLE:
	case TV_FOOD:
	    return 50;

	/* Somewhat breakable objects */
	case TV_LITE:
	case TV_SCROLL:
	case TV_ARROW:
	case TV_SKELETON:
	    return 30;

	/* Slightly breakable objects */
	case TV_WAND:
	case TV_SHOT:
	case TV_BOLT:
	    return 20;
    }

    /* Normal objects */
    return 10;
}


/*
 * Fire an object from the pack or floor.
 *
 * You may only fire items that "match" your missile launcher.
 *
 * You must use slings + pebbles/shots, bows + arrows, xbows + bolts.
 *
 * See "calc_bonuses()" for more calculations and such.
 *
 * Note that "firing" a missile is MUCH better than "throwing" it.
 *
 * Note: "unseen" monsters are very hard to hit.
 *
 * Objects are more likely to break if they "attempt" to hit a monster.
 *
 * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots.
 *
 * The "extra shot" code works by decreasing the amount of energy
 * required to make each shot, spreading the shots out over time.
 *
 * Note that when firing missiles, the launcher multiplier is applied
 * after all the bonuses are added in, making multipliers very useful.
 *
 * Note that Bows of "Extra Might" get extra range and an extra bonus
 * for the damage multiplier.
 *
 * Note that Bows of "Extra Shots" give an extra shot.
 */
void do_cmd_fire(void)
{
    int                 dir, item;
    int                 j, y, x, ny, nx, ty, tx;
    int                 tdam, tdis, thits, tmul;
    int                 bonus, chance;
    int                 cur_dis, visible;

    object_type         throw_obj;
    object_type         *i_ptr;

    object_type         *j_ptr;

    bool                hit_body = FALSE;

    int                 missile_attr;
    int                 missile_char;

    char                i_name[80];


    /* Get the "bow" (if any) */
    j_ptr = &inventory[INVEN_BOW];

    /* Require a launcher */
    if (!j_ptr->tval) 
 {
	msg_print("You have nothing to fire with.");
	return;
    }


    /* Require proper missile */
    item_tester_tval = p_ptr->tval_ammo;

    /* Get an item (from inven or floor) */
    if (!get_item(&item, "Fire which item? ", FALSE, TRUE, TRUE))
    {
	if (item == -2) msg_print("You have nothing to fire.");
	return;
    }

    /* Access the item (if in the pack) */
    if (item >= 0)
    {
	i_ptr = &inventory[item];
    }
    else
    {
	i_ptr = &i_list[0 - item];
    }


    /* Get a direction (or cancel) */
    if (!get_aim_dir(&dir)) return;


    /* Create a "local missile object" */
    throw_obj = *i_ptr;
    throw_obj.set_number(1);

    /* Reduce and describe inventory */
    if (item >= 0)
    {
	inven_item_increase(item, -1);
	inven_item_describe(item);
	inven_item_optimize(item);
    }

    /* Reduce and describe floor item */
    else
    {
	floor_item_increase(0 - item, -1);
	floor_item_optimize(0 - item);
    }

    /* Use the missile object */
    i_ptr = &throw_obj;

    /* Describe the object */
    object_desc(i_name, i_ptr, FALSE, 3);

    /* Find the color and symbol for the object for throwing */
    missile_attr = object_attr(i_ptr);
    missile_char = object_char(i_ptr);


    /* Use the proper number of shots */
    thits = p_ptr->num_fire;

    /* Use a base distance */
    tdis = 10;

    /* Base damage from thrown object plus launcher bonus */
    tdam = i_ptr->damroll + i_ptr->to_d + j_ptr->to_d;

    /* Actually "fire" the object */
    bonus = p_ptr->to_h + i_ptr->to_h + j_ptr->to_h;
    chance = (p_ptr->skill_thb + (bonus * BTH_PLUS_ADJ));

    /* Assume a base multiplier */
    tmul = 1;

    /* Analyze the launcher */
    switch (j_ptr->sval) 
 {
	/* Sling and ammo */
	case SV_SLING:
	    tmul = 2;
	    break;

	/* Short Bow and Arrow */
	case SV_SHORT_BOW:
	    tmul = 2;
	    break;

	/* Long Bow and Arrow */
	case SV_LONG_BOW:
	    tmul = 3;
	    break;

	/* Light Crossbow and Bolt */
	case SV_LIGHT_XBOW:
	    tmul = 3;
	    break;

	/* Heavy Crossbow and Bolt */
	case SV_HEAVY_XBOW:
	    tmul = 4;
	    break;
    }

    /* Get extra "power" from "extra might" */
    if (p_ptr->xtra_might) tmul++;

    /* Boost the damage */
    tdam *= tmul;

    /* Base range */
    tdis = 10 + 5 * tmul;


    /* Take a (partial) turn */
    energy_use = (100 / thits);


    /* Start at the player */
    y = py;
    x = px;

    /* Predict the "target" location */
    tx = px + 99 * ddx[dir];
    ty = py + 99 * ddy[dir];

    /* Check for "target request" */
    if ((dir == 5) && target_okay())
    {
	tx = target_col;
	ty = target_row;
    }


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


    /* Travel until stopped */
    for (cur_dis = 0; cur_dis < tdis; )
    {
	/* Hack -- Stop at the target */
	if ((y == ty) && (x == tx)) break;

	/* Calculate the new location (see "project()") */
	ny = y;
	nx = x;
	mmove2(&ny, &nx, py, px, ty, tx);

	/* Stopped by walls/doors */
	if (!floor_grid_bold(ny,nx)) break;
	
	/* Advance the distance */
	cur_dis++;

	/* Save the new location */
	x = nx;
	y = ny;


	/* The player can see the (on screen) missile */
	if (panel_contains(y, x) && player_can_see_bold(y, x))
	{
	    /* Draw, Hilite, Fresh, Pause, Erase */
	    print_rel(missile_char, missile_attr, y, x);
	    move_cursor_relative(y, x);
	    Term_fresh();
	    delay(10 * delay_spd);
	    lite_spot(y, x);
	    Term_fresh();
	}

	/* The player cannot see the missile */
	else
	{
	    /* Pause anyway, for consistancy */
	    delay(10 * delay_spd);
	}


	/* Monster here, Try to hit it */
	if (cave[y][x].m_idx) 
 {
	    cave_type *c_ptr = &cave[y][x];

	    monster_type *m_ptr = &m_list[c_ptr->m_idx];
	    monster_race *r_ptr = &r_info[m_ptr->r_idx];

	    /* Check the visibility */
	    visible = m_ptr->ml;

	    /* Did we hit it (penalize range) */
	    if (test_hit_fire(chance - cur_dis, r_ptr->ac, m_ptr->ml)) 
 {
		bool fear = FALSE;

		/* Assume a default death */
		cptr note_dies = " dies.";

		/* Some monsters get "destroyed" */
		if ((r_ptr->flags3 & RF3_DEMON) ||
		    (r_ptr->flags3 & RF3_UNDEAD) ||
		    (r_ptr->flags2 & RF2_STUPID) ||
		    (strchr("Evg", r_ptr->r_char)))
		{
		    /* Special note at death */
		    note_dies = " is destroyed.";
		}


		/* Note the collision */
		hit_body = TRUE;


		/* Handle unseen monster */
		if (!visible) 
 {
		    /* Invisible monster */
		    msg_format("The %s finds a mark.", i_name);
		}

		/* Handle visible monster */
		else 
 {
		    char m_name[80];

		    /* Get "the monster" or "it" */
		    monster_desc(m_name, m_ptr, 0);

		    /* Message */
		    msg_format("The %s hits %s.", i_name, m_name);

		    /* Hack -- Track this monster race */
		    if (m_ptr->ml) recent_track(m_ptr->r_idx);

		    /* Hack -- Track this monster */
		    if (m_ptr->ml) health_track(c_ptr->m_idx);
		}

		/* Apply special damage XXX XXX XXX */
		tdam = tot_dam_aux(i_ptr, tdam, m_ptr);
		tdam = critical_shot(i_ptr->weight, i_ptr->to_h,
                    tdam);

		/* No negative damage */
		if (tdam < 0) tdam = 0;

		/* Complex message */
		if (wizard) 
 {
		    msg_format("You do %d (out of %d) damage.",
                        tdam, m_ptr->hp);
		}

		/* Hit the monster, check for death */
		if (mon_take_hit(c_ptr->m_idx, tdam, &fear, note_dies)) 
 {
		    /* Dead monster */
		}

		/* No death */
		else
		{
		    /* Message */
		    message_pain(c_ptr->m_idx, tdam);

		    /* Take note */
		    if (fear && m_ptr->ml)
		    {
			char m_name[80];

			/* Sound */
			game_sound(SOUND_FLEE);

			/* Get the monster name (or "it") */
			monster_desc(m_name, m_ptr, 0);

			/* Message */
			msg_format("%^s flees in terror!", m_name);
		    }
		}
	    }

	    /* Stop looking */
	    break;
	}
    }

    /* Chance of breakage */
    j = breakage_chance(i_ptr);

    /* Double the chance if we hit a monster */
    if (hit_body) j = j * 2;

    /* Paranoia -- maximum breakage chance */
    if (j > 100) j = 100;

    /* Drop (or break) near that location */
    drop_near(i_ptr, j, y, x);
}



/*
 * Throw an object from the pack or floor.
 *
 * Note: "unseen" monsters are very hard to hit.
 *
 * Should throwing a weapon do full damage?  Should it allow the magic
 * to hit bonus of the weapon to have an effect?  Should it ever cause
 * the item to be destroyed?  Should it do any damage at all?
 *
 * Do we really need "verification" (note the "destroy" command)?
 */
void do_cmd_throw(void)
{
    int dir, item;
    int j, y, x, ny, nx, ty, tx;
    int chance, tdam, tdis;
    int mul, div;
    int cur_dis, visible;

    object_type throw_obj;
    object_type *i_ptr;

    bool hit_body = FALSE;

    int missile_attr;
    int missile_char;

    char i_name[80];


    /* Get an item (from inven or floor) */
    if (!get_item(&item, "Throw which item? ", FALSE, TRUE, TRUE)) 
 {
	if (item == -2) msg_print("You have nothing to throw.");
	return;
    }

    /* Access the item (if in the pack) */
    if (item >= 0) 
 {
	i_ptr = &inventory[item];
    }
    else 
 {
	i_ptr = &i_list[-item];
    }


    /* Get a direction (or cancel) */
    if (!get_aim_dir(&dir)) return;


    /* Create a "local missile object" */
    throw_obj = *i_ptr;
    throw_obj.set_number(1);

    /* Reduce and describe inventory */
    if (item >= 0) 
 {
	inven_item_increase(item, -1);
	inven_item_describe(item);
	inven_item_optimize(item);
    }

    /* Reduce and describe floor item */
    else 
 {
	floor_item_increase(0 - item, -1);
	floor_item_optimize(0 - item);
    }

    /* Use the local object */
    i_ptr = &throw_obj;

    /* Description */
    object_desc(i_name, i_ptr, FALSE, 3);

    /* Find the color and symbol for the object for throwing */
    missile_attr = object_attr(i_ptr);
    missile_char = object_char(i_ptr);


    /* Extract a "distance multiplier" */
    mul = 10;

    /* Enforce a minimum "weight" of one pound */
    div = ((i_ptr->weight > 10) ? i_ptr->weight : 10);

    /* Hack -- Distance -- Reward strength, penalize weight */
    tdis = (adj_str_blow[p_ptr->stat_ind[A_STR]] + 20) * mul / div;

    /* Max distance of 10 */
    if (tdis > 10) tdis = 10;

    /* Hack -- Base damage from thrown object */
    tdam = i_ptr->damroll + i_ptr->to_d;

    /* Chance of hitting */
    chance = (p_ptr->skill_tht + (p_ptr->to_h * BTH_PLUS_ADJ));


    /* Take a turn */
    energy_use = 100;


    /* Start at the player */
    x = px;
    y = py;

    /* Predict the "target" location */
    tx = px + 99 * ddx[dir];
    ty = py + 99 * ddy[dir];

    /* Check for "target request" */
    if ((dir == 5) && target_okay()) 
 {
	tx = target_col;
	ty = target_row;
    }


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


    /* Travel until stopped */
    for (cur_dis = 0; cur_dis < tdis; ) 
 {
	/* Hack -- Stop at the target */
	if ((x == tx) && (y == ty)) break;

	/* Calculate the new location (see "project()") */
	nx = x;
	ny = y;
	mmove2(&ny, &nx, py, px, ty, tx);

	/* Stopped by walls/doors */
	if (!floor_grid_bold(ny,nx)) break;

	/* Advance the distance */
	cur_dis++;

	/* Save the new location */
	x = nx;
	y = ny;


	/* The player can see the (on screen) missile */
	if (panel_contains(y, x) && player_can_see_bold(y, x)) 
 {
	    /* Draw, Hilite, Fresh, Pause, Erase */
	    print_rel(missile_char, missile_attr, y, x);
	    move_cursor_relative(y, x);
	    Term_fresh();
	    delay(10 * delay_spd);
	    lite_spot(y, x);
	    Term_fresh();
	}

	/* The player cannot see the missile */
	else 
 {
	    /* Pause anyway, for consistancy */
	    delay(10 * delay_spd);
	}


	/* Monster here, Try to hit it */
	if (cave[y][x].m_idx) 
 {
	    cave_type *c_ptr = &cave[y][x];

	    monster_type *m_ptr = &m_list[c_ptr->m_idx];
	    monster_race *r_ptr = &r_info[m_ptr->r_idx];

	    /* Check the visibility */
	    visible = m_ptr->ml;

	    /* Did we hit it (penalize range) */
	    if (test_hit_fire(chance - cur_dis, r_ptr->ac, m_ptr->ml))
	    {
		bool fear = FALSE;

		/* Assume a default death */
		cptr note_dies = " dies.";

		/* Some monsters get "destroyed" */
		if ((r_ptr->flags3 & RF3_DEMON) ||
		    (r_ptr->flags3 & RF3_UNDEAD) ||
		    (r_ptr->flags2 & RF2_STUPID) ||
		    (strchr("Evg", r_ptr->r_char)))
		{
		    /* Special note at death */
		    note_dies = " is destroyed.";
		}


		/* Note the collision */
		hit_body = TRUE;


		/* Handle unseen monster */
                if (!visible) 
 {
		    /* Invisible monster */
		    msg_format("The %s finds a mark.", i_name);
		}

		/* Handle visible monster */
		else 
 {
		    char m_name[80];

		    /* Get "the monster" or "it" */
		    monster_desc(m_name, m_ptr, 0);

		    /* Message */
		    msg_format("The %s hits %s.", i_name, m_name);

		    /* Hack -- Track this monster race */
		    if (m_ptr->ml) recent_track(m_ptr->r_idx);

		    /* Hack -- Track this monster */
		    if (m_ptr->ml) health_track(c_ptr->m_idx);
		}

		/* Apply special damage XXX XXX XXX */
		tdam = tot_dam_aux(i_ptr, tdam, m_ptr);
		tdam = critical_shot(i_ptr->weight, i_ptr->to_h,
                    tdam);

		/* No negative damage */
		if (tdam < 0) tdam = 0;

		/* Complex message */
		if (wizard) 
 {
		    msg_format("You do %d (out of %d) damage.",
                        tdam, m_ptr->hp);
		}

		/* Hit the monster, check for death */
		if (mon_take_hit(c_ptr->m_idx, tdam, &fear, note_dies)) 
 {
		    /* Dead monster */
		}

		/* No death */
		else 
 {
		    /* Message */
		    message_pain(c_ptr->m_idx, tdam);

		    /* Take note */
		    if (fear && m_ptr->ml) 
 {
			char m_name[80];

			/* Sound */
			game_sound(SOUND_FLEE);

			/* Get the monster name (or "it") */
			monster_desc(m_name, m_ptr, 0);

			/* Message */
			msg_format("%^s flees in terror!", m_name);
		    }
		}
	    }

	    /* Stop looking */
	    break;
	}
    }

    /* Chance of breakage */
    j = breakage_chance(i_ptr);

    /* Double the chance if we hit a monster */
    if (hit_body) j = j * 2;

    /* Paranoia -- maximum breakage chance */
    if (j > 100) j = 100;

    /* Drop (or break) near that location */
    drop_near(i_ptr, j, y, x);
}



