/* テスト */
/*
 * File: squelch.c
 * Purpose: Item destruction
 *
 * Copyright (c) 2007 David T. Blackston, Iain McFall, DarkGod, Jeff Greene,
 * David Vestal, Pete Mack, Andrew Sidwell.
 *
 * This work is free software; you can redistribute it and/or modify it
 * under the terms of either:
 *
 * a) the GNU General Public License as published by the Free Software
 *    Foundation, version 2, or
 *
 * b) the "Angband licence":
 *    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.  Other copyrights may also apply.
 */
#include "angband.h"
#include "cmds.h"
#include "ui-menu.h"
#include "object/tvalsval.h"


/*
 * List of kinds of item, for pseudo-id squelch.
 */
enum
{
	TYPE_WEAPON,
	TYPE_SHOOTER,
	TYPE_MISSILE,
	TYPE_ARMOR,
	TYPE_JEWELRY,
	TYPE_DIGGER,

	TYPE_MAX
};

/*
 * Names of categories.
 */
static const _TCHAR *type_names[TYPE_MAX] =
{
	L"Melee weapons",
	L"Missile weapons",
	L"Ammunition",
	L"Armor",
	L"Jewelry",
	L"Diggers",
};

/* Mapping of tval -> type */
static int type_tvals[][2] =
{
	{ TYPE_WEAPON,	TV_SWORD },
	{ TYPE_WEAPON,	TV_POLEARM },
	{ TYPE_WEAPON,	TV_HAFTED },
	{ TYPE_SHOOTER,	TV_BOW },
	{ TYPE_MISSILE, TV_ARROW },
	{ TYPE_MISSILE,	TV_BOLT },
	{ TYPE_MISSILE,	TV_SHOT },
	{ TYPE_ARMOR,	TV_SHIELD },
	{ TYPE_ARMOR,	TV_HELM },
	{ TYPE_ARMOR,	TV_GLOVES },
	{ TYPE_ARMOR,	TV_BOOTS },
	{ TYPE_ARMOR,	TV_HARD_ARMOR },
	{ TYPE_ARMOR,	TV_SOFT_ARMOR },
	{ TYPE_ARMOR,	TV_CLOAK },
	{ TYPE_ARMOR,	TV_CROWN },
	{ TYPE_JEWELRY,	TV_RING },
	{ TYPE_JEWELRY,	TV_AMULET },
	{ TYPE_DIGGER,	TV_DIGGING },
};

byte squelch_level[TYPE_MAX];
size_t squelch_size = TYPE_MAX;


/*
 * The different kinds of quality squelch
 */
enum
{
	SQUELCH_NONE,
	SQUELCH_BAD,
	SQUELCH_AVERAGE,
	SQUELCH_GOOD,
	SQUELCH_EXCELLENT,
	SQUELCH_ALL,

	SQUELCH_MAX
};

/*
 * The names for the various kinds of quality
 */
static const _TCHAR *quality_names[SQUELCH_MAX] =
{
	L"none",                        /* SQUELCH_NONE */
	L"bad",                         /* SQUELCH_BAD */
	L"average",                     /* SQUELCH_AVERAGE */
	L"good",                        /* SQUELCH_GOOD */
	L"excellent",                   /* SQUELCH_EXCELLENT */
	L"everything except artifacts", /* SQUELCH_ALL */
};


/* Structure to describe tval/description pairings. */
typedef struct
{
	int tval;
	const _TCHAR *desc;
} tval_desc;

/* Categories for sval-dependent squelch. */
static tval_desc sval_dependent[] =
{
	{ TV_STAFF,			L"Staffs" },
	{ TV_WAND,			L"Wands" },
	{ TV_ROD,			L"Rods" },
	{ TV_SCROLL,		L"Scrolls" },
	{ TV_POTION,		L"Potions" },
	{ TV_RING,			L"Rings" },
	{ TV_AMULET,		L"Amulets" },
	{ TV_FOOD,			L"Food" },
	{ TV_MAGIC_BOOK,	L"Magic books" },
	{ TV_PRAYER_BOOK,	L"Prayer books" },
	{ TV_SPIKE,			L"Spikes" },
	{ TV_LITE,			L"Lights" },
	{ TV_FLASK,			L"Flasks of oil" },
	{ TV_DRAG_ARMOR,	L"Dragon Mail Armor" },
};


