OSDN Git Service

[Refactor] #3642 VS2022の警告 (関数戻り値のムーブ)を解消した
[hengbandforosx/hengbandosx.git] / src / window / display-sub-windows.cpp
index 0e98cac..ad76e5b 100644 (file)
@@ -1,5 +1,4 @@
-#include "window/display-sub-windows.h"
-#include "core/window-redrawer.h"
+#include "window/display-sub-windows.h"
 #include "flavor/flavor-describer.h"
 #include "floor/cave.h"
 #include "game-option/option-flags.h"
@@ -7,39 +6,38 @@
 #include "game-option/text-display-options.h"
 #include "grid/feature.h"
 #include "inventory/inventory-describer.h"
-#include "inventory/inventory-slot-types.h"
 #include "inventory/inventory-util.h"
 #include "locale/japanese.h"
 #include "main/sound-of-music.h"
+#include "mind/mind-explanations-table.h"
+#include "mind/mind-info.h"
+#include "mind/mind-sniper.h"
+#include "mind/mind-types.h"
 #include "monster-race/monster-race.h"
-#include "monster-race/race-flags1.h"
-#include "monster/monster-flag-types.h"
-#include "monster/monster-info.h"
-#include "monster/monster-status.h"
+#include "monster/monster-describer.h"
+#include "monster/monster-description-types.h"
 #include "object/item-tester-hooker.h"
 #include "object/object-info.h"
-#include "object/object-mark-types.h"
+#include "player-base/player-class.h"
+#include "player-info/class-info.h"
 #include "player/player-status-flags.h"
+#include "player/player-status-table.h"
 #include "player/player-status.h"
-#include "spell-kind/magic-item-recharger.h"
-#include "system/baseitem-info.h"
+#include "realm/realm-names-table.h"
+#include "spell/spells-execution.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
-#include "system/player-type-definition.h"
 #include "system/terrain-type-definition.h"
-#include "target/target-describer.h"
 #include "target/target-preparation.h"
-#include "target/target-setter.h"
-#include "target/target-types.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
-#include "term/term-color-types.h"
 #include "timed-effect/player-hallucination.h"
+#include "timed-effect/player-stun.h"
 #include "timed-effect/timed-effects.h"
-#include "util/bit-flags-calculator.h"
+#include "util/int-char-converter.h"
 #include "view/display-lore.h"
 #include "view/display-map.h"
 #include "view/display-messages.h"
@@ -48,6 +46,8 @@
 #include "window/main-window-equipments.h"
 #include "window/main-window-util.h"
 #include "world/world.h"
+#include <algorithm>
+#include <concepts>
 #include <mutex>
 #include <sstream>
 #include <string>
@@ -67,26 +67,46 @@ FixItemTesterSetter::~FixItemTesterSetter()
 }
 
 /*!
- * @brief サブウィンドウに所持品一覧を表示する / Hack -- display inventory in sub-windows
- * @param player_ptr プレイヤーへの参照ポインタ
+ * @brief サブウィンドウの描画を行う
+ *
+ * pw_flag で指定したウィンドウフラグが設定されているサブウィンドウに対し描画を行う。
+ * 描画は display_func で指定したコールバック関数で行う。
+ *
+ * @param pw_flag 描画を行うフラグ
+ * @param display_func 描画を行う関数
  */
