OSDN Git Service

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