OSDN Git Service

[Refactor] #37353 スターライトの杖の効果を starlight() に分離。 / 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                         ident = starlight(magic);\r
92                         break;\r
93 \r
94                 case SV_STAFF_LITE:\r
95                 {\r
96                         if (lite_area(damroll(2, 8), (powerful ? 4 : 2))) ident = TRUE;\r
97                         break;\r
98                 }\r
99 \r
100                 case SV_STAFF_MAPPING:\r
101                 {\r
102                         map_area(powerful ? DETECT_RAD_MAP * 3 / 2 : DETECT_RAD_MAP);\r
103                         ident = TRUE;\r
104                         break;\r
105                 }\r
106 \r
107                 case SV_STAFF_DETECT_GOLD:\r
108                 {\r
109                         if (detect_treasure(detect_rad)) ident = TRUE;\r
110                         if (detect_objects_gold(detect_rad)) ident = TRUE;\r
111                         break;\r
112                 }\r
113 \r
114                 case SV_STAFF_DETECT_ITEM:\r
115                 {\r
116                         if (detect_objects_normal(detect_rad)) ident = TRUE;\r
117                         break;\r
118                 }\r
119 \r
120                 case SV_STAFF_DETECT_TRAP:\r
121                 {\r
122                         if (detect_traps(detect_rad, known)) ident = TRUE;\r
123                         break;\r
124                 }\r
125 \r
126                 case SV_STAFF_DETECT_DOOR:\r
127                 {\r
128                         if (detect_doors(detect_rad)) ident = TRUE;\r
129                         if (detect_stairs(detect_rad)) ident = TRUE;\r
130                         break;\r
131                 }\r
132 \r
133                 case SV_STAFF_DETECT_INVIS:\r
134                 {\r
135                         if (detect_monsters_invis(detect_rad)) ident = TRUE;\r
136                         break;\r
137                 }\r
138 \r
139                 case SV_STAFF_DETECT_EVIL:\r
140                 {\r
141                         if (detect_monsters_evil(detect_rad)) ident = TRUE;\r
142                         break;\r
143                 }\r
144 \r
145                 case SV_STAFF_CURE_LIGHT:\r
146                 {\r
147                         ident = cure_light_wounds((powerful ? 4 : 2), 8);\r
148                         break;\r
149                 }\r
150 \r
151                 case SV_STAFF_CURING:\r
152                 {\r
153                         ident = true_healing(0);\r
154                         if (set_shero(0, TRUE)) ident = TRUE;\r
155                         break;\r
156                 }\r
157 \r
158                 case SV_STAFF_HEALING:\r
159                 {\r
160                         if (cure_critical_wounds(powerful ? 500 : 300)) ident = TRUE;\r
161                         break;\r
162                 }\r
163 \r
164                 case SV_STAFF_THE_MAGI:\r
165                 {\r
166                         if (do_res_stat(A_INT)) ident = TRUE;\r
167                         ident |= restore_mana(FALSE);\r
168                         if (set_shero(0, TRUE)) ident = TRUE;\r
169                         break;\r
170                 }\r
171 \r
172                 case SV_STAFF_SLEEP_MONSTERS:\r
173                 {\r
174                         if (sleep_monsters(lev)) ident = TRUE;\r
175                         break;\r
176                 }\r
177 \r
178                 case SV_STAFF_SLOW_MONSTERS:\r
179                 {\r
180                         if (slow_monsters(lev)) ident = TRUE;\r
181                         break;\r
182                 }\r
183 \r
184                 case SV_STAFF_SPEED:\r
185                 {\r
186                         if (set_fast(randint1(30) + (powerful ? 30 : 15), FALSE)) ident = TRUE;\r
187                         break;\r
188                 }\r
189 \r
190                 case SV_STAFF_PROBING:\r
191                 {\r
192                         ident = probing();\r
193                         break;\r
194                 }\r
195 \r
196                 case SV_STAFF_DISPEL_EVIL:\r
197                 {\r
198                         ident = dispel_evil(powerful ? 120 : 80);\r
199                         break;\r
200                 }\r
201 \r
202                 case SV_STAFF_POWER:\r
203                 {\r
204                         ident = dispel_monsters(powerful ? 225 : 150) ;\r
205                         break;\r
206                 }\r
207 \r
208                 case SV_STAFF_HOLINESS:\r
209                 {\r
210                         ident = cleansing_nova(p_ptr, magic, powerful);\r
211                         break;\r
212                 }\r
213 \r
214                 case SV_STAFF_GENOCIDE:\r
215                 {\r
216                         ident = symbol_genocide((magic ? lev + 50 : 200), TRUE);\r
217                         break;\r
218                 }\r
219 \r
220                 case SV_STAFF_EARTHQUAKES:\r
221                 {\r
222                         if (earthquake(p_ptr->y, p_ptr->x, (powerful ? 15 : 10)))\r
223                                 ident = TRUE;\r
224                         else\r
225                                 msg_print(_("ダンジョンが揺れた。", "The dungeon trembles."));\r
226 \r
227                         break;\r
228                 }\r
229 \r
230                 case SV_STAFF_DESTRUCTION:\r
231                 {\r
232                         ident = destroy_area(p_ptr->y, p_ptr->x, (powerful ? 18 : 13) + randint0(5), FALSE);\r
233                         break;\r
234                 }\r
235 \r
236                 case SV_STAFF_ANIMATE_DEAD:\r
237                 {\r
238                         ident = animate_dead(0, p_ptr->y, p_ptr->x);\r
239                         break;\r
240                 }\r
241 \r
242                 case SV_STAFF_MSTORM:\r
243                 {\r
244                         ident = unleash_mana_storm(p_ptr, powerful);\r
245                         break;\r
246                 }\r
247 \r
248                 case SV_STAFF_NOTHING:\r
249                 {\r
250                         msg_print(_("何も起らなかった。", "Nothing happen."));\r
251                         if (prace_is_(RACE_SKELETON) || prace_is_(RACE_GOLEM) ||\r
252                                 prace_is_(RACE_ZOMBIE) || prace_is_(RACE_SPECTRE))\r
253                                 msg_print(_("もったいない事をしたような気がする。食べ物は大切にしなくては。", "What a waste.  It's your food!"));\r
254                         break;\r
255                 }\r
256         }\r
257         return ident;\r
258 }\r
259 \r
260 /*!\r
261  * @brief 杖を使うコマンドのサブルーチン /\r
262  * Use a staff.                 -RAK-\r
263  * @param item 使うオブジェクトの所持品ID\r
264  * @return なし\r
265  * @details\r
266  * One charge of one staff disappears.\r
267  * Hack -- staffs of identify can be "cancelled".\r
268  */\r
269 void do_cmd_use_staff_aux(INVENTORY_IDX item)\r
270 {\r
271         int         ident, chance, lev;\r
272         object_type *o_ptr;\r
273 \r
274 \r
275         /* Hack -- let staffs of identify get aborted */\r
276         bool use_charge = TRUE;\r
277 \r
278 \r
279         /* Get the item (in the pack) */\r
280         if (item >= 0)\r
281         {\r
282                 o_ptr = &inventory[item];\r
283         }\r
284 \r
285         /* Get the item (on the floor) */\r
286         else\r
287         {\r
288                 o_ptr = &o_list[0 - item];\r
289         }\r
290 \r
291 \r
292         /* Mega-Hack -- refuse to use a pile from the ground */\r
293         if ((item < 0) && (o_ptr->number > 1))\r
294         {\r
295                 msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));\r
296                 return;\r
297         }\r
298 \r
299 \r
300         p_ptr->energy_use = 100;\r
301 \r
302         /* Extract the item level */\r
303         lev = k_info[o_ptr->k_idx].level;\r
304         if (lev > 50) lev = 50 + (lev - 50) / 2;\r
305 \r
306         /* Base chance of success */\r
307         chance = p_ptr->skill_dev;\r
308 \r
309         /* Confusion hurts skill */\r
310         if (p_ptr->confused) chance = chance / 2;\r
311 \r
312         /* Hight level objects are harder */\r
313         chance = chance - lev;\r
314 \r
315         /* Give everyone a (slight) chance */\r
316         if ((chance < USE_DEVICE) && one_in_(USE_DEVICE - chance + 1))\r
317         {\r
318                 chance = USE_DEVICE;\r
319         }\r
320 \r
321         if (world_player)\r
322         {\r
323                 if (flush_failure) flush();\r
324                 msg_print(_("止まった時の中ではうまく働かないようだ。", "Nothing happen. Maybe this staff is freezing too."));\r
325                 sound(SOUND_FAIL);\r
326                 return;\r
327         }\r
328 \r
329         /* Roll for usage */\r
330         if ((chance < USE_DEVICE) || (randint1(chance) < USE_DEVICE) || (p_ptr->pclass == CLASS_BERSERKER))\r
331         {\r
332                 if (flush_failure) flush();\r
333                 msg_print(_("杖をうまく使えなかった。", "You failed to use the staff properly."));\r
334                 sound(SOUND_FAIL);\r
335                 return;\r
336         }\r
337 \r
338         /* Notice empty staffs */\r
339         if (o_ptr->pval <= 0)\r
340         {\r
341                 if (flush_failure) flush();\r
342                 msg_print(_("この杖にはもう魔力が残っていない。", "The staff has no charges left."));\r
343                 o_ptr->ident |= (IDENT_EMPTY);\r
344 \r
345                 /* Combine / Reorder the pack (later) */\r
346                 p_ptr->update |= (PU_COMBINE | PU_REORDER);\r
347                 p_ptr->window |= (PW_INVEN);\r
348 \r
349                 return;\r
350         }\r
351 \r
352 \r
353         sound(SOUND_ZAP);\r
354 \r
355         ident = staff_effect(o_ptr->sval, &use_charge, FALSE, FALSE, object_is_aware(o_ptr));\r
356 \r
357         if (!(object_is_aware(o_ptr)))\r
358         {\r
359                 chg_virtue(V_PATIENCE, -1);\r
360                 chg_virtue(V_CHANCE, 1);\r
361                 chg_virtue(V_KNOWLEDGE, -1);\r
362         }\r
363 \r
364         /* Combine / Reorder the pack (later) */\r
365         p_ptr->update |= (PU_COMBINE | PU_REORDER);\r
366 \r
367         /* Tried the item */\r
368         object_tried(o_ptr);\r
369 \r
370         /* An identification was made */\r
371         if (ident && !object_is_aware(o_ptr))\r
372         {\r
373                 object_aware(o_ptr);\r
374                 gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);\r
375         }\r
376 \r
377         p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);\r
378 \r
379 \r
380         /* Hack -- some uses are "free" */\r
381         if (!use_charge) return;\r
382 \r
383 \r
384         /* Use a single charge */\r
385         o_ptr->pval--;\r
386 \r
387         /* XXX Hack -- unstack if necessary */\r
388         if ((item >= 0) && (o_ptr->number > 1))\r
389         {\r
390                 object_type forge;\r
391                 object_type *q_ptr;\r
392                 q_ptr = &forge;\r
393 \r
394                 /* Obtain a local object */\r
395                 object_copy(q_ptr, o_ptr);\r
396 \r
397                 /* Modify quantity */\r
398                 q_ptr->number = 1;\r
399 \r
400                 /* Restore the charges */\r
401                 o_ptr->pval++;\r
402 \r
403                 /* Unstack the used item */\r
404                 o_ptr->number--;\r
405                 p_ptr->total_weight -= q_ptr->weight;\r
406                 item = inven_carry(q_ptr);\r
407 \r
408                 msg_print(_("杖をまとめなおした。", "You unstack your staff."));\r
409         }\r
410 \r
411         /* Describe charges in the pack */\r
412         if (item >= 0)\r
413         {\r
414                 inven_item_charges(item);\r
415         }\r
416 \r
417         /* Describe charges on the floor */\r
418         else\r
419         {\r
420                 floor_item_charges(0 - item);\r
421         }\r
422 }\r
423 \r
424 /*!\r
425 * @brief 杖を使うコマンドのメインルーチン /\r
426 * @return なし\r
427 */\r
428 void do_cmd_use_staff(void)\r
429 {\r
430         OBJECT_IDX item;\r
431         concptr q, s;\r
432 \r
433         if (p_ptr->wild_mode)\r
434         {\r
435                 return;\r
436         }\r
437 \r
438         if (p_ptr->inside_arena)\r
439         {\r
440                 msg_print(_("アリーナが魔法を吸収した!", "The arena absorbs all attempted magic!"));\r
441                 msg_print(NULL);\r
442                 return;\r
443         }\r
444 \r
445         if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN))\r
446         {\r
447                 set_action(ACTION_NONE);\r
448         }\r
449 \r
450         /* Restrict choices to wands */\r
451         item_tester_tval = TV_STAFF;\r
452 \r
453         q = _("どの杖を使いますか? ", "Use which staff? ");\r
454         s = _("使える杖がない。", "You have no staff to use.");\r
455 \r
456         if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return;\r
457 \r
458         do_cmd_use_staff_aux(item);\r
459 }\r