OSDN Git Service

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