OSDN Git Service

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