OSDN Git Service

[Refactor] #3496 optional 型の存在判定 has_value() を撤廃した その6
[hengbandforosx/hengbandosx.git] / src / wizard / wizard-special-process.cpp
index 637f88e..fbe1078 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ウィザードモードの処理(特別処理中心) / Wizard commands
  * @date 2014/09/07
  * @author
@@ -76,6 +76,7 @@
 #include "spell/spells-summon.h"
 #include "status/bad-status-setter.h"
 #include "status/experience.h"
+#include "system/angband-system.h"
 #include "system/angband-version.h"
 #include "system/artifact-type-definition.h"
 #include "system/baseitem-info.h"
@@ -92,7 +93,9 @@
 #include "term/z-form.h"
 #include "util/angband-files.h"
 #include "util/bit-flags-calculator.h"
+#include "util/candidate-selector.h"
 #include "util/enum-converter.h"
+#include "util/finalizer.h"
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
 #include "wizard/spoiler-table.h"
 #include "world/world.h"
 #include <algorithm>
 #include <optional>
+#include <span>
 #include <sstream>
 #include <tuple>
 #include <vector>
@@ -127,22 +131,22 @@ void wiz_cure_all(PlayerType *player_ptr)
 static std::optional<short> wiz_select_tval()
 {
     short list;
-    char ch;
     for (list = 0; (list < 80) && (tvals[list].tval > ItemKindType::NONE); list++) {
         auto row = 2 + (list % 20);
         auto col = _(32, 24) * (list / 20);
-        ch = listsym[list];
-        prt(format("[%c] %s", ch, tvals[list].desc), row, col);
+        prt(format("[%c] %s", listsym[list], tvals[list].desc), row, col);
     }
 
-    auto max_num = list;
-    if (!get_com(_("アイテム種別を選んで下さい", "Get what type of object? "), &ch, false)) {
+    const auto item_type_opt = input_command(_("アイテム種別を選んで下さい", "Get what type of object? "));
+    if (!item_type_opt) {
         return std::nullopt;
     }
 
+    const auto item_type = item_type_opt.value();
     short selection;
+    auto max_num = list;
     for (selection = 0; selection < max_num; selection++) {
-        if (listsym[selection] == ch) {
+        if (listsym[selection] == item_type) {
             break;
         }
     }
@@ -154,11 +158,10 @@ static std::optional<short> wiz_select_tval()
     return selection;
 }
 
-static short wiz_select_sval(const ItemKindType tval, concptr tval_description)
+static short wiz_select_sval(const ItemKindType tval, std::string_view tval_description)
 {
     auto num = 0;
     short choice[80]{};
-    char ch;
     for (const auto &baseitem : baseitems_info) {
         if (num >= 80) {
             break;
@@ -170,17 +173,19 @@ static short wiz_select_sval(const ItemKindType tval, concptr tval_description)
 
         auto row = 2 + (num % 20);
         auto col = _(30, 32) * (num / 20);
-        ch = listsym[num];
         const auto buf = strip_name(baseitem.idx);
-        prt(format("[%c] %s", ch, buf.data()), row, col);
+        prt(format("[%c] %s", listsym[num], buf.data()), row, col);
         choice[num++] = baseitem.idx;
     }
 
     auto max_num = num;
-    if (!get_com(format(_("%s群の具体的なアイテムを選んで下さい", "What Kind of %s? "), tval_description), &ch, false)) {
+    const auto prompt = format(_("%s群の具体的なアイテムを選んで下さい", "What Kind of %s? "), tval_description.data());
+    const auto command = input_command(prompt);
+    if (!command) {
         return 0;
     }
 
+    const auto ch = command.value();
     short selection;
     for (selection = 0; selection < max_num; selection++) {
         if (listsym[selection] == ch) {
@@ -208,7 +213,7 @@ static short wiz_create_itemtype()
 {
     term_clear();
     auto selection = wiz_select_tval();
-    if (!selection.has_value()) {
+    if (!selection) {
         return 0;
     }
 
@@ -270,7 +275,7 @@ static std::string wiz_make_named_artifact_desc(PlayerType *player_ptr, FixedArt
     ItemEntity item;
     item.prep(lookup_baseitem_id(artifact.bi_key));
     item.fixed_artifact_idx = a_idx;
-    object_known(&item);
+    item.mark_as_known();
     return describe_flavor(player_ptr, &item, OD_NAME_ONLY);
 }
 
@@ -282,53 +287,11 @@ static std::string wiz_make_named_artifact_desc(PlayerType *player_ptr, FixedArt
  */
 static std::optional<FixedArtifactId> wiz_select_named_artifact(PlayerType *player_ptr, const std::vector<FixedArtifactId> &a_idx_list)
 {
-    constexpr auto MAX_PER_PAGE = 20UL;
-    const auto page_max = (a_idx_list.size() - 1) / MAX_PER_PAGE + 1;
-    auto current_page = 0UL;
-
-    screen_save();
-
-    std::optional<FixedArtifactId> selected_a_idx;
+    CandidateSelector cs("Which artifact: ", 15);
 
-    while (!selected_a_idx.has_value()) {
-        const auto page_base_idx = current_page * MAX_PER_PAGE;
-        for (auto i = 0U; i < MAX_PER_PAGE + 1; ++i) {
-            term_erase(14, i + 1, 255);
-        }
-        const auto page_item_count = std::min(MAX_PER_PAGE, a_idx_list.size() - page_base_idx);
-        for (auto i = 0U; i < page_item_count; ++i) {
-            std::stringstream ss;
-            ss << I2A(i) << ") " << wiz_make_named_artifact_desc(player_ptr, a_idx_list[page_base_idx + i]);
-            put_str(ss.str(), i + 1, 15);
-        }
-        if (page_max > 1) {
-            put_str(format("-- more (%lu/%lu) --", current_page + 1, page_max), page_item_count + 1, 15);
-        }
-
-        char cmd = ESCAPE;
-        get_com("Which artifact: ", &cmd, false);
-        switch (cmd) {
-        case ESCAPE:
-            screen_load();
-            return selected_a_idx;
-        case ' ':
-            current_page++;
-            if (current_page >= page_max) {
-                current_page = 0;
-            }
-            break;
-        default:
-            const auto select_idx = A2I(cmd) + page_base_idx;
-            if (select_idx < a_idx_list.size()) {
-                selected_a_idx = a_idx_list[select_idx];
-            }
-            break;
-        }
-    }
-
-    screen_load();
-
-    return selected_a_idx;
+    auto describe_artifact = [player_ptr](FixedArtifactId a_idx) { return wiz_make_named_artifact_desc(player_ptr, a_idx); };
+    const auto it = cs.select(a_idx_list, describe_artifact);
+    return (it != a_idx_list.end()) ? std::make_optional(*it) : std::nullopt;
 }
 
 /**
@@ -362,26 +325,25 @@ void wiz_create_named_art(PlayerType *player_ptr)
         const auto &[tval_lit, name] = group_artifact_list[i];
         std::stringstream ss;
         ss << I2A(i) << ") " << name;
-        term_erase(14, i + 1, 255);
+        term_erase(14, i + 1);
         put_str(ss.str(), i + 1, 15);
     }
 
     std::optional<FixedArtifactId> create_a_idx;
-    while (!create_a_idx.has_value()) {
-        char cmd = ESCAPE;
-        get_com("Kind of artifact: ", &cmd, false);
-        switch (cmd) {
-        case ESCAPE:
+    while (!create_a_idx) {
+        const auto command = input_command("Kind of artifact: ");
+        if (!command) {
             screen_load();
             return;
-        default:
-            if (auto idx = A2I(cmd); idx < group_artifact_list.size()) {
-                const auto &a_idx_list = wiz_collect_group_a_idx(group_artifact_list[idx]);
-                create_a_idx = wiz_select_named_artifact(player_ptr, a_idx_list);
-            }
+        }
 
-            break;
+        const auto idx = A2I(*command);
+        if (idx >= group_artifact_list.size()) {
+            continue;
         }
+
+        const auto a_idx_list = wiz_collect_group_a_idx(group_artifact_list[idx]);
+        create_a_idx = wiz_select_named_artifact(player_ptr, a_idx_list);
     }
 
     screen_load();
@@ -396,17 +358,65 @@ void wiz_create_named_art(PlayerType *player_ptr)
     msg_print("Allocated.");
 }
 
+static void wiz_change_status_max(PlayerType *player_ptr)
+{
+    for (auto i = 0; i < A_MAX; ++i) {
+        player_ptr->stat_cur[i] = player_ptr->stat_max_max[i];
+        player_ptr->stat_max[i] = player_ptr->stat_max_max[i];
+    }
+
+    for (auto tval : TV_WEAPON_RANGE) {
+        for (auto &exp : player_ptr->weapon_exp[tval]) {
+            exp = PlayerSkill::weapon_exp_at(PlayerSkillRank::MASTER);
+        }
+    }
+    PlayerSkill(player_ptr).limit_weapon_skills_by_max_value();
+
+    for (auto &[type, exp] : player_ptr->skill_exp) {
+        exp = class_skills_info[enum2i(player_ptr->pclass)].s_max[type];
+    }
+
+    const std::span spells_exp_span(player_ptr->spell_exp);
+    for (auto &exp : spells_exp_span.first(32)) {
+        exp = PlayerSkill::spell_exp_at(PlayerSkillRank::MASTER);
+    }
+    for (auto &exp : spells_exp_span.last(32)) {
+        exp = PlayerSkill::spell_exp_at(PlayerSkillRank::EXPERT);
+    }
+
+    player_ptr->au = 999999999;
+
+    if (PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
+        return;
+    }
+
+    player_ptr->max_exp = 99999999;
+    player_ptr->exp = 99999999;
+    player_ptr->exp_frac = 0;
+}
+
 /*!
  * @brief プレイヤーの現能力値を調整する / Change various "permanent" player variables.
  * @param player_ptr プレイヤーへの参照ポインタ
  */
 void wiz_change_status(PlayerType *player_ptr)
 {
+    const auto finalizer = util::make_finalizer([player_ptr]() {
+        check_experience(player_ptr);
+        do_cmd_redraw(player_ptr);
+    });
+
+    constexpr auto msg = _("全てのステータスを最大にしますか?", "Maximize all statuses? ");
+    if (input_check_strict(player_ptr, msg, { UserCheck::NO_ESCAPE, UserCheck::NO_HISTORY })) {
+        wiz_change_status_max(player_ptr);
+        return;
+    }
+
     for (int i = 0; i < A_MAX; i++) {
         const auto max_max_ability_score = player_ptr->stat_max_max[i];
         const auto max_ability_score = player_ptr->stat_max[i];
         const auto new_ability_score = input_numerics(stat_names[i], 3, max_max_ability_score, max_ability_score);
-        if (!new_ability_score.has_value()) {
+        if (!new_ability_score) {
             return;
         }
 
@@ -418,7 +428,7 @@ void wiz_change_status(PlayerType *player_ptr)
     const auto unskilled = PlayerSkill::weapon_exp_at(PlayerSkillRank::UNSKILLED);
     const auto master = PlayerSkill::weapon_exp_at(PlayerSkillRank::MASTER);
     const auto proficiency_opt = input_numerics(_("熟練度", "Proficiency"), unskilled, master, static_cast<short>(master));
-    if (!proficiency_opt.has_value()) {
+    if (!proficiency_opt) {
         return;
     }
 
@@ -448,18 +458,17 @@ void wiz_change_status(PlayerType *player_ptr)
     }
 
     const auto gold = input_numerics("Gold: ", 0, MAX_INT, player_ptr->au);
-    if (!gold.has_value()) {
+    if (!gold) {
         return;
     }
 
     player_ptr->au = gold.value();
     if (PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
-        do_cmd_redraw(player_ptr);
         return;
     }
 
     const auto experience_opt = input_numerics("Experience: ", 0, MAX_INT, player_ptr->max_exp);
-    if (!experience_opt.has_value()) {
+    if (!experience_opt) {
         return;
     }
 
@@ -467,8 +476,6 @@ void wiz_change_status(PlayerType *player_ptr)
     player_ptr->max_exp = experience;
     player_ptr->exp = experience;
     player_ptr->exp_frac = 0;
-    check_experience(player_ptr);
-    do_cmd_redraw(player_ptr);
 }
 
 /*!
@@ -483,25 +490,26 @@ void wiz_create_feature(PlayerType *player_ptr)
         return;
     }
 
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    const int max = terrains_info.size() - 1;
-    const auto f_val1 = input_numerics(_("実地形ID", "FeatureID"), 0, max, g_ptr->feat);
-    if (!f_val1.has_value()) {
+    const Pos2D pos(y, x);
+    auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const int max = TerrainList::get_instance().size() - 1;
+    const auto f_val1 = input_numerics(_("実地形ID", "FeatureID"), 0, max, grid.feat);
+    if (!f_val1) {
         return;
     }
 
     const auto f_val2 = input_numerics(_("偽装地形ID", "FeatureID"), 0, max, f_val1.value());
-    if (!f_val2.has_value()) {
+    if (!f_val2) {
         return;
     }
 
     cave_set_feat(player_ptr, y, x, f_val1.value());
-    g_ptr->mimic = f_val2.value();
-    auto *f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
-    if (f_ptr->flags.has(TerrainCharacteristics::RUNE_PROTECTION) || f_ptr->flags.has(TerrainCharacteristics::RUNE_EXPLOSION)) {
-        g_ptr->info |= CAVE_OBJECT;
-    } else if (f_ptr->flags.has(TerrainCharacteristics::MIRROR)) {
-        g_ptr->info |= CAVE_GLOW | CAVE_OBJECT;
+    grid.mimic = f_val2.value();
+    const auto &terrain = grid.get_terrain_mimic();
+    if (terrain.flags.has(TerrainCharacteristics::RUNE_PROTECTION) || terrain.flags.has(TerrainCharacteristics::RUNE_EXPLOSION)) {
+        grid.info |= CAVE_OBJECT;
+    } else if (terrain.flags.has(TerrainCharacteristics::MIRROR)) {
+        grid.info |= CAVE_GLOW | CAVE_OBJECT;
     }
 
     note_spot(player_ptr, y, x);
@@ -522,7 +530,7 @@ static std::optional<short> select_debugging_dungeon(short initial_dungeon_id)
 
     while (true) {
         const auto dungeon_id = input_numerics("Jump which dungeon", DUNGEON_ANGBAND, DUNGEON_DARKNESS, initial_dungeon_id);
-        if (!dungeon_id.has_value()) {
+        if (!dungeon_id) {
             return std::nullopt;
         }
 
@@ -589,12 +597,12 @@ void wiz_jump_to_dungeon(PlayerType *player_ptr)
     const auto is_in_dungeon = floor.is_in_dungeon();
     const auto dungeon_idx = is_in_dungeon ? floor.dungeon_idx : static_cast<short>(DUNGEON_ANGBAND);
     const auto dungeon_id_opt = select_debugging_dungeon(dungeon_idx);
-    if (!dungeon_id_opt.has_value()) {
+    if (!dungeon_id_opt) {
         if (!is_in_dungeon) {
             return;
         }
 
-        if (get_check(("Jump to the ground?"))) {
+        if (input_check(("Jump to the ground?"))) {
             wiz_jump_floor(player_ptr, 0, 0);
         }
 
@@ -603,7 +611,7 @@ void wiz_jump_to_dungeon(PlayerType *player_ptr)
 
     const auto dungeon_id = dungeon_id_opt.value();
     const auto level_opt = select_debugging_floor(floor, dungeon_id);
-    if (!level_opt.has_value()) {
+    if (!level_opt) {
         return;
     }
 
@@ -659,7 +667,7 @@ static void change_birth_flags()
 void wiz_reset_race(PlayerType *player_ptr)
 {
     const auto new_race = input_numerics("RaceID", 0, MAX_RACES - 1, player_ptr->prace);
-    if (!new_race.has_value()) {
+    if (!new_race) {
         return;
     }
 
@@ -676,7 +684,7 @@ void wiz_reset_race(PlayerType *player_ptr)
 void wiz_reset_class(PlayerType *player_ptr)
 {
     const auto new_class_opt = input_numerics("ClassID", 0, PLAYER_CLASS_TYPE_MAX - 1, player_ptr->pclass);
-    if (!new_class_opt.has_value()) {
+    if (!new_class_opt) {
         return;
     }
 
@@ -697,12 +705,12 @@ void wiz_reset_class(PlayerType *player_ptr)
 void wiz_reset_realms(PlayerType *player_ptr)
 {
     const auto new_realm1 = input_numerics("1st Realm (None=0)", 0, MAX_REALM - 1, player_ptr->realm1);
-    if (!new_realm1.has_value()) {
+    if (!new_realm1) {
         return;
     }
 
     const auto new_realm2 = input_numerics("2nd Realm (None=0)", 0, MAX_REALM - 1, player_ptr->realm2);
-    if (!new_realm2.has_value()) {
+    if (!new_realm2) {
         return;
     }
 
@@ -764,7 +772,7 @@ void wiz_dump_options(void)
 void set_gametime(void)
 {
     const auto game_time = input_integer("Dungeon Turn", 0, w_ptr->dungeon_turn_limit - 1);
-    if (!game_time.has_value()) {
+    if (!game_time) {
         return;
     }
 
@@ -835,7 +843,7 @@ void cheat_death(PlayerType *player_ptr)
     auto *floor_ptr = player_ptr->current_floor_ptr;
     floor_ptr->dun_level = 0;
     floor_ptr->inside_arena = false;
-    player_ptr->phase_out = false;
+    AngbandSystem::get_instance().set_phase_out(false);
     leaving_quest = QuestId::NONE;
     floor_ptr->quest_number = QuestId::NONE;
     if (floor_ptr->dungeon_idx) {