/*** Autoinscription stuff ***/

/*
 * This code needs documenting.
 */
int get_autoinscription_index(s16b k_idx)
{
	int i;

	for (i = 0; i < inscriptions_count; i++)
	{
		if (k_idx == inscriptions[i].kind_idx)
			return i;
	}

	return -1;
}

/*
 * DOCUMENT ME!
 */
const _TCHAR *get_autoinscription(s16b kind_idx)
{
	int i;

	for (i = 0; i < inscriptions_count; i++)
	{
		if (kind_idx == inscriptions[i].kind_idx)
			return quark_str(inscriptions[i].inscription_idx);
	}

	return 0;
}

/* Put the autoinscription on an object */
int apply_autoinscription(object_type *o_ptr)
{
	_TCHAR o_name[80];
	const _TCHAR *note = get_autoinscription(o_ptr->k_idx);
	const _TCHAR *existing_inscription = quark_str(o_ptr->note);

	/* Don't inscribe unaware objects */
	if (!note || !object_aware_p(o_ptr))
		return 0;

	/* Don't re-inscribe if it's already inscribed */
	if (existing_inscription)
		return 0;

	/* Get an object description */
	object_desc(o_name, _countof(o_name), o_ptr, TRUE, ODESC_FULL);

	if (note[0] != 0)
		o_ptr->note = quark_add(note);
	else
		o_ptr->note = 0;

	msg_format(L"You autoinscribe %s.", o_name);

	return 1;
}

bool remove_autoinscription(s16b kind)
{
	int i = get_autoinscription_index(kind);

	/* It's not here. */
	if (i == -1) return 0;

	while (i < inscriptions_count - 1)
	{
		inscriptions[i] = inscriptions[i+1];
		i++;
	}

	inscriptions_count--;

	return 1;
}


int add_autoinscription(s16b kind, const _TCHAR *inscription)
{
	int index;

	/* Paranoia */
	if (kind == 0) return 0;

	/* If there's no inscription, remove it */
	if (!inscription || (inscription[0] == 0))
		return remove_autoinscription(kind);

	index = get_autoinscription_index(kind);

	if (index == -1)
		index = inscriptions_count;

	if (index >= AUTOINSCRIPTIONS_MAX)
	{
		msg_format(L"This inscription (%s) cannot be added because the inscription array is full!", inscription);
		return 0;
	}

	inscriptions[index].kind_idx = kind;
	inscriptions[index].inscription_idx = quark_add(inscription);

	/* Only increment count if inscription added to end of array */
	if (index == inscriptions_count)
		inscriptions_count++;

	return 1;
}


void autoinscribe_ground(void)
{
	int py = p_ptr->py;
	int px = p_ptr->px;
	s16b this_o_idx, next_o_idx = 0;

	/* Scan the pile of objects */
	for (this_o_idx = cave_o_idx[py][px]; this_o_idx; this_o_idx = next_o_idx)
	{
		/* Get the next object */
		next_o_idx = o_list[this_o_idx].next_o_idx;

		/* Apply an autoinscription */
		apply_autoinscription(&o_list[this_o_idx]);
	}
}

void autoinscribe_pack(void)
{
	int i;

	/* Cycle through the inventory */
	for (i = INVEN_PACK; i >= 0; i--)
	{
		/* Skip empty items */
		if (!inventory[i].k_idx) continue;

		/* Apply the inscription */
		apply_autoinscription(&inventory[i]);
	}

	return;
}




/*** Squelch code ***/

/*
 * Determines whether a tval is eligable for sval-squelch.
 */
bool squelch_tval(int tval)
{
	size_t i;

	/* Only squelch if the tval's allowed */
	for (i = 0; i < N_ELEMENTS(sval_dependent); i++)
	{
		if (tval == sval_dependent[i].tval)
			return TRUE;
	}

	return FALSE;
}


/*
 * Determines if an object is eligable for squelching.
 */
