OSDN Git Service

[Fix] #1727 忍者の変わり身が意図せず発動する事象を修正した / Resolved the issue that the ninja's kawarimi...
[hengbandforosx/hengbandosx.git] / src / mind / mind-weaponsmith.cpp
1 #include "mind/mind-weaponsmith.h"
2 #include "action/action-limited.h"
3 #include "autopick/autopick.h"
4 #include "core/asking-player.h"
5 #include "core/player-update-types.h"
6 #include "core/window-redrawer.h"
7 #include "flavor/flavor-describer.h"
8 #include "flavor/object-flavor-types.h"
9 #include "floor/floor-object.h"
10 #include "game-option/text-display-options.h"
11 #include "io/command-repeater.h"
12 #include "io/input-key-acceptor.h"
13 #include "io/input-key-requester.h"
14 #include "main/sound-of-music.h"
15 #include "mind/mind-weaponsmith.h"
16 #include "object-enchant/object-smith.h"
17 #include "object-enchant/smith-types.h"
18 #include "object-enchant/tr-types.h"
19 #include "object/item-tester-hooker.h"
20 #include "object/item-use-flags.h"
21 #include "player-status/player-energy.h"
22 #include "system/object-type-definition.h"
23 #include "system/player-type-definition.h"
24 #include "term/screen-processor.h"
25 #include "term/term-color-types.h"
26 #include "util/bit-flags-calculator.h"
27 #include "util/buffer-shaper.h"
28 #include "util/int-char-converter.h"
29 #include "view/display-messages.h"
30
31 #include <algorithm>
32 #include <sstream>
33
34 static concptr const kaji_tips[5] = {
35 #ifdef JP
36     "現在持っているエッセンスの一覧を表示する。",
37     "アイテムからエッセンスを取り出す。エッセンスを取られたアイテムは全く魔法がかかっていない初期状態に戻る。",
38     "既にエッセンスが付加されたアイテムからエッセンスのみ消し去る。エッセンスは手に入らない。",
39     "アイテムにエッセンスを付加する。既にエッセンスが付加されたアイテムやアーティファクトには付加できない。",
40     "武器や防具を強化したり、攻撃で傷つかないようにしたりする。エッセンスが付加されたアイテムやアーティファクトに対しても使用できる。",
41 #else
42     "Display essences you have.",
43     "Extract essences from an item. The item become non magical.",
44     "Remove added essences from equipment which was improved before. The removed essence will be ruined.",
45     "Add essences to an item. The improved items or artifacts cannot be reimprove.",
46     "Enchant an item or make an item element-proofed. Improved items and artifacts can be enchanted too.",
47 #endif
48 };
49
50 /*!
51  * @brief 所持しているエッセンス一覧を表示する
52  */
53 static void display_essence(player_type *player_ptr)
54 {
55     constexpr auto row_count = 21U;
56     constexpr auto column_width = 22U;
57     constexpr auto essence_num_per_page = row_count * 3;
58     int page = 0;
59     const auto &essences = Smith::get_essence_list();
60     const int page_max = (essences.size() - 1) / (row_count * 3) + 1;
61
62     Smith smith(player_ptr);
63
64     screen_save();
65     while (true) {
66         for (auto i = 1U; i <= row_count + 1; i++) {
67             prt("", i, 0);
68         }
69         prt(_("エッセンス   個数     エッセンス   個数     エッセンス   個数", "Essence      Num      Essence      Num      Essence      Num "), 1, 8);
70
71         for (auto num = 0U, ei = page * essence_num_per_page;
72              num < essence_num_per_page && ei < essences.size();
73              ++num, ++ei) {
74             auto name = Smith::get_essence_name(essences[ei]);
75             auto amount = smith.get_essence_num_of_posessions(essences[ei]);
76             prt(format("%-11s %5d", name, amount), 2 + num % row_count, 8 + (num / row_count) * column_width);
77         }
78         prt(format(_("現在所持しているエッセンス %d/%d", "List of all essences you have. %d/%d"), (page + 1), page_max), 0, 0);
79
80         auto key = inkey();
81         if (key == ESCAPE) {
82             break;
83         }
84
85         switch (key) {
86         case ' ':
87             page++;
88             break;
89         case '-':
90             page--;
91             break;
92         default:
93             bell();
94             break;
95         }
96         if (page < 0) {
97             page = page_max - 1;
98         }
99         if (page >= page_max) {
100             page = 0;
101         }
102     }
103     screen_load();
104     return;
105 }
106
107 /*!
108  * @brief エッセンスの抽出処理
109  * @param player_ptr プレイヤーへの参照ポインタ
110  */
111 static void drain_essence(player_type *player_ptr)
112 {
113     auto q = _("どのアイテムから抽出しますか?", "Extract from which item? ");
114     auto s = _("抽出できるアイテムがありません。", "You have nothing you can extract from.");
115
116     OBJECT_IDX item;
117     auto o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), FuncItemTester(&object_type::is_weapon_armour_ammo));
118     if (!o_ptr)
119         return;
120
121     if (o_ptr->is_known() && !o_ptr->is_nameless()) {
122         GAME_TEXT o_name[MAX_NLEN];
123         describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
124         if (!get_check(format(_("本当に%sから抽出してよろしいですか?", "Really extract from %s? "), o_name)))
125             return;
126     }
127
128     PlayerEnergy(player_ptr).set_player_turn_energy(100);
129
130     auto drain_result = Smith(player_ptr).drain_essence(o_ptr);
131
132     if (drain_result.empty()) {
133         msg_print(_("エッセンスは抽出できませんでした。", "You were not able to extract any essence."));
134     } else {
135         msg_print(_("抽出したエッセンス:", "Extracted essences:"));
136
137         for (const auto &[essence, amount] : drain_result) {
138             auto essence_name = Smith::get_essence_name(essence);
139             msg_print(nullptr);
140             msg_format("%s...%d%s", essence_name, amount, _("。", ". "));
141         }
142     }
143
144     /* Apply autodestroy/inscription to the drained item */
145     autopick_alter_item(player_ptr, item, true);
146     player_ptr->update |= (PU_COMBINE | PU_REORDER);
147     player_ptr->window_flags |= (PW_INVEN);
148 }
149
150 /*!
151  * @brief 付加するエッセンスの大別を選択する
152  * @return 選んだエッセンスの大別ID
153  */
154 static COMMAND_CODE choose_essence(void)
155 {
156     COMMAND_CODE mode = 0;
157     char choice;
158     COMMAND_CODE menu_line = (use_menu ? 1 : 0);
159
160 #ifdef JP
161     concptr menu_name[] = { "武器属性", "耐性", "能力", "数値", "スレイ", "ESP", "その他", "発動" };
162 #else
163     concptr menu_name[] = { "Brand weapon", "Resistance", "Ability", "Magic number", "Slay", "ESP", "Others", "Activation" };
164 #endif
165     const COMMAND_CODE mode_max = 8;
166
167     if (repeat_pull(&mode) && 1 <= mode && mode <= mode_max)
168         return mode;
169     mode = 0;
170     if (use_menu) {
171         screen_save();
172
173         while (!mode) {
174             int i;
175             for (i = 0; i < mode_max; i++)
176 #ifdef JP
177                 prt(format(" %s %s", (menu_line == 1 + i) ? "》" : "  ", menu_name[i]), 2 + i, 14);
178             prt("どの種類のエッセンス付加を行いますか?", 0, 0);
179 #else
180                 prt(format(" %s %s", (menu_line == 1 + i) ? "> " : "  ", menu_name[i]), 2 + i, 14);
181             prt("Choose from menu.", 0, 0);
182 #endif
183
184             choice = inkey();
185             switch (choice) {
186             case ESCAPE:
187             case 'z':
188             case 'Z':
189                 screen_load();
190                 return 0;
191             case '2':
192             case 'j':
193             case 'J':
194                 menu_line++;
195                 break;
196             case '8':
197             case 'k':
198             case 'K':
199                 menu_line += mode_max - 1;
200                 break;
201             case '\r':
202             case '\n':
203             case 'x':
204             case 'X':
205                 mode = menu_line;
206                 break;
207             }
208             if (menu_line > mode_max)
209                 menu_line -= mode_max;
210         }
211         screen_load();
212     } else {
213         screen_save();
214         while (!mode) {
215             int i;
216
217             for (i = 0; i < mode_max; i++)
218                 prt(format("  %c) %s", 'a' + i, menu_name[i]), 2 + i, 14);
219
220             if (!get_com(_("何を付加しますか:", "Command :"), &choice, true)) {
221                 screen_load();
222                 return 0;
223             }
224
225             if (isupper(choice))
226                 choice = (char)tolower(choice);
227
228             if ('a' <= choice && choice <= 'a' + (char)mode_max - 1)
229                 mode = (int)choice - 'a' + 1;
230         }
231         screen_load();
232     }
233
234     repeat_push(mode);
235     return mode;
236 }
237
238 /**
239  * @brief 鍛冶効果の一覧を表示する
240  *
241  * @param smith 鍛冶情報を得るのに使用するSmithクラスのオブジェクトの参照
242  * @param smith_effect_list 表示する鍛冶効果のリスト
243  * @param menu_line use_menuがtrueの時にカーソルを表示する行番号
244  * @param start_idx smith_effect_list の表示開始インデックス
245  * @param line_max 表示する最大行数
246  */
247 static void display_smith_effect_list(const Smith &smith, const std::vector<SmithEffect> &smith_effect_list, int menu_line, int start_idx, int line_max)
248 {
249     auto x = 10;
250
251     for (auto y = 1; y < line_max + 2; y++)
252         prt("", y, x);
253
254 #ifdef JP
255     prt(format("   %-45s %6s/%s", "能力(必要エッセンス)", "所持数", "必要数"), 1, x);
256 #else
257     prt(format("   %-44s %7s/%s", "Ability (needed essence)", "Possess", "Needs"), 1, x);
258 #endif
259
260     for (int ctr = 0U, ei = start_idx; ctr < line_max && ei < static_cast<int>(smith_effect_list.size()); ++ctr, ++ei) {
261         auto effect = smith_effect_list[ei];
262         std::stringstream title;
263
264         if (use_menu) {
265             if (ctr == (menu_line - 1))
266                 title << _("》 ", ">  ");
267             else
268                 title << "   ";
269
270         } else {
271             title << static_cast<char>(I2A(ctr)) << ") ";
272         }
273
274         title << Smith::get_effect_name(effect);
275         title << "(" << Smith::get_need_essences_desc(effect) << ")";
276
277         char str[160];
278         auto consumption = Smith::get_essence_consumption(effect);
279         auto need_essences = Smith::get_need_essences(effect);
280         if (need_essences.size() == 1) {
281             auto essence = need_essences.front();
282             auto amount = smith.get_essence_num_of_posessions(essence);
283             snprintf(str, sizeof(str), "%-49s %5d/%d", title.str().c_str(), amount, consumption);
284         } else {
285             snprintf(str, sizeof(str), "%-49s  (\?\?)/%d", title.str().c_str(), consumption);
286         }
287
288         auto col = (smith.get_addable_count(effect) > 0) ? TERM_WHITE : TERM_RED;
289         c_prt(col, str, ctr + 2, x);
290     }
291 }
292
293 /*!
294  * @brief エッセンスを実際に付加する
295  * @param mode エッセンスの大別ID
296  */
297 static void add_essence(player_type *player_ptr, SmithCategory mode)
298 {
299     OBJECT_IDX item;
300     bool flag;
301     char choice;
302     concptr q, s;
303     object_type *o_ptr;
304     int ask = true;
305     char out_val[160];
306     GAME_TEXT o_name[MAX_NLEN];
307     int menu_line = (use_menu ? 1 : 0);
308
309     Smith smith(player_ptr);
310
311     auto smith_effect_list = Smith::get_effect_list(mode);
312     const auto smith_effect_list_max = static_cast<int>(smith_effect_list.size());
313     auto page = 0;
314     constexpr auto effect_num_per_page = 22;
315     const int page_max = (smith_effect_list.size() - 1) / effect_num_per_page + 1;
316
317     COMMAND_CODE i = -1;
318     COMMAND_CODE effect_idx;
319
320     if (!repeat_pull(&effect_idx) || effect_idx < 0 || effect_idx >= smith_effect_list_max) {
321         flag = false;
322
323         screen_save();
324
325         while (!flag) {
326             if (page_max > 1) {
327                 std::string page_str = format("%d/%d", page + 1, page_max);
328                 strnfmt(out_val, 78, _("(SPACEで次ページ, ESCで中断) どの能力を付加しますか? %s", "(SPACE=next, ESC=exit) Add which ability? %s"), page_str.c_str());
329             } else {
330                 strnfmt(out_val, 78, _("(ESCで中断) どの能力を付加しますか?", "(ESC=exit) Add which ability? "));
331             }
332
333             display_smith_effect_list(smith, smith_effect_list, menu_line, page * effect_num_per_page, effect_num_per_page);
334
335             const auto page_effect_num = std::min<int>(effect_num_per_page, smith_effect_list.size() - (page * effect_num_per_page));
336
337             if (!get_com(out_val, &choice, false))
338                 break;
339
340             if (use_menu) {
341                 switch (choice) {
342                 case '0': {
343                     screen_load();
344                     return;
345                 }
346
347                 case '8':
348                 case 'k':
349                 case 'K': {
350                     menu_line += (page_effect_num - 1);
351                     break;
352                 }
353
354                 case '2':
355                 case 'j':
356                 case 'J': {
357                     menu_line++;
358                     break;
359                 }
360
361                 case '4':
362                 case 'h':
363                 case 'H': {
364                     page += (page_max - 1);
365                     menu_line = 1;
366                     break;
367                 }
368                 case '6':
369                 case 'l':
370                 case 'L':
371                 case ' ': {
372                     page++;
373                     menu_line = 1;
374                     break;
375                 }
376
377                 case 'x':
378                 case 'X':
379                 case '\r':
380                 case '\n': {
381                     i = menu_line - 1;
382                     ask = false;
383                     break;
384                 }
385                 }
386
387                 if (menu_line > page_effect_num)
388                     menu_line -= page_effect_num;
389             }
390
391             /* Request redraw */
392             if ((choice == ' ') || (use_menu && ask)) {
393                 if (!use_menu) {
394                     page++;
395                 }
396                 if (page >= page_max) {
397                     page = 0;
398                 }
399
400                 /* Redo asking */
401                 continue;
402             }
403
404             if (!use_menu) {
405                 /* Note verify */
406                 ask = (isupper(choice));
407
408                 /* Lowercase */
409                 if (ask)
410                     choice = (char)tolower(choice);
411
412                 /* Extract request */
413                 i = (islower(choice) ? A2I(choice) : -1);
414             }
415
416             effect_idx = page * effect_num_per_page + i;
417             /* Totally Illegal */
418             if ((effect_idx < 0) || (effect_idx >= smith_effect_list_max) || smith.get_addable_count(smith_effect_list[effect_idx]) <= 0) {
419                 bell();
420                 continue;
421             }
422
423             /* Verify it */
424             if (ask) {
425                 char tmp_val[160];
426
427                 /* Prompt */
428                 (void)strnfmt(tmp_val, 78, _("%sを付加しますか? ", "Add the ability of %s? "), Smith::get_effect_name(smith_effect_list[i]));
429
430                 /* Belay that order */
431                 if (!get_check(tmp_val))
432                     continue;
433             }
434
435             /* Stop the loop */
436             flag = true;
437         }
438
439         screen_load();
440
441         if (!flag)
442             return;
443
444         repeat_push(effect_idx);
445     }
446
447     auto effect = smith_effect_list[effect_idx];
448
449     auto item_tester = Smith::get_item_tester(effect);
450
451     q = _("どのアイテムを改良しますか?", "Improve which item? ");
452     s = _("改良できるアイテムがありません。", "You have nothing to improve.");
453
454     o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
455     if (!o_ptr)
456         return;
457
458     describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
459
460     const auto use_essence = Smith::get_essence_consumption(effect, o_ptr);
461     if (o_ptr->number > 1) {
462         msg_format(_("%d個あるのでエッセンスは%d必要です。", "For %d items, it will take %d essences."), o_ptr->number, use_essence);
463     }
464
465     if (smith.get_addable_count(effect, o_ptr) == 0) {
466         msg_print(_("エッセンスが足りない。", "You don't have enough essences."));
467         return;
468     }
469
470     const auto effect_flags = Smith::get_effect_tr_flags(effect);
471     auto add_essence_count = 1;
472     if (effect_flags.has_any_of(TR_PVAL_FLAG_MASK)) {
473         if (o_ptr->pval < 0) {
474             msg_print(_("このアイテムの能力修正を強化することはできない。", "You cannot increase magic number of this item."));
475             return;
476         } else if (effect_flags.has(TR_BLOWS)) {
477             if ((o_ptr->pval > 1) && !get_check(_("修正値は1になります。よろしいですか?", "The magic number of this weapon will become 1. Are you sure? "))) {
478                 return;
479             }
480             o_ptr->pval = 1;
481         } else if (o_ptr->pval == 0) {
482             char tmp[80];
483             char tmp_val[8];
484             auto limit = std::min(5, smith.get_addable_count(effect, o_ptr));
485
486             sprintf(tmp, _("いくつ付加しますか? (1-%d): ", "Enchant how many? (1-%d): "), limit);
487             strcpy(tmp_val, "1");
488
489             if (!get_string(tmp, tmp_val, 1))
490                 return;
491             o_ptr->pval = static_cast<PARAMETER_VALUE>(std::clamp(atoi(tmp_val), 1, limit));
492         }
493
494         add_essence_count = o_ptr->pval;
495     } else if (effect == SmithEffect::SLAY_GLOVE) {
496         char tmp_val[8] = "1";
497         const auto max_val = player_ptr->lev / 7 + 3;
498         if (!get_string(format(_("いくつ付加しますか? (1-%d):", "Enchant how many? (1-%d):"), max_val), tmp_val, 2)) {
499             return;
500         }
501         add_essence_count = std::clamp(atoi(tmp_val), 1, max_val);
502     }
503
504     msg_format(_("エッセンスを%d個使用します。", "It will take %d essences."), use_essence * add_essence_count);
505
506     if (smith.get_addable_count(effect, o_ptr) < add_essence_count) {
507         msg_print(_("エッセンスが足りない。", "You don't have enough essences."));
508         return;
509     }
510
511     PlayerEnergy(player_ptr).set_player_turn_energy(100);
512
513     if (!smith.add_essence(effect, o_ptr, add_essence_count)) {
514         msg_print(_("改良に失敗した。", "You failed to enchant."));
515         return;
516     }
517
518     auto effect_name = Smith::get_effect_name(effect);
519
520     _(msg_format("%sに%sの能力を付加しました。", o_name, effect_name), msg_format("You have added ability of %s to %s.", effect_name, o_name));
521     player_ptr->update |= (PU_COMBINE | PU_REORDER);
522     player_ptr->window_flags |= (PW_INVEN);
523 }
524
525 /*!
526  * @brief エッセンスを消去する
527  */
528 static void erase_essence(player_type *player_ptr)
529 {
530     OBJECT_IDX item;
531     concptr q, s;
532     object_type *o_ptr;
533     GAME_TEXT o_name[MAX_NLEN];
534
535     q = _("どのアイテムのエッセンスを消去しますか?", "Remove from which item? ");
536     s = _("エッセンスを付加したアイテムがありません。", "You have nothing with added essence to remove.");
537
538     o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&object_type::is_smith));
539     if (!o_ptr)
540         return;
541
542     describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
543     if (!get_check(format(_("よろしいですか? [%s]", "Are you sure? [%s]"), o_name)))
544         return;
545
546     PlayerEnergy(player_ptr).set_player_turn_energy(100);
547
548     Smith(player_ptr).erase_essence(o_ptr);
549
550     msg_print(_("エッセンスを取り去った。", "You removed all essence you have added."));
551     player_ptr->update |= (PU_COMBINE | PU_REORDER);
552     player_ptr->window_flags |= (PW_INVEN);
553 }
554
555 /*!
556  * @brief 鍛冶コマンドのメインルーチン
557  * @param only_browse TRUEならばエッセンス一覧の表示のみを行う
558  */
559 void do_cmd_kaji(player_type *player_ptr, bool only_browse)
560 {
561     COMMAND_CODE mode = 0;
562     char choice;
563
564     COMMAND_CODE menu_line = (use_menu ? 1 : 0);
565
566     if (!only_browse) {
567         if (cmd_limit_confused(player_ptr))
568             return;
569         if (cmd_limit_blind(player_ptr))
570             return;
571         if (cmd_limit_image(player_ptr))
572             return;
573     }
574
575     if (!(repeat_pull(&mode) && 1 <= mode && mode <= 5)) {
576         if (only_browse)
577             screen_save();
578         do {
579             if (!only_browse)
580                 screen_save();
581             if (use_menu) {
582                 while (!mode) {
583 #ifdef JP
584                     prt(format(" %s エッセンス一覧", (menu_line == 1) ? "》" : "  "), 2, 14);
585                     prt(format(" %s エッセンス抽出", (menu_line == 2) ? "》" : "  "), 3, 14);
586                     prt(format(" %s エッセンス消去", (menu_line == 3) ? "》" : "  "), 4, 14);
587                     prt(format(" %s エッセンス付加", (menu_line == 4) ? "》" : "  "), 5, 14);
588                     prt(format(" %s 武器/防具強化", (menu_line == 5) ? "》" : "  "), 6, 14);
589                     prt(format("どの種類の技術を%sますか?", only_browse ? "調べ" : "使い"), 0, 0);
590 #else
591                     prt(format(" %s List essences", (menu_line == 1) ? "> " : "  "), 2, 14);
592                     prt(format(" %s Extract essence", (menu_line == 2) ? "> " : "  "), 3, 14);
593                     prt(format(" %s Remove essence", (menu_line == 3) ? "> " : "  "), 4, 14);
594                     prt(format(" %s Add essence", (menu_line == 4) ? "> " : "  "), 5, 14);
595                     prt(format(" %s Enchant weapon/armor", (menu_line == 5) ? "> " : "  "), 6, 14);
596                     prt(format("Choose command from menu."), 0, 0);
597 #endif
598                     choice = inkey();
599                     switch (choice) {
600                     case ESCAPE:
601                     case 'z':
602                     case 'Z':
603                         screen_load();
604                         return;
605                     case '2':
606                     case 'j':
607                     case 'J':
608                         menu_line++;
609                         break;
610                     case '8':
611                     case 'k':
612                     case 'K':
613                         menu_line += 4;
614                         break;
615                     case '\r':
616                     case '\n':
617                     case 'x':
618                     case 'X':
619                         mode = menu_line;
620                         break;
621                     }
622                     if (menu_line > 5)
623                         menu_line -= 5;
624                 }
625             }
626
627             else {
628                 while (!mode) {
629                     prt(_("  a) エッセンス一覧", "  a) List essences"), 2, 14);
630                     prt(_("  b) エッセンス抽出", "  b) Extract essence"), 3, 14);
631                     prt(_("  c) エッセンス消去", "  c) Remove essence"), 4, 14);
632                     prt(_("  d) エッセンス付加", "  d) Add essence"), 5, 14);
633                     prt(_("  e) 武器/防具強化", "  e) Enchant weapon/armor"), 6, 14);
634 #ifdef JP
635                     if (!get_com(format("どの能力を%sますか:", only_browse ? "調べ" : "使い"), &choice, true))
636 #else
637                     if (!get_com("Command :", &choice, true))
638 #endif
639                     {
640                         screen_load();
641                         return;
642                     }
643                     switch (choice) {
644                     case 'A':
645                     case 'a':
646                         mode = 1;
647                         break;
648                     case 'B':
649                     case 'b':
650                         mode = 2;
651                         break;
652                     case 'C':
653                     case 'c':
654                         mode = 3;
655                         break;
656                     case 'D':
657                     case 'd':
658                         mode = 4;
659                         break;
660                     case 'E':
661                     case 'e':
662                         mode = 5;
663                         break;
664                     }
665                 }
666             }
667
668             if (only_browse) {
669                 char temp[62 * 5];
670                 int line, j;
671
672                 /* Clear lines, position cursor  (really should use strlen here) */
673                 term_erase(14, 21, 255);
674                 term_erase(14, 20, 255);
675                 term_erase(14, 19, 255);
676                 term_erase(14, 18, 255);
677                 term_erase(14, 17, 255);
678                 term_erase(14, 16, 255);
679
680                 shape_buffer(kaji_tips[mode - 1], 62, temp, sizeof(temp));
681                 for (j = 0, line = 17; temp[j]; j += (1 + strlen(&temp[j]))) {
682                     prt(&temp[j], line, 15);
683                     line++;
684                 }
685                 mode = 0;
686             }
687             if (!only_browse)
688                 screen_load();
689         } while (only_browse);
690         repeat_push(mode);
691     }
692     switch (mode) {
693     case 1:
694         display_essence(player_ptr);
695         break;
696     case 2:
697         drain_essence(player_ptr);
698         break;
699     case 3:
700         erase_essence(player_ptr);
701         break;
702     case 4:
703         mode = choose_essence();
704         if (mode == 0)
705             break;
706         add_essence(player_ptr, i2enum<SmithCategory>(mode));
707         break;
708     case 5:
709         add_essence(player_ptr, SmithCategory::ENCHANT);
710         break;
711     }
712 }