root/trunk/src/cmd6.c

Revision 918, 6.5 kB (checked in by takkaria, 3 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: cmd6.c
3  * Purpose: Eating/quaffing/reading/aiming/staving/zapping/activating
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 #include "effects.h"
23
24
25
26 /*
27  * Check to see if the player can use a rod/wand/staff/activatable object.
28  */
29 static int check_devices(object_type *o_ptr)
30 {
31         int lev, chance;
32         const char *msg;
33         const char *what = NULL;
34
35         /* Get the right string */
36         switch (o_ptr->tval)
37         {
38                 case TV_ROD:   msg = "zap the rod";   break;
39                 case TV_WAND:  msg = "use the wand";  what = "wand"break;
40                 case TV_STAFF: msg = "use the staff"; what = "staff"; break;
41                 default:       msg = "activate it"break;
42         }
43
44         /* Extract the item level */
45         if (artifact_p(o_ptr))
46                 lev = a_info[o_ptr->name1].level;
47         else
48                 lev = k_info[o_ptr->k_idx].level;
49
50         /* Base chance of success */
51         chance = p_ptr->skills[SKILL_DEVICE];
52
53         /* Confusion hurts skill */
54         if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_AMNESIA])
55                 chance = chance / 2;
56
57         /* High level objects are harder */
58         chance -= MIN(lev, 50);
59
60         /* Give everyone a (slight) chance */
61         if ((chance < USE_DEVICE) && one_in_(USE_DEVICE - chance + 1))
62         {
63                 chance = USE_DEVICE;
64         }
65
66         /* Roll for usage */
67         if ((chance < USE_DEVICE) || (randint1(chance) < USE_DEVICE))
68         {
69                 if (flush_failure) flush();
70                 msg_format("You failed to %s properly.", msg);
71                 return FALSE;
72         }
73
74         /* Notice empty staffs */
75         if (what && o_ptr->pval <= 0)
76         {
77                 if (flush_failure) flush();
78                 msg_format("The %s has no charges left.", what);
79                 o_ptr->ident |= (IDENT_EMPTY);
80                 return FALSE;
81         }
82
83         return TRUE;
84 }
85
86 /*
87  * Return the chance of an effect beaming, given a tval.
88  */
89 static int beam_chance(int tval)
90 {
91         switch (tval)
92         {
93                 case TV_WAND: return 20;
94                 case TV_RODreturn 10;
95         }
96
97         return 0;
98 }
99
100
101 /*
102  * Use an object the right way.
103  *
104  * There may be a BIG problem with any "effect" that can cause "changes"
105  * to the inventory.  For example, a "scroll of recharging" can cause
106  * a wand/staff to "disappear", moving the inventory up.  Luckily, the
107  * scrolls all appear BEFORE the staffs/wands, so this is not a problem.
108  * But, for example, a "staff of recharging" could cause MAJOR problems.
109  * In such a case, it will be best to either (1) "postpone" the effect
110  * until the end of the function, or (2) "change" the effect, say, into
111  * giving a staff "negative" charges, or "turning a staff into a stick".
112  * It seems as though a "rod of recharging" might in fact cause problems.
113  * The basic problem is that the act of recharging (and destroying) an
114  * item causes the inducer of that action to "move", causing "o_ptr" to
115  * no longer point at the correct item, with horrifying results.
116  */
117 void do_cmd_use(object_type *o_ptr, int item, int snd, use_type use)
118 {
119         int effect;
120         bool ident = FALSE, used;
121         bool was_aware = object_aware_p(o_ptr);
122         int dir = 5;
123         int px = p_ptr->px, py = p_ptr->py;
124
125         /* Figure out effect to use */
126         if (o_ptr->name1)
127                 effect = a_info[o_ptr->name1].effect;
128         else
129                 effect = k_info[o_ptr->k_idx].effect;
130
131         /* If the item requires a direction, get one (allow cancelling) */
132         if (effect_aim(effect) ||
133             (o_ptr->tval == TV_WAND) ||
134             (o_ptr->tval == TV_ROD && !object_aware_p(o_ptr)))
135         {
136                 /* Get a direction, allow cancel */
137                 if (!get_aim_dir(&dir))
138                         return;
139         }
140
141         /* Use energy regardless of failure */
142         p_ptr->energy_use = 100;
143
144         /* Check for use */
145         if (use == USE_CHARGE || use == USE_TIMEOUT)
146         {
147                 if (!check_devices(o_ptr))
148                         return;
149         }
150
151         /* Special message for artifacts */
152         if (artifact_p(o_ptr))
153         {
154                 message(snd, 0, "You activate it.");
155                 msg_print(a_text + a_info[o_ptr->name1].effect_msg);
156         }
157         else
158         {
159                 /* Make a noise! */
160                 sound(snd);
161         }
162
163         /* A bit of a hack to make ID work better.
164            -- Check for "obvious" effects beforehand. */
165         if (effect_obvious(effect)) object_aware(o_ptr);
166
167         /* Do effect */
168         used = effect_do(effect, &ident, was_aware, dir, beam_chance(o_ptr->tval));
169
170         /* Food feeds the player */
171         if (o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION)
172                 (void)set_food(p_ptr->food + o_ptr->pval);
173
174         if (!used && !ident) return;
175
176         /* Mark as tried and redisplay */
177         p_ptr->notice |= (PN_COMBINE | PN_REORDER);
178         p_ptr->redraw |= (PR_INVEN | PR_EQUIP);
179
180
181         /*
182          * If the player becomes aware of the item's function, then mark it as
183          * aware and reward the player with some experience.  Otherwise, mark
184          * it as "tried".
185          */
186         if (ident && !was_aware)
187         {
188                 /* Object level */
189                 int lev = k_info[o_ptr->k_idx].level;
190
191                 object_aware(o_ptr);
192                 if (o_ptr->tval == TV_ROD) object_known(o_ptr);
193                 gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev);
194                 p_ptr->notice |= PN_SQUELCH;
195         }
196         else
197         {
198                 object_tried(o_ptr);
199         }
200
201         /* Chargeables act differently to single-used items when not used up */
202         if (used && use == USE_CHARGE)
203         {
204                 /* Use a single charge */
205                 o_ptr->pval--;
206
207                 /* Describe charges */
208                 if (item >= 0)
209                         inven_item_charges(item);
210                 else
211                         floor_item_charges(0 - item);
212         }
213         else if (used && use == USE_TIMEOUT)
214         {
215                 /* Artifacts use their own special field */
216                 if (o_ptr->name1)
217                 {
218                         const artifact_type *a_ptr = &a_info[o_ptr->name1];
219                         o_ptr->timeout = a_ptr->time_base + damroll(a_ptr->time_dice, a_ptr->time_sides);
220                 }
221                 else
222                 {
223                         const object_kind *k_ptr = &k_info[o_ptr->k_idx];
224                         o_ptr->timeout += k_ptr->time_base + damroll(k_ptr->time_dice, k_ptr->time_sides);
225                 }
226         }
227         else if (used && use == USE_SINGLE)
228         {
229                 /* Destroy a potion in the pack */
230                 if (item >= 0)
231                 {
232                         inven_item_increase(item, -1);
233                         inven_item_describe(item);
234                         inven_item_optimize(item);
235                 }
236
237                 /* Destroy a potion on the floor */
238                 else
239                 {
240                         floor_item_increase(0 - item, -1);
241                         floor_item_describe(0 - item);
242                         floor_item_optimize(0 - item);
243                 }
244         }
245        
246         /* Hack to make Glyph of Warding work properly */
247         if (cave_feat[py][px] == FEAT_GLYPH)
248         {
249                 /* Shift any objects to further away */
250                 for (o_ptr = get_first_object(py, px); o_ptr; o_ptr = get_next_object(o_ptr))
251                 {
252                         drop_near(o_ptr, 0, py, px);
253                 }
254                
255                 /* Delete the "moved" objects from their original position */
256                 delete_object(py, px);
257         }
258
259        
260 }
Note: See TracBrowser for help on using the browser.