示例#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
/* pick the context menu options appropiate for the item */
int context_menu_object(const object_type *o_ptr)
{
	menu_type *m;
	rect_region r;
	int selected;
	int location = 0;
	char *labels;
	char header[120];
	s16b *list;

	m = menu_dynamic_new();
	if (!m || !o_ptr) {
		return 0;
	}
	object_desc(header, o_ptr, TRUE, 2, sizeof(header));

	list = look_up_list((object_type*)o_ptr);
	if (list) {
		if (list == &(p_ptr->inventory)) {
			location = USE_INVEN;
		} else
		if (list == &(area(p_ptr->px, p_ptr->py)->o_idx)) {
			location = USE_FLOOR;
		} else
		{
			/* check if in a container */
			location = USE_INVEN;
		}
	} else
	if (GET_ARRAY_INDEX(p_ptr->equipment, o_ptr) >= EQUIP_WIELD) {
		location = USE_EQUIP;
	}

	labels = (char*)string_make(lower_case);
	m->selections = labels;

	menu_dynamic_add_label(m, "Inspect", 'I', 1, labels);

	if (item_tester_hook_is_book(o_ptr)) {
		if (player_can_cast_from(o_ptr)) {
			if (player_can_cast()) {
				menu_dynamic_add_label(m, "Cast", 'm', 8, labels);
			} else {
				menu_dynamic_add_label(m, "$Cast", 'm', 8, labels);
			}
			if (player_can_study()) {
				menu_dynamic_add_label(m, "Study", 'G', 10, labels);
			} else {
				menu_dynamic_add_label(m, "$Study", 'G', 10, labels);
			}
		}
		if (player_is_caster() && player_can_read()) {
			menu_dynamic_add_label(m, "Browse", 'b', 9, labels);
		}
	} else
	if (item_tester_hook_useable(o_ptr)) {
		if (obj_is_wand(o_ptr)) {
			if (obj_has_charges(o_ptr)) {
				menu_dynamic_add_label(m, "Aim", 'a', 8, labels);
			} else {
				menu_dynamic_add_label(m, "$Aim", 'a', 8, labels);
			}
		} else
		if (obj_is_rod(o_ptr)) {
			if (obj_can_zap(o_ptr)) {
				menu_dynamic_add_label(m, "Zap", 'z', 8, labels);
			} else {
				menu_dynamic_add_label(m, "$Zap", 'z', 8, labels);
			}
		} else
		if (obj_is_staff(o_ptr)) {
			if (obj_has_charges(o_ptr)) {
				menu_dynamic_add_label(m, "Use", 'u', 8, labels);
			} else {
				menu_dynamic_add_label(m, "$Use", 'u', 8, labels);
			}
		} else
		if (obj_is_scroll(o_ptr)) {
			if (player_can_read()) {
				menu_dynamic_add_label(m, "Read", 'r', 8, labels);
			} else {
				menu_dynamic_add_label(m, "$Read", 'r', 8, labels);
			}
		} else
		if (obj_is_potion(o_ptr)) {
			menu_dynamic_add_label(m, "Quaff", 'q', 8, labels);
		} else
		if (obj_is_food(o_ptr)) {
			menu_dynamic_add_label(m, "Eat", 'E', 8, labels);
		} else
		if (item_tester_hook_activate(o_ptr)) {
			if (obj_is_activatable(o_ptr)) {
				menu_dynamic_add_label(m, "Activate", 'A', 8, labels);
			} else {
				menu_dynamic_add_label(m, "$Activate", 'A', 8, labels);
			}
		} else
		{
			menu_dynamic_add_label(m, "Use", 'U', 8, labels);
		}
	} else
	if (item_tester_hook_ammo(o_ptr)) {
		if (obj_can_fire(o_ptr)) {
			menu_dynamic_add_label(m, "Fire", 'f', 15, labels);
		} else {
			menu_dynamic_add_label(m, "$Fire", 'f', 15, labels);
		}
	}
	if (obj_can_refill(o_ptr)) {
		menu_dynamic_add_label(m, "Refill", 'F', 11, labels);
	}
	if (item_tester_hook_wear(o_ptr)) {
		if (location == USE_EQUIP) {
			menu_dynamic_add_label(m, "Take off", 't', 3, labels);
		} else
		if (location == USE_INVEN) {
			if (item_tester_hook_armour(o_ptr)) {
				menu_dynamic_add_label(m, "Wear", 'w', 2, labels);
			} else {
		 		menu_dynamic_add_label(m, "Wield", 'w', 2, labels);
			}
			/*menu_dynamic_add_label(m, "Equip", 'w', 2, labels);*/
		}
	}
	if ((location == USE_INVEN) || (location == USE_EQUIP)) {
		menu_dynamic_add_label(m, "Drop", 'd', 6, labels);
		if (o_ptr->number > 1) {
			menu_dynamic_add_label(m, "Drop All", 'd', 13, labels);
		}
	} else
	if (location == USE_FLOOR) {
		if (inven_carry_okay(o_ptr)) {
			menu_dynamic_add_label(m, "Pickup", 'g', 7, labels);
		} else {
			menu_dynamic_add_label(m, "$Pickup", 'g', 7, labels);
		}
	}
	menu_dynamic_add_label(m, "Throw", 'v', 12, labels);

	/*if (obj_has_inscrip(o_ptr)) {*/
	if (o_ptr->inscription) {
		menu_dynamic_add_label(m, "Uninscribe", '}', 5, labels);
	} else {
		menu_dynamic_add_label(m, "Inscribe", '{', 4, labels);
	}
	menu_dynamic_add_label(m, "Destroy", 'k', 14, labels);
#if 0
	if (object_is_squelched(o_ptr)) {
		menu_dynamic_add_label(m, "Unignore", 'k', 14, labels);
	} else {
		menu_dynamic_add_label(m, "Ignore", 'k', 14, labels);
	}
#endif

	/* work out display region */
	r.width = menu_dynamic_longest_entry(m) + 3 + 2; /* +3 for tag, 2 for pad */
	r.col = Term->wid - r.width - 1;
	r.row = 1;
	r.page_rows = m->count;

	/* Hack -- no flush needed */
	msg_flag = FALSE;

	screen_save();
	button_backup_all(TRUE);

	/* Recall object */
	roff_set_width(r.col);
	roff_obj_aux(o_ptr);
	roff_set_width(0);

	menu_layout(m, &r);
	rect_region_erase_bordered(&r);

	prtf(0, 0, "($UEnter to select$Y\n$V, $UESC$Y%c$V) Command for %s:", ESCAPE, header);
	selected = menu_dynamic_select(m);

	menu_dynamic_free(m);
	string_free(labels);

	button_restore();
	screen_load();

	if (selected == 1) {
		/* inspect it */
		identify_fully_aux(o_ptr);
		return 2;
	} else
	if (selected == 2) {
		/* wield the item */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = 'w';
		do_cmd_wield();
 		/*cmd_insert(CMD_WIELD);
		cmd_set_arg_item(cmd_get_top(), 0, slot);*/
	} else
	if (selected == 3) {
		/* take the item off */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = 't';
		do_cmd_takeoff();
 		/*cmd_insert(CMD_TAKEOFF);
		cmd_set_arg_item(cmd_get_top(), 0, slot);*/
	} else
	if (selected == 4) {
		/* inscribe the item */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = '{';
		do_cmd_inscribe();
 		/*cmd_insert(CMD_INSCRIBE);
		cmd_set_arg_item(cmd_get_top(), 0, slot);*/
	} else
	if (selected == 5) {
		/* uninscribe the item */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = '}';
		do_cmd_uninscribe();
 		/*cmd_insert(CMD_UNINSCRIBE);
		cmd_set_arg_item(cmd_get_top(), 0, slot);*/
	} else
	if (selected == 6) {
		/* drop the item */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = 'd';
		do_cmd_drop();
 		/*cmd_insert(CMD_DROP);
		cmd_set_arg_item(cmd_get_top(), 0, slot);*/
	} else
	if (selected == 7) {
		/* pick the item up */
		p_ptr->cmd.cmd = 'g';
		if (inven_carry_okay(o_ptr)) {
			py_pickup_aux((object_type*)o_ptr);
		} else {
			carry(TRUE);
		}
 		/*cmd_insert(CMD_PICKUP);
		cmd_set_arg_item(cmd_get_top(), 0, slot);*/
	} else
	if (selected == 8) {
		/* use the item */
		bool full = item_tester_full;
		item_tester_full = FALSE;
		if (player_can_cast_from(o_ptr)) {
			set_get_item_object(o_ptr);
 			p_ptr->cmd.cmd = 'm';
			do_cmd_cast();
		} else {
			set_get_item_object(o_ptr);
			p_ptr->cmd.cmd = 'u';
			repeat_check();
			do_cmd_use();
			/*cmd_insert(CMD_USE_ANY);
			cmd_set_arg_item(cmd_get_top(), 0, slot);*/
		}
		item_tester_full = full;
	} else
	if (selected == 9) {
		/* browse a spellbook */
 		p_ptr->cmd.cmd = 'b';
		do_cmd_browse_aux(o_ptr);
		/* copied from textui_spell_browse */
		/*textui_book_browse(o_ptr);*/
		return 2;
	} else
	if (selected == 10) {
		/* study a spell book */
 		p_ptr->cmd.cmd = 'G';
		do_cmd_study(FALSE, (object_type*)o_ptr);

	} else
	if (selected == 11) {
		/* use the item to refill a light source */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = 'F';
		do_cmd_refill();
		/*cmd_insert(CMD_REFILL);
		cmd_set_arg_item(cmd_get_top(), 0, slot);*/
	} else
	if (selected == 12) {
		/* throw the item */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = 'v';
		repeat_check();
		do_cmd_throw();
		/*cmd_insert(CMD_THROW);
		cmd_set_arg_item(cmd_get_top(), 0, slot);*/
	} else
	if (selected == 13) {
		/* drop all of the item stack */
		if (get_check(format("Drop %s? ", header))) {
			set_get_item_object(o_ptr);
			p_ptr->cmd.arg = o_ptr->number;
			p_ptr->cmd.cmd = 'd';
			do_cmd_drop();
			/*cmd_insert(CMD_DROP);
			cmd_set_arg_item(cmd_get_top(), 0, slot);
			cmd_set_arg_number(cmd_get_top(), 1, o_ptr->number);*/
		}
	} else
	if (selected == 14) {
		/* squelch or unsquelch the item */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = 'k';
		do_cmd_destroy();
		/*textui_cmd_destroy_menu(slot);*/
	} else
	if (selected == 15) {
		/* fire some ammo */
		set_get_item_object(o_ptr);
 		p_ptr->cmd.cmd = 'f';
		repeat_check();
		do_cmd_fire();
	} else
	if (selected == -1) {
		/* this menu was canceled, tell whatever called us to display its menu again */
		return 3;
	}
	return 1;
}
示例#3
0
/* pick the context menu options appropiate for the item */
int context_menu_object(const object_type *o_ptr, const int slot)
{
	menu_type *m;
	region r;
	int selected;
	char *labels;
	char header[120];

	textblock *tb;
	region area = { 0, 0, 0, 0 };

	bool allowed = TRUE;
	int mode = OPT(rogue_like_commands) ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG;
	unsigned char cmdkey;

	m = menu_dynamic_new();
	if (!m || !o_ptr) {
		return 0;
	}
	object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_BASE);

	labels = string_make(lower_case);
	m->selections = labels;

	/* 'I' is used for inspect in both keymaps. */
	menu_dynamic_add_label(m, "Inspect", 'I', MENU_VALUE_INSPECT, labels);

	if (obj_can_browse(o_ptr)) {
		if (obj_can_cast_from(o_ptr) && player_can_cast(p_ptr, FALSE)) {
			ADD_LABEL("Cast", CMD_CAST, MN_ROW_VALID);
		}

		if (obj_can_study(o_ptr) && player_can_study(p_ptr, FALSE)) {
			cmd_code study_cmd = player_has(PF_CHOOSE_SPELLS) ? CMD_STUDY_SPELL : CMD_STUDY_BOOK;
			/* Hack - Use the STUDY_BOOK command key so that we get the correct command key. */
			cmdkey = cmd_lookup_key_unktrl(CMD_STUDY_BOOK, mode);
			menu_dynamic_add_label(m, "Study", cmdkey, study_cmd, labels);
		}

		if (player_can_read(p_ptr, FALSE)) {
			ADD_LABEL("Browse", CMD_BROWSE_SPELL, MN_ROW_VALID);
		}
	}
	else if (obj_is_useable(o_ptr)) {
		if (obj_is_wand(o_ptr)) {
			menu_row_validity_t valid = (obj_has_charges(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID;
			ADD_LABEL("Aim", CMD_USE_WAND, valid);
		}
		else if (obj_is_rod(o_ptr)) {
			menu_row_validity_t valid = (obj_can_zap(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID;
			ADD_LABEL("Zap", CMD_USE_ROD, valid);
		}
		else if (obj_is_staff(o_ptr)) {
			menu_row_validity_t valid = (obj_has_charges(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID;
			ADD_LABEL("Use", CMD_USE_STAFF, valid);
		}
		else if (obj_is_scroll(o_ptr)) {
			menu_row_validity_t valid = (player_can_read(p_ptr, FALSE)) ? MN_ROW_VALID : MN_ROW_INVALID;
			ADD_LABEL("Read", CMD_READ_SCROLL, valid);
		}
		else if (obj_is_potion(o_ptr)) {
			ADD_LABEL("Quaff", CMD_QUAFF, MN_ROW_VALID);
		}
		else if (obj_is_food(o_ptr)) {
			ADD_LABEL("Eat", CMD_EAT, MN_ROW_VALID);
		}
		else if (obj_is_activatable(o_ptr)) {
			menu_row_validity_t valid = (slot >= INVEN_WIELD && obj_can_activate(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID;
			ADD_LABEL("Activate", CMD_ACTIVATE, valid);
		}
		else if (obj_can_fire(o_ptr)) {
			ADD_LABEL("Fire", CMD_FIRE, MN_ROW_VALID);
		}
		else {
			ADD_LABEL("Use", CMD_USE_ANY, MN_ROW_VALID);
		}
	}

	if (obj_can_refill(o_ptr)) {
		ADD_LABEL("Refill", CMD_REFILL, MN_ROW_VALID);
	}

	if (slot >= INVEN_WIELD && obj_can_takeoff(o_ptr)) {
		ADD_LABEL("Take off", CMD_TAKEOFF, MN_ROW_VALID);
	}
	else if (slot < INVEN_WIELD && obj_can_wear(o_ptr)) {
		//if (obj_is_armor(o_ptr)) {
		//	menu_dynamic_add(m, "Wear", 2);
		//} else {
		// 	menu_dynamic_add(m, "Wield", 2);
		//}
		ADD_LABEL("Equip", CMD_WIELD, MN_ROW_VALID);
	}

	if (slot >= 0) {
		if (!store_in_store || cave_shopnum(cave, p_ptr->py, p_ptr->px) == STORE_HOME) {
			ADD_LABEL("Drop", CMD_DROP, MN_ROW_VALID);

			if (o_ptr->number > 1) {
				/* 'D' is used for squelch in rogue keymap, so we'll just swap letters. */
				cmdkey = (mode == KEYMAP_MODE_ORIG) ? 'D' : 'k';
				menu_dynamic_add_label(m, "Drop All", cmdkey, MENU_VALUE_DROP_ALL, labels);
			}
		}
	}
	else {
		menu_row_validity_t valid = (inven_carry_okay(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID;
		ADD_LABEL("Pick up", CMD_PICKUP, valid);
	}

	ADD_LABEL("Throw", CMD_THROW, MN_ROW_VALID);
	ADD_LABEL("Inscribe", CMD_INSCRIBE, MN_ROW_VALID);

	if (obj_has_inscrip(o_ptr)) {
		ADD_LABEL("Uninscribe", CMD_UNINSCRIBE, MN_ROW_VALID);
	}

	ADD_LABEL( (object_is_squelched(o_ptr) ? "Unignore" : "Ignore"), CMD_DESTROY, MN_ROW_VALID);

	/* work out display region */
	r.width = (int)menu_dynamic_longest_entry(m) + 3 + 2; /* +3 for tag, 2 for pad */
	r.col = Term->wid - r.width - 1;
	r.row = 1;
	r.page_rows = m->count;

	area.width = -(r.width + 2);

	/* Hack -- no flush needed */
	msg_flag = FALSE;
	screen_save();

	/* Display info */
	tb = object_info(o_ptr, OINFO_NONE);
	object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_FULL);

	textui_textblock_place(tb, area, format("%s", header));
	textblock_free(tb);

	menu_layout(m, &r);
	region_erase_bordered(&r);

	prt(format("(Enter to select, ESC) Command for %s:", header), 0, 0);
	selected = menu_dynamic_select(m);

	menu_dynamic_free(m);
	string_free(labels);

	screen_load();

	cmdkey = cmd_lookup_key(selected, mode);

	switch (selected) {
		case -1:
			/* User cancelled the menu. */
			return 3;

		case MENU_VALUE_INSPECT:
			/* copied from textui_obj_examine */
			/* Display info */
			tb = object_info(o_ptr, OINFO_NONE);
			object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_FULL);

			textui_textblock_show(tb, area, format("%s", header));
			textblock_free(tb);
			return 2;

		case MENU_VALUE_DROP_ALL:
			/* Drop entire stack with confirmation. */
			if (get_check(format("Drop %s? ", header))) {
				cmd_insert(store_in_store ? CMD_STASH : CMD_DROP);
				cmd_set_arg_item(cmd_get_top(), 0, slot);
				cmd_set_arg_number(cmd_get_top(), 1, o_ptr->number);
			}
			return 1;

		case CMD_STUDY_SPELL:
			/* Hack - Use the STUDY_BOOK command key so that get_item_allow() works properly. */
			cmdkey = cmd_lookup_key(CMD_STUDY_BOOK, mode);
			/* Fall through. */
		case CMD_BROWSE_SPELL:
		case CMD_STUDY_BOOK:
		case CMD_CAST:
		case CMD_DESTROY:
		case CMD_WIELD:
		case CMD_TAKEOFF:
		case CMD_INSCRIBE:
		case CMD_UNINSCRIBE:
		case CMD_PICKUP:
		case CMD_DROP:
		case CMD_REFILL:
		case CMD_THROW:
		case CMD_USE_WAND:
		case CMD_USE_ROD:
		case CMD_USE_STAFF:
		case CMD_READ_SCROLL:
		case CMD_QUAFF:
		case CMD_EAT:
		case CMD_ACTIVATE:
		case CMD_FIRE:
		case CMD_USE_ANY:
			/* Check for inscriptions that trigger confirmation. */
			allowed = key_confirm_command(cmdkey) && get_item_allow(slot, cmdkey, selected, FALSE);
			break;
		default:
			/* Invalid command; prevent anything from happening. */
			bell("Invalid context menu command.");
			allowed = FALSE;
			break;
	}

	if (!allowed)
		return 1;

	if (selected == CMD_DESTROY) {
		/* squelch or unsquelch the item */
		textui_cmd_destroy_menu(slot);
	}
	else if (selected == CMD_BROWSE_SPELL) {
		/* browse a spellbook */
		/* copied from textui_spell_browse */
		textui_book_browse(o_ptr);
		return 2;
	}
	else if (selected == CMD_STUDY_SPELL) {
		/* study a spell book */
		/* copied from textui_obj_study */
		int spell = get_spell(o_ptr, "study", spell_okay_to_study);

		if (spell >= 0) {
			cmd_insert(CMD_STUDY_SPELL);
			cmd_set_arg_choice(cmd_get_top(), 0, spell);
		}
	}
	else if (selected == CMD_CAST) {
		if (obj_can_browse(o_ptr)) {
			/* copied from textui_obj_cast */
			const char *verb = ((p_ptr->class->spell_book == TV_MAGIC_BOOK) ? "cast" : "recite");
			int spell = get_spell(o_ptr, verb, spell_okay_to_cast);

			if (spell >= 0) {
				cmd_insert(CMD_CAST);
				cmd_set_arg_choice(cmd_get_top(), 0, spell);
			}
		}
	}
	else {