OSDN Git Service

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