OSDN Git Service

[Implement] 指定モンスターをクローンとして生成するデバッグコマンドを追加
[hengbandforosx/hengbandosx.git] / src / wizard / cmd-wizard.cpp
index 8dd4cf3..5e75bbb 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief デバッグコマンドの分岐実装
  * @date 2020/08/01
  * @author Hourier
@@ -13,6 +13,7 @@
 #include "inventory/inventory-slot-types.h"
 #include "io/input-key-requester.h"
 #include "mutation/mutation-investor-remover.h"
+#include "player-base/player-class.h"
 #include "player/patron.h"
 #include "spell-kind/spells-detection.h"
 #include "spell-kind/spells-floor.h"
@@ -23,7 +24,7 @@
 #include "status/experience.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
-#include "system/object-type-definition.h"
+#include "system/item-entity.h"
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h"
 #include "util/int-char-converter.h"
 #include "wizard/wizard-special-process.h"
 #include "wizard/wizard-spells.h"
 #include "wizard/wizard-spoiler.h"
+#include <algorithm>
 #include <sstream>
 #include <string>
+#include <tuple>
 #include <vector>
 
 /*!
  * @details
  * 空き: A,B,E,I,J,k,K,L,M,q,Q,R,T,U,V,W,y,Y
  */
-std::vector<std::vector<std::string>> debug_menu_table = {
-    { "a", _("全状態回復", "Restore all status") },
-    { "b", _("現在のターゲットを引き寄せる", "Teleport target back") },
-    { "c", _("オブジェクト生成", "Create object") },
-    { "C", _("固定アーティファクト生成", "Create fixed artifact") },
-    { "d", _("全感知", "Detection all") },
-    { "D", _("次元の扉", "Dimension door") },
-    { "e", _("能力値変更", "Modify player status") },
-    { "E", _("青魔法を全取得/エッセンスを全取得", "Learn all blue magics / Obtain all essences") },
-    { "f", _("*鑑定*", "*Idenfity*") },
-    { "F", _("地形ID変更", "Modify feature type under player") },
-    { "G", _("ゲーム設定コマンドメニュー", "Modify game configurations") },
-    { "H", _("モンスターの群れ生成", "Summon monsters") },
-    { "i", _("鑑定", "Idenfity") },
-    { "I", _("アイテム設定コマンドメニュー", "Modify item configurations") },
-    { "j", _("指定ダンジョン階にワープ", "Jump to floor depth of target dungeon") },
-    { "k", _("指定ダメージ・半径0の指定属性のボールを自分に放つ", "Fire a zero ball to self") },
-    { "m", _("魔法の地図", "Magic mapping") },
-    { "n", _("指定モンスター生成", "Summon target monster") },
-    { "N", _("指定モンスターをペットとして生成", "Summon target monster as pet") },
-    { "o", _("オブジェクトの能力変更", "Modift object abilities") },
-    { "O", _("オプション設定をダンプ", "Dump current options") },
-    { "p", _("ショート・テレポート", "Phase door") },
-    { "P", _("プレイヤー設定変更メニュー", "Modify player configurations") },
-    { "r", _("カオスパトロンの報酬", "Get reward of chaos patron") },
-    { "s", _("フロア相当のモンスター召喚", "Summon monster which be in target depth") },
-    { "t", _("テレポート", "Teleport self") },
-    { "u", _("啓蒙(忍者以外)", "Wiz-lite all floor except Ninja") },
-    { "w", _("啓蒙(忍者配慮)", "Wiz-lite all floor") },
-    { "x", _("経験値を得る(指定可)", "Get experience") },
-    { "X", _("所持品を初期状態に戻す", "Return inventory to initial") },
-    { "y", _("ダメージ100万・半径0の射撃のボールを放つ", "Cast missile ball had power a million") },
-    { "Y", _("指定ダメージ・半径0の指定属性のボールを放つ", "Cast zero ball had power a thousand") },
-    { "z", _("近隣のモンスター消去", "Terminate near monsters") },
-    { "Z", _("フロアの全モンスター消去", "Terminate all monsters in floor") },
-    { "@", _("特殊スペルの発動", "Activate specified spells") },
-    { "\"", _("スポイラーのダンプ", "Dump spoiler") },
-    { "?", _("ヘルプ表示", "Help") },
+constexpr std::array debug_menu_table = {
+    std::make_tuple('a', _("全状態回復", "Restore all status")),
+    std::make_tuple('b', _("現在のターゲットを引き寄せる", "Teleport target back")),
+    std::make_tuple('c', _("オブジェクト生成", "Create object")),
+    std::make_tuple('C', _("固定アーティファクト生成", "Create fixed artifact")),
+    std::make_tuple('d', _("全感知", "Detection all")),
+    std::make_tuple('D', _("次元の扉", "Dimension door")),
+    std::make_tuple('e', _("能力値変更", "Modify player status")),
+    std::make_tuple('E', _("青魔法を全取得/エッセンスを全取得", "Learn all blue magics / Obtain all essences")),
+    std::make_tuple('f', _("*鑑定*", "*Idenfity*")),
+    std::make_tuple('F', _("地形ID変更", "Modify feature type under player")),
+    std::make_tuple('G', _("ゲーム設定コマンドメニュー", "Modify game configurations")),
+    std::make_tuple('H', _("モンスターの群れ生成", "Summon monsters")),
+    std::make_tuple('i', _("鑑定", "Idenfity")),
+    std::make_tuple('I', _("アイテム設定コマンドメニュー", "Modify item configurations")),
+    std::make_tuple('j', _("指定ダンジョン階にワープ", "Jump to floor depth of target dungeon")),
+    std::make_tuple('k', _("指定ダメージ・半径0の指定属性のボールを自分に放つ", "Fire a zero ball to self")),
+    std::make_tuple('m', _("魔法の地図", "Magic mapping")),
+    std::make_tuple('n', _("指定モンスター生成", "Summon target monster")),
+    std::make_tuple('N', _("指定モンスターをペットとして生成", "Summon target monster as pet")),
+    std::make_tuple(KTRL('N'), _("指定モンスターをクローンとして生成", "Summon target monster as clone")),
+    std::make_tuple('o', _("オブジェクトの能力変更", "Modift object abilities")),
+    std::make_tuple('O', _("オプション設定をダンプ", "Dump current options")),
+    std::make_tuple('p', _("ショート・テレポート", "Phase door")),
+    std::make_tuple('P', _("プレイヤー設定変更メニュー", "Modify player configurations")),
+    std::make_tuple('r', _("カオスパトロンの報酬", "Get reward of chaos patron")),
+    std::make_tuple('s', _("フロア相当のモンスター生成", "Generate monster which be in target depth")),
+    std::make_tuple('S', _("フロア相当のモンスター召喚", "Summon monster which be in target depth")),
+    std::make_tuple('t', _("テレポート", "Teleport self")),
+    std::make_tuple('u', _("啓蒙(忍者以外)", "Wiz-lite all floor except Ninja")),
+    std::make_tuple('w', _("啓蒙(忍者配慮)", "Wiz-lite all floor")),
+    std::make_tuple('x', _("経験値を得る(指定可)", "Get experience")),
+    std::make_tuple('X', _("所持品を初期状態に戻す", "Return inventory to initial")),
+    std::make_tuple('y', _("ダメージ100万・半径0の射撃のボールを放つ", "Cast missile ball had power a million")),
+    std::make_tuple('Y', _("指定ダメージ・半径0の指定属性のボールを放つ", "Cast zero ball had power a thousand")),
+    std::make_tuple('z', _("近隣のモンスター消去", "Terminate near monsters")),
+    std::make_tuple('Z', _("フロアの全モンスター消去", "Terminate all monsters in floor")),
+    std::make_tuple('@', _("特殊スペルの発動", "Activate specified spells")),
+    std::make_tuple('"', _("スポイラーのダンプ", "Dump spoiler")),
+    std::make_tuple('?', _("ヘルプ表示", "Help")),
 };
 
 /*!
@@ -92,22 +97,32 @@ std::vector<std::vector<std::string>> debug_menu_table = {
  */
 void display_debug_menu(int page, int max_page, int page_size, int max_line)
 {
-    for (int y = 1; y < page_size + 3; y++)
+    for (int y = 1; y < page_size + 3; y++) {
         term_erase(14, y, 64);
+    }
 
     int r = 1;
     int c = 15;
     for (int i = 0; i < page_size; i++) {
         int pos = page * page_size + i;
-        if (pos >= max_line)
+        if (pos >= max_line) {
             break;
+        }
 
         std::stringstream ss;
-        ss << debug_menu_table[pos][0] << ") " << debug_menu_table[pos][1];
-        put_str(ss.str().c_str(), r++, c);
+        const auto &[symbol, desc] = debug_menu_table[pos];
+        std::stringstream debug_cmd;
+        if (!(symbol & ~0x1F)) { // CTRL+Ch = Ch & 0x1F のため0x1Fが含まれていなければCTRLと組み合わせたキー
+            debug_cmd << '^' << static_cast<char>(symbol | ('A' & ~KTRL('A'))); // 大文字はAからZで順番通りに並んでいるためこの式で変換する
+        } else {
+            debug_cmd << ' ' << symbol;
+        }
+        ss << debug_cmd.str() << ") " << desc;
+        put_str(ss.str(), r++, c);
     }
-    if (max_page > 1)
+    if (max_page > 1) {
         put_str("-- more --", r++, c);
+    }
 }
 
 /*!
@@ -116,7 +131,7 @@ void display_debug_menu(int page, int max_page, int page_size, int max_line)
  * @param cmd コマンドキー
  * @return コマンド終了ならTRUE、ページ送りならFALSE
  */
-bool exe_cmd_debug(player_type *player_ptr, char cmd)
+bool exe_cmd_debug(PlayerType *player_ptr, char cmd)
 {
     switch (cmd) {
     case ' ':
@@ -127,147 +142,155 @@ bool exe_cmd_debug(player_type *player_ptr, char cmd)
     case ESCAPE:
     case '\n':
     case '\r':
-        break;
+        return true;
     case 'a':
         wiz_cure_all(player_ptr);
-        break;
+        return true;
     case 'b':
         wiz_teleport_back(player_ptr);
-        break;
+        return true;
     case 'c':
         wiz_create_item(player_ptr);
-        break;
+        return true;
     case 'C':
-        wiz_create_named_art(player_ptr, command_arg);
-        break;
+        wiz_create_named_art(player_ptr);
+        return true;
     case 'd':
         detect_all(player_ptr, DETECT_RAD_ALL * 3);
-        break;
+        return true;
     case 'D':
         wiz_dimension_door(player_ptr);
-        break;
+        return true;
     case 'e':
         wiz_change_status(player_ptr);
-        break;
+        return true;
     case 'E':
         switch (player_ptr->pclass) {
-        case CLASS_BLUE_MAGE:
+        case PlayerClassType::BLUE_MAGE:
             wiz_learn_blue_magic_all(player_ptr);
             break;
-        case CLASS_SMITH:
+        case PlayerClassType::SMITH:
             wiz_fillup_all_smith_essences(player_ptr);
             break;
         default:
             break;
         }
-        break;
+
+        return true;
     case 'f':
         identify_fully(player_ptr, false);
-        break;
+        return true;
     case 'F':
         wiz_create_feature(player_ptr);
-        break;
+        return true;
     case 'G':
         wizard_game_modifier(player_ptr);
-        break;
+        return true;
     case 'H':
         wiz_summon_horde(player_ptr);
-        break;
+        return true;
     case 'i':
         (void)ident_spell(player_ptr, false);
-        break;
+        return true;
     case 'I':
         wizard_item_modifier(player_ptr);
-        break;
+        return true;
     case 'j':
         wiz_jump_to_dungeon(player_ptr);
-        break;
+        return true;
     case 'k':
-        wiz_kill_me(player_ptr, 0, command_arg);
-        break;
+        wiz_kill_target(player_ptr, 0, (AttributeType)command_arg, true);
+        return true;
     case 'm':
         map_area(player_ptr, DETECT_RAD_ALL * 3);
-        break;
-    case 'r':
-        gain_level_reward(player_ptr, command_arg);
-        break;
-    case 'N':
-        wiz_summon_pet(player_ptr, command_arg);
-        break;
+        return true;
     case 'n':
-        wiz_summon_specific_enemy(player_ptr, command_arg);
-        break;
-    case 'O':
-        wiz_dump_options();
-        break;
+        wiz_summon_specific_monster(player_ptr, i2enum<MonsterRaceId>(command_arg));
+        return true;
+    case 'N':
+        wiz_summon_pet(player_ptr, i2enum<MonsterRaceId>(command_arg));
+        return true;
+    case KTRL('N'):
+        wiz_summon_clone(player_ptr, i2enum<MonsterRaceId>(command_arg));
+        return true;
     case 'o':
         wiz_modify_item(player_ptr);
-        break;
+        return true;
+    case 'O':
+        wiz_dump_options();
+        return true;
     case 'p':
         teleport_player(player_ptr, 10, TELEPORT_SPONTANEOUS);
-        break;
+        return true;
     case 'P':
         wizard_player_modifier(player_ptr);
-        break;
+        return true;
+    case 'r':
+        patron_list[player_ptr->chaos_patron].gain_level_reward(player_ptr, command_arg);
+        return true;
     case 's':
-        if (command_arg <= 0)
-            command_arg = 1;
-
-        wiz_summon_random_enemy(player_ptr, command_arg);
-        break;
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_generate_random_monster(player_ptr, command_arg);
+        return true;
+    case 'S':
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_summon_random_monster(player_ptr, command_arg);
+        return true;
     case 't':
         teleport_player(player_ptr, 100, TELEPORT_SPONTANEOUS);
-        break;
+        return true;
     case 'u':
-        for (int y = 0; y < player_ptr->current_floor_ptr->height; y++)
-            for (int x = 0; x < player_ptr->current_floor_ptr->width; x++)
+        for (int y = 0; y < player_ptr->current_floor_ptr->height; y++) {
+            for (int x = 0; x < player_ptr->current_floor_ptr->width; x++) {
                 player_ptr->current_floor_ptr->grid_array[y][x].info |= CAVE_GLOW | CAVE_MARK;
+            }
+        }
 
         wiz_lite(player_ptr, false);
-        break;
+        return true;
     case 'w':
-        wiz_lite(player_ptr, (bool)(player_ptr->pclass == CLASS_NINJA));
-        break;
+        wiz_lite(player_ptr, PlayerClass(player_ptr).equals(PlayerClassType::NINJA));
+        return true;
     case 'x':
         gain_exp(player_ptr, command_arg ? command_arg : (player_ptr->exp + 1));
-        break;
+        return true;
     case 'X':
-        for (INVENTORY_IDX i = INVEN_TOTAL - 1; i >= 0; i--)
-            if (player_ptr->inventory_list[i].k_idx)
+        for (INVENTORY_IDX i = INVEN_TOTAL - 1; i >= 0; i--) {
+            if (player_ptr->inventory_list[i].is_valid()) {
                 drop_from_inventory(player_ptr, i, 999);
+            }
+        }
 
         player_outfit(player_ptr);
-        break;
+        return true;
     case 'y':
-        wiz_kill_enemy(player_ptr);
-        break;
+        wiz_kill_target(player_ptr);
+        return true;
     case 'Y':
-        wiz_kill_enemy(player_ptr, 0, command_arg);
-        break;
+        wiz_kill_target(player_ptr, 0, (AttributeType)command_arg);
+        return true;
     case 'z':
         wiz_zap_surrounding_monsters(player_ptr);
-        break;
+        return true;
     case 'Z':
         wiz_zap_floor_monsters(player_ptr);
-        break;
+        return true;
     case '_':
         probing(player_ptr);
-        break;
+        return true;
     case '@':
         wiz_debug_spell(player_ptr);
-        break;
+        return true;
     case '"':
         exe_output_spoilers();
-        break;
+        return true;
     case '?':
         do_cmd_help(player_ptr);
-        break;
+        return true;
     default:
         msg_print("That is not a valid debug command.");
-        break;
+        return true;
     }
-
-    return true;
 }
 
 /*!
@@ -278,25 +301,21 @@ bool exe_cmd_debug(player_type *player_ptr, char cmd)
  * @details
  * 番号を指定するには、それをN及びデバッグコマンドをXとしてとして「0N^aX」とする
  */
-void do_cmd_debug(player_type *player_ptr)
+void do_cmd_debug(PlayerType *player_ptr)
 {
-    TERM_LEN hgt, wid;
-    term_get_size(&wid, &hgt);
-
-    size_t max_line = debug_menu_table.size();
-    int page_size = hgt - 5;
-    int max_page = max_line / page_size + 1;
-    int page = 0;
-    char cmd;
-
+    const auto &[wid, hgt] = term_get_size();
+    const auto max_line = debug_menu_table.size();
+    const auto page_size = hgt - 5;
+    const auto max_page = max_line / page_size + 1;
+    auto page = 0;
     while (true) {
         screen_save();
         display_debug_menu(page, max_page, page_size, max_line);
-        get_com("Debug Command: ", &cmd, false);
+        const auto command = input_command("Debug Command: ");
         screen_load();
-
-        if (exe_cmd_debug(player_ptr, cmd))
-            break;
+        if (exe_cmd_debug(player_ptr, command.value_or(ESCAPE))) {
+            return;
+        }
 
         page = (page + 1) % max_page;
     }