OSDN Git Service

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