OSDN Git Service

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