bool squelch_item_ok(const object_type *o_ptr)
{
	size_t i;
	int type = -1;

	object_kind *k_ptr = &k_info[o_ptr->k_idx];
	bool fullid = object_known_p(o_ptr);
	bool sensed = (o_ptr->ident & IDENT_SENSE) || fullid;
	byte feel   = object_pseudo(o_ptr);


	/* Don't squelch artifacts */
	if (artifact_p(o_ptr)) return FALSE;

	/* Don't squelch stuff inscribed not to be destroyed (!k) */
	if (check_for_inscrip(o_ptr, L"!k") || check_for_inscrip(o_ptr, L"!*"))
	{
		return FALSE;
	}

	/* Auto-squelch dead chests */
	if (o_ptr->tval == TV_CHEST && o_ptr->pval == 0)
		return TRUE;

	/* Do squelching by sval, if we 'know' the flavour. */
	if (k_ptr->squelch && (k_ptr->flavor == 0 || k_ptr->aware))
	{
		if (squelch_tval(k_info[o_ptr->k_idx].tval))
			return TRUE;
	}


	/* Don't check pseudo-ID for nonsensed things */
	if (!sensed) return FALSE;



	/* Find the appropriate squelch group */
	for (i = 0; i < N_ELEMENTS(type_tvals) && (type == -1); i++)
	{
		if (type_tvals[i][1] == o_ptr->tval)
			type = type_tvals[i][0];
	}

	/* Never squelched */
	if (type == -1)
		return FALSE;


	/* Never autosquelch arts */
	if (feel == INSCRIP_SPECIAL)
		return FALSE;


	/* Get result based on the feeling and the squelch_level */
	switch (squelch_level[type])
	{
		case SQUELCH_BAD:
		{
			/* Deal with jewelry specially */
			if (type == TYPE_JEWELRY)
			{
				if (fullid && o_ptr->pval < 0)
					return TRUE;
				else
					return FALSE;
			}

			if (feel == INSCRIP_AVERAGE ||
					feel == INSCRIP_EXCELLENT)
				return FALSE;

			if ((fullid || o_ptr->ident & IDENT_ATTACK) &&
					o_ptr->to_h < 0 && o_ptr->to_d < 0)
				return TRUE;

			if ((fullid || o_ptr->ident & IDENT_DEFENCE) &&
					o_ptr->to_a < 0)
				return TRUE;

			break;
		}

		case SQUELCH_AVERAGE:
		{
			if (feel == INSCRIP_EXCELLENT)
				return FALSE;

			if (feel == INSCRIP_AVERAGE)
				return TRUE;

			if ((fullid || o_ptr->ident & IDENT_ATTACK) &&
					o_ptr->to_h <= 0 && o_ptr->to_d <= 0)
				return TRUE;

			if ((fullid || o_ptr->ident & IDENT_DEFENCE) &&
					o_ptr->to_a <= 0)
				return TRUE;

			break;
		}

		case SQUELCH_GOOD:
		{
			if (feel == INSCRIP_EXCELLENT)
				return FALSE;

			if (feel == INSCRIP_AVERAGE ||
					feel == INSCRIP_MAGICAL)
				return TRUE;

			break;
		}

		case SQUELCH_EXCELLENT:
		case SQUELCH_ALL:
		{
			return TRUE;
		}
	}

	/* Default to not squelching */
	return FALSE;
}


/*
 * Returns TRUE if an item should be hidden due to the player's
 * current settings.
 */
bool squelch_hide_item(object_type *o_ptr)
{
	return (OPT(hide_squelchable) ? squelch_item_ok(o_ptr) : FALSE);
}


/*
 * Destroy all {squelch}able items.
 *
 * Imported, with thanks, from Ey... much cleaner than the original.
 */
void squelch_items(void)
{
	int floor_list[MAX_FLOOR_STACK];
	int floor_num, n;
	int count = 0;

	object_type *o_ptr;

	/* Set the hook and scan the floor */
	item_tester_hook = squelch_item_ok;
	floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), p_ptr->py, p_ptr->px, 0x01);

	if (floor_num)
	{
		for (n = 0; n < floor_num; n++)
		{
			o_ptr = &o_list[floor_list[n]];

			/* Avoid artifacts */
			if (artifact_p(o_ptr)) continue;

			if (item_tester_okay(o_ptr))
			{
				/* Destroy item */
				floor_item_increase(floor_list[n], -o_ptr->number);
				floor_item_optimize(floor_list[n]);
				count++;
			}
		}
	}

	/* Scan through the slots backwards */
	for (n = INVEN_PACK - 1; n >= 0; n--)
	{
		o_ptr = &inventory[n];

		/* Skip non-objects and artifacts */
		if (!o_ptr->k_idx) continue;
		if (artifact_p(o_ptr)) continue;

		if (item_tester_okay(o_ptr))
		{
			/* Destroy item */
			inven_item_increase(n, -o_ptr->number);
			inven_item_optimize(n);
			count++;
		}
	}

	item_tester_hook = NULL;

	/* Mention casualties */
	if (count > 0)
	{
		message_format(MSG_DESTROY, 0, L"%d item%s squelched.",
		               count, ((count > 1) ? L"s" : __T("")));

		/* Combine/reorder the pack */
		p_ptr->notice |= (PN_COMBINE | PN_REORDER);
	}
}


