OSDN Git Service

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