-void fix_inventory(PlayerType *player_ptr)
+static void display_sub_windows(SubWindowRedrawingFlag pw_flag, std::invocable auto display_func)
 {
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        if (!angband_term[j]) {
+    auto current_term = game_term;
+
+    for (auto i = 0U; i < angband_terms.size(); ++i) {
+        auto term = angband_terms[i];
+        if (term == nullptr) {
             continue;
         }
 
-        if (!(window_flag[j] & (PW_INVEN))) {
+        if (!g_window_flags[i].has(pw_flag)) {
             continue;
         }
 
-        term_activate(angband_term[j]);
-        display_inventory(player_ptr, *fix_item_tester);
+        term_activate(term);
+        display_func();
         term_fresh();
-        term_activate(old);
     }
+
+    term_activate(current_term);
+}
+
+/*!
+ * @brief サブウィンドウに所持品一覧を表示する / Hack -- display inventory in sub-windows
+ * @param player_ptr プレイヤーへの参照ポインタ
+ */
+void fix_inventory(PlayerType *player_ptr)
+{
+    display_sub_windows(SubWindowRedrawingFlag::INVENTORY,
+        [player_ptr] {
+            display_inventory(player_ptr, *fix_item_tester);
+        });
 }
 
 /*!
@@ -107,36 +127,34 @@ void fix_inventory(PlayerType *player_ptr)
  */
 static void print_monster_line(TERM_LEN x, TERM_LEN y, MonsterEntity *m_ptr, int n_same, int n_awake)
 {
-    char buf[256];
+    std::string buf;
     MonsterRaceId r_idx = m_ptr->ap_r_idx;
     auto *r_ptr = &monraces_info[r_idx];
 
-    term_erase(0, y, 255);
+    term_erase(0, y);
     term_gotoxy(x, y);
     if (!r_ptr) {
         return;
     }
     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
-        sprintf(buf, _("%3s(覚%2d)", "%3s(%2d)"), MonsterRace(r_idx).is_bounty(true) ? "  W" : "  U", n_awake);
-        term_addstr(-1, TERM_WHITE, buf);
+        buf = format(_("%3s(覚%2d)", "%3s(%2d)"), MonsterRace(r_idx).is_bounty(true) ? "  W" : "  U", n_awake);
     } else {
-        sprintf(buf, _("%3d(覚%2d)", "%3d(%2d)"), n_same, n_awake);
-        term_addstr(-1, TERM_WHITE, buf);
+        buf = format(_("%3d(覚%2d)", "%3d(%2d)"), n_same, n_awake);
     }
+    term_addstr(-1, TERM_WHITE, buf);
 
     term_addstr(-1, TERM_WHITE, " ");
     term_add_bigch(r_ptr->x_attr, r_ptr->x_char);
 
     if (r_ptr->r_tkills && m_ptr->mflag2.has_not(MonsterConstantFlagType::KAGE)) {
-        sprintf(buf, " %2d", (int)r_ptr->level);
+        buf = format(" %2d", (int)r_ptr->level);
     } else {
-        strcpy(buf, " ??");
+        buf = " ??";
     }
 
     term_addstr(-1, TERM_WHITE, buf);
 
-    sprintf(buf, " %s ", r_ptr->name.data());
-    term_addstr(-1, TERM_WHITE, buf);
+    term_addstr(-1, TERM_WHITE, format(" %s ", r_ptr->name.data()));
 }
 
 /*!
@@ -195,7 +213,51 @@ void print_monster_list(FloorType *floor_ptr, const std::vector<MONSTER_IDX> &mo
     }
 
     for (; line < max_lines; line++) {
-        term_erase(0, line, 255);
+        term_erase(0, line);
+    }
+}
+
+static void print_pet_list_oneline(PlayerType *player_ptr, const MonsterEntity &monster, TERM_LEN x, TERM_LEN y, TERM_LEN width)
+{
+    const auto &monrace = monraces_info[monster.ap_r_idx];
+    const auto name = monster_desc(player_ptr, &monster, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE | MD_NO_OWNER);
+    const auto &[bar_color, bar_len] = monster.get_hp_bar_data();
+    const auto is_visible = monster.ml && !player_ptr->effects()->hallucination()->is_hallucinated();
+
+    term_erase(0, y);
+    if (is_visible) {
+        term_putstr(x, y, -1, TERM_WHITE, "[----------]");
+        term_putstr(x + 1, y, bar_len, bar_color, "**********");
+    }
+
+    term_gotoxy(x + 13, y);
+    term_add_bigch(monrace.x_attr, monrace.x_char);
+    term_addstr(-1, TERM_WHITE, " ");
+    term_addstr(-1, TERM_WHITE, name);
+
+    if (width >= 50) {
+        const auto location = format(" (X:%3d Y:%3d)", monster.fx, monster.fy);
+        prt(is_visible ? location : "", y, width - location.length());
+    }
+}
+
+static void print_pet_list(PlayerType *player_ptr, const std::vector<MONSTER_IDX> &pets, TERM_LEN x, TERM_LEN y, TERM_LEN width, TERM_LEN height)
+{
+    for (auto n = 0U; n < pets.size(); ++n) {
+        const auto &monster = player_ptr->current_floor_ptr->m_list[pets[n]];
+        const int line = y + n;
+
+        print_pet_list_oneline(player_ptr, monster, x, line, width);
+
+        if ((line == height - 2) && (n < pets.size() - 2)) {
+            term_erase(0, line + 1);
+            term_putstr(x, line + 1, -1, TERM_WHITE, "-- and more --");
+            break;
+        }
+    }
+
+    for (int n = pets.size(); n < height; ++n) {
+        term_erase(0, y + n);
     }
 }
 
@@ -208,26 +270,12 @@ void fix_monster_list(PlayerType *player_ptr)
     static std::vector<MONSTER_IDX> monster_list;
     std::once_flag once;
 
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        if (!angband_term[j]) {
-            continue;
-        }
-        if (!(window_flag[j] & PW_MONSTER_LIST)) {
-            continue;
-        }
-        if (angband_term[j]->never_fresh) {
-            continue;
-        }
-
-        term_activate(angband_term[j]);
-        int w, h;
-        term_get_size(&w, &h);
-        std::call_once(once, target_sensing_monsters_prepare, player_ptr, monster_list);
-        print_monster_list(player_ptr->current_floor_ptr, monster_list, 0, 0, h);
-        term_fresh();
-        term_activate(old);
-    }
+    display_sub_windows(SubWindowRedrawingFlag::SIGHT_MONSTERS,
+        [player_ptr, &once] {
+            const auto &[wid, hgt] = term_get_size();
+            std::call_once(once, target_sensing_monsters_prepare, player_ptr, monster_list);
+            print_monster_list(player_ptr->current_floor_ptr, monster_list, 0, 0, hgt);
+        });
 
     if (use_music && has_monster_music) {
         std::call_once(once, target_sensing_monsters_prepare, player_ptr, monster_list);
@@ -236,6 +284,19 @@ void fix_monster_list(PlayerType *player_ptr)
 }
 
 /*!
+ * @brief 視界内のペットのリストをサブウィンドウに表示する
+ */
+void fix_pet_list(PlayerType *player_ptr)
+{
+    display_sub_windows(SubWindowRedrawingFlag::PETS,
+        [player_ptr] {
+            const auto &[wid, hgt] = term_get_size();
+            const auto pets = target_pets_prepare(player_ptr);
+            print_pet_list(player_ptr, pets, 0, 0, wid, hgt);
+        });
+}
+
+/*!
  * @brief 装備アイテム一覧を表示する /
  * Choice window "shadow" of the "show_equip()" function
  */
@@ -245,12 +306,8 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
         return;
     }
 
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-
-    TERM_COLOR attr = TERM_WHITE;
-    char tmp_val[80];
-    GAME_TEXT o_name[MAX_NLEN];
+    const auto &[wid, hgt] = term_get_size();
+    byte attr = TERM_WHITE;
     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
         int cur_row = i - INVEN_MAIN_HAND;
         if (cur_row >= hgt) {
@@ -259,7 +316,7 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
 
         auto o_ptr = &player_ptr->inventory_list[i];
         auto do_disp = player_ptr->select_ring_slot ? is_ring_slot(i) : item_tester.okay(o_ptr);
-        strcpy(tmp_val, "   ");
+        std::string tmp_val = "   ";
 
         if (do_disp) {
             tmp_val[0] = index_to_label(i);
@@ -267,18 +324,21 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
         }
 
         int cur_col = 3;
-        term_erase(cur_col, cur_row, 255);
+        term_erase(cur_col, cur_row);
         term_putstr(0, cur_row, cur_col, TERM_WHITE, tmp_val);
 
-        if ((((i == INVEN_MAIN_HAND) && can_attack_with_sub_hand(player_ptr)) || ((i == INVEN_SUB_HAND) && can_attack_with_main_hand(player_ptr))) && has_two_handed_weapons(player_ptr)) {
-            strcpy(o_name, _("(武器を両手持ち)", "(wielding with two-hands)"));
+        std::string item_name;
+        auto is_two_handed = (i == INVEN_MAIN_HAND) && can_attack_with_sub_hand(player_ptr);
+        is_two_handed |= (i == INVEN_SUB_HAND) && can_attack_with_main_hand(player_ptr);
+        if (is_two_handed && has_two_handed_weapons(player_ptr)) {
+            item_name = _("(武器を両手持ち)", "(wielding with two-hands)");
             attr = TERM_WHITE;
         } else {
-            describe_flavor(player_ptr, o_name, o_ptr, 0);
-            attr = tval_to_attr[enum2i(o_ptr->tval) % 128];
+            item_name = describe_flavor(player_ptr, o_ptr, 0);
+            attr = tval_to_attr[enum2i(o_ptr->bi_key.tval()) % 128];
         }
 
-        int n = strlen(o_name);
+        int n = item_name.length();
         if (o_ptr->timeout) {
             attr = TERM_L_DARK;
         }
@@ -294,10 +354,10 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
             cur_col += 2;
         }
 
-        term_putstr(cur_col, cur_row, n, attr, o_name);
+        term_putstr(cur_col, cur_row, n, attr, item_name);
         if (show_weights) {
             int wgt = o_ptr->weight * o_ptr->number;
-            sprintf(tmp_val, _("%3d.%1d kg", "%3d.%1d lb"), _(lb_to_kg_integer(wgt), wgt / 10), _(lb_to_kg_fraction(wgt), wgt % 10));
+            tmp_val = format(_("%3d.%1d kg", "%3d.%1d lb"), _(lb_to_kg_integer(wgt), wgt / 10), _(lb_to_kg_fraction(wgt), wgt % 10));
             prt(tmp_val, cur_row, wid - (show_labels ? 28 : 9));
         }
 
@@ -308,7 +368,7 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
     }
 
     for (int i = INVEN_TOTAL - INVEN_MAIN_HAND; i < hgt; i++) {
-        term_erase(0, i, 255);
+        term_erase(0, i);
     }
 }
 
