OSDN Git Service

[Implement] ウサウサストライカー召喚処理を追加
[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         std::span<BaseitemInfo> candidates(baseitems_info.begin() + 1, baseitems_info.end());
52         const auto &baseitem = rand_choice(candidates);
53         *cp = baseitem.x_char;
54         *ap = baseitem.x_attr;
55         return;
56     }
57
58     *cp = rand_choice(image_objects);
59     *ap = randint1(15);
60 }
61
62 /*!
63  * @brief モンスターの表示を幻覚状態に差し替える / Mega-Hack -- Hallucinatory monster
64  * @param ap 本来の色
65  * @param cp 本来のシンボル
66  */
67 static void image_monster(TERM_COLOR *ap, char *cp)
68 {
69     if (use_graphics) {
70         auto r_idx = MonsterRace::pick_one_at_random();
71         auto *r_ptr = &monraces_info[r_idx];
72         *cp = r_ptr->x_char;
73         *ap = r_ptr->x_attr;
74         return;
75     }
76
77     *cp = one_in_(25) ? rand_choice(image_objects) : rand_choice(image_monsters);
78     *ap = randint1(15);
79 }
80
81 /*!
82  * @brief オブジェクト&モンスターの表示を幻覚状態に差し替える / Hack -- Random hallucination
83  * @param ap 本来の色
84  * @param cp 本来のシンボル
85  */
86 static void image_random(TERM_COLOR *ap, char *cp)
87 {
88     if (randint0(100) < 75) {
89         image_monster(ap, cp);
90     } else {
91         image_object(ap, cp);
92     }
93 }
94
95 /*!
96  * @brief マップに表示されるべき地形(壁)かどうかを判定する
97  * @param floor_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, int y, int x)
106 {
107     const auto &grid = floor_ptr->grid_array[y][x];
108     if (view_hidden_walls) {
109         if (view_unsafe_walls) {
110             return true;
111         }
112         if (none_bits(grid.info, CAVE_UNSAFE)) {
113             return true;
114         }
115     }
116
117     const auto &terrain = grid.get_terrain_mimic();
118     if (terrain.flags.has_not(TerrainCharacteristics::WALL) || terrain.flags.has(TerrainCharacteristics::HAS_GOLD)) {
119         return true;
120     }
121
122     if (in_bounds(floor_ptr, y, x) && terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
123         return true;
124     }
125
126     constexpr auto neighbors = 8;
127     const auto &terrains = TerrainList::get_instance();
128     auto n = 0;
129     for (auto i = 0; i < neighbors; i++) {
130         const auto dy = y + ddy_cdd[i];
131         const auto dx = x + ddx_cdd[i];
132         if (!in_bounds(floor_ptr, dy, dx)) {
133             n++;
134             continue;
135         }
136
137         const auto terrain_id = floor_ptr->grid_array[dy][dx].feat;
138         const auto &terrain_neighbor = terrains[terrain_id];
139         if (terrain_neighbor.flags.has(TerrainCharacteristics::WALL)) {
140             n++;
141         }
142     }
143
144     return n != neighbors;
145 }
146
147 /*!
148  * @brief 指定した座標の地形の表示属性を取得する
149  * @param player_ptr プレイヤー情報への参照ポインタ
150  * @param y 階の中のy座標
151  * @param x 階の中のy座標
152  * @param ap 文字色属性
153  * @param cp 文字種属性
154  * @param tap 文字色属性(タイル)
155  * @param tcp 文字種属性(タイル)
156  * @todo 強力発動コピペの嵐…ポインタ引数の嵐……Fuuu^h^hck!!
157  */
158 void map_info(PlayerType *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, char *cp, TERM_COLOR *tap, char *tcp)
159 {
160     auto &floor = *player_ptr->current_floor_ptr;
161     const Pos2D pos(y, x);
162     auto &grid = floor.get_grid(pos);
163     auto &terrains = TerrainList::get_instance();
164     auto *terrain_mimic_ptr = &grid.get_terrain_mimic();
165     TERM_COLOR a;
166     char c;
167     if (terrain_mimic_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
168         auto is_visible = any_bits(grid.info, (CAVE_MARK | CAVE_LITE | CAVE_MNLT));
169         auto is_glowing = match_bits(grid.info, CAVE_GLOW | CAVE_MNDK, CAVE_GLOW);
170         auto can_view = grid.is_view() && (is_glowing || player_ptr->see_nocto);
171         const auto is_blind = player_ptr->effects()->blindness()->is_blind();
172         if (!is_blind && (is_visible || can_view)) {
173             a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
174             c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
175             if (player_ptr->wild_mode) {
176                 if (view_special_lite && !w_ptr->is_daytime()) {
177                     a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
178                     c = terrain_mimic_ptr->x_char[F_LIT_DARK];
179                 }
180             } else if (darkened_grid(player_ptr, &grid)) {
181                 const auto unsafe_terrain_id = (view_unsafe_grids && (grid.info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
182                 terrain_mimic_ptr = &terrains[unsafe_terrain_id];
183                 a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
184                 c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
185             } else if (view_special_lite) {
186                 if (grid.info & (CAVE_LITE | CAVE_MNLT)) {
187                     if (view_yellow_lite) {
188                         a = terrain_mimic_ptr->x_attr[F_LIT_LITE];
189                         c = terrain_mimic_ptr->x_char[F_LIT_LITE];
190                     }
191                 } else if ((grid.info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
192                     a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
193                     c = terrain_mimic_ptr->x_char[F_LIT_DARK];
194                 } else if (!(grid.info & CAVE_VIEW)) {
195                     if (view_bright_lite) {
196                         a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
197                         c = terrain_mimic_ptr->x_char[F_LIT_DARK];
198                     }
199                 }
200             }
201         } else {
202             const auto unsafe_terrain_id = (view_unsafe_grids && (grid.info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
203             terrain_mimic_ptr = &terrains[unsafe_terrain_id];
204             a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
205             c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
206         }
207     } else {
208         if (grid.is_mark() && is_revealed_wall(&floor, y, x)) {
209             a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
210             c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
211             const auto is_blind = player_ptr->effects()->blindness()->is_blind();
212             if (player_ptr->wild_mode) {
213                 if (view_granite_lite && (is_blind || !w_ptr->is_daytime())) {
214                     a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
215                     c = terrain_mimic_ptr->x_char[F_LIT_DARK];
216                 }
217             } else if (darkened_grid(player_ptr, &grid) && !is_blind) {
218                 if (terrain_mimic_ptr->flags.has_all_of({ TerrainCharacteristics::LOS, TerrainCharacteristics::PROJECT })) {
219                     const auto unsafe_terrain_id = (view_unsafe_grids && (grid.info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
220                     terrain_mimic_ptr = &terrains[unsafe_terrain_id];
221                     a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
222                     c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
223                 } else if (view_granite_lite && view_bright_lite) {
224                     a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
225                     c = terrain_mimic_ptr->x_char[F_LIT_DARK];
226                 }
227             } else if (view_granite_lite) {
228                 if (is_blind) {
229                     a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
230                     c = terrain_mimic_ptr->x_char[F_LIT_DARK];
231                 } else if (grid.info & (CAVE_LITE | CAVE_MNLT)) {
232                     if (view_yellow_lite) {
233                         a = terrain_mimic_ptr->x_attr[F_LIT_LITE];
234                         c = terrain_mimic_ptr->x_char[F_LIT_LITE];
235                     }
236                 } else if (view_bright_lite) {
237                     if (!(grid.info & CAVE_VIEW)) {
238                         a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
239                         c = terrain_mimic_ptr->x_char[F_LIT_DARK];
240                     } else if ((grid.info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
241                         a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
242                         c = terrain_mimic_ptr->x_char[F_LIT_DARK];
243                     } else if (terrain_mimic_ptr->flags.has_not(TerrainCharacteristics::LOS) && !check_local_illumination(player_ptr, y, x)) {
244                         a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
245                         c = terrain_mimic_ptr->x_char[F_LIT_DARK];
246                     }
247                 }
248             }
249         } else {
250             const auto unsafe_terrain_id = (view_unsafe_grids && (grid.info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
251             terrain_mimic_ptr = &terrains[unsafe_terrain_id];
252             a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
253             c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
254         }
255     }
256
257     if (feat_priority == -1) {
258         feat_priority = terrain_mimic_ptr->priority;
259     }
260
261     (*tap) = a;
262     (*tcp) = c;
263     (*ap) = a;
264     (*cp) = c;
265
266     auto is_hallucinated = player_ptr->effects()->hallucination()->is_hallucinated();
267     if (is_hallucinated && one_in_(256)) {
268         image_random(ap, cp);
269     }
270
271     for (const auto this_o_idx : grid.o_idx_list) {
272         ItemEntity *o_ptr;
273         o_ptr = &floor.o_list[this_o_idx];
274         if (o_ptr->marked.has_not(OmType::FOUND)) {
275             continue;
276         }
277
278         if (display_autopick) {
279             byte act;
280
281             match_autopick = find_autopick_list(player_ptr, o_ptr);
282             if (match_autopick == -1) {
283                 continue;
284             }
285
286             act = autopick_list[match_autopick].action;
287
288             if ((act & DO_DISPLAY) && (act & display_autopick)) {
289                 autopick_obj = o_ptr;
290             } else {
291                 match_autopick = -1;
292                 continue;
293             }
294         }
295
296         *cp = o_ptr->get_symbol();
297         *ap = o_ptr->get_color();
298         feat_priority = 20;
299         if (is_hallucinated) {
300             image_object(ap, cp);
301         }
302
303         break;
304     }
305
306     if (grid.m_idx && display_autopick != 0) {
307         set_term_color(player_ptr, y, x, ap, cp);
308         return;
309     }
310
311     auto *m_ptr = &floor.m_list[grid.m_idx];
312     if (!m_ptr->ml) {
313         set_term_color(player_ptr, y, x, ap, cp);
314         return;
315     }
316
317     auto *r_ptr = &m_ptr->get_appearance_monrace();
318     feat_priority = 30;
319     if (is_hallucinated) {
320         if (r_ptr->visual_flags.has_all_of({ MonsterVisualType::CLEAR, MonsterVisualType::CLEAR_COLOR })) {
321             /* Do nothing */
322         } else {
323             image_monster(ap, cp);
324         }
325
326         set_term_color(player_ptr, y, x, ap, cp);
327         return;
328     }
329
330     a = r_ptr->x_attr;
331     c = r_ptr->x_char;
332     if (r_ptr->visual_flags.has_none_of({ MonsterVisualType::CLEAR, MonsterVisualType::SHAPECHANGER, MonsterVisualType::CLEAR_COLOR, MonsterVisualType::MULTI_COLOR, MonsterVisualType::RANDOM_COLOR })) {
333         *ap = a;
334         *cp = c;
335         set_term_color(player_ptr, y, x, ap, cp);
336         return;
337     }
338
339     if (r_ptr->visual_flags.has_all_of({ MonsterVisualType::CLEAR, MonsterVisualType::CLEAR_COLOR })) {
340         set_term_color(player_ptr, y, x, ap, cp);
341         return;
342     }
343
344     if (r_ptr->visual_flags.has(MonsterVisualType::CLEAR_COLOR) && (*ap != TERM_DARK) && !use_graphics) {
345         /* Do nothing */
346     } else if (r_ptr->visual_flags.has(MonsterVisualType::MULTI_COLOR) && !use_graphics) {
347         if (r_ptr->visual_flags.has(MonsterVisualType::ANY_COLOR)) {
348             *ap = randint1(15);
349         } else {
350             constexpr static auto colors = {
351                 TERM_RED,
352                 TERM_L_RED,
353                 TERM_WHITE,
354                 TERM_L_GREEN,
355                 TERM_BLUE,
356                 TERM_L_DARK,
357                 TERM_GREEN,
358             };
359
360             *ap = rand_choice(colors);
361         }
362     } else if (r_ptr->visual_flags.has(MonsterVisualType::RANDOM_COLOR) && !use_graphics) {
363         *ap = grid.m_idx % 15 + 1;
364     } else {
365         *ap = a;
366     }
367
368     if (r_ptr->visual_flags.has(MonsterVisualType::CLEAR) && (*cp != ' ') && !use_graphics) {
369         set_term_color(player_ptr, y, x, ap, cp);
370         return;
371     }
372
373     if (r_ptr->visual_flags.has(MonsterVisualType::SHAPECHANGER)) {
374         if (use_graphics) {
375             auto r_idx = MonsterRace::pick_one_at_random();
376             MonsterRaceInfo *tmp_r_ptr = &monraces_info[r_idx];
377             *cp = tmp_r_ptr->x_char;
378             *ap = tmp_r_ptr->x_attr;
379         } else {
380             *cp = one_in_(25) ? rand_choice(image_objects) : rand_choice(image_monsters);
381         }
382
383         set_term_color(player_ptr, y, x, ap, cp);
384         return;
385     }
386
387     *cp = c;
388     set_term_color(player_ptr, y, x, ap, cp);
389 }