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"
34 static concptr const kaji_tips[5] = {
36 "現在持っているエッセンスの一覧を表示する。",
37 "アイテムからエッセンスを取り出す。エッセンスを取られたアイテムは全く魔法がかかっていない初期状態に戻る。",
38 "既にエッセンスが付加されたアイテムからエッセンスのみ消し去る。エッセンスは手に入らない。",
39 "アイテムにエッセンスを付加する。既にエッセンスが付加されたアイテムやアーティファクトには付加できない。",
40 "武器や防具を強化したり、攻撃で傷つかないようにしたりする。エッセンスが付加されたアイテムやアーティファクトに対しても使用できる。",
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.",
51 * @brief 所持しているエッセンス一覧を表示する
53 static void display_essence(player_type *player_ptr)
55 constexpr auto row_count = 21U;
56 constexpr auto column_width = 22U;
57 constexpr auto essence_num_per_page = row_count * 3;
59 const auto &essences = Smith::get_essence_list();
60 const int page_max = (essences.size() - 1) / (row_count * 3) + 1;
62 Smith smith(player_ptr);
66 for (auto i = 1U; i <= row_count + 1; i++) {
69 prt(_("エッセンス 個数 エッセンス 個数 エッセンス 個数", "Essence Num Essence Num Essence Num "), 1, 8);
71 for (auto num = 0U, ei = page * essence_num_per_page;
72 num < essence_num_per_page && ei < essences.size();
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);
78 prt(format(_("現在所持しているエッセンス %d/%d", "List of all essences you have. %d/%d"), (page + 1), page_max), 0, 0);
99 if (page >= page_max) {
109 * @param player_ptr プレイヤーへの参照ポインタ
111 static void drain_essence(player_type *player_ptr)
113 auto q = _("どのアイテムから抽出しますか?", "Extract from which item? ");
114 auto s = _("抽出できるアイテムがありません。", "You have nothing you can extract from.");
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));
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)))
128 PlayerEnergy(player_ptr).set_player_turn_energy(100);
130 auto drain_result = Smith(player_ptr).drain_essence(o_ptr);
132 if (drain_result.empty()) {
133 msg_print(_("エッセンスは抽出できませんでした。", "You were not able to extract any essence."));
135 msg_print(_("抽出したエッセンス:", "Extracted essences:"));
137 for (const auto &[essence, amount] : drain_result) {
138 auto essence_name = Smith::get_essence_name(essence);
140 msg_format("%s...%d%s", essence_name, amount, _("。", ". "));
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);
151 * @brief 付加するエッセンスの大別を選択する
152 * @return 選んだエッセンスの大別ID
154 static COMMAND_CODE choose_essence(void)
156 COMMAND_CODE mode = 0;
158 COMMAND_CODE menu_line = (use_menu ? 1 : 0);
161 concptr menu_name[] = { "武器属性", "耐性", "能力", "数値", "スレイ", "ESP", "その他", "発動" };
163 concptr menu_name[] = { "Brand weapon", "Resistance", "Ability", "Magic number", "Slay", "ESP", "Others", "Activation" };
165 const COMMAND_CODE mode_max = 8;
167 if (repeat_pull(&mode) && 1 <= mode && mode <= mode_max)
175 for (i = 0; i < mode_max; i++)
177 prt(format(" %s %s", (menu_line == 1 + i) ? "》" : " ", menu_name[i]), 2 + i, 14);
178 prt("どの種類のエッセンス付加を行いますか?", 0, 0);
180 prt(format(" %s %s", (menu_line == 1 + i) ? "> " : " ", menu_name[i]), 2 + i, 14);
181 prt("Choose from menu.", 0, 0);
199 menu_line += mode_max - 1;
208 if (menu_line > mode_max)
209 menu_line -= mode_max;
217 for (i = 0; i < mode_max; i++)
218 prt(format(" %c) %s", 'a' + i, menu_name[i]), 2 + i, 14);
220 if (!get_com(_("何を付加しますか:", "Command :"), &choice, true)) {
226 choice = (char)tolower(choice);
228 if ('a' <= choice && choice <= 'a' + (char)mode_max - 1)
229 mode = (int)choice - 'a' + 1;
239 * @brief 鍛冶効果の一覧を表示する
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 表示する最大行数
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)
251 for (auto y = 1; y < line_max + 2; y++)
255 prt(format(" %-45s %6s/%s", "能力(必要エッセンス)", "所持数", "必要数"), 1, x);
257 prt(format(" %-44s %7s/%s", "Ability (needed essence)", "Possess", "Needs"), 1, x);
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;
265 if (ctr == (menu_line - 1))
266 title << _("》 ", "> ");
271 title << static_cast<char>(I2A(ctr)) << ") ";
274 title << Smith::get_effect_name(effect);
275 title << "(" << Smith::get_need_essences_desc(effect) << ")";
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);
285 snprintf(str, sizeof(str), "%-49s (\?\?)/%d", title.str().c_str(), consumption);
288 auto col = (smith.get_addable_count(effect) > 0) ? TERM_WHITE : TERM_RED;
289 c_prt(col, str, ctr + 2, x);
294 * @brief エッセンスを実際に付加する
295 * @param mode エッセンスの大別ID
297 static void add_essence(player_type *player_ptr, SmithCategory mode)
306 GAME_TEXT o_name[MAX_NLEN];
307 int menu_line = (use_menu ? 1 : 0);
309 Smith smith(player_ptr);
311 auto smith_effect_list = Smith::get_effect_list(mode);
312 const auto smith_effect_list_max = static_cast<int>(smith_effect_list.size());
314 constexpr auto effect_num_per_page = 22;
315 const int page_max = (smith_effect_list.size() - 1) / effect_num_per_page + 1;
318 COMMAND_CODE effect_idx;
320 if (!repeat_pull(&effect_idx) || effect_idx < 0 || effect_idx >= smith_effect_list_max) {
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());
330 strnfmt(out_val, 78, _("(ESCで中断) どの能力を付加しますか?", "(ESC=exit) Add which ability? "));
333 display_smith_effect_list(smith, smith_effect_list, menu_line, page * effect_num_per_page, effect_num_per_page);
335 const auto page_effect_num = std::min<int>(effect_num_per_page, smith_effect_list.size() - (page * effect_num_per_page));
337 if (!get_com(out_val, &choice, false))
350 menu_line += (page_effect_num - 1);
364 page += (page_max - 1);
387 if (menu_line > page_effect_num)
388 menu_line -= page_effect_num;
392 if ((choice == ' ') || (use_menu && ask)) {
396 if (page >= page_max) {
406 ask = (isupper(choice));
410 choice = (char)tolower(choice);
412 /* Extract request */
413 i = (islower(choice) ? A2I(choice) : -1);
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) {
428 (void)strnfmt(tmp_val, 78, _("%sを付加しますか? ", "Add the ability of %s? "), Smith::get_effect_name(smith_effect_list[i]));
430 /* Belay that order */
431 if (!get_check(tmp_val))
444 repeat_push(effect_idx);
447 auto effect = smith_effect_list[effect_idx];
449 auto item_tester = Smith::get_item_tester(effect);
451 q = _("どのアイテムを改良しますか?", "Improve which item? ");
452 s = _("改良できるアイテムがありません。", "You have nothing to improve.");
454 o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
458 describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
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);
465 if (smith.get_addable_count(effect, o_ptr) == 0) {
466 msg_print(_("エッセンスが足りない。", "You don't have enough essences."));
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."));
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? "))) {
481 } else if (o_ptr->pval == 0) {
484 auto limit = std::min(5, smith.get_addable_count(effect, o_ptr));
486 sprintf(tmp, _("いくつ付加しますか? (1-%d): ", "Enchant how many? (1-%d): "), limit);
487 strcpy(tmp_val, "1");
489 if (!get_string(tmp, tmp_val, 1))
491 o_ptr->pval = static_cast<PARAMETER_VALUE>(std::clamp(atoi(tmp_val), 1, limit));
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)) {
501 add_essence_count = std::clamp(atoi(tmp_val), 1, max_val);
504 msg_format(_("エッセンスを%d個使用します。", "It will take %d essences."), use_essence * add_essence_count);
506 if (smith.get_addable_count(effect, o_ptr) < add_essence_count) {
507 msg_print(_("エッセンスが足りない。", "You don't have enough essences."));
511 PlayerEnergy(player_ptr).set_player_turn_energy(100);
513 if (!smith.add_essence(effect, o_ptr, add_essence_count)) {
514 msg_print(_("改良に失敗した。", "You failed to enchant."));
518 auto effect_name = Smith::get_effect_name(effect);
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);
528 static void erase_essence(player_type *player_ptr)
533 GAME_TEXT o_name[MAX_NLEN];
535 q = _("どのアイテムのエッセンスを消去しますか?", "Remove from which item? ");
536 s = _("エッセンスを付加したアイテムがありません。", "You have nothing with added essence to remove.");
538 o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&object_type::is_smith));
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)))
546 PlayerEnergy(player_ptr).set_player_turn_energy(100);
548 Smith(player_ptr).erase_essence(o_ptr);
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);
556 * @brief 鍛冶コマンドのメインルーチン
557 * @param only_browse TRUEならばエッセンス一覧の表示のみを行う
559 void do_cmd_kaji(player_type *player_ptr, bool only_browse)
561 COMMAND_CODE mode = 0;
564 COMMAND_CODE menu_line = (use_menu ? 1 : 0);
567 if (cmd_limit_confused(player_ptr))
569 if (cmd_limit_blind(player_ptr))
571 if (cmd_limit_image(player_ptr))
575 if (!(repeat_pull(&mode) && 1 <= mode && mode <= 5)) {
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);
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);
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);
635 if (!get_com(format("どの能力を%sますか:", only_browse ? "調べ" : "使い"), &choice, true))
637 if (!get_com("Command :", &choice, true))
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);
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);
689 } while (only_browse);
694 display_essence(player_ptr);
697 drain_essence(player_ptr);
700 erase_essence(player_ptr);
703 mode = choose_essence();
706 add_essence(player_ptr, i2enum<SmithCategory>(mode));
709 add_essence(player_ptr, SmithCategory::ENCHANT);