1 /**
2  * @file
3  * @brief Functions for making use of inventory items.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "item-use.h"
9 
10 #include "ability.h"
11 #include "acquire.h"
12 #include "act-iter.h"
13 #include "areas.h"
14 #include "artefact.h"
15 #include "art-enum.h"
16 #include "chardump.h"
17 #include "cloud.h"
18 #include "colour.h"
19 #include "coordit.h"
20 #include "corpse.h"
21 #include "database.h"
22 #include "delay.h"
23 #include "describe.h"
24 #include "directn.h"
25 #include "english.h"
26 #include "env.h"
27 #include "evoke.h"
28 #include "fight.h"
29 #include "god-conduct.h"
30 #include "god-item.h"
31 #include "god-passive.h"
32 #include "hints.h"
33 #include "invent.h"
34 #include "item-prop.h"
35 #include "item-status-flag-type.h"
36 #include "items.h"
37 #include "known-items.h"
38 #include "level-state-type.h"
39 #include "libutil.h"
40 #include "macro.h"
41 #include "makeitem.h"
42 #include "message.h"
43 #include "misc.h"
44 #include "mon-behv.h"
45 #include "mutation.h"
46 #include "nearby-danger.h"
47 #include "orb.h"
48 #include "output.h"
49 #include "player-equip.h"
50 #include "player-stats.h"
51 #include "potion.h"
52 #include "prompt.h"
53 #include "religion.h"
54 #include "shout.h"
55 #include "skills.h"
56 #include "sound.h"
57 #include "spl-book.h"
58 #include "spl-clouds.h"
59 #include "spl-goditem.h"
60 #include "spl-selfench.h"
61 #include "spl-summoning.h"
62 #include "spl-transloc.h"
63 #include "spl-wpnench.h"
64 #include "state.h"
65 #include "stringutil.h"
66 #include "tag-version.h"
67 #include "target.h"
68 #include "terrain.h"
69 #include "throw.h"
70 #include "tiles-build-specific.h"
71 #include "transform.h"
72 #include "uncancel.h"
73 #include "unwind.h"
74 #include "view.h"
75 #include "xom.h"
76 
77 // The menu class for using items from either inv or floor.
78 // Derivative of InvMenu
79 
80 class UseItemMenu : public InvMenu
81 {
82     void populate_list();
83     void populate_menu();
84     bool process_key(int key) override;
85     void repopulate_menu();
86 
87 public:
88     bool display_all;
89     bool is_inventory;
90     int item_type_filter;
91 
92     vector<const item_def*> item_inv;
93     vector<const item_def*> item_floor;
94 
95     // Constructor
96     // Requires int for item filter.
97     // Accepts:
98     //      OBJ_POTIONS
99     //      OBJ_SCROLLS
100     //      OSEL_WIELD
101     //      OBJ_ARMOUR
102     UseItemMenu(int selector, const char* prompt);
103 
104     void toggle_display_all();
105     void toggle_inv_or_floor();
106 };
107 
UseItemMenu(int item_type,const char * prompt)108 UseItemMenu::UseItemMenu(int item_type, const char* prompt)
109     : InvMenu(MF_SINGLESELECT), display_all(false), is_inventory(true),
110       item_type_filter(item_type)
111 {
112     set_title(prompt);
113     populate_list();
114     populate_menu();
115 }
116 
populate_list()117 void UseItemMenu::populate_list()
118 {
119     // Load inv items first
120     for (const auto &item : you.inv)
121     {
122         if (item.defined())
123             item_inv.push_back(&item);
124     }
125     // Load floor items...
126     item_floor = item_list_on_square(you.visible_igrd(you.pos()));
127     // ...only stuff that can go into your inventory though
128     erase_if(item_floor, [=](const item_def* it)
129     {
130         // Did we get them all...?
131         return !it->defined() || item_is_stationary(*it) || item_is_orb(*it)
132             || item_is_spellbook(*it) || it->base_type == OBJ_GOLD
133             || it->base_type == OBJ_RUNES;
134     });
135 
136     // Filter by type
137     if (!display_all)
138     {
139         erase_if(item_inv, [=](const item_def* item)
140         {
141             return !item_is_selected(*item, item_type_filter);
142         });
143         erase_if(item_floor, [=](const item_def* item)
144         {
145             return !item_is_selected(*item, item_type_filter);
146         });
147     }
148 }
149 
populate_menu()150 void UseItemMenu::populate_menu()
151 {
152     if (item_inv.empty())
153         is_inventory = false;
154     else if (item_floor.empty())
155         is_inventory = true;
156 
157     // Entry for unarmed
158     if (item_type_filter == OSEL_WIELD)
159     {
160         string hands_title = " -   unarmed";
161         MenuEntry *hands = new MenuEntry (hands_title, MEL_ITEM);
162         add_entry(hands);
163     }
164 
165     if (!item_inv.empty())
166     {
167         // Only clarify that these are inventory items if there are also floor
168         // items.
169         if (!item_floor.empty())
170         {
171             string subtitle_text = "Inventory Items";
172             if (!is_inventory)
173                 subtitle_text += " (',' to select)";
174             auto subtitle = new MenuEntry(subtitle_text, MEL_TITLE);
175             subtitle->colour = LIGHTGREY;
176             add_entry(subtitle);
177         }
178 
179         // nullptr means using the items' normal hotkeys
180         if (is_inventory)
181             load_items(item_inv);
182         else
183         {
184             load_items(item_inv,
185                         [&](MenuEntry* entry) -> MenuEntry*
186                         {
187                             entry->hotkeys.clear();
188                             return entry;
189                         });
190         }
191     }
192 
193     if (!item_floor.empty())
194     {
195 #ifndef USE_TILE
196         // vertical padding for console
197         if (!item_inv.empty())
198             add_entry(new MenuEntry("", MEL_TITLE));
199 #endif
200         // Load floor items to menu
201         string subtitle_text = "Floor Items";
202         if (is_inventory)
203             subtitle_text += " (',' to select)";
204         auto subtitle = new MenuEntry(subtitle_text, MEL_TITLE);
205         subtitle->colour = LIGHTGREY;
206         add_entry(subtitle);
207 
208         // nullptr means using a-zA-Z
209         if (is_inventory)
210         {
211             load_items(item_floor,
212                         [&](MenuEntry* entry) -> MenuEntry*
213                         {
214                             entry->hotkeys.clear();
215                             return entry;
216                         });
217         }
218         else
219             load_items(item_floor);
220     }
221 }
222 
repopulate_menu()223 void UseItemMenu::repopulate_menu()
224 {
225     deleteAll(items);
226     populate_menu();
227 }
228 
toggle_display_all()229 void UseItemMenu::toggle_display_all()
230 {
231     display_all = !display_all;
232     item_inv.clear();
233     item_floor.clear();
234     populate_list();
235     repopulate_menu();
236 }
237 
toggle_inv_or_floor()238 void UseItemMenu::toggle_inv_or_floor()
239 {
240     is_inventory = !is_inventory;
241     repopulate_menu();
242 }
243 
process_key(int key)244 bool UseItemMenu::process_key(int key)
245 {
246     if (isadigit(key) || key == '*' || key == '\\' || key == ','
247         || key == '-' && item_type_filter == OSEL_WIELD)
248     {
249         lastch = key;
250         return false;
251     }
252     return Menu::process_key(key);
253 }
254 
255 /**
256  * Prompt use of an item from either player inventory or the floor.
257  *
258  * This function generates a menu containing type_expect items based on the
259  * object_class_type to be acted on by another function. First it will list
260  * items in inventory, then items on the floor. If the prompt is cancelled,
261  * false is returned. If something is successfully choosen, then true is
262  * returned, and at function exit the parameter target points to the object the
263  * player chose or to nullptr if the player chose to wield bare hands (this is
264  * only possible if item_type is OSEL_WIELD).
265  *
266  * @param target A pointer by reference to indicate the object selected.
267  * @param item_type The object_class_type or OSEL_* of items to list.
268  * @param oper The operation being done to the selected item.
269  * @param prompt The prompt on the menu title
270  * @param allowcancel If the user tries to cancel out of the prompt, run this
271  *                    function. If it returns false, continue the prompt rather
272  *                    than returning null.
273  *
274  * @return boolean true if something was chosen, false if the process failed and
275  *                 no choice was made
276  */
use_an_item(item_def * & target,int item_type,operation_types oper,const char * prompt,function<bool ()> allowcancel)277 bool use_an_item(item_def *&target, int item_type, operation_types oper,
278                       const char* prompt, function<bool ()> allowcancel)
279 {
280     // First bail if there's nothing appropriate to choose in inv or on floor
281     // (if choosing weapons, then bare hands are always a possibility)
282     if (item_type != OSEL_WIELD && !any_items_of_type(item_type, -1, true))
283     {
284         mprf(MSGCH_PROMPT, "%s",
285              no_selectables_message(item_type).c_str());
286         return false;
287     }
288 
289     bool choice_made = false;
290     item_def *tmp_tgt = nullptr; // We'll change target only if the player
291                                  // actually chooses
292 
293     // Init the menu
294     UseItemMenu menu(item_type, prompt);
295 
296     while (true)
297     {
298         vector<MenuEntry*> sel = menu.show(true);
299         int keyin = menu.getkey();
300 
301         // Handle inscribed item keys
302         if (isadigit(keyin))
303         {
304         // This allows you to select stuff by inscription that is not on the
305         // screen, but only if you couldn't by default use it for that operation
306         // anyway. It's a bit weird, but it does save a '*' keypress for
307         // bread-swingers.
308             tmp_tgt = digit_inscription_to_item(keyin, oper);
309             if (tmp_tgt)
310                 choice_made = true;
311         }
312         else if (keyin == '*')
313         {
314             menu.toggle_display_all();
315             continue;
316         }
317         else if (keyin == ',')
318         {
319             if (Options.easy_floor_use && menu.item_floor.size() == 1)
320             {
321                 choice_made = true;
322                 tmp_tgt = const_cast<item_def*>(menu.item_floor[0]);
323             }
324             else
325             {
326                 menu.toggle_inv_or_floor();
327                 continue;
328             }
329         }
330         else if (keyin == '\\')
331         {
332             check_item_knowledge();
333             continue;
334         }
335         else if (keyin == '-' && menu.item_type_filter == OSEL_WIELD)
336         {
337             choice_made = true;
338             tmp_tgt = nullptr;
339         }
340         else if (!sel.empty())
341         {
342             ASSERT(sel.size() == 1);
343 
344             choice_made = true;
345             auto ie = dynamic_cast<InvEntry *>(sel[0]);
346             tmp_tgt = const_cast<item_def*>(ie->item);
347         }
348 
349         redraw_screen();
350         update_screen();
351         // For weapons, armour, and jewellery this is handled in wield_weapon,
352         // wear_armour, and _puton_item after selection
353         if (item_type != OSEL_WIELD && item_type != OBJ_ARMOUR
354             && item_type != OBJ_JEWELLERY && choice_made && tmp_tgt
355             && !check_warning_inscriptions(*tmp_tgt, oper))
356         {
357             choice_made = false;
358         }
359 
360         if (choice_made)
361             break;
362         else if (allowcancel())
363         {
364             prompt_failed(PROMPT_ABORT);
365             break;
366         }
367         else
368             continue;
369     }
370     if (choice_made)
371         target = tmp_tgt;
372 
373     ASSERT(!choice_made || target || item_type == OSEL_WIELD);
374     return choice_made;
375 }
376 
377 static bool _safe_to_remove_or_wear(const item_def &item, const item_def
378                                     *old_item, bool remove, bool quiet = false);
379 static bool _safe_to_remove_or_wear(const item_def &item,
380                                     bool remove, bool quiet = false);
381 
382 // Rather messy - we've gathered all the can't-wield logic from wield_weapon()
383 // here.
can_wield(const item_def * weapon,bool say_reason,bool ignore_temporary_disability,bool unwield,bool only_known)384 bool can_wield(const item_def *weapon, bool say_reason,
385                bool ignore_temporary_disability, bool unwield, bool only_known)
386 {
387 #define SAY(x) {if (say_reason) { x; }}
388     if (you.melded[EQ_WEAPON] && unwield)
389     {
390         SAY(mpr("Your weapon is melded into your body!"));
391         return false;
392     }
393 
394     if (!ignore_temporary_disability && !form_can_wield(you.form))
395     {
396         SAY(mpr("You can't wield anything in your present form."));
397         return false;
398     }
399 
400     if (!ignore_temporary_disability
401         && you.duration[DUR_EXCRUCIATING_WOUNDS])
402     {
403         SAY(mpr("You cannot break your focus on the pain!"));
404         return false;
405     }
406 
407     if (!ignore_temporary_disability
408         && player_equip_unrand(UNRAND_DEMON_AXE)
409         && you.beheld())
410     {
411         SAY(mpr("Your thirst for blood prevents you from unwielding your "
412                 "weapon!"));
413         return false;
414     }
415 
416     if (!ignore_temporary_disability
417         && you.weapon()
418         && is_weapon(*you.weapon())
419         && you.weapon()->cursed())
420     {
421         SAY(mprf("You can't unwield your weapon%s!",
422                  !unwield ? " to draw a new one" : ""));
423         return false;
424     }
425 
426     // If we don't have an actual weapon to check, return now.
427     if (!weapon)
428         return true;
429 
430     if (you.get_mutation_level(MUT_MISSING_HAND)
431             && you.hands_reqd(*weapon) == HANDS_TWO)
432     {
433         SAY(mprf("You can't wield that without your missing %s.",
434             species::arm_name(you.species).c_str()));
435         return false;
436     }
437 
438     for (int i = EQ_MIN_ARMOUR; i <= EQ_MAX_WORN; i++)
439     {
440         if (you.equip[i] != -1 && &you.inv[you.equip[i]] == weapon)
441         {
442             SAY(mpr("You are wearing that object!"));
443             return false;
444         }
445     }
446 
447     if (!you.could_wield(*weapon, true, true, !say_reason))
448         return false;
449 
450     // All non-weapons only need a shield check.
451     if (weapon->base_type != OBJ_WEAPONS)
452     {
453         if (!ignore_temporary_disability && is_shield_incompatible(*weapon))
454         {
455             SAY(mpr("You can't wield that with a shield."));
456             return false;
457         }
458         else
459             return true;
460     }
461 
462     bool id_brand = false;
463 
464     if (you.undead_or_demonic() && is_holy_item(*weapon)
465         && (item_type_known(*weapon) || !only_known))
466     {
467         if (say_reason)
468         {
469             mpr("This weapon is holy and will not allow you to wield it.");
470             id_brand = true;
471         }
472         else
473             return false;
474     }
475     if (id_brand)
476     {
477         auto wwpn = const_cast<item_def*>(weapon);
478         if (!is_artefact(*weapon) && !is_blessed(*weapon)
479             && !item_type_known(*weapon))
480         {
481             set_ident_flags(*wwpn, ISFLAG_KNOW_TYPE);
482             if (in_inventory(*weapon))
483                 mprf_nocap("%s", weapon->name(DESC_INVENTORY_EQUIP).c_str());
484         }
485         else if (is_artefact(*weapon) && !item_type_known(*weapon))
486             artefact_learn_prop(*wwpn, ARTP_BRAND);
487         return false;
488     }
489 
490     if (!ignore_temporary_disability && is_shield_incompatible(*weapon))
491     {
492         SAY(mpr("You can't wield that with a shield."));
493         return false;
494     }
495 
496     // We can wield this weapon. Phew!
497     return true;
498 
499 #undef SAY
500 }
501 
502 /**
503  * Helper function for wield_weapon, wear_armour, and puton_ring
504  * @param  item    item on floor (where the player is standing)
505  * @param  quiet   print message or not
506  * @return boolean can the player move the item into their inventory, or are
507  *                 they out of space?
508  */
_can_move_item_from_floor_to_inv(const item_def & item)509 static bool _can_move_item_from_floor_to_inv(const item_def &item)
510 {
511     if (inv_count() < ENDOFPACK)
512         return true;
513     if (!is_stackable_item(item))
514     {
515         mpr("You can't carry that many items.");
516         return false;
517     }
518     for (int i = 0; i < ENDOFPACK; ++i)
519     {
520         if (items_stack(you.inv[i], item))
521             return true;
522     }
523     mpr("You can't carry that many items.");
524     return false;
525 }
526 
527 /**
528  * Helper function for wield_weapon, wear_armour, and puton_ring
529  * @param  to_get item on floor (where the player is standing) to move into
530                   inventory
531  * @return int -1 if failure due to already full inventory; otherwise, index in
532  *             you.inv where the item ended up
533  */
_move_item_from_floor_to_inv(const item_def & to_get)534 static int _move_item_from_floor_to_inv(const item_def &to_get)
535 {
536     map<int,int> tmp_l_p = you.last_pickup; // if we need to restore
537     you.last_pickup.clear();
538 
539     if (!move_item_to_inv(to_get.index(), to_get.quantity, true))
540     {
541         mpr("You can't carry that many items.");
542         you.last_pickup = tmp_l_p;
543     }
544     // Get the slot of the last thing picked up
545     // TODO: this is a bit hacky---perhaps it's worth making a function like
546     // move_item_to_inv that returns the slot the item moved into
547     else
548     {
549         ASSERT(you.last_pickup.size() == 1); // Sanity check...
550         return you.last_pickup.begin()->first;
551     }
552     return -1;
553 }
554 
555 /**
556  * Helper function for wield_weapon, wear_armour, and puton_ring
557  * @param  item  item on floor (where the player is standing) or in inventory
558  * @return ret index in you.inv where the item is (either because it was already
559  *               there or just got moved there), or -1 if we tried and failed to
560  *               move the item into inventory
561  */
_get_item_slot_maybe_with_move(const item_def & item)562 static int _get_item_slot_maybe_with_move(const item_def &item)
563 {
564     int ret = item.pos == ITEM_IN_INVENTORY
565         ? item.link : _move_item_from_floor_to_inv(item);
566     return ret;
567 }
568 /**
569  * @param auto_wield false if this was initiated by the wield weapon command (w)
570  *      true otherwise (e.g. switching between ranged and melee with the
571  *      auto_switch option)
572  * @param slot Index into inventory of item to equip. Or one of following
573  *     special values:
574  *      - -1 (default): meaning no particular weapon. We'll either prompt for a
575  *        choice of weapon (if auto_wield is false) or choose one by default.
576  *      - SLOT_BARE_HANDS: equip nothing (unwielding current weapon, if any)
577  */
wield_weapon(bool auto_wield,int slot,bool show_weff_messages,bool show_unwield_msg,bool show_wield_msg,bool adjust_time_taken)578 bool wield_weapon(bool auto_wield, int slot, bool show_weff_messages,
579                   bool show_unwield_msg, bool show_wield_msg,
580                   bool adjust_time_taken)
581 {
582     // Abort immediately if there's some condition that could prevent wielding
583     // weapons.
584     if (!can_wield(nullptr, true, false, slot == SLOT_BARE_HANDS))
585         return false;
586 
587     item_def *to_wield = &you.inv[0]; // default is 'a'
588         // we'll set this to nullptr to indicate bare hands
589 
590     if (auto_wield)
591     {
592         if (to_wield == you.weapon()
593             || you.equip[EQ_WEAPON] == -1 && !item_is_wieldable(*to_wield))
594         {
595             to_wield = &you.inv[1];      // backup is 'b'
596         }
597 
598         if (slot != -1)         // allow external override
599         {
600             if (slot == SLOT_BARE_HANDS)
601                 to_wield = nullptr;
602             else
603                 to_wield = &you.inv[slot];
604         }
605     }
606 
607     if (to_wield)
608     {
609     // Prompt if not using the auto swap command
610         if (!auto_wield)
611         {
612             if (!use_an_item(to_wield, OSEL_WIELD, OPER_WIELD, "Wield "
613                              "which item (- for none, * to show all)?"))
614             {
615                 return false;
616             }
617     // We abort if trying to wield from the floor with full inventory. We could
618     // try something more sophisticated, e.g., drop the currently held weapon,
619     // but that's surely not always what's wanted, and the problem persists if
620     // the player's hands are empty. For now, let's stick with simple behaviour
621     // over trying to guess what the player would like.
622             if (to_wield && to_wield->pos != ITEM_IN_INVENTORY
623                 && !_can_move_item_from_floor_to_inv(*to_wield))
624             {
625                 return false;
626             }
627         }
628 
629     // If autowielding and the swap slot has a bad or invalid item in it, the
630     // swap will be to bare hands.
631         else if (!to_wield->defined() || !item_is_wieldable(*to_wield))
632             to_wield = nullptr;
633     }
634 
635     // Reset the warning counter. We do this before the rewield check to
636     // provide a (slightly hacky) way to let players reset this without
637     // unwielding. (TODO: better ui?)
638     you.received_weapon_warning = false;
639 
640     if (to_wield && to_wield == you.weapon())
641     {
642         if (Options.equip_unequip)
643             to_wield = nullptr;
644         else
645         {
646             mpr("You are already wielding that!");
647             return true;
648         }
649     }
650 
651     if (!to_wield)
652     {
653         if (const item_def* wpn = you.weapon())
654         {
655             bool penance = false;
656             // Can we safely unwield this item?
657             if (needs_handle_warning(*wpn, OPER_WIELD, penance))
658             {
659                 string prompt =
660                     "Really unwield " + wpn->name(DESC_INVENTORY) + "?";
661                 if (penance)
662                     prompt += " This could place you under penance!";
663 
664                 if (!yesno(prompt.c_str(), false, 'n'))
665                 {
666                     canned_msg(MSG_OK);
667                     return false;
668                 }
669             }
670 
671             // check if you'd get stat-zeroed
672             if (!_safe_to_remove_or_wear(*wpn, true))
673                 return false;
674 
675             if (!unwield_item(show_weff_messages))
676                 return false;
677 
678             if (show_unwield_msg)
679             {
680 #ifdef USE_SOUND
681                 parse_sound(WIELD_NOTHING_SOUND);
682 #endif
683                 canned_msg(MSG_EMPTY_HANDED_NOW);
684             }
685 
686             // Switching to bare hands is extra fast.
687             you.turn_is_over = true;
688             if (adjust_time_taken)
689             {
690                 you.time_taken *= 3;
691                 you.time_taken /= 10;
692             }
693         }
694         else
695             canned_msg(MSG_EMPTY_HANDED_ALREADY);
696 
697         return true;
698     }
699 
700     // By now we're sure we're swapping to a real weapon, not bare hands
701 
702     item_def& new_wpn = *to_wield;
703 
704     // Switching to a launcher while berserk is likely a mistake.
705     if (you.berserk() && is_range_weapon(new_wpn))
706     {
707         string prompt = "You can't shoot while berserk! Really wield " +
708                         new_wpn.name(DESC_INVENTORY) + "?";
709         if (!yesno(prompt.c_str(), false, 'n'))
710         {
711             canned_msg(MSG_OK);
712             return false;
713         }
714     }
715 
716     // Ensure wieldable
717     if (!can_wield(&new_wpn, true))
718         return false;
719 
720     // Really ensure wieldable, even unknown brand
721     if (!can_wield(&new_wpn, true, false, false, false))
722         return false;
723 
724     // At this point, we know it's possible to equip this item. However, there
725     // might be reasons it's not advisable.
726     if (!check_warning_inscriptions(new_wpn, OPER_WIELD))
727     {
728         canned_msg(MSG_OK);
729         return false;
730     }
731 
732     if (!_safe_to_remove_or_wear(new_wpn, you.weapon(), false))
733         return false;
734 
735     // Unwield any old weapon.
736     if (you.weapon())
737     {
738         if (unwield_item(show_weff_messages))
739         {
740             // Enable skills so they can be re-disabled later
741             update_can_currently_train();
742         }
743         else
744             return false;
745     }
746 
747     const unsigned int old_talents = your_talents(false).size();
748 
749     // If it's on the ground, pick it up. Once it's picked up, there should be
750     // no aborting, lest we introduce a way to instantly pick things up
751     // NB we already made sure there was space for the item
752     int item_slot = _get_item_slot_maybe_with_move(new_wpn);
753 
754     // At this point new_wpn is potentially not the right thing anymore (the
755     // thing actually in the player's inventory), that is, in the case where the
756     // player chose something from the floor. So use item_slot from here on.
757 
758     // Go ahead and wield the weapon.
759     equip_item(EQ_WEAPON, item_slot, show_weff_messages);
760 
761     if (show_wield_msg)
762     {
763 #ifdef USE_SOUND
764         parse_sound(WIELD_WEAPON_SOUND);
765 #endif
766         mprf_nocap("%s", you.inv[item_slot].name(DESC_INVENTORY_EQUIP).c_str());
767     }
768 
769     check_item_hint(you.inv[item_slot], old_talents);
770 
771     // Time calculations.
772     if (adjust_time_taken)
773         you.time_taken /= 2;
774 
775     you.wield_change  = true;
776     quiver::on_weapon_changed();
777     you.turn_is_over  = true;
778 
779     return true;
780 }
781 
item_is_worn(int inv_slot)782 bool item_is_worn(int inv_slot)
783 {
784     for (int i = EQ_MIN_ARMOUR; i <= EQ_MAX_WORN; ++i)
785         if (inv_slot == you.equip[i])
786             return true;
787 
788     return false;
789 }
790 
791 /**
792  * Prompt user for carried armour.
793  *
794  * @param mesg Title for the prompt
795  * @param index[out] the inventory slot of the item chosen; not initialised
796  *                   if a valid item was not chosen.
797  * @param oper if equal to OPER_TAKEOFF, only show items relevant to the 'T'
798  *             command.
799  * @return whether a valid armour item was chosen.
800  */
armour_prompt(const string & mesg,int * index,operation_types oper)801 bool armour_prompt(const string & mesg, int *index, operation_types oper)
802 {
803     ASSERT(index != nullptr);
804 
805     if (you.berserk())
806         canned_msg(MSG_TOO_BERSERK);
807     else
808     {
809         int selector = OBJ_ARMOUR;
810         if (oper == OPER_TAKEOFF && !Options.equip_unequip)
811             selector = OSEL_WORN_ARMOUR;
812         int slot = prompt_invent_item(mesg.c_str(), menu_type::invlist,
813                                       selector, oper);
814 
815         if (!prompt_failed(slot))
816         {
817             *index = slot;
818             return true;
819         }
820     }
821 
822     return false;
823 }
824 
825 static const int ARMOUR_EQUIP_DELAY = 5;
826 
827 // If you can't wear a bardings, why not? (If you can, return "".)
_cant_wear_barding_reason(bool ignore_temporary)828 static string _cant_wear_barding_reason(bool ignore_temporary)
829 {
830     if (!you.wear_barding())
831         return "You can't wear that!";
832 
833     if (!ignore_temporary && player_is_shapechanged())
834         return "You can wear that only in your normal form.";
835 
836     return "";
837 }
838 
839 /**
840  * Can you wear this item of armour currently?
841  *
842  * Ignores whether or not an item is equipped in its slot already.
843  * If the item is Lear's hauberk, some of this comment may be incorrect.
844  *
845  * @param item The item. Only the base_type and sub_type really should get
846  *             checked, since you_can_wear passes in a dummy item.
847  * @param verbose Whether to print a message about your inability to wear item.
848  * @param ignore_temporary Whether to take into account forms/fishtail/2handers.
849  *                         Note that no matter what this is set to, all
850  *                         mutations will be taken into account, except for
851  *                         ones from Beastly Appendage, which are only checked
852  *                         if this is false.
853  */
can_wear_armour(const item_def & item,bool verbose,bool ignore_temporary)854 bool can_wear_armour(const item_def &item, bool verbose, bool ignore_temporary)
855 {
856     const object_class_type base_type = item.base_type;
857     if (base_type != OBJ_ARMOUR || you.has_mutation(MUT_NO_ARMOUR))
858     {
859         if (verbose)
860             mpr("You can't wear that!");
861 
862         return false;
863     }
864 
865     const int sub_type = item.sub_type;
866     const equipment_type slot = get_armour_slot(item);
867 
868     if (species::bans_eq(you.species, slot))
869     {
870         if (verbose)
871         {
872             // *if* the species bans body armour, then blame it on wings.
873             // (But don't unconditionally ban armour with this mut.)
874             // XX turn this mut into a two-level mutation?
875             if (slot == EQ_BODY_ARMOUR
876                 && species::mutation_level(you.species, MUT_BIG_WINGS))
877             {
878                 mprf("Your wings%s won't fit in that.",
879                     you.has_mutation(MUT_BIG_WINGS)
880                         ? "" : ", even vestigial as they are,");
881             }
882             else
883                 mpr("You can't wear that!");
884         }
885         return false;
886     }
887 
888     if (sub_type == ARM_BARDING)
889     {
890         const string reason = _cant_wear_barding_reason(ignore_temporary);
891         if (reason == "")
892             return true;
893         if (verbose)
894             mpr(reason);
895         return false;
896     }
897 
898     if (you.get_mutation_level(MUT_MISSING_HAND) && is_shield(item))
899     {
900         if (verbose)
901         {
902             if (you.has_innate_mutation(MUT_TENTACLE_ARMS))
903                 mpr("You need the rest of your tentacles for walking.");
904             else
905                 mprf("You'd need another %s to do that!", you.hand_name(false).c_str());
906         }
907         return false;
908     }
909 
910     if (!ignore_temporary && you.weapon()
911         && is_shield(item)
912         && is_shield_incompatible(*you.weapon(), &item))
913     {
914         if (verbose)
915         {
916             if (you.has_innate_mutation(MUT_TENTACLE_ARMS))
917                 mpr("You need the rest of your tentacles for walking.");
918             else
919             {
920                 // Singular hand should have already been handled above.
921                 mprf("You'd need three %s to do that!",
922                      you.hand_name(true).c_str());
923             }
924         }
925         return false;
926     }
927 
928     // Lear's hauberk covers also head, hands and legs.
929     if (is_unrandom_artefact(item, UNRAND_LEAR))
930     {
931         if (you.wear_barding())
932         {
933             if (verbose)
934                 mpr("The hauberk won't fit over your tail.");
935             return false;
936         }
937 
938         if (!player_has_feet(!ignore_temporary))
939         {
940             if (verbose)
941                 mpr("You have no feet.");
942             return false;
943         }
944 
945         if (you.get_mutation_level(MUT_CLAWS, !ignore_temporary) >= 3)
946         {
947             if (verbose)
948             {
949                 mprf("The hauberk won't fit your %s.",
950                      you.hand_name(true).c_str());
951             }
952             return false;
953         }
954 
955         if (you.get_mutation_level(MUT_HORNS, !ignore_temporary) >= 3
956             || you.get_mutation_level(MUT_ANTENNAE, !ignore_temporary) >= 3)
957         {
958             if (verbose)
959                 mpr("The hauberk won't fit your head.");
960             return false;
961         }
962 
963         if (!ignore_temporary)
964         {
965             for (int s = EQ_HELMET; s <= EQ_BOOTS; s++)
966             {
967                 // No strange race can wear this.
968                 const string parts[] = { "head", you.hand_name(true),
969                                          you.foot_name(true) };
970                 COMPILE_CHECK(ARRAYSZ(parts) == EQ_BOOTS - EQ_HELMET + 1);
971 
972                 // Auto-disrobing would be nice.
973                 if (you.equip[s] != -1)
974                 {
975                     if (verbose)
976                     {
977                         mprf("You'd need your %s free.",
978                              parts[s - EQ_HELMET].c_str());
979                     }
980                     return false;
981                 }
982 
983                 if (!get_form()->slot_available(s))
984                 {
985                     if (verbose)
986                     {
987                         mprf("The hauberk won't fit your %s.",
988                              parts[s - EQ_HELMET].c_str());
989                     }
990                     return false;
991                 }
992             }
993         }
994     }
995     else if (slot >= EQ_HELMET && slot <= EQ_BOOTS
996              && !ignore_temporary
997              && player_equip_unrand(UNRAND_LEAR, true))
998     {
999         // The explanation is iffy for loose headgear, especially crowns:
1000         // kings loved hooded hauberks, according to portraits.
1001         if (verbose)
1002             mpr("You can't wear this over your hauberk.");
1003         return false;
1004     }
1005 
1006     size_type player_size = you.body_size(PSIZE_TORSO, ignore_temporary);
1007     int bad_size = fit_armour_size(item, player_size);
1008 #if TAG_MAJOR_VERSION == 34
1009     if (is_unrandom_artefact(item, UNRAND_TALOS))
1010     {
1011         // adjust bad_size for the oversized plate armour
1012         // negative means levels too small, positive means levels too large
1013         bad_size = SIZE_LARGE - player_size;
1014     }
1015 #endif
1016 
1017     if (bad_size)
1018     {
1019         if (verbose)
1020         {
1021             mprf("This armour is too %s for you!",
1022                  (bad_size > 0) ? "big" : "small");
1023         }
1024 
1025         return false;
1026     }
1027 
1028     if (sub_type == ARM_GLOVES)
1029     {
1030         if (you.has_claws(false) == 3)
1031         {
1032             if (verbose)
1033             {
1034                 mprf("You can't wear a glove with your huge claw%s!",
1035                      you.arm_count() == 1 ? "" : "s");
1036             }
1037             return false;
1038         }
1039     }
1040 
1041     if (sub_type == ARM_BOOTS)
1042     {
1043         if (you.get_mutation_level(MUT_HOOVES, false) == 3)
1044         {
1045             if (verbose)
1046                 mpr("You can't wear boots with hooves!");
1047             return false;
1048         }
1049 
1050         if (you.has_talons(false) == 3)
1051         {
1052             if (verbose)
1053                 mpr("Boots don't fit your talons!");
1054             return false;
1055         }
1056 
1057         if (you.wear_barding())
1058         {
1059             if (verbose)
1060             {
1061                 if (you.has_mutation(MUT_CONSTRICTING_TAIL))
1062                     mpr("You have no legs!");
1063                 else
1064                     mpr("Boots don't fit your feet!"); // palentonga
1065             }
1066             return false;
1067         }
1068 
1069         if (!ignore_temporary && you.fishtail)
1070         {
1071             if (verbose)
1072                 mpr("You don't currently have feet!");
1073             return false;
1074         }
1075 
1076         if (you.get_mutation_level(MUT_FLOAT))
1077         {
1078             if (verbose)
1079                 mpr("You have no feet!"); // or legs
1080             return false;
1081         }
1082     }
1083 
1084     if (slot == EQ_HELMET)
1085     {
1086         // Horns 3 & Antennae 3 mutations disallow all headgear
1087         if (you.get_mutation_level(MUT_HORNS, false) == 3)
1088         {
1089             if (verbose)
1090                 mpr("You can't wear any headgear with your large horns!");
1091             return false;
1092         }
1093 
1094         if (you.get_mutation_level(MUT_ANTENNAE, false) == 3)
1095         {
1096             if (verbose)
1097                 mpr("You can't wear any headgear with your large antennae!");
1098             return false;
1099         }
1100 
1101         // Soft helmets (caps and wizard hats) always fit, otherwise.
1102         if (is_hard_helmet(item))
1103         {
1104             if (you.get_mutation_level(MUT_HORNS, false))
1105             {
1106                 if (verbose)
1107                     mpr("You can't wear that with your horns!");
1108                 return false;
1109             }
1110 
1111             if (you.get_mutation_level(MUT_BEAK, false))
1112             {
1113                 if (verbose)
1114                     mpr("You can't wear that with your beak!");
1115                 return false;
1116             }
1117 
1118             if (you.get_mutation_level(MUT_ANTENNAE, false))
1119             {
1120                 if (verbose)
1121                     mpr("You can't wear that with your antennae!");
1122                 return false;
1123             }
1124 
1125             if (species::is_draconian(you.species))
1126             {
1127                 if (verbose)
1128                     mpr("You can't wear that with your reptilian head.");
1129                 return false;
1130             }
1131 
1132             if (you.species == SP_OCTOPODE)
1133             {
1134                 if (verbose)
1135                     mpr("You can't wear that!");
1136                 return false;
1137             }
1138         }
1139     }
1140 
1141     // Can't just use Form::slot_available because of shroom caps.
1142     if (!ignore_temporary && !get_form()->can_wear_item(item))
1143     {
1144         if (verbose)
1145             mpr("You can't wear that in your present form.");
1146         return false;
1147     }
1148 
1149     return true;
1150 }
1151 
1152 static bool _can_takeoff_armour(int item);
1153 
1154 // Like can_wear_armour, but also takes into account currently worn equipment.
1155 // e.g. you may be able to *wear* that robe, but you can't equip it if your
1156 // currently worn armour is cursed, or melded.
1157 // precondition: item is not already worn
_can_equip_armour(const item_def & item)1158 static bool _can_equip_armour(const item_def &item)
1159 {
1160     const object_class_type base_type = item.base_type;
1161     if (base_type != OBJ_ARMOUR)
1162     {
1163         mpr("You can't wear that.");
1164         return false;
1165     }
1166 
1167     const equipment_type slot = get_armour_slot(item);
1168     const int equipped = you.equip[slot];
1169     if (equipped != -1 && !_can_takeoff_armour(equipped))
1170         return false;
1171     return can_wear_armour(item, true, false);
1172 }
1173 
1174 // Try to equip the armour in the given inventory slot (or, if slot is -1,
1175 // prompt for a choice of item, then try to wear it).
wear_armour(int item)1176 bool wear_armour(int item)
1177 {
1178     // Before (possibly) prompting for which item to wear, check for some
1179     // conditions that would make it impossible to wear any type of armour.
1180     // TODO: perhaps also worth checking here whether all available armour slots
1181     // are cursed. Same with jewellery.
1182     if (you.has_mutation(MUT_NO_ARMOUR))
1183     {
1184         mpr("You can't wear anything.");
1185         return false;
1186     }
1187 
1188     if (!form_can_wear())
1189     {
1190         mpr("You can't wear anything in your present form.");
1191         return false;
1192     }
1193 
1194     if (you.berserk())
1195     {
1196         canned_msg(MSG_TOO_BERSERK);
1197         return false;
1198     }
1199 
1200     item_def *to_wear = nullptr;
1201 
1202     if (item == -1)
1203     {
1204         if (!use_an_item(to_wear, OBJ_ARMOUR, OPER_WEAR,
1205                          "Wear which item (* to show all)?"))
1206         {
1207             return false;
1208         }
1209         // use_an_item on armour should never return true and leave to_wear
1210         // nullptr
1211         if (to_wear->pos != ITEM_IN_INVENTORY
1212             && !_can_move_item_from_floor_to_inv(*to_wear))
1213         {
1214             return false;
1215         }
1216     }
1217     else
1218         to_wear = &you.inv[item];
1219 
1220     // First, let's check for any conditions that would make it impossible to
1221     // equip the given item
1222     if (!to_wear->defined())
1223     {
1224         mpr("You don't have any such object.");
1225         return false;
1226     }
1227 
1228     if (to_wear == you.weapon())
1229     {
1230         mpr("You are wielding that object!");
1231         return false;
1232     }
1233 
1234     if (to_wear->pos == ITEM_IN_INVENTORY && item_is_worn(to_wear->link))
1235     {
1236         if (Options.equip_unequip)
1237             // TODO: huh? Why are we inverting the return value?
1238             return !takeoff_armour(to_wear->link);
1239         else
1240         {
1241             mpr("You're already wearing that object!");
1242             return false;
1243         }
1244     }
1245 
1246     if (!_can_equip_armour(*to_wear))
1247         return false;
1248 
1249     // At this point, we know it's possible to equip this item. However, there
1250     // might be reasons it's not advisable. Warn about any dangerous
1251     // inscriptions, giving the player an opportunity to bail out.
1252     if (!check_warning_inscriptions(*to_wear, OPER_WEAR))
1253     {
1254         canned_msg(MSG_OK);
1255         return false;
1256     }
1257 
1258     bool swapping = false;
1259     const equipment_type slot = get_armour_slot(*to_wear);
1260 
1261     if (!_safe_to_remove_or_wear(*to_wear, you.slot_item(slot), false))
1262         return false;
1263 
1264     if ((slot == EQ_CLOAK
1265            || slot == EQ_HELMET
1266            || slot == EQ_GLOVES
1267            || slot == EQ_BOOTS
1268            || slot == EQ_SHIELD
1269            || slot == EQ_BODY_ARMOUR)
1270         && you.equip[slot] != -1)
1271     {
1272         if (!takeoff_armour(you.equip[slot], true))
1273             return false;
1274         swapping = true;
1275     }
1276 
1277     you.turn_is_over = true;
1278 
1279     // If it's on the ground, pick it up. Once it's picked up, there should be
1280     // no aborting
1281     // NB we already made sure there was space for the item
1282     int item_slot = _get_item_slot_maybe_with_move(*to_wear);
1283 
1284     start_delay<EquipOnDelay>(ARMOUR_EQUIP_DELAY - (swapping ? 0 : 1),
1285                                you.inv[item_slot]);
1286 
1287     return true;
1288 }
1289 
_can_takeoff_armour(int item)1290 static bool _can_takeoff_armour(int item)
1291 {
1292     item_def& invitem = you.inv[item];
1293     if (invitem.base_type != OBJ_ARMOUR)
1294     {
1295         mpr("You aren't wearing that!");
1296         return false;
1297     }
1298 
1299     if (you.berserk())
1300     {
1301         canned_msg(MSG_TOO_BERSERK);
1302         return false;
1303     }
1304 
1305     const equipment_type slot = get_armour_slot(invitem);
1306     if (item == you.equip[slot] && you.melded[slot])
1307     {
1308         mprf("%s is melded into your body!",
1309              invitem.name(DESC_YOUR).c_str());
1310         return false;
1311     }
1312 
1313     if (!item_is_worn(item))
1314     {
1315         mpr("You aren't wearing that object!");
1316         return false;
1317     }
1318 
1319     // If we get here, we're wearing the item.
1320     if (invitem.cursed())
1321     {
1322         mprf("%s is stuck to your body!", invitem.name(DESC_YOUR).c_str());
1323         return false;
1324     }
1325     return true;
1326 }
1327 
1328 // TODO: It would be nice if this were made consistent with wear_armour,
1329 // wield_weapon, puton_ring, etc. in terms of taking a default value of -1,
1330 // which has the effect of prompting for an item to take off.
1331 //
1332 /// noask suppresses the "stat zero" prompt.
takeoff_armour(int item,bool noask)1333 bool takeoff_armour(int item, bool noask)
1334 {
1335     if (!_can_takeoff_armour(item))
1336         return false;
1337 
1338     item_def& invitem = you.inv[item];
1339 
1340     // It's possible to take this thing off, but if it would drop a stat
1341     // below 0, we should get confirmation.
1342     if (!noask && !_safe_to_remove_or_wear(invitem, true))
1343         return false;
1344 
1345     const equipment_type slot = get_armour_slot(invitem);
1346 
1347     // TODO: isn't this check covered above by the call to item_is_worn? The
1348     // only way to return false inside this switch would be if the player is
1349     // wearing a hat on their feet or something like that.
1350     switch (slot)
1351     {
1352     case EQ_BODY_ARMOUR:
1353     case EQ_SHIELD:
1354     case EQ_CLOAK:
1355     case EQ_HELMET:
1356     case EQ_GLOVES:
1357     case EQ_BOOTS:
1358         if (item != you.equip[slot])
1359         {
1360             mpr("You aren't wearing that!");
1361             return false;
1362         }
1363         break;
1364 
1365     default:
1366         break;
1367     }
1368 
1369     you.turn_is_over = true;
1370 
1371     start_delay<EquipOffDelay>(ARMOUR_EQUIP_DELAY - 1, invitem);
1372 
1373     return true;
1374 }
1375 
1376 // Returns a list of possible ring slots.
_current_ring_types()1377 static vector<equipment_type> _current_ring_types()
1378 {
1379     vector<equipment_type> ret = species::ring_slots(you.species,
1380                                         you.has_mutation(MUT_MISSING_HAND));
1381 
1382     if (player_equip_unrand(UNRAND_FINGER_AMULET))
1383         ret.push_back(EQ_RING_AMULET);
1384 
1385     erase_if(ret, [](const equipment_type &e)
1386         {
1387             return !get_form()->slot_available(e);
1388         });
1389     return ret;
1390 }
1391 
_current_jewellery_types()1392 static vector<equipment_type> _current_jewellery_types()
1393 {
1394     vector<equipment_type> ret = _current_ring_types();
1395     ret.push_back(EQ_AMULET);
1396     return ret;
1397 }
1398 
_ring_slot_key(equipment_type slot)1399 static char _ring_slot_key(equipment_type slot)
1400 {
1401     switch (slot)
1402     {
1403     case EQ_LEFT_RING:      return '<';
1404     case EQ_RIGHT_RING:     return '>';
1405     case EQ_RING_AMULET:    return '^';
1406     case EQ_RING_ONE:       return '1';
1407     case EQ_RING_TWO:       return '2';
1408     case EQ_RING_THREE:     return '3';
1409     case EQ_RING_FOUR:      return '4';
1410     case EQ_RING_FIVE:      return '5';
1411     case EQ_RING_SIX:       return '6';
1412     case EQ_RING_SEVEN:     return '7';
1413     case EQ_RING_EIGHT:     return '8';
1414     default:
1415         die("Invalid ring slot");
1416     }
1417 }
1418 
_prompt_ring_to_remove()1419 static int _prompt_ring_to_remove()
1420 {
1421     const vector<equipment_type> ring_types = _current_ring_types();
1422     vector<char> slot_chars;
1423     vector<item_def*> rings;
1424     for (auto eq : ring_types)
1425     {
1426         rings.push_back(you.slot_item(eq, true));
1427         ASSERT(rings.back());
1428         slot_chars.push_back(index_to_letter(rings.back()->link));
1429     }
1430 
1431     if (slot_chars.size() + 2 > msgwin_lines() || ui::has_layout())
1432     {
1433         // force a menu rather than a more().
1434         return EQ_NONE;
1435     }
1436 
1437     clear_messages();
1438 
1439     mprf(MSGCH_PROMPT,
1440          "You're wearing all the rings you can. Remove which one?");
1441     mprf(MSGCH_PROMPT, "(<w>?</w> for menu, <w>Esc</w> to cancel)");
1442 
1443     // FIXME: Needs TOUCH_UI version
1444 
1445     for (size_t i = 0; i < rings.size(); i++)
1446     {
1447         string m = "<w>";
1448         const char key = _ring_slot_key(ring_types[i]);
1449         m += key;
1450         if (key == '<')
1451             m += '<';
1452 
1453         m += "</w> or " + rings[i]->name(DESC_INVENTORY);
1454         mprf_nocap("%s", m.c_str());
1455     }
1456     flush_prev_message();
1457 
1458     // Deactivate choice from tile inventory.
1459     // FIXME: We need to be able to get the choice (item letter)n
1460     //        *without* the choice taking action by itself!
1461     int eqslot = EQ_NONE;
1462 
1463     mouse_control mc(MOUSE_MODE_PROMPT);
1464     int c;
1465     do
1466     {
1467         c = getchm();
1468         for (size_t i = 0; i < slot_chars.size(); i++)
1469         {
1470             if (c == slot_chars[i]
1471                 || c == _ring_slot_key(ring_types[i]))
1472             {
1473                 eqslot = ring_types[i];
1474                 c = ' ';
1475                 break;
1476             }
1477         }
1478     } while (!key_is_escape(c) && c != ' ' && c != '?');
1479 
1480     clear_messages();
1481 
1482     if (c == '?')
1483         return EQ_NONE;
1484     else if (key_is_escape(c) || eqslot == EQ_NONE)
1485         return -2;
1486 
1487     return you.equip[eqslot];
1488 }
1489 
1490 // Calculate the stat bonus from an item.
1491 // XXX: This needs to match _stat_modifier() and get_item_description().
_item_stat_bonus(const item_def & item,int & prop_str,int & prop_dex,int & prop_int,bool remove)1492 static void _item_stat_bonus(const item_def &item, int &prop_str,
1493                              int &prop_dex, int &prop_int, bool remove)
1494 {
1495     prop_str = prop_dex = prop_int = 0;
1496 
1497     if (item.base_type == OBJ_JEWELLERY
1498         && item_ident(item, ISFLAG_KNOW_PLUSES))
1499     {
1500         switch (item.sub_type)
1501         {
1502         case RING_STRENGTH:
1503             if (item.plus != 0)
1504                 prop_str = item.plus;
1505             break;
1506         case RING_DEXTERITY:
1507             if (item.plus != 0)
1508                 prop_dex = item.plus;
1509             break;
1510         case RING_INTELLIGENCE:
1511             if (item.plus != 0)
1512                 prop_int = item.plus;
1513             break;
1514         default:
1515             break;
1516         }
1517     }
1518     else if (item.base_type == OBJ_ARMOUR && item_type_known(item))
1519     {
1520         switch (item.brand)
1521         {
1522         case SPARM_STRENGTH:
1523             prop_str = 3;
1524             break;
1525         case SPARM_INTELLIGENCE:
1526             prop_int = 3;
1527             break;
1528         case SPARM_DEXTERITY:
1529             prop_dex = 3;
1530             break;
1531         default:
1532             break;
1533         }
1534     }
1535 
1536     if (is_artefact(item))
1537     {
1538         prop_str += artefact_known_property(item, ARTP_STRENGTH);
1539         prop_int += artefact_known_property(item, ARTP_INTELLIGENCE);
1540         prop_dex += artefact_known_property(item, ARTP_DEXTERITY);
1541     }
1542 
1543     if (!remove)
1544     {
1545         prop_str *= -1;
1546         prop_int *= -1;
1547         prop_dex *= -1;
1548     }
1549 }
1550 
1551 enum class afsz
1552 {
1553     go, // asked the player, who said to to proceed.
1554     stop, // asked the player (or didn't because of "quiet"), who said to stop.
1555     noask // no <1 stats, so not asked.
1556 };
1557 
_abort_for_stat_zero(const item_def & item,int prop_str,int prop_dex,int prop_int,bool remove,bool quiet)1558 static afsz _abort_for_stat_zero(const item_def &item, int prop_str,
1559                                  int prop_dex, int prop_int,  bool remove,
1560                                  bool quiet)
1561 {
1562     stat_type red_stat = NUM_STATS;
1563     if (prop_str >= you.strength() && you.strength() > 0)
1564         red_stat = STAT_STR;
1565     else if (prop_int >= you.intel() && you.intel() > 0)
1566         red_stat = STAT_INT;
1567     else if (prop_dex >= you.dex() && you.dex() > 0)
1568         red_stat = STAT_DEX;
1569 
1570     if (red_stat == NUM_STATS)
1571         return afsz::noask;
1572 
1573     if (quiet)
1574         return afsz::stop;
1575 
1576     string verb = "";
1577     if (remove)
1578     {
1579         if (item.base_type == OBJ_WEAPONS)
1580             verb = "Unwield";
1581         else
1582             verb = "Remov"; // -ing, not a typo
1583     }
1584     else
1585     {
1586         if (item.base_type == OBJ_WEAPONS)
1587             verb = "Wield";
1588         else
1589             verb = "Wear";
1590     }
1591 
1592     string prompt = make_stringf("%sing this item will reduce your %s to zero "
1593                                  "or below. Continue?", verb.c_str(),
1594                                  stat_desc(red_stat, SD_NAME));
1595     if (!yesno(prompt.c_str(), true, 'n', true, false))
1596     {
1597         canned_msg(MSG_OK);
1598         return afsz::stop;
1599     }
1600     return afsz::go;
1601 }
1602 
1603 // Checks whether a to-be-worn or to-be-removed item affects
1604 // character stats and whether wearing/removing it could be fatal.
1605 // If so, warns the player, or just returns false if quiet is true.
_safe_to_remove_or_wear(const item_def & item,const item_def * old_item,bool remove,bool quiet)1606 static bool _safe_to_remove_or_wear(const item_def &item, const item_def
1607                                     *old_item, bool remove, bool quiet)
1608 {
1609     if (remove && !safe_to_remove(item, quiet))
1610         return false;
1611 
1612     int str1 = 0, dex1 = 0, int1 = 0, str2 = 0, dex2 = 0, int2 = 0;
1613     afsz asked = afsz::noask;
1614     if (!remove && old_item)
1615     {
1616         _item_stat_bonus(*old_item, str1, dex1, int1, true);
1617         asked = _abort_for_stat_zero(item, str1, dex1, int1, true, quiet);
1618         if (afsz::stop == asked)
1619             return false;
1620     }
1621     _item_stat_bonus(item, str2, dex2, int2, remove);
1622     return afsz::go == asked
1623         || afsz::stop != _abort_for_stat_zero(item, str1+str2, dex1+dex2,
1624                                               int1+int2, remove, quiet);
1625 }
1626 
_safe_to_remove_or_wear(const item_def & item,bool remove,bool quiet)1627 static bool _safe_to_remove_or_wear(const item_def &item, bool remove,
1628                                     bool quiet)
1629 {
1630     return _safe_to_remove_or_wear(item, 0, remove, quiet);
1631 }
1632 
1633 // Checks whether removing an item would cause flight to end and the
1634 // player to fall to their death.
safe_to_remove(const item_def & item,bool quiet)1635 bool safe_to_remove(const item_def &item, bool quiet)
1636 {
1637     item_def inf = get_item_known_info(item);
1638 
1639     const bool grants_flight =
1640          inf.is_type(OBJ_JEWELLERY, RING_FLIGHT)
1641          || inf.base_type == OBJ_ARMOUR && inf.brand == SPARM_FLYING
1642          || is_artefact(inf)
1643             && artefact_known_property(inf, ARTP_FLY);
1644 
1645     // assumes item can't grant flight twice
1646     const bool removing_ends_flight = you.airborne()
1647                                         && !you.permanent_flight(false)
1648                                         && you.equip_flight() == 1;
1649 
1650     const dungeon_feature_type feat = env.grid(you.pos());
1651 
1652     if (grants_flight && removing_ends_flight
1653         && is_feat_dangerous(feat, false, true))
1654     {
1655         if (!quiet)
1656             mpr("Losing flight right now would be extremely painful!");
1657         return false;
1658     }
1659 
1660     return true;
1661 }
1662 
1663 // Assumptions:
1664 // item is an item in inventory or on the floor where the player is standing
1665 // EQ_LEFT_RING and EQ_RIGHT_RING are both occupied, and item is not
1666 // in one of those slots.
1667 //
1668 // Does not do amulets.
_swap_rings(item_def & to_puton)1669 static bool _swap_rings(item_def& to_puton)
1670 {
1671     vector<equipment_type> ring_types = _current_ring_types();
1672     const int num_rings = ring_types.size();
1673     int unwanted = 0;
1674     int last_inscribed = 0;
1675     int cursed = 0;
1676     int inscribed = 0;
1677     int melded = 0; // Both melded rings and unavailable slots.
1678     int available = 0;
1679     bool all_same = true;
1680     item_def* first_ring = nullptr;
1681     for (auto eq : ring_types)
1682     {
1683         item_def* ring = you.slot_item(eq, true);
1684         if (!you_can_wear(eq, true) || you.melded[eq])
1685             melded++;
1686         else if (ring != nullptr)
1687         {
1688             if (first_ring == nullptr)
1689                 first_ring = ring;
1690             else if (all_same)
1691             {
1692                 if (ring->sub_type != first_ring->sub_type
1693                     || ring->plus  != first_ring->plus
1694                     || is_artefact(*ring) || is_artefact(*first_ring))
1695                 {
1696                     all_same = false;
1697                 }
1698             }
1699 
1700             if (ring->cursed())
1701                 cursed++;
1702             else if (strstr(ring->inscription.c_str(), "=R"))
1703             {
1704                 inscribed++;
1705                 last_inscribed = you.equip[eq];
1706             }
1707             else
1708             {
1709                 available++;
1710                 unwanted = you.equip[eq];
1711             }
1712         }
1713     }
1714 
1715     // If the only swappable rings are inscribed =R, go ahead and use them.
1716     if (available == 0 && inscribed > 0)
1717     {
1718         available += inscribed;
1719         unwanted = last_inscribed;
1720     }
1721 
1722     // We can't put a ring on, because we're wearing all cursed ones.
1723     if (melded == num_rings)
1724     {
1725         // Shouldn't happen, because hogs and bats can't put on jewellery at
1726         // all and thus won't get this far.
1727         mpr("You can't wear that in your present form.");
1728         return false;
1729     }
1730     else if (available == 0)
1731     {
1732         mprf("You're already wearing %s cursed ring%s!%s",
1733              number_in_words(cursed).c_str(),
1734              (cursed == 1 ? "" : "s"),
1735              (cursed > 2 ? " Isn't that enough for you?" : ""));
1736         return false;
1737     }
1738     // The simple case - only one available ring.
1739     // If the jewellery_prompt option is true, always allow choosing the
1740     // ring slot (even if we still have empty slots).
1741     else if (available == 1 && !Options.jewellery_prompt)
1742     {
1743         if (!_safe_to_remove_or_wear(to_puton, &you.inv[unwanted], false))
1744             return false;
1745 
1746         if (!remove_ring(unwanted, false, true))
1747             return false;
1748     }
1749     // We can't put a ring on without swapping - because we found
1750     // multiple available rings.
1751     else
1752     {
1753         // Don't prompt if all the rings are the same.
1754         if (!all_same || Options.jewellery_prompt)
1755             unwanted = _prompt_ring_to_remove();
1756 
1757         if (unwanted == EQ_NONE)
1758         {
1759             // do this here rather than in remove_ring so that the custom
1760             // message is visible.
1761             unwanted = prompt_invent_item(
1762                     "You're wearing all the rings you can. Remove which one?",
1763                     menu_type::invlist, OSEL_UNCURSED_WORN_RINGS, OPER_REMOVE,
1764                     invprompt_flag::no_warning | invprompt_flag::hide_known);
1765         }
1766 
1767         // Cancelled:
1768         if (unwanted < 0)
1769         {
1770             canned_msg(MSG_OK);
1771             return false;
1772         }
1773 
1774         if (!_safe_to_remove_or_wear(to_puton, &you.inv[unwanted], false))
1775             return false;
1776 
1777         if (!remove_ring(unwanted, false, true))
1778             return false;
1779     }
1780 
1781     // Put on the new ring.
1782     start_delay<JewelleryOnDelay>(1, to_puton);
1783 
1784     return true;
1785 }
1786 
_choose_ring_slot()1787 static equipment_type _choose_ring_slot()
1788 {
1789     clear_messages();
1790 
1791     mprf(MSGCH_PROMPT,
1792          "Put ring on which %s? (<w>Esc</w> to cancel)", you.hand_name(false).c_str());
1793 
1794     const vector<equipment_type> slots = _current_ring_types();
1795     for (auto eq : slots)
1796     {
1797         string msg = "<w>";
1798         const char key = _ring_slot_key(eq);
1799         msg += key;
1800         if (key == '<')
1801             msg += '<';
1802 
1803         item_def* ring = you.slot_item(eq, true);
1804         if (ring)
1805             msg += "</w> or " + ring->name(DESC_INVENTORY);
1806         else
1807             msg += "</w> - no ring";
1808 
1809         if (eq == EQ_LEFT_RING)
1810             msg += " (left)";
1811         else if (eq == EQ_RIGHT_RING)
1812             msg += " (right)";
1813         else if (eq == EQ_RING_AMULET)
1814             msg += " (amulet)";
1815         mprf_nocap("%s", msg.c_str());
1816     }
1817     flush_prev_message();
1818 
1819     equipment_type eqslot = EQ_NONE;
1820     mouse_control mc(MOUSE_MODE_PROMPT);
1821     int c;
1822     do
1823     {
1824         c = getchm();
1825         for (auto eq : slots)
1826         {
1827             if (c == _ring_slot_key(eq)
1828                 || (you.slot_item(eq, true)
1829                     && c == index_to_letter(you.slot_item(eq, true)->link)))
1830             {
1831                 eqslot = eq;
1832                 c = ' ';
1833                 break;
1834             }
1835         }
1836     } while (!key_is_escape(c) && c != ' ');
1837 
1838     clear_messages();
1839 
1840     return eqslot;
1841 }
1842 
1843 // Is it possible to put on the given item in a jewellery slot?
1844 // Preconditions:
1845 // - item is not already equipped in a jewellery slot
_can_puton_jewellery(const item_def & item)1846 static bool _can_puton_jewellery(const item_def &item)
1847 {
1848     // TODO: between this function, _puton_item, _swap_rings, and remove_ring,
1849     // there's a bit of duplicated work, and sep. of concerns not clear
1850     if (&item == you.weapon())
1851     {
1852         mpr("You are wielding that object.");
1853         return false;
1854     }
1855 
1856     if (item.base_type != OBJ_JEWELLERY)
1857     {
1858         mpr("You can only put on jewellery.");
1859         return false;
1860     }
1861 
1862     return true;
1863 }
1864 
_can_puton_ring(const item_def & item)1865 static bool _can_puton_ring(const item_def &item)
1866 {
1867     if (!_can_puton_jewellery(item))
1868         return false;
1869     if (!you_can_wear(EQ_RINGS, true))
1870     {
1871         mpr("You can't wear that in your present form.");
1872         return false;
1873     }
1874 
1875     const vector<equipment_type> slots = _current_ring_types();
1876     int melded = 0;
1877     int cursed = 0;
1878     for (auto eq : slots)
1879     {
1880         if (!you_can_wear(eq, true) || you.melded[eq])
1881         {
1882             melded++;
1883             continue;
1884         }
1885         int existing = you.equip[eq];
1886         if (existing != -1 && you.inv[existing].cursed())
1887             cursed++;
1888         else
1889             // We found an available slot. We're done.
1890             return true;
1891     }
1892     // If we got this far, there are no available slots.
1893     if (melded == (int)slots.size())
1894         mpr("You can't wear that in your present form.");
1895     else
1896         mprf("You're already wearing %s cursed ring%s!%s",
1897              number_in_words(cursed).c_str(),
1898              (cursed == 1 ? "" : "s"),
1899              (cursed > 2 ? " Isn't that enough for you?" : ""));
1900     return false;
1901 }
1902 
_can_puton_amulet(const item_def & item)1903 static bool _can_puton_amulet(const item_def &item)
1904 {
1905     if (!_can_puton_jewellery(item))
1906         return false;
1907 
1908     if (!you_can_wear(EQ_AMULET, true))
1909     {
1910         mpr("You can't wear that in your present form.");
1911         return false;
1912     }
1913 
1914     const int existing = you.equip[EQ_AMULET];
1915     if (existing != -1 && you.inv[existing].cursed())
1916     {
1917         mprf("%s is stuck to you!",
1918              you.inv[existing].name(DESC_YOUR).c_str());
1919         return false;
1920     }
1921 
1922     return true;
1923 }
1924 
_puton_amulet(item_def & item,bool check_for_inscriptions)1925 static bool _puton_amulet(item_def &item,
1926                           bool check_for_inscriptions)
1927 {
1928     if (&item == you.slot_item(EQ_AMULET, true))
1929     {
1930         // "Putting on" an equipped item means taking it off.
1931         if (Options.equip_unequip)
1932             // TODO: why invert the return value here? failing to remove
1933             // an amulet is equivalent to successfully putting one on?
1934             return !remove_ring(item.link);
1935         mpr("You're already wearing that amulet!");
1936         return false;
1937     }
1938 
1939     if (!_can_puton_amulet(item))
1940         return false;
1941 
1942     // It looks to be possible to equip this item. Before going any further,
1943     // we should prompt the user with any warnings that come with trying to
1944     // put it on, except when they have already been prompted with them
1945     // from switching rings.
1946     if (check_for_inscriptions && !check_warning_inscriptions(item, OPER_PUTON))
1947     {
1948         canned_msg(MSG_OK);
1949         return false;
1950     }
1951 
1952     item_def *old_amu = you.slot_item(EQ_AMULET, true);
1953 
1954     // Check for stat loss.
1955     if (!_safe_to_remove_or_wear(item, old_amu, false))
1956         return false;
1957 
1958     // Remove the previous one.
1959     if (old_amu && !remove_ring(old_amu->link, true, true))
1960         return false;
1961 
1962     // puton_ring already confirmed there's room for it
1963     int item_slot = _get_item_slot_maybe_with_move(item);
1964 
1965     start_delay<EquipOnDelay>(ARMOUR_EQUIP_DELAY, you.inv[item_slot]);
1966     return true;
1967 }
1968 
1969 // Put on a particular ring.
_puton_ring(item_def & item,bool prompt_slot,bool check_for_inscriptions,bool noask)1970 static bool _puton_ring(item_def &item, bool prompt_slot,
1971                         bool check_for_inscriptions, bool noask)
1972 {
1973     vector<equipment_type> current_jewellery = _current_ring_types();
1974 
1975     for (auto eq : current_jewellery)
1976     {
1977         if (&item != you.slot_item(eq, true))
1978             continue;
1979         // "Putting on" an equipped item means taking it off.
1980         if (Options.equip_unequip)
1981             // TODO: why invert the return value here? failing to remove
1982             // a ring is equivalent to successfully putting one on?
1983             return !remove_ring(item.link);
1984         mpr("You're already wearing that ring!");
1985         return false;
1986     }
1987 
1988     if (!_can_puton_ring(item))
1989         return false;
1990 
1991     // It looks to be possible to equip this item. Before going any further,
1992     // we should prompt the user with any warnings that come with trying to
1993     // put it on, except when they have already been prompted with them
1994     // from switching rings.
1995     if (check_for_inscriptions && !check_warning_inscriptions(item, OPER_PUTON))
1996     {
1997         canned_msg(MSG_OK);
1998         return false;
1999     }
2000 
2001     const vector<equipment_type> ring_types = _current_ring_types();
2002 
2003     // Check whether there are any unused ring slots
2004     bool need_swap = true;
2005     for (auto eq : ring_types)
2006     {
2007         if (!you.slot_item(eq, true))
2008         {
2009             need_swap = false;
2010             break;
2011         }
2012     }
2013 
2014     // No unused ring slots. Swap out a worn ring for the new one.
2015     if (need_swap)
2016         return _swap_rings(item);
2017 
2018     // At this point, we know there's an empty slot for the ring/amulet we're
2019     // trying to equip.
2020 
2021     // Check for stat loss.
2022     if (!noask && !_safe_to_remove_or_wear(item, false))
2023         return false;
2024 
2025     equipment_type hand_used = EQ_NONE;
2026     if (prompt_slot)
2027     {
2028         // Prompt for a slot, even if we have empty ring slots.
2029         hand_used = _choose_ring_slot();
2030 
2031         if (hand_used == EQ_NONE)
2032         {
2033             canned_msg(MSG_OK);
2034             return false;
2035         }
2036         // Allow swapping out a ring.
2037         else if (you.slot_item(hand_used, true))
2038         {
2039             if (!noask && !_safe_to_remove_or_wear(item,
2040                 you.slot_item(hand_used, true), false))
2041             {
2042                 return false;
2043             }
2044 
2045             if (!remove_ring(you.equip[hand_used], false, true))
2046                 return false;
2047 
2048             start_delay<JewelleryOnDelay>(1, item);
2049             return true;
2050         }
2051     }
2052     else
2053     {
2054         for (auto eq : ring_types)
2055         {
2056             if (!you.slot_item(eq, true))
2057             {
2058                 hand_used = eq;
2059                 break;
2060             }
2061         }
2062     }
2063 
2064     const unsigned int old_talents = your_talents(false).size();
2065 
2066     // Actually equip the item.
2067     int item_slot = _get_item_slot_maybe_with_move(item);
2068     equip_item(hand_used, item_slot);
2069 
2070     check_item_hint(you.inv[item_slot], old_talents);
2071 #ifdef USE_TILE_LOCAL
2072     if (your_talents(false).size() != old_talents)
2073     {
2074         tiles.layout_statcol();
2075         redraw_screen();
2076         update_screen();
2077     }
2078 #endif
2079 
2080     // Putting on jewellery is fast.
2081     you.time_taken /= 2;
2082     you.turn_is_over = true;
2083 
2084     return true;
2085 }
2086 
2087 // Put on a ring or amulet. (Most of the work is in _puton_item.)
puton_ring(item_def & to_puton,bool allow_prompt,bool check_for_inscriptions,bool noask)2088 bool puton_ring(item_def &to_puton, bool allow_prompt,
2089                 bool check_for_inscriptions, bool noask)
2090 {
2091     if (you.berserk())
2092     {
2093         canned_msg(MSG_TOO_BERSERK);
2094         return false;
2095     }
2096     if (!to_puton.defined())
2097     {
2098         mpr("You don't have any such object.");
2099         return false;
2100     }
2101     if (to_puton.pos != ITEM_IN_INVENTORY
2102         && !_can_move_item_from_floor_to_inv(to_puton))
2103     {
2104         return false;
2105     }
2106 
2107     // item type checking is a bit convoluted here; we can't yet meet the
2108     // conditions for _can_puton_jewellery (called in _puton_ring) but
2109     // jewellery_is_amulet is only well-defined if it is passed jewellery,
2110     // and ASSERTs accordingly
2111     if (to_puton.base_type == OBJ_JEWELLERY && jewellery_is_amulet(to_puton))
2112         return _puton_amulet(to_puton, check_for_inscriptions);
2113     const bool prompt = allow_prompt && Options.jewellery_prompt;
2114     return _puton_ring(to_puton, prompt, check_for_inscriptions, noask);
2115 }
2116 
2117 // Wraps version of puton_ring with item_def param. If slot is -1, prompt for
2118 // which item to put on; otherwise, pass on the item in inventory slot
puton_ring(int slot,bool allow_prompt,bool check_for_inscriptions,bool noask)2119 bool puton_ring(int slot, bool allow_prompt, bool check_for_inscriptions,
2120                 bool noask)
2121 {
2122     item_def *to_puton_ptr = nullptr;
2123     if (slot == -1)
2124     {
2125         if (!use_an_item(to_puton_ptr, OBJ_JEWELLERY, OPER_PUTON,
2126                         "Put on which piece of jewellery (* to show all)?"))
2127         {
2128             return false;
2129         }
2130     }
2131     else
2132         to_puton_ptr = &you.inv[slot];
2133 
2134     return puton_ring(*to_puton_ptr, allow_prompt, check_for_inscriptions,
2135                       noask);
2136 }
2137 
2138 // Remove the ring/amulet at given inventory slot (or, if slot is -1, prompt
2139 // for which piece of jewellery to remove)
2140 //
2141 // noask suppresses the "stat zero" prompt.
remove_ring(int slot,bool announce,bool noask)2142 bool remove_ring(int slot, bool announce, bool noask)
2143 {
2144     equipment_type hand_used = EQ_NONE;
2145     bool has_jewellery = false;
2146     bool has_melded = false;
2147     const vector<equipment_type> jewellery_slots = _current_jewellery_types();
2148 
2149     for (auto eq : jewellery_slots)
2150     {
2151         if (you.slot_item(eq))
2152         {
2153             if (has_jewellery || Options.jewellery_prompt)
2154             {
2155                 // At least one other piece, which means we'll have to ask
2156                 hand_used = EQ_NONE;
2157             }
2158             else
2159                 hand_used = eq;
2160 
2161             has_jewellery = true;
2162         }
2163         else if (you.melded[eq])
2164             has_melded = true;
2165     }
2166 
2167     if (!has_jewellery)
2168     {
2169         if (has_melded)
2170             mpr("You aren't wearing any unmelded rings or amulets.");
2171         else
2172             mpr("You aren't wearing any rings or amulets.");
2173 
2174         return false;
2175     }
2176 
2177     if (you.berserk())
2178     {
2179         canned_msg(MSG_TOO_BERSERK);
2180         return false;
2181     }
2182 
2183     // If more than one equipment slot had jewellery, we need to figure out
2184     // which one to remove from.
2185     if (hand_used == EQ_NONE)
2186     {
2187         const int equipn =
2188             (slot == -1)? prompt_invent_item("Remove which piece of jewellery?",
2189                                              menu_type::invlist,
2190                                              OBJ_JEWELLERY,
2191                                              OPER_REMOVE,
2192                                              invprompt_flag::no_warning
2193                                                 | invprompt_flag::hide_known)
2194                         : slot;
2195 
2196         if (prompt_failed(equipn))
2197             return false;
2198 
2199         hand_used = item_equip_slot(you.inv[equipn]);
2200         if (hand_used == EQ_NONE)
2201         {
2202             mpr("You aren't wearing that.");
2203             return false;
2204         }
2205         else if (you.inv[equipn].base_type != OBJ_JEWELLERY)
2206         {
2207             mpr("That isn't a piece of jewellery.");
2208             return false;
2209         }
2210     }
2211 
2212     if (you.equip[hand_used] == -1)
2213     {
2214         mpr("I don't think you really meant that.");
2215         return false;
2216     }
2217     else if (you.melded[hand_used])
2218     {
2219         mpr("You can't take that off while it's melded.");
2220         return false;
2221     }
2222     else if (hand_used == EQ_AMULET
2223         && you.equip[EQ_RING_AMULET] != -1)
2224     {
2225         // This can be removed in the future if more ring amulets are added.
2226         ASSERT(player_equip_unrand(UNRAND_FINGER_AMULET));
2227 
2228         mpr("The amulet cannot be taken off without first removing the ring!");
2229         return false;
2230     }
2231 
2232     if (!check_warning_inscriptions(you.inv[you.equip[hand_used]],
2233                                     OPER_REMOVE))
2234     {
2235         canned_msg(MSG_OK);
2236         return false;
2237     }
2238 
2239     if (you.inv[you.equip[hand_used]].cursed())
2240     {
2241         if (announce)
2242         {
2243             mprf("%s is stuck to you!",
2244                  you.inv[you.equip[hand_used]].name(DESC_YOUR).c_str());
2245         }
2246         else
2247             mpr("It's stuck to you!");
2248 
2249         return false;
2250     }
2251 
2252     const int removed_ring_slot = you.equip[hand_used];
2253     item_def &invitem = you.inv[removed_ring_slot];
2254     if (!noask && !_safe_to_remove_or_wear(invitem, true))
2255         return false;
2256 
2257     // Remove the ring.
2258     you.turn_is_over = true;
2259     if (hand_used == EQ_AMULET)
2260     {
2261         start_delay<EquipOffDelay>(ARMOUR_EQUIP_DELAY - 1, invitem);
2262         return true;
2263     }
2264 
2265 #ifdef USE_SOUND
2266     parse_sound(REMOVE_JEWELLERY_SOUND);
2267 #endif
2268     mprf("You remove %s.", invitem.name(DESC_YOUR).c_str());
2269 #ifdef USE_TILE_LOCAL
2270     const unsigned int old_talents = your_talents(false).size();
2271 #endif
2272     unequip_item(hand_used);
2273 #ifdef USE_TILE_LOCAL
2274     if (your_talents(false).size() != old_talents)
2275     {
2276         tiles.layout_statcol();
2277         redraw_screen();
2278         update_screen();
2279     }
2280 #endif
2281 
2282     you.time_taken /= 2;
2283 
2284     return true;
2285 }
2286 
prompt_inscribe_item()2287 void prompt_inscribe_item()
2288 {
2289     if (inv_count() < 1)
2290     {
2291         mpr("You don't have anything to inscribe.");
2292         return;
2293     }
2294 
2295     int item_slot = prompt_invent_item("Inscribe which item?",
2296                                        menu_type::invlist, OSEL_ANY);
2297 
2298     if (prompt_failed(item_slot))
2299         return;
2300 
2301     inscribe_item(you.inv[item_slot]);
2302 }
2303 
drink(item_def * potion)2304 void drink(item_def* potion)
2305 {
2306     if (!you.can_drink(false))
2307     {
2308         mpr("You can't drink.");
2309         return;
2310     }
2311     else if (!you.can_drink(true))
2312     {
2313         mpr("You cannot drink potions in your current state!");
2314         return;
2315     }
2316 
2317     if (you.berserk())
2318     {
2319         canned_msg(MSG_TOO_BERSERK);
2320         return;
2321     }
2322 
2323     if (!potion)
2324     {
2325         if (!use_an_item(potion, OBJ_POTIONS, OPER_QUAFF, "Drink which item (* to show all)?"))
2326             return;
2327     }
2328 
2329     if (potion->base_type != OBJ_POTIONS)
2330     {
2331         mpr("You can't drink that!");
2332         return;
2333     }
2334 
2335     const bool alreadyknown = item_type_known(*potion);
2336 
2337     if (alreadyknown && is_bad_item(*potion))
2338     {
2339         canned_msg(MSG_UNTHINKING_ACT);
2340         return;
2341     }
2342 
2343     bool penance = god_hates_item(*potion);
2344     string prompt = make_stringf("Really quaff the %s?%s",
2345                                  potion->name(DESC_DBNAME).c_str(),
2346                                  penance ? " This action would place"
2347                                            " you under penance!" : "");
2348     if (alreadyknown && (is_dangerous_item(*potion, true) || penance)
2349         && Options.bad_item_prompt
2350         && !yesno(prompt.c_str(), false, 'n'))
2351     {
2352         canned_msg(MSG_OK);
2353         return;
2354     }
2355 
2356     // The "> 1" part is to reduce the amount of times that Xom is
2357     // stimulated when you are a low-level 1 trying your first unknown
2358     // potions on monsters.
2359     const bool dangerous = (player_in_a_dangerous_place()
2360                             && you.experience_level > 1);
2361 
2362     if (player_under_penance(GOD_GOZAG) && one_chance_in(3))
2363     {
2364         simple_god_message(" petitions for your drink to fail.", GOD_GOZAG);
2365         you.turn_is_over = true;
2366         return;
2367     }
2368 
2369     if (!quaff_potion(*potion))
2370         return;
2371 
2372     if (!alreadyknown && dangerous)
2373     {
2374         // Xom loves it when you drink an unknown potion and there is
2375         // a dangerous monster nearby...
2376         xom_is_stimulated(200);
2377     }
2378 
2379     // We'll need this later, after destroying the item.
2380     const bool was_exp = potion->sub_type == POT_EXPERIENCE;
2381     if (in_inventory(*potion))
2382     {
2383         dec_inv_item_quantity(potion->link, 1);
2384         auto_assign_item_slot(*potion);
2385     }
2386     else
2387         dec_mitm_item_quantity(potion->index(), 1);
2388     count_action(CACT_USE, OBJ_POTIONS);
2389     you.turn_is_over = true;
2390 
2391     // This got deferred from PotionExperience::effect to prevent SIGHUP abuse.
2392     if (was_exp)
2393         level_change();
2394 }
2395 
2396 // XXX: there's probably a nicer way of doing this.
god_hates_brand(const int brand)2397 bool god_hates_brand(const int brand)
2398 {
2399     if (is_good_god(you.religion)
2400         && (brand == SPWPN_DRAINING
2401             || brand == SPWPN_VAMPIRISM
2402             || brand == SPWPN_CHAOS
2403             || brand == SPWPN_PAIN))
2404     {
2405         return true;
2406     }
2407 
2408     if (you_worship(GOD_CHEIBRIADOS) && (brand == SPWPN_CHAOS
2409                                          || brand == SPWPN_SPEED))
2410     {
2411         return true;
2412     }
2413 
2414     if (you_worship(GOD_YREDELEMNUL) && brand == SPWPN_HOLY_WRATH)
2415         return true;
2416 
2417     return false;
2418 }
2419 
_rebrand_weapon(item_def & wpn)2420 static void _rebrand_weapon(item_def& wpn)
2421 {
2422     if (&wpn == you.weapon() && you.duration[DUR_EXCRUCIATING_WOUNDS])
2423         end_weapon_brand(wpn);
2424     const brand_type old_brand = get_weapon_brand(wpn);
2425     monster * spect = find_spectral_weapon(&you);
2426     if (&wpn == you.weapon() && old_brand == SPWPN_SPECTRAL && spect)
2427         end_spectral_weapon(spect, false);
2428     brand_type new_brand = old_brand;
2429 
2430     // now try and find an appropriate brand
2431     while (old_brand == new_brand || god_hates_brand(new_brand))
2432     {
2433         if (is_range_weapon(wpn))
2434         {
2435             new_brand = random_choose_weighted(
2436                                     33, SPWPN_FLAMING,
2437                                     33, SPWPN_FREEZING,
2438                                     23, SPWPN_VENOM,
2439                                     23, SPWPN_VORPAL,
2440                                     5, SPWPN_ELECTROCUTION,
2441                                     3, SPWPN_CHAOS);
2442         }
2443         else
2444         {
2445             new_brand = random_choose_weighted(
2446                                     28, SPWPN_FLAMING,
2447                                     28, SPWPN_FREEZING,
2448                                     23, SPWPN_VORPAL,
2449                                     18, SPWPN_VENOM,
2450                                     14, SPWPN_DRAINING,
2451                                     14, SPWPN_ELECTROCUTION,
2452                                     11, SPWPN_PROTECTION,
2453                                     11, SPWPN_SPECTRAL,
2454                                     8, SPWPN_VAMPIRISM,
2455                                     3, SPWPN_CHAOS);
2456         }
2457     }
2458 
2459     set_item_ego_type(wpn, OBJ_WEAPONS, new_brand);
2460     convert2bad(wpn);
2461 }
2462 
_item_name(item_def & item)2463 static string _item_name(item_def &item)
2464 {
2465     return item.name(in_inventory(item) ? DESC_YOUR : DESC_THE);
2466 }
2467 
_brand_weapon(item_def & wpn)2468 static void _brand_weapon(item_def &wpn)
2469 {
2470     you.wield_change = true;
2471 
2472     const string itname = _item_name(wpn);
2473 
2474     _rebrand_weapon(wpn);
2475 
2476     bool success = true;
2477     colour_t flash_colour = BLACK;
2478 
2479     switch (get_weapon_brand(wpn))
2480     {
2481     case SPWPN_VORPAL:
2482         flash_colour = YELLOW;
2483         mprf("%s emits a brilliant flash of light!",itname.c_str());
2484         break;
2485 
2486     case SPWPN_PROTECTION:
2487         flash_colour = YELLOW;
2488         mprf("%s projects an invisible shield of force!",itname.c_str());
2489         break;
2490 
2491     case SPWPN_FLAMING:
2492         flash_colour = RED;
2493         mprf("%s is engulfed in flames!", itname.c_str());
2494         break;
2495 
2496     case SPWPN_FREEZING:
2497         flash_colour = LIGHTCYAN;
2498         mprf("%s is covered with a thin layer of ice!", itname.c_str());
2499         break;
2500 
2501     case SPWPN_DRAINING:
2502         flash_colour = DARKGREY;
2503         mprf("%s craves living souls!", itname.c_str());
2504         break;
2505 
2506     case SPWPN_VAMPIRISM:
2507         flash_colour = DARKGREY;
2508         mprf("%s thirsts for the lives of mortals!", itname.c_str());
2509         break;
2510 
2511     case SPWPN_VENOM:
2512         flash_colour = GREEN;
2513         mprf("%s drips with poison.", itname.c_str());
2514         break;
2515 
2516     case SPWPN_ELECTROCUTION:
2517         flash_colour = LIGHTCYAN;
2518         mprf("%s crackles with electricity.", itname.c_str());
2519         break;
2520 
2521     case SPWPN_CHAOS:
2522         flash_colour = random_colour();
2523         mprf("%s erupts in a glittering mayhem of colour.", itname.c_str());
2524         break;
2525 
2526     case SPWPN_ACID:
2527         flash_colour = ETC_SLIME;
2528         mprf("%s oozes corrosive slime.", itname.c_str());
2529         break;
2530 
2531     case SPWPN_SPECTRAL:
2532         flash_colour = BLUE;
2533         mprf("%s acquires a faint afterimage.", itname.c_str());
2534         break;
2535 
2536     default:
2537         success = false;
2538         break;
2539     }
2540 
2541     if (success)
2542     {
2543         item_set_appearance(wpn);
2544         // Message would spoil this even if we didn't identify.
2545         set_ident_flags(wpn, ISFLAG_KNOW_TYPE);
2546         mprf_nocap("%s", wpn.name(DESC_INVENTORY_EQUIP).c_str());
2547         // Might be rebranding to/from protection or evasion.
2548         you.redraw_armour_class = true;
2549         you.redraw_evasion = true;
2550         // Might be removing antimagic.
2551         calc_mp();
2552         flash_view_delay(UA_PLAYER, flash_colour, 300);
2553     }
2554     return;
2555 }
2556 
_choose_target_item_for_scroll(bool scroll_known,object_selector selector,const char * prompt)2557 static item_def* _choose_target_item_for_scroll(bool scroll_known, object_selector selector,
2558                                                 const char* prompt)
2559 {
2560     item_def *target = nullptr;
2561     bool success = false;
2562 
2563     success = use_an_item(target, selector, OPER_ANY, prompt,
2564                        [=]()
2565                        {
2566                            if (scroll_known
2567                                || crawl_state.seen_hups
2568                                || yesno("Really abort (and waste the scroll)?", false, 0))
2569                            {
2570                                return true;
2571                            }
2572                            return false;
2573                        });
2574     return success ? target : nullptr;
2575 }
2576 
_enchant_selector(scroll_type scroll)2577 static object_selector _enchant_selector(scroll_type scroll)
2578 {
2579     if (scroll == SCR_BRAND_WEAPON)
2580         return OSEL_BRANDABLE_WEAPON;
2581     else if (scroll == SCR_ENCHANT_WEAPON)
2582         return OSEL_ENCHANTABLE_WEAPON;
2583     die("Invalid scroll type %d for _enchant_selector", (int)scroll);
2584 }
2585 
2586 // Returns nullptr if no weapon was chosen.
_scroll_choose_weapon(bool alreadyknown,const string & pre_msg,scroll_type scroll)2587 static item_def* _scroll_choose_weapon(bool alreadyknown, const string &pre_msg,
2588                                        scroll_type scroll)
2589 {
2590     const bool branding = scroll == SCR_BRAND_WEAPON;
2591 
2592     item_def* target = _choose_target_item_for_scroll(alreadyknown, _enchant_selector(scroll),
2593                                                       branding ? "Brand which weapon?"
2594                                                                : "Enchant which weapon?");
2595     if (!target)
2596         return target;
2597 
2598     if (alreadyknown)
2599         mpr(pre_msg);
2600 
2601     return target;
2602 }
2603 
2604 // Returns true if the scroll is used up.
_handle_brand_weapon(bool alreadyknown,const string & pre_msg)2605 static bool _handle_brand_weapon(bool alreadyknown, const string &pre_msg)
2606 {
2607     item_def* weapon = _scroll_choose_weapon(alreadyknown, pre_msg,
2608                                              SCR_BRAND_WEAPON);
2609     if (!weapon)
2610         return !alreadyknown;
2611 
2612     _brand_weapon(*weapon);
2613     return true;
2614 }
2615 
enchant_weapon(item_def & wpn,bool quiet)2616 bool enchant_weapon(item_def &wpn, bool quiet)
2617 {
2618     bool success = false;
2619 
2620     // Get item name now before changing enchantment.
2621     string iname = _item_name(wpn);
2622 
2623     if (is_weapon(wpn)
2624         && !is_artefact(wpn)
2625         && wpn.base_type == OBJ_WEAPONS
2626         && wpn.plus < MAX_WPN_ENCHANT)
2627     {
2628         wpn.plus++;
2629         success = true;
2630         if (!quiet)
2631             mprf("%s glows red for a moment.", iname.c_str());
2632     }
2633 
2634     if (!success && !quiet)
2635         canned_msg(MSG_NOTHING_HAPPENS);
2636 
2637     if (success)
2638         you.wield_change = true;
2639 
2640     return success;
2641 }
2642 
2643 /**
2644  * Prompt for an item to identify (either in the player's inventory or in
2645  * the ground), and then, if one is chosen, identify it.
2646  *
2647  * @param alreadyknown  Did we know that this was an ID scroll before we
2648  *                      started reading it?
2649  * @param pre_msg       'As you read the scroll of foo, it crumbles to dust.'
2650  * @param link[in,out]  The location of the ID scroll in the player's inventory
2651  *                      or, if it's on the floor, -1.
2652  *                      auto_assign_item_slot() may require us to update this.
2653  * @return  true if the scroll is used up. (That is, whether it was used or
2654  *          whether it was previously unknown (& thus uncancellable).)
2655  */
_identify(bool alreadyknown,const string & pre_msg,int & link)2656 static bool _identify(bool alreadyknown, const string &pre_msg, int &link)
2657 {
2658     item_def* itemp = _choose_target_item_for_scroll(alreadyknown, OSEL_UNIDENT,
2659                        "Identify which item? (\\ to view known items)");
2660 
2661     if (!itemp)
2662         return !alreadyknown;
2663 
2664     item_def& item = *itemp;
2665     if (alreadyknown)
2666         mpr(pre_msg);
2667 
2668     set_ident_type(item, true);
2669     set_ident_flags(item, ISFLAG_IDENT_MASK);
2670 
2671     // Output identified item.
2672     mprf_nocap("%s", menu_colour_item_name(item, DESC_INVENTORY_EQUIP).c_str());
2673     if (in_inventory(item))
2674     {
2675         if (item.link == you.equip[EQ_WEAPON])
2676             you.wield_change = true;
2677 
2678         const int target_link = item.link;
2679         item_def* moved_target = auto_assign_item_slot(item);
2680         if (moved_target != nullptr && moved_target->link == link)
2681         {
2682             // auto-swapped ID'd item with scrolls being used to ID it
2683             // correct input 'link' to the new location of the ID scroll stack
2684             // so that we decrement *it* instead of the ID'd item (10663)
2685             ASSERT(you.inv[target_link].defined());
2686             ASSERT(you.inv[target_link].is_type(OBJ_SCROLLS, SCR_IDENTIFY));
2687             link = target_link;
2688         }
2689     }
2690     return true;
2691 }
2692 
_handle_enchant_weapon(bool alreadyknown,const string & pre_msg)2693 static bool _handle_enchant_weapon(bool alreadyknown, const string &pre_msg)
2694 {
2695     item_def* weapon = _scroll_choose_weapon(alreadyknown, pre_msg,
2696                                              SCR_ENCHANT_WEAPON);
2697     if (!weapon)
2698         return !alreadyknown;
2699 
2700     enchant_weapon(*weapon, false);
2701     return true;
2702 }
2703 
enchant_armour(int & ac_change,bool quiet,item_def & arm)2704 bool enchant_armour(int &ac_change, bool quiet, item_def &arm)
2705 {
2706     ASSERT(arm.defined());
2707     ASSERT(arm.base_type == OBJ_ARMOUR);
2708 
2709     ac_change = 0;
2710 
2711     // Cannot be enchanted.
2712     if (!is_enchantable_armour(arm))
2713     {
2714         if (!quiet)
2715             canned_msg(MSG_NOTHING_HAPPENS);
2716         return false;
2717     }
2718 
2719     // Output message before changing enchantment and curse status.
2720     if (!quiet)
2721     {
2722         const bool plural = armour_is_hide(arm)
2723                             && arm.sub_type != ARM_TROLL_LEATHER_ARMOUR;
2724         mprf("%s %s green for a moment.",
2725              _item_name(arm).c_str(),
2726              conjugate_verb("glow", plural).c_str());
2727     }
2728 
2729     arm.plus++;
2730     ac_change++;
2731 
2732     return true;
2733 }
2734 
_handle_enchant_armour(bool alreadyknown,const string & pre_msg)2735 static int _handle_enchant_armour(bool alreadyknown, const string &pre_msg)
2736 {
2737     item_def* target = _choose_target_item_for_scroll(alreadyknown, OSEL_ENCHANTABLE_ARMOUR,
2738                                                       "Enchant which item?");
2739 
2740     if (!target)
2741         return alreadyknown ? -1 : 0;
2742 
2743     // Okay, we may actually (attempt to) enchant something.
2744     if (alreadyknown)
2745         mpr(pre_msg);
2746 
2747     int ac_change;
2748     bool result = enchant_armour(ac_change, false, *target);
2749 
2750     if (ac_change)
2751         you.redraw_armour_class = true;
2752 
2753     return result ? 1 : 0;
2754 }
2755 
_vulnerability_scroll()2756 static void _vulnerability_scroll()
2757 {
2758     const int dur = 30 + random2(20);
2759     mon_enchant lowered_wl(ENCH_LOWERED_WL, 1, &you, dur * BASELINE_DELAY);
2760 
2761     // Go over all creatures in LOS.
2762     for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
2763     {
2764         if (monster* mon = monster_at(*ri))
2765         {
2766             // If relevant, monsters have their WL halved.
2767             if (!mons_invuln_will(*mon))
2768                 mon->add_ench(lowered_wl);
2769 
2770             // Annoying but not enough to turn friendlies against you.
2771             if (!mon->wont_attack())
2772                 behaviour_event(mon, ME_ANNOY, &you);
2773         }
2774     }
2775 
2776     you.set_duration(DUR_LOWERED_WL, dur, 0,
2777                      "Magic quickly surges around you.");
2778 }
2779 
_is_cancellable_scroll(scroll_type scroll)2780 static bool _is_cancellable_scroll(scroll_type scroll)
2781 {
2782     return scroll == SCR_IDENTIFY
2783            || scroll == SCR_BLINKING
2784            || scroll == SCR_ENCHANT_ARMOUR
2785            || scroll == SCR_AMNESIA
2786 #if TAG_MAJOR_VERSION == 34
2787            || scroll == SCR_CURSE_ARMOUR
2788            || scroll == SCR_CURSE_JEWELLERY
2789            || scroll == SCR_RECHARGING
2790 #endif
2791            || scroll == SCR_BRAND_WEAPON
2792            || scroll == SCR_ENCHANT_WEAPON
2793            || scroll == SCR_MAGIC_MAPPING
2794            || scroll == SCR_ACQUIREMENT;
2795 }
2796 
2797 /**
2798  * If the player has no items matching the given selector, give an appropriate
2799  * response to print. Otherwise, if they do have such items, return the empty
2800  * string.
2801  */
_no_items_reason(object_selector type,bool check_floor=false)2802 static string _no_items_reason(object_selector type, bool check_floor = false)
2803 {
2804     if (!any_items_of_type(type, -1, check_floor))
2805         return no_selectables_message(type);
2806     return "";
2807 }
2808 
2809 /**
2810  * If the player is unable to (r)ead the item in the given slot, return the
2811  * reason why. Otherwise (if they are able to read it), returns "", the empty
2812  * string. If item is nullptr, do only general reading checks.
2813  */
cannot_read_item_reason(const item_def * item)2814 string cannot_read_item_reason(const item_def *item)
2815 {
2816     // general checks
2817     if (you.berserk())
2818         return "You are too berserk!";
2819 
2820     if (you.confused())
2821         return "You are too confused!";
2822 
2823     // no reading while threatened (Ru/random mutation)
2824     if (you.duration[DUR_NO_SCROLLS])
2825         return "You cannot read scrolls in your current state!";
2826 
2827     if (silenced(you.pos()))
2828         return "Magic scrolls do not work when you're silenced!";
2829 
2830     // water elementals
2831     if (you.duration[DUR_WATER_HOLD] && !you.res_water_drowning())
2832         return "You cannot read scrolls while unable to breathe!";
2833 
2834     if (!item)
2835         return "";
2836 
2837     // item-specific checks
2838 
2839     // still possible to use * at the `r` prompt. (Why do we allow this now?)
2840     if (item->base_type != OBJ_SCROLLS)
2841         return "You can't read that!";
2842 
2843     // don't waste the player's time reading known scrolls in situations where
2844     // they'd be useless
2845 
2846     if (!item_type_known(*item))
2847         return "";
2848 
2849     switch (item->sub_type)
2850     {
2851         case SCR_BLINKING:
2852         case SCR_TELEPORTATION:
2853             return you.no_tele_reason(false, item->sub_type == SCR_BLINKING);
2854 
2855         case SCR_AMNESIA:
2856             if (you.spell_no == 0)
2857                 return "You have no spells to forget!";
2858             return "";
2859 
2860         case SCR_ENCHANT_ARMOUR:
2861             return _no_items_reason(OSEL_ENCHANTABLE_ARMOUR, true);
2862 
2863         case SCR_ENCHANT_WEAPON:
2864             return _no_items_reason(OSEL_ENCHANTABLE_WEAPON, true);
2865 
2866         case SCR_IDENTIFY:
2867             if (have_passive(passive_t::want_curses))
2868                 return _no_items_reason(OSEL_CURSED_WORN);
2869             return _no_items_reason(OSEL_UNIDENT, true);
2870 
2871 #if TAG_MAJOR_VERSION == 34
2872         case SCR_CURSE_WEAPON:
2873             if (!you.weapon())
2874                 return "This scroll only affects a wielded weapon!";
2875 
2876             // assumption: wielded weapons always have their curse & brand known
2877             if (you.weapon()->cursed())
2878                 return "Your weapon is already cursed!";
2879 
2880             if (get_weapon_brand(*you.weapon()) == SPWPN_HOLY_WRATH)
2881                 return "Holy weapons cannot be cursed!";
2882             return "";
2883 
2884         case SCR_CURSE_ARMOUR:
2885             return _no_items_reason(OSEL_UNCURSED_WORN_ARMOUR);
2886 
2887         case SCR_CURSE_JEWELLERY:
2888             return _no_items_reason(OSEL_UNCURSED_WORN_JEWELLERY);
2889 #endif
2890 
2891         default:
2892             return "";
2893     }
2894 }
2895 
2896 /**
2897  * Check if a particular scroll type would hurt a monster.
2898  *
2899  * @param scr           Scroll type in question
2900  * @param m             Actor as a potential victim to the scroll
2901  * @return  true if the provided scroll type is harmful to the actor.
2902  */
_scroll_will_harm(const scroll_type scr,const actor & m)2903 static bool _scroll_will_harm(const scroll_type scr, const actor &m)
2904 {
2905     if (!m.alive())
2906         return false;
2907 
2908     switch (scr)
2909     {
2910         case SCR_HOLY_WORD:
2911             if (m.undead_or_demonic())
2912                 return true;
2913             break;
2914         case SCR_TORMENT:
2915             if (!m.res_torment())
2916                 return true;
2917             break;
2918         default: break;
2919     }
2920 
2921     return false;
2922 }
2923 
_desc_finite_wl(const monster_info & mi)2924 static vector<string> _desc_finite_wl(const monster_info& mi)
2925 {
2926     vector<string> r;
2927     const int wl = mi.willpower();
2928     if (wl == WILL_INVULN)
2929         r.push_back("infinite will");
2930     else
2931         r.push_back("susceptible");
2932     return r;
2933 }
2934 
_desc_holy_word(const monster_info & mi)2935 static vector<string> _desc_holy_word(const monster_info& mi)
2936 {
2937     if (mi.holi & (MH_UNDEAD | MH_DEMONIC))
2938         return { "susceptible" };
2939     else
2940         return { "not susceptible" };
2941 }
2942 
_desc_res_torment(const monster_info & mi)2943 static vector<string> _desc_res_torment(const monster_info& mi)
2944 {
2945     if (mi.resists() & (MR_RES_TORMENT))
2946         return { "not susceptible" };
2947     else
2948         return { "susceptible" };
2949 }
2950 
2951 class targeter_finite_will : public targeter_multimonster
2952 {
2953 public:
targeter_finite_will()2954     targeter_finite_will() : targeter_multimonster(&you)
2955     { }
2956 
affects_monster(const monster_info & mon)2957     bool affects_monster(const monster_info& mon)
2958     {
2959         return mon.willpower() != WILL_INVULN;
2960     }
2961 };
2962 
2963 class targeter_holy_word : public targeter_multimonster
2964 {
2965 public:
targeter_holy_word()2966     targeter_holy_word() : targeter_multimonster(&you)
2967     { }
2968 
affects_monster(const monster_info & mon)2969     bool affects_monster(const monster_info& mon)
2970     {
2971         return bool(mon.holi & (MH_UNDEAD | MH_DEMONIC));
2972     }
2973 
is_affected(coord_def loc)2974     aff_type is_affected(coord_def loc)
2975     {
2976         if (loc == you.pos() && you.undead_or_demonic())
2977             return AFF_YES;
2978         return targeter_multimonster::is_affected(loc);
2979     }
2980 };
2981 
2982 class targeter_torment : public targeter_multimonster
2983 {
2984 public:
targeter_torment()2985     targeter_torment() : targeter_multimonster(&you)
2986     { }
2987 
affects_monster(const monster_info & mon)2988     bool affects_monster(const monster_info& mon)
2989     {
2990         // TODO: if this is ever used for the pain card it will need an
2991         // override for the player in `is_affected`
2992         return !bool(mon.resists() & MR_RES_TORMENT);
2993     }
2994 };
2995 
2996 class targeter_silence : public targeter_maybe_radius
2997 {
2998     targeter_radius inner_rad;
2999 public:
targeter_silence(int r1,int r2)3000     targeter_silence(int r1, int r2)
3001         : targeter_maybe_radius(&you, LOS_DEFAULT, r2),
3002           inner_rad(&you, LOS_DEFAULT, r1)
3003     {
3004     }
3005 
is_affected(coord_def loc)3006     aff_type is_affected(coord_def loc) override
3007     {
3008         if (inner_rad.is_affected(loc) == AFF_YES)
3009             return AFF_YES;
3010         else
3011             return targeter_maybe_radius::is_affected(loc);
3012     }
3013 };
3014 
3015 // TODO: why do I have to do this
3016 class scroll_targeting_behaviour : public targeting_behaviour
3017 {
3018 public:
scroll_targeting_behaviour()3019     scroll_targeting_behaviour() : targeting_behaviour(false)
3020     {
3021     }
3022 
targeted()3023     bool targeted() override
3024     {
3025         return false;
3026     }
3027 };
3028 
_get_scroll_targeter(scroll_type which_scroll)3029 static unique_ptr<targeter> _get_scroll_targeter(scroll_type which_scroll)
3030 {
3031     // blinking handled elsewhere
3032     switch (which_scroll)
3033     {
3034     case SCR_FEAR:
3035         return find_spell_targeter(SPELL_CAUSE_FEAR, 1000, LOS_RADIUS);
3036     case SCR_SUMMONING:
3037         // TODO: shadow creatures targeter doesn't handle band placement very
3038         // well, and this is more obvious with the scroll
3039         return find_spell_targeter(SPELL_SHADOW_CREATURES, 1000, LOS_RADIUS);
3040     case SCR_VULNERABILITY:
3041     case SCR_IMMOLATION:
3042         return make_unique<targeter_finite_will>();
3043     case SCR_HOLY_WORD:
3044         return make_unique<targeter_holy_word>();
3045     case SCR_SILENCE:
3046         return make_unique<targeter_silence>(2, 4); // TODO: calculate from power (or simplify the calc)
3047     case SCR_TORMENT:
3048         return make_unique<targeter_torment>();
3049     default:
3050         return nullptr;
3051     }
3052 }
3053 
_scroll_targeting_check(scroll_type scroll,dist * target)3054 static bool _scroll_targeting_check(scroll_type scroll, dist *target)
3055 {
3056     // TODO: restructure so that spell scrolls call your_spells, and targeting
3057     // is handled automatically for such scrolls
3058     if (target && target->needs_targeting())
3059     {
3060         direction_chooser_args args;
3061         unique_ptr<targeter> hitfunc = _get_scroll_targeter(scroll);
3062         if (!hitfunc)
3063             return true; // sanity check
3064         if (scroll == SCR_FEAR)
3065         {
3066             // TODO: can't these be rolled in with the targeter somehow? Will
3067             // a fear (etc) targeter ever not have this?
3068             args.get_desc_func = targeter_addl_desc(SPELL_CAUSE_FEAR, 1000,
3069                 get_spell_flags(SPELL_CAUSE_FEAR), hitfunc.get());
3070         }
3071         else if (scroll == SCR_HOLY_WORD)
3072             args.get_desc_func = _desc_holy_word;
3073         else if (scroll == SCR_VULNERABILITY || scroll == SCR_IMMOLATION)
3074             args.get_desc_func = _desc_finite_wl;
3075         else if (scroll == SCR_TORMENT)
3076             args.get_desc_func = _desc_res_torment;
3077 
3078         args.mode = TARG_ANY;
3079         args.self = confirm_prompt_type::cancel;
3080         args.hitfunc = hitfunc.get();
3081         scroll_targeting_behaviour beh;
3082         args.behaviour = &beh;
3083 
3084         direction(*target, args);
3085         return target->isValid && !target->isCancel;
3086     }
3087     else
3088         return true;
3089 }
3090 
scroll_has_targeter(scroll_type which_scroll)3091 bool scroll_has_targeter(scroll_type which_scroll)
3092 {
3093     switch (which_scroll)
3094     {
3095     case SCR_BLINKING:
3096     case SCR_FEAR:
3097     case SCR_SUMMONING:
3098     case SCR_VULNERABILITY:
3099     case SCR_IMMOLATION:
3100     case SCR_HOLY_WORD:
3101     case SCR_SILENCE:
3102     case SCR_TORMENT:
3103         return true;
3104     default:
3105         return false;
3106     }
3107 }
3108 
3109 // If needed, check whether there are hostiles in range that would be affected.
3110 // True means that the scroll either doesn't have such a check, or that there
3111 // are relevant enemies in range. False means that the check failed.
scroll_hostile_check(scroll_type which_scroll)3112 bool scroll_hostile_check(scroll_type which_scroll)
3113 {
3114     // cf spell_no_hostile_in_range
3115     if (!in_bounds(you.pos()) || !you.on_current_level)
3116         return false;
3117 
3118     // no hostile check
3119     if (which_scroll == SCR_SUMMONING || which_scroll == SCR_BLINKING)
3120         return true;
3121 
3122     unique_ptr<targeter> hitfunc = _get_scroll_targeter(which_scroll);
3123     if (!hitfunc)
3124         return true; // no checks for these
3125 
3126     // all scrolls that have a targeter are los radius
3127     for (radius_iterator ri(you.pos(), LOS_NO_TRANS, true);
3128          ri; ++ri)
3129     {
3130         const monster* mon = monster_at(*ri);
3131         if (!mon
3132             || !mon->visible_to(&you)
3133             // Plants/fungi don't count.
3134             || (!mons_is_threatening(*mon) || mon->wont_attack())
3135                 && !mons_class_is_test(mon->type))
3136         {
3137             continue;
3138         }
3139 
3140         if (hitfunc->valid_aim(*ri) && hitfunc->is_affected(*ri) != AFF_NO)
3141             return true;
3142     }
3143     // nothing found: check fails
3144     return false;
3145 }
3146 
3147 /**
3148  * Read the provided scroll.
3149  *
3150  * Check to see if the player can read the provided scroll, and if so,
3151  * reads it. If no scroll is provided, prompt for a scroll.
3152  *
3153  * @param scroll The scroll to be read.
3154  * @param target targeting information, used by the quiver API
3155  */
read(item_def * scroll,dist * target)3156 void read(item_def* scroll, dist *target)
3157 {
3158     string failure_reason = cannot_read_item_reason(scroll);
3159 
3160     if (!scroll && failure_reason.empty())
3161     {
3162         // player can currently read, but no scroll was provided
3163         if (!use_an_item(scroll, OBJ_SCROLLS, OPER_READ, "Read which item (* to show all)?"))
3164             return;
3165         failure_reason = cannot_read_item_reason(scroll);
3166     }
3167 
3168     if (!failure_reason.empty())
3169     {
3170         mprf(MSGCH_PROMPT, "%s", failure_reason.c_str());
3171         return;
3172     }
3173     ASSERT(scroll);
3174 
3175     const scroll_type which_scroll = static_cast<scroll_type>(scroll->sub_type);
3176     // Handle player cancels before we waste time
3177     if (item_type_known(*scroll))
3178     {
3179         const bool hostile_check = scroll_hostile_check(which_scroll);
3180         bool penance = god_hates_item(*scroll);
3181         string verb_object = "read the " + scroll->name(DESC_DBNAME);
3182 
3183         string penance_prompt = make_stringf("Really %s? This action would"
3184                                              " place you under penance%s!",
3185                                              verb_object.c_str(),
3186                                              hostile_check ? ""
3187                     : " and you can't even see any enemies this would affect");
3188 
3189         targeter_radius hitfunc(&you, LOS_NO_TRANS);
3190 
3191         const bool bad_item = (is_dangerous_item(*scroll, true)
3192                                     || is_bad_item(*scroll))
3193                             && Options.bad_item_prompt;
3194 
3195         if (stop_attack_prompt(hitfunc, verb_object.c_str(),
3196                                [which_scroll] (const actor* m)
3197                                {
3198                                    return _scroll_will_harm(which_scroll, *m);
3199                                },
3200                                nullptr, nullptr))
3201         {
3202             return;
3203         }
3204         else if (penance && !yesno(penance_prompt.c_str(), false, 'n'))
3205         {
3206             canned_msg(MSG_OK);
3207             return;
3208         }
3209         else if (bad_item
3210                  && !yesno(make_stringf("Really %s?%s",
3211                                         verb_object.c_str(),
3212                                         hostile_check ? ""
3213                         : " You can't even see any enemies this would affect."
3214                                         ).c_str(),
3215                            false, 'n'))
3216         {
3217             canned_msg(MSG_OK);
3218             return;
3219         }
3220         else if (!bad_item && !hostile_check && !yesno(make_stringf(
3221             "You can't see any enemies this would affect, really %s?",
3222                                         verb_object.c_str()).c_str(),
3223                                                 false, 'n'))
3224         {
3225             // is this too nanny dev?
3226             canned_msg(MSG_OK);
3227             return;
3228         }
3229     }
3230 
3231     // Ok - now we FINALLY get to read a scroll !!! {dlb}
3232     you.turn_is_over = true;
3233 
3234     if (you.duration[DUR_BRAINLESS] && !one_chance_in(5))
3235     {
3236         mpr("You almost manage to decipher the scroll,"
3237             " but fail in this attempt.");
3238         return;
3239     }
3240 
3241     const int prev_quantity = scroll->quantity;
3242     int link = in_inventory(*scroll) ? scroll->link : -1;
3243     const bool alreadyknown = item_type_known(*scroll);
3244 
3245     if (alreadyknown
3246         && scroll_has_targeter(which_scroll)
3247         && which_scroll != SCR_BLINKING // blinking calls its own targeter
3248         && !_scroll_targeting_check(which_scroll, target))
3249     {
3250         // a targeter can't be used for unid'd or uncancellable scrolls, so
3251         // we can skip the rest of the function
3252         you.turn_is_over = false;
3253         return;
3254     }
3255 
3256     // For cancellable scrolls leave printing this message to their
3257     // respective functions.
3258     const string pre_succ_msg =
3259             make_stringf("As you read the %s, it crumbles to dust.",
3260                           scroll->name(DESC_QUALNAME).c_str());
3261     if (!_is_cancellable_scroll(which_scroll))
3262     {
3263         mpr(pre_succ_msg);
3264         // Actual removal of scroll done afterwards. -- bwr
3265     }
3266 
3267     const bool dangerous = player_in_a_dangerous_place();
3268 
3269     // ... but some scrolls may still be cancelled afterwards.
3270     bool cancel_scroll = false;
3271     bool bad_effect = false; // for Xom: result is bad (or at least dangerous)
3272 
3273     switch (which_scroll)
3274     {
3275     case SCR_BLINKING:
3276     {
3277         const string reason = you.no_tele_reason(true, true);
3278         if (!reason.empty())
3279         {
3280             mpr(pre_succ_msg);
3281             mpr(reason);
3282             break;
3283         }
3284 
3285         cancel_scroll = (controlled_blink(alreadyknown, target)
3286                          == spret::abort) && alreadyknown;
3287 
3288         if (!cancel_scroll)
3289             mpr(pre_succ_msg); // ordering is iffy but w/e
3290     }
3291         break;
3292 
3293     case SCR_TELEPORTATION:
3294         you_teleport();
3295         break;
3296 
3297     case SCR_ACQUIREMENT:
3298         if (!alreadyknown)
3299             mpr("This is a scroll of acquirement!");
3300 
3301         // included in default force_more_message
3302         // Identify it early in case the player checks the '\' screen.
3303         set_ident_type(*scroll, true);
3304 
3305         if (feat_eliminates_items(env.grid(you.pos())))
3306         {
3307             mpr("Anything you acquired here would fall and be lost!");
3308             cancel_scroll = true;
3309             break;
3310         }
3311 
3312         cancel_scroll = !acquirement_menu();
3313         break;
3314 
3315     case SCR_FEAR:
3316         mpr("You assume a fearsome visage.");
3317         mass_enchantment(ENCH_FEAR, 1000);
3318         break;
3319 
3320     case SCR_NOISE:
3321         noisy(25, you.pos(), "You hear a loud clanging noise!");
3322         break;
3323 
3324     case SCR_SUMMONING:
3325         cancel_scroll =
3326                     cast_shadow_creatures(MON_SUMM_SCROLL) == spret::abort
3327                     && alreadyknown;
3328         break;
3329 
3330     case SCR_FOG:
3331     {
3332         if (alreadyknown && (env.level_state & LSTATE_STILL_WINDS))
3333         {
3334             mpr("The air is too still for clouds to form.");
3335             cancel_scroll = true;
3336             break;
3337         }
3338         mpr("The scroll dissolves into smoke.");
3339         auto smoke = random_smoke_type();
3340         big_cloud(smoke, &you, you.pos(), 50, 8 + random2(8));
3341         break;
3342     }
3343 
3344     case SCR_MAGIC_MAPPING:
3345         if (alreadyknown && !is_map_persistent())
3346         {
3347             cancel_scroll = true;
3348             mpr("It would have no effect in this place.");
3349             break;
3350         }
3351         mpr(pre_succ_msg);
3352         magic_mapping(500, 100, false);
3353         break;
3354 
3355     case SCR_TORMENT:
3356         torment(&you, TORMENT_SCROLL, you.pos());
3357 
3358         // This is only naughty if you know you're doing it.
3359         did_god_conduct(DID_EVIL, 10, item_type_known(*scroll));
3360         bad_effect = !you.res_torment();
3361         break;
3362 
3363     case SCR_IMMOLATION:
3364     {
3365         bool had_effect = false;
3366         for (monster_near_iterator mi(you.pos(), LOS_NO_TRANS); mi; ++mi)
3367         {
3368             if (mons_invuln_will(**mi))
3369                 continue;
3370 
3371             if (mi->add_ench(mon_enchant(ENCH_INNER_FLAME, 0, &you)))
3372                 had_effect = true;
3373         }
3374 
3375         if (had_effect)
3376             mpr("The creatures around you are filled with an inner flame!");
3377         else
3378             mpr("The air around you briefly surges with heat, but it dissipates.");
3379 
3380         bad_effect = true;
3381         break;
3382     }
3383 
3384     case SCR_ENCHANT_WEAPON:
3385         if (!alreadyknown)
3386         {
3387             mpr(pre_succ_msg);
3388             mpr("It is a scroll of enchant weapon.");
3389             // included in default force_more_message (to show it before menu)
3390         }
3391 
3392         cancel_scroll = !_handle_enchant_weapon(alreadyknown, pre_succ_msg);
3393         break;
3394 
3395     case SCR_BRAND_WEAPON:
3396         if (!alreadyknown)
3397         {
3398             mpr(pre_succ_msg);
3399             mpr("It is a scroll of brand weapon.");
3400             // included in default force_more_message (to show it before menu)
3401         }
3402 
3403         cancel_scroll = !_handle_brand_weapon(alreadyknown, pre_succ_msg);
3404         break;
3405 
3406     case SCR_IDENTIFY:
3407         if (!alreadyknown)
3408         {
3409             mpr(pre_succ_msg);
3410             mpr("It is a scroll of identify.");
3411             // included in default force_more_message (to show it before menu)
3412             // Do this here so it doesn't turn up in the ID menu.
3413             set_ident_type(*scroll, true);
3414         }
3415         cancel_scroll = !_identify(alreadyknown, pre_succ_msg, link);
3416         break;
3417 
3418     case SCR_ENCHANT_ARMOUR:
3419         if (!alreadyknown)
3420         {
3421             mpr(pre_succ_msg);
3422             mpr("It is a scroll of enchant armour.");
3423             // included in default force_more_message (to show it before menu)
3424         }
3425         cancel_scroll =
3426             (_handle_enchant_armour(alreadyknown, pre_succ_msg) == -1);
3427         break;
3428 #if TAG_MAJOR_VERSION == 34
3429     case SCR_CURSE_WEAPON:
3430     case SCR_CURSE_ARMOUR:
3431     case SCR_CURSE_JEWELLERY:
3432     case SCR_RECHARGING:
3433     case SCR_RANDOM_USELESSNESS:
3434     {
3435         mpr("This item has been removed, sorry!");
3436         cancel_scroll = true;
3437         break;
3438     }
3439 #endif
3440 
3441     case SCR_HOLY_WORD:
3442     {
3443         holy_word(100, HOLY_WORD_SCROLL, you.pos(), false, &you);
3444 
3445         // This is always naughty, even if you didn't affect anyone.
3446         // Don't speak those foul holy words even in jest!
3447         did_god_conduct(DID_HOLY, 10, item_type_known(*scroll));
3448         bad_effect = you.undead_or_demonic();
3449         break;
3450     }
3451 
3452     case SCR_SILENCE:
3453         cast_silence(30);
3454         break;
3455 
3456     case SCR_VULNERABILITY:
3457         _vulnerability_scroll();
3458         break;
3459 
3460     case SCR_AMNESIA:
3461         if (!alreadyknown)
3462         {
3463             mpr(pre_succ_msg);
3464             mpr("It is a scroll of amnesia.");
3465             // included in default force_more_message (to show it before menu)
3466         }
3467         if (you.spell_no == 0 || you.has_mutation(MUT_INNATE_CASTER))
3468         {
3469             mpr("You feel forgetful for a moment.");
3470             break;
3471         }
3472         bool done;
3473         bool aborted;
3474         do
3475         {
3476             aborted = cast_selective_amnesia() == -1;
3477             done = !aborted
3478                    || alreadyknown
3479                    || crawl_state.seen_hups
3480                    || yesno("Really abort (and waste the scroll)?",
3481                             false, 0);
3482             cancel_scroll = aborted && alreadyknown;
3483         } while (!done);
3484         if (aborted)
3485             canned_msg(MSG_OK);
3486         break;
3487 
3488     default:
3489         mpr("Read a buggy scroll, please report this.");
3490         break;
3491     }
3492 
3493     if (cancel_scroll)
3494         you.turn_is_over = false;
3495 
3496     set_ident_type(*scroll, true);
3497     set_ident_flags(*scroll, ISFLAG_KNOW_TYPE); // for notes
3498 
3499     string scroll_name = scroll->name(DESC_QUALNAME);
3500 
3501     if (!cancel_scroll)
3502     {
3503         if (in_inventory(*scroll))
3504             dec_inv_item_quantity(link, 1);
3505         else
3506             dec_mitm_item_quantity(scroll->index(), 1);
3507         count_action(CACT_USE, OBJ_SCROLLS);
3508     }
3509 
3510     if (!alreadyknown
3511         && which_scroll != SCR_BRAND_WEAPON
3512         && which_scroll != SCR_ENCHANT_WEAPON
3513         && which_scroll != SCR_IDENTIFY
3514         && which_scroll != SCR_ENCHANT_ARMOUR
3515 #if TAG_MAJOR_VERSION == 34
3516         && which_scroll != SCR_RECHARGING
3517 #endif
3518         && which_scroll != SCR_AMNESIA
3519         && which_scroll != SCR_ACQUIREMENT)
3520     {
3521         mprf("It %s a %s.",
3522              scroll->quantity < prev_quantity ? "was" : "is",
3523              scroll_name.c_str());
3524     }
3525 
3526     if (!alreadyknown && dangerous)
3527     {
3528         // Xom loves it when you read an unknown scroll and there is a
3529         // dangerous monster nearby... (though not as much as potions
3530         // since there are no *really* bad scrolls, merely useless ones).
3531         xom_is_stimulated(bad_effect ? 100 : 50);
3532     }
3533 
3534     if (!alreadyknown)
3535         auto_assign_item_slot(*scroll);
3536 
3537 }
3538 
3539 #ifdef USE_TILE
3540 // Interactive menu for item drop/use.
3541 
tile_item_pickup(int idx,bool part)3542 void tile_item_pickup(int idx, bool part)
3543 {
3544     if (item_is_stationary(env.item[idx]))
3545     {
3546         mpr("You can't pick that up.");
3547         return;
3548     }
3549 
3550     if (part)
3551     {
3552         pickup_menu(idx);
3553         return;
3554     }
3555     pickup_single_item(idx, -1);
3556 }
3557 
tile_item_drop(int idx,bool partdrop)3558 void tile_item_drop(int idx, bool partdrop)
3559 {
3560     int quantity = you.inv[idx].quantity;
3561     if (partdrop && quantity > 1)
3562     {
3563         quantity = prompt_for_int("Drop how many? ", true);
3564         if (quantity < 1)
3565         {
3566             canned_msg(MSG_OK);
3567             return;
3568         }
3569         if (quantity > you.inv[idx].quantity)
3570             quantity = you.inv[idx].quantity;
3571     }
3572     drop_item(idx, quantity);
3573 }
3574 
tile_item_use_secondary(int idx)3575 void tile_item_use_secondary(int idx)
3576 {
3577     const item_def item = you.inv[idx];
3578 
3579     // TODO: add quiver stuff here?
3580     if (you.equip[EQ_WEAPON] == idx)
3581         wield_weapon(true, SLOT_BARE_HANDS);
3582     else if (item_is_wieldable(item))
3583     {
3584         // secondary wield for several spells and such
3585         wield_weapon(true, idx); // wield
3586     }
3587 }
3588 
tile_item_use(int idx)3589 void tile_item_use(int idx)
3590 {
3591     const item_def item = you.inv[idx];
3592 
3593     // Equipped?
3594     bool equipped = false;
3595     bool equipped_weapon = false;
3596     for (unsigned int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; i++)
3597     {
3598         if (you.equip[i] == idx)
3599         {
3600             equipped = true;
3601             if (i == EQ_WEAPON)
3602                 equipped_weapon = true;
3603             break;
3604         }
3605     }
3606 
3607     // Special case for folks who are wielding something
3608     // that they shouldn't be wielding.
3609     // Note that this is only a problem for equipables
3610     // (otherwise it would only waste a turn)
3611     if (you.equip[EQ_WEAPON] == idx
3612         && (item.base_type == OBJ_ARMOUR
3613             || item.base_type == OBJ_JEWELLERY))
3614     {
3615         wield_weapon(true, SLOT_BARE_HANDS);
3616         return;
3617     }
3618 
3619     const int type = item.base_type;
3620 
3621     // Use it
3622     switch (type)
3623     {
3624         case OBJ_WEAPONS:
3625         case OBJ_STAVES:
3626         case OBJ_MISCELLANY:
3627         case OBJ_WANDS:
3628             // Wield any unwielded item of these types.
3629             if (!equipped && item_is_wieldable(item))
3630             {
3631                 wield_weapon(true, idx);
3632                 return;
3633             }
3634             // Evoke misc. items or wands.
3635             if (item_is_evokable(item, false))
3636             {
3637                 evoke_item(idx);
3638                 return;
3639             }
3640             // Unwield wielded items.
3641             if (equipped)
3642                 wield_weapon(true, SLOT_BARE_HANDS);
3643             return;
3644 
3645         case OBJ_MISSILES:
3646             if (check_warning_inscriptions(item, OPER_FIRE))
3647                 quiver::slot_to_action(idx)->trigger(); // TODO: anything more interesting?
3648             return;
3649 
3650         case OBJ_ARMOUR:
3651             if (!form_can_wear())
3652             {
3653                 mpr("You can't wear or remove anything in your present form.");
3654                 return;
3655             }
3656             if (equipped && !equipped_weapon)
3657             {
3658                 if (check_warning_inscriptions(item, OPER_TAKEOFF))
3659                     takeoff_armour(idx);
3660             }
3661             else if (check_warning_inscriptions(item, OPER_WEAR))
3662                 wear_armour(idx);
3663             return;
3664 
3665         case OBJ_SCROLLS:
3666             if (check_warning_inscriptions(item, OPER_READ))
3667                 read(&you.inv[idx]);
3668             return;
3669 
3670         case OBJ_JEWELLERY:
3671             if (equipped && !equipped_weapon)
3672                 remove_ring(idx);
3673             else if (check_warning_inscriptions(item, OPER_PUTON))
3674                 puton_ring(idx);
3675             return;
3676 
3677         case OBJ_POTIONS:
3678             if (check_warning_inscriptions(item, OPER_QUAFF))
3679                 drink(&you.inv[idx]);
3680             return;
3681 
3682         default:
3683             return;
3684     }
3685 }
3686 #endif
3687