2 * @brief プレイヤーのアイテムに関するコマンドの実装2 / Spell/Prayer commands
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
14 * This file includes code for eating food, drinking potions,
15 * reading scrolls, aiming wands, using staffs, zapping rods,
16 * and activating artifacts.
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".
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.
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.
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.
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.
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).
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 "player-info/avatar.h"
70 #include "player-status/player-energy.h"
71 #include "player/player-class.h"
72 #include "player/player-status-table.h"
73 #include "spell/spell-info.h"
74 #include "sv-definition/sv-other-types.h"
75 #include "sv-definition/sv-rod-types.h"
76 #include "system/player-type-definition.h"
77 #include "target/target-getter.h"
78 #include "term/screen-processor.h"
79 #include "term/term-color-types.h"
80 #include "util/buffer-shaper.h"
81 #include "util/int-char-converter.h"
82 #include "view/display-messages.h"
85 * @brief 魔道具術師の取り込んだ魔力一覧から選択/閲覧する /
86 * @param only_browse 閲覧するだけならばTRUE
87 * @return 選択した魔力のID、キャンセルならば-1を返す
89 static OBJECT_SUBTYPE_VALUE select_magic_eater(player_type *creature_ptr, bool only_browse)
91 OBJECT_SUBTYPE_VALUE ext = 0;
93 bool flag, request_list;
94 tval_type tval = TV_NONE;
96 OBJECT_SUBTYPE_VALUE i = 0;
99 int menu_line = (use_menu ? 1 : 0);
102 if (repeat_pull(&sn)) {
103 /* Verify the spell */
104 if (sn >= EATER_EXT * 2
105 && !(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))
107 else if (sn < EATER_EXT * 2 && !(creature_ptr->magic_num1[sn] < EATER_CHARGE))
111 for (i = 0; i < MAX_SPELLS; i++) {
112 if (creature_ptr->magic_num2[i])
116 if (i == MAX_SPELLS) {
117 msg_print(_("魔法を覚えていない!", "You don't have any magic!"));
126 prt(format(" %s 杖", (menu_line == 1) ? "》" : " "), 2, 14);
127 prt(format(" %s 魔法棒", (menu_line == 2) ? "》" : " "), 3, 14);
128 prt(format(" %s ロッド", (menu_line == 3) ? "》" : " "), 4, 14);
130 prt(format(" %s staff", (menu_line == 1) ? "> " : " "), 2, 14);
131 prt(format(" %s wand", (menu_line == 2) ? "> " : " "), 3, 14);
132 prt(format(" %s rod", (menu_line == 3) ? "> " : " "), 4, 14);
136 prt(_("どの種類の魔法を見ますか?", "Which type of magic do you browse?"), 0, 0);
138 prt(_("どの種類の魔法を使いますか?", "Which type of magic do you use?"), 0, 0);
160 ext = (menu_line - 1) * EATER_EXT;
163 else if (menu_line == 2)
175 if (!get_com(_("[A] 杖, [B] 魔法棒, [C] ロッド:", "[A] staff, [B] wand, [C] rod:"), &choice, TRUE)) {
178 if (choice == 'A' || choice == 'a') {
183 if (choice == 'B' || choice == 'b') {
188 if (choice == 'C' || choice == 'c') {
195 for (i = ext; i < ext + EATER_EXT; i++) {
196 if (creature_ptr->magic_num2[i]) {
198 menu_line = i - ext + 1;
202 if (i == ext + EATER_EXT) {
203 msg_print(_("その種類の魔法は覚えていない!", "You don't have that type of magic!"));
207 /* Nothing chosen yet */
211 strnfmt(out_val, 78, _("('*'で一覧, ESCで中断) どの魔力を見ますか?", "(*=List, ESC=exit) Browse which power? "));
213 strnfmt(out_val, 78, _("('*'で一覧, ESCで中断) どの魔力を使いますか?", "(*=List, ESC=exit) Use which power? "));
216 request_list = always_show_list;
220 if (request_list || use_menu) {
222 OBJECT_SUBTYPE_VALUE ctr;
224 KIND_OBJECT_IDX k_idx;
232 for (y = 1; y < 20; y++)
237 /* Print header(s) */
239 prt(format(" %s 失率 %s 失率", (tval == TV_ROD ? " 状態 " : "使用回数"),
240 (tval == TV_ROD ? " 状態 " : "使用回数")),
243 prt(format(" %s Fail %s Fail", (tval == TV_ROD ? " Stat " : " Charges"),
244 (tval == TV_ROD ? " Stat " : " Charges")),
249 for (ctr = 0; ctr < EATER_EXT; ctr++) {
250 if (!creature_ptr->magic_num2[ctr + ext])
253 k_idx = lookup_kind(tval, ctr);
256 if (ctr == (menu_line - 1))
257 strcpy(dummy, _("》", "> "));
261 /* letter/number for power selection */
267 letter = '0' + ctr - 26;
268 sprintf(dummy, "%c)", letter);
270 x1 = ((ctr < EATER_EXT / 2) ? x : x + 40);
271 y1 = ((ctr < EATER_EXT / 2) ? y + ctr : y + ctr - EATER_EXT / 2);
272 level = (tval == TV_ROD ? k_info[k_idx].level * 5 / 6 - 5 : k_info[k_idx].level);
273 chance = level * 4 / 5 + 20;
274 chance -= 3 * (adj_mag_stat[creature_ptr->stat_index[mp_ptr->spell_stat]] - 1);
276 if (creature_ptr->lev > level) {
277 chance -= 3 * (creature_ptr->lev - level);
279 chance = mod_spell_chance_1(creature_ptr, chance);
280 chance = MAX(chance, adj_mag_fail[creature_ptr->stat_index[mp_ptr->spell_stat]]);
281 /* Stunning makes spells harder */
282 if (creature_ptr->stun > 50)
284 else if (creature_ptr->stun)
290 chance = mod_spell_chance_2(creature_ptr, chance);
295 if (tval == TV_ROD) {
297 format(_(" %-22.22s 充填:%2d/%2d%3d%%", " %-22.22s (%2d/%2d) %3d%%"), k_info[k_idx].name.c_str(),
298 creature_ptr->magic_num1[ctr + ext] ? (creature_ptr->magic_num1[ctr + ext] - 1) / (EATER_ROD_CHARGE * k_info[k_idx].pval) + 1
300 creature_ptr->magic_num2[ctr + ext], chance));
301 if (creature_ptr->magic_num1[ctr + ext] > k_info[k_idx].pval * (creature_ptr->magic_num2[ctr + ext] - 1) * EATER_ROD_CHARGE)
305 format(" %-22.22s %2d/%2d %3d%%", k_info[k_idx].name.c_str(), (s16b)(creature_ptr->magic_num1[ctr + ext] / EATER_CHARGE),
306 creature_ptr->magic_num2[ctr + ext], chance));
307 if (creature_ptr->magic_num1[ctr + ext] < EATER_CHARGE)
312 c_prt(col, dummy, y1, x1);
316 if (!get_com(out_val, &choice, FALSE))
319 if (use_menu && choice != ' ') {
330 menu_line += EATER_EXT - 1;
331 if (menu_line > EATER_EXT)
332 menu_line -= EATER_EXT;
333 } while (!creature_ptr->magic_num2[menu_line + ext - 1]);
342 if (menu_line > EATER_EXT)
343 menu_line -= EATER_EXT;
344 } while (!creature_ptr->magic_num2[menu_line + ext - 1]);
354 bool reverse = FALSE;
355 if ((choice == '4') || (choice == 'h') || (choice == 'H'))
357 if (menu_line > EATER_EXT / 2) {
358 menu_line -= EATER_EXT / 2;
361 menu_line += EATER_EXT / 2;
362 while (!creature_ptr->magic_num2[menu_line + ext - 1]) {
369 if (menu_line > EATER_EXT - 1)
391 if (!use_menu && ((choice == ' ') || (choice == '*') || (choice == '?'))) {
395 request_list = FALSE;
406 if (isalpha(choice)) {
408 ask = (isupper(choice));
412 choice = (char)tolower(choice);
414 /* Extract request */
415 i = (islower(choice) ? A2I(choice) : -1);
417 ask = FALSE; /* Can't uppercase digits */
419 i = choice - '0' + 26;
423 /* Totally Illegal */
424 if ((i < 0) || (i > EATER_EXT) || !creature_ptr->magic_num2[i + ext]) {
435 (void)strnfmt(tmp_val, 78, _("%sを使いますか? ", "Use %s? "), k_info[lookup_kind(tval, i)].name.c_str());
437 /* Belay that order */
438 if (!get_check(tmp_val))
441 if (tval == TV_ROD) {
442 if (creature_ptr->magic_num1[ext + i] > k_info[lookup_kind(tval, i)].pval * (creature_ptr->magic_num2[ext + i] - 1) * EATER_ROD_CHARGE) {
443 msg_print(_("その魔法はまだ充填している最中だ。", "The magic is still charging."));
450 if (creature_ptr->magic_num1[ext + i] < EATER_CHARGE) {
451 msg_print(_("その魔法は使用回数が切れている。", "The magic has no charges left."));
465 /* Clear lines, position cursor (really should use strlen here) */
466 term_erase(7, 23, 255);
467 term_erase(7, 22, 255);
468 term_erase(7, 21, 255);
469 term_erase(7, 20, 255);
471 shape_buffer(k_info[lookup_kind(tval, i)].text.c_str(), 62, temp, sizeof(temp));
472 for (j = 0, line = 21; temp[j]; j += 1 + strlen(&temp[j])) {
473 prt(&temp[j], line, 10);
488 repeat_push(ext + i);
493 * @brief 取り込んだ魔力を利用するコマンドのメインルーチン /
494 * Use eaten rod, wand or staff
495 * @param only_browse 閲覧するだけならばTRUE
496 * @param powerful 強力発動中の処理ならばTRUE
497 * @return 実際にコマンドを実行したならばTRUEを返す。
499 bool do_cmd_magic_eater(player_type *creature_ptr, bool only_browse, bool powerful)
502 OBJECT_SUBTYPE_VALUE sval;
503 bool use_charge = TRUE;
505 if (cmd_limit_confused(creature_ptr))
508 auto item = select_magic_eater(creature_ptr, only_browse);
509 PlayerEnergy energy(creature_ptr);
511 energy.reset_player_turn();
514 if (item >= EATER_EXT * 2) {
516 sval = item - EATER_EXT * 2;
517 } else if (item >= EATER_EXT) {
519 sval = item - EATER_EXT;
525 auto k_idx = lookup_kind(tval, sval);
526 auto level = (tval == TV_ROD ? k_info[k_idx].level * 5 / 6 - 5 : k_info[k_idx].level);
527 auto chance = level * 4 / 5 + 20;
528 chance -= 3 * (adj_mag_stat[creature_ptr->stat_index[mp_ptr->spell_stat]] - 1);
530 if (creature_ptr->lev > level) {
531 chance -= 3 * (creature_ptr->lev - level);
533 chance = mod_spell_chance_1(creature_ptr, chance);
534 chance = MAX(chance, adj_mag_fail[creature_ptr->stat_index[mp_ptr->spell_stat]]);
535 /* Stunning makes spells harder */
536 if (creature_ptr->stun > 50)
538 else if (creature_ptr->stun)
544 chance = mod_spell_chance_2(creature_ptr, chance);
546 if (randint0(100) < chance) {
550 msg_print(_("呪文をうまく唱えられなかった!", "You failed to get the magic off!"));
552 if (randint1(100) >= chance)
553 chg_virtue(creature_ptr, V_CHANCE, -1);
554 energy.set_player_turn_energy(100);
560 if (tval == TV_ROD) {
561 if ((sval >= SV_ROD_MIN_DIRECTION) && (sval != SV_ROD_HAVOC) && (sval != SV_ROD_AGGRAVATE) && (sval != SV_ROD_PESTICIDE))
562 if (!get_aim_dir(creature_ptr, &dir))
564 rod_effect(creature_ptr, sval, dir, &use_charge, powerful, TRUE);
567 } else if (tval == TV_WAND) {
568 if (!get_aim_dir(creature_ptr, &dir))
570 wand_effect(creature_ptr, sval, dir, powerful, TRUE);
572 staff_effect(creature_ptr, sval, &use_charge, powerful, TRUE, TRUE);
576 if (randint1(100) < chance)
577 chg_virtue(creature_ptr, V_CHANCE, 1);
580 energy.set_player_turn_energy(100);
582 creature_ptr->magic_num1[item] += k_info[k_idx].pval * EATER_ROD_CHARGE;
584 creature_ptr->magic_num1[item] -= EATER_CHARGE;