OSDN Git Service

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