OSDN Git Service

[Refactor] #37353 複数の is_bound* マクロを floor.h へ移動。
[hengband/hengband.git] / src / geometry.c
1 #include "angband.h"
2 #include "floor.h"
3
4 /*!
5  * @brief プレイヤーから指定の座標がどの方角にあるかを返す /
6  * Convert an adjacent location to a direction.
7  * @param y 方角を確認したY座標
8  * @param x 方角を確認したX座標
9  * @return 方向ID
10  */
11 DIRECTION coords_to_dir(POSITION y, POSITION x)
12 {
13         DIRECTION d[3][3] = { {7, 4, 1}, {8, 5, 2}, {9, 6, 3} };
14         POSITION dy, dx;
15
16         dy = y - p_ptr->y;
17         dx = x - p_ptr->x;
18         if (ABS(dx) > 1 || ABS(dy) > 1) return (0);
19
20         return d[dx + 1][dy + 1];
21 }
22
23 /*!
24  * @brief 始点から終点への直線経路を返す /
25  * Determine the path taken by a projection.
26  * @param gp 経路座標リストを返す参照ポインタ
27  * @param range 距離
28  * @param y1 始点Y座標
29  * @param x1 始点X座標
30  * @param y2 終点Y座標
31  * @param x2 終点X座標
32  * @param flg フラグID
33  * @return リストの長さ
34  * @details
35  * <pre>
36  * The projection will always start from the grid (y1,x1), and will travel
37  * towards the grid (y2,x2), touching one grid per unit of distance along
38  * the major axis, and stopping when it enters the destination grid or a
39  * wall grid, or has travelled the maximum legal distance of "range".
40  *
41  * Note that "distance" in this function (as in the "update_view()" code)
42  * is defined as "MAX(dy,dx) + MIN(dy,dx)/2", which means that the player
43  * actually has an "octagon of projection" not a "circle of projection".
44  *
45  * The path grids are saved into the grid array pointed to by "gp", and
46  * there should be room for at least "range" grids in "gp".  Note that
47  * due to the way in which distance is calculated, this function normally
48  * uses fewer than "range" grids for the projection path, so the result
49  * of this function should never be compared directly to "range".  Note
50  * that the initial grid (y1,x1) is never saved into the grid array, not
51  * even if the initial grid is also the final grid.
52  *
53  * The "flg" flags can be used to modify the behavior of this function.
54  *
55  * In particular, the "PROJECT_STOP" and "PROJECT_THRU" flags have the same
56  * semantics as they do for the "project" function, namely, that the path
57  * will stop as soon as it hits a monster, or that the path will continue
58  * through the destination grid, respectively.
59  *
60  * The "PROJECT_JUMP" flag, which for the "project()" function means to
61  * start at a special grid (which makes no sense in this function), means
62  * that the path should be "angled" slightly if needed to avoid any wall
63  * grids, allowing the player to "target" any grid which is in "view".
64  * This flag is non-trivial and has not yet been implemented, but could
65  * perhaps make use of the "vinfo" array (above).
66  *
67  * This function returns the number of grids (if any) in the path.  This
68  * function will return zero if and only if (y1,x1) and (y2,x2) are equal.
69  *
70  * This algorithm is similar to, but slightly different from, the one used
71  * by "update_view_los()", and very different from the one used by "los()".
72  * </pre>
73  */
74 sint project_path(u16b *gp, POSITION range, POSITION y1, POSITION x1, POSITION y2, POSITION x2, BIT_FLAGS flg)
75 {
76         POSITION y, x;
77
78         int n = 0;
79         int k = 0;
80
81         /* Absolute */
82         POSITION ay, ax;
83
84         /* Offsets */
85         POSITION sy, sx;
86
87         /* Fractions */
88         int frac;
89
90         /* Scale factors */
91         int full, half;
92
93         /* Slope */
94         int m;
95
96         /* No path necessary (or allowed) */
97         if ((x1 == x2) && (y1 == y2)) return (0);
98
99
100         /* Analyze "dy" */
101         if (y2 < y1)
102         {
103                 ay = (y1 - y2);
104                 sy = -1;
105         }
106         else
107         {
108                 ay = (y2 - y1);
109                 sy = 1;
110         }
111
112         /* Analyze "dx" */
113         if (x2 < x1)
114         {
115                 ax = (x1 - x2);
116                 sx = -1;
117         }
118         else
119         {
120                 ax = (x2 - x1);
121                 sx = 1;
122         }
123
124
125         /* Number of "units" in one "half" grid */
126         half = (ay * ax);
127
128         /* Number of "units" in one "full" grid */
129         full = half << 1;
130
131         /* Vertical */
132         if (ay > ax)
133         {
134                 /* Let m = ((dx/dy) * full) = (dx * dx * 2) */
135                 m = ax * ax * 2;
136
137                 /* Start */
138                 y = y1 + sy;
139                 x = x1;
140
141                 frac = m;
142
143                 if (frac > half)
144                 {
145                         /* Advance (X) part 2 */
146                         x += sx;
147
148                         /* Advance (X) part 3 */
149                         frac -= full;
150
151                         /* Track distance */
152                         k++;
153                 }
154
155                 /* Create the projection path */
156                 while (1)
157                 {
158                         /* Save grid */
159                         gp[n++] = GRID(y, x);
160
161                         /* Hack -- Check maximum range */
162                         if ((n + (k >> 1)) >= range) break;
163
164                         /* Sometimes stop at destination grid */
165                         if (!(flg & (PROJECT_THRU)))
166                         {
167                                 if ((x == x2) && (y == y2)) break;
168                         }
169
170                         if (flg & (PROJECT_DISI))
171                         {
172                                 if ((n > 0) && cave_stop_disintegration(y, x)) break;
173                         }
174                         else if (flg & (PROJECT_LOS))
175                         {
176                                 if ((n > 0) && !cave_los_bold(y, x)) break;
177                         }
178                         else if (!(flg & (PROJECT_PATH)))
179                         {
180                                 /* Always stop at non-initial wall grids */
181                                 if ((n > 0) && !cave_have_flag_bold(y, x, FF_PROJECT)) break;
182                         }
183
184                         /* Sometimes stop at non-initial monsters/players */
185                         if (flg & (PROJECT_STOP))
186                         {
187                                 if ((n > 0) &&
188                                         (player_bold(y, x) || current_floor_ptr->grid_array[y][x].m_idx != 0))
189                                         break;
190                         }
191
192                         if (!in_bounds(y, x)) break;
193
194                         /* Slant */
195                         if (m)
196                         {
197                                 /* Advance (X) part 1 */
198                                 frac += m;
199
200                                 /* Horizontal change */
201                                 if (frac > half)
202                                 {
203                                         /* Advance (X) part 2 */
204                                         x += sx;
205
206                                         /* Advance (X) part 3 */
207                                         frac -= full;
208
209                                         /* Track distance */
210                                         k++;
211                                 }
212                         }
213
214                         /* Advance (Y) */
215                         y += sy;
216                 }
217         }
218
219         /* Horizontal */
220         else if (ax > ay)
221         {
222                 /* Let m = ((dy/dx) * full) = (dy * dy * 2) */
223                 m = ay * ay * 2;
224
225                 /* Start */
226                 y = y1;
227                 x = x1 + sx;
228
229                 frac = m;
230
231                 /* Vertical change */
232                 if (frac > half)
233                 {
234                         /* Advance (Y) part 2 */
235                         y += sy;
236
237                         /* Advance (Y) part 3 */
238                         frac -= full;
239
240                         /* Track distance */
241                         k++;
242                 }
243
244                 /* Create the projection path */
245                 while (1)
246                 {
247                         /* Save grid */
248                         gp[n++] = GRID(y, x);
249
250                         /* Hack -- Check maximum range */
251                         if ((n + (k >> 1)) >= range) break;
252
253                         /* Sometimes stop at destination grid */
254                         if (!(flg & (PROJECT_THRU)))
255                         {
256                                 if ((x == x2) && (y == y2)) break;
257                         }
258
259                         if (flg & (PROJECT_DISI))
260                         {
261                                 if ((n > 0) && cave_stop_disintegration(y, x)) break;
262                         }
263                         else if (flg & (PROJECT_LOS))
264                         {
265                                 if ((n > 0) && !cave_los_bold(y, x)) break;
266                         }
267                         else if (!(flg & (PROJECT_PATH)))
268                         {
269                                 /* Always stop at non-initial wall grids */
270                                 if ((n > 0) && !cave_have_flag_bold(y, x, FF_PROJECT)) break;
271                         }
272
273                         /* Sometimes stop at non-initial monsters/players */
274                         if (flg & (PROJECT_STOP))
275                         {
276                                 if ((n > 0) &&
277                                         (player_bold(y, x) || current_floor_ptr->grid_array[y][x].m_idx != 0))
278                                         break;
279                         }
280
281                         if (!in_bounds(y, x)) break;
282
283                         /* Slant */
284                         if (m)
285                         {
286                                 /* Advance (Y) part 1 */
287                                 frac += m;
288
289                                 /* Vertical change */
290                                 if (frac > half)
291                                 {
292                                         /* Advance (Y) part 2 */
293                                         y += sy;
294
295                                         /* Advance (Y) part 3 */
296                                         frac -= full;
297
298                                         /* Track distance */
299                                         k++;
300                                 }
301                         }
302
303                         /* Advance (X) */
304                         x += sx;
305                 }
306         }
307
308         /* Diagonal */
309         else
310         {
311                 /* Start */
312                 y = y1 + sy;
313                 x = x1 + sx;
314
315                 /* Create the projection path */
316                 while (1)
317                 {
318                         /* Save grid */
319                         gp[n++] = GRID(y, x);
320
321                         /* Hack -- Check maximum range */
322                         if ((n + (n >> 1)) >= range) break;
323
324                         /* Sometimes stop at destination grid */
325                         if (!(flg & (PROJECT_THRU)))
326                         {
327                                 if ((x == x2) && (y == y2)) break;
328                         }
329
330                         if (flg & (PROJECT_DISI))
331                         {
332                                 if ((n > 0) && cave_stop_disintegration(y, x)) break;
333                         }
334                         else if (flg & (PROJECT_LOS))
335                         {
336                                 if ((n > 0) && !cave_los_bold(y, x)) break;
337                         }
338                         else if (!(flg & (PROJECT_PATH)))
339                         {
340                                 /* Always stop at non-initial wall grids */
341                                 if ((n > 0) && !cave_have_flag_bold(y, x, FF_PROJECT)) break;
342                         }
343
344                         /* Sometimes stop at non-initial monsters/players */
345                         if (flg & (PROJECT_STOP))
346                         {
347                                 if ((n > 0) &&
348                                         (player_bold(y, x) || current_floor_ptr->grid_array[y][x].m_idx != 0))
349                                         break;
350                         }
351
352                         if (!in_bounds(y, x)) break;
353
354                         /* Advance (Y) */
355                         y += sy;
356
357                         /* Advance (X) */
358                         x += sx;
359                 }
360         }
361
362         /* Length */
363         return (n);
364 }
365
366 /*
367  * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
368  * at the final destination, assuming no monster gets in the way.
369  *
370  * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
371  */
372 bool projectable(POSITION y1, POSITION x1, POSITION y2, POSITION x2)
373 {
374         POSITION y, x;
375
376         int grid_n = 0;
377         u16b grid_g[512];
378
379         /* Check the projection path */
380         grid_n = project_path(grid_g, (project_length ? project_length : MAX_RANGE), y1, x1, y2, x2, 0);
381
382         /* Identical grid */
383         if (!grid_n) return TRUE;
384
385         /* Final grid */
386         y = GRID_Y(grid_g[grid_n - 1]);
387         x = GRID_X(grid_g[grid_n - 1]);
388
389         /* May not end in an unrequested grid */
390         if ((y != y2) || (x != x2)) return (FALSE);
391
392         /* Assume okay */
393         return (TRUE);
394 }