OSDN Git Service

Merge pull request #629 from iks3/refactor-remove-zangband-savefile-loader
[hengbandforosx/hengbandosx.git] / src / monster-floor / monster-safety-hiding.cpp
1 /*!
2  * @brief モンスターの逃走・隠匿に関する処理
3  * @date 2020/03/08
4  * @author Hourier
5  */
6
7 #include "monster-floor/monster-safety-hiding.h"
8 #include "floor/cave.h"
9 #include "grid/grid.h"
10 #include "monster-floor/monster-dist-offsets.h"
11 #include "monster-race/monster-race.h"
12 #include "monster/monster-flag-types.h"
13 #include "monster/monster-info.h"
14 #include "mspell/mspell-checker.h"
15 #include "system/floor-type-definition.h"
16 #include "target/projection-path-calculator.h"
17
18 /*!
19  * @brief モンスターが逃げ込める地点を走査する
20  * @param target_ptr プレーヤーへの参照ポインタ
21  * @param m_idx モンスターID
22  * @param y_offsets
23  * @param x_offsets
24  * @param d モンスターがいる地点からの距離
25  * @return 逃げ込める地点の候補地
26  */
27 static coordinate_candidate sweep_safe_coordinate(player_type *target_ptr, MONSTER_IDX m_idx, const POSITION *y_offsets, const POSITION *x_offsets, int d)
28 {
29     coordinate_candidate candidate = init_coordinate_candidate();
30     floor_type *floor_ptr = target_ptr->current_floor_ptr;
31     monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
32     for (POSITION i = 0, dx = x_offsets[0], dy = y_offsets[0]; dx != 0 || dy != 0; i++, dx = x_offsets[i], dy = y_offsets[i]) {
33         POSITION y = m_ptr->fy + dy;
34         POSITION x = m_ptr->fx + dx;
35         if (!in_bounds(floor_ptr, y, x))
36             continue;
37
38         monster_race *r_ptr = &r_info[m_ptr->r_idx];
39         grid_type *g_ptr;
40         g_ptr = &floor_ptr->grid_array[y][x];
41
42         BIT_FLAGS16 riding_mode = (m_idx == target_ptr->riding) ? CEM_RIDING : 0;
43         if (!monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, riding_mode))
44             continue;
45
46         if (m_ptr->mflag2.has_not(MFLAG2::NOFLOW)) {
47             byte dist = grid_dist(g_ptr, r_ptr);
48             if (dist == 0)
49                 continue;
50             if (dist > grid_dist(&floor_ptr->grid_array[m_ptr->fy][m_ptr->fx], r_ptr) + 2 * d)
51                 continue;
52         }
53
54         if (projectable(target_ptr, target_ptr->y, target_ptr->x, y, x))
55             continue;
56
57         POSITION dis = distance(y, x, target_ptr->y, target_ptr->x);
58         if (dis <= candidate.gdis)
59             continue;
60
61         candidate.gy = y;
62         candidate.gx = x;
63         candidate.gdis = dis;
64     }
65
66     return candidate;
67 }
68
69 /*!
70  * @brief モンスターが逃げ込める安全な地点を返す /
71  * Choose a "safe" location near a monster for it to run toward.
72  * @param target_ptr プレーヤーへの参照ポインタ
73  * @param m_idx モンスターの参照ID
74  * @param yp 移動先のマスのY座標を返す参照ポインタ
75  * @param xp 移動先のマスのX座標を返す参照ポインタ
76  * @return 有効なマスがあった場合TRUEを返す
77  * @details
78  * A location is "safe" if it can be reached quickly and the player\n
79  * is not able to fire into it (it isn't a "clean shot").  So, this will\n
80  * cause monsters to "duck" behind walls.  Hopefully, monsters will also\n
81  * try to run towards corridor openings if they are in a room.\n
82  *\n
83  * This function may take lots of CPU time if lots of monsters are\n
84  * fleeing.\n
85  *\n
86  * Return TRUE if a safe location is available.\n
87  */
88 bool find_safety(player_type *target_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITION *xp)
89 {
90     monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
91     for (POSITION d = 1; d < 10; d++) {
92         const POSITION *y_offsets;
93         y_offsets = dist_offsets_y[d];
94
95         const POSITION *x_offsets;
96         x_offsets = dist_offsets_x[d];
97
98         coordinate_candidate candidate = sweep_safe_coordinate(target_ptr, m_idx, y_offsets, x_offsets, d);
99
100         if (candidate.gdis <= 0)
101             continue;
102
103         *yp = m_ptr->fy - candidate.gy;
104         *xp = m_ptr->fx - candidate.gx;
105
106         return TRUE;
107     }
108
109     return FALSE;
110 }
111
112 /*!
113  * @brief モンスターが隠れられる地点を走査する
114  * @param target_ptr プレーヤーへの参照ポインタ
115  * @param m_idx モンスターID
116  * @param y_offsets
117  * @param x_offsets
118  * @param candidate 隠れられる地点の候補地
119  * @return なし
120  */
121 static void sweep_hiding_candidate(
122     player_type *target_ptr, monster_type *m_ptr, const POSITION *y_offsets, const POSITION *x_offsets, coordinate_candidate *candidate)
123 {
124     monster_race *r_ptr = &r_info[m_ptr->r_idx];
125     for (POSITION i = 0, dx = x_offsets[0], dy = y_offsets[0]; dx != 0 || dy != 0; i++, dx = x_offsets[i], dy = y_offsets[i]) {
126         POSITION y = m_ptr->fy + dy;
127         POSITION x = m_ptr->fx + dx;
128         if (!in_bounds(target_ptr->current_floor_ptr, y, x))
129             continue;
130         if (!monster_can_enter(target_ptr, y, x, r_ptr, 0))
131             continue;
132         if (projectable(target_ptr, target_ptr->y, target_ptr->x, y, x) || !clean_shot(target_ptr, m_ptr->fy, m_ptr->fx, y, x, FALSE))
133             continue;
134
135         POSITION dis = distance(y, x, target_ptr->y, target_ptr->x);
136         if (dis < candidate->gdis && dis >= 2) {
137             candidate->gy = y;
138             candidate->gx = x;
139             candidate->gdis = dis;
140         }
141     }
142 }
143
144 /*!
145  * @brief モンスターが隠れ潜める地点を返す /
146  * Choose a good hiding place near a monster for it to run toward.
147  * @param target_ptr プレーヤーへの参照ポインタ
148  * @param m_idx モンスターの参照ID
149  * @param yp 移動先のマスのY座標を返す参照ポインタ
150  * @param xp 移動先のマスのX座標を返す参照ポインタ
151  * @return 有効なマスがあった場合TRUEを返す
152  * @details
153  * Pack monsters will use this to "ambush" the player and lure him out\n
154  * of corridors into open space so they can swarm him.\n
155  *\n
156  * Return TRUE if a good location is available.\n
157  */
158 bool find_hiding(player_type *target_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITION *xp)
159 {
160     monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
161     coordinate_candidate candidate = init_coordinate_candidate();
162     candidate.gdis = 999;
163
164     for (POSITION d = 1; d < 10; d++) {
165         const POSITION *y_offsets;
166         y_offsets = dist_offsets_y[d];
167
168         const POSITION *x_offsets;
169         x_offsets = dist_offsets_x[d];
170
171         sweep_hiding_candidate(target_ptr, m_ptr, y_offsets, x_offsets, &candidate);
172         if (candidate.gdis >= 999)
173             continue;
174
175         *yp = m_ptr->fy - candidate.gy;
176         *xp = m_ptr->fx - candidate.gx;
177         return TRUE;
178     }
179
180     return FALSE;
181 }