OSDN Git Service

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