OSDN Git Service

[Refactor] #37353 聖浄の杖の効果を cleasing_nova() に分離。 / Separate implementation of 'staff...
[hengband/hengband.git] / src / cmd-usestaff.c
1 #include "angband.h"\r
2 #include "projection.h"\r
3 #include "spells-summon.h"\r
4 \r
5 \r
6 \r
7 /*!\r
8 * @brief 杖の効果を発動する\r
9 * @param sval オブジェクトのsval\r
10 * @param use_charge 使用回数を消費したかどうかを返す参照ポインタ\r
11 * @param powerful 強力発動上の処理ならばTRUE\r
12 * @param magic 魔道具術上の処理ならばTRUE\r
13 * @param known 判明済ならばTRUE\r
14 * @return 発動により効果内容が確定したならばTRUEを返す\r
15 */\r
16 int staff_effect(OBJECT_SUBTYPE_VALUE sval, bool *use_charge, bool powerful, bool magic, bool known)\r
17 {\r
18         int k;\r
19         int ident = FALSE;\r
20         PLAYER_LEVEL lev = powerful ? p_ptr->lev * 2 : p_ptr->lev;\r
21         POSITION detect_rad = powerful ? DETECT_RAD_DEFAULT * 3 / 2 : DETECT_RAD_DEFAULT;\r
22 \r
23         /* Analyze the staff */\r
24         switch (sval)\r
25         {\r
26         case SV_STAFF_DARKNESS:\r
27         {\r
28                 if (!(p_ptr->resist_blind) && !(p_ptr->resist_dark))\r
29                 {\r
30                         if (set_blind(p_ptr->blind + 3 + randint1(5))) ident = TRUE;\r
31                 }\r
32                 if (unlite_area(10, (powerful ? 6 : 3))) ident = TRUE;\r
33                 break;\r
34         }\r
35 \r
36         case SV_STAFF_SLOWNESS:\r
37         {\r
38                 if (set_slow(p_ptr->slow + randint1(30) + 15, FALSE)) ident = TRUE;\r
39                 break;\r
40         }\r
41 \r
42         case SV_STAFF_HASTE_MONSTERS:\r
43         {\r
44                 if (speed_monsters()) ident = TRUE;\r
45                 break;\r
46         }\r
47 \r
48         case SV_STAFF_SUMMONING:\r
49         {\r
50                 const int times = randint1(powerful ? 8 : 4);\r
51                 for (k = 0; k < times; k++)\r
52                 {\r
53                         if (summon_specific(0, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0'))\r
54                         {\r
55                                 ident = TRUE;\r
56                         }\r
57                 }\r
58                 break;\r
59         }\r
60 \r
61         case SV_STAFF_TELEPORTATION:\r
62         {\r
63                 teleport_player((powerful ? 150 : 100), 0L);\r
64                 ident = TRUE;\r
65                 break;\r
66         }\r
67 \r
68         case SV_STAFF_IDENTIFY:\r
69         {\r
70                 if (powerful) {\r
71                         if (!identify_fully(FALSE)) *use_charge = FALSE;\r
72                 }\r
73                 else {\r
74                         if (!ident_spell(FALSE)) *use_charge = FALSE;\r
75                 }\r
76                 ident = TRUE;\r
77                 break;\r
78         }\r
79 \r
80         case SV_STAFF_REMOVE_CURSE:\r
81         {\r
82                 bool result = powerful ? remove_all_curse() : remove_curse();\r
83                 if (result)\r
84                 {\r
85                         ident = TRUE;\r
86                 }\r
87                 break;\r
88         }\r
89 \r
90         case SV_STAFF_STARLITE:\r
91         {\r
92                 HIT_POINT num = damroll(5, 3);\r
93                 POSITION y = 0, x = 0;\r
94                 int attempts;\r
95 \r
96                 if (!p_ptr->blind && !magic)\r
97                 {\r
98                         msg_print(_("杖の先が明るく輝いた...", "The end of the staff glows brightly..."));\r
99                 }\r
100                 for (k = 0; k < num; k++)\r
101                 {\r
102                         attempts = 1000;\r
103 \r
104                         while (attempts--)\r
105                         {\r
106                                 scatter(&y, &x, p_ptr->y, p_ptr->x, 4, PROJECT_LOS);\r
107                                 if (!cave_have_flag_bold(y, x, FF_PROJECT)) continue;\r
108                                 if (!player_bold(y, x)) break;\r
109                         }\r
110 \r
111                         project(0, 0, y, x, damroll(6 + lev / 8, 10), GF_LITE_WEAK,\r
112                                 (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_KILL | PROJECT_LOS), -1);\r
113                 }\r
114                 ident = TRUE;\r
115                 break;\r
116         }\r
117 \r
118         case SV_STAFF_LITE:\r
119         {\r
120                 if (lite_area(damroll(2, 8), (powerful ? 4 : 2))) ident = TRUE;\r
121                 break;\r
122         }\r
123 \r
124         case SV_STAFF_MAPPING:\r
125         {\r
126                 map_area(powerful ? DETECT_RAD_MAP * 3 / 2 : DETECT_RAD_MAP);\r
127                 ident = TRUE;\r
128                 break;\r
129         }\r
130 \r
131         case SV_STAFF_DETECT_GOLD:\r
132         {\r
133                 if (detect_treasure(detect_rad)) ident = TRUE;\r
134                 if (detect_objects_gold(detect_rad)) ident = TRUE;\r
135                 break;\r
136         }\r
137 \r
138         case SV_STAFF_DETECT_ITEM:\r
139         {\r
140                 if (detect_objects_normal(detect_rad)) ident = TRUE;\r
141                 break;\r
142         }\r
143 \r
144         case SV_STAFF_DETECT_TRAP:\r
145         {\r
146                 if (detect_traps(detect_rad, known)) ident = TRUE;\r
147                 break;\r
148         }\r
149 \r
150         case SV_STAFF_DETECT_DOOR:\r
151         {\r
152                 if (detect_doors(detect_rad)) ident = TRUE;\r
153                 if (detect_stairs(detect_rad)) ident = TRUE;\r
154                 break;\r
155         }\r
156 \r
157         case SV_STAFF_DETECT_INVIS:\r
158         {\r
159                 if (detect_monsters_invis(detect_rad)) ident = TRUE;\r
160                 break;\r
161         }\r
162 \r
163         case SV_STAFF_DETECT_EVIL:\r
164         {\r
165                 if (detect_monsters_evil(detect_rad)) ident = TRUE;\r
166                 break;\r
167         }\r
168 \r
169         case SV_STAFF_CURE_LIGHT:\r
170         {\r
171                 ident = cure_light_wounds((powerful ? 4 : 2), 8);\r
172                 break;\r
173         }\r
174 \r
175         case SV_STAFF_CURING:\r
176         {\r
177                 ident = true_healing(0);\r
178                 if (set_shero(0, TRUE)) ident = TRUE;\r
179                 break;\r
180         }\r
181 \r
182         case SV_STAFF_HEALING:\r
183         {\r
184                 if (cure_critical_wounds(powerful ? 500 : 300)) ident = TRUE;\r
185                 break;\r
186         }\r
187 \r
188         case SV_STAFF_THE_MAGI:\r
189         {\r
190                 if (do_res_stat(A_INT)) ident = TRUE;\r
191                 ident |= restore_mana(FALSE);\r
192                 if (set_shero(0, TRUE)) ident = TRUE;\r
193                 break;\r
194         }\r
195 \r
196         case SV_STAFF_SLEEP_MONSTERS:\r
197         {\r
198                 if (sleep_monsters(lev)) ident = TRUE;\r
199                 break;\r
200         }\r
201 \r
202         case SV_STAFF_SLOW_MONSTERS:\r
203         {\r
204                 if (slow_monsters(lev)) ident = TRUE;\r
205                 break;\r
206         }\r
207 \r
208         case SV_STAFF_SPEED:\r
209         {\r
210                 if (set_fast(randint1(30) + (powerful ? 30 : 15), FALSE)) ident = TRUE;\r
211                 break;\r
212         }\r
213 \r
214         case SV_STAFF_PROBING:\r
215         {\r
216                 probing();\r
217                 ident = TRUE;\r
218                 break;\r
219         }\r
220 \r
221         case SV_STAFF_DISPEL_EVIL:\r
222         {\r
223                 if (dispel_evil(powerful ? 120 : 80)) ident = TRUE;\r
224                 break;\r
225         }\r
226 \r
227         case SV_STAFF_POWER:\r
228         {\r
229                 if (dispel_monsters(powerful ? 225 : 150)) ident = TRUE;\r
230                 break;\r
231         }\r
232 \r
233         case SV_STAFF_HOLINESS:\r
234         {\r
235                 if (cleansing_nova(p_ptr, magic, powerful)) ident = TRUE;\r
236                 break;\r
237         }\r
238 \r
239         case SV_STAFF_GENOCIDE:\r
240         {\r
241                 (void)symbol_genocide((magic ? lev + 50 : 200), TRUE);\r
242                 ident = TRUE;\r
243                 break;\r
244         }\r
245 \r
246         case SV_STAFF_EARTHQUAKES:\r
247         {\r
248                 if (earthquake(p_ptr->y, p_ptr->x, (powerful ? 15 : 10)))\r
249                         ident = TRUE;\r
250                 else\r
251                         msg_print(_("ダンジョンが揺れた。", "The dungeon trembles."));\r
252 \r
253                 break;\r
254         }\r
255 \r
256         case SV_STAFF_DESTRUCTION:\r
257         {\r
258                 if (destroy_area(p_ptr->y, p_ptr->x, (powerful ? 18 : 13) + randint0(5), FALSE))\r
259                         ident = TRUE;\r
260 \r
261                 break;\r
262         }\r
263 \r
264         case SV_STAFF_ANIMATE_DEAD:\r
265         {\r
266                 if (animate_dead(0, p_ptr->y, p_ptr->x))\r
267                         ident = TRUE;\r
268 \r
269                 break;\r
270         }\r
271 \r
272         case SV_STAFF_MSTORM:\r
273         {\r
274                 msg_print(_("強力な魔力が敵を引き裂いた!", "Mighty magics rend your enemies!"));\r
275                 project(0, (powerful ? 7 : 5), p_ptr->y, p_ptr->x,\r
276                         (randint1(200) + (powerful ? 500 : 300)) * 2, GF_MANA, PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID, -1);\r
277                 if ((p_ptr->pclass != CLASS_MAGE) && (p_ptr->pclass != CLASS_HIGH_MAGE) && (p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_MAGIC_EATER) && (p_ptr->pclass != CLASS_BLUE_MAGE))\r
278                 {\r
279                         (void)take_hit(DAMAGE_NOESCAPE, 50, _("コントロールし難い強力な魔力の解放", "unleashing magics too mighty to control"), -1);\r
280                 }\r
281                 ident = TRUE;\r
282 \r
283                 break;\r
284         }\r
285 \r
286         case SV_STAFF_NOTHING:\r
287         {\r
288                 msg_print(_("何も起らなかった。", "Nothing happen."));\r
289                 if (prace_is_(RACE_SKELETON) || prace_is_(RACE_GOLEM) ||\r
290                         prace_is_(RACE_ZOMBIE) || prace_is_(RACE_SPECTRE))\r
291                         msg_print(_("もったいない事をしたような気がする。食べ物は大切にしなくては。", "What a waste.  It's your food!"));\r
292                 break;\r
293         }\r
294         }\r
295         return ident;\r
296 }\r
297 \r
298 /*!\r
299  * @brief 杖を使うコマンドのサブルーチン /\r
300  * Use a staff.                 -RAK-\r
301  * @param item 使うオブジェクトの所持品ID\r
302  * @return なし\r
303  * @details\r
304  * One charge of one staff disappears.\r
305  * Hack -- staffs of identify can be "cancelled".\r
306  */\r
307 void do_cmd_use_staff_aux(INVENTORY_IDX item)\r
308 {\r
309         int         ident, chance, lev;\r
310         object_type *o_ptr;\r
311 \r
312 \r
313         /* Hack -- let staffs of identify get aborted */\r
314         bool use_charge = TRUE;\r
315 \r
316 \r
317         /* Get the item (in the pack) */\r
318         if (item >= 0)\r
319         {\r
320                 o_ptr = &inventory[item];\r
321         }\r
322 \r
323         /* Get the item (on the floor) */\r
324         else\r
325         {\r
326                 o_ptr = &o_list[0 - item];\r
327         }\r
328 \r
329 \r
330         /* Mega-Hack -- refuse to use a pile from the ground */\r
331         if ((item < 0) && (o_ptr->number > 1))\r
332         {\r
333                 msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));\r
334                 return;\r
335         }\r
336 \r
337 \r
338         p_ptr->energy_use = 100;\r
339 \r
340         /* Extract the item level */\r
341         lev = k_info[o_ptr->k_idx].level;\r
342         if (lev > 50) lev = 50 + (lev - 50) / 2;\r
343 \r
344         /* Base chance of success */\r
345         chance = p_ptr->skill_dev;\r
346 \r
347         /* Confusion hurts skill */\r
348         if (p_ptr->confused) chance = chance / 2;\r
349 \r
350         /* Hight level objects are harder */\r
351         chance = chance - lev;\r
352 \r
353         /* Give everyone a (slight) chance */\r
354         if ((chance < USE_DEVICE) && one_in_(USE_DEVICE - chance + 1))\r
355         {\r
356                 chance = USE_DEVICE;\r
357         }\r
358 \r
359         if (world_player)\r
360         {\r
361                 if (flush_failure) flush();\r
362                 msg_print(_("止まった時の中ではうまく働かないようだ。", "Nothing happen. Maybe this staff is freezing too."));\r
363                 sound(SOUND_FAIL);\r
364                 return;\r
365         }\r
366 \r
367         /* Roll for usage */\r
368         if ((chance < USE_DEVICE) || (randint1(chance) < USE_DEVICE) || (p_ptr->pclass == CLASS_BERSERKER))\r
369         {\r
370                 if (flush_failure) flush();\r
371                 msg_print(_("杖をうまく使えなかった。", "You failed to use the staff properly."));\r
372                 sound(SOUND_FAIL);\r
373                 return;\r
374         }\r
375 \r
376         /* Notice empty staffs */\r
377         if (o_ptr->pval <= 0)\r
378         {\r
379                 if (flush_failure) flush();\r
380                 msg_print(_("この杖にはもう魔力が残っていない。", "The staff has no charges left."));\r
381                 o_ptr->ident |= (IDENT_EMPTY);\r
382 \r
383                 /* Combine / Reorder the pack (later) */\r
384                 p_ptr->update |= (PU_COMBINE | PU_REORDER);\r
385                 p_ptr->window |= (PW_INVEN);\r
386 \r
387                 return;\r
388         }\r
389 \r
390 \r
391         sound(SOUND_ZAP);\r
392 \r
393         ident = staff_effect(o_ptr->sval, &use_charge, FALSE, FALSE, object_is_aware(o_ptr));\r
394 \r
395         if (!(object_is_aware(o_ptr)))\r
396         {\r
397                 chg_virtue(V_PATIENCE, -1);\r
398                 chg_virtue(V_CHANCE, 1);\r
399                 chg_virtue(V_KNOWLEDGE, -1);\r
400         }\r
401 \r
402         /* Combine / Reorder the pack (later) */\r
403         p_ptr->update |= (PU_COMBINE | PU_REORDER);\r
404 \r
405         /* Tried the item */\r
406         object_tried(o_ptr);\r
407 \r
408         /* An identification was made */\r
409         if (ident && !object_is_aware(o_ptr))\r
410         {\r
411                 object_aware(o_ptr);\r
412                 gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);\r
413         }\r
414 \r
415         p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);\r
416 \r
417 \r
418         /* Hack -- some uses are "free" */\r
419         if (!use_charge) return;\r
420 \r
421 \r
422         /* Use a single charge */\r
423         o_ptr->pval--;\r
424 \r
425         /* XXX Hack -- unstack if necessary */\r
426         if ((item >= 0) && (o_ptr->number > 1))\r
427         {\r
428                 object_type forge;\r
429                 object_type *q_ptr;\r
430                 q_ptr = &forge;\r
431 \r
432                 /* Obtain a local object */\r
433                 object_copy(q_ptr, o_ptr);\r
434 \r
435                 /* Modify quantity */\r
436                 q_ptr->number = 1;\r
437 \r
438                 /* Restore the charges */\r
439                 o_ptr->pval++;\r
440 \r
441                 /* Unstack the used item */\r
442                 o_ptr->number--;\r
443                 p_ptr->total_weight -= q_ptr->weight;\r
444                 item = inven_carry(q_ptr);\r
445 \r
446                 msg_print(_("杖をまとめなおした。", "You unstack your staff."));\r
447         }\r
448 \r
449         /* Describe charges in the pack */\r
450         if (item >= 0)\r
451         {\r
452                 inven_item_charges(item);\r
453         }\r
454 \r
455         /* Describe charges on the floor */\r
456         else\r
457         {\r
458                 floor_item_charges(0 - item);\r
459         }\r
460 }\r
461 \r
462 /*!\r
463 * @brief 杖を使うコマンドのメインルーチン /\r
464 * @return なし\r
465 */\r
466 void do_cmd_use_staff(void)\r
467 {\r
468         OBJECT_IDX item;\r
469         concptr q, s;\r
470 \r
471         if (p_ptr->wild_mode)\r
472         {\r
473                 return;\r
474         }\r
475 \r
476         if (p_ptr->inside_arena)\r
477         {\r
478                 msg_print(_("アリーナが魔法を吸収した!", "The arena absorbs all attempted magic!"));\r
479                 msg_print(NULL);\r
480                 return;\r
481         }\r
482 \r
483         if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN))\r
484         {\r
485                 set_action(ACTION_NONE);\r
486         }\r
487 \r
488         /* Restrict choices to wands */\r
489         item_tester_tval = TV_STAFF;\r
490 \r
491         q = _("どの杖を使いますか? ", "Use which staff? ");\r
492         s = _("使える杖がない。", "You have no staff to use.");\r
493 \r
494         if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return;\r
495 \r
496         do_cmd_use_staff_aux(item);\r
497 }\r