OSDN Git Service

[Fix] 床置きアイテム自動破壊時にメッセージウインドウが遅れる #92
[hengbandforosx/hengbandosx.git] / src / window / display-sub-windows.c
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 "grid/grid.h"
10 #include "inventory/inventory-describer.h"
11 #include "inventory/inventory-slot-types.h"
12 #include "inventory/inventory-util.h"
13 #include "monster-race/monster-race.h"
14 #include "monster-race/race-flags1.h"
15 #include "monster/monster-flag-types.h"
16 #include "monster/monster-info.h"
17 #include "object/item-tester-hooker.h"
18 #include "object/object-info.h"
19 #include "player/player-status-flags.h"
20 #include "spell-kind/magic-item-recharger.h"
21 #include "system/floor-type-definition.h"
22 #include "system/monster-type-definition.h"
23 #include "target/target-preparation.h"
24 #include "target/target-setter.h"
25 #include "target/target-types.h"
26 #include "term/gameterm.h"
27 #include "term/screen-processor.h"
28 #include "term/term-color-types.h"
29 #include "view/display-lore.h"
30 #include "view/display-map.h"
31 #include "view/display-messages.h"
32 #include "view/display-player.h"
33 #include "view/object-describer.h"
34 #include "window/main-window-equipments.h"
35 #include "window/main-window-util.h"
36 #include "world/world.h"
37
38 /*!
39  * @brief サブウィンドウに所持品一覧を表示する / Hack -- display inventory in sub-windows
40  * @param player_ptr プレーヤーへの参照ポインタ
41  * @return なし
42  */
43 void fix_inventory(player_type *player_ptr, tval_type item_tester_tval)
44 {
45     for (int j = 0; j < 8; j++) {
46         term_type *old = Term;
47         if (!angband_term[j])
48             continue;
49
50         if (!(window_flag[j] & (PW_INVEN)))
51             continue;
52
53         term_activate(angband_term[j]);
54         display_inventory(player_ptr, item_tester_tval);
55         term_fresh();
56         term_activate(old);
57     }
58 }
59
60 /*!
61  * @brief モンスターの現在数を一行で表現する / Print monster info in line
62  * @param x 表示列
63  * @param y 表示行
64  * @param m_ptr 思い出を表示するモンスター情報の参照ポインタ
65  * @param n_same モンスターの数の現在数
66  * @details
67  * <pre>
68  * nnn X LV name
69  *  nnn : number or unique(U) or wanted unique(W)
70  *  X   : symbol of monster
71  *  LV  : monster lv if known
72  *  name: name of monster
73  * </pre>
74  * @return なし
75  */
76 static void print_monster_line(TERM_LEN x, TERM_LEN y, monster_type *m_ptr, int n_same)
77 {
78     char buf[256];
79     MONRACE_IDX r_idx = m_ptr->ap_r_idx;
80     monster_race *r_ptr = &r_info[r_idx];
81
82     term_erase(0, y, 255);
83     term_gotoxy(x, y);
84     if (!r_ptr)
85         return;
86     if (r_ptr->flags1 & RF1_UNIQUE) {
87         bool is_bounty = FALSE;
88         for (int i = 0; i < MAX_BOUNTY; i++) {
89             if (current_world_ptr->bounty_r_idx[i] == r_idx) {
90                 is_bounty = TRUE;
91                 break;
92             }
93         }
94
95         term_addstr(-1, TERM_WHITE, is_bounty ? "  W" : "  U");
96     } else {
97         sprintf(buf, "%3d", n_same);
98         term_addstr(-1, TERM_WHITE, buf);
99     }
100
101     term_addstr(-1, TERM_WHITE, " ");
102     term_add_bigch(r_ptr->x_attr, r_ptr->x_char);
103
104     if (r_ptr->r_tkills && !(m_ptr->mflag2 & MFLAG2_KAGE)) {
105         sprintf(buf, " %2d", (int)r_ptr->level);
106     } else {
107         strcpy(buf, " ??");
108     }
109
110     term_addstr(-1, TERM_WHITE, buf);
111
112     sprintf(buf, " %s ", r_name + r_ptr->name);
113     term_addstr(-1, TERM_WHITE, buf);
114 }
115
116 /*!
117  * @brief モンスターの出現リストを表示する / Print monster info in line
118  * @param x 表示列
119  * @param y 表示行
120  * @param max_lines 最大何行描画するか
121  */
122 void print_monster_list(floor_type *floor_ptr, TERM_LEN x, TERM_LEN y, TERM_LEN max_lines)
123 {
124     TERM_LEN line = y;
125     monster_type *last_mons = NULL;
126     monster_type *m_ptr = NULL;
127     int n_same = 0;
128     int i;
129     for (i = 0; i < tmp_pos.n; i++) {
130         grid_type *g_ptr = &floor_ptr->grid_array[tmp_pos.y[i]][tmp_pos.x[i]];
131         if (!g_ptr->m_idx || !floor_ptr->m_list[g_ptr->m_idx].ml)
132             continue;
133         m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
134         if (is_pet(m_ptr))
135             continue; // pet
136         if (!m_ptr->r_idx)
137             continue; // dead?
138
139         //ソート済みなので同じモンスターは連続する.これを利用して同じモンスターをカウント,まとめて表示する.
140         //先頭モンスター
141         if (!last_mons) {
142             last_mons = m_ptr;
143             n_same = 1;
144             continue;
145         }
146
147         // same race?
148         if (last_mons->ap_r_idx == m_ptr->ap_r_idx) {
149             n_same++;
150             continue; //表示処理を次に回す
151         }
152
153         // print last mons info
154         print_monster_line(x, line++, last_mons, n_same);
155         n_same = 1;
156         last_mons = m_ptr;
157         if (line - y - 1 == max_lines)
158             break;
159     }
160
161     if (line - y - 1 == max_lines && i != tmp_pos.n) {
162         term_erase(0, line, 255);
163         term_gotoxy(x, line);
164         term_addstr(-1, TERM_WHITE, "-- and more --");
165     } else {
166         if (last_mons)
167             print_monster_line(x, line++, last_mons, n_same);
168         for (; line < max_lines; line++)
169             term_erase(0, line, 255);
170     }
171 }
172
173 /*!
174  * @brief 出現中モンスターのリストをサブウィンドウに表示する / Hack -- display monster list in sub-windows
175  * @param player_ptr プレーヤーへの参照ポインタ
176  * @return なし
177  */
178 void fix_monster_list(player_type *player_ptr)
179 {
180     for (int j = 0; j < 8; j++) {
181         term_type *old = Term;
182         if (!angband_term[j])
183             continue;
184         if (!(window_flag[j] & PW_MONSTER_LIST))
185             continue;
186         if (angband_term[j]->never_fresh)
187             continue;
188
189         term_activate(angband_term[j]);
190         int w, h;
191         term_get_size(&w, &h);
192         target_set_prepare(player_ptr, TARGET_LOOK);
193         print_monster_list(player_ptr->current_floor_ptr, 0, 0, h);
194         target_clear(player_ptr);
195         term_fresh();
196         term_activate(old);
197     }
198 }
199
200 /*!
201  * @brief 装備アイテム一覧を表示する /
202  * Choice window "shadow" of the "show_equip()" function
203  * @return なし
204  */
205 static void display_equipment(player_type *owner_ptr, tval_type tval)
206 {
207     if (!owner_ptr || !owner_ptr->inventory_list)
208         return;
209
210     TERM_LEN wid, hgt;
211     term_get_size(&wid, &hgt);
212
213     TERM_COLOR attr = TERM_WHITE;
214     char tmp_val[80];
215     GAME_TEXT o_name[MAX_NLEN];
216     for (inventory_slot_type i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
217         object_type *o_ptr;
218         o_ptr = &owner_ptr->inventory_list[i];
219         tmp_val[0] = tmp_val[1] = tmp_val[2] = ' ';
220         if (owner_ptr->select_ring_slot ? is_ring_slot(i) : item_tester_okay(owner_ptr, o_ptr, tval)) {
221             tmp_val[0] = index_to_label(i);
222             tmp_val[1] = ')';
223         }
224
225         term_putstr(0, i - INVEN_MAIN_HAND, 3, TERM_WHITE, tmp_val);
226         if ((((i == INVEN_MAIN_HAND) && can_attack_with_sub_hand(owner_ptr)) || ((i == INVEN_SUB_HAND) && can_attack_with_main_hand(owner_ptr)))
227             && has_two_handed_weapons(owner_ptr)) {
228             strcpy(o_name, _("(武器を両手持ち)", "(wielding with two-hands)"));
229             attr = TERM_WHITE;
230         } else {
231             describe_flavor(owner_ptr, o_name, o_ptr, 0);
232             attr = tval_to_attr[o_ptr->tval % 128];
233         }
234
235         int n = strlen(o_name);
236         if (o_ptr->timeout)
237             attr = TERM_L_DARK;
238
239         term_putstr(3, i - INVEN_MAIN_HAND, n, attr, o_name);
240         term_erase(3 + n, i - INVEN_MAIN_HAND, 255);
241         if (show_weights) {
242             int wgt = o_ptr->weight * o_ptr->number;
243             sprintf(tmp_val, _("%3d.%1d kg", "%3d.%1d lb"), _(lbtokg1(wgt), wgt / 10), _(lbtokg2(wgt), wgt % 10));
244             prt(tmp_val, i - INVEN_MAIN_HAND, wid - (show_labels ? 28 : 9));
245         }
246
247         if (show_labels) {
248             term_putstr(wid - 20, i - INVEN_MAIN_HAND, -1, TERM_WHITE, " <-- ");
249             prt(mention_use(owner_ptr, i), i - INVEN_MAIN_HAND, wid - 15);
250         }
251     }
252
253     for (int i = INVEN_TOTAL - INVEN_MAIN_HAND; i < hgt; i++)
254         term_erase(0, i, 255);
255 }
256
257 /*!
258  * @brief 現在の装備品をサブウィンドウに表示する /
259  * Hack -- display equipment in sub-windows
260  * @param player_ptr プレーヤーへの参照ポインタ
261  * @return なし
262  */
263 void fix_equip(player_type *player_ptr, tval_type item_tester_tval)
264 {
265     for (int j = 0; j < 8; j++) {
266         term_type *old = Term;
267         if (!angband_term[j])
268             continue;
269         if (!(window_flag[j] & (PW_EQUIP)))
270             continue;
271
272         term_activate(angband_term[j]);
273         display_equipment(player_ptr, item_tester_tval);
274         term_fresh();
275         term_activate(old);
276     }
277 }
278
279 /*!
280  * @brief 現在のプレイヤーステータスをサブウィンドウに表示する /
281  * @param player_ptr プレーヤーへの参照ポインタ
282  * Hack -- display character in sub-windows
283  * @return なし
284  */
285 void fix_player(player_type *player_ptr)
286 {
287     for (int j = 0; j < 8; j++) {
288         term_type *old = Term;
289         if (!angband_term[j])
290             continue;
291
292         if (!(window_flag[j] & (PW_PLAYER)))
293             continue;
294
295         term_activate(angband_term[j]);
296         update_playtime();
297         display_player(player_ptr, 0);
298         term_fresh();
299         term_activate(old);
300     }
301 }
302
303 /*!
304  * @brief ゲームメッセージ履歴をサブウィンドウに表示する /
305  * Hack -- display recent messages in sub-windows
306  * Adjust for width and split messages
307  * @return なし
308  */
309 void fix_message(void)
310 {
311     for (int j = 0; j < 8; j++) {
312         term_type *old = Term;
313         if (!angband_term[j])
314             continue;
315
316         if (!(window_flag[j] & (PW_MESSAGE)))
317             continue;
318
319         term_activate(angband_term[j]);
320         TERM_LEN w, h;
321         term_get_size(&w, &h);
322         for (int i = 0; i < h; i++) {
323             term_putstr(0, (h - 1) - i, -1, (byte)((i < now_message) ? TERM_WHITE : TERM_SLATE), message_str((s16b)i));
324             TERM_LEN x, y;
325             term_locate(&x, &y);
326             term_erase(x, y, 255);
327         }
328
329         term_fresh();
330         term_activate(old);
331     }
332 }
333
334 /*!
335  * @brief 簡易マップをサブウィンドウに表示する /
336  * Hack -- display overhead view in sub-windows
337  * Adjust for width and split messages
338  * @param player_ptr プレーヤーへの参照ポインタ
339  * @return なし
340  * @details
341  * Note that the "player" symbol does NOT appear on the map.
342  */
343 void fix_overhead(player_type *player_ptr)
344 {
345     for (int j = 0; j < 8; j++) {
346         term_type *old = Term;
347         TERM_LEN wid, hgt;
348         if (!angband_term[j])
349             continue;
350
351         if (!(window_flag[j] & (PW_OVERHEAD)))
352             continue;
353
354         term_activate(angband_term[j]);
355         term_get_size(&wid, &hgt);
356         if (wid > COL_MAP + 2 && hgt > ROW_MAP + 2) {
357             int cy, cx;
358             display_map(player_ptr, &cy, &cx);
359             term_fresh();
360         }
361
362         term_activate(old);
363     }
364 }
365
366 static void display_dungeon(player_type *player_ptr)
367 {
368     TERM_COLOR ta = 0;
369     SYMBOL_CODE tc = '\0';
370
371     for (TERM_LEN x = player_ptr->x - Term->wid / 2 + 1; x <= player_ptr->x + Term->wid / 2; x++) {
372         for (TERM_LEN y = player_ptr->y - Term->hgt / 2 + 1; y <= player_ptr->y + Term->hgt / 2; y++) {
373             TERM_COLOR a;
374             SYMBOL_CODE c;
375             if (!in_bounds2(player_ptr->current_floor_ptr, y, x)) {
376                 feature_type *f_ptr = &f_info[feat_none];
377                 a = f_ptr->x_attr[F_LIT_STANDARD];
378                 c = f_ptr->x_char[F_LIT_STANDARD];
379                 term_queue_char(x - player_ptr->x + Term->wid / 2 - 1, y - player_ptr->y + Term->hgt / 2 - 1, a, c, ta, tc);
380                 continue;
381             }
382
383             map_info(player_ptr, y, x, &a, &c, &ta, &tc);
384
385             if (!use_graphics) {
386                 if (current_world_ptr->timewalk_m_idx)
387                     a = TERM_DARK;
388                 else if (is_invuln(player_ptr) || player_ptr->timewalk)
389                     a = TERM_WHITE;
390                 else if (player_ptr->wraith_form)
391                     a = TERM_L_DARK;
392             }
393
394             term_queue_char(x - player_ptr->x + Term->wid / 2 - 1, y - player_ptr->y + Term->hgt / 2 - 1, a, c, ta, tc);
395         }
396     }
397 }
398
399 /*!
400  * @brief ダンジョンの地形をサブウィンドウに表示する /
401  * Hack -- display dungeon view in sub-windows
402  * @param player_ptr プレーヤーへの参照ポインタ
403  * @return なし
404  */
405 void fix_dungeon(player_type *player_ptr)
406 {
407     for (int j = 0; j < 8; j++) {
408         term_type *old = Term;
409         if (!angband_term[j])
410             continue;
411
412         if (!(window_flag[j] & (PW_DUNGEON)))
413             continue;
414
415         term_activate(angband_term[j]);
416         display_dungeon(player_ptr);
417         term_fresh();
418         term_activate(old);
419     }
420 }
421
422 /*!
423  * @brief モンスターの思い出をサブウィンドウに表示する /
424  * Hack -- display dungeon view in sub-windows
425  * @param player_ptr プレーヤーへの参照ポインタ
426  * @return なし
427  */
428 void fix_monster(player_type *player_ptr)
429 {
430     for (int j = 0; j < 8; j++) {
431         term_type *old = Term;
432         if (!angband_term[j])
433             continue;
434
435         if (!(window_flag[j] & (PW_MONSTER)))
436             continue;
437
438         term_activate(angband_term[j]);
439         if (player_ptr->monster_race_idx)
440             display_roff(player_ptr);
441
442         term_fresh();
443         term_activate(old);
444     }
445 }
446
447 /*!
448  * @brief ベースアイテム情報をサブウィンドウに表示する /
449  * Hack -- display object recall in sub-windows
450  * @param player_ptr プレーヤーへの参照ポインタ
451  * @return なし
452  */
453 void fix_object(player_type *player_ptr)
454 {
455     for (int j = 0; j < 8; j++) {
456         term_type *old = Term;
457         if (!angband_term[j])
458             continue;
459
460         if (!(window_flag[j] & (PW_OBJECT)))
461             continue;
462
463         term_activate(angband_term[j]);
464         if (player_ptr->object_kind_idx)
465             display_koff(player_ptr, player_ptr->object_kind_idx);
466
467         term_fresh();
468         term_activate(old);
469     }
470 }
471
472 /*!
473  * @brief サブウィンドウに所持品、装備品リストの表示を行う /
474  * Flip "inven" and "equip" in any sub-windows
475  * @return なし
476  */
477 void toggle_inventory_equipment(player_type *owner_ptr)
478 {
479     for (int j = 0; j < 8; j++) {
480         if (!angband_term[j])
481             continue;
482
483         if (window_flag[j] & (PW_INVEN)) {
484             window_flag[j] &= ~(PW_INVEN);
485             window_flag[j] |= (PW_EQUIP);
486             owner_ptr->window_flags |= (PW_EQUIP);
487             continue;
488         }
489
490         if (window_flag[j] & PW_EQUIP) {
491             window_flag[j] &= ~(PW_EQUIP);
492             window_flag[j] |= PW_INVEN;
493             owner_ptr->window_flags |= PW_INVEN;
494         }
495     }
496 }