OSDN Git Service

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