2 * @brief 魔法による距離やエリアの計算
4 * @author Ben Harrison, James E. Wilson, Robert A. Koeneke, deskull and Hourier
7 #include "spell/range-calc.h"
8 #include "floor/cave.h"
9 #include "floor/line-of-sight.h"
10 #include "grid/feature.h"
11 #include "grid/grid.h"
12 #include "spell/spell-types.h"
13 #include "system/floor-type-definition.h"
14 #include "target/projection-path-calculator.h"
15 #include "util/bit-flags-calculator.h"
18 * Find the distance from (x, y) to a line.
20 POSITION dist_to_line(POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
24 POSITION ny = x2 - x1;
25 POSITION nx = y1 - y2;
26 POSITION pd = distance(y1, x1, y, x);
27 POSITION nd = distance(y1, x1, y2, x2);
29 if (pd > nd) return distance(y, x, y2, x2);
31 nd = ((nd) ? ((py * ny + px * nx) / nd) : 0);
32 return((nd >= 0) ? nd : 0 - nd);
38 * Modified version of los() for calculation of disintegration balls.
39 * Disintegration effects are stopped by permanent walls.
41 bool in_disintegration_range(floor_type *floor_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
43 POSITION delta_y = y2 - y1;
44 POSITION delta_x = x2 - x1;
45 POSITION absolute_y = ABS(delta_y);
46 POSITION absolute_x = ABS(delta_x);
47 if ((absolute_x < 2) && (absolute_y < 2)) return TRUE;
52 /* South -- check for walls */
55 for (scanner_y = y1 + 1; scanner_y < y2; scanner_y++)
57 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) return FALSE;
61 /* North -- check for walls */
64 for (scanner_y = y1 - 1; scanner_y > y2; scanner_y--)
66 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) return FALSE;
73 /* Directly East/West */
77 /* East -- check for walls */
80 for (scanner_x = x1 + 1; scanner_x < x2; scanner_x++)
82 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) return FALSE;
86 /* West -- check for walls */
89 for (scanner_x = x1 - 1; scanner_x > x2; scanner_x--)
91 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) return FALSE;
98 POSITION sign_x = (delta_x < 0) ? -1 : 1;
99 POSITION sign_y = (delta_y < 0) ? -1 : 1;
104 if (!cave_stop_disintegration(floor_ptr, y1 + sign_y, x1)) return TRUE;
107 else if (absolute_y == 1)
111 if (!cave_stop_disintegration(floor_ptr, y1, x1 + sign_x)) return TRUE;
115 POSITION scale_factor_2 = (absolute_x * absolute_y);
116 POSITION scale_factor_1 = scale_factor_2 << 1;
118 POSITION m; /* Slope, or 1/Slope, of LOS */
119 if (absolute_x >= absolute_y)
121 fraction_y = absolute_y * absolute_y;
123 scanner_x = x1 + sign_x;
124 if (fraction_y == scale_factor_2)
126 scanner_y = y1 + sign_y;
127 fraction_y -= scale_factor_1;
134 /* Note (below) the case (qy == f2), where */
135 /* the LOS exactly meets the corner of a tile. */
136 while (x2 - scanner_x)
138 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
142 if (fraction_y < scale_factor_2)
146 else if (fraction_y > scale_factor_2)
149 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
150 fraction_y -= scale_factor_1;
156 fraction_y -= scale_factor_1;
164 POSITION fraction_x = absolute_x * absolute_x;
166 scanner_y = y1 + sign_y;
167 if (fraction_x == scale_factor_2)
169 scanner_x = x1 + sign_x;
170 fraction_x -= scale_factor_1;
177 /* Note (below) the case (qx == f2), where */
178 /* the LOS exactly meets the corner of a tile. */
179 while (y2 - scanner_y)
181 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
185 if (fraction_x < scale_factor_2)
189 else if (fraction_x > scale_factor_2)
192 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
193 fraction_x -= scale_factor_1;
199 fraction_x -= scale_factor_1;
211 void breath_shape(player_type *caster_ptr, u16b *path_g, int dist, int *pgrids, POSITION *gx, POSITION *gy, POSITION *gm, POSITION *pgm_rad, POSITION rad, POSITION y1, POSITION x1, POSITION y2, POSITION x2, EFFECT_ID typ)
216 int brev = rad * rad / dist;
220 int mdis = distance(y1, x1, y2, x2) + rad;
222 floor_type *floor_ptr = caster_ptr->current_floor_ptr;
225 if ((0 < dist) && (path_n < dist))
227 POSITION ny = get_grid_y(path_g[path_n]);
228 POSITION nx = get_grid_x(path_g[path_n]);
229 POSITION nd = distance(ny, nx, y1, x1);
239 /* Travel from center outward */
240 for (cdis = 0; cdis <= brad; cdis++)
242 for (POSITION y = by - cdis; y <= by + cdis; y++)
244 for (POSITION x = bx - cdis; x <= bx + cdis; x++)
246 if (!in_bounds(floor_ptr, y, x)) continue;
247 if (distance(y1, x1, y, x) != bdis) continue;
248 if (distance(by, bx, y, x) != cdis) continue;
254 /* Lights are stopped by opaque terrains */
255 if (!los(caster_ptr, by, bx, y, x)) continue;
257 case GF_DISINTEGRATE:
258 /* Disintegration are stopped only by perma-walls */
259 if (!in_disintegration_range(floor_ptr, by, bx, y, x)) continue;
262 /* Ball explosions are stopped by walls */
263 if (!projectable(caster_ptr, by, bx, y, x)) continue;
274 gm[bdis + 1] = *pgrids;
275 brad = rad * (path_n + brev) / (dist + brev);