summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/invent.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/invent.cc')
-rw-r--r--crawl-ref/source/invent.cc1027
1 files changed, 1027 insertions, 0 deletions
diff --git a/crawl-ref/source/invent.cc b/crawl-ref/source/invent.cc
new file mode 100644
index 0000000000..2145f80f72
--- /dev/null
+++ b/crawl-ref/source/invent.cc
@@ -0,0 +1,1027 @@
+/*
+ * File: invent.cc
+ * Summary: Functions for inventory related commands.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <5> 10/9/99 BCR Added wizard help screen
+ * <4> 10/1/99 BCR Clarified help screen
+ * <3> 6/9/99 DML Autopickup
+ * <2> 5/20/99 BWR Extended screen lines support
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "invent.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "clua.h"
+#include "itemname.h"
+#include "items.h"
+#include "macro.h"
+#include "player.h"
+#include "shopping.h"
+#include "stuff.h"
+#include "view.h"
+#include "menu.h"
+
+const char *command_string( int i );
+const char *wizard_string( int i );
+
+struct InvTitle : public MenuEntry
+{
+ Menu *m;
+ std::string (*titlefn)( int menuflags, const std::string &oldt );
+
+ InvTitle( Menu *mn, const char *title,
+ std::string (*tfn)( int menuflags, const std::string &oldt ) )
+ : MenuEntry( title )
+ {
+ m = mn;
+ titlefn = tfn;
+ }
+
+ std::string get_text() const
+ {
+ return titlefn? titlefn( m->get_flags(), MenuEntry::get_text() ) :
+ MenuEntry::get_text();
+ }
+};
+
+class InvShowPrices;
+class InvEntry : public MenuEntry
+{
+private:
+ static bool show_prices;
+ static char temp_id[4][50];
+ static void set_show_prices(bool doshow);
+
+ friend class InvShowPrices;
+public:
+ const item_def *item;
+
+ InvEntry( const item_def &i ) : MenuEntry( "", MEL_ITEM ), item( &i )
+ {
+ data = const_cast<item_def *>( item );
+
+ char buf[ITEMNAME_SIZE];
+ if (i.base_type == OBJ_GOLD)
+ snprintf(buf, sizeof buf, "%d gold piece%s", i.quantity,
+ (i.quantity > 1? "s" : ""));
+ else
+ item_name(i,
+ in_inventory(i)?
+ DESC_INVENTORY_EQUIP : DESC_NOCAP_A, buf, false);
+ text = buf;
+
+ if (i.base_type != OBJ_GOLD)
+ {
+ if (in_inventory(i))
+ {
+ text = text.substr( 4 ); // Skip the inventory letter.
+ add_hotkey(index_to_letter( i.link ));
+ }
+ else
+ add_hotkey(' '); // Dummy hotkey
+ }
+ else
+ {
+ // Dummy hotkey for gold.
+ add_hotkey(' ');
+ }
+ add_class_hotkeys(i);
+
+ quantity = i.quantity;
+ }
+
+ std::string get_text() const
+ {
+ char buf[ITEMNAME_SIZE];
+ char suffix[ITEMNAME_SIZE] = "";
+
+ if (InvEntry::show_prices)
+ {
+ int value = item_value(*item, temp_id, true);
+ if (value > 0)
+ snprintf(suffix, sizeof suffix,
+ " (%d gold)", value);
+ }
+ snprintf( buf, sizeof buf,
+ "%c %c %s%s",
+ hotkeys[0],
+ (!selected_qty? '-' : selected_qty < quantity? '#' : '+'),
+ text.c_str(),
+ suffix );
+ return (buf);
+ }
+private:
+ void add_class_hotkeys(const item_def &i)
+ {
+ switch (i.base_type)
+ {
+ case OBJ_GOLD:
+ add_hotkey('$');
+ break;
+ case OBJ_MISSILES:
+ add_hotkey('(');
+ break;
+ case OBJ_WEAPONS:
+ add_hotkey(')');
+ break;
+ case OBJ_ARMOUR:
+ add_hotkey('[');
+ break;
+ case OBJ_WANDS:
+ add_hotkey('/');
+ break;
+ case OBJ_FOOD:
+ add_hotkey('%');
+ break;
+ case OBJ_BOOKS:
+ add_hotkey('+');
+ add_hotkey(':');
+ break;
+ case OBJ_SCROLLS:
+ add_hotkey('?');
+ break;
+ case OBJ_JEWELLERY:
+ add_hotkey(i.sub_type >= AMU_RAGE? '"' : '=');
+ break;
+ case OBJ_POTIONS:
+ add_hotkey('!');
+ break;
+ case OBJ_STAVES:
+ add_hotkey('\\');
+ add_hotkey('|');
+ break;
+ case OBJ_MISCELLANY:
+ add_hotkey('}');
+ break;
+ case OBJ_CORPSES:
+ add_hotkey('&');
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+bool InvEntry::show_prices = false;
+char InvEntry::temp_id[4][50];
+
+void InvEntry::set_show_prices(bool doshow)
+{
+ if ((show_prices = doshow))
+ {
+ memset(temp_id, 1, sizeof temp_id);
+ }
+}
+
+class InvShowPrices {
+public:
+ InvShowPrices(bool doshow = true)
+ {
+ InvEntry::set_show_prices(doshow);
+ }
+ ~InvShowPrices()
+ {
+ InvEntry::set_show_prices(false);
+ }
+};
+
+class InvMenu : public Menu
+{
+public:
+ InvMenu(int flags = MF_MULTISELECT) : Menu(flags) { }
+protected:
+ bool process_key(int key);
+};
+
+bool InvMenu::process_key( int key )
+{
+ if (items.size() && (key == CONTROL('D') || key == '@'))
+ {
+ int newflag =
+ is_set(MF_MULTISELECT)?
+ MF_SINGLESELECT | MF_EASY_EXIT | MF_ANYPRINTABLE
+ : MF_MULTISELECT;
+
+ flags &= ~(MF_SINGLESELECT | MF_MULTISELECT |
+ MF_EASY_EXIT | MF_ANYPRINTABLE);
+ flags |= newflag;
+
+ deselect_all();
+ sel->clear();
+ draw_select_count(0);
+ return true;
+ }
+ return Menu::process_key( key );
+}
+
+bool in_inventory( const item_def &i )
+{
+ return i.x == -1 && i.y == -1;
+}
+
+unsigned char get_invent( int invent_type )
+{
+ unsigned char nothing = invent_select( invent_type );
+
+ redraw_screen();
+
+ return (nothing);
+} // end get_invent()
+
+std::string item_class_name( int type, bool terse )
+{
+ if (terse)
+ {
+ switch (type)
+ {
+ case OBJ_GOLD: return ("gold");
+ case OBJ_WEAPONS: return ("weapon");
+ case OBJ_MISSILES: return ("missile");
+ case OBJ_ARMOUR: return ("armour");
+ case OBJ_WANDS: return ("wand");
+ case OBJ_FOOD: return ("food");
+ case OBJ_UNKNOWN_I: return ("book");
+ case OBJ_SCROLLS: return ("scroll");
+ case OBJ_JEWELLERY: return ("jewelry");
+ case OBJ_POTIONS: return ("potion");
+ case OBJ_UNKNOWN_II: return ("gem");
+ case OBJ_BOOKS: return ("book");
+ case OBJ_STAVES: return ("stave");
+ case OBJ_ORBS: return ("orb");
+ case OBJ_MISCELLANY: return ("misc");
+ case OBJ_CORPSES: return ("carrion");
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case OBJ_GOLD: return ("Gold");
+ case OBJ_WEAPONS: return ("Hand Weapons");
+ case OBJ_MISSILES: return ("Missiles");
+ case OBJ_ARMOUR: return ("Armour");
+ case OBJ_WANDS: return ("Magical Devices");
+ case OBJ_FOOD: return ("Comestibles");
+ case OBJ_UNKNOWN_I: return ("Books");
+ case OBJ_SCROLLS: return ("Scrolls");
+ case OBJ_JEWELLERY: return ("Jewellery");
+ case OBJ_POTIONS: return ("Potions");
+ case OBJ_UNKNOWN_II: return ("Gems");
+ case OBJ_BOOKS: return ("Books");
+ case OBJ_STAVES: return ("Magical Staves and Rods");
+ case OBJ_ORBS: return ("Orbs of Power");
+ case OBJ_MISCELLANY: return ("Miscellaneous");
+ case OBJ_CORPSES: return ("Carrion");
+ }
+ }
+ return ("");
+}
+
+void populate_item_menu( Menu *menu, const std::vector<item_def> &items,
+ void (*callback)(MenuEntry *me) )
+{
+ FixedVector< int, NUM_OBJECT_CLASSES > inv_class;
+ for (int i = 0; i < NUM_OBJECT_CLASSES; ++i)
+ inv_class[i] = 0;
+ for (int i = 0, count = items.size(); i < count; ++i)
+ inv_class[ items[i].base_type ]++;
+
+ menu_letter ckey;
+ for (int i = 0; i < NUM_OBJECT_CLASSES; ++i)
+ {
+ if (!inv_class[i]) continue;
+
+ menu->add_entry( new MenuEntry( item_class_name(i), MEL_SUBTITLE ) );
+
+ for (int j = 0, count = items.size(); j < count; ++j)
+ {
+ if (items[j].base_type != i) continue;
+
+ InvEntry *ie = new InvEntry( items[j] );
+ ie->hotkeys[0] = ckey++;
+ callback(ie);
+
+ menu->add_entry( ie );
+ }
+ }
+}
+
+std::vector<SelItem> select_items( std::vector<item_def*> &items,
+ const char *title )
+{
+ std::vector<SelItem> selected;
+
+ if (items.empty())
+ return selected;
+
+ FixedVector< int, NUM_OBJECT_CLASSES > inv_class;
+ for (int i = 0; i < NUM_OBJECT_CLASSES; ++i)
+ inv_class[i] = 0;
+ for (int i = 0, count = items.size(); i < count; ++i)
+ inv_class[ items[i]->base_type ]++;
+
+ Menu menu;
+ menu.set_title( new MenuEntry(title) );
+
+ char ckey = 'a';
+ for (int i = 0; i < NUM_OBJECT_CLASSES; ++i)
+ {
+ if (!inv_class[i]) continue;
+
+ menu.add_entry( new MenuEntry( item_class_name(i), MEL_SUBTITLE ) );
+
+ for (int j = 0, count = items.size(); j < count; ++j)
+ {
+ if (items[j]->base_type != i) continue;
+
+ InvEntry *ie = new InvEntry( *items[j] );
+ ie->hotkeys[0] = ckey;
+
+ menu.add_entry( ie );
+
+ ckey = ckey == 'z'? 'A' :
+ ckey == 'Z'? 'a' :
+ ckey + 1;
+ }
+ }
+ menu.set_flags( MF_MULTISELECT | MF_SELECT_ANY_PAGE );
+ std::vector< MenuEntry * > sel = menu.show();
+ for (int i = 0, count = sel.size(); i < count; ++i)
+ {
+ InvEntry *inv = (InvEntry *) sel[i];
+ selected.push_back( SelItem( inv->hotkeys[0],
+ inv->selected_qty,
+ inv->item ) );
+ }
+
+ return selected;
+}
+
+static bool item_class_selected(const item_def &i, int selector)
+{
+ const int itype = i.base_type;
+ if (selector == OSEL_ANY || selector == itype)
+ return (true);
+
+ switch (selector)
+ {
+ case OBJ_MISSILES:
+ return (itype == OBJ_MISSILES || itype == OBJ_WEAPONS);
+ case OBJ_WEAPONS:
+ case OSEL_WIELD:
+ return (itype == OBJ_WEAPONS || itype == OBJ_STAVES
+ || itype == OBJ_MISCELLANY);
+ case OBJ_SCROLLS:
+ return (itype == OBJ_SCROLLS || itype == OBJ_BOOKS);
+ default:
+ return (false);
+ }
+}
+
+static bool userdef_item_selected(const item_def &i, int selector)
+{
+#if defined(CLUA_BINDINGS)
+ const char *luafn = selector == OSEL_WIELD? "ch_item_wieldable" :
+ NULL;
+ return (luafn && clua.callbooleanfn(false, luafn, "u", &i));
+#else
+ return (false);
+#endif
+}
+
+static bool is_item_selected(const item_def &i, int selector)
+{
+ return item_class_selected(i, selector)
+ || userdef_item_selected(i, selector);
+}
+
+static void get_inv_items_to_show(std::vector<item_def*> &v, int selector)
+{
+ for (int i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item(you.inv[i]) && is_item_selected(you.inv[i], selector))
+ v.push_back( &you.inv[i] );
+ }
+}
+
+static void set_vectitem_classes(const std::vector<item_def*> &v,
+ FixedVector<int, NUM_OBJECT_CLASSES> &fv)
+{
+ for (int i = 0; i < NUM_OBJECT_CLASSES; i++)
+ fv[i] = 0;
+
+ for (int i = 0, size = v.size(); i < size; i++)
+ fv[ v[i]->base_type ]++;
+}
+
+unsigned char invent_select(
+ int item_selector,
+ int flags,
+ std::string (*titlefn)( int menuflags,
+ const std::string &oldt ),
+ std::vector<SelItem> *items,
+ std::vector<text_pattern> *filter,
+ Menu::selitem_tfn selitemfn )
+{
+ InvMenu menu;
+
+ menu.selitem_text = selitemfn;
+ if (filter)
+ menu.set_select_filter( *filter );
+
+ FixedVector< int, NUM_OBJECT_CLASSES > inv_class2;
+ for (int i = 0; i < NUM_OBJECT_CLASSES; i++)
+ inv_class2[i] = 0;
+
+ int inv_count = 0;
+
+ for (int i = 0; i < ENDOFPACK; i++)
+ {
+ if (you.inv[i].quantity)
+ {
+ inv_class2[ you.inv[i].base_type ]++;
+ inv_count++;
+ }
+ }
+
+ if (!inv_count)
+ {
+ menu.set_title( new MenuEntry( "You aren't carrying anything." ) );
+ menu.show();
+ return 0;
+ }
+
+ std::vector<item_def*> tobeshown;
+ get_inv_items_to_show( tobeshown, item_selector );
+ set_vectitem_classes( tobeshown, inv_class2 );
+
+ if (tobeshown.size())
+ {
+ const int cap = carrying_capacity();
+
+ char title_buf[200];
+ snprintf( title_buf, sizeof title_buf,
+ "Inventory: %d.%d/%d.%d aum (%d%%, %d/52 slots)",
+ you.burden / 10, you.burden % 10,
+ cap / 10, cap % 10,
+ (you.burden * 100) / cap,
+ inv_count );
+ menu.set_title( new InvTitle( &menu, title_buf, titlefn ) );
+
+ for (int i = 0; i < 15; i++)
+ {
+ if (inv_class2[i] != 0)
+ {
+ std::string s = item_class_name(i);
+ menu.add_entry( new MenuEntry( s, MEL_SUBTITLE ) );
+
+ for (int j = 0, size = tobeshown.size(); j < size; ++j)
+ {
+ if (tobeshown[j]->base_type == i)
+ {
+ menu.add_entry( new InvEntry( *tobeshown[j] ) );
+ }
+ } // end of j loop
+ } // end of if inv_class2
+ } // end of i loop.
+ }
+ else
+ {
+ std::string s;
+ if (item_selector == -1)
+ s = "You aren't carrying anything.";
+ else
+ {
+ if (item_selector == OBJ_WEAPONS || item_selector == OSEL_WIELD)
+ s = "You aren't carrying any weapons.";
+ else if (item_selector == OBJ_MISSILES)
+ s = "You aren't carrying any ammunition.";
+ else
+ s = "You aren't carrying any such object.";
+ }
+ menu.set_title( new MenuEntry( s ) );
+ }
+
+ menu.set_flags( flags );
+ std::vector< MenuEntry * > sel = menu.show();
+ if (items)
+ {
+ for (int i = 0, count = sel.size(); i < count; ++i)
+ items->push_back( SelItem( sel[i]->hotkeys[0],
+ sel[i]->selected_qty ) );
+ }
+
+ unsigned char mkey = menu.getkey();
+ if (!isalnum(mkey) && mkey != '$' && mkey != '-' && mkey != '?'
+ && mkey != '*')
+ mkey = ' ';
+ return mkey;
+}
+
+unsigned char invent( int item_class_inv, bool show_price )
+{
+ InvShowPrices show_item_prices(show_price);
+ return (invent_select(item_class_inv));
+} // end invent()
+
+
+// Reads in digits for a count and apprends then to val, the
+// return value is the character that stopped the reading.
+static unsigned char get_invent_quant( unsigned char keyin, int &quant )
+{
+ quant = keyin - '0';
+
+ for(;;)
+ {
+ keyin = get_ch();
+
+ if (!isdigit( keyin ))
+ break;
+
+ quant *= 10;
+ quant += (keyin - '0');
+
+ if (quant > 9999999)
+ {
+ quant = 9999999;
+ keyin = '\0';
+ break;
+ }
+ }
+
+ return (keyin);
+}
+
+// This function prompts the user for an item, handles the '?' and '*'
+// listings, and returns the inventory slot to the caller (which if
+// must_exist is true (the default) will be an assigned item, with
+// a positive quantity.
+//
+// It returns PROMPT_ABORT if the player hits escape.
+// It returns PROMPT_GOT_SPECIAL if the player hits the "other_valid_char".
+//
+// Note: This function never checks if the item is appropriate.
+std::vector<SelItem> prompt_invent_items(
+ const char *prompt,
+ int type_expect,
+ std::string (*titlefn)( int menuflags,
+ const std::string &oldt ),
+ bool allow_auto_list,
+ bool allow_easy_quit,
+ const char other_valid_char,
+ std::vector<text_pattern> *select_filter,
+ Menu::selitem_tfn fn )
+{
+ unsigned char keyin = 0;
+ int ret = -1;
+
+ bool need_redraw = false;
+ bool need_prompt = true;
+ bool need_getch = true;
+
+ if (Options.auto_list && allow_auto_list)
+ {
+ need_getch = false;
+ need_redraw = false;
+ need_prompt = false;
+ keyin = '?';
+ }
+
+ std::vector< SelItem > items;
+ int count = -1;
+ for (;;)
+ {
+ if (need_redraw)
+ {
+ redraw_screen();
+ mesclr( true );
+ }
+
+ if (need_prompt)
+ mpr( prompt, MSGCH_PROMPT );
+
+ if (need_getch)
+ keyin = get_ch();
+
+ need_redraw = false;
+ need_prompt = true;
+ need_getch = true;
+
+ // Note: We handle any "special" character first, so that
+ // it can be used to override the others.
+ if (other_valid_char != '\0' && keyin == other_valid_char)
+ {
+ ret = PROMPT_GOT_SPECIAL;
+ break;
+ }
+ else if (keyin == '?' || keyin == '*' || keyin == ',')
+ {
+ int selmode = Options.drop_mode == DM_SINGLE?
+ MF_SINGLESELECT | MF_EASY_EXIT | MF_ANYPRINTABLE :
+ MF_MULTISELECT;
+ // The "view inventory listing" mode.
+ int ch = invent_select(
+ keyin == '*'? -1 : type_expect,
+ selmode | MF_SELECT_ANY_PAGE,
+ titlefn, &items, select_filter, fn );
+
+ if (selmode & MF_SINGLESELECT)
+ {
+ keyin = ch;
+ need_getch = false;
+ }
+ else
+ {
+ keyin = 0;
+ need_getch = true;
+ }
+
+ if (items.size())
+ {
+ redraw_screen();
+ mesclr( true );
+
+ for (int i = 0, count = items.size(); i < count; ++i)
+ items[i].slot = letter_to_index( items[i].slot );
+ return items;
+ }
+
+ need_redraw = !(keyin == '?' || keyin == '*'
+ || keyin == ',' || keyin == '+');
+ need_prompt = need_redraw;
+ }
+ else if (isdigit( keyin ))
+ {
+ // The "read in quantity" mode
+ keyin = get_invent_quant( keyin, count );
+
+ need_prompt = false;
+ need_getch = false;
+ }
+ else if (keyin == ESCAPE
+ || (Options.easy_quit_item_prompts
+ && allow_easy_quit
+ && keyin == ' '))
+ {
+ ret = PROMPT_ABORT;
+ break;
+ }
+ else if (isalpha( keyin ))
+ {
+ ret = letter_to_index( keyin );
+
+ if (!is_valid_item( you.inv[ret] ))
+ mpr( "You do not have any such object." );
+ else
+ break;
+ }
+ else if (!isspace( keyin ))
+ {
+ // we've got a character we don't understand...
+ canned_msg( MSG_HUH );
+ }
+ }
+
+ if (ret != PROMPT_ABORT)
+ items.push_back( SelItem( ret, count ) );
+ return items;
+}
+
+// This function prompts the user for an item, handles the '?' and '*'
+// listings, and returns the inventory slot to the caller (which if
+// must_exist is true (the default) will be an assigned item, with
+// a positive quantity.
+//
+// It returns PROMPT_ABORT if the player hits escape.
+// It returns PROMPT_GOT_SPECIAL if the player hits the "other_valid_char".
+//
+// Note: This function never checks if the item is appropriate.
+int prompt_invent_item( const char *prompt, int type_expect,
+ bool must_exist, bool allow_auto_list,
+ bool allow_easy_quit,
+ const char other_valid_char,
+ int *const count )
+{
+ unsigned char keyin = 0;
+ int ret = -1;
+
+ bool need_redraw = false;
+ bool need_prompt = true;
+ bool need_getch = true;
+
+ if (Options.auto_list && allow_auto_list)
+ {
+ std::vector< SelItem > items;
+
+ // pretend the player has hit '?' and setup state.
+ keyin = invent_select( type_expect,
+ MF_SINGLESELECT | MF_ANYPRINTABLE
+ | MF_EASY_EXIT,
+ NULL, &items );
+
+ if (items.size())
+ {
+ if (count)
+ *count = items[0].quantity;
+ redraw_screen();
+ mesclr( true );
+ return letter_to_index( keyin );
+ }
+
+ need_getch = false;
+
+ // Don't redraw if we're just going to display another listing
+ need_redraw = (keyin != '?' && keyin != '*');
+
+ // A prompt is nice for when we're moving to "count" mode.
+ need_prompt = (count != NULL && isdigit( keyin ));
+ }
+
+ for (;;)
+ {
+ if (need_redraw)
+ {
+ redraw_screen();
+ mesclr( true );
+ }
+
+ if (need_prompt)
+ mpr( prompt, MSGCH_PROMPT );
+
+ if (need_getch)
+ keyin = get_ch();
+
+ need_redraw = false;
+ need_prompt = true;
+ need_getch = true;
+
+ // Note: We handle any "special" character first, so that
+ // it can be used to override the others.
+ if (other_valid_char != '\0' && keyin == other_valid_char)
+ {
+ ret = PROMPT_GOT_SPECIAL;
+ break;
+ }
+ else if (keyin == '?' || keyin == '*')
+ {
+ // The "view inventory listing" mode.
+ std::vector< SelItem > items;
+ keyin = invent_select( keyin == '*'? OSEL_ANY : type_expect,
+ MF_SINGLESELECT | MF_ANYPRINTABLE
+ | MF_EASY_EXIT,
+ NULL,
+ &items );
+
+ if (items.size())
+ {
+ if (count)
+ *count = items[0].quantity;
+ redraw_screen();
+ mesclr( true );
+ return letter_to_index( keyin );
+ }
+
+ need_getch = false;
+
+ // Don't redraw if we're just going to display another listing
+ need_redraw = (keyin != '?' && keyin != '*');
+
+ // A prompt is nice for when we're moving to "count" mode.
+ need_prompt = (count != NULL && isdigit( keyin ));
+ }
+ else if (count != NULL && isdigit( keyin ))
+ {
+ // The "read in quantity" mode
+ keyin = get_invent_quant( keyin, *count );
+
+ need_prompt = false;
+ need_getch = false;
+ }
+ else if (keyin == ESCAPE
+ || (Options.easy_quit_item_prompts
+ && allow_easy_quit
+ && keyin == ' '))
+ {
+ ret = PROMPT_ABORT;
+ break;
+ }
+ else if (isalpha( keyin ))
+ {
+ ret = letter_to_index( keyin );
+
+ if (must_exist && !is_valid_item( you.inv[ret] ))
+ mpr( "You do not have any such object." );
+ else
+ break;
+ }
+ else if (!isspace( keyin ))
+ {
+ // we've got a character we don't understand...
+ canned_msg( MSG_HUH );
+ }
+ }
+
+ return (ret);
+}
+
+void list_commands(bool wizard)
+{
+ const char *line;
+ int j = 0;
+
+#ifdef DOS_TERM
+ char buffer[4800];
+
+ window(1, 1, 80, 25);
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+ clrscr();
+
+ // BCR - Set to screen length - 1 to display the "more" string
+ int moreLength = (get_number_of_lines() - 1) * 2;
+
+ for (int i = 0; i < 500; i++)
+ {
+ if (wizard)
+ line = wizard_string( i );
+ else
+ line = command_string( i );
+
+ if (strlen( line ) != 0)
+ {
+ // BCR - If we've reached the end of the screen, clear
+ if (j == moreLength)
+ {
+ gotoxy(2, j / 2 + 1);
+ cprintf("More...");
+ getch();
+ clrscr();
+ j = 0;
+ }
+
+ gotoxy( ((j % 2) ? 40 : 2), ((j / 2) + 1) );
+ cprintf( line );
+
+ j++;
+ }
+ }
+
+ getch();
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ return;
+} // end list_commands()
+
+const char *wizard_string( int i )
+{
+ UNUSED( i );
+
+#ifdef WIZARD
+ return((i == 10) ? "a : acquirement" :
+ (i == 13) ? "A : set all skills to level" :
+ (i == 15) ? "b : controlled blink" :
+ (i == 20) ? "B : banish yourself to the Abyss" :
+ (i == 30) ? "g : add a skill" :
+ (i == 35) ? "G : remove all monsters" :
+ (i == 40) ? "h/H : heal yourself (super-Heal)" :
+ (i == 50) ? "i/I : identify/unidentify inventory":
+ (i == 70) ? "l : make entrance to labyrinth" :
+ (i == 80) ? "m/M : create monster by number/name":
+ (i == 90) ? "o/%% : create an object" :
+ (i == 100) ? "p : make entrance to pandemonium" :
+ (i == 110) ? "x : gain an experience level" :
+ (i == 115) ? "r : change character's species" :
+ (i == 120) ? "s : gain 20000 skill points" :
+ (i == 130) ? "S : set skill to level" :
+ (i == 140) ? "t : tweak object properties" :
+ (i == 150) ? "X : Receive a gift from Xom" :
+ (i == 160) ? "z/Z : cast any spell by number/name":
+ (i == 200) ? "$ : get 1000 gold" :
+ (i == 210) ? "</> : create up/down staircase" :
+ (i == 220) ? "u/d : shift up/down one level" :
+ (i == 230) ? "~/\" : goto a level" :
+ (i == 240) ? "( : create a feature" :
+ (i == 250) ? "] : get a mutation" :
+ (i == 260) ? "[ : get a demonspawn mutation" :
+ (i == 270) ? ": : find branch" :
+ (i == 280) ? "{ : magic mapping" :
+ (i == 290) ? "^ : gain piety" :
+ (i == 300) ? "_ : gain religion" :
+ (i == 310) ? "\' : list items" :
+ (i == 320) ? "? : list wizard commands" :
+ (i == 330) ? "| : acquire all unrand artefacts" :
+ (i == 340) ? "+ : turn item into random artefact" :
+ (i == 350) ? "= : sum skill points"
+ : "");
+
+#else
+ return ("");
+#endif
+} // end wizard_string()
+
+const char *command_string( int i )
+{
+ /*
+ * BCR - Command printing, case statement
+ * Note: The numbers in this case indicate the order in which the
+ * commands will be printed out. Make sure none of these
+ * numbers is greater than 500, because that is the limit.
+ *
+ * Arranged alpha lower, alpha upper, punctuation, ctrl.
+ *
+ */
+
+ return((i == 10) ? "a : use special ability" :
+ (i == 20) ? "d(#) : drop (exact quantity of) items" :
+ (i == 30) ? "e : eat food" :
+ (i == 40) ? "f : fire first available missile" :
+ (i == 50) ? "i : inventory listing" :
+ (i == 55) ? "m : check skills" :
+ (i == 60) ? "o/c : open / close a door" :
+ (i == 65) ? "p : pray" :
+ (i == 70) ? "q : quaff a potion" :
+ (i == 80) ? "r : read a scroll or book" :
+ (i == 90) ? "s : search adjacent tiles" :
+ (i == 100) ? "t : throw/shoot an item" :
+ (i == 110) ? "v : view item description" :
+ (i == 120) ? "w : wield an item" :
+ (i == 130) ? "x : examine visible surroundings" :
+ (i == 135) ? "z : zap a wand" :
+ (i == 140) ? "A : list abilities/mutations" :
+ (i == 141) ? "C : check experience" :
+ (i == 142) ? "D : dissect a corpse" :
+ (i == 145) ? "E : evoke power of wielded item" :
+ (i == 150) ? "M : memorise a spell" :
+ (i == 155) ? "O : overview of the dungeon" :
+ (i == 160) ? "P/R : put on / remove jewellery" :
+ (i == 165) ? "Q : quit without saving" :
+ (i == 168) ? "S : save game and exit" :
+ (i == 179) ? "V : version information" :
+ (i == 200) ? "W/T : wear / take off armour" :
+ (i == 210) ? "X : examine level map" :
+ (i == 220) ? "Z : cast a spell" :
+ (i == 240) ? ",/g : pick up items" :
+ (i == 242) ? "./del: rest one turn" :
+ (i == 250) ? "</> : ascend / descend a staircase" :
+ (i == 270) ? "; : examine occupied tile" :
+ (i == 280) ? "\\ : check item knowledge" :
+#ifdef WIZARD
+ (i == 290) ? "& : invoke your Wizardly powers" :
+#endif
+ (i == 300) ? "+/- : scroll up/down [level map only]" :
+ (i == 310) ? "! : shout or command allies" :
+ (i == 325) ? "^ : describe religion" :
+ (i == 337) ? "@ : status" :
+ (i == 340) ? "# : dump character to file" :
+ (i == 350) ? "= : reassign inventory/spell letters" :
+ (i == 360) ? "\' : wield item a, or switch to b" :
+#ifdef USE_MACROS
+ (i == 380) ? "` : add macro" :
+ (i == 390) ? "~ : save macros" :
+#endif
+ (i == 400) ? "] : display worn armour" :
+ (i == 410) ? "\" : display worn jewellery" :
+ (i == 420) ? "Ctrl-P : see old messages" :
+#ifdef PLAIN_TERM
+ (i == 430) ? "Ctrl-R : Redraw screen" :
+#endif
+ (i == 440) ? "Ctrl-A : toggle autopickup" :
+ (i == 450) ? "Ctrl-X : Save game without query" :
+
+#ifdef ALLOW_DESTROY_ITEM_COMMAND
+ (i == 451) ? "Ctrl-D : Destroy inventory item" :
+#endif
+ (i == 453) ? "Ctrl-G : interlevel travel" :
+ (i == 455) ? "Ctrl-O : explore" :
+
+#ifdef STASH_TRACKING
+ (i == 456) ? "Ctrl-S : mark stash" :
+ (i == 457) ? "Ctrl-E : forget stash" :
+ (i == 458) ? "Ctrl-F : search stashes" :
+#endif
+
+ (i == 460) ? "Shift & DIR : long walk" :
+ (i == 465) ? "/ DIR : long walk" :
+ (i == 470) ? "Ctrl & DIR : door; untrap; attack" :
+ (i == 475) ? "* DIR : door; untrap; attack" :
+ (i == 478) ? "Shift & 5 on keypad : rest 100 turns"
+ : "");
+} // end command_string()