OSDN Git Service

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