OSDN Git Service

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