OSDN Git Service

[Refactor] max_*_idx の代わりに *_info.size() を使用する
[hengbandforosx/hengbandosx.git] / src / view / display-map.cpp
1 #include "view/display-map.h"
2 #include "autopick/autopick-finder.h"
3 #include "autopick/autopick-methods-table.h"
4 #include "autopick/autopick-util.h"
5 #include "floor/cave.h"
6 #include "floor/geometry.h"
7 #include "game-option/map-screen-options.h"
8 #include "game-option/special-options.h"
9 #include "grid/feature.h"
10 #include "grid/grid.h"
11 #include "monster-race/monster-race.h"
12 #include "monster-race/race-flags1.h"
13 #include "monster-race/race-flags2.h"
14 #include "object/object-info.h"
15 #include "object/object-kind.h"
16 #include "object/object-mark-types.h"
17 #include "system/floor-type-definition.h"
18 #include "system/grid-type-definition.h"
19 #include "system/monster-race-definition.h"
20 #include "system/monster-type-definition.h"
21 #include "system/object-type-definition.h"
22 #include "system/player-type-definition.h"
23 #include "term/term-color-types.h"
24 #include "util/bit-flags-calculator.h"
25 #include "window/main-window-util.h"
26 #include "world/world.h"
27
28 byte display_autopick; /*!< 自動拾い状態の設定フラグ */
29
30 /* 一般的にオブジェクトシンボルとして扱われる記号を定義する(幻覚処理向け) /  Hack -- Legal object codes */
31 char image_object_hack[MAX_IMAGE_OBJECT_HACK] = "?/|\\\"!$()_-=[]{},~";
32
33 /* 一般的にモンスターシンボルとして扱われる記号を定義する(幻覚処理向け) / Hack -- Legal monster codes */
34 char image_monster_hack[MAX_IMAGE_MONSTER_HACK] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
35
36 /*!
37  * @brief オブジェクトの表示を幻覚状態に差し替える / Hallucinatory object
38  * @param ap 本来の色
39  * @param cp 本来のシンボル
40  */
41 static void image_object(TERM_COLOR *ap, SYMBOL_CODE *cp)
42 {
43     if (use_graphics) {
44         object_kind *k_ptr = &k_info[randint1(k_info.size() - 1)];
45         *cp = k_ptr->x_char;
46         *ap = k_ptr->x_attr;
47         return;
48     }
49
50     size_t n = sizeof(image_object_hack) - 1;
51     *cp = image_object_hack[randint0(n)];
52     *ap = randint1(15);
53 }
54
55 /*!
56  * @brief モンスターの表示を幻覚状態に差し替える / Mega-Hack -- Hallucinatory monster
57  * @param ap 本来の色
58  * @param cp 本来のシンボル
59  */
60 static void image_monster(TERM_COLOR *ap, SYMBOL_CODE *cp)
61 {
62     if (use_graphics) {
63         monster_race *r_ptr = &r_info[randint1(r_info.size() - 1)];
64         *cp = r_ptr->x_char;
65         *ap = r_ptr->x_attr;
66         return;
67     }
68
69     *cp = (one_in_(25) ? image_object_hack[randint0(sizeof(image_object_hack) - 1)] : image_monster_hack[randint0(sizeof(image_monster_hack) - 1)]);
70     *ap = randint1(15);
71 }
72
73 /*!
74  * @brief オブジェクト&モンスターの表示を幻覚状態に差し替える / Hack -- Random hallucination
75  * @param ap 本来の色
76  * @param cp 本来のシンボル
77  */
78 static void image_random(TERM_COLOR *ap, SYMBOL_CODE *cp)
79 {
80     if (randint0(100) < 75) {
81         image_monster(ap, cp);
82     } else {
83         image_object(ap, cp);
84     }
85 }
86
87 /*!
88  * @brief マップに表示されるべき地形(壁)かどうかを判定する
89  * @param floor_ptr 階の情報への参照ポインタ
90  * @param f_ptr 地形の情報への参照ポインタ
91  * @param y グリッドy座標
92  * @param x グリッドx座標
93  * @return 表示されるべきならtrue、そうでないならfalse
94  * @details
95  * 周り全てが壁に囲まれている壁についてはオプション状態による。
96  * 1か所でも空きがあるか、壁ではない地形、金を含む地形、永久岩は表示。
97  */
98 static bool is_revealed_wall(floor_type *floor_ptr, feature_type *f_ptr, POSITION y, POSITION x)
99 {
100     if (view_hidden_walls) {
101         if (view_unsafe_walls)
102             return true;
103         if (none_bits(floor_ptr->grid_array[y][x].info, CAVE_UNSAFE))
104             return true;
105     }
106
107     if (f_ptr->flags.has_not(FF::WALL) || f_ptr->flags.has(FF::HAS_GOLD))
108         return true;
109
110     if (in_bounds(floor_ptr, y, x) && f_ptr->flags.has(FF::PERMANENT))
111         return true;
112
113     int n = 0;
114     for (int i = 0; i < 8; i++) {
115         int dy = y + ddy_cdd[i];
116         int dx = x + ddx_cdd[i];
117         if (!in_bounds(floor_ptr, dy, dx)) {
118             n++;
119             continue;
120         }
121
122         FEAT_IDX f_idx = floor_ptr->grid_array[dy][dx].feat;
123         feature_type *n_ptr = &f_info[f_idx];
124         if (n_ptr->flags.has(FF::WALL))
125             n++;
126     }
127
128     return (n != 8);
129 }
130
131 /*!
132  * @brief 指定した座標の地形の表示属性を取得する / Extract the attr/char to display at the given (legal) map location
133  * @param player_ptr プレイヤー情報への参照ポインタ
134  * @param y 階の中のy座標
135  * @param x 階の中のy座標
136  * @param ap 文字色属性
137  * @param cp 文字種属性
138  * @param tap 文字色属性(タイル)
139  * @param tcp 文字種属性(タイル)
140  */
141 void map_info(player_type *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, SYMBOL_CODE *cp, TERM_COLOR *tap, SYMBOL_CODE *tcp)
142 {
143     floor_type *floor_ptr = player_ptr->current_floor_ptr;
144     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
145     FEAT_IDX feat = g_ptr->get_feat_mimic();
146     feature_type *f_ptr = &f_info[feat];
147     TERM_COLOR a;
148     SYMBOL_CODE c;
149     if (f_ptr->flags.has_not(FF::REMEMBER)) {
150         auto is_visible = any_bits(g_ptr->info, (CAVE_MARK | CAVE_LITE | CAVE_MNLT));
151         auto is_glowing = match_bits(g_ptr->info, CAVE_GLOW | CAVE_MNDK, CAVE_GLOW);
152         auto can_view = g_ptr->is_view() && (is_glowing || player_ptr->see_nocto);
153         if ((player_ptr->blind == 0) && (is_visible || can_view)) {
154             a = f_ptr->x_attr[F_LIT_STANDARD];
155             c = f_ptr->x_char[F_LIT_STANDARD];
156             if (player_ptr->wild_mode) {
157                 if (view_special_lite && !is_daytime()) {
158                     a = f_ptr->x_attr[F_LIT_DARK];
159                     c = f_ptr->x_char[F_LIT_DARK];
160                 }
161             } else if (darkened_grid(player_ptr, g_ptr)) {
162                 feat = (view_unsafe_grids && (g_ptr->info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
163                 f_ptr = &f_info[feat];
164                 a = f_ptr->x_attr[F_LIT_STANDARD];
165                 c = f_ptr->x_char[F_LIT_STANDARD];
166             } else if (view_special_lite) {
167                 if (g_ptr->info & (CAVE_LITE | CAVE_MNLT)) {
168                     if (view_yellow_lite) {
169                         a = f_ptr->x_attr[F_LIT_LITE];
170                         c = f_ptr->x_char[F_LIT_LITE];
171                     }
172                 } else if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
173                     a = f_ptr->x_attr[F_LIT_DARK];
174                     c = f_ptr->x_char[F_LIT_DARK];
175                 } else if (!(g_ptr->info & CAVE_VIEW)) {
176                     if (view_bright_lite) {
177                         a = f_ptr->x_attr[F_LIT_DARK];
178                         c = f_ptr->x_char[F_LIT_DARK];
179                     }
180                 }
181             }
182         } else {
183             feat = (view_unsafe_grids && (g_ptr->info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
184             f_ptr = &f_info[feat];
185             a = f_ptr->x_attr[F_LIT_STANDARD];
186             c = f_ptr->x_char[F_LIT_STANDARD];
187         }
188     } else {
189         if (g_ptr->is_mark() && is_revealed_wall(floor_ptr, f_ptr, y, x)) {
190             a = f_ptr->x_attr[F_LIT_STANDARD];
191             c = f_ptr->x_char[F_LIT_STANDARD];
192             if (player_ptr->wild_mode) {
193                 if (view_granite_lite && (player_ptr->blind || !is_daytime())) {
194                     a = f_ptr->x_attr[F_LIT_DARK];
195                     c = f_ptr->x_char[F_LIT_DARK];
196                 }
197             } else if (darkened_grid(player_ptr, g_ptr) && !player_ptr->blind) {
198                 if (f_ptr->flags.has_all_of({FF::LOS, FF::PROJECT})) {
199                     feat = (view_unsafe_grids && (g_ptr->info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
200                     f_ptr = &f_info[feat];
201                     a = f_ptr->x_attr[F_LIT_STANDARD];
202                     c = f_ptr->x_char[F_LIT_STANDARD];
203                 } else if (view_granite_lite && view_bright_lite) {
204                     a = f_ptr->x_attr[F_LIT_DARK];
205                     c = f_ptr->x_char[F_LIT_DARK];
206                 }
207             } else if (view_granite_lite) {
208                 if (player_ptr->blind) {
209                     a = f_ptr->x_attr[F_LIT_DARK];
210                     c = f_ptr->x_char[F_LIT_DARK];
211                 } else if (g_ptr->info & (CAVE_LITE | CAVE_MNLT)) {
212                     if (view_yellow_lite) {
213                         a = f_ptr->x_attr[F_LIT_LITE];
214                         c = f_ptr->x_char[F_LIT_LITE];
215                     }
216                 } else if (view_bright_lite) {
217                     if (!(g_ptr->info & CAVE_VIEW)) {
218                         a = f_ptr->x_attr[F_LIT_DARK];
219                         c = f_ptr->x_char[F_LIT_DARK];
220                     } else if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
221                         a = f_ptr->x_attr[F_LIT_DARK];
222                         c = f_ptr->x_char[F_LIT_DARK];
223                     } else if (f_ptr->flags.has_not(FF::LOS) && !check_local_illumination(player_ptr, y, x)) {
224                         a = f_ptr->x_attr[F_LIT_DARK];
225                         c = f_ptr->x_char[F_LIT_DARK];
226                     }
227                 }
228             }
229         } else {
230             feat = (view_unsafe_grids && (g_ptr->info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
231             f_ptr = &f_info[feat];
232             a = f_ptr->x_attr[F_LIT_STANDARD];
233             c = f_ptr->x_char[F_LIT_STANDARD];
234         }
235     }
236
237     if (feat_priority == -1)
238         feat_priority = f_ptr->priority;
239
240     (*tap) = a;
241     (*tcp) = c;
242     (*ap) = a;
243     (*cp) = c;
244
245     if (player_ptr->hallucinated && one_in_(256))
246         image_random(ap, cp);
247
248     for (const auto this_o_idx : g_ptr->o_idx_list) {
249         object_type *o_ptr;
250         o_ptr = &floor_ptr->o_list[this_o_idx];
251         if (!(o_ptr->marked & OM_FOUND))
252             continue;
253
254         if (display_autopick) {
255             byte act;
256
257             match_autopick = find_autopick_list(player_ptr, o_ptr);
258             if (match_autopick == -1)
259                 continue;
260
261             act = autopick_list[match_autopick].action;
262
263             if ((act & DO_DISPLAY) && (act & display_autopick)) {
264                 autopick_obj = o_ptr;
265             } else {
266                 match_autopick = -1;
267                 continue;
268             }
269         }
270
271         (*cp) = object_char(o_ptr);
272         (*ap) = object_attr(o_ptr);
273         feat_priority = 20;
274         if (player_ptr->hallucinated)
275             image_object(ap, cp);
276
277         break;
278     }
279
280     if (g_ptr->m_idx && display_autopick != 0) {
281         set_term_color(player_ptr, y, x, ap, cp);
282         return;
283     }
284
285     monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
286     if (!m_ptr->ml) {
287         set_term_color(player_ptr, y, x, ap, cp);
288         return;
289     }
290
291     monster_race *r_ptr = &r_info[m_ptr->ap_r_idx];
292     feat_priority = 30;
293     if (player_ptr->hallucinated) {
294         if ((r_ptr->flags1 & (RF1_CHAR_CLEAR | RF1_ATTR_CLEAR)) == (RF1_CHAR_CLEAR | RF1_ATTR_CLEAR)) {
295             /* Do nothing */
296         } else {
297             image_monster(ap, cp);
298         }
299
300         set_term_color(player_ptr, y, x, ap, cp);
301         return;
302     }
303
304     a = r_ptr->x_attr;
305     c = r_ptr->x_char;
306     if (!(r_ptr->flags1 & (RF1_CHAR_CLEAR | RF1_SHAPECHANGER | RF1_ATTR_CLEAR | RF1_ATTR_MULTI | RF1_ATTR_SEMIRAND))) {
307         *ap = a;
308         *cp = c;
309         set_term_color(player_ptr, y, x, ap, cp);
310         return;
311     }
312
313     if ((r_ptr->flags1 & (RF1_CHAR_CLEAR | RF1_ATTR_CLEAR)) == (RF1_CHAR_CLEAR | RF1_ATTR_CLEAR)) {
314         set_term_color(player_ptr, y, x, ap, cp);
315         return;
316     }
317
318     if ((r_ptr->flags1 & RF1_ATTR_CLEAR) && (*ap != TERM_DARK) && !use_graphics) {
319         /* Do nothing */
320     } else if ((r_ptr->flags1 & RF1_ATTR_MULTI) && !use_graphics) {
321         if (r_ptr->flags2 & RF2_ATTR_ANY)
322             *ap = randint1(15);
323         else
324             switch (randint1(7)) {
325             case 1:
326                 *ap = TERM_RED;
327                 break;
328             case 2:
329                 *ap = TERM_L_RED;
330                 break;
331             case 3:
332                 *ap = TERM_WHITE;
333                 break;
334             case 4:
335                 *ap = TERM_L_GREEN;
336                 break;
337             case 5:
338                 *ap = TERM_BLUE;
339                 break;
340             case 6:
341                 *ap = TERM_L_DARK;
342                 break;
343             case 7:
344                 *ap = TERM_GREEN;
345                 break;
346             }
347     } else if ((r_ptr->flags1 & RF1_ATTR_SEMIRAND) && !use_graphics) {
348         *ap = g_ptr->m_idx % 15 + 1;
349     } else {
350         *ap = a;
351     }
352
353     if ((r_ptr->flags1 & RF1_CHAR_CLEAR) && (*cp != ' ') && !use_graphics) {
354         set_term_color(player_ptr, y, x, ap, cp);
355         return;
356     }
357
358     if (r_ptr->flags1 & RF1_SHAPECHANGER) {
359         if (use_graphics) {
360             monster_race *tmp_r_ptr = &r_info[randint1(r_info.size() - 1)];
361             *cp = tmp_r_ptr->x_char;
362             *ap = tmp_r_ptr->x_attr;
363         } else {
364             *cp = (one_in_(25) ? image_object_hack[randint0(sizeof(image_object_hack) - 1)] : image_monster_hack[randint0(sizeof(image_monster_hack) - 1)]);
365         }
366
367         set_term_color(player_ptr, y, x, ap, cp);
368         return;
369     }
370
371     *cp = c;
372     set_term_color(player_ptr, y, x, ap, cp);
373 }