OSDN Git Service

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