OSDN Git Service

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