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"
6 #include "spell-class/spells-mirror-master.h"
7 #include "system/floor-type-definition.h"
8 #include "system/grid-type-definition.h"
9 #include "system/player-type-definition.h"
10 #include "util/bit-flags-calculator.h"
12 struct projection_path_type {
13 std::vector<std::pair<int, int>> *position;
33 std::vector<std::pair<int, int>>::const_iterator projection_path::begin() const
35 return this->position.cbegin();
38 std::vector<std::pair<int, int>>::const_iterator projection_path::end() const
40 return this->position.cend();
43 const std::pair<int, int> &projection_path::front() const
45 return this->position.front();
48 const std::pair<int, int> &projection_path::back() const
50 return this->position.back();
53 const std::pair<int, int> &projection_path::operator[](int num) const
55 return this->position[num];
58 int projection_path::path_num() const
60 return static_cast<int>(this->position.size());
63 static projection_path_type *initialize_projection_path_type(
64 projection_path_type *pp_ptr, std::vector<std::pair<int, int>> *position, POSITION range, BIT_FLAGS flag, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
66 pp_ptr->position = position;
67 pp_ptr->range = range;
76 static void set_asxy(projection_path_type *pp_ptr)
78 if (pp_ptr->y2 < pp_ptr->y1) {
79 pp_ptr->ay = pp_ptr->y1 - pp_ptr->y2;
82 pp_ptr->ay = pp_ptr->y2 - pp_ptr->y1;
86 if (pp_ptr->x2 < pp_ptr->x1) {
87 pp_ptr->ax = pp_ptr->x1 - pp_ptr->x2;
90 pp_ptr->ax = pp_ptr->x2 - pp_ptr->x1;
95 static bool project_stop(PlayerType *player_ptr, projection_path_type *pp_ptr)
97 auto *floor_ptr = player_ptr->current_floor_ptr;
99 if (none_bits(pp_ptr->flag, PROJECT_THRU) && (pp_ptr->x == pp_ptr->x2) && (pp_ptr->y == pp_ptr->y2)) {
103 if (any_bits(pp_ptr->flag, PROJECT_DISI)) {
104 if (!pp_ptr->position->empty() && cave_stop_disintegration(floor_ptr, pp_ptr->y, pp_ptr->x)) {
107 } else if (any_bits(pp_ptr->flag, PROJECT_LOS)) {
108 if (!pp_ptr->position->empty() && !cave_los_bold(floor_ptr, pp_ptr->y, pp_ptr->x)) {
111 } else if (none_bits(pp_ptr->flag, PROJECT_PATH)) {
112 if (!pp_ptr->position->empty() && !cave_has_flag_bold(floor_ptr, pp_ptr->y, pp_ptr->x, TerrainCharacteristics::PROJECT)) {
117 if (any_bits(pp_ptr->flag, PROJECT_MIRROR)) {
118 if (!pp_ptr->position->empty() && floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].is_mirror()) {
123 if (any_bits(pp_ptr->flag, PROJECT_STOP) && !pp_ptr->position->empty() && (player_bold(player_ptr, pp_ptr->y, pp_ptr->x) || floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].m_idx != 0)) {
127 if (!in_bounds(floor_ptr, pp_ptr->y, pp_ptr->x)) {
134 static void calc_frac(projection_path_type *pp_ptr, bool is_vertical)
136 if (pp_ptr->m == 0) {
140 pp_ptr->frac += pp_ptr->m;
141 if (pp_ptr->frac <= pp_ptr->half) {
146 pp_ptr->x += pp_ptr->sx;
148 pp_ptr->y += pp_ptr->sy;
151 pp_ptr->frac -= pp_ptr->full;
155 static void calc_projection_to_target(PlayerType *player_ptr, projection_path_type *pp_ptr, bool is_vertical)
158 pp_ptr->position->emplace_back(pp_ptr->y, pp_ptr->x);
159 if (static_cast<int>(pp_ptr->position->size()) + pp_ptr->k / 2 >= pp_ptr->range) {
163 if (project_stop(player_ptr, pp_ptr)) {
167 calc_frac(pp_ptr, is_vertical);
169 pp_ptr->y += pp_ptr->sy;
171 pp_ptr->x += pp_ptr->sx;
176 static bool calc_vertical_projection(PlayerType *player_ptr, projection_path_type *pp_ptr)
178 if (pp_ptr->ay <= pp_ptr->ax) {
182 pp_ptr->m = pp_ptr->ax * pp_ptr->ax * 2;
183 pp_ptr->y = pp_ptr->y1 + pp_ptr->sy;
184 pp_ptr->x = pp_ptr->x1;
185 pp_ptr->frac = pp_ptr->m;
186 if (pp_ptr->frac > pp_ptr->half) {
187 pp_ptr->x += pp_ptr->sx;
188 pp_ptr->frac -= pp_ptr->full;
192 calc_projection_to_target(player_ptr, pp_ptr, true);
196 static bool calc_horizontal_projection(PlayerType *player_ptr, projection_path_type *pp_ptr)
198 if (pp_ptr->ax <= pp_ptr->ay) {
202 pp_ptr->m = pp_ptr->ay * pp_ptr->ay * 2;
203 pp_ptr->y = pp_ptr->y1;
204 pp_ptr->x = pp_ptr->x1 + pp_ptr->sx;
205 pp_ptr->frac = pp_ptr->m;
206 if (pp_ptr->frac > pp_ptr->half) {
207 pp_ptr->y += pp_ptr->sy;
208 pp_ptr->frac -= pp_ptr->full;
212 calc_projection_to_target(player_ptr, pp_ptr, false);
216 static void calc_projection_others(PlayerType *player_ptr, projection_path_type *pp_ptr)
219 pp_ptr->position->emplace_back(pp_ptr->y, pp_ptr->x);
220 if (static_cast<int>(pp_ptr->position->size()) * 3 / 2 >= pp_ptr->range) {
224 if (project_stop(player_ptr, pp_ptr)) {
228 pp_ptr->y += pp_ptr->sy;
229 pp_ptr->x += pp_ptr->sx;
234 * @brief 始点から終点への直線経路を返す /
235 * Determine the path taken by a projection.
236 * @param player_ptr プレイヤーへの参照ポインタ
245 projection_path::projection_path(PlayerType *player_ptr, POSITION range, POSITION y1, POSITION x1, POSITION y2, POSITION x2, BIT_FLAGS flag)
247 this->position.clear();
248 if ((x1 == x2) && (y1 == y2)) {
252 projection_path_type tmp_projection_path;
253 auto *pp_ptr = initialize_projection_path_type(&tmp_projection_path, &this->position, range, flag, y1, x1, y2, x2);
255 pp_ptr->half = pp_ptr->ay * pp_ptr->ax;
256 pp_ptr->full = pp_ptr->half << 1;
259 if (calc_vertical_projection(player_ptr, pp_ptr)) {
263 if (calc_horizontal_projection(player_ptr, pp_ptr)) {
267 pp_ptr->y = y1 + pp_ptr->sy;
268 pp_ptr->x = x1 + pp_ptr->sx;
269 calc_projection_others(player_ptr, pp_ptr);
273 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
274 * at the final destination, assuming no monster gets in the way.
276 * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
278 bool projectable(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
280 projection_path grid_g(player_ptr, (project_length ? project_length : get_max_range(player_ptr)), y1, x1, y2, x2, 0);
281 if (grid_g.path_num() == 0) {
285 const auto [y, x] = grid_g.back();
286 if ((y != y2) || (x != x2)) {
294 * @briefプレイヤーの攻撃射程(マス) / Maximum range (spells, etc)
295 * @param player_ptr プレイヤーへの参照ポインタ
298 int get_max_range(PlayerType *player_ptr)
300 return player_ptr->phase_out ? 36 : 18;
304 * Convert a "grid" (G) into a "location" (Y)
306 POSITION get_grid_y(uint16_t grid)
308 return (int)(grid / 256U);
312 * Convert a "grid" (G) into a "location" (X)
314 POSITION get_grid_x(uint16_t grid)
316 return (int)(grid % 256U);