示例#1
0
/*
 * Use an object the right way.
 *
 * There may be a BIG problem with any "effect" that can cause "changes"
 * to the inventory.  For example, a "scroll of recharging" can cause
 * a wand/staff to "disappear", moving the inventory up.  Luckily, the
 * scrolls all appear BEFORE the staffs/wands, so this is not a problem.
 * But, for example, a "staff of recharging" could cause MAJOR problems.
 * In such a case, it will be best to either (1) "postpone" the effect
 * until the end of the function, or (2) "change" the effect, say, into
 * giving a staff "negative" charges, or "turning a staff into a stick".
 * It seems as though a "rod of recharging" might in fact cause problems.
 * The basic problem is that the act of recharging (and destroying) an
 * item causes the inducer of that action to "move", causing "o_ptr" to
 * no longer point at the correct item, with horrifying results.
 */
void do_cmd_use(cmd_code code, cmd_arg args[])
{
	int item = args[0].item;
	object_type *o_ptr = object_from_item_idx(item);
	int effect;
	bool ident = FALSE, used = FALSE;
	bool was_aware = object_flavor_is_aware(o_ptr);
	int dir = 5;
	int px = p_ptr->px, py = p_ptr->py;
	int snd, boost, level;
	use_type use;
	int items_allowed = 0;

	/* Determine how this item is used. */
	if (obj_is_rod(o_ptr))
	{
		if (!obj_can_zap(o_ptr))
		{
			msg("That rod is still charging.");
			return;
		}

		use = USE_TIMEOUT;
		snd = MSG_ZAP_ROD;
		items_allowed = USE_INVEN | USE_FLOOR;
	}
	else if (obj_is_wand(o_ptr))
	{
		if (!obj_has_charges(o_ptr))
		{
			msg("That wand has no charges.");
			return;
		}

		use = USE_CHARGE;
		snd = MSG_ZAP_ROD;
		items_allowed = USE_INVEN | USE_FLOOR;
	}
	else if (obj_is_staff(o_ptr))
	{
		if (!obj_has_charges(o_ptr))
		{
			msg("That staff has no charges.");
			return;
		}

		use = USE_CHARGE;
		snd = MSG_USE_STAFF;
		items_allowed = USE_INVEN | USE_FLOOR;
	}
	else if (obj_is_food(o_ptr))
	{
		use = USE_SINGLE;
		snd = MSG_EAT;
		items_allowed = USE_INVEN | USE_FLOOR;
	}
	else if (obj_is_potion(o_ptr))
	{
		use = USE_SINGLE;
		snd = MSG_QUAFF;
		items_allowed = USE_INVEN | USE_FLOOR;
	}
	else if (obj_is_scroll(o_ptr))
	{
		/* Check player can use scroll */
		if (!player_can_read())
			return;

		use = USE_SINGLE;
		snd = MSG_GENERIC;
		items_allowed = USE_INVEN | USE_FLOOR;
	}
	else if (obj_is_activatable(o_ptr))
	{
		if (!obj_can_activate(o_ptr))
		{
			msg("That item is still charging.");
			return;
		}

		use = USE_TIMEOUT;
		snd = MSG_ACT_ARTIFACT;
		items_allowed = USE_EQUIP;
	}
	else
	{
		msg("The item cannot be used at the moment");
	}

	/* Check if item is within player's reach. */
	if (items_allowed == 0 || !item_is_available(item, NULL, items_allowed))
	{
		msg("You cannot use that item from its current location.");
		return;
	}

	/* track the object used */
	track_object(item);

	/* Figure out effect to use */
	effect = object_effect(o_ptr);

	/* If the item requires a direction, get one (allow cancelling) */
	if (obj_needs_aim(o_ptr))
		dir = args[1].direction;

	/* Check for use if necessary, and execute the effect */
	if ((use != USE_CHARGE && use != USE_TIMEOUT) || check_devices(o_ptr))
	{
		int beam = beam_chance(o_ptr->tval);

		/* Special message for artifacts */
		if (o_ptr->artifact)
		{
			msgt(snd, "You activate it.");
			if (o_ptr->artifact->effect_msg)
				activation_message(o_ptr, o_ptr->artifact->effect_msg);
			level = o_ptr->artifact->level;
		}
		else
		{
			/* Make a noise! */
			sound(snd);
			level = o_ptr->kind->level;
		}

		/* A bit of a hack to make ID work better.
			-- Check for "obvious" effects beforehand. */
		if (effect_obvious(effect)) object_flavor_aware(o_ptr);

		/* Boost damage effects if skill > difficulty */
		boost = MAX(p_ptr->state.skills[SKILL_DEVICE] - level, 0);

		/* Do effect */
		used = effect_do(effect, &ident, was_aware, dir, beam, boost);

		/* Quit if the item wasn't used and no knowledge was gained */
		if (!used && (was_aware || !ident)) return;
	}

	/* If the item is a null pointer or has been wiped, be done now */
	if (!o_ptr || !o_ptr->kind) return;

	if (ident) object_notice_effect(o_ptr);

	/* Food feeds the player */
	if (o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION)
		(void)set_food(p_ptr->food + o_ptr->pval[DEFAULT_PVAL]);

	/* Use the turn */
	p_ptr->energy_use = 100;

	/* Mark as tried and redisplay */
	p_ptr->notice |= (PN_COMBINE | PN_REORDER);
	p_ptr->redraw |= (PR_INVEN | PR_EQUIP | PR_OBJECT);

	/*
	 * If the player becomes aware of the item's function, then mark it as
	 * aware and reward the player with some experience.  Otherwise, mark
	 * it as "tried".
	 */
	if (ident && !was_aware)
	{
		/* Object level */
		int lev = o_ptr->kind->level;

		object_flavor_aware(o_ptr);
		if (o_ptr->tval == TV_ROD) object_notice_everything(o_ptr);
		player_exp_gain(p_ptr, (lev + (p_ptr->lev / 2)) / p_ptr->lev);
		p_ptr->notice |= PN_SQUELCH;
	}
	else if (used)
	{
		object_flavor_tried(o_ptr);
	}

	/* If there are no more of the item left, then we're done. */
	if (!o_ptr->number) return;

	/* Chargeables act differently to single-used items when not used up */
	if (used && use == USE_CHARGE)
	{
		/* Use a single charge */
		o_ptr->pval[DEFAULT_PVAL]--;

		/* Describe charges */
		if (item >= 0)
			inven_item_charges(item);
		else
			floor_item_charges(0 - item);
	}
	else if (used && use == USE_TIMEOUT)
	{
		/* Artifacts use their own special field */
		if (o_ptr->artifact)
			o_ptr->timeout = randcalc(o_ptr->artifact->time, 0, RANDOMISE);
		else
			o_ptr->timeout += randcalc(o_ptr->kind->time, 0, RANDOMISE);
	}
	else if (used && use == USE_SINGLE)
	{
		/* Destroy a potion in the pack */
		if (item >= 0)
		{
			inven_item_increase(item, -1);
			inven_item_describe(item);
			inven_item_optimize(item);
		}

		/* Destroy a potion on the floor */
		else
		{
			floor_item_increase(0 - item, -1);
			floor_item_describe(0 - item);
			floor_item_optimize(0 - item);
		}
	}
	
	/* Hack to make Glyph of Warding work properly */
	if (cave->feat[py][px] == FEAT_GLYPH)
	{
		/* Push objects off the grid */
		if (cave->o_idx[py][px]) push_object(py, px);
	}


}
示例#2
0
/*
 * Request a game command from the uI and carry out whatever actions
 * go along with it.
 */
