OSDN Git Service

6aff38222f902409fa22e497daa7f7e44518af13
[hengband/hengband.git] / src / 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 inventory.  For example, a "scroll of recharging" can cause
39  * a wand/staff to "disappear", moving the inventory 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 "cmd-usestaff.h"
57 #include "cmd-zaprod.h"
58 #include "cmd-zapwand.h"
59 #include "avatar.h"
60
61
62 /*!
63  * @brief 魔道具術師の取り込んだ魔力一覧から選択/閲覧する /
64  * @param only_browse 閲覧するだけならばTRUE
65  * @return 選択した魔力のID、キャンセルならば-1を返す
66  */
67 static OBJECT_SUBTYPE_VALUE select_magic_eater(bool only_browse)
68 {
69         OBJECT_SUBTYPE_VALUE ext = 0;
70         char choice;
71         bool flag, request_list;
72         OBJECT_TYPE_VALUE tval = 0;
73         int             ask = TRUE;
74         OBJECT_SUBTYPE_VALUE i = 0;
75         char            out_val[160];
76
77         int menu_line = (use_menu ? 1 : 0);
78
79         COMMAND_CODE sn;
80         if (repeat_pull(&sn))
81         {
82                 /* Verify the spell */
83                 if (sn >= EATER_EXT*2 && !(p_ptr->magic_num1[sn] > k_info[lookup_kind(TV_ROD, sn-EATER_EXT*2)].pval * (p_ptr->magic_num2[sn] - 1) * EATER_ROD_CHARGE))
84                         return sn;
85                 else if (sn < EATER_EXT*2 && !(p_ptr->magic_num1[sn] < EATER_CHARGE))
86                         return sn;
87         }
88         
89         for (i = 0; i < 108; i++)
90         {
91                 if (p_ptr->magic_num2[i]) break;
92         }
93         if (i == 108)
94         {
95                 msg_print(_("魔法を覚えていない!", "You don't have any magic!"));
96                 return -1;
97         }
98
99         if (use_menu)
100         {
101                 screen_save();
102
103                 while(!tval)
104                 {
105 #ifdef JP
106                         prt(format(" %s 杖", (menu_line == 1) ? "》" : "  "), 2, 14);
107                         prt(format(" %s 魔法棒", (menu_line == 2) ? "》" : "  "), 3, 14);
108                         prt(format(" %s ロッド", (menu_line == 3) ? "》" : "  "), 4, 14);
109 #else
110                         prt(format(" %s staff", (menu_line == 1) ? "> " : "  "), 2, 14);
111                         prt(format(" %s wand", (menu_line == 2) ? "> " : "  "), 3, 14);
112                         prt(format(" %s rod", (menu_line == 3) ? "> " : "  "), 4, 14);
113 #endif
114
115                         if (only_browse) prt(_("どの種類の魔法を見ますか?", "Which type of magic do you browse?"), 0, 0);
116                         else prt(_("どの種類の魔法を使いますか?", "Which type of magic do you use?"), 0, 0);
117
118                         choice = inkey();
119                         switch(choice)
120                         {
121                         case ESCAPE:
122                         case 'z':
123                         case 'Z':
124                                 screen_load();
125                                 return -1;
126                         case '2':
127                         case 'j':
128                         case 'J':
129                                 menu_line++;
130                                 break;
131                         case '8':
132                         case 'k':
133                         case 'K':
134                                 menu_line+= 2;
135                                 break;
136                         case '\r':
137                         case 'x':
138                         case 'X':
139                                 ext = (menu_line-1)*EATER_EXT;
140                                 if (menu_line == 1) tval = TV_STAFF;
141                                 else if (menu_line == 2) tval = TV_WAND;
142                                 else tval = TV_ROD;
143                                 break;
144                         }
145                         if (menu_line > 3) menu_line -= 3;
146                 }
147                 screen_load();
148         }
149         else
150         {
151         while (TRUE)
152         {
153                 if (!get_com(_("[A] 杖, [B] 魔法棒, [C] ロッド:", "[A] staff, [B] wand, [C] rod:"), &choice, TRUE))
154                 {
155                         return -1;
156                 }
157                 if (choice == 'A' || choice == 'a')
158                 {
159                         ext = 0;
160                         tval = TV_STAFF;
161                         break;
162                 }
163                 if (choice == 'B' || choice == 'b')
164                 {
165                         ext = EATER_EXT;
166                         tval = TV_WAND;
167                         break;
168                 }
169                 if (choice == 'C' || choice == 'c')
170                 {
171                         ext = EATER_EXT*2;
172                         tval = TV_ROD;
173                         break;
174                 }
175         }
176         }
177         for (i = ext; i < ext + EATER_EXT; i++)
178         {
179                 if (p_ptr->magic_num2[i])
180                 {
181                         if (use_menu) menu_line = i-ext+1;
182                         break;
183                 }
184         }
185         if (i == ext+EATER_EXT)
186         {
187                 msg_print(_("その種類の魔法は覚えていない!", "You don't have that type of magic!"));
188                 return -1;
189         }
190
191         /* Nothing chosen yet */
192         flag = FALSE;
193
194         /* Build a prompt */
195         if (only_browse) strnfmt(out_val, 78, _("('*'で一覧, ESCで中断) どの魔力を見ますか?",
196                                                                                         "(*=List, ESC=exit) Browse which power? "));
197         else strnfmt(out_val, 78, _("('*'で一覧, ESCで中断) どの魔力を使いますか?",
198                                                                 "(*=List, ESC=exit) Use which power? "));
199                 screen_save();
200
201         request_list = always_show_list;
202
203         /* Get a spell from the user */
204         while (!flag)
205         {
206                 /* Show the list */
207                 if (request_list || use_menu)
208                 {
209                         byte y, x = 0;
210                         OBJECT_SUBTYPE_VALUE ctr;
211                         PERCENTAGE chance;
212                         KIND_OBJECT_IDX k_idx;
213                         char dummy[80];
214                         POSITION x1, y1;
215                         DEPTH level;
216                         byte col;
217
218                         strcpy(dummy, "");
219
220                         for (y = 1; y < 20; y++)
221                                 prt("", y, x);
222
223                         y = 1;
224
225                         /* Print header(s) */
226 #ifdef JP
227                         prt(format("                           %s 失率                           %s 失率", (tval == TV_ROD ? "  状態  " : "使用回数"), (tval == TV_ROD ? "  状態  " : "使用回数")), y++, x);
228 #else
229                         prt(format("                           %s Fail                           %s Fail", (tval == TV_ROD ? "  Stat  " : " Charges"), (tval == TV_ROD ? "  Stat  " : " Charges")), y++, x);
230 #endif
231
232                         /* Print list */
233                         for (ctr = 0; ctr < EATER_EXT; ctr++)
234                         {
235                                 if (!p_ptr->magic_num2[ctr+ext]) continue;
236
237                                 k_idx = lookup_kind(tval, ctr);
238
239                                 if (use_menu)
240                                 {
241                                         if (ctr == (menu_line-1))
242                                                 strcpy(dummy, _("》", "> "));
243                                         else
244                                                 strcpy(dummy, "  ");
245                                 }
246                                 /* letter/number for power selection */
247                                 else
248                                 {
249                                         char letter;
250                                         if (ctr < 26)
251                                                 letter = I2A(ctr);
252                                         else
253                                                 letter = '0' + ctr - 26;
254                                         sprintf(dummy, "%c)",letter);
255                                 }
256                                 x1 = ((ctr < EATER_EXT/2) ? x : x + 40);
257                                 y1 = ((ctr < EATER_EXT/2) ? y + ctr : y + ctr - EATER_EXT/2);
258                                 level = (tval == TV_ROD ? k_info[k_idx].level * 5 / 6 - 5 : k_info[k_idx].level);
259                                 chance = level * 4 / 5 + 20;
260                                 chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[mp_ptr->spell_stat]] - 1);
261                                 level /= 2;
262                                 if (p_ptr->lev > level)
263                                 {
264                                         chance -= 3 * (p_ptr->lev - level);
265                                 }
266                                 chance = mod_spell_chance_1(chance);
267                                 chance = MAX(chance, adj_mag_fail[p_ptr->stat_ind[mp_ptr->spell_stat]]);
268                                 /* Stunning makes spells harder */
269                                 if (p_ptr->stun > 50) chance += 25;
270                                 else if (p_ptr->stun) chance += 15;
271
272                                 if (chance > 95) chance = 95;
273
274                                 chance = mod_spell_chance_2(chance);
275
276                                 col = TERM_WHITE;
277
278                                 if (k_idx)
279                                 {
280                                         if (tval == TV_ROD)
281                                         {
282                                                 strcat(dummy, format(
283                                                                _(" %-22.22s 充填:%2d/%2d%3d%%", " %-22.22s   (%2d/%2d) %3d%%"),
284                                                                k_name + k_info[k_idx].name, 
285                                                                p_ptr->magic_num1[ctr+ext] ? 
286                                                                (p_ptr->magic_num1[ctr+ext] - 1) / (EATER_ROD_CHARGE * k_info[k_idx].pval) +1 : 0, 
287                                                                p_ptr->magic_num2[ctr+ext], chance));
288                                                 if (p_ptr->magic_num1[ctr+ext] > k_info[k_idx].pval * (p_ptr->magic_num2[ctr+ext]-1) * EATER_ROD_CHARGE) col = TERM_RED;
289                                         }
290                                         else
291                                         {
292                                                 strcat(dummy, format(" %-22.22s    %2d/%2d %3d%%", k_name + k_info[k_idx].name, (s16b)(p_ptr->magic_num1[ctr+ext]/EATER_CHARGE), p_ptr->magic_num2[ctr+ext], chance));
293                                                 if (p_ptr->magic_num1[ctr+ext] < EATER_CHARGE) col = TERM_RED;
294                                         }
295                                 }
296                                 else
297                                         strcpy(dummy, "");
298                                 c_prt(col, dummy, y1, x1);
299                         }
300                 }
301
302                 if (!get_com(out_val, &choice, FALSE)) break;
303
304                 if (use_menu && choice != ' ')
305                 {
306                         switch (choice)
307                         {
308                                 case '0':
309                                 {
310                                         screen_load();
311                                         return 0;
312                                 }
313
314                                 case '8':
315                                 case 'k':
316                                 case 'K':
317                                 {
318                                         do
319                                         {
320                                                 menu_line += EATER_EXT - 1;
321                                                 if (menu_line > EATER_EXT) menu_line -= EATER_EXT;
322                                         } while(!p_ptr->magic_num2[menu_line+ext-1]);
323                                         break;
324                                 }
325
326                                 case '2':
327                                 case 'j':
328                                 case 'J':
329                                 {
330                                         do
331                                         {
332                                                 menu_line++;
333                                                 if (menu_line > EATER_EXT) menu_line -= EATER_EXT;
334                                         } while(!p_ptr->magic_num2[menu_line+ext-1]);
335                                         break;
336                                 }
337
338                                 case '4':
339                                 case 'h':
340                                 case 'H':
341                                 case '6':
342                                 case 'l':
343                                 case 'L':
344                                 {
345                                         bool reverse = FALSE;
346                                         if ((choice == '4') || (choice == 'h') || (choice == 'H')) reverse = TRUE;
347                                         if (menu_line > EATER_EXT/2)
348                                         {
349                                                 menu_line -= EATER_EXT/2;
350                                                 reverse = TRUE;
351                                         }
352                                         else menu_line+=EATER_EXT/2;
353                                         while(!p_ptr->magic_num2[menu_line+ext-1])
354                                         {
355                                                 if (reverse)
356                                                 {
357                                                         menu_line--;
358                                                         if (menu_line < 2) reverse = FALSE;
359                                                 }
360                                                 else
361                                                 {
362                                                         menu_line++;
363                                                         if (menu_line > EATER_EXT-1) reverse = TRUE;
364                                                 }
365                                         }
366                                         break;
367                                 }
368
369                                 case 'x':
370                                 case 'X':
371                                 case '\r':
372                                 {
373                                         i = menu_line - 1;
374                                         ask = FALSE;
375                                         break;
376                                 }
377                         }
378                 }
379
380                 /* Request redraw */
381                 if (use_menu && ask) continue;
382
383                 /* Request redraw */
384                 if (!use_menu && ((choice == ' ') || (choice == '*') || (choice == '?')))
385                 {
386                         /* Hide the list */
387                         if (request_list)
388                         {
389                                 /* Hide list */
390                                 request_list = FALSE;
391                                                                 screen_load();
392                                 screen_save();
393                         }
394                         else
395                                 request_list = TRUE;
396
397                         /* Redo asking */
398                         continue;
399                 }
400
401                 if (!use_menu)
402                 {
403                         if (isalpha(choice))
404                         {
405                                 /* Note verify */
406                                 ask = (isupper(choice));
407
408                                 /* Lowercase */
409                                 if (ask) choice = (char)tolower(choice);
410
411                                 /* Extract request */
412                                 i = (islower(choice) ? A2I(choice) : -1);
413                         }
414                         else
415                         {
416                                 ask = FALSE; /* Can't uppercase digits */
417
418                                 i = choice - '0' + 26;
419                         }
420                 }
421
422                 /* Totally Illegal */
423                 if ((i < 0) || (i > EATER_EXT) || !p_ptr->magic_num2[i+ext])
424                 {
425                         bell();
426                         continue;
427                 }
428
429                 if (!only_browse)
430                 {
431                         /* Verify it */
432                         if (ask)
433                         {
434                                 char tmp_val[160];
435
436                                 /* Prompt */
437                                 (void) strnfmt(tmp_val, 78, _("%sを使いますか? ", "Use %s?"), k_name + k_info[lookup_kind(tval ,i)].name);
438
439                                 /* Belay that order */
440                                 if (!get_check(tmp_val)) continue;
441                         }
442                         if (tval == TV_ROD)
443                         {
444                                 if (p_ptr->magic_num1[ext+i]  > k_info[lookup_kind(tval, i)].pval * (p_ptr->magic_num2[ext+i] - 1) * EATER_ROD_CHARGE)
445                                 {
446                                         msg_print(_("その魔法はまだ充填している最中だ。", "The magic are still charging."));
447                                         msg_print(NULL);
448                                         if (use_menu) ask = TRUE;
449                                         continue;
450                                 }
451                         }
452                         else
453                         {
454                                 if (p_ptr->magic_num1[ext+i] < EATER_CHARGE)
455                                 {
456                                         msg_print(_("その魔法は使用回数が切れている。", "The magic has no charges left."));
457                                         msg_print(NULL);
458                                         if (use_menu) ask = TRUE;
459                                         continue;
460                                 }
461                         }
462                 }
463
464                 /* Browse */
465                 else
466                 {
467                         int line, j;
468                         char temp[70 * 20];
469
470                         /* Clear lines, position cursor  (really should use strlen here) */
471                         Term_erase(7, 23, 255);
472                         Term_erase(7, 22, 255);
473                         Term_erase(7, 21, 255);
474                         Term_erase(7, 20, 255);
475
476                         roff_to_buf(k_text + k_info[lookup_kind(tval, i)].text, 62, temp, sizeof(temp));
477                         for (j = 0, line = 21; temp[j]; j += 1 + strlen(&temp[j]))
478                         {
479                                 prt(&temp[j], line, 10);
480                                 line++;
481                         }
482
483                         continue;
484                 }
485
486                 /* Stop the loop */
487                 flag = TRUE;
488         }
489         screen_load();
490
491         if (!flag) return -1;
492
493         repeat_push(ext+i);
494         return ext+i;
495 }
496
497
498 /*!
499  * @brief 取り込んだ魔力を利用するコマンドのメインルーチン /
500  * Use eaten rod, wand or staff
501  * @param only_browse 閲覧するだけならばTRUE
502  * @param powerful 強力発動中の処理ならばTRUE
503  * @return 実際にコマンドを実行したならばTRUEを返す。
504  */
505 bool do_cmd_magic_eater(bool only_browse, bool powerful)
506 {
507         OBJECT_SUBTYPE_VALUE item;
508         PERCENTAGE chance;
509         DEPTH level;
510         KIND_OBJECT_IDX k_idx;
511         OBJECT_TYPE_VALUE tval;
512         OBJECT_SUBTYPE_VALUE sval;
513         bool use_charge = TRUE;
514
515         /* Not when confused */
516         if (!only_browse && p_ptr->confused)
517         {
518                 msg_print(_("混乱していて唱えられない!", "You are too confused!"));
519                 return FALSE;
520         }
521
522         item = select_magic_eater(only_browse);
523         if (item == -1)
524         {
525                 p_ptr->energy_use = 0;
526                 return FALSE;
527         }
528         if (item >= EATER_EXT*2) {tval = TV_ROD;sval = item - EATER_EXT*2;}
529         else if (item >= EATER_EXT) {tval = TV_WAND;sval = item - EATER_EXT;}
530         else {tval = TV_STAFF; sval = item;}
531         k_idx = lookup_kind(tval, sval);
532
533         level = (tval == TV_ROD ? k_info[k_idx].level * 5 / 6 - 5 : k_info[k_idx].level);
534         chance = level * 4 / 5 + 20;
535         chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[mp_ptr->spell_stat]] - 1);
536         level /= 2;
537         if (p_ptr->lev > level)
538         {
539                 chance -= 3 * (p_ptr->lev - level);
540         }
541         chance = mod_spell_chance_1(chance);
542         chance = MAX(chance, adj_mag_fail[p_ptr->stat_ind[mp_ptr->spell_stat]]);
543         /* Stunning makes spells harder */
544         if (p_ptr->stun > 50) chance += 25;
545         else if (p_ptr->stun) chance += 15;
546
547         if (chance > 95) chance = 95;
548
549         chance = mod_spell_chance_2(chance);
550
551         if (randint0(100) < chance)
552         {
553                 if (flush_failure) flush();
554                 
555                 msg_print(_("呪文をうまく唱えられなかった!", "You failed to get the magic off!"));
556                 sound(SOUND_FAIL);
557                 if (randint1(100) >= chance)
558                         chg_virtue(V_CHANCE,-1);
559                 p_ptr->energy_use = 100;
560
561                 return TRUE;
562         }
563         else
564         {
565                 DIRECTION dir = 0;
566
567                 if (tval == TV_ROD)
568                 {
569                         if ((sval >= SV_ROD_MIN_DIRECTION) && (sval != SV_ROD_HAVOC) && (sval != SV_ROD_AGGRAVATE) && (sval != SV_ROD_PESTICIDE))
570                                 if (!get_aim_dir(&dir)) return FALSE;
571                         rod_effect(sval, dir, &use_charge, powerful, TRUE);
572                         if (!use_charge) return FALSE;
573                 }
574                 else if (tval == TV_WAND)
575                 {
576                         if (!get_aim_dir(&dir)) return FALSE;
577                         wand_effect(sval, dir, powerful, TRUE);
578                 }
579                 else
580                 {
581                         staff_effect(sval, &use_charge, powerful, TRUE, TRUE);
582                         if (!use_charge) return FALSE;
583                 }
584                 if (randint1(100) < chance)
585                         chg_virtue(V_CHANCE,1);
586         }
587         p_ptr->energy_use = 100;
588         if (tval == TV_ROD) p_ptr->magic_num1[item] += k_info[k_idx].pval * EATER_ROD_CHARGE;
589         else p_ptr->magic_num1[item] -= EATER_CHARGE;
590
591         return TRUE;
592 }