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"
33 static concptr const kaji_tips[5] = {
35 "現在持っているエッセンスの一覧を表示する。",
36 "アイテムからエッセンスを取り出す。エッセンスを取られたアイテムは全く魔法がかかっていない初期状態に戻る。",
37 "既にエッセンスが付加されたアイテムからエッセンスのみ消し去る。エッセンスは手に入らない。",
38 "アイテムにエッセンスを付加する。既にエッセンスが付加されたアイテムやアーティファクトには付加できない。",
39 "武器や防具を強化したり、攻撃で傷つかないようにしたりする。エッセンスが付加されたアイテムやアーティファクトに対しても使用できる。",
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.",
50 * @brief 所持しているエッセンス一覧を表示する
52 static void display_essence(PlayerType *player_ptr)
54 constexpr auto row_count = 21U;
55 constexpr auto column_width = 22U;
56 constexpr auto essence_num_per_page = row_count * 3;
58 const auto &essences = Smith::get_essence_list();
59 const int page_max = (essences.size() - 1) / (row_count * 3) + 1;
61 Smith smith(player_ptr);
65 for (auto i = 1U; i <= row_count + 1; i++) {
68 prt(_("エッセンス 個数 エッセンス 個数 エッセンス 個数", "Essence Num Essence Num Essence Num "), 1, 8);
70 for (auto num = 0U, ei = page * essence_num_per_page;
71 num < essence_num_per_page && ei < essences.size();
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);
77 prt(format(_("現在所持しているエッセンス %d/%d", "List of all essences you have. %d/%d"), (page + 1), page_max), 0, 0);
98 if (page >= page_max) {
108 * @param player_ptr プレイヤーへの参照ポインタ
110 static void drain_essence(PlayerType *player_ptr)
112 auto q = _("どのアイテムから抽出しますか?", "Extract from which item? ");
113 auto s = _("抽出できるアイテムがありません。", "You have nothing you can extract from.");
116 auto o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), FuncItemTester(&object_type::is_weapon_armour_ammo));
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)))
127 PlayerEnergy(player_ptr).set_player_turn_energy(100);
129 auto drain_result = Smith(player_ptr).drain_essence(o_ptr);
131 if (drain_result.empty()) {
132 msg_print(_("エッセンスは抽出できませんでした。", "You were not able to extract any essence."));
134 msg_print(_("抽出したエッセンス:", "Extracted essences:"));
136 for (const auto &[essence, amount] : drain_result) {
137 auto essence_name = Smith::get_essence_name(essence);
139 msg_format("%s...%d%s", essence_name, amount, _("。", ". "));
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);
150 * @brief 付加するエッセンスの大別を選択する
151 * @return 選んだエッセンスの大別ID
153 static COMMAND_CODE choose_essence(void)
155 COMMAND_CODE mode = 0;
157 COMMAND_CODE menu_line = (use_menu ? 1 : 0);
160 concptr menu_name[] = { "武器属性", "耐性", "能力", "数値", "スレイ", "ESP", "その他", "発動" };
162 concptr menu_name[] = { "Brand weapon", "Resistance", "Ability", "Magic number", "Slay", "ESP", "Others", "Activation" };
164 const COMMAND_CODE mode_max = 8;
166 if (repeat_pull(&mode) && 1 <= mode && mode <= mode_max)
174 for (i = 0; i < mode_max; i++)
176 prt(format(" %s %s", (menu_line == 1 + i) ? "》" : " ", menu_name[i]), 2 + i, 14);
177 prt("どの種類のエッセンス付加を行いますか?", 0, 0);
179 prt(format(" %s %s", (menu_line == 1 + i) ? "> " : " ", menu_name[i]), 2 + i, 14);
180 prt("Choose from menu.", 0, 0);
198 menu_line += mode_max - 1;
207 if (menu_line > mode_max)
208 menu_line -= mode_max;
216 for (i = 0; i < mode_max; i++)
217 prt(format(" %c) %s", 'a' + i, menu_name[i]), 2 + i, 14);
219 if (!get_com(_("何を付加しますか:", "Command :"), &choice, true)) {
225 choice = (char)tolower(choice);
227 if ('a' <= choice && choice <= 'a' + (char)mode_max - 1)
228 mode = (int)choice - 'a' + 1;
238 * @brief 鍛冶効果の一覧を表示する
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 表示する最大行数
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)
250 for (auto y = 1; y < line_max + 2; y++)
254 prt(format(" %-45s %6s/%s", "能力(必要エッセンス)", "所持数", "必要数"), 1, x);
256 prt(format(" %-44s %7s/%s", "Ability (needed essence)", "Possess", "Needs"), 1, x);
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;
264 if (ctr == (menu_line - 1))
265 title << _("》 ", "> ");
270 title << static_cast<char>(I2A(ctr)) << ") ";
273 title << Smith::get_effect_name(effect);
274 title << "(" << Smith::get_need_essences_desc(effect) << ")";
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);
284 snprintf(str, sizeof(str), "%-49s (\?\?)/%d", title.str().c_str(), consumption);
287 auto col = (smith.get_addable_count(effect) > 0) ? TERM_WHITE : TERM_RED;
288 c_prt(col, str, ctr + 2, x);
293 * @brief エッセンスを実際に付加する
294 * @param mode エッセンスの大別ID
296 static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
305 GAME_TEXT o_name[MAX_NLEN];
306 int menu_line = (use_menu ? 1 : 0);
308 Smith smith(player_ptr);
310 auto smith_effect_list = Smith::get_effect_list(mode);
311 const auto smith_effect_list_max = static_cast<int>(smith_effect_list.size());
313 constexpr auto effect_num_per_page = 22;
314 const int page_max = (smith_effect_list.size() - 1) / effect_num_per_page + 1;
317 COMMAND_CODE effect_idx;
319 if (!repeat_pull(&effect_idx) || effect_idx < 0 || effect_idx >= smith_effect_list_max) {
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());
329 strnfmt(out_val, 78, _("(ESCで中断) どの能力を付加しますか?", "(ESC=exit) Add which ability? "));
332 display_smith_effect_list(smith, smith_effect_list, menu_line, page * effect_num_per_page, effect_num_per_page);
334 const auto page_effect_num = std::min<int>(effect_num_per_page, smith_effect_list.size() - (page * effect_num_per_page));
336 if (!get_com(out_val, &choice, false))
349 menu_line += (page_effect_num - 1);
363 page += (page_max - 1);
386 if (menu_line > page_effect_num)
387 menu_line -= page_effect_num;
391 if ((choice == ' ') || (use_menu && ask)) {
395 if (page >= page_max) {
405 ask = (isupper(choice));
409 choice = (char)tolower(choice);
411 /* Extract request */
412 i = (islower(choice) ? A2I(choice) : -1);
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) {
427 (void)strnfmt(tmp_val, 78, _("%sを付加しますか? ", "Add the ability of %s? "), Smith::get_effect_name(smith_effect_list[i]));
429 /* Belay that order */
430 if (!get_check(tmp_val))
443 repeat_push(effect_idx);
446 auto effect = smith_effect_list[effect_idx];
448 auto item_tester = Smith::get_item_tester(effect);
450 q = _("どのアイテムを改良しますか?", "Improve which item? ");
451 s = _("改良できるアイテムがありません。", "You have nothing to improve.");
453 o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
457 describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
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);
464 if (smith.get_addable_count(effect, o_ptr) == 0) {
465 msg_print(_("エッセンスが足りない。", "You don't have enough essences."));
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."));
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? "))) {
480 } else if (o_ptr->pval == 0) {
483 auto limit = std::min(5, smith.get_addable_count(effect, o_ptr));
485 sprintf(tmp, _("いくつ付加しますか? (1-%d): ", "Enchant how many? (1-%d): "), limit);
486 strcpy(tmp_val, "1");
488 if (!get_string(tmp, tmp_val, 1))
490 o_ptr->pval = static_cast<PARAMETER_VALUE>(std::clamp(atoi(tmp_val), 1, limit));
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)) {
500 add_essence_count = std::clamp(atoi(tmp_val), 1, max_val);
503 msg_format(_("エッセンスを%d個使用します。", "It will take %d essences."), use_essence * add_essence_count);
505 if (smith.get_addable_count(effect, o_ptr) < add_essence_count) {
506 msg_print(_("エッセンスが足りない。", "You don't have enough essences."));
510 PlayerEnergy(player_ptr).set_player_turn_energy(100);
512 if (!smith.add_essence(effect, o_ptr, add_essence_count)) {
513 msg_print(_("改良に失敗した。", "You failed to enchant."));
517 auto effect_name = Smith::get_effect_name(effect);
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);
527 static void erase_essence(PlayerType *player_ptr)
532 GAME_TEXT o_name[MAX_NLEN];
534 q = _("どのアイテムのエッセンスを消去しますか?", "Remove from which item? ");
535 s = _("エッセンスを付加したアイテムがありません。", "You have nothing with added essence to remove.");
537 o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&object_type::is_smith));
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)))
545 PlayerEnergy(player_ptr).set_player_turn_energy(100);
547 Smith(player_ptr).erase_essence(o_ptr);
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);
555 * @brief 鍛冶コマンドのメインルーチン
556 * @param only_browse TRUEならばエッセンス一覧の表示のみを行う
558 void do_cmd_kaji(PlayerType *player_ptr, bool only_browse)
560 COMMAND_CODE mode = 0;
563 COMMAND_CODE menu_line = (use_menu ? 1 : 0);
566 if (cmd_limit_confused(player_ptr))
568 if (cmd_limit_blind(player_ptr))
570 if (cmd_limit_image(player_ptr))
574 if (!(repeat_pull(&mode) && 1 <= mode && mode <= 5)) {
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);
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);
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);
634 if (!get_com(format("どの能力を%sますか:", only_browse ? "調べ" : "使い"), &choice, true))
636 if (!get_com("Command :", &choice, true))
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);
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);
688 } while (only_browse);
693 display_essence(player_ptr);
696 drain_essence(player_ptr);
699 erase_essence(player_ptr);
702 mode = choose_essence();
705 add_essence(player_ptr, i2enum<SmithCategoryType>(mode));
708 add_essence(player_ptr, SmithCategoryType::ENCHANT);