OSDN Git Service

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