1 #include "target/projection-path-calculator.h"
2 #include "effect/effect-characteristics.h"
3 #include "effect/spells-effect-util.h"
4 #include "floor/cave.h"
5 #include "grid/feature-flag-types.h"
7 #include "system/floor-type-definition.h"
9 typedef struct projection_path_type {
29 } projection_path_type;
32 * @brief Convert a "location" (Y, X) into a "grid" (G)
37 static u16b location_to_grid(POSITION y, POSITION x) { return 256 * y + x; }
39 static projection_path_type *initialize_projection_path_type(
40 projection_path_type *pp_ptr, u16b *gp, POSITION range, BIT_FLAGS flag, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
43 pp_ptr->range = range;
52 static void set_asxy(projection_path_type *pp_ptr)
54 if (pp_ptr->y2 < pp_ptr->y1) {
55 pp_ptr->ay = pp_ptr->y1 - pp_ptr->y2;
58 pp_ptr->ay = pp_ptr->y2 - pp_ptr->y1;
62 if (pp_ptr->x2 < pp_ptr->x1) {
63 pp_ptr->ax = pp_ptr->x1 - pp_ptr->x2;
66 pp_ptr->ax = pp_ptr->x2 - pp_ptr->x1;
71 static void calc_frac(projection_path_type *pp_ptr, bool is_vertical)
76 pp_ptr->frac += pp_ptr->m;
77 if (pp_ptr->frac <= pp_ptr->half)
81 pp_ptr->x += pp_ptr->sx;
83 pp_ptr->y += pp_ptr->sy;
85 pp_ptr->frac -= pp_ptr->full;
89 static void calc_projection_to_target(player_type *player_ptr, projection_path_type *pp_ptr, bool is_vertical)
91 floor_type *floor_ptr = player_ptr->current_floor_ptr;
93 pp_ptr->gp[pp_ptr->n++] = location_to_grid(pp_ptr->y, pp_ptr->x);
94 if ((pp_ptr->n + (pp_ptr->k >> 1)) >= pp_ptr->range)
97 if (!(pp_ptr->flag & PROJECT_THRU)) {
98 if ((pp_ptr->x == pp_ptr->x2) && (pp_ptr->y == pp_ptr->y2))
102 if (pp_ptr->flag & PROJECT_DISI) {
103 if ((pp_ptr->n > 0) && cave_stop_disintegration(floor_ptr, pp_ptr->y, pp_ptr->x))
105 } else if (pp_ptr->flag & PROJECT_LOS) {
106 if ((pp_ptr->n > 0) && !cave_los_bold(floor_ptr, pp_ptr->y, pp_ptr->x))
108 } else if (!(pp_ptr->flag & PROJECT_PATH)) {
109 if ((pp_ptr->n > 0) && !cave_has_flag_bold(floor_ptr, pp_ptr->y, pp_ptr->x, FF_PROJECT))
113 if (pp_ptr->flag & PROJECT_STOP) {
114 if ((pp_ptr->n > 0) && (player_bold(player_ptr, pp_ptr->y, pp_ptr->x) || floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].m_idx != 0))
118 if (!in_bounds(floor_ptr, pp_ptr->y, pp_ptr->x))
121 calc_frac(pp_ptr, is_vertical);
123 pp_ptr->y += pp_ptr->sy;
125 pp_ptr->x += pp_ptr->sx;
129 static bool calc_vertical_projection(player_type *player_ptr, projection_path_type *pp_ptr)
131 if (pp_ptr->ay <= pp_ptr->ax)
134 pp_ptr->m = pp_ptr->ax * pp_ptr->ax * 2;
135 pp_ptr->y = pp_ptr->y1 + pp_ptr->sy;
136 pp_ptr->x = pp_ptr->x1;
137 pp_ptr->frac = pp_ptr->m;
138 if (pp_ptr->frac > pp_ptr->half) {
139 pp_ptr->x += pp_ptr->sx;
140 pp_ptr->frac -= pp_ptr->full;
144 calc_projection_to_target(player_ptr, pp_ptr, TRUE);
148 static bool calc_horizontal_projection(player_type *player_ptr, projection_path_type *pp_ptr)
150 if (pp_ptr->ax <= pp_ptr->ay)
153 pp_ptr->m = pp_ptr->ay * pp_ptr->ay * 2;
154 pp_ptr->y = pp_ptr->y1;
155 pp_ptr->x = pp_ptr->x1 + pp_ptr->sx;
156 pp_ptr->frac = pp_ptr->m;
157 if (pp_ptr->frac > pp_ptr->half) {
158 pp_ptr->y += pp_ptr->sy;
159 pp_ptr->frac -= pp_ptr->full;
163 calc_projection_to_target(player_ptr, pp_ptr, FALSE);
167 static void calc_projection_others(player_type *player_ptr, projection_path_type *pp_ptr)
169 floor_type *floor_ptr = player_ptr->current_floor_ptr;
171 pp_ptr->gp[pp_ptr->n++] = location_to_grid(pp_ptr->y, pp_ptr->x);
172 if ((pp_ptr->n + (pp_ptr->n >> 1)) >= pp_ptr->range)
175 if (((pp_ptr->flag & PROJECT_THRU) == 0) && (pp_ptr->x == pp_ptr->x2) && (pp_ptr->y == pp_ptr->y2))
178 if (pp_ptr->flag & PROJECT_DISI) {
179 if ((pp_ptr->n > 0) && cave_stop_disintegration(floor_ptr, pp_ptr->y, pp_ptr->x))
181 } else if (pp_ptr->flag & PROJECT_LOS) {
182 if ((pp_ptr->n > 0) && !cave_los_bold(floor_ptr, pp_ptr->y, pp_ptr->x))
184 } else if (!(pp_ptr->flag & PROJECT_PATH)) {
185 if ((pp_ptr->n > 0) && !cave_has_flag_bold(floor_ptr, pp_ptr->y, pp_ptr->x, FF_PROJECT))
189 if (((pp_ptr->flag & PROJECT_STOP) != 0) && (pp_ptr->n > 0)
190 && (player_bold(player_ptr, pp_ptr->y, pp_ptr->x) || floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].m_idx != 0))
193 if (!in_bounds(floor_ptr, pp_ptr->y, pp_ptr->x))
196 pp_ptr->y += pp_ptr->sy;
197 pp_ptr->x += pp_ptr->sx;
202 * @brief 始点から終点への直線経路を返す /
203 * Determine the path taken by a projection.
204 * @param player_ptr プレーヤーへの参照ポインタ
205 * @param gp 経路座標リストを返す参照ポインタ
214 int projection_path(player_type *player_ptr, u16b *gp, POSITION range, POSITION y1, POSITION x1, POSITION y2, POSITION x2, BIT_FLAGS flag)
216 if ((x1 == x2) && (y1 == y2))
219 projection_path_type tmp_projection_path;
220 projection_path_type *pp_ptr = initialize_projection_path_type(&tmp_projection_path, gp, range, flag, y1, x1, y2, x2);
222 pp_ptr->half = pp_ptr->ay * pp_ptr->ax;
223 pp_ptr->full = pp_ptr->half << 1;
227 if (calc_vertical_projection(player_ptr, pp_ptr))
230 if (calc_horizontal_projection(player_ptr, pp_ptr))
233 pp_ptr->y = y1 + pp_ptr->sy;
234 pp_ptr->x = x1 + pp_ptr->sx;
235 calc_projection_others(player_ptr, pp_ptr);
240 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
241 * at the final destination, assuming no monster gets in the way.
243 * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
245 bool projectable(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
248 int grid_n = projection_path(player_ptr, grid_g, (project_length ? project_length : get_max_range(player_ptr)), y1, x1, y2, x2, 0);
252 POSITION y = get_grid_y(grid_g[grid_n - 1]);
253 POSITION x = get_grid_x(grid_g[grid_n - 1]);
254 if ((y != y2) || (x != x2))
261 * @briefプレイヤーの攻撃射程(マス) / Maximum range (spells, etc)
262 * @param creature_ptr プレーヤーへの参照ポインタ
265 int get_max_range(player_type *creature_ptr) { return creature_ptr->phase_out ? 36 : 18; }
268 * Convert a "grid" (G) into a "location" (Y)
270 POSITION get_grid_y(u16b grid) { return (int)(grid / 256U); }
273 * Convert a "grid" (G) into a "location" (X)
275 POSITION get_grid_x(u16b grid) { return (int)(grid % 256U); }