OSDN Git Service

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