OSDN Git Service

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