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 "monster/monster-util.h"
7 #include "spell-class/spells-mirror-master.h"
8 #include "system/angband-system.h"
9 #include "system/floor-type-definition.h"
10 #include "system/grid-type-definition.h"
11 #include "system/player-type-definition.h"
12 #include "util/bit-flags-calculator.h"
14 struct projection_path_type {
15 std::vector<std::pair<int, int>> *position;
35 std::vector<std::pair<int, int>>::const_iterator projection_path::begin() const
37 return this->position.cbegin();
40 std::vector<std::pair<int, int>>::const_iterator projection_path::end() const
42 return this->position.cend();
45 const std::pair<int, int> &projection_path::front() const
47 return this->position.front();
50 const std::pair<int, int> &projection_path::back() const
52 return this->position.back();
55 const std::pair<int, int> &projection_path::operator[](int num) const
57 return this->position[num];
60 int projection_path::path_num() const
62 return static_cast<int>(this->position.size());
65 static projection_path_type *initialize_projection_path_type(
66 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)
68 pp_ptr->position = position;
69 pp_ptr->range = range;
78 static void set_asxy(projection_path_type *pp_ptr)
80 if (pp_ptr->y2 < pp_ptr->y1) {
81 pp_ptr->ay = pp_ptr->y1 - pp_ptr->y2;
84 pp_ptr->ay = pp_ptr->y2 - pp_ptr->y1;
88 if (pp_ptr->x2 < pp_ptr->x1) {
89 pp_ptr->ax = pp_ptr->x1 - pp_ptr->x2;
92 pp_ptr->ax = pp_ptr->x2 - pp_ptr->x1;
97 static bool project_stop(PlayerType *player_ptr, projection_path_type *pp_ptr)
99 auto *floor_ptr = player_ptr->current_floor_ptr;
100 const Pos2D pos(pp_ptr->y, pp_ptr->x);
101 const Pos2D pos2(pp_ptr->y2, pp_ptr->x2);
102 if (none_bits(pp_ptr->flag, PROJECT_THRU) && (pos == pos2)) {
106 if (any_bits(pp_ptr->flag, PROJECT_DISI)) {
107 if (!pp_ptr->position->empty() && cave_stop_disintegration(floor_ptr, pos.y, pos.x)) {
110 } else if (any_bits(pp_ptr->flag, PROJECT_LOS)) {
111 if (!pp_ptr->position->empty() && !cave_los_bold(floor_ptr, pos.y, pos.x)) {
114 } else if (none_bits(pp_ptr->flag, PROJECT_PATH)) {
115 if (!pp_ptr->position->empty() && !cave_has_flag_bold(floor_ptr, pos.y, pos.x, TerrainCharacteristics::PROJECT)) {
120 const auto &grid = floor_ptr->get_grid(pos);
121 if (any_bits(pp_ptr->flag, PROJECT_MIRROR)) {
122 if (!pp_ptr->position->empty() && grid.is_mirror()) {
127 if (any_bits(pp_ptr->flag, PROJECT_STOP) && !pp_ptr->position->empty() && (player_ptr->is_located_at(pos) || is_monster(grid.m_idx))) {
131 if (!in_bounds(floor_ptr, pos.y, pos.x)) {
138 static void calc_frac(projection_path_type *pp_ptr, bool is_vertical)
140 if (pp_ptr->m == 0) {
144 pp_ptr->frac += pp_ptr->m;
145 if (pp_ptr->frac <= pp_ptr->half) {
150 pp_ptr->x += pp_ptr->sx;
152 pp_ptr->y += pp_ptr->sy;
155 pp_ptr->frac -= pp_ptr->full;
159 static void calc_projection_to_target(PlayerType *player_ptr, projection_path_type *pp_ptr, bool is_vertical)
162 pp_ptr->position->emplace_back(pp_ptr->y, pp_ptr->x);
163 if (static_cast<int>(pp_ptr->position->size()) + pp_ptr->k / 2 >= pp_ptr->range) {
167 if (project_stop(player_ptr, pp_ptr)) {
171 calc_frac(pp_ptr, is_vertical);
173 pp_ptr->y += pp_ptr->sy;
175 pp_ptr->x += pp_ptr->sx;
180 static bool calc_vertical_projection(PlayerType *player_ptr, projection_path_type *pp_ptr)
182 if (pp_ptr->ay <= pp_ptr->ax) {
186 pp_ptr->m = pp_ptr->ax * pp_ptr->ax * 2;
187 pp_ptr->y = pp_ptr->y1 + pp_ptr->sy;
188 pp_ptr->x = pp_ptr->x1;
189 pp_ptr->frac = pp_ptr->m;
190 if (pp_ptr->frac > pp_ptr->half) {
191 pp_ptr->x += pp_ptr->sx;
192 pp_ptr->frac -= pp_ptr->full;
196 calc_projection_to_target(player_ptr, pp_ptr, true);
200 static bool calc_horizontal_projection(PlayerType *player_ptr, projection_path_type *pp_ptr)
202 if (pp_ptr->ax <= pp_ptr->ay) {
206 pp_ptr->m = pp_ptr->ay * pp_ptr->ay * 2;
207 pp_ptr->y = pp_ptr->y1;
208 pp_ptr->x = pp_ptr->x1 + pp_ptr->sx;
209 pp_ptr->frac = pp_ptr->m;
210 if (pp_ptr->frac > pp_ptr->half) {
211 pp_ptr->y += pp_ptr->sy;
212 pp_ptr->frac -= pp_ptr->full;
216 calc_projection_to_target(player_ptr, pp_ptr, false);
220 static void calc_projection_others(PlayerType *player_ptr, projection_path_type *pp_ptr)
223 pp_ptr->position->emplace_back(pp_ptr->y, pp_ptr->x);
224 if (static_cast<int>(pp_ptr->position->size()) * 3 / 2 >= pp_ptr->range) {
228 if (project_stop(player_ptr, pp_ptr)) {
232 pp_ptr->y += pp_ptr->sy;
233 pp_ptr->x += pp_ptr->sx;
238 * @brief 始点から終点への直線経路を返す /
239 * Determine the path taken by a projection.
240 * @param player_ptr プレイヤーへの参照ポインタ
249 projection_path::projection_path(PlayerType *player_ptr, POSITION range, POSITION y1, POSITION x1, POSITION y2, POSITION x2, BIT_FLAGS flag)
251 this->position.clear();
252 if ((x1 == x2) && (y1 == y2)) {
256 projection_path_type tmp_projection_path;
257 auto *pp_ptr = initialize_projection_path_type(&tmp_projection_path, &this->position, range, flag, y1, x1, y2, x2);
259 pp_ptr->half = pp_ptr->ay * pp_ptr->ax;
260 pp_ptr->full = pp_ptr->half << 1;
263 if (calc_vertical_projection(player_ptr, pp_ptr)) {
267 if (calc_horizontal_projection(player_ptr, pp_ptr)) {
271 pp_ptr->y = y1 + pp_ptr->sy;
272 pp_ptr->x = x1 + pp_ptr->sx;
273 calc_projection_others(player_ptr, pp_ptr);
277 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
278 * at the final destination, assuming no monster gets in the way.
280 * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
282 bool projectable(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
284 projection_path grid_g(player_ptr, (project_length ? project_length : AngbandSystem::get_instance().get_max_range()), y1, x1, y2, x2, 0);
285 if (grid_g.path_num() == 0) {
289 const auto &[y, x] = grid_g.back();
290 if ((y != y2) || (x != x2)) {
298 * Convert a "grid" (G) into a "location" (Y)
300 POSITION get_grid_y(uint16_t grid)
302 return (int)(grid / 256U);
306 * Convert a "grid" (G) into a "location" (X)
308 POSITION get_grid_x(uint16_t grid)
310 return (int)(grid % 256U);