/*
 * Drop all {squelch}able items.
 */
void squelch_drop(void)
{
	int n;

	/* Scan through the slots backwards */
	for (n = INVEN_PACK - 1; n >= 0; n--)
	{
		object_type *o_ptr = &inventory[n];

		/* Skip non-objects and unsquelchable objects */
		if (!o_ptr->k_idx) continue;
		if (!squelch_item_ok(o_ptr)) continue;

		/* Check for !d (no drop) inscription */
		if (!check_for_inscrip(o_ptr, L"!d") && !check_for_inscrip(o_ptr, L"!*"))
		{
			/* We're allowed to drop it. */
			inven_drop(n, o_ptr->number);
		}
	}

	/* Combine/reorder the pack */
	p_ptr->notice |= (PN_COMBINE | PN_REORDER);
}



/*** Quality-squelch menu ***/

/*
 * Display an entry in the menu.
 */
static void quality_display(menu_type *menu, int oid, bool cursor, int row, int col, int width)
{
	const _TCHAR *name = type_names[oid];

	byte level = squelch_level[oid];
	const _TCHAR *level_name = quality_names[level];

	byte attr = (cursor ? TERM_L_BLUE : TERM_WHITE);
	UNREFERENCED_PARAMETER(width);
	UNREFERENCED_PARAMETER(menu);

	c_put_str(attr, format(L"%-20s : %s", name, level_name), row, col);
}


/*
 * Display the quality squelch subtypes.
 */
static void quality_subdisplay(menu_type *menu, int oid, bool cursor, int row, int col, int width)
{
	const _TCHAR *name = quality_names[oid];
	byte attr = (cursor ? TERM_L_BLUE : TERM_WHITE);
	UNREFERENCED_PARAMETER(width);
	UNREFERENCED_PARAMETER(menu);

	c_put_str(attr, name, row, col);
}

/*
 * Handle "Enter".  :(
 */
static bool quality_subaction(_TCHAR cmd, void *db, int oid)
{
	UNREFERENCED_PARAMETER(cmd);
	UNREFERENCED_PARAMETER(db);
	UNREFERENCED_PARAMETER(oid);

	return TRUE;
}


/*
 * Handle keypresses.
 */
static bool quality_action(_TCHAR cmd, void *db, int oid)
{
	menu_type menu;
	menu_iter menu_f = { NULL, NULL, quality_subdisplay, quality_subaction };
	region area = { 24, 5, 26, SQUELCH_MAX };
	ui_event_data evt;
	int cursor;
	UNREFERENCED_PARAMETER(db);
	UNREFERENCED_PARAMETER(cmd);

	/* Display at the right point */
	area.row += oid;
	cursor = squelch_level[oid];

	/* Save */
	screen_save();

	/* Run menu */
	WIPE(&menu, menu);
	menu.cmd_keys = L"\n\r";
	menu.count = SQUELCH_MAX;
	if (oid == TYPE_JEWELRY)
		menu.count = area.page_rows = SQUELCH_BAD + 1;

	menu_init(&menu, MN_SKIN_SCROLL, &menu_f, &area);
	window_make(area.col - 2, area.row - 1, area.col + area.width + 2, area.row + area.page_rows);

	evt = menu_select(&menu, &cursor, 0);

	/* Set the new value appropriately */
	if (evt.key != ESCAPE && evt.type != EVT_BACK)
		squelch_level[oid] = cursor;

	/* Load and finish */
	screen_load();
	return TRUE;
}

/*
 * Display quality squelch menu.
 */
