OSDN Git Service

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