OSDN Git Service

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