static void quality_menu(void *unused, const _TCHAR *also_unused)
{
	menu_type menu;
	menu_iter menu_f = { NULL, NULL, quality_display, quality_action };
	region area = { 1, 5, -1, -1 };
	ui_event_data evt = EVENT_EMPTY;
	int cursor = 0;
	UNREFERENCED_PARAMETER(unused);
	UNREFERENCED_PARAMETER(also_unused);

	/* Save screen */
	screen_save();
	clear_from(0);

	/* Help text */
	prt(L"Quality squelch menu", 0, 0);

	Term_gotoxy(1, 1);
	text_out_to_screen(TERM_L_RED, L"Use the movement keys to navigate, and Enter to change settings.");

	/* Set up the menu */
	WIPE(&menu, menu);
	menu.cmd_keys = L" \n\r";
	menu.count = TYPE_MAX;
	menu_init(&menu, MN_SKIN_SCROLL, &menu_f, &area);

	/* Select an entry */
	while (evt.key != ESCAPE)
		evt = menu_select(&menu, &cursor, 0);

	/* Load screen */
	screen_load();
	return;
}



/*** Sval-dependent menu ***/

/*
 * Display an entry on the sval menu
 */
static void sval_display(menu_type *menu, int oid, bool cursor, int row, int col, int width)
{
	_TCHAR buf[80];
	const u16b *choice = (const u16b *)menu->menu_data;
	int idx = choice[oid];

	byte attr = (cursor ? TERM_L_BLUE : TERM_WHITE);
	UNREFERENCED_PARAMETER(width);


	/* Acquire the "name" of object "i" */
	object_kind_name(buf, _countof(buf), idx, TRUE);

	/* Print it */
	c_put_str(attr, format(L"[ ] %s", buf), row, col);
	if (k_info[idx].squelch)
		c_put_str(TERM_L_RED, L"*", row, col + 1);
}

/*
 * Deal with events on the sval menu
 */
static bool sval_action(_TCHAR cmd, void *db, int oid)
{
	u16b *choice = (u16b *)db;

	/* Toggle */
	if (cmd == '\n' || cmd == '\r')
	{
		int idx = choice[oid];
		k_info[idx].squelch = !k_info[idx].squelch;

		return TRUE;
	}

	return FALSE;
}


/*
 * Display list of svals to be squelched.
 */
static bool sval_menu(int tval, const _TCHAR *desc)
{
	menu_type menu;
	menu_iter menu_f = { NULL, NULL, sval_display, sval_action };
	region area = { 1, 5, -1, -1 };
	ui_event_data evt = { EVT_NONE, 0, 0, 0, 0 };
	int cursor = 0;

	int num = 0;
	size_t i;

	u16b *choice;
	UNREFERENCED_PARAMETER(desc);


	/* Create the array */
	choice = C_ZNEW(z_info->k_max, u16b);

	/* Iterate over all possible object kinds, finding ones which can be squelched */
	for (i = 1; i < z_info->k_max; i++)
	{
		object_kind *k_ptr = &k_info[i];

		/* Skip empty objects, unseen objects, and incorrect tvals */
		if (!k_ptr->name) continue;
		if (!k_ptr->everseen) continue;
		if (k_ptr->tval != tval) continue;

		/* Add this item to our possibles list */
		choice[num++] = i;
	}

	/* Return here if there are no objects */
	if (!num)
	{
		FREE(choice);
		return FALSE;
	}


	/* Save the screen and clear it */
	screen_save();
	clear_from(0);

	/* Help text */

	/* Output to the screen */
	text_out_hook = text_out_to_screen;

	/* Indent output */
	text_out_indent = 1;
	text_out_wrap = 79;
	Term_gotoxy(1, 0);

	/* Display some helpful information */
	text_out(L"Use the ");
	text_out_c(TERM_L_GREEN, L"movement keys");
	text_out(L" to scroll the list or ");
	text_out_c(TERM_L_GREEN, L"ESC");
	text_out(L" to return to the previous menu.  ");
	text_out_c(TERM_L_BLUE, L"Enter");
	text_out(L" toggles the current setting.");

	text_out_indent = 0;

	/* Set up the menu */
	WIPE(&menu, menu);
	menu.cmd_keys = L" \n\r";
	menu.count = num;
	menu.menu_data = choice;
	menu_init(&menu, MN_SKIN_SCROLL, &menu_f, &area);

	/* Select an entry */
	while (evt.key != ESCAPE)
		evt = menu_select(&menu, &cursor, 0);

	/* Free memory */
	FREE(choice);

	/* Load screen */
	screen_load();
	return TRUE;
}