void process_command(cmd_context ctx, bool no_request)
{
	int idx;
	game_command cmd;

	/* If we've got a command to process, do it. */
	if (cmd_get(ctx, &cmd, !no_request) == 0)
	{
		idx = cmd_idx(cmd.command);

		if (idx == -1) return;

		/* Do some sanity checking on those arguments that might have
		   been declared as "unknown", such as directions and targets. */
		switch (cmd.command)
		{
			case CMD_WALK:
			case CMD_RUN:
			case CMD_JUMP:
			case CMD_OPEN:
			case CMD_CLOSE:
			case CMD_TUNNEL:
			case CMD_DISARM:
			case CMD_BASH:
			case CMD_ALTER:
			case CMD_JAM:
			case CMD_MAKE_TRAP:
			{
				/* Direction hasn't been specified, so we ask for one. */
				if (cmd.args[0].direction == DIR_UNKNOWN)
				{
					if (!get_rep_dir(&cmd.args[0].direction))
						return;
				}

				break;
			}

			/*
			 * These take an item number and a  "target" as arguments,
			 * though a target isn't always actually needed, so we'll
			 * only prompt for it via callback if the item being used needs it.
			 */
			case CMD_USE_WAND:
			case CMD_USE_ROD:
			case CMD_QUAFF:
			case CMD_ACTIVATE:
			case CMD_READ_SCROLL:
			case CMD_FIRE:
			case CMD_THROW:
			case CMD_STEAL:
			{
				bool get_target = FALSE;

				if (cmd.command == CMD_FIRE ||
					cmd.command == CMD_THROW ||
					obj_needs_aim(object_from_item_idx(cmd.args[0].choice)))
				{
					if (cmd.args[1].direction == DIR_UNKNOWN)
						get_target = TRUE;

					if (cmd.args[1].direction == DIR_TARGET && !target_okay())
						get_target = TRUE;
				}

				if (get_target && !get_aim_dir(&cmd.args[1].direction, FALSE))
						return;

				break;
			}

			/* This takes a choice and a direction. */
			case CMD_CAST:
			{
				bool get_target = FALSE;

				if (spell_needs_aim(cp_ptr->spell_book, cmd.args[0].choice))
				{
					if (cmd.args[1].direction == DIR_UNKNOWN)
						get_target = TRUE;

					if (cmd.args[1].direction == DIR_TARGET && !target_okay())
						get_target = TRUE;

				}

				if (get_target && !get_aim_dir(&cmd.args[1].direction, FALSE))
						return;

				break;
			}

			default:
			{
				/* I can see the point of the compiler warning, but still... */
				break;
			}
		}

		/* Command repetition */
		if (game_cmds[idx].repeat_allowed)
		{
			/* Auto-repeat */
			if (game_cmds[idx].auto_repeat_n > 0 && p_ptr->command_arg == 0 && p_ptr->command_rep == 0)
				p_ptr->command_arg = game_cmds[idx].auto_repeat_n;

			allow_repeated_command();
		}

		repeat_prev_allowed = TRUE;

		if (game_cmds[idx].fn)
			game_cmds[idx].fn(cmd.command, cmd.args);
	}
}
示例#3
0
// Repeat the previous command
// Assumes the command and args were properly saved
void do_cmd_repeat(void)
{
    if (!character_dungeon) return;
    if (!p_ptr->command_previous) return;

    // repeat the previous command
    command_type *command_ptr = &command_info[p_ptr->command_previous];

    // Make sure we are dealing with the same item
    if (command_ptr->cmd_needs & (ARG_ITEM))
    {
        object_type *o_ptr = object_from_item_idx(p_ptr->command_previous_args.item);

        if (o_ptr->k_idx != p_ptr->command_previous_args.k_idx)
        {
            pop_up_message_box("Unable to repeat command.<br>Item has been moved or changed.");
            p_ptr->player_previous_command_wipe();
            return;
        }
    }

    if (p_ptr->command_previous == CMD_CAST)
    {

        if (!spell_needs_aim(cp_ptr->spell_book, p_ptr->command_previous_args.number)) p_ptr->command_previous_args.direction = DIR_UNKNOWN;
        else if (p_ptr->command_previous_args.direction == DIR_CLOSEST)
        {
            int mode = TARGET_QUIET;

            if (!is_trap_spell(cp_ptr->spell_book, p_ptr->command_previous_args.number)) mode |= TARGET_KILL;
            else mode |= TARGET_TRAP;

            if (!target_set_closest(mode)) p_ptr->command_previous_args.direction = DIR_UNKNOWN;
        }
    }

    else if (p_ptr->command_previous == CMD_ITEM_USE)
    {
        object_type *o_ptr = object_from_item_idx(p_ptr->command_previous_args.item);

        if (!obj_needs_aim(o_ptr)) p_ptr->command_previous_args.direction = DIR_UNKNOWN;
        else if (p_ptr->command_previous_args.direction == DIR_CLOSEST)
        {
            int mode = TARGET_QUIET;

            if (!k_info[o_ptr->k_idx].is_trap_object_kind()) mode |= TARGET_KILL;
            else mode |= TARGET_TRAP;

            if (!target_set_closest(mode)) p_ptr->command_previous_args.direction = DIR_UNKNOWN;
        }
    }


    else if (!command_ptr->keep_direction())
    {
        p_ptr->command_previous_args.direction = DIR_UNKNOWN;
    }

    // Get the direction, if necessary
    if (command_ptr->needs_direction())
    {
        if (!get_aim_dir(&p_ptr->command_previous_args.direction, FALSE)) return;
    }

    command_ptr->command_function(p_ptr->command_previous_args);
}