OSDN Git Service

Merge pull request #2874 from Hourier/Reshape-Wild
[hengbandforosx/hengbandosx.git] / src / window / display-sub-windows.cpp
1 #include "window/display-sub-windows.h"
2 #include "core/window-redrawer.h"
3 #include "flavor/flavor-describer.h"
4 #include "floor/cave.h"
5 #include "game-option/option-flags.h"
6 #include "game-option/special-options.h"
7 #include "game-option/text-display-options.h"
8 #include "grid/feature.h"
9 #include "inventory/inventory-describer.h"
10 #include "inventory/inventory-slot-types.h"
11 #include "inventory/inventory-util.h"
12 #include "locale/japanese.h"
13 #include "main/sound-of-music.h"
14 #include "monster-race/monster-race.h"
15 #include "monster-race/race-flags1.h"
16 #include "monster/monster-flag-types.h"
17 #include "monster/monster-info.h"
18 #include "monster/monster-status.h"
19 #include "object/item-tester-hooker.h"
20 #include "object/object-info.h"
21 #include "object/object-mark-types.h"
22 #include "player/player-status-flags.h"
23 #include "player/player-status.h"
24 #include "spell-kind/magic-item-recharger.h"
25 #include "system/baseitem-info.h"
26 #include "system/floor-type-definition.h"
27 #include "system/grid-type-definition.h"
28 #include "system/item-entity.h"
29 #include "system/monster-entity.h"
30 #include "system/monster-race-info.h"
31 #include "system/player-type-definition.h"
32 #include "system/terrain-type-definition.h"
33 #include "target/target-describer.h"
34 #include "target/target-preparation.h"
35 #include "target/target-setter.h"
36 #include "target/target-types.h"
37 #include "term/gameterm.h"
38 #include "term/screen-processor.h"
39 #include "term/term-color-types.h"
40 #include "timed-effect/player-hallucination.h"
41 #include "timed-effect/timed-effects.h"
42 #include "util/bit-flags-calculator.h"
43 #include "view/display-lore.h"
44 #include "view/display-map.h"
45 #include "view/display-messages.h"
46 #include "view/display-player.h"
47 #include "view/object-describer.h"
48 #include "window/main-window-equipments.h"
49 #include "window/main-window-util.h"
50 #include "world/world.h"
51 #include <algorithm>
52 #include <mutex>
53 #include <sstream>
54 #include <string>
55 #include <util/object-sort.h>
56
57 /*! サブウィンドウ表示用の ItemTester オブジェクト */
58 static std::unique_ptr<ItemTester> fix_item_tester = std::make_unique<AllMatchItemTester>();
59
60 FixItemTesterSetter::FixItemTesterSetter(const ItemTester &item_tester)
61 {
62     fix_item_tester = item_tester.clone();
63 }
64
65 FixItemTesterSetter::~FixItemTesterSetter()
66 {
67     fix_item_tester = std::make_unique<AllMatchItemTester>();
68 }
69
70 /*!
71  * @brief サブウィンドウに所持品一覧を表示する / Hack -- display inventory in sub-windows
72  * @param player_ptr プレイヤーへの参照ポインタ
73  */
74 void fix_inventory(PlayerType *player_ptr)
75 {
76     for (int j = 0; j < 8; j++) {
77         term_type *old = game_term;
78         if (!angband_term[j]) {
79             continue;
80         }
81
82         if (!(window_flag[j] & (PW_INVEN))) {
83             continue;
84         }
85
86         term_activate(angband_term[j]);
87         display_inventory(player_ptr, *fix_item_tester);
88         term_fresh();
89         term_activate(old);
90     }
91 }
92
93 /*!
94  * @brief モンスターの現在数を一行で表現する / Print monster info in line
95  * @param x 表示列
96  * @param y 表示行
97  * @param m_ptr 思い出を表示するモンスター情報の参照ポインタ
98  * @param n_same モンスター数の現在数
99  * @param n_awake 起きている数
100  * @details
101  * <pre>
102  * nnn X LV name
103  *  nnn : number or unique(U) or wanted unique(W)
104  *  X   : symbol of monster
105  *  LV  : monster lv if known
106  *  name: name of monster
107  * </pre>
108  */
109 static void print_monster_line(TERM_LEN x, TERM_LEN y, MonsterEntity *m_ptr, int n_same, int n_awake)
110 {
111     char buf[256];
112     MonsterRaceId r_idx = m_ptr->ap_r_idx;
113     auto *r_ptr = &monraces_info[r_idx];
114
115     term_erase(0, y, 255);
116     term_gotoxy(x, y);
117     if (!r_ptr) {
118         return;
119     }
120     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
121         sprintf(buf, _("%3s(覚%2d)", "%3s(%2d)"), MonsterRace(r_idx).is_bounty(true) ? "  W" : "  U", n_awake);
122         term_addstr(-1, TERM_WHITE, buf);
123     } else {
124         sprintf(buf, _("%3d(覚%2d)", "%3d(%2d)"), n_same, n_awake);
125         term_addstr(-1, TERM_WHITE, buf);
126     }
127
128     term_addstr(-1, TERM_WHITE, " ");
129     term_add_bigch(r_ptr->x_attr, r_ptr->x_char);
130
131     if (r_ptr->r_tkills && m_ptr->mflag2.has_not(MonsterConstantFlagType::KAGE)) {
132         sprintf(buf, " %2d", (int)r_ptr->level);
133     } else {
134         strcpy(buf, " ??");
135     }
136
137     term_addstr(-1, TERM_WHITE, buf);
138
139     sprintf(buf, " %s ", r_ptr->name.data());
140     term_addstr(-1, TERM_WHITE, buf);
141 }
142
143 /*!
144  * @brief モンスターの出現リストを表示する / Print monster info in line
145  * @param x 表示列
146  * @param y 表示行
147  * @param max_lines 最大何行描画するか
148  */
149 void print_monster_list(FloorType *floor_ptr, const std::vector<MONSTER_IDX> &monster_list, TERM_LEN x, TERM_LEN y, TERM_LEN max_lines)
150 {
151     TERM_LEN line = y;
152     struct info {
153         MonsterEntity *monster_entity;
154         int visible_count; // 現在数
155         int awake_count; // 起きている数
156     };
157
158     // 出現リスト表示用のデータ
159     std::vector<info> monster_list_info;
160
161     // 描画に必要なデータを集める
162     for (auto monster_index : monster_list) {
163         auto m_ptr = &floor_ptr->m_list[monster_index];
164
165         if (m_ptr->is_pet()) {
166             continue;
167         } // pet
168         if (!MonsterRace(m_ptr->r_idx).is_valid()) {
169             continue;
170         } // dead?
171
172         // ソート済みなので同じモンスターは連続する.これを利用して同じモンスターをカウント,まとめて表示する.
173         if (monster_list_info.empty() || (monster_list_info.back().monster_entity->ap_r_idx != m_ptr->ap_r_idx)) {
174             monster_list_info.push_back({ m_ptr, 0, 0 });
175         }
176
177         // 出現数をカウント
178         monster_list_info.back().visible_count++;
179
180         // 起きているモンスターをカウント
181         if (!m_ptr->is_asleep()) {
182             monster_list_info.back().awake_count++;
183         }
184     }
185
186     // 集めたデータを元にリストを表示する
187     for (const auto &info : monster_list_info) {
188         print_monster_line(x, line++, info.monster_entity, info.visible_count, info.awake_count);
189
190         // 行数が足りなくなったら中断。
191         if (line - y == max_lines) {
192             // 行数が足りなかった場合、最終行にその旨表示。
193             term_addstr(-1, TERM_WHITE, "-- and more --");
194             break;
195         }
196     }
197
198     for (; line < max_lines; line++) {
199         term_erase(0, line, 255);
200     }
201 }
202
203 /*!
204  * @brief 出現中モンスターのリストをサブウィンドウに表示する / Hack -- display monster list in sub-windows
205  * @param player_ptr プレイヤーへの参照ポインタ
206  */
207 void fix_monster_list(PlayerType *player_ptr)
208 {
209     static std::vector<MONSTER_IDX> monster_list;
210     std::once_flag once;
211
212     for (int j = 0; j < 8; j++) {
213         term_type *old = game_term;
214         if (!angband_term[j]) {
215             continue;
216         }
217         if (!(window_flag[j] & PW_MONSTER_LIST)) {
218             continue;
219         }
220         if (angband_term[j]->never_fresh) {
221             continue;
222         }
223
224         term_activate(angband_term[j]);
225         int w, h;
226         term_get_size(&w, &h);
227         std::call_once(once, target_sensing_monsters_prepare, player_ptr, monster_list);
228         print_monster_list(player_ptr->current_floor_ptr, monster_list, 0, 0, h);
229         term_fresh();
230         term_activate(old);
231     }
232
233     if (use_music && has_monster_music) {
234         std::call_once(once, target_sensing_monsters_prepare, player_ptr, monster_list);
235         select_monster_music(player_ptr, monster_list);
236     }
237 }
238
239 /*!
240  * @brief 装備アイテム一覧を表示する /
241  * Choice window "shadow" of the "show_equip()" function
242  */
243 static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tester)
244 {
245     if (!player_ptr || !player_ptr->inventory_list) {
246         return;
247     }
248
249     TERM_LEN wid, hgt;
250     term_get_size(&wid, &hgt);
251
252     TERM_COLOR attr = TERM_WHITE;
253     char tmp_val[80];
254     GAME_TEXT o_name[MAX_NLEN];
255     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
256         int cur_row = i - INVEN_MAIN_HAND;
257         if (cur_row >= hgt) {
258             break;
259         }
260
261         auto o_ptr = &player_ptr->inventory_list[i];
262         auto do_disp = player_ptr->select_ring_slot ? is_ring_slot(i) : item_tester.okay(o_ptr);
263         strcpy(tmp_val, "   ");
264
265         if (do_disp) {
266             tmp_val[0] = index_to_label(i);
267             tmp_val[1] = ')';
268         }
269
270         int cur_col = 3;
271         term_erase(cur_col, cur_row, 255);
272         term_putstr(0, cur_row, cur_col, TERM_WHITE, tmp_val);
273
274         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)) {
275             strcpy(o_name, _("(武器を両手持ち)", "(wielding with two-hands)"));
276             attr = TERM_WHITE;
277         } else {
278             describe_flavor(player_ptr, o_name, o_ptr, 0);
279             attr = tval_to_attr[enum2i(o_ptr->tval) % 128];
280         }
281
282         int n = strlen(o_name);
283         if (o_ptr->timeout) {
284             attr = TERM_L_DARK;
285         }
286
287         if (show_item_graph) {
288             const auto a = o_ptr->get_color();
289             const auto c = o_ptr->get_symbol();
290             term_queue_bigchar(cur_col, cur_row, a, c, 0, 0);
291             if (use_bigtile) {
292                 cur_col++;
293             }
294
295             cur_col += 2;
296         }
297
298         term_putstr(cur_col, cur_row, n, attr, o_name);
299         if (show_weights) {
300             int wgt = o_ptr->weight * o_ptr->number;
301             sprintf(tmp_val, _("%3d.%1d kg", "%3d.%1d lb"), _(lb_to_kg_integer(wgt), wgt / 10), _(lb_to_kg_fraction(wgt), wgt % 10));
302             prt(tmp_val, cur_row, wid - (show_labels ? 28 : 9));
303         }
304
305         if (show_labels) {
306             term_putstr(wid - 20, cur_row, -1, TERM_WHITE, " <-- ");
307             prt(mention_use(player_ptr, i), cur_row, wid - 15);
308         }
309     }
310
311     for (int i = INVEN_TOTAL - INVEN_MAIN_HAND; i < hgt; i++) {
312         term_erase(0, i, 255);
313     }
314 }
315
316 /*!
317  * @brief 現在の装備品をサブウィンドウに表示する /
318  * Hack -- display equipment in sub-windows
319  * @param player_ptr プレイヤーへの参照ポインタ
320  */
321 void fix_equip(PlayerType *player_ptr)
322 {
323     for (int j = 0; j < 8; j++) {
324         term_type *old = game_term;
325         if (!angband_term[j]) {
326             continue;
327         }
328         if (!(window_flag[j] & (PW_EQUIP))) {
329             continue;
330         }
331
332         term_activate(angband_term[j]);
333         display_equipment(player_ptr, *fix_item_tester);
334         term_fresh();
335         term_activate(old);
336     }
337 }
338
339 /*!
340  * @brief 現在のプレイヤーステータスをサブウィンドウに表示する /
341  * @param player_ptr プレイヤーへの参照ポインタ
342  * Hack -- display character in sub-windows
343  */
344 void fix_player(PlayerType *player_ptr)
345 {
346     for (int j = 0; j < 8; j++) {
347         term_type *old = game_term;
348         if (!angband_term[j]) {
349             continue;
350         }
351
352         if (!(window_flag[j] & (PW_PLAYER))) {
353             continue;
354         }
355
356         term_activate(angband_term[j]);
357         update_playtime();
358         (void)display_player(player_ptr, 0);
359         term_fresh();
360         term_activate(old);
361     }
362 }
363
364 /*!
365  * @brief ゲームメッセージ履歴をサブウィンドウに表示する /
366  * Hack -- display recent messages in sub-windows
367  * Adjust for width and split messages
368  */
369 void fix_message(void)
370 {
371     for (int j = 0; j < 8; j++) {
372         term_type *old = game_term;
373         if (!angband_term[j]) {
374             continue;
375         }
376
377         if (!(window_flag[j] & (PW_MESSAGE))) {
378             continue;
379         }
380
381         term_activate(angband_term[j]);
382         TERM_LEN w, h;
383         term_get_size(&w, &h);
384         for (int i = 0; i < h; i++) {
385             term_putstr(0, (h - 1) - i, -1, (byte)((i < now_message) ? TERM_WHITE : TERM_SLATE), message_str((int16_t)i));
386             TERM_LEN x, y;
387             term_locate(&x, &y);
388             term_erase(x, y, 255);
389         }
390
391         term_fresh();
392         term_activate(old);
393     }
394 }
395
396 /*!
397  * @brief 簡易マップをサブウィンドウに表示する /
398  * Hack -- display overhead view in sub-windows
399  * Adjust for width and split messages
400  * @param player_ptr プレイヤーへの参照ポインタ
401  * @details
402  * Note that the "player" symbol does NOT appear on the map.
403  */
404 void fix_overhead(PlayerType *player_ptr)
405 {
406     for (int j = 0; j < 8; j++) {
407         term_type *old = game_term;
408         TERM_LEN wid, hgt;
409         if (!angband_term[j]) {
410             continue;
411         }
412
413         if (!(window_flag[j] & (PW_OVERHEAD))) {
414             continue;
415         }
416
417         term_activate(angband_term[j]);
418         term_get_size(&wid, &hgt);
419         if (wid > COL_MAP + 2 && hgt > ROW_MAP + 2) {
420             int cy, cx;
421             display_map(player_ptr, &cy, &cx);
422             term_fresh();
423         }
424
425         term_activate(old);
426     }
427 }
428
429 /*!
430  * @brief 自分の周辺の地形をTermに表示する
431  * @param プレイヤー情報への参照ポインタ
432  */
433 static void display_dungeon(PlayerType *player_ptr)
434 {
435     TERM_COLOR ta = 0;
436     auto tc = '\0';
437
438     for (TERM_LEN x = player_ptr->x - game_term->wid / 2 + 1; x <= player_ptr->x + game_term->wid / 2; x++) {
439         for (TERM_LEN y = player_ptr->y - game_term->hgt / 2 + 1; y <= player_ptr->y + game_term->hgt / 2; y++) {
440             TERM_COLOR a;
441             char c;
442             if (!in_bounds2(player_ptr->current_floor_ptr, y, x)) {
443                 auto *f_ptr = &terrains_info[feat_none];
444                 a = f_ptr->x_attr[F_LIT_STANDARD];
445                 c = f_ptr->x_char[F_LIT_STANDARD];
446                 term_queue_char(x - player_ptr->x + game_term->wid / 2 - 1, y - player_ptr->y + game_term->hgt / 2 - 1, a, c, ta, tc);
447                 continue;
448             }
449
450             map_info(player_ptr, y, x, &a, &c, &ta, &tc);
451
452             if (!use_graphics) {
453                 if (w_ptr->timewalk_m_idx) {
454                     a = TERM_DARK;
455                 } else if (is_invuln(player_ptr) || player_ptr->timewalk) {
456                     a = TERM_WHITE;
457                 } else if (player_ptr->wraith_form) {
458                     a = TERM_L_DARK;
459                 }
460             }
461
462             term_queue_char(x - player_ptr->x + game_term->wid / 2 - 1, y - player_ptr->y + game_term->hgt / 2 - 1, a, c, ta, tc);
463         }
464     }
465 }
466
467 /*!
468  * @brief 自分の周辺のダンジョンの地形をサブウィンドウに表示する / display dungeon view around player in a sub window
469  * @param player_ptr プレイヤーへの参照ポインタ
470  */
471 void fix_dungeon(PlayerType *player_ptr)
472 {
473     for (int j = 0; j < 8; j++) {
474         term_type *old = game_term;
475         if (!angband_term[j]) {
476             continue;
477         }
478
479         if (!(window_flag[j] & (PW_DUNGEON))) {
480             continue;
481         }
482
483         term_activate(angband_term[j]);
484         display_dungeon(player_ptr);
485         term_fresh();
486         term_activate(old);
487     }
488 }
489
490 /*!
491  * @brief モンスターの思い出をサブウィンドウに表示する /
492  * Hack -- display dungeon view in sub-windows
493  * @param player_ptr プレイヤーへの参照ポインタ
494  */
495 void fix_monster(PlayerType *player_ptr)
496 {
497     for (int j = 0; j < 8; j++) {
498         term_type *old = game_term;
499         if (!angband_term[j]) {
500             continue;
501         }
502
503         if (!(window_flag[j] & (PW_MONSTER))) {
504             continue;
505         }
506
507         term_activate(angband_term[j]);
508         if (MonsterRace(player_ptr->monster_race_idx).is_valid()) {
509             display_roff(player_ptr);
510         }
511
512         term_fresh();
513         term_activate(old);
514     }
515 }
516
517 /*!
518  * @brief ベースアイテム情報をサブウィンドウに表示する /
519  * Hack -- display object recall in sub-windows
520  * @param player_ptr プレイヤーへの参照ポインタ
521  */
522 void fix_object(PlayerType *player_ptr)
523 {
524     for (int j = 0; j < 8; j++) {
525         term_type *old = game_term;
526         if (!angband_term[j]) {
527             continue;
528         }
529
530         if (!(window_flag[j] & (PW_OBJECT))) {
531             continue;
532         }
533
534         term_activate(angband_term[j]);
535         if (player_ptr->baseitem_info_idx) {
536             display_koff(player_ptr, player_ptr->baseitem_info_idx);
537         }
538
539         term_fresh();
540         term_activate(old);
541     }
542 }
543
544 /*!
545  * @brief 床上のモンスター情報を返す
546  * @param floor_ptr 階の情報への参照ポインタ
547  * @param grid_prt 座標グリッドの情報への参照ポインタ
548  * @return モンスターが見える場合にはモンスター情報への参照ポインタ、それ以外はnullptr
549  * @details
550  * Lookコマンドでカーソルを合わせた場合に合わせてミミックは考慮しない。
551  */
552 static const MonsterEntity *monster_on_floor_items(FloorType *floor_ptr, const grid_type *g_ptr)
553 {
554     if (g_ptr->m_idx == 0) {
555         return nullptr;
556     }
557
558     auto m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
559     if (!m_ptr->is_valid() || !m_ptr->ml) {
560         return nullptr;
561     }
562
563     return m_ptr;
564 }
565
566 /*!
567  * @brief 床上のアイテム一覧を作成し、表示する
568  * @param プレイヤー情報への参照ポインタ
569  * @param y 参照する座標グリッドのy座標
570  * @param x 参照する座標グリッドのx座標
571  */
572 static void display_floor_item_list(PlayerType *player_ptr, const int y, const int x)
573 {
574     // Term の行数を取得。
575     TERM_LEN term_h;
576     {
577         TERM_LEN term_w;
578         term_get_size(&term_w, &term_h);
579     }
580     if (term_h <= 0) {
581         return;
582     }
583
584     term_clear();
585     term_gotoxy(0, 0);
586
587     auto *floor_ptr = player_ptr->current_floor_ptr;
588     const auto *g_ptr = &floor_ptr->grid_array[y][x];
589     char line[1024];
590
591     // 先頭行を書く。
592     auto is_hallucinated = player_ptr->effects()->hallucination()->is_hallucinated();
593     if (player_bold(player_ptr, y, x)) {
594         sprintf(line, _("(X:%03d Y:%03d) あなたの足元のアイテム一覧", "Items at (%03d,%03d) under you"), x, y);
595     } else if (const auto *m_ptr = monster_on_floor_items(floor_ptr, g_ptr); m_ptr != nullptr) {
596         if (is_hallucinated) {
597             sprintf(line, _("(X:%03d Y:%03d) 何か奇妙な物の足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under something strange"), x, y);
598         } else {
599             const MonsterRaceInfo *const r_ptr = &monraces_info[m_ptr->ap_r_idx];
600             sprintf(line, _("(X:%03d Y:%03d) %sの足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under %s"), x, y, r_ptr->name.data());
601         }
602     } else {
603         const TerrainType *const f_ptr = &terrains_info[g_ptr->feat];
604         concptr fn = f_ptr->name.data();
605         char buf[512];
606
607         if (f_ptr->flags.has(TerrainCharacteristics::STORE) || (f_ptr->flags.has(TerrainCharacteristics::BLDG) && !floor_ptr->inside_arena)) {
608             sprintf(buf, _("%sの入口", "on the entrance of %s"), fn);
609         } else if (f_ptr->flags.has(TerrainCharacteristics::WALL)) {
610             sprintf(buf, _("%sの中", "in %s"), fn);
611         } else {
612             sprintf(buf, _("%s", "on %s"), fn);
613         }
614         sprintf(line, _("(X:%03d Y:%03d) %sの上の発見済みアイテム一覧", "Found items at (X:%03d Y:%03d) %s"), x, y, buf);
615     }
616     term_addstr(-1, TERM_WHITE, line);
617
618     // (y,x) のアイテムを1行に1個ずつ書く。
619     TERM_LEN term_y = 1;
620     for (const auto o_idx : g_ptr->o_idx_list) {
621         ItemEntity *const o_ptr = &floor_ptr->o_list[o_idx];
622
623         // 未発見アイテムおよび金は対象外。
624         if (o_ptr->marked.has_not(OmType::FOUND) || o_ptr->tval == ItemKindType::GOLD) {
625             continue;
626         }
627
628         // 途中で行数が足りなくなったら最終行にその旨追記して終了。
629         if (term_y >= term_h) {
630             term_addstr(-1, TERM_WHITE, "-- more --");
631             break;
632         }
633
634         term_gotoxy(0, term_y);
635
636         if (is_hallucinated) {
637             term_addstr(-1, TERM_WHITE, _("何か奇妙な物", "something strange"));
638         } else {
639             describe_flavor(player_ptr, line, o_ptr, 0);
640             TERM_COLOR attr = tval_to_attr[enum2i(o_ptr->tval) % 128];
641             term_addstr(-1, attr, line);
642         }
643
644         ++term_y;
645     }
646 }
647
648 /*!
649  * @brief (y,x) のアイテム一覧をサブウィンドウに表示する / display item at (y,x) in sub-windows
650  */
651 void fix_floor_item_list(PlayerType *player_ptr, const int y, const int x)
652 {
653     for (int j = 0; j < 8; j++) {
654         if (!angband_term[j]) {
655             continue;
656         }
657         if (angband_term[j]->never_fresh) {
658             continue;
659         }
660         if (!(window_flag[j] & PW_FLOOR_ITEM_LIST)) {
661             continue;
662         }
663
664         term_type *old = game_term;
665         term_activate(angband_term[j]);
666
667         display_floor_item_list(player_ptr, y, x);
668         term_fresh();
669
670         term_activate(old);
671     }
672 }
673
674 /*!
675  * @brief 発見済みのアイテム一覧を作成し、表示する
676  * @param プレイヤー情報への参照ポインタ
677  */
678 static void display_found_item_list(PlayerType *player_ptr)
679 {
680     // Term の行数を取得。
681     TERM_LEN term_h;
682     TERM_LEN term_w;
683     term_get_size(&term_w, &term_h);
684
685     if (term_h <= 0) {
686         return;
687     }
688
689     auto *floor_ptr = player_ptr->current_floor_ptr;
690
691     // 所持品一覧と同じ順にソートする
692     // あらかじめfloor_ptr->o_list から↓項目を取り除く
693     // bi_idが0
694     // OM_FOUNDフラグが立っていない
695     // ItemKindTypeがGOLD
696     std::vector<ItemEntity *> found_item_list;
697     for (auto &item : floor_ptr->o_list) {
698         auto item_entity_ptr = &item;
699         if (item_entity_ptr->bi_id > 0 && item_entity_ptr->marked.has(OmType::FOUND) && item_entity_ptr->tval != ItemKindType::GOLD) {
700             found_item_list.push_back(item_entity_ptr);
701         }
702     }
703
704     std::sort(
705         found_item_list.begin(), found_item_list.end(),
706         [player_ptr](ItemEntity *left, ItemEntity *right) -> bool {
707             return object_sort_comp(player_ptr, left, left->get_price(), right);
708         });
709
710     term_clear();
711     term_gotoxy(0, 0);
712
713     // 先頭行を書く。
714     term_addstr(-1, TERM_WHITE, _("発見済みのアイテム一覧", "Found items"));
715
716     // 発見済みのアイテムを表示
717     TERM_LEN term_y = 1;
718     for (auto item : found_item_list) {
719         // 途中で行数が足りなくなったら終了。
720         if (term_y >= term_h) {
721             break;
722         }
723
724         term_gotoxy(0, term_y);
725
726         // アイテムシンボル表示
727         const auto symbol_code = item->get_symbol();
728         const std::string symbol = format(" %c ", symbol_code);
729         const auto color_code_for_symbol = item->get_color();
730         term_addstr(-1, color_code_for_symbol, symbol.data());
731
732         // アイテム名表示
733         char temp[512];
734         describe_flavor(player_ptr, temp, item, 0);
735         const std::string item_description(temp);
736         const auto color_code_for_item = tval_to_attr[enum2i(item->tval) % 128];
737         term_addstr(-1, color_code_for_item, item_description.data());
738
739         // アイテム座標表示
740         const std::string item_location = format("(X:%3d Y:%3d)", item->ix, item->iy);
741         prt(item_location.data(), term_y, term_w - item_location.length() - 1);
742
743         ++term_y;
744     }
745 }
746
747 /*!
748  * @brief 発見済みのアイテム一覧をサブウィンドウに表示する
749  */
750 void fix_found_item_list(PlayerType *player_ptr)
751 {
752     for (int j = 0; j < 8; j++) {
753         if (!angband_term[j]) {
754             continue;
755         }
756         if (angband_term[j]->never_fresh) {
757             continue;
758         }
759         if (none_bits(window_flag[j], PW_FOUND_ITEM_LIST)) {
760             continue;
761         }
762
763         term_type *old = game_term;
764         term_activate(angband_term[j]);
765
766         display_found_item_list(player_ptr);
767         term_fresh();
768
769         term_activate(old);
770     }
771 }
772
773 /*!
774  * @brief サブウィンドウに所持品、装備品リストの表示を行う /
775  * Flip "inven" and "equip" in any sub-windows
776  */
777 void toggle_inventory_equipment(PlayerType *player_ptr)
778 {
779     for (int j = 0; j < 8; j++) {
780         if (!angband_term[j]) {
781             continue;
782         }
783
784         if (window_flag[j] & (PW_INVEN)) {
785             window_flag[j] &= ~(PW_INVEN);
786             window_flag[j] |= (PW_EQUIP);
787             player_ptr->window_flags |= (PW_EQUIP);
788             continue;
789         }
790
791         if (window_flag[j] & PW_EQUIP) {
792             window_flag[j] &= ~(PW_EQUIP);
793             window_flag[j] |= PW_INVEN;
794             player_ptr->window_flags |= PW_INVEN;
795         }
796     }
797 }