OSDN Git Service

[Refactor] #3230 PlayerType::update に関わる処理を、RedrawingFlagsUpdaterに集約した
[hengbandforosx/hengbandosx.git] / src / monster / monster-update.cpp
1 /*!
2  * @brief モンスター情報のアップデート処理
3  * @date 2020/03/08
4  * @author Hourier
5  */
6
7 #include "monster/monster-update.h"
8 #include "core/disturbance.h"
9 #include "core/player-redraw-types.h"
10 #include "core/player-update-types.h"
11 #include "core/window-redrawer.h"
12 #include "dungeon/dungeon-flag-types.h"
13 #include "floor/cave.h"
14 #include "floor/geometry.h"
15 #include "game-option/birth-options.h"
16 #include "game-option/disturbance-options.h"
17 #include "grid/grid.h"
18 #include "mind/drs-types.h"
19 #include "monster-race/monster-race.h"
20 #include "monster-race/race-brightness-flags.h"
21 #include "monster-race/race-brightness-mask.h"
22 #include "monster-race/race-flags1.h"
23 #include "monster-race/race-flags2.h"
24 #include "monster-race/race-flags3.h"
25 #include "monster-race/race-flags7.h"
26 #include "monster-race/race-indice-types.h"
27 #include "monster/monster-flag-types.h"
28 #include "monster/monster-info.h"
29 #include "monster/monster-processor-util.h"
30 #include "monster/monster-status.h"
31 #include "monster/smart-learn-types.h"
32 #include "player-base/player-class.h"
33 #include "player-info/samurai-data-type.h"
34 #include "player-info/sniper-data-type.h"
35 #include "player/player-move.h"
36 #include "player/player-status-flags.h"
37 #include "player/special-defense-types.h"
38 #include "status/element-resistance.h"
39 #include "system/dungeon-info.h"
40 #include "system/floor-type-definition.h"
41 #include "system/grid-type-definition.h"
42 #include "system/monster-entity.h"
43 #include "system/monster-race-info.h"
44 #include "system/player-type-definition.h"
45 #include "system/redrawing-flags-updater.h"
46 #include "target/projection-path-calculator.h"
47 #include "timed-effect/player-blindness.h"
48 #include "timed-effect/player-hallucination.h"
49 #include "timed-effect/timed-effects.h"
50 #include "util/bit-flags-calculator.h"
51 #include "world/world.h"
52
53 // Update Monster.
54 struct um_type {
55     MonsterEntity *m_ptr;
56     bool do_disturb;
57     POSITION fy;
58     POSITION fx;
59     bool flag;
60     bool easy;
61     bool in_darkness;
62     bool full;
63 };
64
65 /*!
66  * @brief 騎乗中のモンスター情報を更新する
67  * @param player_ptr プレイヤーへの参照ポインタ
68  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
69  * @param m_idx モンスターID
70  * @param oy 移動前の、モンスターのY座標
71  * @param ox 移動前の、モンスターのX座標
72  * @param ny 移動後の、モンスターのY座標
73  * @param ox 移動後の、モンスターのX座標
74  * @return アイテム等に影響を及ぼしたらTRUE
75  */
76 bool update_riding_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, POSITION oy, POSITION ox, POSITION ny, POSITION nx)
77 {
78     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
79     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
80     MonsterEntity *y_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
81     if (turn_flags_ptr->is_riding_mon) {
82         return move_player_effect(player_ptr, ny, nx, MPE_DONT_PICKUP);
83     }
84
85     player_ptr->current_floor_ptr->grid_array[oy][ox].m_idx = g_ptr->m_idx;
86     if (g_ptr->m_idx) {
87         y_ptr->fy = oy;
88         y_ptr->fx = ox;
89         update_monster(player_ptr, g_ptr->m_idx, true);
90     }
91
92     g_ptr->m_idx = m_idx;
93     m_ptr->fy = ny;
94     m_ptr->fx = nx;
95     update_monster(player_ptr, m_idx, true);
96
97     lite_spot(player_ptr, oy, ox);
98     lite_spot(player_ptr, ny, nx);
99     return true;
100 }
101
102 /*!
103  * @brief updateフィールドを更新する
104  * @param player_ptr プレイヤーへの参照ポインタ
105  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
106  */
107 void update_player_type(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterRaceInfo *r_ptr)
108 {
109     using Mbt = MonsterBrightnessType;
110     const auto except_has_lite = EnumClassFlagGroup<Mbt>(self_ld_mask).set({ Mbt::HAS_DARK_1, Mbt::HAS_DARK_2 });
111     auto &rfu = RedrawingFlagsUpdater::get_instance();
112     if (turn_flags_ptr->do_view) {
113         rfu.set_flag(StatusRedrawingFlag::FLOW);
114         player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
115     }
116
117     const auto has_lite = r_ptr->brightness_flags.has_any_of({ Mbt::HAS_LITE_1, Mbt::HAS_LITE_2 });
118     if (turn_flags_ptr->do_move && (r_ptr->brightness_flags.has_any_of(except_has_lite) || (has_lite && !player_ptr->phase_out))) {
119         rfu.set_flag(StatusRedrawingFlag::MONSTER_LITE);
120     }
121 }
122
123 /*!
124  * @brief モンスターのフラグを更新する
125  * @param player_ptr プレイヤーへの参照ポインタ
126  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
127  * @param m_ptr モンスターへの参照ポインタ
128  */
129 void update_monster_race_flags(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr)
130 {
131     auto *r_ptr = &monraces_info[m_ptr->r_idx];
132     if (!is_original_ap_and_seen(player_ptr, m_ptr)) {
133         return;
134     }
135
136     if (turn_flags_ptr->did_open_door) {
137         r_ptr->r_behavior_flags.set(MonsterBehaviorType::OPEN_DOOR);
138     }
139
140     if (turn_flags_ptr->did_bash_door) {
141         r_ptr->r_behavior_flags.set(MonsterBehaviorType::BASH_DOOR);
142     }
143
144     if (turn_flags_ptr->did_take_item) {
145         r_ptr->r_behavior_flags.set(MonsterBehaviorType::TAKE_ITEM);
146     }
147
148     if (turn_flags_ptr->did_kill_item) {
149         r_ptr->r_behavior_flags.set(MonsterBehaviorType::KILL_ITEM);
150     }
151
152     if (turn_flags_ptr->did_move_body) {
153         r_ptr->r_behavior_flags.set(MonsterBehaviorType::MOVE_BODY);
154     }
155
156     if (turn_flags_ptr->did_pass_wall) {
157         r_ptr->r_feature_flags.set(MonsterFeatureType::PASS_WALL);
158     }
159
160     if (turn_flags_ptr->did_kill_wall) {
161         r_ptr->r_feature_flags.set(MonsterFeatureType::KILL_WALL);
162     }
163 }
164
165 /*!
166  * @brief モンスターフラグの更新に基づき、モンスター表示を更新する
167  * @param monster_race_idx モンスターID
168  * @param window ウィンドウフラグ
169  * @param old_race_flags_ptr モンスターフラグへの参照ポインタ
170  */
171 void update_player_window(PlayerType *player_ptr, old_race_flags *old_race_flags_ptr)
172 {
173     MonsterRaceInfo *r_ptr;
174     r_ptr = &monraces_info[player_ptr->monster_race_idx];
175     if ((old_race_flags_ptr->old_r_flags1 != r_ptr->r_flags1) || (old_race_flags_ptr->old_r_flags2 != r_ptr->r_flags2) ||
176         (old_race_flags_ptr->old_r_flags3 != r_ptr->r_flags3) || (old_race_flags_ptr->old_r_ability_flags != r_ptr->r_ability_flags) ||
177         (old_race_flags_ptr->old_r_resistance_flags != r_ptr->r_resistance_flags) || (old_race_flags_ptr->old_r_blows0 != r_ptr->r_blows[0]) ||
178         (old_race_flags_ptr->old_r_blows1 != r_ptr->r_blows[1]) || (old_race_flags_ptr->old_r_blows2 != r_ptr->r_blows[2]) ||
179         (old_race_flags_ptr->old_r_blows3 != r_ptr->r_blows[3]) || (old_race_flags_ptr->old_r_cast_spell != r_ptr->r_cast_spell) ||
180         (old_race_flags_ptr->old_r_behavior_flags != r_ptr->r_behavior_flags) || (old_race_flags_ptr->old_r_kind_flags != r_ptr->r_kind_flags) ||
181         (old_race_flags_ptr->old_r_drop_flags != r_ptr->r_drop_flags) || (old_race_flags_ptr->old_r_feature_flags != r_ptr->r_feature_flags)) {
182         player_ptr->window_flags |= PW_MONSTER_LORE;
183     }
184 }
185
186 static um_type *initialize_um_type(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx, bool full)
187 {
188     um_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
189     um_ptr->do_disturb = disturb_move;
190     um_ptr->fy = um_ptr->m_ptr->fy;
191     um_ptr->fx = um_ptr->m_ptr->fx;
192     um_ptr->flag = false;
193     um_ptr->easy = false;
194     um_ptr->in_darkness = dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS) && !player_ptr->see_nocto;
195     um_ptr->full = full;
196     return um_ptr;
197 }
198
199 static POSITION decide_updated_distance(PlayerType *player_ptr, um_type *um_ptr)
200 {
201     if (!um_ptr->full) {
202         return um_ptr->m_ptr->cdis;
203     }
204
205     int dy = (player_ptr->y > um_ptr->fy) ? (player_ptr->y - um_ptr->fy) : (um_ptr->fy - player_ptr->y);
206     int dx = (player_ptr->x > um_ptr->fx) ? (player_ptr->x - um_ptr->fx) : (um_ptr->fx - player_ptr->x);
207     POSITION distance = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
208     if (distance > 255) {
209         distance = 255;
210     }
211
212     if (!distance) {
213         distance = 1;
214     }
215
216     um_ptr->m_ptr->cdis = distance;
217     return distance;
218 }
219
220 static void update_smart_stupid_flags(MonsterRaceInfo *r_ptr)
221 {
222     if (r_ptr->r_behavior_flags.has(MonsterBehaviorType::SMART)) {
223         r_ptr->r_behavior_flags.set(MonsterBehaviorType::SMART);
224     }
225
226     if (r_ptr->r_behavior_flags.has(MonsterBehaviorType::STUPID)) {
227         r_ptr->r_behavior_flags.set(MonsterBehaviorType::STUPID);
228     }
229 }
230
231 /*!
232  * @brief WEIRD_MINDフラグ持ちのモンスターを1/10の確率でテレパシーに引っかける
233  * @param player_ptr プレイヤーへの参照ポインタ
234  * @param um_ptr モンスター情報アップデート構造体への参照ポインタ
235  * @param m_idx モンスターID
236  * @return WEIRD_MINDフラグがあるならTRUE
237  */
238 static bool update_weird_telepathy(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx)
239 {
240     auto *m_ptr = um_ptr->m_ptr;
241     auto *r_ptr = &monraces_info[m_ptr->r_idx];
242     if ((r_ptr->flags2 & RF2_WEIRD_MIND) == 0) {
243         return false;
244     }
245
246     if ((m_idx % 10) != (w_ptr->game_turn % 10)) {
247         return true;
248     }
249
250     um_ptr->flag = true;
251     m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
252     if (m_ptr->is_original_ap() && !player_ptr->effects()->hallucination()->is_hallucinated()) {
253         r_ptr->r_flags2 |= RF2_WEIRD_MIND;
254         update_smart_stupid_flags(r_ptr);
255     }
256
257     return true;
258 }
259
260 static void update_telepathy_sight(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx)
261 {
262     auto *m_ptr = um_ptr->m_ptr;
263     auto *r_ptr = &monraces_info[m_ptr->r_idx];
264     if (PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU)) {
265         um_ptr->flag = true;
266         um_ptr->m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
267         if (um_ptr->m_ptr->is_original_ap() && !player_ptr->effects()->hallucination()->is_hallucinated()) {
268             update_smart_stupid_flags(r_ptr);
269         }
270
271         return;
272     }
273
274     if (!player_ptr->telepathy) {
275         return;
276     }
277
278     auto is_hallucinated = player_ptr->effects()->hallucination()->is_hallucinated();
279     if (r_ptr->flags2 & RF2_EMPTY_MIND) {
280         if (m_ptr->is_original_ap() && !is_hallucinated) {
281             r_ptr->r_flags2 |= RF2_EMPTY_MIND;
282         }
283
284         return;
285     }
286
287     if (update_weird_telepathy(player_ptr, um_ptr, m_idx)) {
288         return;
289     }
290
291     um_ptr->flag = true;
292     m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
293     if (m_ptr->is_original_ap() && !is_hallucinated) {
294         update_smart_stupid_flags(r_ptr);
295     }
296 }
297
298 static void update_specific_race_telepathy(PlayerType *player_ptr, um_type *um_ptr)
299 {
300     auto *m_ptr = um_ptr->m_ptr;
301     auto *r_ptr = &monraces_info[m_ptr->r_idx];
302     auto is_hallucinated = player_ptr->effects()->hallucination()->is_hallucinated();
303     if ((player_ptr->esp_animal) && r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
304         um_ptr->flag = true;
305         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
306         if (m_ptr->is_original_ap() && !is_hallucinated) {
307             r_ptr->r_kind_flags.set(MonsterKindType::ANIMAL);
308         }
309     }
310
311     if ((player_ptr->esp_undead) && r_ptr->kind_flags.has(MonsterKindType::UNDEAD)) {
312         um_ptr->flag = true;
313         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
314         if (m_ptr->is_original_ap() && !is_hallucinated) {
315             r_ptr->r_kind_flags.set(MonsterKindType::UNDEAD);
316         }
317     }
318
319     if ((player_ptr->esp_demon) && r_ptr->kind_flags.has(MonsterKindType::DEMON)) {
320         um_ptr->flag = true;
321         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
322         if (m_ptr->is_original_ap() && !is_hallucinated) {
323             r_ptr->r_kind_flags.set(MonsterKindType::DEMON);
324         }
325     }
326
327     if ((player_ptr->esp_orc) && r_ptr->kind_flags.has(MonsterKindType::ORC)) {
328         um_ptr->flag = true;
329         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
330         if (m_ptr->is_original_ap() && !is_hallucinated) {
331             r_ptr->r_kind_flags.set(MonsterKindType::ORC);
332         }
333     }
334
335     if ((player_ptr->esp_troll) && r_ptr->kind_flags.has(MonsterKindType::TROLL)) {
336         um_ptr->flag = true;
337         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
338         if (m_ptr->is_original_ap() && !is_hallucinated) {
339             r_ptr->r_kind_flags.set(MonsterKindType::TROLL);
340         }
341     }
342
343     if ((player_ptr->esp_giant) && r_ptr->kind_flags.has(MonsterKindType::GIANT)) {
344         um_ptr->flag = true;
345         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
346         if (m_ptr->is_original_ap() && !is_hallucinated) {
347             r_ptr->r_kind_flags.set(MonsterKindType::GIANT);
348         }
349     }
350
351     if ((player_ptr->esp_dragon) && r_ptr->kind_flags.has(MonsterKindType::DRAGON)) {
352         um_ptr->flag = true;
353         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
354         if (m_ptr->is_original_ap() && !is_hallucinated) {
355             r_ptr->r_kind_flags.set(MonsterKindType::DRAGON);
356         }
357     }
358
359     if ((player_ptr->esp_human) && r_ptr->kind_flags.has(MonsterKindType::HUMAN)) {
360         um_ptr->flag = true;
361         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
362         if (m_ptr->is_original_ap() && !is_hallucinated) {
363             r_ptr->r_kind_flags.set(MonsterKindType::HUMAN);
364         }
365     }
366
367     if ((player_ptr->esp_evil) && r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
368         um_ptr->flag = true;
369         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
370         if (m_ptr->is_original_ap() && !is_hallucinated) {
371             r_ptr->r_kind_flags.set(MonsterKindType::EVIL);
372         }
373     }
374
375     if ((player_ptr->esp_good) && r_ptr->kind_flags.has(MonsterKindType::GOOD)) {
376         um_ptr->flag = true;
377         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
378         if (m_ptr->is_original_ap() && !is_hallucinated) {
379             r_ptr->r_kind_flags.set(MonsterKindType::GOOD);
380         }
381     }
382
383     if ((player_ptr->esp_nonliving) && r_ptr->kind_flags.has(MonsterKindType::NONLIVING) && r_ptr->kind_flags.has_none_of({ MonsterKindType::DEMON, MonsterKindType::UNDEAD })) {
384         um_ptr->flag = true;
385         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
386         if (m_ptr->is_original_ap() && !is_hallucinated) {
387             r_ptr->r_kind_flags.set(MonsterKindType::NONLIVING);
388         }
389     }
390
391     if ((player_ptr->esp_unique) && r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
392         um_ptr->flag = true;
393         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
394         if (m_ptr->is_original_ap() && !is_hallucinated) {
395             r_ptr->r_kind_flags.set(MonsterKindType::UNIQUE);
396         }
397     }
398 }
399
400 static bool check_cold_blood(PlayerType *player_ptr, um_type *um_ptr, const POSITION distance)
401 {
402     if (distance > player_ptr->see_infra) {
403         return false;
404     }
405
406     auto *r_ptr = &monraces_info[um_ptr->m_ptr->r_idx];
407     if (any_bits(r_ptr->flags2, RF2_COLD_BLOOD) && r_ptr->aura_flags.has_not(MonsterAuraType::FIRE)) {
408         return false;
409     }
410
411     um_ptr->easy = true;
412     um_ptr->flag = true;
413     return true;
414 }
415
416 static bool check_invisible(PlayerType *player_ptr, um_type *um_ptr)
417 {
418     if (!player_can_see_bold(player_ptr, um_ptr->fy, um_ptr->fx)) {
419         return false;
420     }
421
422     auto *r_ptr = &monraces_info[um_ptr->m_ptr->r_idx];
423     if (r_ptr->flags2 & RF2_INVISIBLE) {
424         if (player_ptr->see_inv) {
425             um_ptr->easy = true;
426             um_ptr->flag = true;
427         }
428     } else {
429         um_ptr->easy = true;
430         um_ptr->flag = true;
431     }
432
433     return true;
434 }
435
436 /*!
437  * @brief テレパシー・赤外線視力・可視透明によってモンスターを感知できるかどうかの判定
438  * @param player_ptr プレイヤーへの参照ポインタ
439  * @param um_ptr モンスター情報アップデート構造体への参照ポインタ
440  */
441 static void decide_sight_invisible_monster(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx)
442 {
443     POSITION distance = decide_updated_distance(player_ptr, um_ptr);
444     auto *m_ptr = um_ptr->m_ptr;
445     auto *r_ptr = &monraces_info[m_ptr->r_idx];
446
447     m_ptr->mflag.reset(MonsterTemporaryFlagType::ESP);
448
449     if (distance > (um_ptr->in_darkness ? MAX_PLAYER_SIGHT / 2 : MAX_PLAYER_SIGHT)) {
450         return;
451     }
452
453     if (!um_ptr->in_darkness || (distance <= MAX_PLAYER_SIGHT / 4)) {
454         update_telepathy_sight(player_ptr, um_ptr, m_idx);
455         update_specific_race_telepathy(player_ptr, um_ptr);
456     }
457
458     if (!player_has_los_bold(player_ptr, um_ptr->fy, um_ptr->fx) || player_ptr->effects()->blindness()->is_blind()) {
459         return;
460     }
461
462     auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
463     if (sniper_data && (sniper_data->concent >= CONCENT_RADAR_THRESHOLD)) {
464         um_ptr->easy = true;
465         um_ptr->flag = true;
466     }
467
468     bool do_cold_blood = check_cold_blood(player_ptr, um_ptr, distance);
469     bool do_invisible = check_invisible(player_ptr, um_ptr);
470     if (!um_ptr->flag || !m_ptr->is_original_ap() || player_ptr->effects()->hallucination()->is_hallucinated()) {
471         return;
472     }
473
474     if (do_invisible) {
475         r_ptr->r_flags2 |= RF2_INVISIBLE;
476     }
477
478     if (do_cold_blood) {
479         r_ptr->r_flags2 |= RF2_COLD_BLOOD;
480     }
481 }
482
483 /*!
484  * @brief 壁の向こうにいるモンスターへのテレパシー・赤外線視力による冷血動物以外の透明モンスター・可視透明能力による透明モンスター
485  * 以上を感知する
486  * @param player_ptr プレイヤーへの参照ポインタ
487  * @param um_ptr モンスター情報アップデート構造体への参照ポインタ
488  * @param m_idx フロアのモンスター番号
489  * @details 感知した結果、エルドリッチホラー持ちがいたら精神を破壊する
490  */
491 static void update_invisible_monster(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx)
492 {
493     auto *m_ptr = um_ptr->m_ptr;
494     if (m_ptr->ml) {
495         return;
496     }
497
498     m_ptr->ml = true;
499     lite_spot(player_ptr, um_ptr->fy, um_ptr->fx);
500
501     if (player_ptr->health_who == m_idx) {
502         player_ptr->redraw |= PR_HEALTH;
503     }
504
505     if (player_ptr->riding == m_idx) {
506         player_ptr->redraw |= PR_UHEALTH;
507     }
508
509     if (!player_ptr->effects()->hallucination()->is_hallucinated()) {
510         auto *r_ptr = &monraces_info[m_ptr->r_idx];
511         if ((m_ptr->ap_r_idx == MonsterRaceId::KAGE) && (monraces_info[MonsterRaceId::KAGE].r_sights < MAX_SHORT)) {
512             monraces_info[MonsterRaceId::KAGE].r_sights++;
513         } else if (m_ptr->is_original_ap() && (r_ptr->r_sights < MAX_SHORT)) {
514             r_ptr->r_sights++;
515         }
516     }
517
518     if (w_ptr->is_loading_now && w_ptr->character_dungeon && !player_ptr->phase_out && monraces_info[m_ptr->ap_r_idx].flags2 & RF2_ELDRITCH_HORROR) {
519         m_ptr->mflag.set(MonsterTemporaryFlagType::SANITY_BLAST);
520     }
521
522     const auto projectable_from_monster = projectable(player_ptr, m_ptr->fy, m_ptr->fx, player_ptr->y, player_ptr->x);
523     const auto projectable_from_player = projectable(player_ptr, player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx);
524     if (disturb_near && projectable_from_monster && projectable_from_player) {
525         if (disturb_pets || m_ptr->is_hostile()) {
526             disturb(player_ptr, true, true);
527         }
528     }
529 }
530
531 static void update_visible_monster(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx)
532 {
533     if (!um_ptr->m_ptr->ml) {
534         return;
535     }
536
537     um_ptr->m_ptr->ml = false;
538     lite_spot(player_ptr, um_ptr->fy, um_ptr->fx);
539
540     if (player_ptr->health_who == m_idx) {
541         player_ptr->redraw |= PR_HEALTH;
542     }
543
544     if (player_ptr->riding == m_idx) {
545         player_ptr->redraw |= PR_UHEALTH;
546     }
547
548     if (um_ptr->do_disturb && (disturb_pets || um_ptr->m_ptr->is_hostile())) {
549         disturb(player_ptr, true, true);
550     }
551 }
552
553 static bool update_clear_monster(PlayerType *player_ptr, um_type *um_ptr)
554 {
555     if (!um_ptr->easy) {
556         return false;
557     }
558
559     if (um_ptr->m_ptr->mflag.has_not(MonsterTemporaryFlagType::VIEW)) {
560         um_ptr->m_ptr->mflag.set(MonsterTemporaryFlagType::VIEW);
561         if (um_ptr->do_disturb && (disturb_pets || um_ptr->m_ptr->is_hostile())) {
562             disturb(player_ptr, true, true);
563         }
564     }
565
566     return true;
567 }
568
569 /*!
570  * @brief モンスターの各情報を更新する / This function updates the monster record of the given monster
571  * @param m_idx 更新するモンスター情報のID
572  * @param full プレイヤーとの距離更新を行うならばtrue
573  */
574 void update_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool full)
575 {
576     um_type tmp_um;
577     um_type *um_ptr = initialize_um_type(player_ptr, &tmp_um, m_idx, full);
578     if (disturb_high) {
579         MonsterRaceInfo *ap_r_ptr = &monraces_info[um_ptr->m_ptr->ap_r_idx];
580         if (ap_r_ptr->r_tkills && ap_r_ptr->level >= player_ptr->lev) {
581             um_ptr->do_disturb = true;
582         }
583     }
584
585     if (um_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::MARK)) {
586         um_ptr->flag = true;
587     }
588
589     decide_sight_invisible_monster(player_ptr, um_ptr, m_idx);
590     if (um_ptr->flag) {
591         update_invisible_monster(player_ptr, um_ptr, m_idx);
592     } else {
593         update_visible_monster(player_ptr, um_ptr, m_idx);
594     }
595
596     if (update_clear_monster(player_ptr, um_ptr) || um_ptr->m_ptr->mflag.has_not(MonsterTemporaryFlagType::VIEW)) {
597         return;
598     }
599
600     um_ptr->m_ptr->mflag.reset(MonsterTemporaryFlagType::VIEW);
601     if (um_ptr->do_disturb && (disturb_pets || um_ptr->m_ptr->is_hostile())) {
602         disturb(player_ptr, true, true);
603     }
604 }
605
606 /*!
607  * @param player_ptr プレイヤーへの参照ポインタ
608  * @brief 単純に生存している全モンスターの更新処理を行う / This function simply updates all the (non-dead) monsters (see above).
609  * @param full 距離更新を行うならtrue
610  * @todo モンスターの感知状況しか更新していないように見える。関数名変更を検討する
611  */
612 void update_monsters(PlayerType *player_ptr, bool full)
613 {
614     auto *floor_ptr = player_ptr->current_floor_ptr;
615     for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
616         auto *m_ptr = &floor_ptr->m_list[i];
617         if (!m_ptr->is_valid()) {
618             continue;
619         }
620
621         update_monster(player_ptr, i, full);
622     }
623 }
624
625 /*!
626  * @brief SMART(適格に攻撃を行う)モンスターの学習状況を更新する / Learn about an "observed" resistance.
627  * @param m_idx 更新を行う「モンスター情報ID
628  * @param what 学習対象ID
629  */
630 void update_smart_learn(PlayerType *player_ptr, MONSTER_IDX m_idx, int what)
631 {
632     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
633     auto *r_ptr = &monraces_info[m_ptr->r_idx];
634     if (!smart_learn || (r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) || ((r_ptr->behavior_flags.has_not(MonsterBehaviorType::SMART)) && (randint0(100) < 50))) {
635         return;
636     }
637
638     switch (what) {
639     case DRS_ACID:
640         if (has_resist_acid(player_ptr)) {
641             m_ptr->smart.set(MonsterSmartLearnType::RES_ACID);
642         }
643
644         if (is_oppose_acid(player_ptr)) {
645             m_ptr->smart.set(MonsterSmartLearnType::OPP_ACID);
646         }
647
648         if (has_immune_acid(player_ptr)) {
649             m_ptr->smart.set(MonsterSmartLearnType::IMM_ACID);
650         }
651
652         break;
653     case DRS_ELEC:
654         if (has_resist_elec(player_ptr)) {
655             m_ptr->smart.set(MonsterSmartLearnType::RES_ELEC);
656         }
657
658         if (is_oppose_elec(player_ptr)) {
659             m_ptr->smart.set(MonsterSmartLearnType::OPP_ELEC);
660         }
661
662         if (has_immune_elec(player_ptr)) {
663             m_ptr->smart.set(MonsterSmartLearnType::IMM_ELEC);
664         }
665
666         break;
667     case DRS_FIRE:
668         if (has_resist_fire(player_ptr)) {
669             m_ptr->smart.set(MonsterSmartLearnType::RES_FIRE);
670         }
671
672         if (is_oppose_fire(player_ptr)) {
673             m_ptr->smart.set(MonsterSmartLearnType::OPP_FIRE);
674         }
675
676         if (has_immune_fire(player_ptr)) {
677             m_ptr->smart.set(MonsterSmartLearnType::IMM_FIRE);
678         }
679
680         break;
681     case DRS_COLD:
682         if (has_resist_cold(player_ptr)) {
683             m_ptr->smart.set(MonsterSmartLearnType::RES_COLD);
684         }
685
686         if (is_oppose_cold(player_ptr)) {
687             m_ptr->smart.set(MonsterSmartLearnType::OPP_COLD);
688         }
689
690         if (has_immune_cold(player_ptr)) {
691             m_ptr->smart.set(MonsterSmartLearnType::IMM_COLD);
692         }
693
694         break;
695     case DRS_POIS:
696         if (has_resist_pois(player_ptr)) {
697             m_ptr->smart.set(MonsterSmartLearnType::RES_POIS);
698         }
699
700         if (is_oppose_pois(player_ptr)) {
701             m_ptr->smart.set(MonsterSmartLearnType::OPP_POIS);
702         }
703
704         break;
705     case DRS_NETH:
706         if (has_resist_neth(player_ptr)) {
707             m_ptr->smart.set(MonsterSmartLearnType::RES_NETH);
708         }
709
710         break;
711     case DRS_LITE:
712         if (has_resist_lite(player_ptr)) {
713             m_ptr->smart.set(MonsterSmartLearnType::RES_LITE);
714         }
715
716         break;
717     case DRS_DARK:
718         if (has_resist_dark(player_ptr) || has_immune_dark(player_ptr)) {
719             m_ptr->smart.set(MonsterSmartLearnType::RES_DARK);
720         }
721
722         break;
723     case DRS_FEAR:
724         if (has_resist_fear(player_ptr)) {
725             m_ptr->smart.set(MonsterSmartLearnType::RES_FEAR);
726         }
727
728         break;
729     case DRS_CONF:
730         if (has_resist_conf(player_ptr)) {
731             m_ptr->smart.set(MonsterSmartLearnType::RES_CONF);
732         }
733
734         break;
735     case DRS_CHAOS:
736         if (has_resist_chaos(player_ptr)) {
737             m_ptr->smart.set(MonsterSmartLearnType::RES_CHAOS);
738         }
739
740         break;
741     case DRS_DISEN:
742         if (has_resist_disen(player_ptr)) {
743             m_ptr->smart.set(MonsterSmartLearnType::RES_DISEN);
744         }
745
746         break;
747     case DRS_BLIND:
748         if (has_resist_blind(player_ptr)) {
749             m_ptr->smart.set(MonsterSmartLearnType::RES_BLIND);
750         }
751
752         break;
753     case DRS_NEXUS:
754         if (has_resist_nexus(player_ptr)) {
755             m_ptr->smart.set(MonsterSmartLearnType::RES_NEXUS);
756         }
757
758         break;
759     case DRS_SOUND:
760         if (has_resist_sound(player_ptr)) {
761             m_ptr->smart.set(MonsterSmartLearnType::RES_SOUND);
762         }
763
764         break;
765     case DRS_SHARD:
766         if (has_resist_shard(player_ptr)) {
767             m_ptr->smart.set(MonsterSmartLearnType::RES_SHARD);
768         }
769
770         break;
771     case DRS_FREE:
772         if (player_ptr->free_act) {
773             m_ptr->smart.set(MonsterSmartLearnType::IMM_FREE);
774         }
775
776         break;
777     case DRS_MANA:
778         if (!player_ptr->msp) {
779             m_ptr->smart.set(MonsterSmartLearnType::IMM_MANA);
780         }
781
782         break;
783     case DRS_REFLECT:
784         if (has_reflect(player_ptr)) {
785             m_ptr->smart.set(MonsterSmartLearnType::IMM_REFLECT);
786         }
787
788         break;
789     default:
790         break;
791     }
792 }