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