OSDN Git Service

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