OSDN Git Service

[Refactor] #864 Separated player_type struct from player-type.h to player-type-defini...
[hengbandforosx/hengbandosx.git] / src / floor / geometry.cpp
1 #include "floor/geometry.h"
2 #include "floor/cave.h"
3 #include "game-option/text-display-options.h"
4 #include "grid/feature.h"
5 #include "grid/grid.h"
6 #include "system/floor-type-definition.h"
7 #include "system/monster-type-definition.h"
8 #include "system/player-type-definition.h"
9 #include "target/projection-path-calculator.h"
10 #include "util/bit-flags-calculator.h"
11
12 /*!
13  * キーパッドの方向を南から反時計回り順に列挙 / Global array for looping through the "keypad directions"
14  */
15 const POSITION ddd[9] = { 2, 8, 6, 4, 3, 1, 9, 7, 5 };
16
17 /*!
18  * dddで定義した順にベクトルのX軸成分を定義 / Global arrays for converting "keypad direction" into offsets
19  */
20 const POSITION ddx[10] = { 0, -1, 0, 1, -1, 0, 1, -1, 0, 1 };
21
22 /*!
23  * dddで定義した順にベクトルのY軸成分を定義 / Global arrays for converting "keypad direction" into offsets
24  */
25 const POSITION ddy[10] = { 0, 1, 1, 1, 0, 0, 0, -1, -1, -1 };
26
27 /*!
28  * ddd越しにベクトルのX軸成分を定義 / Global arrays for optimizing "ddx[ddd[i]]" and "ddy[ddd[i]]"
29  */
30 const POSITION ddx_ddd[9] = { 0, 0, 1, -1, 1, -1, 1, -1, 0 };
31
32 /*!
33  * ddd越しにベクトルのY軸成分を定義 / Global arrays for optimizing "ddx[ddd[i]]" and "ddy[ddd[i]]"
34  */
35 const POSITION ddy_ddd[9] = { 1, -1, 0, 0, 1, 1, -1, -1, 0 };
36
37 /*!
38  * キーパッドの円環状方向配列 / Circular keypad direction array
39  */
40 const POSITION cdd[8] = { 2, 3, 6, 9, 8, 7, 4, 1 };
41
42 /*!
43  * cdd越しにベクトルのX軸成分を定義 / Global arrays for optimizing "ddx[cdd[i]]" and "ddy[cdd[i]]"
44  */
45 const POSITION ddx_cdd[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
46
47 /*!
48  * cdd越しにベクトルのY軸成分を定義 / Global arrays for optimizing "ddx[cdd[i]]" and "ddy[cdd[i]]"
49  */
50 const POSITION ddy_cdd[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
51
52 /*!
53  * @brief 2点間の距離をニュートン・ラプソン法で算出する / Distance between two points via Newton-Raphson technique
54  * @param y1 1点目のy座標
55  * @param x1 1点目のx座標
56  * @param y2 2点目のy座標
57  * @param x2 2点目のx座標
58  * @return 2点間の距離
59  */
60 POSITION distance(POSITION y1, POSITION x1, POSITION y2, POSITION x2)
61 {
62     POSITION dy = (y1 > y2) ? (y1 - y2) : (y2 - y1);
63     POSITION dx = (x1 > x2) ? (x1 - x2) : (x2 - x1);
64
65     /* Squared distance */
66     POSITION target = (dy * dy) + (dx * dx);
67
68     /* Approximate distance: hypot(dy,dx) = max(dy,dx) + min(dy,dx) / 2 */
69     POSITION d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
70
71     POSITION err;
72
73     /* Simple case */
74     if (!dy || !dx)
75         return d;
76
77     while (TRUE) {
78         /* Approximate error */
79         err = (target - d * d) / (2 * d);
80
81         /* No error - we are done */
82         if (!err)
83             break;
84
85         /* Adjust distance */
86         d += err;
87     }
88
89     return d;
90 }
91
92 /*!
93  * @brief プレイヤーから指定の座標がどの方角にあるかを返す /
94  * Convert an adjacent location to a direction.
95  * @param y 方角を確認したY座標
96  * @param x 方角を確認したX座標
97  * @return 方向ID
98  */
99 DIRECTION coords_to_dir(player_type *creature_ptr, POSITION y, POSITION x)
100 {
101     DIRECTION d[3][3] = { { 7, 4, 1 }, { 8, 5, 2 }, { 9, 6, 3 } };
102     POSITION dy, dx;
103
104     dy = y - creature_ptr->y;
105     dx = x - creature_ptr->x;
106     if (ABS(dx) > 1 || ABS(dy) > 1)
107         return 0;
108
109     return d[dx + 1][dy + 1];
110 }
111
112 /*!
113  * @brief 指定された座標をプレイヤーが視覚に収められるかを返す。 / Can the player "see" the given grid in detail?
114  * @param y y座標
115  * @param x x座標
116  * @return 視覚に収められる状態ならTRUEを返す
117  * @details
118  * He must have vision, illumination, and line of sight.\n
119  * \n
120  * Note -- "CAVE_LITE" is only set if the "torch" has "los()".\n
121  * So, given "CAVE_LITE", we know that the grid is "fully visible".\n
122  *\n
123  * Note that "CAVE_GLOW" makes little sense for a wall, since it would mean\n
124  * that a wall is visible from any direction.  That would be odd.  Except\n
125  * under wizard light, which might make sense.  Thus, for walls, we require\n
126  * not only that they be "CAVE_GLOW", but also, that they be adjacent to a\n
127  * grid which is not only "CAVE_GLOW", but which is a non-wall, and which is\n
128  * in line of sight of the player.\n
129  *\n
130  * This extra check is expensive, but it provides a more "correct" semantics.\n
131  *\n
132  * Note that we should not run this check on walls which are "outer walls" of\n
133  * the dungeon, or we will induce a memory fault, but actually verifying all\n
134  * of the locations would be extremely expensive.\n
135  *\n
136  * Thus, to speed up the function, we assume that all "perma-walls" which are\n
137  * "CAVE_GLOW" are "illuminated" from all sides.  This is correct for all cases\n
138  * except "vaults" and the "buildings" in town.  But the town is a hack anyway,\n
139  * and the player has more important things on his mind when he is attacking a\n
140  * monster vault.  It is annoying, but an extremely important optimization.\n
141  *\n
142  * Note that "glowing walls" are only considered to be "illuminated" if the\n
143  * grid which is next to the wall in the direction of the player is also a\n
144  * "glowing" grid.  This prevents the player from being able to "see" the\n
145  * walls of illuminated rooms from a corridor outside the room.\n
146  */
147 bool player_can_see_bold(player_type *creature_ptr, POSITION y, POSITION x)
148 {
149     grid_type *g_ptr;
150
151     /* Blind players see nothing */
152     if (creature_ptr->blind)
153         return FALSE;
154
155     g_ptr = &creature_ptr->current_floor_ptr->grid_array[y][x];
156
157     /* Note that "torch-lite" yields "illumination" */
158     if (g_ptr->info & (CAVE_LITE | CAVE_MNLT))
159         return TRUE;
160
161     /* Require line of sight to the grid */
162     if (!player_has_los_bold(creature_ptr, y, x))
163         return FALSE;
164
165     /* Noctovision of Ninja */
166     if (creature_ptr->see_nocto)
167         return TRUE;
168
169     /* Require "perma-lite" of the grid */
170     if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW)
171         return FALSE;
172
173     /* Feature code (applying "mimic" field) */
174     /* Floors are simple */
175     if (feat_supports_los(get_feat_mimic(g_ptr)))
176         return TRUE;
177
178     /* Check for "local" illumination */
179     return check_local_illumination(creature_ptr, y, x);
180 }
181
182 /*
183  * Calculate "incremental motion". Used by project() and shoot().
184  * Assumes that (*y,*x) lies on the path from (y1,x1) to (y2,x2).
185  */
186 void mmove2(POSITION *y, POSITION *x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
187 {
188     POSITION dy, dx, dist, shift;
189
190     /* Extract the distance travelled */
191     dy = (*y < y1) ? y1 - *y : *y - y1;
192     dx = (*x < x1) ? x1 - *x : *x - x1;
193
194     /* Number of steps */
195     dist = (dy > dx) ? dy : dx;
196
197     /* We are calculating the next location */
198     dist++;
199
200     /* Calculate the total distance along each axis */
201     dy = (y2 < y1) ? (y1 - y2) : (y2 - y1);
202     dx = (x2 < x1) ? (x1 - x2) : (x2 - x1);
203
204     /* Paranoia -- Hack -- no motion */
205     if (!dy && !dx)
206         return;
207
208     /* Move mostly vertically */
209     if (dy > dx) {
210         /* Extract a shift factor */
211         shift = (dist * dx + (dy - 1) / 2) / dy;
212
213         /* Sometimes move along the minor axis */
214         (*x) = (x2 < x1) ? (x1 - shift) : (x1 + shift);
215
216         /* Always move along major axis */
217         (*y) = (y2 < y1) ? (y1 - dist) : (y1 + dist);
218     }
219
220     /* Move mostly horizontally */
221     else {
222         /* Extract a shift factor */
223         shift = (dist * dy + (dx - 1) / 2) / dx;
224
225         /* Sometimes move along the minor axis */
226         (*y) = (y2 < y1) ? (y1 - shift) : (y1 + shift);
227
228         /* Always move along major axis */
229         (*x) = (x2 < x1) ? (x1 - dist) : (x1 + dist);
230     }
231 }
232
233 /*!
234  * @brief Is the monster seen by the player?
235  * @param creature_ptr プレーヤーへの参照ポインタ
236  * @param m_ptr 個々のモンスターへの参照ポインタ
237  * @return 個々のモンスターがプレーヤーが見えたらTRUE
238  * @todo is_seen() の関数マクロをバラそうとしたがインクルード関係のコンパイルエラーで失敗
239  */
240 bool is_seen(player_type *creature_ptr, monster_type *m_ptr)
241 {
242     bool is_inside_view = !ignore_unview;
243     is_inside_view |= creature_ptr->phase_out;
244     is_inside_view
245         |= player_can_see_bold(creature_ptr, m_ptr->fy, m_ptr->fx) && projectable(creature_ptr, creature_ptr->y, creature_ptr->x, m_ptr->fy, m_ptr->fx);
246     return m_ptr->ml && is_inside_view;
247 }