OSDN Git Service

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