OSDN Git Service

9fe7a5334555cdda08b9908c48b71ecb30fac2ed
[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 (dispel_evil(powerful ? 225 : 150)) ident = TRUE;\r
236                 k = 3 * lev;\r
237                 if (set_protevil((magic ? 0 : p_ptr->protevil) + randint1(25) + k, FALSE)) ident = TRUE;\r
238                 if (set_poisoned(0)) ident = TRUE;\r
239                 if (set_afraid(0)) ident = TRUE;\r
240                 if (hp_player(50)) ident = TRUE;\r
241                 if (set_stun(0)) ident = TRUE;\r
242                 if (set_cut(0)) ident = TRUE;\r
243                 break;\r
244         }\r
245 \r
246         case SV_STAFF_GENOCIDE:\r
247         {\r
248                 (void)symbol_genocide((magic ? lev + 50 : 200), TRUE);\r
249                 ident = TRUE;\r
250                 break;\r
251         }\r
252 \r
253         case SV_STAFF_EARTHQUAKES:\r
254         {\r
255                 if (earthquake(p_ptr->y, p_ptr->x, (powerful ? 15 : 10)))\r
256                         ident = TRUE;\r
257                 else\r
258                         msg_print(_("ダンジョンが揺れた。", "The dungeon trembles."));\r
259 \r
260                 break;\r
261         }\r
262 \r
263         case SV_STAFF_DESTRUCTION:\r
264         {\r
265                 if (destroy_area(p_ptr->y, p_ptr->x, (powerful ? 18 : 13) + randint0(5), FALSE))\r
266                         ident = TRUE;\r
267 \r
268                 break;\r
269         }\r
270 \r
271         case SV_STAFF_ANIMATE_DEAD:\r
272         {\r
273                 if (animate_dead(0, p_ptr->y, p_ptr->x))\r
274                         ident = TRUE;\r
275 \r
276                 break;\r
277         }\r
278 \r
279         case SV_STAFF_MSTORM:\r
280         {\r
281                 msg_print(_("強力な魔力が敵を引き裂いた!", "Mighty magics rend your enemies!"));\r
282                 project(0, (powerful ? 7 : 5), p_ptr->y, p_ptr->x,\r
283                         (randint1(200) + (powerful ? 500 : 300)) * 2, GF_MANA, PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID, -1);\r
284                 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
285                 {\r
286                         (void)take_hit(DAMAGE_NOESCAPE, 50, _("コントロールし難い強力な魔力の解放", "unleashing magics too mighty to control"), -1);\r
287                 }\r
288                 ident = TRUE;\r
289 \r
290                 break;\r
291         }\r
292 \r
293         case SV_STAFF_NOTHING:\r
294         {\r
295                 msg_print(_("何も起らなかった。", "Nothing happen."));\r
296                 if (prace_is_(RACE_SKELETON) || prace_is_(RACE_GOLEM) ||\r
297                         prace_is_(RACE_ZOMBIE) || prace_is_(RACE_SPECTRE))\r
298                         msg_print(_("もったいない事をしたような気がする。食べ物は大切にしなくては。", "What a waste.  It's your food!"));\r
299                 break;\r
300         }\r
301         }\r
302         return ident;\r
303 }\r
304 \r
305 /*!\r
306  * @brief 杖を使うコマンドのサブルーチン /\r
307  * Use a staff.                 -RAK-\r
308  * @param item 使うオブジェクトの所持品ID\r
309  * @return なし\r
310  * @details\r
311  * One charge of one staff disappears.\r
312  * Hack -- staffs of identify can be "cancelled".\r
313  */\r
314 void do_cmd_use_staff_aux(INVENTORY_IDX item)\r
315 {\r
316         int         ident, chance, lev;\r
317         object_type *o_ptr;\r
318 \r
319 \r
320         /* Hack -- let staffs of identify get aborted */\r
321         bool use_charge = TRUE;\r
322 \r
323 \r
324         /* Get the item (in the pack) */\r
325         if (item >= 0)\r
326         {\r
327                 o_ptr = &inventory[item];\r
328         }\r
329 \r
330         /* Get the item (on the floor) */\r
331         else\r
332         {\r
333                 o_ptr = &o_list[0 - item];\r
334         }\r
335 \r
336 \r
337         /* Mega-Hack -- refuse to use a pile from the ground */\r
338         if ((item < 0) && (o_ptr->number > 1))\r
339         {\r
340                 msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));\r
341                 return;\r
342         }\r
343 \r
344 \r
345         p_ptr->energy_use = 100;\r
346 \r
347         /* Extract the item level */\r
348         lev = k_info[o_ptr->k_idx].level;\r
349         if (lev > 50) lev = 50 + (lev - 50) / 2;\r
350 \r
351         /* Base chance of success */\r
352         chance = p_ptr->skill_dev;\r
353 \r
354         /* Confusion hurts skill */\r
355         if (p_ptr->confused) chance = chance / 2;\r
356 \r
357         /* Hight level objects are harder */\r
358         chance = chance - lev;\r
359 \r
360         /* Give everyone a (slight) chance */\r
361         if ((chance < USE_DEVICE) && one_in_(USE_DEVICE - chance + 1))\r
362         {\r
363                 chance = USE_DEVICE;\r
364         }\r
365 \r
366         if (world_player)\r
367         {\r
368                 if (flush_failure) flush();\r
369                 msg_print(_("止まった時の中ではうまく働かないようだ。", "Nothing happen. Maybe this staff is freezing too."));\r
370                 sound(SOUND_FAIL);\r
371                 return;\r
372         }\r
373 \r
374         /* Roll for usage */\r
375         if ((chance < USE_DEVICE) || (randint1(chance) < USE_DEVICE) || (p_ptr->pclass == CLASS_BERSERKER))\r
376         {\r
377                 if (flush_failure) flush();\r
378                 msg_print(_("杖をうまく使えなかった。", "You failed to use the staff properly."));\r
379                 sound(SOUND_FAIL);\r
380                 return;\r
381         }\r
382 \r
383         /* Notice empty staffs */\r
384         if (o_ptr->pval <= 0)\r
385         {\r
386                 if (flush_failure) flush();\r
387                 msg_print(_("この杖にはもう魔力が残っていない。", "The staff has no charges left."));\r
388                 o_ptr->ident |= (IDENT_EMPTY);\r
389 \r
390                 /* Combine / Reorder the pack (later) */\r
391                 p_ptr->update |= (PU_COMBINE | PU_REORDER);\r
392                 p_ptr->window |= (PW_INVEN);\r
393 \r
394                 return;\r
395         }\r
396 \r
397 \r
398         sound(SOUND_ZAP);\r
399 \r
400         ident = staff_effect(o_ptr->sval, &use_charge, FALSE, FALSE, object_is_aware(o_ptr));\r
401 \r
402         if (!(object_is_aware(o_ptr)))\r
403         {\r
404                 chg_virtue(V_PATIENCE, -1);\r
405                 chg_virtue(V_CHANCE, 1);\r
406                 chg_virtue(V_KNOWLEDGE, -1);\r
407         }\r
408 \r
409         /* Combine / Reorder the pack (later) */\r
410         p_ptr->update |= (PU_COMBINE | PU_REORDER);\r
411 \r
412         /* Tried the item */\r
413         object_tried(o_ptr);\r
414 \r
415         /* An identification was made */\r
416         if (ident && !object_is_aware(o_ptr))\r
417         {\r
418                 object_aware(o_ptr);\r
419                 gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);\r
420         }\r
421 \r
422         p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);\r
423 \r
424 \r
425         /* Hack -- some uses are "free" */\r
426         if (!use_charge) return;\r
427 \r
428 \r
429         /* Use a single charge */\r
430         o_ptr->pval--;\r
431 \r
432         /* XXX Hack -- unstack if necessary */\r
433         if ((item >= 0) && (o_ptr->number > 1))\r
434         {\r
435                 object_type forge;\r
436                 object_type *q_ptr;\r
437                 q_ptr = &forge;\r
438 \r
439                 /* Obtain a local object */\r
440                 object_copy(q_ptr, o_ptr);\r
441 \r
442                 /* Modify quantity */\r
443                 q_ptr->number = 1;\r
444 \r
445                 /* Restore the charges */\r
446                 o_ptr->pval++;\r
447 \r
448                 /* Unstack the used item */\r
449                 o_ptr->number--;\r
450                 p_ptr->total_weight -= q_ptr->weight;\r
451                 item = inven_carry(q_ptr);\r
452 \r
453                 msg_print(_("杖をまとめなおした。", "You unstack your staff."));\r
454         }\r
455 \r
456         /* Describe charges in the pack */\r
457         if (item >= 0)\r
458         {\r
459                 inven_item_charges(item);\r
460         }\r
461 \r
462         /* Describe charges on the floor */\r
463         else\r
464         {\r
465                 floor_item_charges(0 - item);\r
466         }\r
467 }\r
468 \r
469 /*!\r
470 * @brief 杖を使うコマンドのメインルーチン /\r
471 * @return なし\r
472 */\r
473 void do_cmd_use_staff(void)\r
474 {\r
475         OBJECT_IDX item;\r
476         concptr q, s;\r
477 \r
478         if (p_ptr->wild_mode)\r
479         {\r
480                 return;\r
481         }\r
482 \r
483         if (p_ptr->inside_arena)\r
484         {\r
485                 msg_print(_("アリーナが魔法を吸収した!", "The arena absorbs all attempted magic!"));\r
486                 msg_print(NULL);\r
487                 return;\r
488         }\r
489 \r
490         if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN))\r
491         {\r
492                 set_action(ACTION_NONE);\r
493         }\r
494 \r
495         /* Restrict choices to wands */\r
496         item_tester_tval = TV_STAFF;\r
497 \r
498         q = _("どの杖を使いますか? ", "Use which staff? ");\r
499         s = _("使える杖がない。", "You have no staff to use.");\r
500 \r
501         if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return;\r
502 \r
503         do_cmd_use_staff_aux(item);\r
504 }\r