OSDN Git Service

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