OSDN Git Service

625893722b3e85f92b81123023d01dd1985a5d33
[hengbandforosx/hengbandosx.git] / src / cmd-item / cmd-magiceat.c
1 /*!
2  * @brief プレイヤーのアイテムに関するコマンドの実装2 / Spell/Prayer commands
3  * @date 2014/01/27
4  * @author
5  * <pre>
6  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
7  * This software may be copied and distributed for educational, research,
8  * and not for profit purposes provided that this copyright and statement
9  * are included in all such copies.  Other copyrights may also apply.
10  * 2014 Deskull rearranged comment for Doxygen.\n
11  * </pre>
12  * @details
13  * <pre>
14  * This file includes code for eating food, drinking potions,
15  * reading scrolls, aiming wands, using staffs, zapping rods,
16  * and activating artifacts.
17  *
18  * In all cases, if the player becomes "aware" of the item's use
19  * by testing it, mark it as "aware" and reward some experience
20  * based on the object's level, always rounding up.  If the player
21  * remains "unaware", mark that object "kind" as "tried".
22  *
23  * This code now correctly handles the unstacking of wands, staffs,
24  * and rods.  Note the overly paranoid warning about potential pack
25  * overflow, which allows the player to use and drop a stacked item.
26  *
27  * In all "unstacking" scenarios, the "used" object is "carried" as if
28  * the player had just picked it up.  In particular, this means that if
29  * the use of an item induces pack overflow, that item will be dropped.
30  *
31  * For simplicity, these routines induce a full "pack reorganization"
32  * which not only combines similar items, but also reorganizes various
33  * items to obey the current "sorting" method.  This may require about
34  * 400 item comparisons, but only occasionally.
35  *
36  * There may be a BIG problem with any "effect" that can cause "changes"
37  * to the inventory.  For example, a "scroll of recharging" can cause
38  * a wand/staff to "disappear", moving the inventory up.  Luckily, the
39  * scrolls all appear BEFORE the staffs/wands, so this is not a problem.
40  * But, for example, a "staff of recharging" could cause MAJOR problems.
41  * In such a case, it will be best to either (1) "postpone" the effect
42  * until the end of the function, or (2) "change" the effect, say, into
43  * giving a staff "negative" charges, or "turning a staff into a stick".
44  * It seems as though a "rod of recharging" might in fact cause problems.
45  * The basic problem is that the act of recharging (and destroying) an
46  * item causes the inducer of that action to "move", causing "o_ptr" to
47  * no longer point at the correct item, with horrifying results.
48  *
49  * Note that food/potions/scrolls no longer use bit-flags for effects,
50  * but instead use the "sval" (which is also used to sort the objects).
51  * </pre>
52  */
53
54 #include "cmd-item/cmd-magiceat.h"
55 #include "action/action-limited.h"
56 #include "cmd-item/cmd-usestaff.h"
57 #include "cmd-item/cmd-zaprod.h"
58 #include "cmd-item/cmd-zapwand.h"
59 #include "core/asking-player.h"
60 #include "game-option/disturbance-options.h"
61 #include "game-option/text-display-options.h"
62 #include "io/command-repeater.h"
63 #include "io/input-key-acceptor.h"
64 #include "io/input-key-requester.h"
65 #include "main/sound-definitions-table.h"
66 #include "main/sound-of-music.h"
67 #include "object/object-kind-hook.h"
68 #include "object/object-kind.h"
69 #include "sv-definition/sv-other-types.h"
70 #include "sv-definition/sv-rod-types.h"
71 #include "player-info/avatar.h"
72 #include "player/player-class.h"
73 #include "player/player-status.h"
74 #include "player/player-status-table.h"
75 #include "spell/spell-info.h"
76 #include "target/target-getter.h"
77 #include "term/screen-processor.h"
78 #include "term/term-color-types.h"
79 #include "util/buffer-shaper.h"
80 #include "util/int-char-converter.h"
81 #include "view/display-messages.h"
82
83 /*!
84  * @brief 魔道具術師の取り込んだ魔力一覧から選択/閲覧する /
85  * @param only_browse 閲覧するだけならばTRUE
86  * @return 選択した魔力のID、キャンセルならば-1を返す
87  */
88 static OBJECT_SUBTYPE_VALUE select_magic_eater(player_type *creature_ptr, bool only_browse)
89 {
90         OBJECT_SUBTYPE_VALUE ext = 0;
91         char choice;
92         bool flag, request_list;
93         tval_type tval = 0;
94         int             ask = TRUE;
95         OBJECT_SUBTYPE_VALUE i = 0;
96         char            out_val[160];
97
98         int menu_line = (use_menu ? 1 : 0);
99
100         COMMAND_CODE sn;
101         if (repeat_pull(&sn))
102         {
103                 /* Verify the spell */
104                 if (sn >= EATER_EXT*2 && !(creature_ptr->magic_num1[sn] > k_info[lookup_kind(TV_ROD, sn-EATER_EXT*2)].pval * (creature_ptr->magic_num2[sn] - 1) * EATER_ROD_CHARGE))
105                         return sn;
106                 else if (sn < EATER_EXT*2 && !(creature_ptr->magic_num1[sn] < EATER_CHARGE))
107                         return sn;
108         }
109         
110         for (i = 0; i < MAX_SPELLS; i++)
111         {
112                 if (creature_ptr->magic_num2[i]) break;
113         }
114
115         if (i == MAX_SPELLS)
116         {
117                 msg_print(_("魔法を覚えていない!", "You don't have any magic!"));
118                 return -1;
119         }
120
121         if (use_menu)
122         {
123                 screen_save();
124
125                 while(!tval)
126                 {
127 #ifdef JP
128                         prt(format(" %s 杖", (menu_line == 1) ? "》" : "  "), 2, 14);
129                         prt(format(" %s 魔法棒", (menu_line == 2) ? "》" : "  "), 3, 14);
130                         prt(format(" %s ロッド", (menu_line == 3) ? "》" : "  "), 4, 14);
131 #else
132                         prt(format(" %s staff", (menu_line == 1) ? "> " : "  "), 2, 14);
133                         prt(format(" %s wand", (menu_line == 2) ? "> " : "  "), 3, 14);
134                         prt(format(" %s rod", (menu_line == 3) ? "> " : "  "), 4, 14);
135 #endif
136
137                         if (only_browse) prt(_("どの種類の魔法を見ますか?", "Which type of magic do you browse?"), 0, 0);
138                         else prt(_("どの種類の魔法を使いますか?", "Which type of magic do you use?"), 0, 0);
139
140                         choice = inkey();
141                         switch(choice)
142                         {
143                         case ESCAPE:
144                         case 'z':
145                         case 'Z':
146                                 screen_load();
147                                 return -1;
148                         case '2':
149                         case 'j':
150                         case 'J':
151                                 menu_line++;
152                                 break;
153                         case '8':
154                         case 'k':
155                         case 'K':
156                                 menu_line+= 2;
157                                 break;
158                         case '\r':
159                         case 'x':
160                         case 'X':
161                                 ext = (menu_line-1)*EATER_EXT;
162                                 if (menu_line == 1) tval = TV_STAFF;
163                                 else if (menu_line == 2) tval = TV_WAND;
164                                 else tval = TV_ROD;
165                                 break;
166                         }
167                         if (menu_line > 3) menu_line -= 3;
168                 }
169                 screen_load();
170         }
171         else
172         {
173         while (TRUE)
174         {
175                 if (!get_com(_("[A] 杖, [B] 魔法棒, [C] ロッド:", "[A] staff, [B] wand, [C] rod:"), &choice, TRUE))
176                 {
177                         return -1;
178                 }
179                 if (choice == 'A' || choice == 'a')
180                 {
181                         ext = 0;
182                         tval = TV_STAFF;
183                         break;
184                 }
185                 if (choice == 'B' || choice == 'b')
186                 {
187                         ext = EATER_EXT;
188                         tval = TV_WAND;
189                         break;
190                 }
191                 if (choice == 'C' || choice == 'c')
192                 {
193                         ext = EATER_EXT*2;
194                         tval = TV_ROD;
195                         break;
196                 }
197         }
198         }
199         for (i = ext; i < ext + EATER_EXT; i++)
200         {
201                 if (creature_ptr->magic_num2[i])
202                 {
203                         if (use_menu) menu_line = i-ext+1;
204                         break;
205                 }
206         }
207         if (i == ext+EATER_EXT)
208         {
209                 msg_print(_("その種類の魔法は覚えていない!", "You don't have that type of magic!"));
210                 return -1;
211         }
212
213         /* Nothing chosen yet */
214         flag = FALSE;
215
216         if (only_browse) strnfmt(out_val, 78, _("('*'で一覧, ESCで中断) どの魔力を見ますか?",
217                                                                                         "(*=List, ESC=exit) Browse which power? "));
218         else strnfmt(out_val, 78, _("('*'で一覧, ESCで中断) どの魔力を使いますか?",
219                                                                 "(*=List, ESC=exit) Use which power? "));
220         screen_save();
221
222         request_list = always_show_list;
223
224         while (!flag)
225         {
226                 /* Show the list */
227                 if (request_list || use_menu)
228                 {
229                         byte y, x = 0;
230                         OBJECT_SUBTYPE_VALUE ctr;
231                         PERCENTAGE chance;
232                         KIND_OBJECT_IDX k_idx;
233                         char dummy[80];
234                         POSITION x1, y1;
235                         DEPTH level;
236                         byte col;
237
238                         strcpy(dummy, "");
239
240                         for (y = 1; y < 20; y++)
241                                 prt("", y, x);
242
243                         y = 1;
244
245                         /* Print header(s) */
246 #ifdef JP
247                         prt(format("                           %s 失率                           %s 失率", (tval == TV_ROD ? "  状態  " : "使用回数"), (tval == TV_ROD ? "  状態  " : "使用回数")), y++, x);
248 #else
249                         prt(format("                           %s Fail                           %s Fail", (tval == TV_ROD ? "  Stat  " : " Charges"), (tval == TV_ROD ? "  Stat  " : " Charges")), y++, x);
250 #endif
251
252                         /* Print list */
253                         for (ctr = 0; ctr < EATER_EXT; ctr++)
254                         {
255                                 if (!creature_ptr->magic_num2[ctr+ext]) continue;
256
257                                 k_idx = lookup_kind(tval, ctr);
258
259                                 if (use_menu)
260                                 {
261                                         if (ctr == (menu_line-1))
262                                                 strcpy(dummy, _("》", "> "));
263                                         else
264                                                 strcpy(dummy, "  ");
265                                 }
266                                 /* letter/number for power selection */
267                                 else
268                                 {
269                                         char letter;
270                                         if (ctr < 26)
271                                                 letter = I2A(ctr);
272                                         else
273                                                 letter = '0' + ctr - 26;
274                                         sprintf(dummy, "%c)",letter);
275                                 }
276                                 x1 = ((ctr < EATER_EXT/2) ? x : x + 40);
277                                 y1 = ((ctr < EATER_EXT/2) ? y + ctr : y + ctr - EATER_EXT/2);
278                                 level = (tval == TV_ROD ? k_info[k_idx].level * 5 / 6 - 5 : k_info[k_idx].level);
279                                 chance = level * 4 / 5 + 20;
280                                 chance -= 3 * (adj_mag_stat[creature_ptr->stat_ind[mp_ptr->spell_stat]] - 1);
281                                 level /= 2;
282                                 if (creature_ptr->lev > level)
283                                 {
284                                         chance -= 3 * (creature_ptr->lev - level);
285                                 }
286                                 chance = mod_spell_chance_1(creature_ptr, chance);
287                                 chance = MAX(chance, adj_mag_fail[creature_ptr->stat_ind[mp_ptr->spell_stat]]);
288                                 /* Stunning makes spells harder */
289                                 if (creature_ptr->stun > 50) chance += 25;
290                                 else if (creature_ptr->stun) chance += 15;
291
292                                 if (chance > 95) chance = 95;
293
294                                 chance = mod_spell_chance_2(creature_ptr, chance);
295
296                                 col = TERM_WHITE;
297
298                                 if (k_idx)
299                                 {
300                                         if (tval == TV_ROD)
301                                         {
302                                                 strcat(dummy, format(
303                                                                _(" %-22.22s 充填:%2d/%2d%3d%%", " %-22.22s   (%2d/%2d) %3d%%"),
304                                                                k_name + k_info[k_idx].name, 
305                                                                creature_ptr->magic_num1[ctr+ext] ? 
306                                                                (creature_ptr->magic_num1[ctr+ext] - 1) / (EATER_ROD_CHARGE * k_info[k_idx].pval) +1 : 0, 
307                                                                creature_ptr->magic_num2[ctr+ext], chance));
308                                                 if (creature_ptr->magic_num1[ctr+ext] > k_info[k_idx].pval * (creature_ptr->magic_num2[ctr+ext]-1) * EATER_ROD_CHARGE) col = TERM_RED;
309                                         }
310                                         else
311                                         {
312                                                 strcat(dummy, format(" %-22.22s    %2d/%2d %3d%%", k_name + k_info[k_idx].name, (s16b)(creature_ptr->magic_num1[ctr+ext]/EATER_CHARGE), creature_ptr->magic_num2[ctr+ext], chance));
313                                                 if (creature_ptr->magic_num1[ctr+ext] < EATER_CHARGE) col = TERM_RED;
314                                         }
315                                 }
316                                 else
317                                         strcpy(dummy, "");
318                                 c_prt(col, dummy, y1, x1);
319                         }
320                 }
321
322                 if (!get_com(out_val, &choice, FALSE)) break;
323
324                 if (use_menu && choice != ' ')
325                 {
326                         switch (choice)
327                         {
328                                 case '0':
329                                 {
330                                         screen_load();
331                                         return 0;
332                                 }
333
334                                 case '8':
335                                 case 'k':
336                                 case 'K':
337                                 {
338                                         do
339                                         {
340                                                 menu_line += EATER_EXT - 1;
341                                                 if (menu_line > EATER_EXT) menu_line -= EATER_EXT;
342                                         } while(!creature_ptr->magic_num2[menu_line+ext-1]);
343                                         break;
344                                 }
345
346                                 case '2':
347                                 case 'j':
348                                 case 'J':
349                                 {
350                                         do
351                                         {
352                                                 menu_line++;
353                                                 if (menu_line > EATER_EXT) menu_line -= EATER_EXT;
354                                         } while(!creature_ptr->magic_num2[menu_line+ext-1]);
355                                         break;
356                                 }
357
358                                 case '4':
359                                 case 'h':
360                                 case 'H':
361                                 case '6':
362                                 case 'l':
363                                 case 'L':
364                                 {
365                                         bool reverse = FALSE;
366                                         if ((choice == '4') || (choice == 'h') || (choice == 'H')) reverse = TRUE;
367                                         if (menu_line > EATER_EXT/2)
368                                         {
369                                                 menu_line -= EATER_EXT/2;
370                                                 reverse = TRUE;
371                                         }
372                                         else menu_line+=EATER_EXT/2;
373                                         while(!creature_ptr->magic_num2[menu_line+ext-1])
374                                         {
375                                                 if (reverse)
376                                                 {
377                                                         menu_line--;
378                                                         if (menu_line < 2) reverse = FALSE;
379                                                 }
380                                                 else
381                                                 {
382                                                         menu_line++;
383                                                         if (menu_line > EATER_EXT-1) reverse = TRUE;
384                                                 }
385                                         }
386                                         break;
387                                 }
388
389                                 case 'x':
390                                 case 'X':
391                                 case '\r':
392                                 {
393                                         i = menu_line - 1;
394                                         ask = FALSE;
395                                         break;
396                                 }
397                         }
398                 }
399
400                 /* Request redraw */
401                 if (use_menu && ask) continue;
402
403                 /* Request redraw */
404                 if (!use_menu && ((choice == ' ') || (choice == '*') || (choice == '?')))
405                 {
406                         /* Hide the list */
407                         if (request_list)
408                         {
409                                 /* Hide list */
410                                 request_list = FALSE;
411                                                                 screen_load();
412                                 screen_save();
413                         }
414                         else
415                                 request_list = TRUE;
416
417                         /* Redo asking */
418                         continue;
419                 }
420
421                 if (!use_menu)
422                 {
423                         if (isalpha(choice))
424                         {
425                                 /* Note verify */
426                                 ask = (isupper(choice));
427
428                                 /* Lowercase */
429                                 if (ask) choice = (char)tolower(choice);
430
431                                 /* Extract request */
432                                 i = (islower(choice) ? A2I(choice) : -1);
433                         }
434                         else
435                         {
436                                 ask = FALSE; /* Can't uppercase digits */
437
438                                 i = choice - '0' + 26;
439                         }
440                 }
441
442                 /* Totally Illegal */
443                 if ((i < 0) || (i > EATER_EXT) || !creature_ptr->magic_num2[i+ext])
444                 {
445                         bell();
446                         continue;
447                 }
448
449                 if (!only_browse)
450                 {
451                         /* Verify it */
452                         if (ask)
453                         {
454                                 char tmp_val[160];
455
456                                 /* Prompt */
457                                 (void) strnfmt(tmp_val, 78, _("%sを使いますか? ", "Use %s?"), k_name + k_info[lookup_kind(tval ,i)].name);
458
459                                 /* Belay that order */
460                                 if (!get_check(tmp_val)) continue;
461                         }
462                         if (tval == TV_ROD)
463                         {
464                                 if (creature_ptr->magic_num1[ext+i]  > k_info[lookup_kind(tval, i)].pval * (creature_ptr->magic_num2[ext+i] - 1) * EATER_ROD_CHARGE)
465                                 {
466                                         msg_print(_("その魔法はまだ充填している最中だ。", "The magic is still charging."));
467                                         msg_print(NULL);
468                                         if (use_menu) ask = TRUE;
469                                         continue;
470                                 }
471                         }
472                         else
473                         {
474                                 if (creature_ptr->magic_num1[ext+i] < EATER_CHARGE)
475                                 {
476                                         msg_print(_("その魔法は使用回数が切れている。", "The magic has no charges left."));
477                                         msg_print(NULL);
478                                         if (use_menu) ask = TRUE;
479                                         continue;
480                                 }
481                         }
482                 }
483
484                 /* Browse */
485                 else
486                 {
487                         int line, j;
488                         char temp[70 * 20];
489
490                         /* Clear lines, position cursor  (really should use strlen here) */
491                         term_erase(7, 23, 255);
492                         term_erase(7, 22, 255);
493                         term_erase(7, 21, 255);
494                         term_erase(7, 20, 255);
495
496                         shape_buffer(k_text + k_info[lookup_kind(tval, i)].text, 62, temp, sizeof(temp));
497                         for (j = 0, line = 21; temp[j]; j += 1 + strlen(&temp[j]))
498                         {
499                                 prt(&temp[j], line, 10);
500                                 line++;
501                         }
502
503                         continue;
504                 }
505
506                 /* Stop the loop */
507                 flag = TRUE;
508         }
509         screen_load();
510
511         if (!flag) return -1;
512
513         repeat_push(ext+i);
514         return ext+i;
515 }
516
517
518 /*!
519  * @brief 取り込んだ魔力を利用するコマンドのメインルーチン /
520  * Use eaten rod, wand or staff
521  * @param only_browse 閲覧するだけならばTRUE
522  * @param powerful 強力発動中の処理ならばTRUE
523  * @return 実際にコマンドを実行したならばTRUEを返す。
524  */
525 bool do_cmd_magic_eater(player_type *creature_ptr, bool only_browse, bool powerful)
526 {
527         OBJECT_SUBTYPE_VALUE item;
528         PERCENTAGE chance;
529         DEPTH level;
530         KIND_OBJECT_IDX k_idx;
531         tval_type tval;
532         OBJECT_SUBTYPE_VALUE sval;
533         bool use_charge = TRUE;
534
535         if (cmd_limit_confused(creature_ptr)) return FALSE;
536
537         item = select_magic_eater(creature_ptr, only_browse);
538         if (item == -1)
539         {
540                 free_turn(creature_ptr);
541                 return FALSE;
542         }
543         if (item >= EATER_EXT*2) {tval = TV_ROD;sval = item - EATER_EXT*2;}
544         else if (item >= EATER_EXT) {tval = TV_WAND;sval = item - EATER_EXT;}
545         else {tval = TV_STAFF; sval = item;}
546         k_idx = lookup_kind(tval, sval);
547
548         level = (tval == TV_ROD ? k_info[k_idx].level * 5 / 6 - 5 : k_info[k_idx].level);
549         chance = level * 4 / 5 + 20;
550         chance -= 3 * (adj_mag_stat[creature_ptr->stat_ind[mp_ptr->spell_stat]] - 1);
551         level /= 2;
552         if (creature_ptr->lev > level)
553         {
554                 chance -= 3 * (creature_ptr->lev - level);
555         }
556         chance = mod_spell_chance_1(creature_ptr, chance);
557         chance = MAX(chance, adj_mag_fail[creature_ptr->stat_ind[mp_ptr->spell_stat]]);
558         /* Stunning makes spells harder */
559         if (creature_ptr->stun > 50) chance += 25;
560         else if (creature_ptr->stun) chance += 15;
561
562         if (chance > 95) chance = 95;
563
564         chance = mod_spell_chance_2(creature_ptr, chance);
565
566         if (randint0(100) < chance)
567         {
568                 if (flush_failure) flush();
569                 
570                 msg_print(_("呪文をうまく唱えられなかった!", "You failed to get the magic off!"));
571                 sound(SOUND_FAIL);
572                 if (randint1(100) >= chance)
573                         chg_virtue(creature_ptr, V_CHANCE,-1);
574                 take_turn(creature_ptr, 100);
575
576                 return TRUE;
577         }
578         else
579         {
580                 DIRECTION dir = 0;
581
582                 if (tval == TV_ROD)
583                 {
584                         if ((sval >= SV_ROD_MIN_DIRECTION) && (sval != SV_ROD_HAVOC) && (sval != SV_ROD_AGGRAVATE) && (sval != SV_ROD_PESTICIDE))
585                                 if (!get_aim_dir(creature_ptr, &dir)) return FALSE;
586                         rod_effect(creature_ptr, sval, dir, &use_charge, powerful, TRUE);
587                         if (!use_charge) return FALSE;
588                 }
589                 else if (tval == TV_WAND)
590                 {
591                         if (!get_aim_dir(creature_ptr, &dir)) return FALSE;
592                         wand_effect(creature_ptr, sval, dir, powerful, TRUE);
593                 }
594                 else
595                 {
596                         staff_effect(creature_ptr, sval, &use_charge, powerful, TRUE, TRUE);
597                         if (!use_charge) return FALSE;
598                 }
599                 if (randint1(100) < chance)
600                         chg_virtue(creature_ptr, V_CHANCE,1);
601         }
602         take_turn(creature_ptr, 100);
603         if (tval == TV_ROD) creature_ptr->magic_num1[item] += k_info[k_idx].pval * EATER_ROD_CHARGE;
604         else creature_ptr->magic_num1[item] -= EATER_CHARGE;
605
606         return TRUE;
607 }