2 * @brief 魔法による距離やエリアの計算
4 * @author Ben Harrison, James E. Wilson, Robert A. Koeneke, deskull and Hourier
7 #include "spell/range-calc.h"
8 #include "effect/attribute-types.h"
9 #include "floor/cave.h"
10 #include "floor/geometry.h"
11 #include "floor/line-of-sight.h"
12 #include "grid/feature.h"
13 #include "grid/grid.h"
14 #include "system/floor-type-definition.h"
15 #include "system/player-type-definition.h"
16 #include "target/projection-path-calculator.h"
17 #include "util/bit-flags-calculator.h"
20 * Find the distance from (x, y) to a line.
22 POSITION dist_to_line(POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
26 POSITION ny = x2 - x1;
27 POSITION nx = y1 - y2;
28 POSITION pd = distance(y1, x1, y, x);
29 POSITION nd = distance(y1, x1, y2, x2);
32 return distance(y, x, y2, x2);
35 nd = ((nd) ? ((py * ny + px * nx) / nd) : 0);
36 return nd >= 0 ? nd : 0 - nd;
41 * Modified version of los() for calculation of disintegration balls.
42 * Disintegration effects are stopped by permanent walls.
44 bool in_disintegration_range(floor_type *floor_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
46 POSITION delta_y = y2 - y1;
47 POSITION delta_x = x2 - x1;
48 POSITION absolute_y = std::abs(delta_y);
49 POSITION absolute_x = std::abs(delta_x);
50 if ((absolute_x < 2) && (absolute_y < 2)) {
56 /* South -- check for walls */
58 for (scanner_y = y1 + 1; scanner_y < y2; scanner_y++) {
59 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) {
65 /* North -- check for walls */
67 for (scanner_y = y1 - 1; scanner_y > y2; scanner_y--) {
68 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) {
77 /* Directly East/West */
80 /* East -- check for walls */
82 for (scanner_x = x1 + 1; scanner_x < x2; scanner_x++) {
83 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) {
89 /* West -- check for walls */
91 for (scanner_x = x1 - 1; scanner_x > x2; scanner_x--) {
92 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) {
101 POSITION sign_x = (delta_x < 0) ? -1 : 1;
102 POSITION sign_y = (delta_y < 0) ? -1 : 1;
103 if (absolute_x == 1) {
104 if (absolute_y == 2) {
105 if (!cave_stop_disintegration(floor_ptr, y1 + sign_y, x1)) {
109 } else if (absolute_y == 1) {
110 if (absolute_x == 2) {
111 if (!cave_stop_disintegration(floor_ptr, y1, x1 + sign_x)) {
117 POSITION scale_factor_2 = (absolute_x * absolute_y);
118 POSITION scale_factor_1 = scale_factor_2 << 1;
120 POSITION m; /* Slope, or 1/Slope, of LOS */
121 if (absolute_x >= absolute_y) {
122 fraction_y = absolute_y * absolute_y;
124 scanner_x = x1 + sign_x;
125 if (fraction_y == scale_factor_2) {
126 scanner_y = y1 + sign_y;
127 fraction_y -= scale_factor_1;
132 /* Note (below) the case (qy == f2), where */
133 /* the LOS exactly meets the corner of a tile. */
134 while (x2 - scanner_x) {
135 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) {
141 if (fraction_y < scale_factor_2) {
143 } else if (fraction_y > scale_factor_2) {
145 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) {
148 fraction_y -= scale_factor_1;
152 fraction_y -= scale_factor_1;
160 POSITION fraction_x = absolute_x * absolute_x;
162 scanner_y = y1 + sign_y;
163 if (fraction_x == scale_factor_2) {
164 scanner_x = x1 + sign_x;
165 fraction_x -= scale_factor_1;
170 /* Note (below) the case (qx == f2), where */
171 /* the LOS exactly meets the corner of a tile. */
172 while (y2 - scanner_y) {
173 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) {
179 if (fraction_x < scale_factor_2) {
181 } else if (fraction_x > scale_factor_2) {
183 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) {
186 fraction_x -= scale_factor_1;
190 fraction_x -= scale_factor_1;
201 void breath_shape(PlayerType *player_ptr, const projection_path &path, int dist, int *pgrids, POSITION *gx, POSITION *gy, POSITION *gm, POSITION *pgm_rad, POSITION rad, POSITION y1, POSITION x1, POSITION y2, POSITION x2, AttributeType typ)
206 int brev = rad * rad / dist;
210 int mdis = distance(y1, x1, y2, x2) + rad;
212 auto *floor_ptr = player_ptr->current_floor_ptr;
213 while (bdis <= mdis) {
214 if ((0 < dist) && (path_n < dist)) {
215 const auto [ny, nx] = path[path_n];
216 POSITION nd = distance(ny, nx, y1, x1);
225 /* Travel from center outward */
226 for (cdis = 0; cdis <= brad; cdis++) {
227 for (POSITION y = by - cdis; y <= by + cdis; y++) {
228 for (POSITION x = bx - cdis; x <= bx + cdis; x++) {
229 if (!in_bounds(floor_ptr, y, x)) {
232 if (distance(y1, x1, y, x) != bdis) {
235 if (distance(by, bx, y, x) != cdis) {
240 case AttributeType::LITE:
241 case AttributeType::LITE_WEAK:
242 /* Lights are stopped by opaque terrains */
243 if (!los(player_ptr, by, bx, y, x)) {
247 case AttributeType::DISINTEGRATE:
248 /* Disintegration are stopped only by perma-walls */
249 if (!in_disintegration_range(floor_ptr, by, bx, y, x)) {
254 /* Ball explosions are stopped by walls */
255 if (!projectable(player_ptr, by, bx, y, x)) {
268 gm[bdis + 1] = *pgrids;
269 brad = rad * (path_n + brev) / (dist + brev);