@@ -319,20 +379,10 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
  */
 void fix_equip(PlayerType *player_ptr)
 {
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        if (!angband_term[j]) {
-            continue;
-        }
-        if (!(window_flag[j] & (PW_EQUIP))) {
-            continue;
-        }
-
-        term_activate(angband_term[j]);
-        display_equipment(player_ptr, *fix_item_tester);
-        term_fresh();
-        term_activate(old);
-    }
+    display_sub_windows(SubWindowRedrawingFlag::EQUIPMENT,
+        [player_ptr] {
+            display_equipment(player_ptr, *fix_item_tester);
+        });
 }
 
 /*!
@@ -342,22 +392,11 @@ void fix_equip(PlayerType *player_ptr)
  */
 void fix_player(PlayerType *player_ptr)
 {
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        if (!angband_term[j]) {
-            continue;
-        }
-
-        if (!(window_flag[j] & (PW_PLAYER))) {
-            continue;
-        }
-
-        term_activate(angband_term[j]);
-        update_playtime();
-        (void)display_player(player_ptr, 0);
-        term_fresh();
-        term_activate(old);
-    }
+    update_playtime();
+    display_sub_windows(SubWindowRedrawingFlag::PLAYER,
+        [player_ptr] {
+            display_player(player_ptr, 0);
+        });
 }
 
 /*!
@@ -367,29 +406,16 @@ void fix_player(PlayerType *player_ptr)
  */
 void fix_message(void)
 {
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        if (!angband_term[j]) {
-            continue;
-        }
-
-        if (!(window_flag[j] & (PW_MESSAGE))) {
-            continue;
-        }
-
-        term_activate(angband_term[j]);
-        TERM_LEN w, h;
-        term_get_size(&w, &h);
-        for (int i = 0; i < h; i++) {
-            term_putstr(0, (h - 1) - i, -1, (byte)((i < now_message) ? TERM_WHITE : TERM_SLATE), message_str((int16_t)i));
-            TERM_LEN x, y;
-            term_locate(&x, &y);
-            term_erase(x, y, 255);
-        }
-
-        term_fresh();
-        term_activate(old);
-    }
+    display_sub_windows(SubWindowRedrawingFlag::MESSAGE,
+        [] {
+            const auto &[wid, hgt] = term_get_size();
+            for (short i = 0; i < hgt; i++) {
+                term_putstr(0, (hgt - 1) - i, -1, (byte)((i < now_message) ? TERM_WHITE : TERM_SLATE), *message_str(i));
+                TERM_LEN x, y;
+                term_locate(&x, &y);
+                term_erase(x, y);
+            }
+        });
 }
 
 /*!
@@ -402,27 +428,14 @@ void fix_message(void)
  */
 void fix_overhead(PlayerType *player_ptr)
 {
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        TERM_LEN wid, hgt;
-        if (!angband_term[j]) {
-            continue;
-        }
-
-        if (!(window_flag[j] & (PW_OVERHEAD))) {
-            continue;
-        }
-
-        term_activate(angband_term[j]);
-        term_get_size(&wid, &hgt);
-        if (wid > COL_MAP + 2 && hgt > ROW_MAP + 2) {
-            int cy, cx;
-            display_map(player_ptr, &cy, &cx);
-            term_fresh();
-        }
-
-        term_activate(old);
-    }
+    display_sub_windows(SubWindowRedrawingFlag::OVERHEAD,
+        [player_ptr] {
+            const auto &[wid, hgt] = term_get_size();
+            if (wid > COL_MAP + 2 && hgt > ROW_MAP + 2) {
+                int cy, cx;
+                display_map(player_ptr, &cy, &cx);
+            }
+        });
 }
 
 /*!
@@ -469,21 +482,10 @@ static void display_dungeon(PlayerType *player_ptr)
  */
 void fix_dungeon(PlayerType *player_ptr)
 {
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        if (!angband_term[j]) {
-            continue;
-        }
-
-        if (!(window_flag[j] & (PW_DUNGEON))) {
-            continue;
-        }
-
-        term_activate(angband_term[j]);
-        display_dungeon(player_ptr);
-        term_fresh();
-        term_activate(old);
-    }
+    display_sub_windows(SubWindowRedrawingFlag::DUNGEON,
+        [player_ptr] {
+            display_dungeon(player_ptr);
+        });
 }
 
 /*!
@@ -493,24 +495,13 @@ void fix_dungeon(PlayerType *player_ptr)
  */
 void fix_monster(PlayerType *player_ptr)
 {
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        if (!angband_term[j]) {
-            continue;
-        }
-
-        if (!(window_flag[j] & (PW_MONSTER))) {
-            continue;
-        }
-
-        term_activate(angband_term[j]);
-        if (MonsterRace(player_ptr->monster_race_idx).is_valid()) {
-            display_roff(player_ptr);
-        }
-
-        term_fresh();
-        term_activate(old);
+    if (!MonsterRace(player_ptr->monster_race_idx).is_valid()) {
+        return;
     }
+    display_sub_windows(SubWindowRedrawingFlag::MONSTER_LORE,
+        [player_ptr] {
+            display_roff(player_ptr);
+        });
 }
 
 /*!
@@ -520,24 +511,10 @@ void fix_monster(PlayerType *player_ptr)
  */
 void fix_object(PlayerType *player_ptr)
 {
-    for (int j = 0; j < 8; j++) {
-        term_type *old = game_term;
-        if (!angband_term[j]) {
-            continue;
-        }
-
-        if (!(window_flag[j] & (PW_OBJECT))) {
-            continue;
-        }
-
-        term_activate(angband_term[j]);
-        if (player_ptr->baseitem_info_idx) {
-            display_koff(player_ptr, player_ptr->baseitem_info_idx);
-        }
-
-        term_fresh();
-        term_activate(old);
-    }
+    display_sub_windows(SubWindowRedrawingFlag::ITEM_KNOWLEDGE,
+        [player_ptr] {
+            display_koff(player_ptr);
+        });
 }
 
 /*!
@@ -570,13 +547,8 @@ static const MonsterEntity *monster_on_floor_items(FloorType *floor_ptr, const g
  */
 static void display_floor_item_list(PlayerType *player_ptr, const int y, const int x)
 {
-    // Term の行数を取得。
-    TERM_LEN term_h;
-    {
-        TERM_LEN term_w;
-        term_get_size(&term_w, &term_h);
-    }
-    if (term_h <= 0) {
+    const auto &[wid, hgt] = term_get_size();
+    if (hgt <= 0) {
         return;
     }
 
@@ -585,47 +557,46 @@ static void display_floor_item_list(PlayerType *player_ptr, const int y, const i
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     const auto *g_ptr = &floor_ptr->grid_array[y][x];
-    char line[1024];
+    std::string line;
 
     // 先頭行を書く。
     auto is_hallucinated = player_ptr->effects()->hallucination()->is_hallucinated();
     if (player_bold(player_ptr, y, x)) {
-        sprintf(line, _("(X:%03d Y:%03d) あなたの足元のアイテム一覧", "Items at (%03d,%03d) under you"), x, y);
+        line = format(_("(X:%03d Y:%03d) あなたの足元のアイテム一覧", "Items at (%03d,%03d) under you"), x, y);
     } else if (const auto *m_ptr = monster_on_floor_items(floor_ptr, g_ptr); m_ptr != nullptr) {
         if (is_hallucinated) {
-            sprintf(line, _("(X:%03d Y:%03d) 何か奇妙な物の足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under something strange"), x, y);
+            line = format(_("(X:%03d Y:%03d) 何か奇妙な物の足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under something strange"), x, y);
         } else {
             const MonsterRaceInfo *const r_ptr = &monraces_info[m_ptr->ap_r_idx];
-            sprintf(line, _("(X:%03d Y:%03d) %sの足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under %s"), x, y, r_ptr->name.data());
+            line = format(_("(X:%03d Y:%03d) %sの足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under %s"), x, y, r_ptr->name.data());
         }
     } else {
         const TerrainType *const f_ptr = &terrains_info[g_ptr->feat];
         concptr fn = f_ptr->name.data();
-        char buf[512];
+        std::string buf;
 
         if (f_ptr->flags.has(TerrainCharacteristics::STORE) || (f_ptr->flags.has(TerrainCharacteristics::BLDG) && !floor_ptr->inside_arena)) {
-            sprintf(buf, _("%sの入口", "on the entrance of %s"), fn);
+            buf = format(_("%sの入口", "on the entrance of %s"), fn);
         } else if (f_ptr->flags.has(TerrainCharacteristics::WALL)) {
-            sprintf(buf, _("%sの中", "in %s"), fn);
+            buf = format(_("%sの中", "in %s"), fn);
         } else {
-            sprintf(buf, _("%s", "on %s"), fn);
+            buf = format(_("%s", "on %s"), fn);
         }
-        sprintf(line, _("(X:%03d Y:%03d) %sの上の発見済みアイテム一覧", "Found items at (X:%03d Y:%03d) %s"), x, y, buf);
+        line = format(_("(X:%03d Y:%03d) %sの上の発見済みアイテム一覧", "Found items at (X:%03d Y:%03d) %s"), x, y, buf.data());
     }
     term_addstr(-1, TERM_WHITE, line);
 
     // (y,x) のアイテムを1行に1個ずつ書く。
     TERM_LEN term_y = 1;
     for (const auto o_idx : g_ptr->o_idx_list) {
-        ItemEntity *const o_ptr = &floor_ptr->o_list[o_idx];
-
-        // 未発見アイテムおよび金は対象外。
-        if (o_ptr->marked.has_not(OmType::FOUND) || o_ptr->tval == ItemKindType::GOLD) {
+        auto *const o_ptr = &floor_ptr->o_list[o_idx];
+        const auto tval = o_ptr->bi_key.tval();
+        if (o_ptr->marked.has_not(OmType::FOUND) || tval == ItemKindType::GOLD) {
             continue;
         }
 
         // 途中で行数が足りなくなったら最終行にその旨追記して終了。
-        if (term_y >= term_h) {
+        if (term_y >= hgt) {
             term_addstr(-1, TERM_WHITE, "-- more --");
             break;
         }
@@ -635,9 +606,9 @@ static void display_floor_item_list(PlayerType *player_ptr, const int y, const i
         if (is_hallucinated) {
             term_addstr(-1, TERM_WHITE, _("何か奇妙な物", "something strange"));
         } else {
-            describe_flavor(player_ptr, line, o_ptr, 0);
-            TERM_COLOR attr = tval_to_attr[enum2i(o_ptr->tval) % 128];
-            term_addstr(-1, attr, line);
+            const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
+            TERM_COLOR attr = tval_to_attr[enum2i(tval) % 128];
+            term_addstr(-1, attr, item_name);
         }
 
         ++term_y;
@@ -649,25 +620,10 @@ static void display_floor_item_list(PlayerType *player_ptr, const int y, const i
  */
 void fix_floor_item_list(PlayerType *player_ptr, const int y, const int x)
 {
-    for (int j = 0; j < 8; j++) {
-        if (!angband_term[j]) {
-            continue;
-        }
-        if (angband_term[j]->never_fresh) {
-            continue;
-        }
-        if (!(window_flag[j] & PW_FLOOR_ITEM_LIST)) {
-            continue;
-        }
-
-        term_type *old = game_term;
-        term_activate(angband_term[j]);
-
-        display_floor_item_list(player_ptr, y, x);
-        term_fresh();
-
-        term_activate(old);
-    }
+    display_sub_windows(SubWindowRedrawingFlag::FLOOR_ITEMS,
+        [player_ptr, y, x] {
+            display_floor_item_list(player_ptr, y, x);
+        });
 }
 
 /*!
@@ -676,12 +632,8 @@ void fix_floor_item_list(PlayerType *player_ptr, const int y, const int x)
  */
 static void display_found_item_list(PlayerType *player_ptr)
 {
-    // Term の行数を取得。
-    TERM_LEN term_h;
-    TERM_LEN term_w;
-    term_get_size(&term_w, &term_h);
-
-    if (term_h <= 0) {
+    const auto &[wid, hgt] = term_get_size();
+    if (hgt <= 0) {
         return;
     }
 
@@ -694,9 +646,12 @@ static void display_found_item_list(PlayerType *player_ptr)
     // ItemKindTypeがGOLD
     std::vector<ItemEntity *> found_item_list;
     for (auto &item : floor_ptr->o_list) {
-        auto item_entity_ptr = &item;
-        if (item_entity_ptr->bi_id > 0 && item_entity_ptr->marked.has(OmType::FOUND) && item_entity_ptr->tval != ItemKindType::GOLD) {
-            found_item_list.push_back(item_entity_ptr);
+        const auto is_item_to_display =
+            item.is_valid() && (item.number > 0) &&
+            item.marked.has(OmType::FOUND) && (item.bi_key.tval() != ItemKindType::GOLD);
+
+        if (is_item_to_display) {
+            found_item_list.push_back(&item);
         }
     }
 
@@ -716,7 +671,7 @@ static void display_found_item_list(PlayerType *player_ptr)
     TERM_LEN term_y = 1;
     for (auto item : found_item_list) {
         // 途中で行数が足りなくなったら終了。
-        if (term_y >= term_h) {
+        if (term_y >= hgt) {
             break;
         }
 
@@ -724,20 +679,17 @@ static void display_found_item_list(PlayerType *player_ptr)
 
         // アイテムシンボル表示
         const auto symbol_code = item->get_symbol();
-        const std::string symbol = format(" %c ", symbol_code);
+        const auto symbol = format(" %c ", symbol_code);
         const auto color_code_for_symbol = item->get_color();
-        term_addstr(-1, color_code_for_symbol, symbol.data());
+        term_addstr(-1, color_code_for_symbol, symbol);
 
-        // アイテム名表示
-        char temp[512];
-        describe_flavor(player_ptr, temp, item, 0);
-        const std::string item_description(temp);
-        const auto color_code_for_item = tval_to_attr[enum2i(item->tval) % 128];
-        term_addstr(-1, color_code_for_item, item_description.data());
+        const auto item_name = describe_flavor(player_ptr, item, 0);
+        const auto color_code_for_item = tval_to_attr[enum2i(item->bi_key.tval()) % 128];
+        term_addstr(-1, color_code_for_item, item_name);
 
         // アイテム座標表示
-        const std::string item_location = format("(X:%3d Y:%3d)", item->ix, item->iy);
-        prt(item_location.data(), term_y, term_w - item_location.length() - 1);
+        const auto item_location = format("(X:%3d Y:%3d)", item->ix, item->iy);
+        prt(item_location, term_y, wid - item_location.length() - 1);
 
         ++term_y;
     }
@@ -748,49 +700,195 @@ static void display_found_item_list(PlayerType *player_ptr)
  */
 void fix_found_item_list(PlayerType *player_ptr)
 {
-    for (int j = 0; j < 8; j++) {
-        if (!angband_term[j]) {
-            continue;
-        }
-        if (angband_term[j]->never_fresh) {
-            continue;
+    display_sub_windows(SubWindowRedrawingFlag::FOUND_ITEMS,
+        [player_ptr] {
+            display_found_item_list(player_ptr);
+        });
+}
+
+/*!
+ * @brief プレイヤーの全既知呪文を表示する / Display all known spells in a window
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @details
+ * Need to analyze size of the window.
+ * Need more color coding.
+ */
+static void display_spell_list(PlayerType *player_ptr)
+{
+    TERM_LEN y, x;
+    int m[9];
+    const magic_type *s_ptr;
+    GAME_TEXT name[MAX_NLEN];
+
+    clear_from(0);
+
+    PlayerClass pc(player_ptr);
+    if (pc.is_every_magic()) {
+        return;
+    }
+
+    if (pc.equals(PlayerClassType::SNIPER)) {
+        display_snipe_list(player_ptr);
+        return;
+    }
+
+    if (pc.has_listed_magics()) {
+        PERCENTAGE minfail = 0;
+        PLAYER_LEVEL plev = player_ptr->lev;
+        PERCENTAGE chance = 0;
+        mind_type spell;
+        MindKindType use_mind;
+        bool use_hp = false;
+
+        y = 1;
+        x = 1;
+
+        prt("", y, x);
+        put_str(_("名前", "Name"), y, x + 5);
+        put_str(_("Lv   MP 失率 効果", "Lv Mana Fail Info"), y, x + 35);
+
+        switch (player_ptr->pclass) {
+        case PlayerClassType::MINDCRAFTER:
+            use_mind = MindKindType::MINDCRAFTER;
+            break;
+        case PlayerClassType::FORCETRAINER:
+            use_mind = MindKindType::KI;
+            break;
+        case PlayerClassType::BERSERKER:
+            use_mind = MindKindType::BERSERKER;
+            use_hp = true;
+            break;
+        case PlayerClassType::MIRROR_MASTER:
+            use_mind = MindKindType::MIRROR_MASTER;
+            break;
+        case PlayerClassType::NINJA:
+            use_mind = MindKindType::NINJUTSU;
+            use_hp = true;
+            break;
+        case PlayerClassType::ELEMENTALIST:
+            use_mind = MindKindType::ELEMENTAL;
+            break;
+        default:
+            use_mind = MindKindType::MINDCRAFTER;
+            break;
         }
-        if (none_bits(window_flag[j], PW_FOUND_ITEM_LIST)) {
-            continue;
+
+        for (int i = 0; i < MAX_MIND_POWERS; i++) {
+            byte a = TERM_WHITE;
+            spell = mind_powers[static_cast<int>(use_mind)].info[i];
+            if (spell.min_lev > plev) {
+                break;
+            }
+
+            chance = spell.fail;
+            chance -= 3 * (player_ptr->lev - spell.min_lev);
+            chance -= 3 * (adj_mag_stat[player_ptr->stat_index[mp_ptr->spell_stat]] - 1);
+            if (!use_hp) {
+                if (spell.mana_cost > player_ptr->csp) {
+                    chance += 5 * (spell.mana_cost - player_ptr->csp);
+                    a = TERM_ORANGE;
+                }
+            } else {
+                if (spell.mana_cost > player_ptr->chp) {
+                    chance += 100;
+                    a = TERM_RED;
+                }
+            }
+
+            minfail = adj_mag_fail[player_ptr->stat_index[mp_ptr->spell_stat]];
+            if (chance < minfail) {
+                chance = minfail;
+            }
+
+            auto player_stun = player_ptr->effects()->stun();
+            chance += player_stun->get_magic_chance_penalty();
+            if (chance > 95) {
+                chance = 95;
+            }
+
+            const auto comment = mindcraft_info(player_ptr, use_mind, i);
+            constexpr auto fmt = "  %c) %-30s%2d %4d %3d%%%s";
+            term_putstr(x, y + i + 1, -1, a, format(fmt, I2A(i), spell.name, spell.min_lev, spell.mana_cost, chance, comment.data()));
         }
 
-        term_type *old = game_term;
-        term_activate(angband_term[j]);
+        return;
+    }
 
-        display_found_item_list(player_ptr);
-        term_fresh();
+    if (REALM_NONE == player_ptr->realm1) {
+        return;
+    }
+
+    for (int j = 0; j < ((player_ptr->realm2 > REALM_NONE) ? 2 : 1); j++) {
+        m[j] = 0;
+        y = (j < 3) ? 0 : (m[j - 3] + 2);
+        x = 27 * (j % 3);
+        int n = 0;
+        for (int i = 0; i < 32; i++) {
+            byte a = TERM_WHITE;
 
-        term_activate(old);
+            if (!is_magic((j < 1) ? player_ptr->realm1 : player_ptr->realm2)) {
+                s_ptr = &technic_info[((j < 1) ? player_ptr->realm1 : player_ptr->realm2) - MIN_TECHNIC][i % 32];
+            } else {
+                s_ptr = &mp_ptr->info[((j < 1) ? player_ptr->realm1 : player_ptr->realm2) - 1][i % 32];
+            }
+
+            const auto realm = (j < 1) ? player_ptr->realm1 : player_ptr->realm2;
+            const auto spell_name = exe_spell(player_ptr, realm, i % 32, SpellProcessType::NAME);
+            strcpy(name, spell_name->data());
+
+            if (s_ptr->slevel >= 99) {
+                strcpy(name, _("(判読不能)", "(illegible)"));
+                a = TERM_L_DARK;
+            } else if ((j < 1) ? ((player_ptr->spell_forgotten1 & (1UL << i))) : ((player_ptr->spell_forgotten2 & (1UL << (i % 32))))) {
+                a = TERM_ORANGE;
+            } else if (!((j < 1) ? (player_ptr->spell_learned1 & (1UL << i)) : (player_ptr->spell_learned2 & (1UL << (i % 32))))) {
+                a = TERM_RED;
+            } else if (!((j < 1) ? (player_ptr->spell_worked1 & (1UL << i)) : (player_ptr->spell_worked2 & (1UL << (i % 32))))) {
+                a = TERM_YELLOW;
+            }
+
+            m[j] = y + n;
+            term_putstr(x, m[j], -1, a, format("%c/%c) %-20.20s", I2A(n / 8), I2A(n % 8), name));
+            n++;
+        }
     }
 }
 
 /*!
- * @brief サブウィンドウに所持品、装備品リストの表示を行う /
- * Flip "inven" and "equip" in any sub-windows
+ * @brief 現在の習得済魔法をサブウィンドウに表示する /
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * Hack -- display spells in sub-windows
+ */
+void fix_spell(PlayerType *player_ptr)
+{
+    display_sub_windows(SubWindowRedrawingFlag::SPELL,
+        [player_ptr] {
+            display_spell_list(player_ptr);
+        });
+}
+
+/*!
+ * @brief サブウィンドウに所持品、装備品リストの表示を行う
  */
-void toggle_inventory_equipment(PlayerType *player_ptr)
+void toggle_inventory_equipment()
 {
-    for (int j = 0; j < 8; j++) {
-        if (!angband_term[j]) {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    for (auto i = 0U; i < angband_terms.size(); ++i) {
+        if (!angband_terms[i]) {
             continue;
         }
 
-        if (window_flag[j] & (PW_INVEN)) {
-            window_flag[j] &= ~(PW_INVEN);
-            window_flag[j] |= (PW_EQUIP);
-            player_ptr->window_flags |= (PW_EQUIP);
+        if (g_window_flags[i].has(SubWindowRedrawingFlag::INVENTORY)) {
+            g_window_flags[i].reset(SubWindowRedrawingFlag::INVENTORY);
+            g_window_flags[i].set(SubWindowRedrawingFlag::EQUIPMENT);
+            rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
             continue;
         }
 
-        if (window_flag[j] & PW_EQUIP) {
-            window_flag[j] &= ~(PW_EQUIP);
-            window_flag[j] |= PW_INVEN;
-            player_ptr->window_flags |= PW_INVEN;
+        if (g_window_flags[i].has(SubWindowRedrawingFlag::EQUIPMENT)) {
+            g_window_flags[i].reset(SubWindowRedrawingFlag::EQUIPMENT);
+            g_window_flags[i].set(SubWindowRedrawingFlag::INVENTORY);
+            rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
         }
     }
 }