OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / monster-floor / monster-lite.cpp
1 #include "monster-floor/monster-lite.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "floor/cave.h"
4 #include "grid/feature-flag-types.h"
5 #include "grid/grid.h"
6 #include "monster-floor/monster-lite-util.h"
7 #include "monster-race/monster-race.h"
8 #include "monster-race/race-brightness-flags.h"
9 #include "monster-race/race-flags7.h"
10 #include "monster/monster-status.h"
11 #include "player-base/player-class.h"
12 #include "player-info/ninja-data-type.h"
13 #include "player/special-defense-types.h"
14 #include "system/dungeon-info.h"
15 #include "system/floor-type-definition.h"
16 #include "system/grid-type-definition.h"
17 #include "system/monster-entity.h"
18 #include "system/monster-race-info.h"
19 #include "system/player-type-definition.h"
20 #include "system/redrawing-flags-updater.h"
21 #include "util/point-2d.h"
22 #include "view/display-messages.h"
23 #include "world/world.h"
24 #include <vector>
25
26 /*!
27  * @brief モンスターによる光量状態更新 / Add a square to the changes array
28  * @param player_ptr プレイヤーへの参照ポインタ
29  * @param points 座標たちを記録する配列
30  * @param y Y座標
31  * @param x X座標
32  */
33 static void update_monster_lite(
34     PlayerType *const player_ptr, std::vector<Pos2D> &points, const POSITION y, const POSITION x, const monster_lite_type *const ml_ptr)
35 {
36     grid_type *g_ptr;
37     int dpf, d;
38     POSITION midpoint;
39     g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
40     if ((g_ptr->info & (CAVE_MNLT | CAVE_VIEW)) != CAVE_VIEW) {
41         return;
42     }
43
44     if (!feat_supports_los(g_ptr->feat)) {
45         if (((y < player_ptr->y) && (y > ml_ptr->mon_fy)) || ((y > player_ptr->y) && (y < ml_ptr->mon_fy))) {
46             dpf = player_ptr->y - ml_ptr->mon_fy;
47             d = y - ml_ptr->mon_fy;
48             midpoint = ml_ptr->mon_fx + ((player_ptr->x - ml_ptr->mon_fx) * std::abs(d)) / std::abs(dpf);
49             if (x < midpoint) {
50                 if (!cave_los_bold(player_ptr->current_floor_ptr, y, x + 1)) {
51                     return;
52                 }
53             } else if (x > midpoint) {
54                 if (!cave_los_bold(player_ptr->current_floor_ptr, y, x - 1)) {
55                     return;
56                 }
57             } else if (ml_ptr->mon_invis) {
58                 return;
59             }
60         }
61
62         if (((x < player_ptr->x) && (x > ml_ptr->mon_fx)) || ((x > player_ptr->x) && (x < ml_ptr->mon_fx))) {
63             dpf = player_ptr->x - ml_ptr->mon_fx;
64             d = x - ml_ptr->mon_fx;
65             midpoint = ml_ptr->mon_fy + ((player_ptr->y - ml_ptr->mon_fy) * std::abs(d)) / std::abs(dpf);
66             if (y < midpoint) {
67                 if (!cave_los_bold(player_ptr->current_floor_ptr, y + 1, x)) {
68                     return;
69                 }
70             } else if (y > midpoint) {
71                 if (!cave_los_bold(player_ptr->current_floor_ptr, y - 1, x)) {
72                     return;
73                 }
74             } else if (ml_ptr->mon_invis) {
75                 return;
76             }
77         }
78     }
79
80     if (!(g_ptr->info & CAVE_MNDK)) {
81         points.emplace_back(y, x);
82     } else {
83         g_ptr->info &= ~(CAVE_MNDK);
84     }
85
86     g_ptr->info |= CAVE_MNLT;
87 }
88
89 /*
90  * Add a square to the changes array
91  */
92 static void update_monster_dark(
93     PlayerType *const player_ptr, std::vector<Pos2D> &points, const POSITION y, const POSITION x, const monster_lite_type *const ml_ptr)
94 {
95     grid_type *g_ptr;
96     int midpoint, dpf, d;
97     g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
98     if ((g_ptr->info & (CAVE_LITE | CAVE_MNLT | CAVE_MNDK | CAVE_VIEW)) != CAVE_VIEW) {
99         return;
100     }
101
102     if (!feat_supports_los(g_ptr->feat) && !g_ptr->cave_has_flag(TerrainCharacteristics::PROJECT)) {
103         if (((y < player_ptr->y) && (y > ml_ptr->mon_fy)) || ((y > player_ptr->y) && (y < ml_ptr->mon_fy))) {
104             dpf = player_ptr->y - ml_ptr->mon_fy;
105             d = y - ml_ptr->mon_fy;
106             midpoint = ml_ptr->mon_fx + ((player_ptr->x - ml_ptr->mon_fx) * std::abs(d)) / std::abs(dpf);
107             if (x < midpoint) {
108                 if (!cave_los_bold(player_ptr->current_floor_ptr, y, x + 1) && !cave_has_flag_bold(player_ptr->current_floor_ptr, y, x + 1, TerrainCharacteristics::PROJECT)) {
109                     return;
110                 }
111             } else if (x > midpoint) {
112                 if (!cave_los_bold(player_ptr->current_floor_ptr, y, x - 1) && !cave_has_flag_bold(player_ptr->current_floor_ptr, y, x - 1, TerrainCharacteristics::PROJECT)) {
113                     return;
114                 }
115             } else if (ml_ptr->mon_invis) {
116                 return;
117             }
118         }
119
120         if (((x < player_ptr->x) && (x > ml_ptr->mon_fx)) || ((x > player_ptr->x) && (x < ml_ptr->mon_fx))) {
121             dpf = player_ptr->x - ml_ptr->mon_fx;
122             d = x - ml_ptr->mon_fx;
123             midpoint = ml_ptr->mon_fy + ((player_ptr->y - ml_ptr->mon_fy) * std::abs(d)) / std::abs(dpf);
124             if (y < midpoint) {
125                 if (!cave_los_bold(player_ptr->current_floor_ptr, y + 1, x) && !cave_has_flag_bold(player_ptr->current_floor_ptr, y + 1, x, TerrainCharacteristics::PROJECT)) {
126                     return;
127                 }
128             } else if (y > midpoint) {
129                 if (!cave_los_bold(player_ptr->current_floor_ptr, y - 1, x) && !cave_has_flag_bold(player_ptr->current_floor_ptr, y - 1, x, TerrainCharacteristics::PROJECT)) {
130                     return;
131                 }
132             } else if (ml_ptr->mon_invis) {
133                 return;
134             }
135         }
136     }
137
138     points.emplace_back(y, x);
139     g_ptr->info |= CAVE_MNDK;
140 }
141
142 /*!
143  * @brief Update squares illuminated or darkened by monsters.
144  * The CAVE_TEMP and CAVE_XTRA flag are used to store the state during the
145  * updating.  Only squares in view of the player, whos state
146  * changes are drawn via lite_spot().
147  * @todo player-status からのみ呼ばれている。しかしあちらは行数が酷いので要調整
148  */
149 void update_mon_lite(PlayerType *player_ptr)
150 {
151     // 座標たちを記録する配列。
152     std::vector<Pos2D> points;
153
154     void (*add_mon_lite)(PlayerType *, std::vector<Pos2D> &, const POSITION, const POSITION, const monster_lite_type *);
155     auto *floor_ptr = player_ptr->current_floor_ptr;
156     const auto &dungeon = floor_ptr->get_dungeon_definition();
157     auto dis_lim = (dungeon.flags.has(DungeonFeatureType::DARKNESS) && !player_ptr->see_nocto) ? (MAX_PLAYER_SIGHT / 2 + 1) : (MAX_PLAYER_SIGHT + 3);
158     for (int i = 0; i < floor_ptr->mon_lite_n; i++) {
159         grid_type *g_ptr;
160         g_ptr = &floor_ptr->grid_array[floor_ptr->mon_lite_y[i]][floor_ptr->mon_lite_x[i]];
161         g_ptr->info |= (g_ptr->info & CAVE_MNLT) ? CAVE_TEMP : CAVE_XTRA;
162         g_ptr->info &= ~(CAVE_MNLT | CAVE_MNDK);
163     }
164
165     if (!w_ptr->timewalk_m_idx) {
166         MonsterEntity *m_ptr;
167         MonsterRaceInfo *r_ptr;
168         for (int i = 1; i < floor_ptr->m_max; i++) {
169             m_ptr = &floor_ptr->m_list[i];
170             r_ptr = &monraces_info[m_ptr->r_idx];
171             if (!m_ptr->is_valid() || (m_ptr->cdis > dis_lim)) {
172                 continue;
173             }
174
175             int rad = 0;
176             if (r_ptr->brightness_flags.has_any_of({ MonsterBrightnessType::HAS_LITE_1, MonsterBrightnessType::SELF_LITE_1 })) {
177                 rad++;
178             }
179
180             if (r_ptr->brightness_flags.has_any_of({ MonsterBrightnessType::HAS_LITE_2, MonsterBrightnessType::SELF_LITE_2 })) {
181                 rad += 2;
182             }
183
184             if (r_ptr->brightness_flags.has_any_of({ MonsterBrightnessType::HAS_DARK_1, MonsterBrightnessType::SELF_DARK_1 })) {
185                 rad--;
186             }
187
188             if (r_ptr->brightness_flags.has_any_of({ MonsterBrightnessType::HAS_DARK_2, MonsterBrightnessType::SELF_DARK_2 })) {
189                 rad -= 2;
190             }
191
192             if (!rad) {
193                 continue;
194             }
195
196             TerrainCharacteristics f_flag;
197             if (rad > 0) {
198                 if (r_ptr->brightness_flags.has_none_of({ MonsterBrightnessType::SELF_LITE_1, MonsterBrightnessType::SELF_LITE_2 }) && (m_ptr->is_asleep() || (!floor_ptr->dun_level && is_daytime()) || player_ptr->phase_out)) {
199                     continue;
200                 }
201
202                 if (dungeon.flags.has(DungeonFeatureType::DARKNESS)) {
203                     rad = 1;
204                 }
205
206                 add_mon_lite = update_monster_lite;
207                 f_flag = TerrainCharacteristics::LOS;
208             } else {
209                 if (r_ptr->brightness_flags.has_none_of({ MonsterBrightnessType::SELF_DARK_1, MonsterBrightnessType::SELF_DARK_2 }) && (m_ptr->is_asleep() || (!floor_ptr->dun_level && !is_daytime()))) {
210                     continue;
211                 }
212
213                 add_mon_lite = update_monster_dark;
214                 f_flag = TerrainCharacteristics::PROJECT;
215                 rad = -rad;
216             }
217
218             monster_lite_type tmp_ml;
219             monster_lite_type *ml_ptr = initialize_monster_lite_type(floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].info, &tmp_ml, m_ptr);
220             add_mon_lite(player_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx, ml_ptr);
221             add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx, ml_ptr);
222             add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx, ml_ptr);
223             add_mon_lite(player_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx + 1, ml_ptr);
224             add_mon_lite(player_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx - 1, ml_ptr);
225             add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 1, ml_ptr);
226             add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 1, ml_ptr);
227             add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 1, ml_ptr);
228             add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 1, ml_ptr);
229             if (rad < 2) {
230                 continue;
231             }
232
233             grid_type *g_ptr;
234             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx, f_flag)) {
235                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx + 1, ml_ptr);
236                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx, ml_ptr);
237                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx - 1, ml_ptr);
238                 g_ptr = &floor_ptr->grid_array[ml_ptr->mon_fy + 2][ml_ptr->mon_fx];
239                 if ((rad == 3) && g_ptr->cave_has_flag(f_flag)) {
240                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 3, ml_ptr->mon_fx + 1, ml_ptr);
241                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 3, ml_ptr->mon_fx, ml_ptr);
242                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 3, ml_ptr->mon_fx - 1, ml_ptr);
243                 }
244             }
245
246             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx, f_flag)) {
247                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx + 1, ml_ptr);
248                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx, ml_ptr);
249                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx - 1, ml_ptr);
250                 g_ptr = &floor_ptr->grid_array[ml_ptr->mon_fy - 2][ml_ptr->mon_fx];
251                 if ((rad == 3) && g_ptr->cave_has_flag(f_flag)) {
252                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 3, ml_ptr->mon_fx + 1, ml_ptr);
253                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 3, ml_ptr->mon_fx, ml_ptr);
254                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 3, ml_ptr->mon_fx - 1, ml_ptr);
255                 }
256             }
257
258             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx + 1, f_flag)) {
259                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 2, ml_ptr);
260                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx + 2, ml_ptr);
261                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 2, ml_ptr);
262                 g_ptr = &floor_ptr->grid_array[ml_ptr->mon_fy][ml_ptr->mon_fx + 2];
263                 if ((rad == 3) && g_ptr->cave_has_flag(f_flag)) {
264                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 3, ml_ptr);
265                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx + 3, ml_ptr);
266                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 3, ml_ptr);
267                 }
268             }
269
270             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx - 1, f_flag)) {
271                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 2, ml_ptr);
272                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx - 2, ml_ptr);
273                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 2, ml_ptr);
274                 g_ptr = &floor_ptr->grid_array[ml_ptr->mon_fy][ml_ptr->mon_fx - 2];
275                 if ((rad == 3) && g_ptr->cave_has_flag(f_flag)) {
276                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 3, ml_ptr);
277                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx - 3, ml_ptr);
278                     add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 3, ml_ptr);
279                 }
280             }
281
282             if (rad != 3) {
283                 continue;
284             }
285
286             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 1, f_flag)) {
287                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx + 2, ml_ptr);
288             }
289
290             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 1, f_flag)) {
291                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx - 2, ml_ptr);
292             }
293
294             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 1, f_flag)) {
295                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx + 2, ml_ptr);
296             }
297
298             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 1, f_flag)) {
299                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx - 2, ml_ptr);
300             }
301         }
302     }
303
304     const auto end_temp = size(points);
305     for (int i = 0; i < floor_ptr->mon_lite_n; i++) {
306         POSITION fx = floor_ptr->mon_lite_x[i];
307         POSITION fy = floor_ptr->mon_lite_y[i];
308         grid_type *g_ptr;
309         g_ptr = &floor_ptr->grid_array[fy][fx];
310         if (g_ptr->info & CAVE_TEMP) {
311             if ((g_ptr->info & (CAVE_VIEW | CAVE_MNLT)) == CAVE_VIEW) {
312                 cave_note_and_redraw_later(floor_ptr, fy, fx);
313             }
314         } else if ((g_ptr->info & (CAVE_VIEW | CAVE_MNDK)) == CAVE_VIEW) {
315             cave_note_and_redraw_later(floor_ptr, fy, fx);
316         }
317
318         points.emplace_back(fy, fx);
319     }
320
321     floor_ptr->mon_lite_n = 0;
322     for (size_t i = 0; i < end_temp; i++) {
323         const auto &[fy, fx] = points[i];
324
325         grid_type *const g_ptr = &floor_ptr->grid_array[fy][fx];
326         if (g_ptr->info & CAVE_MNLT) {
327             if ((g_ptr->info & (CAVE_VIEW | CAVE_TEMP)) == CAVE_VIEW) {
328                 cave_note_and_redraw_later(floor_ptr, fy, fx);
329             }
330         } else if ((g_ptr->info & (CAVE_VIEW | CAVE_XTRA)) == CAVE_VIEW) {
331             cave_note_and_redraw_later(floor_ptr, fy, fx);
332         }
333
334         floor_ptr->mon_lite_x[floor_ptr->mon_lite_n] = fx;
335         floor_ptr->mon_lite_y[floor_ptr->mon_lite_n] = fy;
336         floor_ptr->mon_lite_n++;
337     }
338
339     for (size_t i = end_temp; i < size(points); i++) {
340         const auto &[y, x] = points[i];
341         floor_ptr->grid_array[y][x].info &= ~(CAVE_TEMP | CAVE_XTRA);
342     }
343
344     RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::DELAY_VISIBILITY);
345     player_ptr->monlite = (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_MNLT) != 0;
346     auto ninja_data = PlayerClass(player_ptr).get_specific_data<ninja_data_type>();
347     if (!ninja_data || !ninja_data->s_stealth) {
348         player_ptr->old_monlite = player_ptr->monlite;
349         return;
350     }
351
352     if (player_ptr->old_monlite == player_ptr->monlite) {
353         player_ptr->old_monlite = player_ptr->monlite;
354         return;
355     }
356
357     if (player_ptr->monlite) {
358         msg_print(_("影の覆いが薄れた気がする。", "Your mantle of shadow becomes thin."));
359     } else {
360         msg_print(_("影の覆いが濃くなった!", "Your mantle of shadow is restored to its original darkness."));
361     }
362
363     player_ptr->old_monlite = player_ptr->monlite;
364 }
365
366 /*!
367  * @brief 画面切り替え等でモンスターの灯りを消去する
368  * @param floor_ptr 現在フロアへの参照ポインタ
369  */
370 void clear_mon_lite(FloorType *floor_ptr)
371 {
372     for (int i = 0; i < floor_ptr->mon_lite_n; i++) {
373         grid_type *g_ptr;
374         g_ptr = &floor_ptr->grid_array[floor_ptr->mon_lite_y[i]][floor_ptr->mon_lite_x[i]];
375         g_ptr->info &= ~(CAVE_MNLT | CAVE_MNDK);
376     }
377
378     floor_ptr->mon_lite_n = 0;
379 }