Don't auto-drop ?tele in Gauntlet (Yermak)
[crawl.git] / crawl-ref / source / invent.cc
1 /**
2  * @file
3  * @brief Functions for inventory related commands.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "invent.h"
9
10 #include <algorithm> // any_of
11 #include <cctype>
12 #include <cstdlib>
13 #include <cstring>
14 #include <iomanip>
15 #include <sstream>
16
17 #include "artefact.h"
18 #include "colour.h"
19 #include "command.h"
20 #include "describe.h"
21 #include "env.h"
22 #include "evoke.h"
23 #include "god-item.h"
24 #include "god-passive.h"
25 #include "initfile.h"
26 #include "item-prop.h"
27 #include "items.h"
28 #include "item-use.h"
29 #include "item-prop.h"
30 #include "item-status-flag-type.h"
31 #include "known-items.h"
32 #include "libutil.h"
33 #include "macro.h"
34 #include "message.h"
35 #include "options.h"
36 #include "output.h"
37 #include "prompt.h"
38 #include "religion.h"
39 #include "rltiles/tiledef-dngn.h"
40 #include "rltiles/tiledef-icons.h"
41 #include "rltiles/tiledef-main.h"
42 #include "showsymb.h"
43 #include "state.h"
44 #include "stringutil.h"
45 #include "tag-version.h"
46 #include "terrain.h"
47 #include "throw.h"
48 #include "tilepick.h"
49 #include "tile-env.h"
50
51 ///////////////////////////////////////////////////////////////////////////////
52 // Inventory menu shenanigans
53
54 static void _get_inv_items_to_show(vector<const item_def*> &v,
55                                    int selector, int excluded_slot = -1);
56
57 InvTitle::InvTitle(Menu *mn, const string &title, invtitle_annotator tfn)
58     : MenuEntry(title, MEL_TITLE)
59 {
60     m       = mn;
61     titlefn = tfn;
62 }
63
64 string InvTitle::get_text(const bool) const
65 {
66     return titlefn ? titlefn(m, MenuEntry::get_text())
67                    : MenuEntry::get_text();
68 }
69
70 InvEntry::InvEntry(const item_def &i)
71     : MenuEntry("", MEL_ITEM), item(&i), _has_star(false)
72 {
73     // Data is an inherited void *. When using InvEntry in menus
74     // use the const item in this class whenever possible
75     data = const_cast<item_def *>(item);
76
77     if (in_inventory(i) && i.base_type != OBJ_GOLD)
78     {
79         // We need to do this in order to get the 'wielded' annotation.
80         // We then toss out the first four characters, which look
81         // like this: "a - ". Ow. FIXME.
82         text = i.name(DESC_INVENTORY_EQUIP, false).substr(4);
83     }
84     else
85         text = i.name(DESC_A, false);
86
87     if (item_is_stationary_net(i))
88     {
89         actor *trapped = actor_at(i.pos);
90         text += make_stringf(" (holding %s)",
91                             trapped ? trapped->name(DESC_A).c_str()
92                                     : "nobody"); // buggy net, but don't crash
93     }
94
95     if (i.base_type != OBJ_GOLD && in_inventory(i))
96         add_hotkey(index_to_letter(i.link));
97     else
98         add_hotkey(' ');        // dummy hotkey
99
100     add_class_hotkeys(i);
101
102     quantity = i.quantity;
103 }
104
105 const string &InvEntry::get_basename() const
106 {
107     if (basename.empty())
108         basename = item->name(DESC_BASENAME);
109     return basename;
110 }
111
112 const string &InvEntry::get_qualname() const
113 {
114     if (qualname.empty())
115         qualname = item->name(DESC_QUALNAME);
116     return qualname;
117 }
118
119 const string &InvEntry::get_fullname() const
120 {
121     return text;
122 }
123
124 const string &InvEntry::get_dbname() const
125 {
126     if (dbname.empty())
127         dbname = item->name(DESC_DBNAME);
128     return dbname;
129 }
130
131 bool InvEntry::is_cursed() const
132 {
133     return item_ident(*item, ISFLAG_KNOW_CURSE) && item->cursed();
134 }
135
136 bool InvEntry::is_glowing() const
137 {
138     return !item_ident(*item, ISFLAG_KNOW_TYPE)
139            && (get_equip_desc(*item)
140                || (is_artefact(*item)
141                    && (item->base_type == OBJ_WEAPONS
142                        || item->base_type == OBJ_ARMOUR
143                        || item->base_type == OBJ_BOOKS)));
144 }
145
146 bool InvEntry::is_ego() const
147 {
148     return item_ident(*item, ISFLAG_KNOW_TYPE) && !is_artefact(*item)
149            && item->brand != 0
150            && (item->base_type == OBJ_WEAPONS
151                || item->base_type == OBJ_MISSILES
152                || item->base_type == OBJ_ARMOUR);
153 }
154
155 bool InvEntry::is_art() const
156 {
157     return item_ident(*item, ISFLAG_KNOW_TYPE) && is_artefact(*item);
158 }
159
160 bool InvEntry::is_equipped() const
161 {
162     if (item->link == -1 || item->pos != ITEM_IN_INVENTORY)
163         return false;
164
165     for (int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; i++)
166         if (item->link == you.equip[i])
167             return true;
168
169     return false;
170 }
171
172 void InvEntry::select(int qty)
173 {
174     if (item && item->quantity < qty)
175         qty = item->quantity;
176
177     MenuEntry::select(qty);
178 }
179
180 bool InvEntry::has_star() const
181 {
182     return _has_star;
183 }
184
185 string InvEntry::get_filter_text() const
186 {
187     return item_prefix(*item, false) + " " + get_text();
188 }
189
190 string InvEntry::get_text(bool need_cursor) const
191 {
192     need_cursor = need_cursor && show_cursor;
193
194     ostringstream tstr;
195
196     const bool nosel = hotkeys.empty();
197     const char key = nosel ? ' ' : static_cast<char>(hotkeys[0]);
198
199     tstr << ' ';
200
201     if (!nosel || tag == "pickup")
202     {
203         tstr << key;
204
205         if (need_cursor)
206             tstr << '[';
207         else
208             tstr << ' ';
209
210         if (nosel)
211             tstr << ' ';
212         else if (!selected_qty)
213             tstr << '-';
214         else if (selected_qty < quantity)
215             tstr << '#';
216         else if (_has_star)
217             tstr << '*';
218         else
219             tstr << '+';
220
221         if (need_cursor)
222             tstr << ']';
223         else
224             tstr << ' ';
225     }
226     if (InvEntry::show_glyph)
227         tstr << "(" << glyph_to_tagstr(get_item_glyph(*item)) << ")" << " ";
228
229     if (InvEntry::show_coordinates && in_bounds(item->pos))
230     {
231         const coord_def relpos = item->pos - you.pos();
232         tstr << "(" << relpos.x << ", " << -relpos.y << ")" << " ";
233     }
234
235     tstr << text;
236     return tstr.str();
237 }
238
239 void get_class_hotkeys(const int type, vector<char> &glyphs)
240 {
241     switch (type)
242     {
243     case OBJ_GOLD:
244         glyphs.push_back('$');
245         break;
246     case OBJ_MISSILES:
247         glyphs.push_back('(');
248         break;
249     case OBJ_WEAPONS:
250         glyphs.push_back(')');
251         break;
252     case OBJ_ARMOUR:
253         glyphs.push_back('[');
254         break;
255     case OBJ_WANDS:
256         glyphs.push_back('/');
257         break;
258     case OBJ_BOOKS:
259         glyphs.push_back(':');
260         break;
261     case OBJ_SCROLLS:
262         glyphs.push_back('?');
263         break;
264     case OBJ_JEWELLERY:
265         glyphs.push_back('"');
266         glyphs.push_back('=');
267         break;
268     case OBJ_POTIONS:
269         glyphs.push_back('!');
270         break;
271     case OBJ_STAVES:
272         glyphs.push_back('|');
273         break;
274 #if TAG_MAJOR_VERSION == 34
275     case OBJ_RODS:
276         glyphs.push_back('\\');
277         break;
278 #endif
279     case OBJ_MISCELLANY:
280         glyphs.push_back('}');
281         break;
282     default:
283         break;
284     }
285 }
286
287 void InvEntry::add_class_hotkeys(const item_def &i)
288 {
289     const int type = i.base_type;
290     if (type == OBJ_JEWELLERY)
291     {
292         add_hotkey(i.sub_type >= AMU_FIRST_AMULET ? '"' : '=');
293         return;
294     }
295
296     vector<char> glyphs;
297     get_class_hotkeys(type, glyphs);
298     for (char gly : glyphs)
299         add_hotkey(gly);
300 }
301
302 bool InvEntry::show_cursor = false;
303 void InvEntry::set_show_cursor(bool doshow)
304 {
305     show_cursor = doshow;
306 }
307
308 bool InvEntry::show_glyph = false;
309 void InvEntry::set_show_glyph(bool doshow)
310 {
311     show_glyph = doshow;
312 }
313
314 bool InvEntry::show_coordinates = false;
315 void InvEntry::set_show_coordinates(bool doshow)
316 {
317     show_coordinates = doshow;
318 }
319
320 InvMenu::InvMenu(int mflags)
321     : Menu(mflags, "inventory"), type(menu_type::invlist), pre_select(nullptr),
322       title_annotate(nullptr), _mode_special_drop(false)
323 {
324 #ifdef USE_TILE_LOCAL
325     if (Options.tile_menu_icons)
326         set_flags(mflags | MF_USE_TWO_COLUMNS);
327 #endif
328
329     InvEntry::set_show_cursor(false);
330 }
331
332 bool InvMenu::mode_special_drop() const
333 {
334     return _mode_special_drop;
335 }
336
337 void InvMenu::set_type(menu_type t)
338 {
339     type = t;
340 }
341
342 void InvMenu::set_title_annotator(invtitle_annotator afn)
343 {
344     title_annotate = afn;
345 }
346
347 void InvMenu::set_title(MenuEntry *t, bool first)
348 {
349     Menu::set_title(t, first);
350 }
351
352 void InvMenu::set_preselect(const vector<SelItem> *pre)
353 {
354     pre_select = pre;
355 }
356
357 string slot_description()
358 {
359     return make_stringf("%d/%d slots", inv_count(), ENDOFPACK);
360 }
361
362 void InvMenu::set_title(const string &s)
363 {
364     set_title(new InvTitle(this, s.empty() ? "Inventory: " + slot_description()
365                                            : s,
366                            title_annotate));
367 }
368
369 int InvMenu::pre_process(int key)
370 {
371     if (type == menu_type::drop && key == '\\')
372     {
373         _mode_special_drop = !_mode_special_drop;
374         key = CK_NO_KEY;
375     }
376     else if (key == ';'
377              && you.last_unequip != -1
378              && (type == menu_type::drop || type == menu_type::invlist))
379     {
380         key = index_to_letter(you.last_unequip);
381     }
382     else if (key == '-')
383         _mode_special_drop = false;
384     return key;
385 }
386
387 static bool _item_is_permadrop_candidate(const item_def &item)
388 {
389     // Known, non-artefact items of the types you see on the '\' menu proper.
390     // (No disabling autopickup for "green fizzy potion", "+3 whip", etc.)
391     if (item_type_unknown(item))
392         return false;
393     return item.base_type == OBJ_MISCELLANY
394         || is_stackable_item(item)
395         || item_type_has_ids(item.base_type);
396 }
397
398 void InvMenu::select_item_index(int idx, int qty, bool draw_cursor)
399 {
400     if (type != menu_type::drop)
401         return Menu::select_item_index(idx, qty, draw_cursor);
402
403     InvEntry *ie = static_cast<InvEntry*>(items[idx]);
404
405     bool should_toggle_star = _item_is_permadrop_candidate(ie->item[0])
406         && (ie->has_star() || _mode_special_drop);
407
408     if (should_toggle_star)
409     {
410         // Toggle starred items back to selected-but-not-starred in this mode
411         // instead of turning them all the way off.
412         qty = _mode_special_drop ? -2 : 0;
413         ie->set_star(!ie->has_star());
414     }
415     Menu::select_item_index(idx, qty, draw_cursor);
416 }
417
418 void InvEntry::set_star(bool val)
419 {
420     _has_star = val;
421 }
422
423 static bool _has_melded_armour()
424 {
425     for (int e = EQ_CLOAK; e <= EQ_BODY_ARMOUR; e++)
426         if (you.melded[e])
427             return true;
428     return false;
429 }
430
431 static bool _has_temp_unwearable_armour()
432 {
433     for (const auto &item : you.inv)
434     {
435         if (item.defined() && item.base_type == OBJ_ARMOUR
436             && can_wear_armour(item, false, true)
437             && !can_wear_armour(item, false, false))
438         {
439             return true;
440         }
441     }
442     return false;
443 }
444
445 static bool _has_hand_evokable()
446 {
447     for (const auto &item : you.inv)
448     {
449         if (item.defined()
450             && item_is_evokable(item, true, false, false)
451             && !item_is_evokable(item, true, false, true))
452         {
453             return true;
454         }
455     }
456     return false;
457 }
458
459 /**
460  * What message should the player be given when they look for items matching
461  * the given selector and don't find any?
462  *
463  * @param selector      The given type of object_selector.
464  * @return              A message such as "You aren't carrying any weapons."
465  *                      "Your armour is currently melded into you.", etc.
466  */
467 string no_selectables_message(int item_selector)
468 {
469     switch (item_selector)
470     {
471     case OSEL_ANY:
472         return "You aren't carrying anything.";
473     case OSEL_WIELD:
474     case OBJ_WEAPONS:
475         return "You aren't carrying any weapons.";
476     case OSEL_BLESSABLE_WEAPON:
477         return "You aren't carrying any weapons that can be blessed.";
478     case OBJ_ARMOUR:
479     {
480         if (_has_melded_armour())
481             return "Your armour is currently melded into you.";
482         else if (_has_temp_unwearable_armour())
483             return "You aren't carrying any currently wearable armour.";
484         else
485             return "You aren't carrying any wearable armour.";
486     }
487     case OSEL_UNIDENT:
488         return "You don't have any unidentified items.";
489     case OSEL_ENCHANTABLE_ARMOUR:
490         return "You aren't carrying any armour which can be enchanted further.";
491     case OBJ_CORPSES:
492         return "You don't have any corpses.";
493     case OBJ_POTIONS:
494         return "You aren't carrying any potions.";
495     case OBJ_SCROLLS:
496         return "You aren't carrying any scrolls.";
497     case OBJ_BOOKS:
498         return "You don't have any books.";
499     case OBJ_WANDS:
500         return "You aren't carrying any wands.";
501     case OBJ_JEWELLERY:
502         return "You aren't carrying any pieces of jewellery.";
503     case OSEL_THROWABLE:
504         return "You aren't carrying any items that might be thrown or fired.";
505     case OSEL_EVOKABLE:
506         if (_has_hand_evokable())
507             return "You aren't carrying any items that you can evoke without wielding.";
508         else
509             return "You aren't carrying any items that you can evoke.";
510     case OSEL_CURSED_WORN:
511         return "None of your equipped items are cursed.";
512 #if TAG_MAJOR_VERSION == 34
513     case OSEL_UNCURSED_WORN_ARMOUR:
514         return "You aren't wearing any piece of uncursed armour.";
515     case OSEL_UNCURSED_WORN_JEWELLERY:
516         return "You aren't wearing any piece of uncursed jewellery.";
517 #endif
518     case OSEL_BRANDABLE_WEAPON:
519         return "You aren't carrying any weapons that can be branded.";
520     case OSEL_ENCHANTABLE_WEAPON:
521         return "You aren't carrying any weapons that can be enchanted.";
522     case OSEL_BEOGH_GIFT:
523         return "You aren't carrying anything you can give to a follower.";
524     case OSEL_CURSABLE:
525         return "You don't have any cursable items.";
526     case OSEL_UNCURSED_WORN_RINGS:
527         return "You aren't wearing any uncursed rings.";
528     case OSEL_QUIVER_ACTION:
529     case OSEL_QUIVER_ACTION_FORCE:
530         return "You don't have any quiverable items.";
531     }
532
533     return "You aren't carrying any such object.";
534 }
535
536 void InvMenu::load_inv_items(int item_selector, int excluded_slot,
537                              function<MenuEntry* (MenuEntry*)> procfn)
538 {
539     vector<const item_def *> tobeshown;
540     _get_inv_items_to_show(tobeshown, item_selector, excluded_slot);
541
542     load_items(tobeshown, procfn);
543
544     if (!item_count())
545         set_title(no_selectables_message(item_selector));
546     else
547         set_title("");
548 }
549
550 bool get_tiles_for_item(const item_def &item, vector<tile_def>& tileset, bool show_background)
551 {
552     tileidx_t idx = tileidx_item(get_item_info(item));
553     if (!idx)
554         return false;
555
556     if (in_inventory(item))
557     {
558         const equipment_type eq = item_equip_slot(item);
559         if (eq != EQ_NONE)
560         {
561             if (item_known_cursed(item))
562                 tileset.emplace_back(TILE_ITEM_SLOT_EQUIP_CURSED);
563             else
564                 tileset.emplace_back(TILE_ITEM_SLOT_EQUIP);
565         }
566         else if (item_known_cursed(item))
567             tileset.emplace_back(TILE_ITEM_SLOT_CURSED);
568
569         tileidx_t base_item = tileidx_known_base_item(idx);
570         if (base_item)
571             tileset.emplace_back(base_item);
572         tileset.emplace_back(idx);
573
574         if (eq != EQ_NONE && you.melded[eq])
575             tileset.emplace_back(TILEI_MESH);
576     }
577     else
578     {
579         // Do we want to display the floor type or is that too distracting?
580         const coord_def c = item.held_by_monster()
581             ? item.holding_monster()->pos()
582             : item.pos;
583         tileidx_t ch = 0;
584         if (c != coord_def() && show_background && item.link != ITEM_IN_SHOP)
585         {
586             ch = tileidx_feature(c);
587             if (ch == TILE_FLOOR_NORMAL)
588                 ch = tile_env.flv(c).floor;
589             else if (ch == TILE_WALL_NORMAL)
590                 ch = tile_env.flv(c).wall;
591
592             tileset.emplace_back(ch);
593         }
594         tileidx_t base_item = tileidx_known_base_item(idx);
595         if (base_item)
596             tileset.emplace_back(base_item);
597
598         tileset.emplace_back(idx);
599
600         if (ch != 0)
601         {
602             // Needs to be displayed so as to not give away mimics in shallow water.
603             if (ch == TILE_DNGN_SHALLOW_WATER)
604                 tileset.emplace_back(TILEI_MASK_SHALLOW_WATER);
605             else if (ch == TILE_DNGN_SHALLOW_WATER_MURKY)
606                 tileset.emplace_back(TILEI_MASK_SHALLOW_WATER_MURKY);
607         }
608     }
609     if (item.base_type == OBJ_WEAPONS || item.base_type == OBJ_MISSILES
610         || item.base_type == OBJ_ARMOUR
611 #if TAG_MAJOR_VERSION == 34
612         || item.base_type == OBJ_RODS
613 #endif
614        )
615     {
616         tileidx_t brand = tileidx_known_brand(item);
617         if (brand)
618             tileset.emplace_back(brand);
619     }
620     else if (item.base_type == OBJ_CORPSES)
621     {
622         tileidx_t brand = tileidx_corpse_brand(item);
623         if (brand)
624             tileset.emplace_back(brand);
625     }
626
627     return true;
628 }
629
630 #ifdef USE_TILE
631 bool InvEntry::get_tiles(vector<tile_def>& tileset) const
632 {
633     if (!Options.tile_menu_icons)
634         return false;
635
636     // Runes + orb of zot have a special uncollected tile
637     if (quantity <= 0 && (item->base_type != OBJ_RUNES && item->base_type != OBJ_ORBS))
638         return false;
639
640     return get_tiles_for_item(*item, tileset, show_background);
641 }
642 #else
643 bool InvEntry::get_tiles(vector<tile_def>& /*tileset*/) const { return false; }
644 #endif
645
646 bool InvMenu::is_selectable(int index) const
647 {
648     if (type == menu_type::drop)
649     {
650         InvEntry *item = dynamic_cast<InvEntry*>(items[index]);
651         if (item->is_cursed() && item->is_equipped())
652             return false;
653
654         string text = item->get_text();
655
656         if (text.find("!*") != string::npos || text.find("!d") != string::npos)
657             return false;
658     }
659
660     return Menu::is_selectable(index);
661 }
662
663 template <const string &(InvEntry::*method)() const>
664 static int compare_item_str(const InvEntry *a, const InvEntry *b)
665 {
666     return (a->*method)().compare((b->*method)());
667 }
668
669 // Would call this just compare_item, but MSVC mistakenly thinks the next
670 // one is a specialization rather than an overload.
671 template <typename T, T (*proc)(const InvEntry *a)>
672 static int compare_item_fn(const InvEntry *a, const InvEntry *b)
673 {
674     return int(proc(a)) - int(proc(b));
675 }
676
677 template <typename T, T (InvEntry::*method)() const>
678 static int compare_item(const InvEntry *a, const InvEntry *b)
679 {
680     return int((a->*method)()) - int((b->*method)());
681 }
682
683 template <typename T, T (InvEntry::*method)() const>
684 static int compare_item_rev(const InvEntry *a, const InvEntry *b)
685 {
686     return int((b->*method)()) - int((a->*method)());
687 }
688
689 template <item_sort_fn cmp>
690 static int compare_reverse(const InvEntry *a, const InvEntry *b)
691 {
692     return -cmp(a, b);
693 }
694
695 // We need C++11 already!
696 // Some prototypes to prevent warnings; we can't make these static because
697 // they're used as template parameters.
698 int sort_item_qty(const InvEntry *a);
699 int sort_item_slot(const InvEntry *a);
700 bool sort_item_identified(const InvEntry *a);
701 bool sort_item_charged(const InvEntry *a);
702
703 int sort_item_qty(const InvEntry *a)
704 {
705     return a->quantity;
706 }
707 int sort_item_slot(const InvEntry *a)
708 {
709     return a->item->link;
710 }
711
712 bool sort_item_identified(const InvEntry *a)
713 {
714     return !item_type_known(*(a->item));
715 }
716
717 bool sort_item_charged(const InvEntry *a)
718 {
719     return a->item->base_type != OBJ_WANDS
720            || !item_is_evokable(*(a->item), false);
721 }
722
723 static bool _compare_invmenu_items(const InvEntry *a, const InvEntry *b,
724                                    const item_sort_comparators *cmps)
725 {
726     for (const auto &comparator : *cmps)
727     {
728         const int cmp = comparator.compare(a, b);
729         if (cmp)
730             return cmp < 0;
731     }
732     return a->item->link < b->item->link;
733 }
734
735 struct menu_entry_comparator
736 {
737     const menu_sort_condition *cond;
738
739     menu_entry_comparator(const menu_sort_condition *c)
740         : cond(c)
741     {
742     }
743
744     bool operator () (const MenuEntry* a, const MenuEntry* b) const
745     {
746         const InvEntry *ia = dynamic_cast<const InvEntry *>(a);
747         const InvEntry *ib = dynamic_cast<const InvEntry *>(b);
748         return _compare_invmenu_items(ia, ib, &cond->cmp);
749     }
750 };
751
752 void init_item_sort_comparators(item_sort_comparators &list, const string &set)
753 {
754     static struct
755     {
756         const string cname;
757         item_sort_fn cmp;
758     } cmp_map[]  =
759       {
760           { "basename",  compare_item_str<&InvEntry::get_basename> },
761           { "qualname",  compare_item_str<&InvEntry::get_qualname> },
762           { "fullname",  compare_item_str<&InvEntry::get_fullname> },
763           { "dbname",    compare_item_str<&InvEntry::get_dbname> },
764           { "curse",     compare_item<bool, &InvEntry::is_cursed> },
765           { "glowing",   compare_item_rev<bool, &InvEntry::is_glowing> },
766           { "ego",       compare_item_rev<bool, &InvEntry::is_ego> },
767           { "art",       compare_item_rev<bool, &InvEntry::is_art> },
768           { "equipped",  compare_item_rev<bool, &InvEntry::is_equipped> },
769           { "identified",compare_item_fn<bool, sort_item_identified> },
770           { "charged",   compare_item_fn<bool, sort_item_charged>},
771           { "qty",       compare_item_fn<int, sort_item_qty> },
772           { "slot",      compare_item_fn<int, sort_item_slot> },
773       };
774
775     list.clear();
776     for (string s : split_string(",", set))
777     {
778         if (s.empty())
779             continue;
780
781         const bool negated = s[0] == '>';
782         if (s[0] == '<' || s[0] == '>')
783             s = s.substr(1);
784
785         for (const auto &ci : cmp_map)
786             if (ci.cname == s)
787             {
788                 list.emplace_back(ci.cmp, negated);
789                 break;
790             }
791     }
792
793     if (list.empty())
794         list.emplace_back(compare_item_str<&InvEntry::get_fullname>);
795 }
796
797 const menu_sort_condition *InvMenu::find_menu_sort_condition() const
798 {
799     for (int i = Options.sort_menus.size() - 1; i >= 0; --i)
800         if (Options.sort_menus[i].matches(type))
801             return &Options.sort_menus[i];
802
803     return nullptr;
804 }
805
806 void InvMenu::sort_menu(vector<InvEntry*> &invitems,
807                         const menu_sort_condition *cond)
808 {
809     if (!cond || cond->sort == -1 || (int) invitems.size() < cond->sort)
810         return;
811
812     sort(invitems.begin(), invitems.end(), menu_entry_comparator(cond));
813 }
814
815 FixedVector<int, NUM_OBJECT_CLASSES> inv_order(
816     OBJ_WEAPONS,
817     OBJ_MISSILES,
818     OBJ_ARMOUR,
819     OBJ_STAVES,
820 #if TAG_MAJOR_VERSION == 34
821     OBJ_RODS,
822 #endif
823     OBJ_JEWELLERY,
824     OBJ_WANDS,
825     OBJ_SCROLLS,
826     OBJ_POTIONS,
827     OBJ_BOOKS,
828     OBJ_MISCELLANY,
829 #if TAG_MAJOR_VERSION == 34
830     OBJ_FOOD,
831 #endif
832     // These four can't actually be in your inventory.
833     OBJ_CORPSES,
834     OBJ_RUNES,
835     OBJ_ORBS,
836     OBJ_GOLD);
837
838 menu_letter InvMenu::load_items(const vector<item_def>& mitems,
839                                 function<MenuEntry* (MenuEntry*)> procfn,
840                                 menu_letter ckey, bool sort)
841 {
842     vector<const item_def*> xlatitems;
843     for (const item_def &item : mitems)
844         xlatitems.push_back(&item);
845     return load_items(xlatitems, procfn, ckey, sort);
846 }
847
848 menu_letter InvMenu::load_items(const vector<const item_def*> &mitems,
849                                 function<MenuEntry* (MenuEntry*)> procfn,
850                                 menu_letter ckey, bool sort)
851 {
852     FixedVector< int, NUM_OBJECT_CLASSES > inv_class(0);
853     for (const item_def * const mitem : mitems)
854         inv_class[mitem->base_type]++;
855
856     vector<InvEntry*> items_in_class;
857     const menu_sort_condition *cond = nullptr;
858     if (sort) cond = find_menu_sort_condition();
859
860     for (int obj = 0; obj < NUM_OBJECT_CLASSES; ++obj)
861     {
862         int i = inv_order[obj];
863
864         if (!inv_class[i])
865             continue;
866
867         string subtitle = item_class_name(i);
868
869         // Mention the class selection shortcuts.
870         if (is_set(MF_MULTISELECT))
871         {
872             vector<char> glyphs;
873             get_class_hotkeys(i, glyphs);
874             if (!glyphs.empty())
875             {
876                 // longest string
877                 const string str = "Magical Staves ";
878                 subtitle += string(strwidth(str) - strwidth(subtitle),
879                                    ' ');
880                 subtitle += "(select all with <w>";
881                 for (char gly : glyphs)
882                     subtitle += gly;
883                 subtitle += "</w><blue>)";
884             }
885         }
886         add_entry(new MenuEntry(subtitle, MEL_SUBTITLE));
887
888         items_in_class.clear();
889
890         InvEntry *forced_first = nullptr;
891         for (const item_def * const mitem : mitems)
892         {
893             if (mitem->base_type != i)
894                 continue;
895
896             InvEntry * const ie = new InvEntry(*mitem);
897             if (mitem->sub_type == get_max_subtype(mitem->base_type))
898                 forced_first = ie;
899             else
900                 items_in_class.push_back(ie);
901         }
902
903         sort_menu(items_in_class, cond);
904         if (forced_first)
905             items_in_class.insert(items_in_class.begin(),forced_first);
906
907         for (InvEntry *ie : items_in_class)
908         {
909             if (tag == "pickup")
910             {
911                 if (ie->item && item_is_stationary(*ie->item))
912                     ie->tag = "nopickup";
913                 else
914                     ie->tag = "pickup";
915             }
916             if (get_flags() & MF_NOSELECT)
917                 ie->hotkeys.clear();
918             // If there's no hotkey, provide one.
919             else if (ie->hotkeys[0] == ' ')
920             {
921                 if (ie->tag == "nopickup")
922                     ie->hotkeys.clear();
923                 else
924                     ie->hotkeys[0] = ckey++;
925             }
926             do_preselect(ie);
927
928             add_entry(procfn ? procfn(ie) : ie);
929         }
930     }
931
932     return ckey;
933 }
934
935 void InvMenu::do_preselect(InvEntry *ie)
936 {
937     if (!pre_select || pre_select->empty())
938         return;
939
940     for (const SelItem &presel : *pre_select)
941         if (ie->item && ie->item == presel.item)
942         {
943             ie->selected_qty = presel.quantity;
944             break;
945         }
946 }
947
948 vector<SelItem> InvMenu::get_selitems() const
949 {
950     vector<SelItem> selected_items;
951     for (MenuEntry *me : sel)
952     {
953         InvEntry *inv = dynamic_cast<InvEntry*>(me);
954         selected_items.emplace_back(inv->hotkeys[0], inv->selected_qty,
955                                     inv->item, inv->has_star());
956     }
957     return selected_items;
958 }
959
960 string InvMenu::help_key() const
961 {
962     return type == menu_type::drop || type == menu_type::pickup ? "pick-up"
963                                                                 : "";
964 }
965
966 int InvMenu::getkey() const
967 {
968     auto mkey = lastch;
969     if (type == menu_type::know && (mkey == 0 || mkey == CK_ENTER))
970         return mkey;
971
972     if (!isaalnum(mkey) && mkey != '$' && mkey != '-' && mkey != '?'
973         && mkey != '*' && !key_is_escape(mkey) && mkey != '\\'
974         && mkey != ',')
975     {
976         mkey = ' ';
977     }
978     return mkey;
979 }
980
981 //////////////////////////////////////////////////////////////////////////////
982
983 bool in_inventory(const item_def &i)
984 {
985     return i.pos == ITEM_IN_INVENTORY;
986 }
987
988 const char *item_class_name(int type, bool terse)
989 {
990     if (terse)
991     {
992         switch (type)
993         {
994         case OBJ_STAVES:     return "magical staff";
995         case OBJ_MISCELLANY: return "misc";
996         default:             return base_type_string((object_class_type) type);
997         }
998     }
999     else
1000     {
1001         switch (type)
1002         {
1003         case OBJ_GOLD:       return "Gold";
1004         case OBJ_WEAPONS:    return "Hand Weapons";
1005         case OBJ_MISSILES:   return "Missiles";
1006         case OBJ_ARMOUR:     return "Armour";
1007         case OBJ_WANDS:      return "Wands";
1008 #if TAG_MAJOR_VERSION == 34
1009         case OBJ_FOOD:       return "Comestibles";
1010 #endif
1011         case OBJ_SCROLLS:    return "Scrolls";
1012         case OBJ_JEWELLERY:  return "Jewellery";
1013         case OBJ_POTIONS:    return "Potions";
1014         case OBJ_BOOKS:      return "Books";
1015         case OBJ_STAVES:     return "Magical Staves";
1016 #if TAG_MAJOR_VERSION == 34
1017         case OBJ_RODS:       return "Rods";
1018 #endif
1019         case OBJ_ORBS:       return "Orbs of Power";
1020         case OBJ_MISCELLANY: return "Miscellaneous";
1021         case OBJ_CORPSES:    return "Carrion";
1022         case OBJ_RUNES:      return "Runes of Zot";
1023         }
1024     }
1025     return "";
1026 }
1027
1028 const char* item_slot_name(equipment_type type)
1029 {
1030     switch (type)
1031     {
1032     case EQ_CLOAK:       return "cloak";
1033     case EQ_HELMET:      return "helmet";
1034     case EQ_GLOVES:      return "gloves";
1035     case EQ_BOOTS:       return "boots";
1036     case EQ_SHIELD:      return "shield";
1037     case EQ_BODY_ARMOUR: return "body";
1038     default:             return "";
1039     }
1040 }
1041
1042 vector<SelItem> select_items(const vector<const item_def*> &items,
1043                              const char *title, bool noselect,
1044                              menu_type mtype)
1045 {
1046     vector<SelItem> selected;
1047     if (!items.empty())
1048     {
1049         InvMenu menu;
1050         menu.set_type(mtype);
1051         menu.set_title(title);
1052         if (mtype == menu_type::pickup)
1053             menu.set_tag("pickup");
1054
1055         menu.load_items(items);
1056         int new_flags = noselect ? MF_NOSELECT
1057                                  : MF_MULTISELECT | MF_ALLOW_FILTER;
1058
1059         if (mtype == menu_type::sel_one)
1060         {
1061             new_flags |= MF_SINGLESELECT;
1062             new_flags &= ~MF_MULTISELECT;
1063         }
1064
1065         new_flags |= MF_ALLOW_FORMATTING;
1066         new_flags |= menu.get_flags() & MF_USE_TWO_COLUMNS;
1067         menu.set_flags(new_flags);
1068         menu.show();
1069         selected = menu.get_selitems();
1070     }
1071     return selected;
1072 }
1073
1074 bool item_is_selected(const item_def &i, int selector)
1075 {
1076     const object_class_type itype = i.base_type;
1077     if (selector == OSEL_ANY || selector == itype
1078                                 && itype != OBJ_ARMOUR)
1079     {
1080         return true;
1081     }
1082
1083     switch (selector)
1084     {
1085     case OBJ_ARMOUR:
1086         return itype == OBJ_ARMOUR && can_wear_armour(i, false, false);
1087
1088     case OSEL_WORN_ARMOUR:
1089         return itype == OBJ_ARMOUR && item_is_equipped(i);
1090
1091     case OSEL_UNIDENT:
1092         return !fully_identified(i) && itype != OBJ_BOOKS;
1093
1094     case OBJ_MISSILES:
1095         return itype == OBJ_MISSILES || itype == OBJ_WEAPONS;
1096
1097     case OSEL_THROWABLE:
1098     {
1099         if (itype != OBJ_WEAPONS && itype != OBJ_MISSILES)
1100             return false;
1101
1102         const launch_retval projected = is_launched(&you, you.weapon(), i);
1103
1104         if (projected == launch_retval::FUMBLED)
1105             return false;
1106
1107         return true;
1108     }
1109     case OBJ_WEAPONS:
1110     case OSEL_WIELD:
1111         return item_is_wieldable(i);
1112
1113     case OBJ_SCROLLS:
1114         return itype == OBJ_SCROLLS
1115                || (itype == OBJ_BOOKS && i.sub_type != BOOK_MANUAL);
1116
1117     case OSEL_EVOKABLE:
1118         // assumes valid link...would break with evoking from floor?
1119         return item_is_evokable(i, true) && item_is_evokable(i, true, false);//evoke_check(i.link, true);
1120
1121     case OSEL_ENCHANTABLE_ARMOUR:
1122         return is_enchantable_armour(i, true);
1123
1124     case OSEL_CURSED_WORN:
1125         return i.cursed() && item_is_equipped(i)
1126                && (&i != you.weapon() || is_weapon(i));
1127
1128 #if TAG_MAJOR_VERSION == 34
1129     case OSEL_UNCURSED_WORN_ARMOUR:
1130         return !i.cursed() && item_is_equipped(i) && itype == OBJ_ARMOUR;
1131
1132     case OSEL_UNCURSED_WORN_JEWELLERY:
1133         return !i.cursed() && item_is_equipped(i) && itype == OBJ_JEWELLERY;
1134 #endif
1135
1136     case OSEL_BRANDABLE_WEAPON:
1137         return is_brandable_weapon(i, true);
1138
1139     case OSEL_ENCHANTABLE_WEAPON:
1140         return itype == OBJ_WEAPONS
1141                && !is_artefact(i)
1142                && (!item_ident(i, ISFLAG_KNOW_PLUSES)
1143                    || i.plus < MAX_WPN_ENCHANT);
1144
1145     case OSEL_BLESSABLE_WEAPON:
1146         return is_brandable_weapon(i, you_worship(GOD_SHINING_ONE), true);
1147
1148     case OSEL_BEOGH_GIFT:
1149         return (itype == OBJ_WEAPONS
1150                 || is_shield(i)
1151                 || itype == OBJ_ARMOUR
1152                    && get_armour_slot(i) == EQ_BODY_ARMOUR)
1153                 && !item_is_equipped(i);
1154
1155     case OSEL_CURSABLE:
1156         return item_is_cursable(i);
1157
1158     case OSEL_UNCURSED_WORN_RINGS:
1159         return !i.cursed() && item_is_equipped(i) && itype == OBJ_JEWELLERY
1160             && !jewellery_is_amulet(i);
1161
1162     case OSEL_QUIVER_ACTION:
1163         return in_inventory(i) && quiver::slot_to_action(i.link)->is_valid();
1164     case OSEL_QUIVER_ACTION_FORCE:
1165         return in_inventory(i) && quiver::slot_to_action(i.link, true)->is_valid();
1166
1167     default:
1168         return false;
1169     }
1170 }
1171
1172 static void _get_inv_items_to_show(vector<const item_def*> &v,
1173                                    int selector, int excluded_slot)
1174 {
1175     for (const auto &item : you.inv)
1176     {
1177         if (item.defined()
1178             && item.link != excluded_slot
1179             && item_is_selected(item, selector))
1180         {
1181             v.push_back(&item);
1182         }
1183     }
1184 }
1185
1186
1187 /**
1188  * Does the player have any items of the given type?
1189  *
1190  * @param selector          A object_selector.
1191  * @param excluded_slot     An item slot to ignore.
1192  * @param inspect_floor     If true, also check the floor where the player is
1193  *                          standing.
1194  *
1195  * @return                  Whether there are any items matching the given
1196  *                          selector in the player's inventory.
1197  */
1198 bool any_items_of_type(int selector, int excluded_slot, bool inspect_floor)
1199 {
1200     bool ret = any_of(begin(you.inv), end(you.inv),
1201                   [=] (const item_def &item) -> bool
1202                   {
1203                       return item.defined() && item.link != excluded_slot
1204                           && item_is_selected(item, selector);
1205                   });
1206     if (!ret && inspect_floor)
1207     {
1208         auto item_floor = item_list_on_square(you.visible_igrd(you.pos()));
1209         ret = any_of(begin(item_floor), end(item_floor),
1210                       [=] (const item_def* item) -> bool
1211                       {
1212                           return item->defined()
1213                                     && item_is_selected(*item, selector);
1214                       });
1215     }
1216     return ret;
1217 }
1218
1219 // Use title = nullptr for stock Inventory title
1220 // type = menu_type::drop allows the multidrop toggle
1221 static unsigned char _invent_select(const char *title = nullptr,
1222                                     menu_type type = menu_type::invlist,
1223                                     int item_selector = OSEL_ANY,
1224                                     int excluded_slot = -1,
1225                                     int flags = MF_NOSELECT,
1226                                     invtitle_annotator titlefn = nullptr,
1227                                     vector<SelItem> *items = nullptr,
1228                                     vector<text_pattern> *filter = nullptr,
1229                                     Menu::selitem_tfn selitemfn = nullptr,
1230                                     const vector<SelItem> *pre_select = nullptr)
1231 {
1232     InvMenu menu(flags | MF_ALLOW_FORMATTING);
1233
1234     menu.set_preselect(pre_select);
1235     menu.set_title_annotator(titlefn);
1236     menu.f_selitem = selitemfn;
1237     if (filter)
1238         menu.set_select_filter(*filter);
1239     menu.load_inv_items(item_selector, excluded_slot);
1240     menu.set_type(type);
1241
1242     // Don't override title if there are no items.
1243     if (title && menu.item_count())
1244         menu.set_title(title);
1245
1246     menu.show(true);
1247
1248     if (items)
1249         *items = menu.get_selitems();
1250
1251     return menu.getkey();
1252 }
1253
1254 void display_inventory()
1255 {
1256     InvMenu menu(MF_SINGLESELECT | MF_ALLOW_FORMATTING);
1257     menu.load_inv_items(OSEL_ANY, -1);
1258     menu.set_type(menu_type::invlist);
1259
1260     menu.on_single_selection = [](const MenuEntry& item)
1261     {
1262         unsigned char select = item.hotkeys[0];
1263         const int invidx = letter_to_index(select);
1264         ASSERT(you.inv[invidx].defined());
1265         return describe_item(you.inv[invidx]);
1266     };
1267
1268     menu.show(true);
1269     if (!crawl_state.doing_prev_cmd_again)
1270     {
1271         redraw_screen();
1272         update_screen();
1273     }
1274 }
1275
1276 // Reads in digits for a count and apprends then to val, the
1277 // return value is the character that stopped the reading.
1278 static unsigned char _get_invent_quant(unsigned char keyin, int &quant)
1279 {
1280     quant = keyin - '0';
1281
1282     while (true)
1283     {
1284         keyin = get_ch();
1285
1286         if (!isadigit(keyin))
1287             break;
1288
1289         quant *= 10;
1290         quant += (keyin - '0');
1291
1292         if (quant > 9999999)
1293         {
1294             quant = 9999999;
1295             keyin = '\0';
1296             break;
1297         }
1298     }
1299
1300     return keyin;
1301 }
1302
1303 static string _drop_selitem_text(const vector<MenuEntry*> *s)
1304 {
1305     bool extraturns = false;
1306
1307     if (s->empty())
1308         return "";
1309
1310     for (MenuEntry *entry : *s)
1311     {
1312         const item_def *item = static_cast<item_def *>(entry->data);
1313         const int eq = get_equip_slot(item);
1314         if (eq > EQ_WEAPON && eq < NUM_EQUIP)
1315         {
1316             extraturns = true;
1317             break;
1318         }
1319     }
1320
1321     return make_stringf(" (%u%s turn%s)",
1322                         (unsigned int)s->size(),
1323                         extraturns? "+" : "",
1324                         s->size() > 1? "s" : "");
1325 }
1326
1327 static string _drop_prompt(bool as_menu_title, bool menu_autopickup_mode)
1328 {
1329     string prompt_base;
1330
1331     if (as_menu_title && menu_autopickup_mode)
1332         prompt_base = "Drop (and turn off autopickup for) what? ";
1333     else if (as_menu_title)
1334         prompt_base = "Drop what?                               ";
1335     else
1336         prompt_base = "Drop what? ";
1337     return prompt_base + slot_description()
1338 #ifdef TOUCH_UI
1339                           + " (<Enter> or tap header to drop)";
1340 #else
1341                           + " (_ for help)";
1342 #endif
1343 }
1344
1345 static string _drop_menu_titlefn(const Menu *m, const string &)
1346 {
1347     const InvMenu *invmenu = static_cast<const InvMenu *>(m);
1348     return _drop_prompt(true, invmenu->mode_special_drop());
1349 }
1350
1351 /**
1352  * Prompt the player to select zero or more items to drop.
1353  * TODO: deduplicate/merge with prompt_invent_item().
1354  *
1355  * @param   Items already selected to drop.
1356  * @return  The total set of items the player's chosen to drop.
1357  */
1358 vector<SelItem> prompt_drop_items(const vector<SelItem> &preselected_items)
1359 {
1360     unsigned char  keyin = '?';
1361     int            ret = PROMPT_ABORT;
1362
1363     bool           need_redraw = false;
1364     bool           need_prompt = true;
1365     bool           need_getch  = false;
1366
1367     vector<SelItem> items;
1368     int count = -1;
1369     while (true)
1370     {
1371         if (need_redraw && !crawl_state.doing_prev_cmd_again)
1372         {
1373             redraw_screen();
1374             update_screen();
1375             clear_messages();
1376         }
1377
1378         if (need_prompt)
1379         {
1380             const string prompt = _drop_prompt(false, false);
1381             mprf(MSGCH_PROMPT, "%s (<w>?</w> for menu, <w>Esc</w> to quit)",
1382                  prompt.c_str());
1383         }
1384
1385         if (need_getch)
1386             keyin = get_ch();
1387
1388         need_redraw = false;
1389         need_prompt = true;
1390         need_getch  = true;
1391
1392         if (keyin == '_')
1393             show_specific_help("pick-up");
1394         else if (keyin == '?' || keyin == '*' || keyin == ',')
1395         {
1396             // The "view inventory listing" mode.
1397             const int ch = _invent_select("",
1398                                           menu_type::drop,
1399                                           OSEL_ANY,
1400                                           -1,
1401                                           MF_MULTISELECT | MF_ALLOW_FILTER,
1402                                           _drop_menu_titlefn,
1403                                           &items,
1404                                           &Options.drop_filter,
1405                                           _drop_selitem_text,
1406                                           &preselected_items);
1407
1408             if (key_is_escape(ch))
1409             {
1410                 keyin       = ch;
1411                 need_prompt = false;
1412                 need_getch  = false;
1413             }
1414             else
1415             {
1416                 keyin       = 0;
1417                 need_prompt = true;
1418                 need_getch  = true;
1419             }
1420
1421             if (!items.empty())
1422             {
1423                 if (!crawl_state.doing_prev_cmd_again)
1424                 {
1425                     redraw_screen();
1426                     update_screen();
1427                     clear_messages();
1428                 }
1429
1430                 for (SelItem &sel : items)
1431                     sel.slot = letter_to_index(sel.slot);
1432                 return items;
1433             }
1434
1435             need_redraw = !(keyin == '?' || keyin == '*'
1436                             || keyin == ',' || keyin == '+');
1437         }
1438         else if (isadigit(keyin))
1439         {
1440             // The "read in quantity" mode
1441             keyin = _get_invent_quant(keyin, count);
1442
1443             need_prompt = false;
1444             need_getch  = false;
1445         }
1446         else if (key_is_escape(keyin)
1447                 || (Options.easy_quit_item_prompts && keyin == ' '))
1448         {
1449             ret = PROMPT_ABORT;
1450             break;
1451         }
1452         else if (isaalpha(keyin))
1453         {
1454             ret = letter_to_index(keyin);
1455
1456             if (!you.inv[ret].defined())
1457                 mpr("You don't have any such object.");
1458             else
1459                 break;
1460         }
1461         else if (keyin == ';')
1462         {
1463             ret = you.last_unequip;
1464             break;
1465         }
1466         else if (!isspace(keyin))
1467         {
1468             // We've got a character we don't understand...
1469             canned_msg(MSG_HUH);
1470         }
1471         else
1472         {
1473             // We're going to loop back up, so don't draw another prompt.
1474             need_prompt = false;
1475         }
1476     }
1477
1478     if (ret != PROMPT_ABORT)
1479         items.emplace_back(ret, count, &you.inv[ret]);
1480     return items;
1481 }
1482
1483 static bool item_matches_digit_inscription(item_def &item, char digit, operation_types oper)
1484 {
1485     const string& r(item.inscription);
1486     const char iletter = static_cast<char>(oper);
1487     for (unsigned int j = 0; j + 2 < r.size(); ++j)
1488         if (r[j] == '@' && (r[j+1] == iletter || r[j+1] == '*') && r[j+2] == digit)
1489             return true;
1490     return false;
1491 }
1492
1493 item_def *digit_inscription_to_item(char digit, operation_types oper)
1494 {
1495     for (int i = 0; i < ENDOFPACK; ++i)
1496         if (you.inv[i].defined()
1497                 && item_matches_digit_inscription(you.inv[i], digit, oper))
1498         {
1499             return &you.inv[i];
1500         }
1501
1502     for (stack_iterator si(you.pos(), true); si; ++si)
1503         if (item_matches_digit_inscription(*si, digit, oper))
1504             return &*si;
1505
1506     return nullptr;
1507 }
1508
1509 static bool _has_warning_inscription(const item_def& item,
1510                              operation_types oper)
1511 {
1512     const char iletter = static_cast<char>(oper);
1513
1514     const string& r(item.inscription);
1515     for (unsigned int i = 0; i + 1 < r.size(); ++i)
1516     {
1517         if (r[i] == '!')
1518         {
1519             if (r[i+1] == iletter || r[i+1] == '*')
1520                 return true;
1521             else if (oper == OPER_ZAP && r[i+1] == 'z') // for the 0.3.4. keys
1522                 return true;
1523             else if (oper == OPER_EVOKE
1524                      && (r[i+1] == 'V' || toalower(r[i+1]) == 'z'))
1525             {
1526                 return true;
1527             }
1528         }
1529     }
1530
1531     return false;
1532 }
1533
1534 // In order to equip this item, we may need to remove an old item in the
1535 // corresponding slot which has a warning inscription. If this is the case,
1536 // prompt the user for confirmation.
1537 bool check_old_item_warning(const item_def& item,
1538                              operation_types oper)
1539 {
1540     item_def old_item;
1541     string prompt;
1542     bool penance = false;
1543     if (oper == OPER_WIELD) // can we safely unwield old item?
1544     {
1545         if (!you.weapon())
1546             return true;
1547
1548         int equip = you.equip[EQ_WEAPON];
1549         if (equip == -1 || item.link == equip)
1550             return true;
1551
1552         old_item = *you.weapon();
1553         if (!needs_handle_warning(old_item, OPER_WIELD, penance))
1554             return true;
1555
1556         prompt += "Really unwield ";
1557     }
1558     else if (oper == OPER_WEAR) // can we safely take off old item?
1559     {
1560         if (item.base_type != OBJ_ARMOUR)
1561             return true;
1562
1563         equipment_type eq_slot = get_armour_slot(item);
1564         int equip = you.equip[eq_slot];
1565         if (equip == -1 || item.link == equip)
1566             return true;
1567
1568         old_item = you.inv[you.equip[eq_slot]];
1569
1570         if (!needs_handle_warning(old_item, OPER_TAKEOFF, penance))
1571             return true;
1572
1573         prompt += "Really take off ";
1574     }
1575     else if (oper == OPER_PUTON) // can we safely remove old item?
1576     {
1577         if (item.base_type != OBJ_JEWELLERY)
1578             return true;
1579
1580         if (jewellery_is_amulet(item))
1581         {
1582             int equip = you.equip[EQ_AMULET];
1583             if (equip == -1 || item.link == equip)
1584                 return true;
1585
1586             old_item = you.inv[equip];
1587             if (!needs_handle_warning(old_item, OPER_TAKEOFF, penance))
1588                 return true;
1589
1590             prompt += "Really remove ";
1591         }
1592         else // rings handled in prompt_ring_to_remove
1593             return true;
1594     }
1595     else // anything else doesn't have a counterpart
1596         return true;
1597
1598     // now ask
1599     prompt += old_item.name(DESC_INVENTORY);
1600     prompt += "?";
1601     if (penance)
1602         prompt += " This could place you under penance!";
1603     return yesno(prompt.c_str(), false, 'n');
1604 }
1605
1606 static string _operation_verb(operation_types oper)
1607 {
1608     switch (oper)
1609     {
1610     case OPER_WIELD:          return "wield";
1611     case OPER_QUAFF:          return "quaff";
1612     case OPER_DROP:           return "drop";
1613     case OPER_TAKEOFF:        return "take off";
1614     case OPER_WEAR:           return "wear";
1615     case OPER_PUTON:          return "put on";
1616     case OPER_REMOVE:         return "remove";
1617     case OPER_READ:           return "read";
1618     case OPER_MEMORISE:       return "memorise from";
1619     case OPER_ZAP:            return "zap";
1620     case OPER_FIRE:           return "fire";
1621     case OPER_EVOKE:          return "evoke";
1622     case OPER_DESTROY:        return "destroy";
1623     case OPER_QUIVER:         return "quiver";
1624     case OPER_ANY:
1625     default:
1626         return "choose";
1627     }
1628 }
1629
1630 static bool _is_wielded(const item_def &item)
1631 {
1632     int equip = you.equip[EQ_WEAPON];
1633     return equip != -1 && item.link == equip;
1634 }
1635
1636 static bool _is_known_no_tele_item(const item_def &item)
1637 {
1638     if (!is_artefact(item))
1639         return false;
1640
1641     return artefact_known_property(item, ARTP_PREVENT_TELEPORTATION);
1642 }
1643
1644 bool needs_notele_warning(const item_def &item, operation_types oper)
1645 {
1646     return (oper == OPER_PUTON || oper == OPER_WEAR
1647                 || oper == OPER_WIELD && !_is_wielded(item))
1648                 && (_is_known_no_tele_item(item) && you.duration[DUR_TELEPORT]);
1649 }
1650
1651 bool needs_handle_warning(const item_def &item, operation_types oper,
1652                           bool &penance)
1653 {
1654     if (_has_warning_inscription(item, oper))
1655         return true;
1656
1657     // Curses first.
1658     if (item_known_cursed(item)
1659         && (oper == OPER_WIELD && is_weapon(item) && !_is_wielded(item)
1660             || oper == OPER_PUTON || oper == OPER_WEAR))
1661     {
1662         return true;
1663     }
1664
1665     // The consequences of evokables are generally known.
1666     if (item.base_type == OBJ_MISCELLANY
1667         && oper == OPER_EVOKE && god_hates_item(item))
1668     {
1669         penance = true;
1670         return true;
1671     }
1672
1673     // Everything else depends on knowing the item subtype/brand.
1674     if (!item_type_known(item))
1675         return false;
1676
1677     if (oper == OPER_REMOVE
1678         && item.is_type(OBJ_JEWELLERY, AMU_FAITH)
1679         && !(you_worship(GOD_RU) && you.piety >= piety_breakpoint(5))
1680         && !you_worship(GOD_GOZAG)
1681         && !you_worship(GOD_NO_GOD)
1682         && !you_worship(GOD_XOM))
1683     {
1684         return true;
1685     }
1686
1687     if (needs_notele_warning(item, oper))
1688         return true;
1689
1690     if (oper == OPER_ATTACK && god_hates_item(item)
1691 #if TAG_MAJOR_VERSION == 34
1692         && !you_worship(GOD_PAKELLAS)
1693 #endif
1694        )
1695     {
1696         penance = true;
1697         return true;
1698     }
1699
1700     if (oper == OPER_WIELD // unwielding uses OPER_WIELD too
1701         && is_weapon(item))
1702     {
1703         if (get_weapon_brand(item) == SPWPN_DISTORTION
1704             && !have_passive(passive_t::safe_distortion))
1705         {
1706             return true;
1707         }
1708
1709         if (is_artefact(item) && artefact_property(item, ARTP_CONTAM))
1710         {
1711             if (_is_wielded(item) && you_worship(GOD_ZIN))
1712                 penance = true;
1713             return true;
1714         }
1715
1716         if (is_artefact(item) && (artefact_property(item, ARTP_DRAIN)
1717                                   || artefact_property(item, ARTP_FRAGILE)))
1718         {
1719             return true;
1720         }
1721     }
1722
1723     if (oper == OPER_PUTON || oper == OPER_WEAR || oper == OPER_TAKEOFF
1724         || oper == OPER_REMOVE)
1725     {
1726         if (is_artefact(item) && artefact_property(item, ARTP_CONTAM))
1727         {
1728             if ((oper == OPER_TAKEOFF || oper == OPER_REMOVE)
1729                  && you_worship(GOD_ZIN))
1730             {
1731                 penance = true;
1732             }
1733             return true;
1734         }
1735
1736         if (is_artefact(item) && (artefact_property(item, ARTP_DRAIN)
1737                                   || artefact_property(item, ARTP_FRAGILE)))
1738         {
1739             return true;
1740         }
1741     }
1742
1743     if (oper == OPER_EVOKE && god_hates_item(item))
1744     {
1745         penance = true;
1746         return true;
1747     }
1748
1749     // If you're invis from an item, warn that you're about to get an extra dose
1750     // of contam from removing it. This check is rough, since we need to
1751     // establish that the operation is a removal, the item being removed is in
1752     // fact the +Invis one, and no other +Invis sources exist, and the player
1753     // is currently invis from +Invis.
1754     if ((oper == OPER_TAKEOFF || oper == OPER_REMOVE || (oper == OPER_WIELD && item_is_equipped(item)))
1755         && (
1756                 (is_artefact(item) && artefact_property(item, ARTP_INVISIBLE))
1757                 || (item.base_type == OBJ_ARMOUR && get_armour_ego_type(item) == SPARM_INVISIBILITY)
1758             )
1759         && you.evokable_invis() < 2 // If you've got 2 sources, removing 1 is fine.
1760         && you.duration[DUR_INVIS] > 1
1761         && !you.attribute[ATTR_INVIS_UNCANCELLABLE])
1762     {
1763         return true;
1764     }
1765
1766     return false;
1767 }
1768
1769 // If there are warning inscriptions associated with performing this operation
1770 // on this item, prompt the user for confirmation. Return true if all prompts
1771 // are OK'd.
1772 bool check_warning_inscriptions(const item_def& item,
1773                                  operation_types oper)
1774 {
1775     bool penance = false;
1776     if (item.defined()
1777         && needs_handle_warning(item, oper, penance))
1778     {
1779         // When it's about destroying an item, don't even ask.
1780         // If the player really wants to do that, they'll have
1781         // to remove the inscription.
1782         if (oper == OPER_DESTROY)
1783             return false;
1784
1785         // Common pattern for wield/wear/put:
1786         // - if the player isn't capable of equipping it, return true
1787         //   immediately. No point warning, since the op is impossible.
1788         // - if the item is already worn, treat this as the corresponding
1789         //   unequip operation
1790         if (oper == OPER_WIELD)
1791         {
1792             // Can't use can_wield in item-use.cc because it wants
1793             // a non-const item_def.
1794             if (!you.can_wield(item))
1795                 return true;
1796
1797             int equip = you.equip[EQ_WEAPON];
1798             if (equip != -1 && item.link == equip)
1799                 return check_old_item_warning(item, oper);
1800         }
1801         else if (oper == OPER_WEAR)
1802         {
1803             if (!can_wear_armour(item, false, false))
1804                 return true;
1805
1806             int equip = you.equip[get_armour_slot(item)];
1807             if (equip != -1 && item.link == equip)
1808                 return check_old_item_warning(item, oper);
1809         }
1810         else if (oper == OPER_PUTON)
1811         {
1812             if (item.base_type != OBJ_JEWELLERY)
1813                 return true;
1814
1815             if (jewellery_is_amulet(item))
1816             {
1817                 int equip = you.equip[EQ_AMULET];
1818                 if (equip != -1 && item.link == equip)
1819                     return check_old_item_warning(item, oper);
1820             }
1821             else
1822             {
1823                 for (int slots = EQ_FIRST_JEWELLERY; slots <= EQ_LAST_JEWELLERY; ++slots)
1824                 {
1825                     if (slots == EQ_AMULET)
1826                         continue;
1827
1828                     int equip = you.equip[slots];
1829                     if (equip != -1 && item.link == equip)
1830                         return check_old_item_warning(item, oper);
1831                 }
1832             }
1833         }
1834         else if (oper == OPER_REMOVE || oper == OPER_TAKEOFF)
1835         {
1836             // Don't ask if it will fail anyway.
1837             if (item.cursed())
1838                 return true;
1839         }
1840
1841         // XXX: duplicates a check in delay.cc:_finish_delay()
1842         string prompt = "Really " + _operation_verb(oper) + " ";
1843         prompt += (in_inventory(item) ? item.name(DESC_INVENTORY)
1844                                       : item.name(DESC_A));
1845         if (needs_notele_warning(item, oper)
1846             && item_ident(item, ISFLAG_KNOW_TYPE))
1847         {
1848             prompt += " while about to teleport";
1849         }
1850         prompt += "?";
1851         if (penance)
1852             prompt += " This could place you under penance!";
1853         return yesno(prompt.c_str(), false, 'n')
1854                && check_old_item_warning(item, oper);
1855     }
1856     else
1857         return check_old_item_warning(item, oper);
1858 }
1859
1860 /**
1861  * Prompts the user for an item.
1862  *
1863  * Prompts the user for an item, handling the '?' and '*' listings,
1864  * and returns the inventory slot to the caller (which if
1865  * must_exist is true (the default) will be an assigned item), with
1866  * a positive quantity.
1867  *
1868  * Note: Does not check if the item is appropriate.
1869  *
1870  * @param prompt           The question to ask the user.
1871  * @param mtype            The menu type.
1872  * @param type_expect      The object_class_type or object_selector for
1873  *                         items to be listed.
1874  * @param oper             The operation_type that will be used on the result.
1875  *                         Modifies some checks, including applicability of
1876  *                         warning inscriptions.
1877  * @param flags            See comments on invent_prompt_flags.
1878  * @param other_valid_char A character that, if not '\0', will cause
1879  *                         PROMPT_GOT_SPECIAL to be returned when pressed.
1880  *
1881  * @return  the inventory slot of an item or one of the following special values
1882  *          - PROMPT_ABORT:       if the player hits escape.
1883  *          - PROMPT_GOT_SPECIAL: if the player hits the "other_valid_char".
1884  *          - PROMPT_NOTHING:     if there are no matching items.
1885  */
1886 int prompt_invent_item(const char *prompt,
1887                        menu_type mtype, int type_expect,
1888                        operation_types oper,
1889                        invent_prompt_flags flags,
1890                        const char other_valid_char)
1891 {
1892     const bool do_warning = !(flags & invprompt_flag::no_warning);
1893     const bool allow_list_known = !(flags & invprompt_flag::hide_known);
1894     const bool must_exist = !(flags & invprompt_flag::unthings_ok);
1895     const bool auto_list = !(flags & invprompt_flag::manual_list);
1896     const bool allow_easy_quit = !(flags & invprompt_flag::escape_only);
1897
1898     if (!any_items_of_type(type_expect) && type_expect != OSEL_WIELD
1899         && type_expect != OSEL_QUIVER_ACTION)
1900     {
1901         mprf(MSGCH_PROMPT, "%s",
1902              no_selectables_message(type_expect).c_str());
1903         return PROMPT_NOTHING;
1904     }
1905
1906     unsigned char  keyin = 0;
1907     int            ret = PROMPT_ABORT;
1908
1909     int current_type_expected = type_expect;
1910     bool           need_redraw = false;
1911     bool           need_prompt = true;
1912     bool           need_getch  = true;
1913
1914     if (auto_list)
1915     {
1916         need_getch = false;
1917
1918         if (any_items_of_type(type_expect))
1919             keyin = '?';
1920         else
1921             keyin = '*';
1922     }
1923
1924     while (true)
1925     {
1926         if (need_redraw && !crawl_state.doing_prev_cmd_again)
1927         {
1928             redraw_screen();
1929             clear_messages();
1930         }
1931
1932         if (need_prompt)
1933         {
1934             mprf(MSGCH_PROMPT, "%s (<w>?</w> for menu, <w>Esc</w> to quit)",
1935                  prompt);
1936         }
1937         else
1938             flush_prev_message();
1939
1940         if (need_getch)
1941             keyin = get_ch();
1942
1943         need_redraw = false;
1944         need_prompt = true;
1945         need_getch  = true;
1946
1947         // Note:  We handle any "special" character first, so that
1948         //        it can be used to override the others.
1949         if (other_valid_char != 0 && keyin == other_valid_char)
1950         {
1951             ret = PROMPT_GOT_SPECIAL;
1952             break;
1953         }
1954
1955         // TODO: it seems like for some uses of this function, `*` shouldn't
1956         // be allowed at all, e.g. evoke.
1957         if (keyin == '?' || keyin == '*')
1958         {
1959             // The "view inventory listing" mode.
1960             vector< SelItem > items;
1961             const auto last_keyin = keyin;
1962             current_type_expected = keyin == '*' ? OSEL_ANY : type_expect;
1963             int mflags = MF_SINGLESELECT | MF_ANYPRINTABLE | MF_NO_SELECT_QTY;
1964             if (other_valid_char == '-')
1965                 mflags |= MF_SPECIAL_MINUS;
1966
1967             while (true)
1968             {
1969                 keyin = _invent_select(prompt, mtype, current_type_expected, -1,
1970                                        mflags, nullptr, &items);
1971
1972                 if (allow_list_known && keyin == '\\')
1973                 {
1974                     check_item_knowledge();
1975                     continue;
1976                 }
1977                 break;
1978             }
1979
1980             // a continue at this point has need_prompt = need_getch = true
1981
1982             // let `?` toggle the menu altogether. If this is a non-autolist,
1983             // return to the prompt, otherwise we will pass escape to the
1984             // abort handling below. (TODO: is this the right behavior?)
1985             // TODO: some versions of _invent_select, such as wield, never
1986             // return '?'. Is this a problem?
1987             if (keyin == '?' || key_is_escape(keyin) && !auto_list)
1988                 continue;
1989
1990             if (keyin == '*')
1991             {
1992                 // let `*` act as a toggle. This is a slightly wacky
1993                 // implementation in that '?' as a toggle does something
1994                 // entirely different...
1995                 need_prompt = need_getch = false;
1996                 if (last_keyin == '*')
1997                     keyin = '?';
1998                 else
1999                     keyin = '*';
2000                 continue;
2001             }
2002
2003             if (other_valid_char != 0 && keyin == other_valid_char)
2004             {
2005                 // need to handle overrides...ugly code duplication
2006                 ret = PROMPT_GOT_SPECIAL;
2007                 break;
2008             }
2009         }
2010
2011         if (isadigit(keyin))
2012         {
2013             // scan for our item
2014             item_def *item = digit_inscription_to_item(keyin, oper);
2015             if (item && in_inventory(*item))
2016             {
2017                 ret = item->link;
2018                 if (!do_warning || check_warning_inscriptions(*item, oper))
2019                     break;
2020             }
2021         }
2022         else if (key_is_escape(keyin)
2023                  || (Options.easy_quit_item_prompts
2024                      && allow_easy_quit && keyin == ' '))
2025         {
2026             ret = PROMPT_ABORT;
2027             break;
2028         }
2029         else if (allow_list_known && keyin == '\\')
2030         {
2031             check_item_knowledge();
2032             keyin = '?';
2033             need_getch = false;
2034         }
2035         else if (isaalpha(keyin))
2036         {
2037             ret = letter_to_index(keyin);
2038
2039             if (must_exist && !you.inv[ret].defined())
2040                 mpr("You don't have any such object.");
2041             else if (must_exist && !item_is_selected(you.inv[ret],
2042                                                      current_type_expected))
2043             {
2044                 mpr("That's the wrong kind of item! (Use * to select it.)");
2045             }
2046             else if (!do_warning || check_warning_inscriptions(you.inv[ret], oper))
2047                 break;
2048         }
2049         else if (keyin == ';')
2050         {
2051             ret = you.last_unequip;
2052             break;
2053         }
2054         else if (!isspace(keyin))
2055         {
2056             // We've got a character we don't understand...
2057             canned_msg(MSG_HUH);
2058         }
2059         else
2060         {
2061             // We're going to loop back up, so don't draw another prompt.
2062             need_prompt = false;
2063         }
2064     }
2065
2066     return ret;
2067 }
2068
2069 bool prompt_failed(int retval)
2070 {
2071     if (retval != PROMPT_ABORT && retval != PROMPT_NOTHING)
2072         return false;
2073
2074     if (retval == PROMPT_ABORT)
2075         canned_msg(MSG_OK);
2076
2077     crawl_state.cancel_cmd_repeat();
2078
2079     return true;
2080 }
2081
2082 // Most items are wieldable, but this function check for items that needs to be
2083 // wielded to be used normally.
2084 bool item_is_wieldable(const item_def &item)
2085 {
2086     return is_weapon(item) && you.species != SP_FELID;
2087 }
2088
2089 /// Does the item only serve to produce summons or allies?
2090 static bool _item_ally_only(const item_def &item)
2091 {
2092     if (item.base_type == OBJ_WANDS)
2093         return item.sub_type == WAND_ENSLAVEMENT;
2094     else if (item.base_type == OBJ_MISCELLANY)
2095     {
2096         switch (item.sub_type)
2097         {
2098         case MISC_PHANTOM_MIRROR:
2099         case MISC_HORN_OF_GERYON:
2100         case MISC_BOX_OF_BEASTS:
2101             return true;
2102         default:
2103             return false;
2104         }
2105     }
2106     return false;
2107 }
2108
2109 /**
2110  * Return whether an item can be evoked.
2111  *
2112  * @param item      The item to check
2113  * @param unskilled Do items that don't use Evocations skill (weapons of
2114  *                  reaching and tremorstones) count?
2115  * @param msg       Whether we need to print a message.
2116  * @param equip     When false, ignore wield and meld requirements.
2117  */
2118 bool item_is_evokable(const item_def &item, bool unskilled,
2119                       bool msg, bool equip)
2120 {
2121     const string error = item_is_melded(item)
2122             ? "Your " + item.name(DESC_QUALNAME) + " is melded into your body."
2123             : "That item can only be evoked when wielded.";
2124
2125     const bool no_evocables = you.get_mutation_level(MUT_NO_ARTIFICE);
2126     const char* const no_evocable_error = "You cannot evoke magical items.";
2127
2128     if (is_unrandom_artefact(item))
2129     {
2130         const unrandart_entry* entry = get_unrand_entry(item.unrand_idx);
2131
2132         if ((entry->evoke_func || entry->targeted_evoke_func)
2133             && item_type_known(item))
2134         {
2135             if (no_evocables)
2136             {
2137                 if (msg)
2138                     mpr(no_evocable_error);
2139                 return false;
2140             }
2141
2142             if (item_is_equipped(item) && !item_is_melded(item) || !equip)
2143                 return true;
2144
2145             if (msg)
2146                 mpr(error);
2147
2148             return false;
2149         }
2150         // Unrandart might still be evokable (e.g., reaching)
2151     }
2152
2153     if (no_evocables
2154         && item.base_type != OBJ_WEAPONS // reaching is ok.
2155         && !(item.base_type == OBJ_MISCELLANY
2156              && item.sub_type == MISC_ZIGGURAT)) // zigfigs are OK.
2157     {
2158         // the rest are forbidden under sac evocables.
2159         if (msg)
2160             mpr(no_evocable_error);
2161         return false;
2162     }
2163
2164     // TODO: check other summoning constraints here?
2165     if (_item_ally_only(item) && you.has_mutation(MUT_NO_LOVE))
2166     {
2167         if (msg)
2168             mpr("That item cannot be used by those hated by all!");
2169         return false;
2170     }
2171
2172     const bool wielded = !equip || you.equip[EQ_WEAPON] == item.link
2173                                    && !item_is_melded(item);
2174
2175     switch (item.base_type)
2176     {
2177     case OBJ_WANDS:
2178         return true;
2179
2180     // TODO: move these out of evoke
2181     case OBJ_WEAPONS:
2182         if ((!wielded || !unskilled) && !msg)
2183             return false;
2184
2185         // XX code duplication with evoke_check
2186         if (unskilled
2187             && (weapon_reach(item) > REACH_NONE && item_type_known(item)
2188                 || you.weapon() && is_range_weapon(*you.weapon())))
2189         {
2190             if (!wielded)
2191             {
2192                 if (msg)
2193                     mpr(error);
2194                 return false;
2195             }
2196             return true;
2197         }
2198
2199         if (msg)
2200             mpr("That item cannot be evoked!");
2201         return false;
2202
2203 #if TAG_MAJOR_VERSION == 34
2204     case OBJ_MISCELLANY:
2205         if (item.sub_type != MISC_BUGGY_LANTERN_OF_SHADOWS
2206             && item.sub_type != MISC_BUGGY_EBONY_CASKET)
2207         {
2208             return true;
2209         }
2210         // removed items fallthrough to failure
2211 #endif
2212
2213     default:
2214         if (msg)
2215             mpr("That item cannot be evoked!");
2216         return false;
2217     }
2218 }
2219
2220 /**
2221  * What xp-charged evocable items is the player currently devoting XP to, if
2222  * any?
2223  *
2224  * @param[out] evokers  A vector, to be filled with a list of the elemental
2225  *                      evokers that the player is currently charging.
2226  *                      (Only one of a type is charged at a time.)
2227  */
2228 void list_charging_evokers(FixedVector<item_def*, NUM_MISCELLANY> &evokers)
2229 {
2230     for (auto &item : you.inv)
2231     {
2232         // can't charge non-evokers, or evokers that are full
2233         if (!is_xp_evoker(item) || evoker_debt(item.sub_type) == 0)
2234             continue;
2235
2236         evokers[item.sub_type] = &item;
2237     }
2238 }
2239
2240 void identify_inventory()
2241 {
2242     for (auto &item : you.inv)
2243     {
2244         if (item.defined())
2245         {
2246             set_ident_type(item, true);
2247             set_ident_flags(item, ISFLAG_IDENT_MASK);
2248         }
2249     }
2250 }