/* Returns TRUE if there's anything to display a menu of */
static bool seen_tval(int tval)
{
	int i;

	for (i = 1; i < z_info->k_max; i++)
	{
		object_kind *k_ptr = &k_info[i];

		/* Skip empty objects, unseen objects, and incorrect tvals */
		if (!k_ptr->name) continue;
		if (!k_ptr->everseen) continue;
		if (k_ptr->tval != tval) continue;

		 return TRUE;
	}


	return FALSE;
}


/* Extra options on the "item options" menu */
struct
{
	_TCHAR tag;
	const _TCHAR *name;
	void (*action)(void *unused, const _TCHAR *also_unused);
} extra_item_options[] =
{
	{ 'Q', L"Quality squelching options", quality_menu },
	{ '{', L"Autoinscription setup", do_cmd_knowledge_objects },
};

static _TCHAR tag_options_item(menu_type *menu, int oid)
{
	size_t line = (size_t) oid;
	UNREFERENCED_PARAMETER(menu);

	if (line < N_ELEMENTS(sval_dependent))
		return I2A(oid);

	/* Separator - blank line. */
	if (line == N_ELEMENTS(sval_dependent))
		return 0;

	line = line - N_ELEMENTS(sval_dependent) - 1;

	if (line < N_ELEMENTS(extra_item_options))
		return extra_item_options[line].tag;

	return 0;
}

static int valid_options_item(menu_type *menu, int oid)
{
	size_t line = (size_t) oid;
	UNREFERENCED_PARAMETER(menu);

	if (line < N_ELEMENTS(sval_dependent))
		return 1;

	/* Separator - blank line. */
	if (line == N_ELEMENTS(sval_dependent))
		return 0;

	line = line - N_ELEMENTS(sval_dependent) - 1;

	if (line < N_ELEMENTS(extra_item_options))
		return 1;

	return 0;
}

static void display_options_item(menu_type *menu, int oid, bool cursor, int row, int col, int width)
{
	size_t line = (size_t) oid;
	UNREFERENCED_PARAMETER(width);
	UNREFERENCED_PARAMETER(menu);

	/* First section of menu - the svals */
	if (line < N_ELEMENTS(sval_dependent))
	{
		bool known = seen_tval(sval_dependent[line].tval);
		byte attr = curs_attrs[known ? CURS_KNOWN: CURS_UNKNOWN][(int)cursor];

		c_prt(attr, sval_dependent[line].desc, row, col);
	}
	/* Second section - the "extra options" */
	else
	{
		byte attr = curs_attrs[CURS_KNOWN][(int)cursor];

		line = line - N_ELEMENTS(sval_dependent) - 1;

		if (line < N_ELEMENTS(extra_item_options))
			c_prt(attr, extra_item_options[line].name, row, col);
	}
}


static const menu_iter options_item_iter =
{
	tag_options_item,
	valid_options_item,
	display_options_item,
	NULL
};


/*
 * Display and handle the main squelching menu.
 */
void do_cmd_options_item(void *unused, const _TCHAR *title)
{
	int cursor = 0;
	ui_event_data c = EVENT_EMPTY;
	const _TCHAR cmd_keys[] = { ARROW_LEFT, ARROW_RIGHT, 0 };

	menu_type menu;
	UNREFERENCED_PARAMETER(unused);

	WIPE(&menu, menu_type);
	menu.title = title;
        menu.cmd_keys = cmd_keys;
	menu.count = N_ELEMENTS(sval_dependent) + N_ELEMENTS(extra_item_options) + 1;
	menu_init(&menu, MN_SKIN_SCROLL, &options_item_iter, &SCREEN_REGION);

	/* Save and clear screen */
	screen_save();
	clear_from(0);

	while (c.key != ESCAPE)
	{
		clear_from(0);
		c = menu_select(&menu, &cursor, 0);

		if (c.type == EVT_SELECT)
		{
			if ((size_t) cursor < N_ELEMENTS(sval_dependent))
			{
				sval_menu(sval_dependent[cursor].tval, sval_dependent[cursor].desc);
			}
			else
			{
				cursor = cursor - N_ELEMENTS(sval_dependent) - 1;
				if ((size_t) cursor < N_ELEMENTS(extra_item_options))
					extra_item_options[cursor].action(NULL, NULL);
			}
		}
	}

	/* Load screen and finish */
	screen_load();
	p_ptr->notice |= PN_SQUELCH;

	return;
}
