4 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
17 * This file includes code for eating food, drinking potions,
18 * reading scrolls, aiming wands, using staffs, zapping rods,
19 * and activating artifacts.
21 * In all cases, if the player becomes "aware" of the item's use
22 * by testing it, mark it as "aware" and reward some experience
23 * based on the object's level, always rounding up. If the player
24 * remains "unaware", mark that object "kind" as "tried".
26 * This code now correctly handles the unstacking of wands, staffs,
27 * and rods. Note the overly paranoid warning about potential pack
28 * overflow, which allows the player to use and drop a stacked item.
30 * In all "unstacking" scenarios, the "used" object is "carried" as if
31 * the player had just picked it up. In particular, this means that if
32 * the use of an item induces pack overflow, that item will be dropped.
34 * For simplicity, these routines induce a full "pack reorganization"
35 * which not only combines similar items, but also reorganizes various
36 * items to obey the current "sorting" method. This may require about
37 * 400 item comparisons, but only occasionally.
39 * There may be a BIG problem with any "effect" that can cause "changes"
40 * to the inventory. For example, a "scroll of recharging" can cause
41 * a wand/staff to "disappear", moving the inventory up. Luckily, the
42 * scrolls all appear BEFORE the staffs/wands, so this is not a problem.
43 * But, for example, a "staff of recharging" could cause MAJOR problems.
44 * In such a case, it will be best to either (1) "postpone" the effect
45 * until the end of the function, or (2) "change" the effect, say, into
46 * giving a staff "negative" charges, or "turning a staff into a stick".
47 * It seems as though a "rod of recharging" might in fact cause problems.
48 * The basic problem is that the act of recharging (and destroying) an
49 * item causes the inducer of that action to "move", causing "o_ptr" to
50 * no longer point at the correct item, with horrifying results.
52 * Note that food/potions/scrolls no longer use bit-flags for effects,
53 * but instead use the "sval" (which is also used to sort the objects).
62 * Eat some food (from the pack or floor)
64 void do_cmd_eat_food(void)
74 /* Restrict choices to food */
75 item_tester_tval
= TV_FOOD
;
78 q
= "Eat which item? ";
79 s
= "You have nothing to eat.";
80 if (!get_item(&item
, q
, s
, (USE_INVEN
| USE_FLOOR
))) return;
82 /* Get the item (in the pack) */
85 o_ptr
= &inventory
[item
];
88 /* Get the item (on the floor) */
91 o_ptr
= &o_list
[0 - item
];
100 p_ptr
->energy_use
= 100;
102 /* Identity not known yet */
106 lev
= k_info
[o_ptr
->k_idx
].level
;
109 use_object(o_ptr
, &ident
);
111 /* Combine / Reorder the pack (later) */
112 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
114 /* We have tried it */
117 /* The player is now aware of the object */
118 if (ident
&& !object_aware_p(o_ptr
))
121 gain_exp((lev
+ (p_ptr
->lev
/ 2)) / p_ptr
->lev
);
122 p_ptr
->notice
|= PN_SQUELCH
;
126 p_ptr
->window
|= (PW_INVEN
| PW_EQUIP
);
129 /* Destroy a food in the pack */
132 inven_item_increase(item
, -1);
133 inven_item_describe(item
);
134 inven_item_optimize(item
);
137 /* Destroy a food on the floor */
140 floor_item_increase(0 - item
, -1);
141 floor_item_describe(0 - item
);
142 floor_item_optimize(0 - item
);
150 * Quaff a potion (from the pack or the floor)
152 void do_cmd_quaff_potion(void)
160 /* Restrict choices to potions */
161 item_tester_tval
= TV_POTION
;
164 q
= "Quaff which potion? ";
165 s
= "You have no potions to quaff.";
166 if (!get_item(&item
, q
, s
, (USE_INVEN
| USE_FLOOR
))) return;
168 /* Get the item (in the pack) */
171 o_ptr
= &inventory
[item
];
174 /* Get the item (on the floor) */
177 o_ptr
= &o_list
[0 - item
];
186 p_ptr
->energy_use
= 100;
188 /* Not identified yet */
192 lev
= k_info
[o_ptr
->k_idx
].level
;
194 /* Quaff the potion */
195 use_object(o_ptr
, &ident
);
197 /* Combine / Reorder the pack (later) */
198 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
200 /* The item has been tried */
203 /* An identification was made */
204 if (ident
&& !object_aware_p(o_ptr
))
207 gain_exp((lev
+ (p_ptr
->lev
/ 2)) / p_ptr
->lev
);
208 p_ptr
->notice
|= PN_SQUELCH
;
212 p_ptr
->window
|= (PW_INVEN
| PW_EQUIP
);
214 /* Destroy a potion in the pack */
217 inven_item_increase(item
, -1);
218 inven_item_describe(item
);
219 inven_item_optimize(item
);
222 /* Destroy a potion on the floor */
225 floor_item_increase(0 - item
, -1);
226 floor_item_describe(0 - item
);
227 floor_item_optimize(0 - item
);
233 * Read a scroll (from the pack or floor).
235 * Certain scrolls can be "aborted" without losing the scroll. These
236 * include scrolls with no effects but recharge or identify, which are
237 * cancelled before use. XXX Reading them still takes a turn, though.
239 void do_cmd_read_scroll(void)
241 int item
, used_up
, lev
;
249 /* Check some conditions */
250 if (p_ptr
->timed
[TMD_BLIND
])
252 msg_print("You can't see anything.");
257 msg_print("You have no light to read by.");
261 if (p_ptr
->timed
[TMD_CONFUSED
])
263 msg_print("You are too confused!");
267 /* Restrict choices to scrolls */
268 item_tester_tval
= TV_SCROLL
;
271 q
= "Read which scroll? ";
272 s
= "You have no scrolls to read.";
273 if (!get_item(&item
, q
, s
, (USE_INVEN
| USE_FLOOR
))) return;
275 /* Get the item (in the pack) */
278 o_ptr
= &inventory
[item
];
281 /* Get the item (on the floor) */
284 o_ptr
= &o_list
[0 - item
];
289 p_ptr
->energy_use
= 100;
291 /* Check for amnesia */
292 if (rand_int(2) != 0 && p_ptr
->timed
[TMD_AMNESIA
])
294 /* Can't remember how */
295 msg_print("You can't remember how to read!");
299 /* Not identified yet */
303 lev
= k_info
[o_ptr
->k_idx
].level
;
305 /* Read the scroll */
306 used_up
= use_object(o_ptr
, &ident
);
308 /* Combine / Reorder the pack (later) */
309 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
311 /* The item was tried */
314 /* An identification was made */
315 if (ident
&& !object_aware_p(o_ptr
))
318 gain_exp((lev
+ (p_ptr
->lev
/ 2)) / p_ptr
->lev
);
319 p_ptr
->notice
|= PN_SQUELCH
;
323 p_ptr
->window
|= (PW_INVEN
| PW_EQUIP
);
326 /* Hack -- allow certain scrolls to be "preserved" */
327 if (!used_up
) return;
330 /* Destroy a scroll in the pack */
333 inven_item_increase(item
, -1);
334 inven_item_describe(item
);
335 inven_item_optimize(item
);
338 /* Destroy a scroll on the floor */
341 floor_item_increase(0 - item
, -1);
342 floor_item_describe(0 - item
);
343 floor_item_optimize(0 - item
);
356 * One charge of one staff disappears.
358 * Hack -- staffs of identify can be "cancelled".
360 void do_cmd_use_staff(void)
362 int item
, chance
, lev
;
373 /* Restrict choices to staves */
374 item_tester_tval
= TV_STAFF
;
377 q
= "Use which staff? ";
378 s
= "You have no staff to use.";
379 if (!get_item(&item
, q
, s
, (USE_INVEN
| USE_FLOOR
))) return;
381 /* Get the item (in the pack) */
384 o_ptr
= &inventory
[item
];
387 /* Get the item (on the floor) */
390 o_ptr
= &o_list
[0 - item
];
394 p_ptr
->energy_use
= 100;
397 /* Not identified yet */
400 /* Extract the item level */
401 lev
= k_info
[o_ptr
->k_idx
].level
;
403 /* Base chance of success */
404 chance
= p_ptr
->skills
[SKILL_DEV
];
406 /* Confusion hurts skill */
407 if (p_ptr
->timed
[TMD_CONFUSED
]) chance
= chance
/ 2;
409 /* High level objects are harder */
410 chance
= chance
- ((lev
> 50) ? 50 : lev
);
412 /* Give everyone a (slight) chance */
413 if ((chance
< USE_DEVICE
) && (rand_int(USE_DEVICE
- chance
+ 1) == 0))
419 if ((chance
< USE_DEVICE
) || (randint(chance
) < USE_DEVICE
))
421 if (flush_failure
) flush();
422 msg_print("You failed to use the staff properly.");
426 /* Notice empty staffs */
427 if (o_ptr
->pval
<= 0)
429 if (flush_failure
) flush();
430 msg_print("The staff has no charges left.");
431 o_ptr
->ident
|= (IDENT_EMPTY
);
432 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
433 p_ptr
->window
|= (PW_INVEN
);
439 sound(MSG_USE_STAFF
);
443 use_charge
= use_object(o_ptr
, &ident
);
446 /* Combine / Reorder the pack (later) */
447 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
452 /* An identification was made */
453 if (ident
&& !object_aware_p(o_ptr
))
456 gain_exp((lev
+ (p_ptr
->lev
/ 2)) / p_ptr
->lev
);
457 p_ptr
->notice
|= PN_SQUELCH
;
461 p_ptr
->window
|= (PW_INVEN
| PW_EQUIP
);
464 /* Hack -- some uses are "free" */
465 if (!use_charge
) return;
468 /* Use a single charge */
471 /* Describe charges in the pack */
474 inven_item_charges(item
);
477 /* Describe charges on the floor */
480 floor_item_charges(0 - item
);
486 * Aim a wand (from the pack or floor).
488 * Use a single charge from a single item.
489 * Handle "unstacking" in a logical manner.
491 * For simplicity, you cannot use a stack of items from the
492 * ground. This would require too much nasty code.
494 * There are no wands which can "destroy" themselves, in the inventory
495 * or on the ground, so we can ignore this possibility. Note that this
496 * required giving "wand of wonder" the ability to ignore destruction
499 * All wands can be "cancelled" at the "Direction?" prompt for free.
501 * Note that the basic "bolt" wands do slightly less damage than the
502 * basic "bolt" rods, but the basic "ball" wands do the same damage
503 * as the basic "ball" rods.
505 void do_cmd_aim_wand(void)
516 /* Restrict choices to wands */
517 item_tester_tval
= TV_WAND
;
520 q
= "Aim which wand? ";
521 s
= "You have no wand to aim.";
522 if (!get_item(&item
, q
, s
, (USE_INVEN
| USE_FLOOR
))) return;
524 /* Get the item (in the pack) */
527 o_ptr
= &inventory
[item
];
530 /* Get the item (on the floor) */
533 o_ptr
= &o_list
[0 - item
];
539 if (!use_object(o_ptr
, &ident
)) return;
542 /* Combine / Reorder the pack (later) */
543 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
545 /* Mark it as tried */
549 lev
= k_info
[o_ptr
->k_idx
].level
;
551 /* Apply identification */
552 if (ident
&& !object_aware_p(o_ptr
))
555 gain_exp((lev
+ (p_ptr
->lev
/ 2)) / p_ptr
->lev
);
556 p_ptr
->notice
|= PN_SQUELCH
;
560 p_ptr
->window
|= (PW_INVEN
| PW_EQUIP
);
563 /* Use a single charge */
566 /* Describe the charges in the pack */
569 inven_item_charges(item
);
572 /* Describe the charges on the floor */
575 floor_item_charges(0 - item
);
586 * Unstack fully charged rods as needed.
588 * Hack -- rods of perception can be "cancelled"
589 * All rods can be cancelled at the "Direction?" prompt
591 void do_cmd_zap_rod(void)
599 /* Restrict choices to rods */
600 item_tester_tval
= TV_ROD
;
603 q
= "Zap which rod? ";
604 s
= "You have no rod to zap.";
605 if (!get_item(&item
, q
, s
, (USE_INVEN
| USE_FLOOR
))) return;
607 /* Get the item (in the pack) */
610 o_ptr
= &inventory
[item
];
613 /* Get the item (on the floor) */
616 o_ptr
= &o_list
[0 - item
];
620 if (!use_object(o_ptr
, &ident
)) return;
622 /* Combine / Reorder the pack (later) */
623 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
625 /* Tried the object */
628 /* Successfully determined the object function */
629 if (ident
&& !object_aware_p(o_ptr
))
632 int lev
= k_info
[o_ptr
->k_idx
].level
;
635 gain_exp((lev
+ (p_ptr
->lev
/ 2)) / p_ptr
->lev
);
636 p_ptr
->notice
|= PN_SQUELCH
;
640 p_ptr
->window
|= (PW_INVEN
| PW_EQUIP
);
647 * Hook to determine if an object is activatable
649 static bool item_tester_hook_activate(const object_type
*o_ptr
)
654 if (!object_known_p(o_ptr
)) return (FALSE
);
656 /* Extract the flags */
657 object_flags(o_ptr
, &f1
, &f2
, &f3
);
659 /* Check activation flag */
660 if (f3
& (TR3_ACTIVATE
)) return (TRUE
);
668 * Activate a wielded object. Wielded objects never stack.
669 * And even if they did, activatable objects never stack.
671 * Note that it always takes a turn to activate an artifact, even if
672 * the user hits "escape" at the "direction" prompt.
674 void do_cmd_activate(void)
676 int item
, lev
, chance
;
683 /* Prepare the hook */
684 item_tester_hook
= item_tester_hook_activate
;
687 q
= "Activate which item? ";
688 s
= "You have nothing to activate.";
689 if (!get_item(&item
, q
, s
, (USE_EQUIP
))) return;
691 /* Get the item (in the pack) */
694 o_ptr
= &inventory
[item
];
697 /* Get the item (on the floor) */
700 o_ptr
= &o_list
[0 - item
];
705 p_ptr
->energy_use
= 100;
708 /* Extract the item level */
709 lev
= k_info
[o_ptr
->k_idx
].level
;
711 /* Hack -- use artifact level instead */
712 if (artifact_p(o_ptr
)) lev
= a_info
[o_ptr
->name1
].level
;
714 /* Base chance of success */
715 chance
= p_ptr
->skills
[SKILL_DEV
];
717 /* Confusion hurts skill */
718 if (p_ptr
->timed
[TMD_CONFUSED
]) chance
= chance
/ 2;
720 /* High level objects are harder */
721 chance
= chance
- ((lev
> 50) ? 50 : lev
);
724 /* Give everyone a (slight) chance */
725 if ((chance
< USE_DEVICE
) && (rand_int(USE_DEVICE
- chance
+ 1) == 0))
730 /* Check for amnesia */
731 if (rand_int(2) != 0 && p_ptr
->timed
[TMD_AMNESIA
])
733 if (flush_failure
) flush();
734 msg_print("You can't remember how to activate it.");
739 if ((chance
< USE_DEVICE
) || (randint(chance
) < USE_DEVICE
))
741 if (flush_failure
) flush();
742 msg_print("You failed to activate it properly.");
746 /* Activate the object */
747 (void)use_object(o_ptr
, &ident
);