OSDN Git Service

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