OSDN Git Service

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