OSDN Git Service

Merge pull request #2290 from habu1010/feature/clang-format-insert-braces
[hengbandforosx/hengbandosx.git] / src / action / open-close-execution.cpp
1 /*!
2  * @file open-close-execution.cpp
3  * @brief 扉や箱を開ける処理
4  * @date 2020/07/11
5  * @author Hourier
6  */
7
8 #include "action/open-close-execution.h"
9 #include "action/movement-execution.h"
10 #include "combat/attack-power-table.h"
11 #include "game-option/disturbance-options.h"
12 #include "game-option/input-options.h"
13 #include "grid/feature.h"
14 #include "grid/grid.h"
15 #include "grid/trap.h"
16 #include "main/sound-definitions-table.h"
17 #include "main/sound-of-music.h"
18 #include "perception/object-perception.h"
19 #include "player-base/player-class.h"
20 #include "player-status/player-energy.h"
21 #include "player/player-status-table.h"
22 #include "specific-object/chest.h"
23 #include "status/bad-status-setter.h"
24 #include "status/experience.h"
25 #include "system/floor-type-definition.h"
26 #include "system/grid-type-definition.h"
27 #include "system/object-type-definition.h"
28 #include "system/player-type-definition.h"
29 #include "term/screen-processor.h"
30 #include "util/bit-flags-calculator.h"
31 #include "view/display-messages.h"
32
33 /*!
34  * @brief 「開ける」動作コマンドのサブルーチン /
35  * Perform the basic "open" command on doors
36  * @param y 対象を行うマスのY座標
37  * @param x 対象を行うマスのX座標
38  * @return 連続でコマンドを実行する時のみTRUE、1回きりの時はFALSE
39  */
40 bool exe_open(PlayerType *player_ptr, POSITION y, POSITION x)
41 {
42     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
43     auto *f_ptr = &f_info[g_ptr->feat];
44     PlayerEnergy(player_ptr).set_player_turn_energy(100);
45     if (f_ptr->flags.has_not(FloorFeatureType::OPEN)) {
46         msg_format(_("%sはがっちりと閉じられているようだ。", "The %s appears to be stuck."), f_info[g_ptr->get_feat_mimic()].name.c_str());
47         return false;
48     }
49
50     if (!f_ptr->power) {
51         cave_alter_feat(player_ptr, y, x, FloorFeatureType::OPEN);
52         sound(SOUND_OPENDOOR);
53         return false;
54     }
55
56     int i = player_ptr->skill_dis;
57     if (player_ptr->blind || no_lite(player_ptr)) {
58         i = i / 10;
59     }
60
61     if (player_ptr->confused || player_ptr->hallucinated) {
62         i = i / 10;
63     }
64
65     int j = f_ptr->power;
66     j = i - (j * 4);
67     if (j < 2) {
68         j = 2;
69     }
70
71     if (randint0(100) >= j) {
72         if (flush_failure) {
73             flush();
74         }
75
76         msg_print(_("鍵をはずせなかった。", "You failed to pick the lock."));
77         return true;
78     }
79
80     msg_print(_("鍵をはずした。", "You have picked the lock."));
81     cave_alter_feat(player_ptr, y, x, FloorFeatureType::OPEN);
82     sound(SOUND_OPENDOOR);
83     gain_exp(player_ptr, 1);
84     return false;
85 }
86
87 /*!
88  * @brief 「閉じる」動作コマンドのサブルーチン /
89  * Perform the basic "close" command
90  * @param y 対象を行うマスのY座標
91  * @param x 対象を行うマスのX座標
92  * @return 実際に処理が行われた場合TRUEを返す。
93  * @details
94  * Assume destination is an open/broken door
95  * Assume there is no monster blocking the destination
96  * Returns TRUE if repeated commands may continue
97  * @todo 常にFALSEを返している
98  */
99 bool exe_close(PlayerType *player_ptr, POSITION y, POSITION x)
100 {
101     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
102     FEAT_IDX old_feat = g_ptr->feat;
103     bool more = false;
104     PlayerEnergy(player_ptr).set_player_turn_energy(100);
105     if (f_info[old_feat].flags.has_not(FloorFeatureType::CLOSE)) {
106         return more;
107     }
108
109     int16_t closed_feat = feat_state(player_ptr->current_floor_ptr, old_feat, FloorFeatureType::CLOSE);
110     if ((!g_ptr->o_idx_list.empty() || g_ptr->is_object()) && (closed_feat != old_feat) && f_info[closed_feat].flags.has_not(FloorFeatureType::DROP)) {
111         msg_print(_("何かがつっかえて閉まらない。", "Something prevents it from closing."));
112         return more;
113     }
114
115     cave_alter_feat(player_ptr, y, x, FloorFeatureType::CLOSE);
116     if (old_feat == g_ptr->feat) {
117         msg_print(_("ドアは壊れてしまっている。", "The door appears to be broken."));
118     } else {
119         sound(SOUND_SHUTDOOR);
120     }
121
122     return more;
123 }
124
125 /*!
126  * @brief 移動処理による簡易な「開く」処理 /
127  * easy_open_door --
128  * @return 開く処理が実際に試みられた場合TRUEを返す
129  * @details
130  * <pre>
131  *      If there is a jammed/closed/locked door at the given location,
132  *      then attempt to unlock/open it. Return TRUE if an attempt was
133  *      made (successful or not), otherwise return FALSE.
134  *
135  *      The code here should be nearly identical to that in
136  *      do_cmd_open_test() and exe_open().
137  * </pre>
138  */
139 bool easy_open_door(PlayerType *player_ptr, POSITION y, POSITION x)
140 {
141     int i, j;
142     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
143     auto *f_ptr = &f_info[g_ptr->feat];
144     if (!is_closed_door(player_ptr, g_ptr->feat)) {
145         return false;
146     }
147
148     if (f_ptr->flags.has_not(FloorFeatureType::OPEN)) {
149         msg_format(_("%sはがっちりと閉じられているようだ。", "The %s appears to be stuck."), f_info[g_ptr->get_feat_mimic()].name.c_str());
150     } else if (f_ptr->power) {
151         i = player_ptr->skill_dis;
152         if (player_ptr->blind || no_lite(player_ptr)) {
153             i = i / 10;
154         }
155
156         if (player_ptr->confused || player_ptr->hallucinated) {
157             i = i / 10;
158         }
159
160         j = f_ptr->power;
161         j = i - (j * 4);
162         if (j < 2) {
163             j = 2;
164         }
165
166         if (randint0(100) < j) {
167             msg_print(_("鍵をはずした。", "You have picked the lock."));
168             cave_alter_feat(player_ptr, y, x, FloorFeatureType::OPEN);
169             sound(SOUND_OPENDOOR);
170             gain_exp(player_ptr, 1);
171         } else {
172             if (flush_failure) {
173                 flush();
174             }
175
176             msg_print(_("鍵をはずせなかった。", "You failed to pick the lock."));
177         }
178     } else {
179         cave_alter_feat(player_ptr, y, x, FloorFeatureType::OPEN);
180         sound(SOUND_OPENDOOR);
181     }
182
183     return true;
184 }
185
186 /*!
187  * @brief 箱のトラップを解除する実行処理 /
188  * Perform the basic "disarm" command
189  * @param y 解除を行うマスのY座標
190  * @param x 解除を行うマスのX座標
191  * @param o_idx 箱のオブジェクトID
192  * @return ターンを消費する処理が行われた場合TRUEを返す
193  * @details
194  * <pre>
195  * Assume destination is a visible trap
196  * Assume there is no monster blocking the destination
197  * Returns TRUE if repeated commands may continue
198  * </pre>
199  */
200 bool exe_disarm_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJECT_IDX o_idx)
201 {
202     bool more = false;
203     auto *o_ptr = &player_ptr->current_floor_ptr->o_list[o_idx];
204     PlayerEnergy(player_ptr).set_player_turn_energy(100);
205     int i = player_ptr->skill_dis;
206     if (player_ptr->blind || no_lite(player_ptr)) {
207         i = i / 10;
208     }
209
210     if (player_ptr->confused || player_ptr->hallucinated) {
211         i = i / 10;
212     }
213
214     int j = i - o_ptr->pval;
215     if (j < 2) {
216         j = 2;
217     }
218
219     if (!o_ptr->is_known()) {
220         msg_print(_("トラップが見あたらない。", "I don't see any traps."));
221     } else if (o_ptr->pval <= 0) {
222         msg_print(_("箱にはトラップが仕掛けられていない。", "The chest is not trapped."));
223     } else if (chest_traps[o_ptr->pval].none()) {
224         msg_print(_("箱にはトラップが仕掛けられていない。", "The chest is not trapped."));
225     } else if (randint0(100) < j) {
226         msg_print(_("箱に仕掛けられていたトラップを解除した。", "You have disarmed the chest."));
227         gain_exp(player_ptr, o_ptr->pval);
228         o_ptr->pval = (0 - o_ptr->pval);
229     } else if ((i > 5) && (randint1(i) > 5)) {
230         more = true;
231         if (flush_failure) {
232             flush();
233         }
234
235         msg_print(_("箱のトラップ解除に失敗した。", "You failed to disarm the chest."));
236     } else {
237         msg_print(_("トラップを作動させてしまった!", "You set off a trap!"));
238         sound(SOUND_FAIL);
239         Chest(player_ptr).chest_trap(y, x, o_idx);
240     }
241
242     return more;
243 }
244
245 /*!
246  * @brief 箱のトラップを解除するコマンドのサブルーチン /
247  * Perform the basic "disarm" command
248  * @param y 解除を行うマスのY座標
249  * @param x 解除を行うマスのX座標
250  * @param dir プレイヤーからみた方向ID
251  * @return ターンを消費する処理が行われた場合TRUEを返す
252  * @details
253  * <pre>
254  * Assume destination is a visible trap
255  * Assume there is no monster blocking the destination
256  * Returns TRUE if repeated commands may continue
257  * </pre>
258  */
259
260 bool exe_disarm(PlayerType *player_ptr, POSITION y, POSITION x, DIRECTION dir)
261 {
262     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
263     auto *f_ptr = &f_info[g_ptr->feat];
264     concptr name = f_ptr->name.c_str();
265     int power = f_ptr->power;
266     bool more = false;
267     int i = player_ptr->skill_dis;
268     PlayerEnergy(player_ptr).set_player_turn_energy(100);
269     if (player_ptr->blind || no_lite(player_ptr)) {
270         i = i / 10;
271     }
272
273     if (player_ptr->confused || player_ptr->hallucinated) {
274         i = i / 10;
275     }
276
277     int j = i - power;
278     if (j < 2) {
279         j = 2;
280     }
281
282     if (randint0(100) < j) {
283         msg_format(_("%sを解除した。", "You have disarmed the %s."), name);
284         gain_exp(player_ptr, power);
285         cave_alter_feat(player_ptr, y, x, FloorFeatureType::DISARM);
286         exe_movement(player_ptr, dir, easy_disarm, false);
287     } else if ((i > 5) && (randint1(i) > 5)) {
288         if (flush_failure) {
289             flush();
290         }
291
292         msg_format(_("%sの解除に失敗した。", "You failed to disarm the %s."), name);
293         more = true;
294     } else {
295         msg_format(_("%sを作動させてしまった!", "You set off the %s!"), name);
296         exe_movement(player_ptr, dir, easy_disarm, false);
297     }
298
299     return more;
300 }
301
302 /*!
303  * @brief 「打ち破る」動作コマンドのサブルーチン /
304  * Perform the basic "bash" command
305  * @param y 対象を行うマスのY座標
306  * @param x 対象を行うマスのX座標
307  * @param dir プレイヤーから見たターゲットの方角ID
308  * @return 実際に処理が行われた場合TRUEを返す。
309  * @details
310  * <pre>
311  * Assume destination is a closed/locked/jammed door
312  * Assume there is no monster blocking the destination
313  * Returns TRUE if repeated commands may continue
314  * </pre>
315  */
316 bool exe_bash(PlayerType *player_ptr, POSITION y, POSITION x, DIRECTION dir)
317 {
318     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
319     auto *f_ptr = &f_info[g_ptr->feat];
320     int bash = adj_str_blow[player_ptr->stat_index[A_STR]];
321     int temp = f_ptr->power;
322     bool more = false;
323     concptr name = f_info[g_ptr->get_feat_mimic()].name.c_str();
324     PlayerEnergy(player_ptr).set_player_turn_energy(100);
325     msg_format(_("%sに体当たりをした!", "You smash into the %s!"), name);
326     temp = (bash - (temp * 10));
327     if (PlayerClass(player_ptr).equals(PlayerClassType::BERSERKER)) {
328         temp *= 2;
329     }
330
331     if (temp < 1) {
332         temp = 1;
333     }
334
335     if (randint0(100) < temp) {
336         msg_format(_("%sを壊した!", "The %s crashes open!"), name);
337         sound(f_ptr->flags.has(FloorFeatureType::GLASS) ? SOUND_GLASS : SOUND_OPENDOOR);
338         if ((randint0(100) < 50) || (feat_state(player_ptr->current_floor_ptr, g_ptr->feat, FloorFeatureType::OPEN) == g_ptr->feat) || f_ptr->flags.has(FloorFeatureType::GLASS)) {
339             cave_alter_feat(player_ptr, y, x, FloorFeatureType::BASH);
340         } else {
341             cave_alter_feat(player_ptr, y, x, FloorFeatureType::OPEN);
342         }
343
344         exe_movement(player_ptr, dir, false, false);
345     } else if (randint0(100) < adj_dex_safe[player_ptr->stat_index[A_DEX]] + player_ptr->lev) {
346         msg_format(_("この%sは頑丈だ。", "The %s holds firm."), name);
347         more = true;
348     } else {
349         msg_print(_("体のバランスをくずしてしまった。", "You are off-balance."));
350         (void)BadStatusSetter(player_ptr).mod_paralysis(2 + randint0(2));
351     }
352
353     return more;
354 }