OSDN Git Service

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