OSDN Git Service

[Refactor] #37353 effects.c を player-effects.c に改名しつつ、宣言を player-effects.h を分離。
[hengband/hengband.git] / src / cmd-zapwand.c
1 #include "angband.h"
2 #include "avatar.h"
3 #include "spells.h"
4 #include "spells-status.h"
5 #include "player-status.h"
6 #include "player-effects.h"
7 #include "object-hook.h"
8 #include "cmd-basic.h"
9
10
11 /*!
12 * @brief 魔法棒の効果を発動する
13 * @param sval オブジェクトのsval
14 * @param dir 発動の方向ID
15 * @param powerful 強力発動上の処理ならばTRUE
16 * @param magic 魔道具術上の処理ならばTRUE
17 * @return 発動により効果内容が確定したならばTRUEを返す
18 */
19 bool wand_effect(OBJECT_SUBTYPE_VALUE sval, DIRECTION dir, bool powerful, bool magic)
20 {
21         bool ident = FALSE;
22         PLAYER_LEVEL lev = powerful ? p_ptr->lev * 2 : p_ptr->lev;
23         POSITION rad = powerful ? 3 : 2;
24
25         /* XXX Hack -- Wand of wonder can do anything before it */
26         if (sval == SV_WAND_WONDER)
27         {
28                 int vir = virtue_number(V_CHANCE);
29                 sval = (OBJECT_SUBTYPE_VALUE)randint0(SV_WAND_WONDER);
30
31                 if (vir)
32                 {
33                         if (p_ptr->virtues[vir - 1] > 0)
34                         {
35                                 while (randint1(300) < p_ptr->virtues[vir - 1]) sval++;
36                                 if (sval > SV_WAND_COLD_BALL) sval = randint0(4) + SV_WAND_ACID_BALL;
37                         }
38                         else
39                         {
40                                 while (randint1(300) < (0 - p_ptr->virtues[vir - 1])) sval--;
41                                 if (sval < SV_WAND_HEAL_MONSTER) sval = randint0(3) + SV_WAND_HEAL_MONSTER;
42                         }
43                 }
44                 if (sval < SV_WAND_TELEPORT_AWAY)
45                         chg_virtue(V_CHANCE, 1);
46         }
47
48         /* Analyze the wand */
49         switch (sval)
50         {
51                 case SV_WAND_HEAL_MONSTER:
52                 {
53                         HIT_POINT dam = damroll((powerful ? 20 : 10), 10);
54                         if (heal_monster(dir, dam)) ident = TRUE;
55                         break;
56                 }
57
58                 case SV_WAND_HASTE_MONSTER:
59                 {
60                         if (speed_monster(dir, lev)) ident = TRUE;
61                         break;
62                 }
63
64                 case SV_WAND_CLONE_MONSTER:
65                 {
66                         if (clone_monster(dir)) ident = TRUE;
67                         break;
68                 }
69
70                 case SV_WAND_TELEPORT_AWAY:
71                 {
72                         int distance = MAX_SIGHT * (powerful ? 8 : 5);
73                         if (teleport_monster(dir, distance)) ident = TRUE;
74                         break;
75                 }
76
77                 case SV_WAND_DISARMING:
78                 {
79                         if (disarm_trap(dir)) ident = TRUE;
80                         if (powerful && disarm_traps_touch()) ident = TRUE;
81                         break;
82                 }
83
84                 case SV_WAND_TRAP_DOOR_DEST:
85                 {
86                         if (destroy_door(dir)) ident = TRUE;
87                         if (powerful && destroy_doors_touch()) ident = TRUE;
88                         break;
89                 }
90
91                 case SV_WAND_STONE_TO_MUD:
92                 {
93                         HIT_POINT dam = powerful ? 40 + randint1(60) : 20 + randint1(30);
94                         if (wall_to_mud(dir, dam)) ident = TRUE;
95                         break;
96                 }
97
98                 case SV_WAND_LITE:
99                 {
100                         HIT_POINT dam = damroll((powerful ? 12 : 6), 8);
101                         msg_print(_("青く輝く光線が放たれた。", "A line of blue shimmering light appears."));
102                         (void)lite_line(dir, dam);
103                         ident = TRUE;
104                         break;
105                 }
106
107                 case SV_WAND_SLEEP_MONSTER:
108                 {
109                         if (sleep_monster(dir, lev)) ident = TRUE;
110                         break;
111                 }
112
113                 case SV_WAND_SLOW_MONSTER:
114                 {
115                         if (slow_monster(dir, lev)) ident = TRUE;
116                         break;
117                 }
118
119                 case SV_WAND_CONFUSE_MONSTER:
120                 {
121                         if (confuse_monster(dir, lev)) ident = TRUE;
122                         break;
123                 }
124
125                 case SV_WAND_FEAR_MONSTER:
126                 {
127                         if (fear_monster(dir, lev)) ident = TRUE;
128                         break;
129                 }
130
131                 case SV_WAND_HYPODYNAMIA:
132                 {
133                         if (hypodynamic_bolt(dir, 80 + lev)) ident = TRUE;
134                         break;
135                 }
136
137                 case SV_WAND_POLYMORPH:
138                 {
139                         if (poly_monster(dir, lev)) ident = TRUE;
140                         break;
141                 }
142
143                 case SV_WAND_STINKING_CLOUD:
144                 {
145                         fire_ball(GF_POIS, dir, 12 + lev / 4, rad);
146                         ident = TRUE;
147                         break;
148                 }
149
150                 case SV_WAND_MAGIC_MISSILE:
151                 {
152                         fire_bolt_or_beam(20, GF_MISSILE, dir, damroll(2 + lev / 10, 6));
153                         ident = TRUE;
154                         break;
155                 }
156
157                 case SV_WAND_ACID_BOLT:
158                 {
159                         fire_bolt_or_beam(20, GF_ACID, dir, damroll(6 + lev / 7, 8));
160                         ident = TRUE;
161                         break;
162                 }
163
164                 case SV_WAND_CHARM_MONSTER:
165                 {
166                         if (charm_monster(dir, MAX(20, lev)))
167                                 ident = TRUE;
168                         break;
169                 }
170
171                 case SV_WAND_FIRE_BOLT:
172                 {
173                         fire_bolt_or_beam(20, GF_FIRE, dir, damroll(7 + lev / 6, 8));
174                         ident = TRUE;
175                         break;
176                 }
177
178                 case SV_WAND_COLD_BOLT:
179                 {
180                         fire_bolt_or_beam(20, GF_COLD, dir, damroll(5 + lev / 8, 8));
181                         ident = TRUE;
182                         break;
183                 }
184
185                 case SV_WAND_ACID_BALL:
186                 {
187                         fire_ball(GF_ACID, dir, 60 + 3 * lev / 4, rad);
188                         ident = TRUE;
189                         break;
190                 }
191
192                 case SV_WAND_ELEC_BALL:
193                 {
194                         fire_ball(GF_ELEC, dir, 40 + 3 * lev / 4, rad);
195                         ident = TRUE;
196                         break;
197                 }
198
199                 case SV_WAND_FIRE_BALL:
200                 {
201                         fire_ball(GF_FIRE, dir, 70 + 3 * lev / 4, rad);
202                         ident = TRUE;
203                         break;
204                 }
205
206                 case SV_WAND_COLD_BALL:
207                 {
208                         fire_ball(GF_COLD, dir, 50 + 3 * lev / 4, rad);
209                         ident = TRUE;
210                         break;
211                 }
212
213                 case SV_WAND_WONDER:
214                 {
215                         msg_print(_("おっと、謎の魔法棒を始動させた。", "Oops.  Wand of wonder activated."));
216                         break;
217                 }
218
219                 case SV_WAND_DRAGON_FIRE:
220                 {
221                         fire_breath(GF_FIRE, dir, (powerful ? 300 : 200), 3);
222                         ident = TRUE;
223                         break;
224                 }
225
226                 case SV_WAND_DRAGON_COLD:
227                 {
228                         fire_breath(GF_COLD, dir, (powerful ? 270 : 180), 3);
229                         ident = TRUE;
230                         break;
231                 }
232
233                 case SV_WAND_DRAGON_BREATH:
234                 {
235                         HIT_POINT dam;
236                         EFFECT_ID typ;
237
238                         switch (randint1(5))
239                         {
240                         case 1:
241                                 dam = 240;
242                                 typ = GF_ACID;
243                                 break;
244                         case 2:
245                                 dam = 210;
246                                 typ = GF_ELEC;
247                                 break;
248                         case 3:
249                                 dam = 240;
250                                 typ = GF_FIRE;
251                                 break;
252                         case 4:
253                                 dam = 210;
254                                 typ = GF_COLD;
255                                 break;
256                         default:
257                                 dam = 180;
258                                 typ = GF_POIS;
259                                 break;
260                         }
261
262                         if (powerful) dam = (dam * 3) / 2;
263
264                         fire_breath(typ, dir, dam, 3);
265
266                         ident = TRUE;
267                         break;
268                 }
269
270                 case SV_WAND_DISINTEGRATE:
271                 {
272                         fire_ball(GF_DISINTEGRATE, dir, 200 + randint1(lev * 2), rad);
273                         ident = TRUE;
274                         break;
275                 }
276
277                 case SV_WAND_ROCKETS:
278                 {
279                         msg_print(_("ロケットを発射した!", "You launch a rocket!"));
280                         fire_rocket(GF_ROCKET, dir, 250 + lev * 3, rad);
281                         ident = TRUE;
282                         break;
283                 }
284
285                 case SV_WAND_STRIKING:
286                 {
287                         fire_bolt(GF_METEOR, dir, damroll(15 + lev / 3, 13));
288                         ident = TRUE;
289                         break;
290                 }
291
292                 case SV_WAND_GENOCIDE:
293                 {
294                         fire_ball_hide(GF_GENOCIDE, dir, magic ? lev + 50 : 250, 0);
295                         ident = TRUE;
296                         break;
297                 }
298         }
299         return ident;
300 }
301
302 /*!
303 * @brief 魔法棒を使うコマンドのサブルーチン /
304 * Aim a wand (from the pack or floor).
305 * @param item 使うオブジェクトの所持品ID
306 * @return なし
307 * @details
308 * <pre>
309 * Use a single charge from a single item.
310 * Handle "unstacking" in a logical manner.
311 * For simplicity, you cannot use a stack of items from the
312 * ground.  This would require too much nasty code.
313 * There are no wands which can "destroy" themselves, in the inventory
314 * or on the ground, so we can ignore this possibility.  Note that this
315 * required giving "wand of wonder" the ability to ignore destruction
316 * by electric balls.
317 * All wands can be "cancelled" at the "Direction?" prompt for free.
318 * Note that the basic "bolt" wands do slightly less damage than the
319 * basic "bolt" rods, but the basic "ball" wands do the same damage
320 * as the basic "ball" rods.
321 * </pre>
322 */
323 void do_cmd_aim_wand_aux(INVENTORY_IDX item)
324 {
325         DEPTH lev;
326         int ident, chance;
327         DIRECTION dir;
328         object_type *o_ptr;
329         bool old_target_pet = target_pet;
330
331         /* Get the item (in the pack) */
332         if (item >= 0)
333         {
334                 o_ptr = &inventory[item];
335         }
336
337         /* Get the item (on the floor) */
338         else
339         {
340                 o_ptr = &current_floor_ptr->o_list[0 - item];
341         }
342
343         /* Mega-Hack -- refuse to aim a pile from the ground */
344         if ((item < 0) && (o_ptr->number > 1))
345         {
346                 msg_print(_("まずは魔法棒を拾わなければ。", "You must first pick up the wands."));
347                 return;
348         }
349
350
351         /* Allow direction to be cancelled for free */
352         if (object_is_aware(o_ptr) && (o_ptr->sval == SV_WAND_HEAL_MONSTER
353                 || o_ptr->sval == SV_WAND_HASTE_MONSTER))
354                 target_pet = TRUE;
355         if (!get_aim_dir(&dir))
356         {
357                 target_pet = old_target_pet;
358                 return;
359         }
360         target_pet = old_target_pet;
361
362         take_turn(p_ptr, 100);
363
364         /* Get the level */
365         lev = k_info[o_ptr->k_idx].level;
366         if (lev > 50) lev = 50 + (lev - 50) / 2;
367
368         /* Base chance of success */
369         chance = p_ptr->skill_dev;
370
371         /* Confusion hurts skill */
372         if (p_ptr->confused) chance = chance / 2;
373
374         /* Hight level objects are harder */
375         chance = chance - lev;
376
377         /* Give everyone a (slight) chance */
378         if ((chance < USE_DEVICE) && one_in_(USE_DEVICE - chance + 1))
379         {
380                 chance = USE_DEVICE;
381         }
382
383         if (cmd_limit_time_walk(p_ptr)) return;
384
385         /* Roll for usage */
386         if ((chance < USE_DEVICE) || (randint1(chance) < USE_DEVICE) || (p_ptr->pclass == CLASS_BERSERKER))
387         {
388                 if (flush_failure) flush();
389                 msg_print(_("魔法棒をうまく使えなかった。", "You failed to use the wand properly."));
390                 sound(SOUND_FAIL);
391                 return;
392         }
393
394         /* The wand is already empty! */
395         if (o_ptr->pval <= 0)
396         {
397                 if (flush_failure) flush();
398                 msg_print(_("この魔法棒にはもう魔力が残っていない。", "The wand has no charges left."));
399                 o_ptr->ident |= (IDENT_EMPTY);
400                 p_ptr->update |= (PU_COMBINE | PU_REORDER);
401                 p_ptr->window |= (PW_INVEN);
402
403                 return;
404         }
405
406         sound(SOUND_ZAP);
407
408         ident = wand_effect(o_ptr->sval, dir, FALSE, FALSE);
409         p_ptr->update |= (PU_COMBINE | PU_REORDER);
410
411         if (!(object_is_aware(o_ptr)))
412         {
413                 chg_virtue(V_PATIENCE, -1);
414                 chg_virtue(V_CHANCE, 1);
415                 chg_virtue(V_KNOWLEDGE, -1);
416         }
417
418         /* Mark it as tried */
419         object_tried(o_ptr);
420
421         /* Apply identification */
422         if (ident && !object_is_aware(o_ptr))
423         {
424                 object_aware(o_ptr);
425                 gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);
426         }
427
428         p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
429
430
431         /* Use a single charge */
432         o_ptr->pval--;
433
434         /* Describe the charges in the pack */
435         if (item >= 0)
436         {
437                 inven_item_charges(item);
438         }
439
440         /* Describe the charges on the floor */
441         else
442         {
443                 floor_item_charges(0 - item);
444         }
445 }
446
447 /*!
448 * @brief 魔法棒を使うコマンドのメインルーチン /
449 * @return なし
450 */
451 void do_cmd_aim_wand(void)
452 {
453         OBJECT_IDX item;
454         concptr q, s;
455
456         if (p_ptr->wild_mode) return;
457         if (cmd_limit_arena(p_ptr)) return;
458
459         /* Restrict choices to wands */
460         item_tester_tval = TV_WAND;
461
462         if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN))
463         {
464                 set_action(ACTION_NONE);
465         }
466
467         q = _("どの魔法棒で狙いますか? ", "Aim which wand? ");
468         s = _("使える魔法棒がない。", "You have no wand to aim.");
469         if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return;
470
471         do_cmd_aim_wand_aux(item);
472 }