OSDN Git Service

[Release] 3.0.0Alpha48
[hengbandforosx/hengbandosx.git] / src / cmd-action / cmd-travel.cpp
1 #include "cmd-action/cmd-travel.h"
2 #include "action/travel-execution.h"
3 #include "core/asking-player.h"
4 #include "floor/cave.h"
5 #include "floor/geometry.h"
6 #include "grid/feature.h"
7 #include "grid/grid.h"
8 #include "player/player-move.h"
9 #include "player/player-status-flags.h"
10 #include "system/floor-type-definition.h"
11 #include "system/grid-type-definition.h"
12 #include "system/player-type-definition.h"
13 #include "target/grid-selector.h"
14 #include "util/bit-flags-calculator.h"
15 #include "view/display-messages.h"
16
17 #define TRAVEL_UNABLE 9999
18
19 /*!
20  * @brief トラベル処理中に地形に応じた移動コスト基準を返す
21  * @param player_ptr    プレイヤーへの参照ポインタ
22  * @param y 該当地点のY座標
23  * @param x 該当地点のX座標
24  * @return コスト値
25  */
26 static int travel_flow_cost(PlayerType *player_ptr, POSITION y, POSITION x)
27 {
28     int cost = 1;
29     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
30     feature_type *f_ptr = &f_info[g_ptr->feat];
31     if (f_ptr->flags.has(FloorFeatureType::AVOID_RUN))
32         cost += 1;
33
34     if (f_ptr->flags.has_all_of({FloorFeatureType::WATER, FloorFeatureType::DEEP}) && !player_ptr->levitation)
35         cost += 5;
36
37     if (f_ptr->flags.has(FloorFeatureType::LAVA)) {
38         int lava = 2;
39         if (!has_resist_fire(player_ptr))
40             lava *= 2;
41
42         if (!player_ptr->levitation)
43             lava *= 2;
44
45         if (f_ptr->flags.has(FloorFeatureType::DEEP))
46             lava *= 2;
47
48         cost += lava;
49     }
50
51     if (g_ptr->is_mark()) {
52         if (f_ptr->flags.has(FloorFeatureType::DOOR))
53             cost += 1;
54
55         if (f_ptr->flags.has(FloorFeatureType::TRAP))
56             cost += 10;
57     }
58
59     return cost;
60 }
61
62 /*!
63  * @brief トラベル処理の到達地点までの行程を得る処理のサブルーチン
64  * @param player_ptr    プレイヤーへの参照ポインタ
65  * @param y 目標地点のY座標
66  * @param x 目標地点のX座標
67  * @param n 現在のコスト
68  * @param wall プレイヤーが壁の中にいるならばTRUE
69  */
70 static void travel_flow_aux(PlayerType *player_ptr, POSITION y, POSITION x, int n, bool wall)
71 {
72     floor_type *floor_ptr = player_ptr->current_floor_ptr;
73     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
74     feature_type *f_ptr = &f_info[g_ptr->feat];
75     if (!in_bounds(floor_ptr, y, x))
76         return;
77
78     if (floor_ptr->dun_level > 0 && !(g_ptr->info & CAVE_KNOWN))
79         return;
80
81     int add_cost = 1;
82     int from_wall = (n / TRAVEL_UNABLE);
83     if (f_ptr->flags.has(FloorFeatureType::WALL) || f_ptr->flags.has(FloorFeatureType::CAN_DIG) || (f_ptr->flags.has(FloorFeatureType::DOOR) && floor_ptr->grid_array[y][x].mimic)
84         || (f_ptr->flags.has_not(FloorFeatureType::MOVE) && f_ptr->flags.has(FloorFeatureType::CAN_FLY) && !player_ptr->levitation)) {
85         if (!wall || !from_wall)
86             return;
87
88         add_cost += TRAVEL_UNABLE;
89     } else
90         add_cost = travel_flow_cost(player_ptr, y, x);
91
92     int base_cost = (n % TRAVEL_UNABLE);
93     int cost = base_cost + add_cost;
94     if (travel.cost[y][x] <= cost)
95         return;
96
97     travel.cost[y][x] = cost;
98     int old_head = flow_head;
99     temp2_y[flow_head] = y;
100     temp2_x[flow_head] = x;
101     if (++flow_head == MAX_SHORT)
102         flow_head = 0;
103
104     if (flow_head == flow_tail)
105         flow_head = old_head;
106 }
107
108 /*!
109  * @brief トラベル処理の到達地点までの行程を得る処理のメインルーチン
110  * @param player_ptr    プレイヤーへの参照ポインタ
111  * @param ty 目標地点のY座標
112  * @param tx 目標地点のX座標
113  */
114 static void travel_flow(PlayerType *player_ptr, POSITION ty, POSITION tx)
115 {
116     flow_head = flow_tail = 0;
117     bool wall = false;
118     feature_type *f_ptr = &f_info[player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].feat];
119     if (f_ptr->flags.has_not(FloorFeatureType::MOVE))
120         wall = true;
121
122     travel_flow_aux(player_ptr, ty, tx, 0, wall);
123     POSITION x, y;
124     while (flow_head != flow_tail) {
125         y = temp2_y[flow_tail];
126         x = temp2_x[flow_tail];
127         if (++flow_tail == MAX_SHORT)
128             flow_tail = 0;
129
130         for (DIRECTION d = 0; d < 8; d++)
131             travel_flow_aux(player_ptr, y + ddy_ddd[d], x + ddx_ddd[d], travel.cost[y][x], wall);
132     }
133
134     flow_head = flow_tail = 0;
135 }
136
137 /*!
138  * @brief トラベル処理のメインルーチン
139  */
140 void do_cmd_travel(PlayerType *player_ptr)
141 {
142     POSITION x, y;
143     if ((travel.x != 0) && (travel.y != 0) && (travel.x != player_ptr->x) && (travel.y != player_ptr->y)
144         && get_check(_("トラベルを継続しますか?", "Do you continue to travel? "))) {
145         y = travel.y;
146         x = travel.x;
147     } else if (!tgt_pt(player_ptr, &x, &y))
148         return;
149
150     if ((x == player_ptr->x) && (y == player_ptr->y)) {
151         msg_print(_("すでにそこにいます!", "You are already there!!"));
152         return;
153     }
154
155     floor_type *floor_ptr = player_ptr->current_floor_ptr;
156     feature_type *f_ptr;
157     f_ptr = &f_info[floor_ptr->grid_array[y][x].feat];
158     if ((floor_ptr->grid_array[y][x].info & CAVE_MARK)
159         && (f_ptr->flags.has(FloorFeatureType::WALL) || f_ptr->flags.has(FloorFeatureType::CAN_DIG) || (f_ptr->flags.has(FloorFeatureType::DOOR) && floor_ptr->grid_array[y][x].mimic))) {
160         msg_print(_("そこには行くことができません!", "You cannot travel there!"));
161         return;
162     }
163
164     forget_travel_flow(player_ptr->current_floor_ptr);
165     travel_flow(player_ptr, y, x);
166     travel.x = x;
167     travel.y = y;
168     travel.run = 255;
169     travel.dir = 0;
170     POSITION dx = abs(player_ptr->x - x);
171     POSITION dy = abs(player_ptr->y - y);
172     POSITION sx = ((x == player_ptr->x) || (dx < dy)) ? 0 : ((x > player_ptr->x) ? 1 : -1);
173     POSITION sy = ((y == player_ptr->y) || (dy < dx)) ? 0 : ((y > player_ptr->y) ? 1 : -1);
174     for (int i = 1; i <= 9; i++)
175         if ((sx == ddx[i]) && (sy == ddy[i]))
176             travel.dir = i;
177 }