OSDN Git Service

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