root/trunk/src/cmd-obj.c

Revision 918, 14.8 kB (checked in by takkaria, 2 months ago)

Use consistent newlines everywhere, and also set the svn:eol-style property to native on all text files.

  • Property svn:eol-style set to native
Line 
1 /*
2  * File: cmd-obj.c
3  * Purpose: Handle objects in various ways
4  *
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  * Copyright (c) 2007 Andrew Sidwell
7  *
8  * This work is free software; you can redistribute it and/or modify it
9  * under the terms of either:
10  *
11  * a) the GNU General Public License as published by the Free Software
12  *    Foundation, version 2, or
13  *
14  * b) the "Angband licence":
15  *    This software may be copied and distributed for educational, research,
16  *    and not for profit purposes provided that this copyright and statement
17  *    are included in all such copies.  Other copyrights may also apply.
18  */
19 #include "angband.h"
20 #include "tvalsval.h"
21 #include "cmds.h"
22
23
24 /*** Inscriptions ***/
25
26 /* Can has inscrip pls */
27 static bool obj_has_inscrip(const object_type *o_ptr)
28 {
29         return (o_ptr->note ? TRUE : FALSE);
30 }
31
32 /* Remove inscription */
33 static void obj_uninscribe(object_type *o_ptr, int item)
34 {
35         o_ptr->note = 0;
36         msg_print("Inscription removed.");
37
38         p_ptr->notice |= (PN_COMBINE | PN_SQUELCH);
39         p_ptr->redraw |= (PR_INVEN | PR_EQUIP);
40 }
41
42 /* Add inscription */
43 static void obj_inscribe(object_type *o_ptr, int item)
44 {
45         char o_name[80];
46         char tmp[80] = "";
47
48         object_desc(o_name, sizeof(o_name), o_ptr, TRUE, ODESC_FULL);
49         msg_format("Inscribing %s.", o_name);
50         message_flush();
51
52         /* Use old inscription */
53         if (o_ptr->note)
54                 strnfmt(tmp, sizeof(tmp), "%s", quark_str(o_ptr->note));
55
56         /* Get a new inscription (possibly empty) */
57         if (get_string("Inscription: ", tmp, sizeof(tmp)))
58         {
59                 o_ptr->note = quark_add(tmp);
60
61                 p_ptr->notice |= (PN_COMBINE | PN_SQUELCH);
62                 p_ptr->redraw |= (PR_INVEN | PR_EQUIP);
63         }
64 }
65
66
67 /*** Examination ***/
68 static void obj_examine(object_type *o_ptr, int item)
69 {
70         text_out_hook = text_out_to_screen;
71         screen_save();
72
73         object_info_header(o_ptr);
74         if (!object_info_known(o_ptr))
75                 text_out("\n\nThis item does not seem to possess any special abilities.");
76
77         text_out_c(TERM_L_BLUE, "\n\n[Press any key to continue]\n");
78         (void)anykey();
79
80         screen_load();
81 }
82
83
84
85 /*** Taking off/putting on ***/
86
87 /* Can only take off non-cursed items */
88 static bool obj_can_takeoff(const object_type *o_ptr)
89 {
90         return !cursed_p(o_ptr);
91 }
92
93 /* Can only put on wieldable items */
94 static bool obj_can_wear(const object_type *o_ptr)
95 {
96         return (wield_slot(o_ptr) >= INVEN_WIELD);
97 }
98
99
100 /* Take off an item */
101 static void obj_takeoff(object_type *o_ptr, int item)
102 {
103         (void)inven_takeoff(item, 255);
104         p_ptr->energy_use = 50;
105 }
106
107 /* Wield or wear an item */
108 static void obj_wear(object_type *o_ptr, int item)
109 {
110         int slot;
111         object_type *equip_o_ptr;
112
113         char o_name[80];
114
115         unsigned n;
116
117         /* Check the slot */
118         slot = wield_slot(o_ptr);
119         equip_o_ptr = &inventory[slot];
120
121         /* Check for existing wielded item */
122         if (equip_o_ptr)
123         {
124                 /* Prevent wielding into a cursed slot */
125                 if (cursed_p(equip_o_ptr))
126                 {
127                         /* Message */
128                         object_desc(o_name, sizeof(o_name), equip_o_ptr, FALSE, ODESC_BASE);
129                         msg_format("The %s you are %s appears to be cursed.",
130                                    o_name, describe_use(slot));
131
132                         return;
133                 }
134
135                 /* "!t" checks for taking off */
136                 n = check_for_inscrip(equip_o_ptr, "!t");
137                 while (n--)
138                 {
139                         /* Prompt */
140                         object_desc(o_name, sizeof(o_name), equip_o_ptr, TRUE, ODESC_FULL);
141
142                         /* Forget it */
143                         if (!get_check(format("Really take off %s? ", o_name))) return;
144                 }
145         }
146
147         wield_item(o_ptr, item);
148 }
149
150 /* Drop an item */
151 static void obj_drop(object_type *o_ptr, int item)
152 {
153         int amt;
154
155         amt = get_quantity(NULL, o_ptr->number);
156         if (amt <= 0) return;
157
158         /* Hack -- Cannot remove cursed items */
159         if ((item >= INVEN_WIELD) && cursed_p(o_ptr))
160         {
161                 msg_print("Hmmm, it seems to be cursed.");
162                 return;
163         }
164
165         inven_drop(item, amt);
166         p_ptr->energy_use = 50;
167 }
168
169
170 /*** Squelch stuff ***/
171
172 /* See if one can squelch a given kind of item. */
173 static bool obj_can_set_squelch(const object_type *o_ptr)
174 {
175         object_kind *k_ptr = &k_info[o_ptr->k_idx];
176
177         if (k_ptr->squelch) return FALSE;
178         if (!squelch_tval(o_ptr->tval)) return FALSE;
179
180         /* Only allow if aware */
181         return object_aware_p(o_ptr);
182 }
183
184 /*
185  * Mark item as "squelch".
186  */
187 static void obj_set_squelch(object_type *o_ptr, int item)
188 {
189         k_info[o_ptr->k_idx].squelch = TRUE;
190
191         /* Hack -- Cannot remove cursed items */
192         if ((item >= INVEN_WIELD) && cursed_p(o_ptr))
193                 return;
194
195         if (item >= 0)
196                 inven_drop(item, o_ptr->number);
197 }
198
199
200 /*** Casting and browsing ***/
201
202 static bool obj_can_browse(const object_type *o_ptr)
203 {
204         if (o_ptr->tval != cp_ptr->spell_book) return FALSE;
205         return TRUE;
206 }
207
208
209 static bool obj_cast_pre(void)
210 {
211         if (!cp_ptr->spell_book)
212         {
213                 msg_print("You cannot pray or produce magics.");
214                 return FALSE;
215         }
216
217         if (p_ptr->timed[TMD_BLIND] || no_lite())
218         {
219                 msg_print("You cannot see!");
220                 return FALSE;
221         }
222
223         if (p_ptr->timed[TMD_CONFUSED])
224         {
225                 msg_print("You are too confused!");
226                 return FALSE;
227         }
228
229         return TRUE;
230 }
231
232 /* A prerequisite to studying */
233 static bool obj_study_pre(void)
234 {
235         if (!obj_cast_pre())
236                 return FALSE;
237
238         if (!p_ptr->new_spells)
239         {
240                 cptr p = ((cp_ptr->spell_book == TV_MAGIC_BOOK) ? "spell" : "prayer");
241                 msg_format("You cannot learn any new %ss!", p);
242                 return FALSE;
243         }
244
245         return TRUE;
246 }
247
248
249 /* Peruse spells in a book */
250 static void obj_browse(object_type *o_ptr, int item)
251 {
252         do_cmd_browse_aux(o_ptr);
253 }
254
255 /* Study a book to gain a new spell */
256 static void obj_study(object_type *o_ptr, int item)
257 {
258         int spell;
259
260         /* Track the object kind */
261         object_kind_track(o_ptr->k_idx);
262         handle_stuff();
263
264         /* Choose a spell to study */
265         spell = spell_choose_new(o_ptr);
266         if (spell < 0) return;
267
268         /* Learn the spell */
269         spell_learn(spell);
270         p_ptr->energy_use = 100;
271 }
272
273 /* Cast a spell from a book */
274 static void obj_cast(object_type *o_ptr, int item)
275 {
276         int spell;
277         cptr verb = ((cp_ptr->spell_book == TV_MAGIC_BOOK) ? "cast" : "recite");
278
279         /* Track the object kind */
280         object_kind_track(o_ptr->k_idx);
281         handle_stuff();
282
283         /* Ask for a spell */
284         spell = get_spell(o_ptr, verb, TRUE, FALSE);
285         if (spell < 0)
286         {
287                 cptr p = ((cp_ptr->spell_book == TV_MAGIC_BOOK) ? "spell" : "prayer");
288
289                 if (spell == -2) msg_format("You don't know any %ss in that book.", p);
290                 return;
291         }
292
293         /* Cast a spell */
294         if (spell_cast(spell))
295             p_ptr->energy_use = 100;
296 }
297
298
299 /*** Using items the traditional way ***/
300
301 /* Determine if the player can read scrolls. */
302 static bool obj_read_pre(void)
303 {
304         if (p_ptr->timed[TMD_BLIND])
305         {
306                 msg_print("You can't see anything.");
307                 return FALSE;
308         }
309
310         if (no_lite())
311         {
312                 msg_print("You have no light to read by.");
313                 return FALSE;
314         }
315
316         if (p_ptr->timed[TMD_CONFUSED])
317         {
318                 msg_print("You are too confused to read!");
319                 return FALSE;
320         }
321
322         if (p_ptr->timed[TMD_AMNESIA])
323         {
324                 msg_print("You can't remember how to read!");
325                 return FALSE;
326         }
327
328         return TRUE;
329 }
330
331 /* Basic tval testers */
332 static bool obj_is_staff(const object_type *o_ptr)  { return o_ptr->tval == TV_STAFF; }
333 static bool obj_is_wand(const object_type *o_ptr)   { return o_ptr->tval == TV_WAND; }
334 static bool obj_is_potion(const object_type *o_ptr) { return o_ptr->tval == TV_POTION; }
335 static bool obj_is_scroll(const object_type *o_ptr) { return o_ptr->tval == TV_SCROLL; }
336 static bool obj_is_food(const object_type *o_ptr)   { return o_ptr->tval == TV_FOOD; }
337
338 /* Determine if an object is zappable */
339 static bool obj_can_zap(const object_type *o_ptr)
340 {
341         const object_kind *k_ptr = &k_info[o_ptr->k_idx];
342         if (o_ptr->tval != TV_ROD) return FALSE;
343
344         /* All still charging? */
345         if (o_ptr->number <= (o_ptr->timeout + (k_ptr->time_base - 1)) / k_ptr->time_base) return FALSE;
346
347         /* Otherwise OK */
348         return TRUE;
349 }
350
351 /* Determine if an object is activatable */
352 static bool obj_can_activate(const object_type *o_ptr)
353 {
354         u32b f1, f2, f3;
355
356         /* Not known */
357         if (!object_known_p(o_ptr)) return (FALSE);
358
359         /* Check the recharge */
360         if (o_ptr->timeout) return (FALSE);
361
362         /* Extract the flags */
363         object_flags(o_ptr, &f1, &f2, &f3);
364
365         /* Check activation flag */
366         return (f3 & TR3_ACTIVATE) ? TRUE : FALSE;
367 }
368
369
370 /* Use a staff */
371 static void obj_use_staff(object_type *o_ptr, int item)
372 {
373         do_cmd_use(o_ptr, item, MSG_USE_STAFF, USE_CHARGE);
374 }
375
376 /* Aim a wand */
377 static void obj_use_wand(object_type *o_ptr, int item)
378 {
379         do_cmd_use(o_ptr, item, MSG_ZAP_ROD, USE_CHARGE);
380 }
381
382 /* Zap a rod */
383 static void obj_use_rod(object_type *o_ptr, int item)
384 {
385         do_cmd_use(o_ptr, item, MSG_ZAP_ROD, USE_TIMEOUT);
386 }
387
388 /* Activate a wielded object */
389 static void obj_activate(object_type *o_ptr, int item)
390 {
391         do_cmd_use(o_ptr, item, MSG_ACT_ARTIFACT, USE_TIMEOUT);
392 }
393
394 /* Eat some food */
395 static void obj_use_food(object_type *o_ptr, int item)
396 {
397         do_cmd_use(o_ptr, item, MSG_EAT, USE_SINGLE);
398 }
399
400 /* Quaff a potion (from the pack or the floor) */
401 static void obj_use_potion(object_type *o_ptr, int item)
402 {
403         do_cmd_use(o_ptr, item, MSG_QUAFF, USE_SINGLE);
404 }
405
406 /* Read a scroll (from the pack or floor) */
407 static void obj_use_scroll(object_type *o_ptr, int item)
408 {
409         do_cmd_use(o_ptr, item, MSG_GENERIC, USE_SINGLE);
410 }
411
412 /*** Refuelling ***/
413
414 static bool obj_refill_pre(void)
415 {
416         object_type *o_ptr;
417         u32b f1, f2, f3;
418
419         o_ptr = &inventory[INVEN_LITE];
420         object_flags(o_ptr, &f1, &f2, &f3);
421
422         if (o_ptr->tval != TV_LITE)
423         {
424                 msg_print("You are not wielding a light.");
425                 return FALSE;
426         }
427
428         else if (f3 & TR3_NO_FUEL)
429         {
430                 msg_print("Your light cannot be refilled.");
431                 return FALSE;
432         }
433
434         return TRUE;
435 }
436
437 static bool obj_can_refill(const object_type *o_ptr)
438 {
439         u32b f1, f2, f3;
440         const object_type *j_ptr = &inventory[INVEN_LITE];
441
442         /* Get flags */
443         object_flags(o_ptr, &f1, &f2, &f3);
444
445         if (j_ptr->sval == SV_LITE_LANTERN)
446         {
447                 /* Flasks of oil are okay */
448                 if (o_ptr->tval == TV_FLASK) return (TRUE);
449         }
450
451         /* Non-empty, non-everburning sources are okay */
452         if ((o_ptr->tval == TV_LITE) &&
453             (o_ptr->sval == j_ptr->sval) &&
454             (o_ptr->timeout > 0) &&
455                 !(f3 & TR3_NO_FUEL))
456         {
457                 return (TRUE);
458         }
459
460         /* Assume not okay */
461         return (FALSE);
462 }
463
464 static void obj_refill(object_type *o_ptr, int item)
465 {
466         object_type *j_ptr = &inventory[INVEN_LITE];
467         p_ptr->energy_use = 50;
468
469         /* It's a lamp */
470         if (j_ptr->sval == SV_LITE_LANTERN)
471                 refill_lamp(j_ptr, o_ptr, item);
472
473         /* It's a torch */
474         else if (j_ptr->sval == SV_LITE_TORCH)
475                 refuel_torch(j_ptr, o_ptr, item);
476 }
477
478
479
480
481 /*** Handling bits ***/
482
483 /* Item "action" type */
484 typedef struct
485 {
486         void (*action)(object_type *, int);
487         const char *desc;
488
489         const char *prompt;
490         const char *noop;
491
492         bool (*filter)(const object_type *o_ptr);
493         int mode;
494         bool (*prereq)(void);
495 } item_act_t;
496
497
498 /* All possible item actions */
499 static item_act_t item_actions[] =
500 {
501         { obj_uninscribe, "uninscribe",
502           "Un-inscribe which item? ", "You have nothing to un-inscribe.",
503           obj_has_inscrip, (USE_EQUIP | USE_INVEN | USE_FLOOR), NULL },
504
505         { obj_inscribe, "inscribe",
506           "Inscribe which item? ", "You have nothing to inscribe.",
507           NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR), NULL },
508
509         { obj_examine, "examine",
510           "Examine which item? ", "You have nothing to examine.",
511           NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR), NULL },
512
513         /*** Takeoff/drop/wear ***/
514         { obj_takeoff, "takeoff",
515           "Take off which item? ", "You are not wearing anything you can take off.",
516           obj_can_takeoff, USE_EQUIP, NULL },
517
518         { obj_wear, "wield",
519           "Wear/Wield which item? ", "You have nothing you can wear or wield.",
520           obj_can_wear, (USE_INVEN | USE_FLOOR), NULL },
521
522         { obj_drop, "drop",
523           "Drop which item? ", "You have nothing to drop.",
524           NULL, (USE_EQUIP | USE_INVEN), NULL },
525
526         { obj_set_squelch, "setsquelch",
527           "Squelch which item kind? ", "You have nothing you can squelch.",
528           obj_can_set_squelch, (USE_INVEN | USE_FLOOR), NULL },
529
530         /*** Spellbooks ***/
531         { obj_browse, "browse",
532           "Browse which book? ", "You have no books that you can read.",
533           obj_can_browse, (USE_INVEN | USE_FLOOR), NULL },
534
535         { obj_study, "study",
536           "Study which book? ", "You have no books that you can read.",
537           obj_can_browse, (USE_INVEN | USE_FLOOR), obj_study_pre },
538
539         { obj_cast, "cast",
540           "Use which book? ", "You have no books that you can read.",
541           obj_can_browse, (USE_INVEN | USE_FLOOR), obj_cast_pre },
542
543         /*** Item usage ***/
544         { obj_use_staff, "use",
545           "Use which staff? ", "You have no staff to use.",
546           obj_is_staff, (USE_INVEN | USE_FLOOR), NULL },
547
548         { obj_use_wand, "aim",
549       "Aim which wand? ", "You have no wand to aim.",
550           obj_is_wand, (USE_INVEN | USE_FLOOR), NULL },
551
552         { obj_use_rod, "zap",
553       "Zap which rod? ", "You have no charged rods to zap.",
554           obj_can_zap, (USE_INVEN | USE_FLOOR), NULL },
555
556         { obj_activate, "activate",
557       "Activate which item? ", "You have nothing to activate.",
558           obj_can_activate, USE_EQUIP, NULL },
559
560         { obj_use_food, "eat",
561       "Eat which item? ", "You have nothing to eat.",
562           obj_is_food, (USE_INVEN | USE_FLOOR), NULL },
563
564         { obj_use_potion, "quaff",
565       "Quaff which potion? ", "You have no potions to quaff.",
566           obj_is_potion, (USE_INVEN | USE_FLOOR), NULL },
567
568         { obj_use_scroll, "read",
569       "Read which scroll? ", "You have no scrolls to read.",
570           obj_is_scroll, (USE_INVEN | USE_FLOOR), obj_read_pre },
571
572         { obj_refill, "refill",
573       "Refuel with what fuel source? ", "You have nothing to refuel with.",
574           obj_can_refill, (USE_INVEN | USE_FLOOR), obj_refill_pre },
575 };
576
577
578 /* List matching up to item_actions[] */
579 typedef enum
580 {
581         ACTION_UNINSCRIBE = 0,
582         ACTION_INSCRIBE,
583         ACTION_EXAMINE,
584         ACTION_TAKEOFF,
585         ACTION_WIELD,
586         ACTION_DROP,
587         ACTION_SET_SQUELCH,
588
589         ACTION_BROWSE,
590         ACTION_STUDY,
591         ACTION_CAST,
592
593         ACTION_USE_STAFF,
594         ACTION_AIM_WAND,
595         ACTION_ZAP_ROD,
596         ACTION_ACTIVATE,
597         ACTION_EAT_FOOD,
598         ACTION_QUAFF_POTION,
599         ACTION_READ_SCROLL,
600         ACTION_REFILL
601 } item_act;
602
603
604
605 /*** Old-style noun-verb functions ***/
606
607 /* Generic "do item action" function */
608 static void do_item(item_act act)
609 {
610         int item;
611         object_type *o_ptr;
612
613         cptr q, s;
614
615         if (item_actions[act].prereq)
616         {
617                 if (!item_actions[act].prereq())
618                         return;
619         }
620
621         /* Get item */
622         q = item_actions[act].prompt;
623         s = item_actions[act].noop;
624         item_tester_hook = item_actions[act].filter;
625         if (!get_item(&item, q, s, item_actions[act].mode)) return;
626
627         /* Get the item */
628         if (item >= 0)
629                 o_ptr = &inventory[item];
630         else
631                 o_ptr = &o_list[0 - item];
632
633         item_actions[act].action(o_ptr, item);
634 }
635
636 /* Wrappers */
637 void do_cmd_uninscribe(void) { do_item(ACTION_UNINSCRIBE); }
638 void do_cmd_inscribe(void) { do_item(ACTION_INSCRIBE); }
639 void do_cmd_observe(void) { do_item(ACTION_EXAMINE); }
640 void do_cmd_takeoff(void) { do_item(ACTION_TAKEOFF); }
641 void do_cmd_wield(void) { do_item(ACTION_WIELD); }
642 void do_cmd_drop(void) { do_item(ACTION_DROP); }
643 void do_cmd_mark_squelch(void) { do_item(ACTION_SET_SQUELCH); }
644 void do_cmd_browse(void) { do_item(ACTION_BROWSE); }
645 void do_cmd_study(void) { do_item(ACTION_STUDY); }
646 void do_cmd_cast(void) { do_item(ACTION_CAST); }
647 void do_cmd_pray(void) { do_item(ACTION_CAST); }
648 void do_cmd_use_staff(void) { do_item(ACTION_USE_STAFF); }
649 void do_cmd_aim_wand(void) { do_item(ACTION_AIM_WAND); }
650 void do_cmd_zap_rod(void) { do_item(ACTION_ZAP_ROD); }
651 void do_cmd_activate(void) { do_item(ACTION_ACTIVATE); }
652 void do_cmd_eat_food(void) { do_item(ACTION_EAT_FOOD); }
653 void do_cmd_quaff_potion(void) { do_item(ACTION_QUAFF_POTION); }
654 void do_cmd_read_scroll(void) { do_item(ACTION_READ_SCROLL); }
655 void do_cmd_refill(void) { do_item(ACTION_REFILL); }
Note: See TracBrowser for help on using the browser.