OSDN Git Service

[Refactor] #37353 object-kind.c/h を作成して関連構造体と変数を移動.
[hengband/hengband.git] / src / cmd-zaprod.c
1 #include "angband.h"
2 #include "util.h"
3
4 #include "avatar.h"
5 #include "player-status.h"
6 #include "player-effects.h"
7 #include "objectkind.h"
8 #include "object-hook.h"
9 #include "spells.h"
10 #include "spells-status.h"
11 #include "spells-floor.h"
12 #include "cmd-basic.h"
13 #include "floor.h"
14
15 /*!
16  * @brief ロッドの効果を発動する
17  * @param sval オブジェクトのsval
18  * @param dir 発動目標の方向ID
19  * @param use_charge チャージを消費したかどうかを返す参照ポインタ
20  * @param powerful 強力発動上の処理ならばTRUE
21  * @param magic 魔道具術上の処理ならばTRUE
22  * @return 発動により効果内容が確定したならばTRUEを返す
23  */
24 int rod_effect(OBJECT_SUBTYPE_VALUE sval, DIRECTION dir, bool *use_charge, bool powerful, bool magic)
25 {
26         int ident = FALSE;
27         PLAYER_LEVEL lev = powerful ? p_ptr->lev * 2 : p_ptr->lev;
28         POSITION detect_rad = powerful ? DETECT_RAD_DEFAULT * 3 / 2 : DETECT_RAD_DEFAULT;
29         POSITION rad = powerful ? 3 : 2;
30
31         /* Unused */
32         (void)magic;
33
34         /* Analyze the rod */
35         switch (sval)
36         {
37         case SV_ROD_DETECT_TRAP:
38         {
39                 if (detect_traps(detect_rad, (bool)(dir ? FALSE : TRUE))) ident = TRUE;
40                 break;
41         }
42
43         case SV_ROD_DETECT_DOOR:
44         {
45                 if (detect_doors(detect_rad)) ident = TRUE;
46                 if (detect_stairs(detect_rad)) ident = TRUE;
47                 break;
48         }
49
50         case SV_ROD_IDENTIFY:
51         {
52                 if (powerful) {
53                         if (!identify_fully(FALSE)) *use_charge = FALSE;
54                 }
55                 else {
56                         if (!ident_spell(FALSE)) *use_charge = FALSE;
57                 }
58                 ident = TRUE;
59                 break;
60         }
61
62         case SV_ROD_RECALL:
63         {
64                 if (!recall_player(p_ptr, randint0(21) + 15)) *use_charge = FALSE;
65                 ident = TRUE;
66                 break;
67         }
68
69         case SV_ROD_ILLUMINATION:
70         {
71                 if (lite_area(damroll(2, 8), (powerful ? 4 : 2))) ident = TRUE;
72                 break;
73         }
74
75         case SV_ROD_MAPPING:
76         {
77                 map_area(powerful ? DETECT_RAD_MAP * 3 / 2 : DETECT_RAD_MAP);
78                 ident = TRUE;
79                 break;
80         }
81
82         case SV_ROD_DETECTION:
83         {
84                 detect_all(detect_rad);
85                 ident = TRUE;
86                 break;
87         }
88
89         case SV_ROD_PROBING:
90         {
91                 probing();
92                 ident = TRUE;
93                 break;
94         }
95
96         case SV_ROD_CURING:
97         {
98                 if (true_healing(0)) ident = TRUE;
99                 if (set_shero(0, TRUE)) ident = TRUE;
100                 break;
101         }
102
103         case SV_ROD_HEALING:
104         {
105                 if(cure_critical_wounds(powerful ? 750 : 500)) ident = TRUE;
106                 break;
107         }
108
109         case SV_ROD_RESTORATION:
110         {
111                 if(restore_level()) ident = TRUE;
112                 if(restore_all_status()) ident = TRUE;
113                 break;
114         }
115
116         case SV_ROD_SPEED:
117         {
118                 if (set_fast(randint1(30) + (powerful ? 30 : 15), FALSE)) ident = TRUE;
119                 break;
120         }
121
122         case SV_ROD_PESTICIDE:
123         {
124                 if (dispel_monsters(powerful ? 8 : 4)) ident = TRUE;
125                 break;
126         }
127
128         case SV_ROD_TELEPORT_AWAY:
129         {
130                 int distance = MAX_SIGHT * (powerful ? 8 : 5);
131                 if (teleport_monster(dir, distance)) ident = TRUE;
132                 break;
133         }
134
135         case SV_ROD_DISARMING:
136         {
137                 if (disarm_trap(dir)) ident = TRUE;
138                 if (powerful && disarm_traps_touch()) ident = TRUE;
139                 break;
140         }
141
142         case SV_ROD_LITE:
143         {
144                 HIT_POINT dam = damroll((powerful ? 12 : 6), 8);
145                 msg_print(_("青く輝く光線が放たれた。", "A line of blue shimmering light appears."));
146                 (void)lite_line(dir, dam);
147                 ident = TRUE;
148                 break;
149         }
150
151         case SV_ROD_SLEEP_MONSTER:
152         {
153                 if (sleep_monster(dir, lev)) ident = TRUE;
154                 break;
155         }
156
157         case SV_ROD_SLOW_MONSTER:
158         {
159                 if (slow_monster(dir, lev)) ident = TRUE;
160                 break;
161         }
162
163         case SV_ROD_HYPODYNAMIA:
164         {
165                 if (hypodynamic_bolt(dir, 70 + 3 * lev / 2)) ident = TRUE;
166                 break;
167         }
168
169         case SV_ROD_POLYMORPH:
170         {
171                 if (poly_monster(dir, lev)) ident = TRUE;
172                 break;
173         }
174
175         case SV_ROD_ACID_BOLT:
176         {
177                 fire_bolt_or_beam(10, GF_ACID, dir, damroll(6 + lev / 7, 8));
178                 ident = TRUE;
179                 break;
180         }
181
182         case SV_ROD_ELEC_BOLT:
183         {
184                 fire_bolt_or_beam(10, GF_ELEC, dir, damroll(4 + lev / 9, 8));
185                 ident = TRUE;
186                 break;
187         }
188
189         case SV_ROD_FIRE_BOLT:
190         {
191                 fire_bolt_or_beam(10, GF_FIRE, dir, damroll(7 + lev / 6, 8));
192                 ident = TRUE;
193                 break;
194         }
195
196         case SV_ROD_COLD_BOLT:
197         {
198                 fire_bolt_or_beam(10, GF_COLD, dir, damroll(5 + lev / 8, 8));
199                 ident = TRUE;
200                 break;
201         }
202
203         case SV_ROD_ACID_BALL:
204         {
205                 fire_ball(GF_ACID, dir, 60 + lev, rad);
206                 ident = TRUE;
207                 break;
208         }
209
210         case SV_ROD_ELEC_BALL:
211         {
212                 fire_ball(GF_ELEC, dir, 40 + lev, rad);
213                 ident = TRUE;
214                 break;
215         }
216
217         case SV_ROD_FIRE_BALL:
218         {
219                 fire_ball(GF_FIRE, dir, 70 + lev, rad);
220                 ident = TRUE;
221                 break;
222         }
223
224         case SV_ROD_COLD_BALL:
225         {
226                 fire_ball(GF_COLD, dir, 50 + lev, rad);
227                 ident = TRUE;
228                 break;
229         }
230
231         case SV_ROD_HAVOC:
232         {
233                 call_chaos();
234                 ident = TRUE;
235                 break;
236         }
237
238         case SV_ROD_STONE_TO_MUD:
239         {
240                 HIT_POINT dam = powerful ? 40 + randint1(60) : 20 + randint1(30);
241                 if (wall_to_mud(dir, dam)) ident = TRUE;
242                 break;
243         }
244
245         case SV_ROD_AGGRAVATE:
246         {
247                 aggravate_monsters(0);
248                 ident = TRUE;
249                 break;
250         }
251         }
252         return ident;
253 }
254
255 /*!
256 * @brief ロッドを使うコマンドのサブルーチン /
257 * Activate (zap) a Rod
258 * @param item 使うオブジェクトの所持品ID
259 * @return なし
260 * @details
261 * <pre>
262 * Unstack fully charged rods as needed.
263 * Hack -- rods of perception/genocide can be "cancelled"
264 * All rods can be cancelled at the "Direction?" prompt
265 * pvals are defined for each rod in k_info. -LM-
266 * </pre>
267 */
268 void do_cmd_zap_rod_aux(INVENTORY_IDX item)
269 {
270         int ident, chance, lev, fail;
271         DIRECTION dir = 0;
272         object_type *o_ptr;
273         bool success;
274
275         /* Hack -- let perception get aborted */
276         bool use_charge = TRUE;
277
278         object_kind *k_ptr;
279
280         /* Get the item (in the pack) */
281         if (item >= 0)
282         {
283                 o_ptr = &p_ptr->inventory_list[item];
284         }
285
286         /* Get the item (on the floor) */
287         else
288         {
289                 o_ptr = &current_floor_ptr->o_list[0 - item];
290         }
291
292
293         /* Mega-Hack -- refuse to zap a pile from the ground */
294         if ((item < 0) && (o_ptr->number > 1))
295         {
296                 msg_print(_("まずはロッドを拾わなければ。", "You must first pick up the rods."));
297                 return;
298         }
299
300
301         /* Get a direction (unless KNOWN not to need it) */
302         if (((o_ptr->sval >= SV_ROD_MIN_DIRECTION) && (o_ptr->sval != SV_ROD_HAVOC) && (o_ptr->sval != SV_ROD_AGGRAVATE) && (o_ptr->sval != SV_ROD_PESTICIDE)) ||
303                 !object_is_aware(o_ptr))
304         {
305                 /* Get a direction, allow cancel */
306                 if (!get_aim_dir(&dir)) return;
307         }
308
309
310         take_turn(p_ptr, 100);
311
312         /* Extract the item level */
313         lev = k_info[o_ptr->k_idx].level;
314
315         /* Base chance of success */
316         chance = p_ptr->skill_dev;
317
318         /* Confusion hurts skill */
319         if (p_ptr->confused) chance = chance / 2;
320
321         fail = lev + 5;
322         if (chance > fail) fail -= (chance - fail) * 2;
323         else chance -= (fail - chance) * 2;
324         if (fail < USE_DEVICE) fail = USE_DEVICE;
325         if (chance < USE_DEVICE) chance = USE_DEVICE;
326
327         if (cmd_limit_time_walk(p_ptr)) return;
328
329         if (p_ptr->pclass == CLASS_BERSERKER) success = FALSE;
330         else if (chance > fail)
331         {
332                 if (randint0(chance * 2) < fail) success = FALSE;
333                 else success = TRUE;
334         }
335         else
336         {
337                 if (randint0(fail * 2) < chance) success = TRUE;
338                 else success = FALSE;
339         }
340
341         /* Roll for usage */
342         if (!success)
343         {
344                 if (flush_failure) flush();
345                 msg_print(_("うまくロッドを使えなかった。", "You failed to use the rod properly."));
346                 sound(SOUND_FAIL);
347                 return;
348         }
349
350         k_ptr = &k_info[o_ptr->k_idx];
351
352         /* A single rod is still charging */
353         if ((o_ptr->number == 1) && (o_ptr->timeout))
354         {
355                 if (flush_failure) flush();
356                 msg_print(_("このロッドはまだ魔力を充填している最中だ。", "The rod is still charging."));
357                 return;
358         }
359         /* A stack of rods lacks enough energy. */
360         else if ((o_ptr->number > 1) && (o_ptr->timeout > k_ptr->pval * (o_ptr->number - 1)))
361         {
362                 if (flush_failure) flush();
363                 msg_print(_("そのロッドはまだ充填中です。", "The rods are all still charging."));
364                 return;
365         }
366
367         sound(SOUND_ZAP);
368
369         ident = rod_effect(o_ptr->sval, dir, &use_charge, FALSE, FALSE);
370
371         /* Increase the timeout by the rod kind's pval. -LM- */
372         if (use_charge) o_ptr->timeout += k_ptr->pval;
373         p_ptr->update |= (PU_COMBINE | PU_REORDER);
374
375         if (!(object_is_aware(o_ptr)))
376         {
377                 chg_virtue(V_PATIENCE, -1);
378                 chg_virtue(V_CHANCE, 1);
379                 chg_virtue(V_KNOWLEDGE, -1);
380         }
381
382         /* Tried the object */
383         object_tried(o_ptr);
384
385         /* Successfully determined the object function */
386         if (ident && !object_is_aware(o_ptr))
387         {
388                 object_aware(o_ptr);
389                 gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);
390         }
391
392         p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
393 }
394
395 /*!
396 * @brief ロッドを使うコマンドのメインルーチン /
397 * @return なし
398 */
399 void do_cmd_zap_rod(void)
400 {
401         OBJECT_IDX item;
402         concptr q, s;
403
404         if (p_ptr->wild_mode)
405         {
406                 return;
407         }
408
409         if (cmd_limit_arena(p_ptr)) return;
410
411         if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN))
412         {
413                 set_action(ACTION_NONE);
414         }
415
416         /* Restrict choices to rods */
417         item_tester_tval = TV_ROD;
418
419         q = _("どのロッドを振りますか? ", "Zap which rod? ");
420         s = _("使えるロッドがない。", "You have no rod to zap.");
421
422         if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
423
424         /* Zap the rod */
425         do_cmd_zap_rod_aux(item);
426 }