OSDN Git Service

Merge remote-tracking branch 'remotes/origin/feature/Implement-Debug-Auto-Save' into...
[hengband/hengband.git] / src / cmd-action / cmd-open-close.c
1 #include "cmd-action/cmd-open-close.h"
2 #include "action/open-close-execution.h"
3 #include "action/open-util.h"
4 #include "cmd-action/cmd-attack.h"
5 #include "core/disturbance.h"
6 #include "core/player-redraw-types.h"
7 #include "game-option/disturbance-options.h"
8 #include "game-option/input-options.h"
9 #include "grid/feature.h"
10 #include "grid/grid.h"
11 #include "inventory/inventory-object.h"
12 #include "inventory/inventory-slot-types.h"
13 #include "io/input-key-requester.h"
14 #include "player/attack-defense-types.h"
15 #include "player/special-defense-types.h"
16 #include "specific-object/chest.h"
17 #include "status/action-setter.h"
18 #include "status/experience.h"
19 #include "system/floor-type-definition.h"
20 #include "system/object-type-definition.h"
21 #include "target/target-getter.h"
22 #include "term/screen-processor.h"
23 #include "util/bit-flags-calculator.h"
24 #include "view/display-messages.h"
25
26 /*!
27  * @brief 箱を開ける実行処理 /
28  * Attempt to open the given chest at the given location
29  * @param y 箱の存在するマスのY座標
30  * @param x 箱の存在するマスのX座標
31  * @param o_idx 箱のオブジェクトID
32  * @return 箱が開かなかった場合TRUE / Returns TRUE if repeated commands may continue
33  * @details
34  * Assume there is no monster blocking the destination
35  */
36 static bool exe_open_chest(player_type *creature_ptr, POSITION y, POSITION x, OBJECT_IDX o_idx)
37 {
38     bool flag = TRUE;
39     bool more = FALSE;
40     object_type *o_ptr = &creature_ptr->current_floor_ptr->o_list[o_idx];
41     take_turn(creature_ptr, 100);
42     if (o_ptr->pval > 0) {
43         flag = FALSE;
44         int i = creature_ptr->skill_dis;
45         if (creature_ptr->blind || no_lite(creature_ptr))
46             i = i / 10;
47
48         if (creature_ptr->confused || creature_ptr->image)
49             i = i / 10;
50
51         int j = i - o_ptr->pval;
52         if (j < 2)
53             j = 2;
54
55         if (randint0(100) < j) {
56             msg_print(_("鍵をはずした。", "You have picked the lock."));
57             gain_exp(creature_ptr, 1);
58             flag = TRUE;
59         } else {
60             more = TRUE;
61             if (flush_failure)
62                 flush();
63
64             msg_print(_("鍵をはずせなかった。", "You failed to pick the lock."));
65         }
66     }
67
68     if (flag) {
69         chest_trap(creature_ptr, y, x, o_idx);
70         chest_death(creature_ptr, FALSE, y, x, o_idx);
71     }
72
73     return more;
74 }
75
76 /*!
77  * @brief 「開ける」コマンドのメインルーチン /
78  * Open a closed/locked/jammed door or a closed/locked chest.
79  * @return なし
80  * @details
81  * Unlocking a locked door/chest is worth one experience point.
82  */
83 void do_cmd_open(player_type *creature_ptr)
84 {
85     POSITION y, x;
86     DIRECTION dir;
87     OBJECT_IDX o_idx;
88     bool more = FALSE;
89     if (creature_ptr->wild_mode)
90         return;
91
92     if (creature_ptr->special_defense & KATA_MUSOU)
93         set_action(creature_ptr, ACTION_NONE);
94
95     if (easy_open) {
96         int num_doors = count_dt(creature_ptr, &y, &x, is_closed_door, FALSE);
97         int num_chests = count_chests(creature_ptr, &y, &x, FALSE);
98         if (num_doors || num_chests) {
99             bool too_many = (num_doors && num_chests) || (num_doors > 1) || (num_chests > 1);
100             if (!too_many)
101                 command_dir = coords_to_dir(creature_ptr, y, x);
102         }
103     }
104
105     if (command_arg) {
106         command_rep = command_arg - 1;
107         creature_ptr->redraw |= PR_STATE;
108         command_arg = 0;
109     }
110
111     if (get_rep_dir(creature_ptr, &dir, TRUE)) {
112         FEAT_IDX feat;
113         grid_type *g_ptr;
114         y = creature_ptr->y + ddy[dir];
115         x = creature_ptr->x + ddx[dir];
116         g_ptr = &creature_ptr->current_floor_ptr->grid_array[y][x];
117         feat = get_feat_mimic(g_ptr);
118         o_idx = chest_check(creature_ptr->current_floor_ptr, y, x, FALSE);
119         if (!has_flag(f_info[feat].flags, FF_OPEN) && !o_idx) {
120             msg_print(_("そこには開けるものが見当たらない。", "You see nothing there to open."));
121         } else if (g_ptr->m_idx && creature_ptr->riding != g_ptr->m_idx) {
122             take_turn(creature_ptr, 100);
123             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
124             do_cmd_attack(creature_ptr, y, x, 0);
125         } else if (o_idx) {
126             more = exe_open_chest(creature_ptr, y, x, o_idx);
127         } else {
128             more = exe_open(creature_ptr, y, x);
129         }
130     }
131
132     if (!more)
133         disturb(creature_ptr, FALSE, FALSE);
134 }
135
136 /*!
137  * @brief 「閉じる」コマンドのメインルーチン /
138  * Close an open door.
139  * @return なし
140  * @details
141  * Unlocking a locked door/chest is worth one experience point.
142  */
143 void do_cmd_close(player_type *creature_ptr)
144 {
145     POSITION y, x;
146     DIRECTION dir;
147     bool more = FALSE;
148     if (creature_ptr->wild_mode)
149         return;
150
151     if (creature_ptr->special_defense & KATA_MUSOU)
152         set_action(creature_ptr, ACTION_NONE);
153
154     if (easy_open && (count_dt(creature_ptr, &y, &x, is_open, FALSE) == 1))
155         command_dir = coords_to_dir(creature_ptr, y, x);
156
157     if (command_arg) {
158         command_rep = command_arg - 1;
159         creature_ptr->redraw |= (PR_STATE);
160         command_arg = 0;
161     }
162
163     if (get_rep_dir(creature_ptr, &dir, FALSE)) {
164         grid_type *g_ptr;
165         FEAT_IDX feat;
166         y = creature_ptr->y + ddy[dir];
167         x = creature_ptr->x + ddx[dir];
168         g_ptr = &creature_ptr->current_floor_ptr->grid_array[y][x];
169         feat = get_feat_mimic(g_ptr);
170         if (!has_flag(f_info[feat].flags, FF_CLOSE)) {
171             msg_print(_("そこには閉じるものが見当たらない。", "You see nothing there to close."));
172         } else if (g_ptr->m_idx) {
173             take_turn(creature_ptr, 100);
174             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
175             do_cmd_attack(creature_ptr, y, x, 0);
176         } else {
177             more = exe_close(creature_ptr, y, x);
178         }
179     }
180
181     if (!more)
182         disturb(creature_ptr, FALSE, FALSE);
183 }
184
185 /*!
186  * @brief 箱、床のトラップ解除処理双方の統合メインルーチン /
187  * Disarms a trap, or chest
188  * @return なし
189  */
190 void do_cmd_disarm(player_type *creature_ptr)
191 {
192     POSITION y, x;
193     DIRECTION dir;
194     OBJECT_IDX o_idx;
195     bool more = FALSE;
196     if (creature_ptr->wild_mode)
197         return;
198
199     if (creature_ptr->special_defense & KATA_MUSOU)
200         set_action(creature_ptr, ACTION_NONE);
201
202     if (easy_disarm) {
203         int num_traps = count_dt(creature_ptr, &y, &x, is_trap, TRUE);
204         int num_chests = count_chests(creature_ptr, &y, &x, TRUE);
205         if (num_traps || num_chests) {
206             bool too_many = (num_traps && num_chests) || (num_traps > 1) || (num_chests > 1);
207             if (!too_many)
208                 command_dir = coords_to_dir(creature_ptr, y, x);
209         }
210     }
211
212     if (command_arg) {
213         command_rep = command_arg - 1;
214         creature_ptr->redraw |= (PR_STATE);
215         command_arg = 0;
216     }
217
218     if (get_rep_dir(creature_ptr, &dir, TRUE)) {
219         grid_type *g_ptr;
220         FEAT_IDX feat;
221         y = creature_ptr->y + ddy[dir];
222         x = creature_ptr->x + ddx[dir];
223         g_ptr = &creature_ptr->current_floor_ptr->grid_array[y][x];
224         feat = get_feat_mimic(g_ptr);
225         o_idx = chest_check(creature_ptr->current_floor_ptr, y, x, TRUE);
226         if (!is_trap(creature_ptr, feat) && !o_idx) {
227             msg_print(_("そこには解除するものが見当たらない。", "You see nothing there to disarm."));
228         } else if (g_ptr->m_idx && creature_ptr->riding != g_ptr->m_idx) {
229             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
230             do_cmd_attack(creature_ptr, y, x, 0);
231         } else if (o_idx) {
232             more = exe_disarm_chest(creature_ptr, y, x, o_idx);
233         } else {
234             more = exe_disarm(creature_ptr, y, x, dir);
235         }
236     }
237
238     if (!more)
239         disturb(creature_ptr, FALSE, FALSE);
240 }
241
242 /*!
243  * @brief 「打ち破る」動作コマンドのメインルーチン /
244  * Bash open a door, success based on character strength
245  * @return なし
246  * @details
247  * <pre>
248  * For a closed door, pval is positive if locked; negative if stuck.
249  *
250  * For an open door, pval is positive for a broken door.
251  *
252  * A closed door can be opened - harder if locked. Any door might be
253  * bashed open (and thereby broken). Bashing a door is (potentially)
254  * faster! You move into the door way. To open a stuck door, it must
255  * be bashed. A closed door can be jammed (see do_cmd_spike()).
256  *
257  * Creatures can also open or bash doors, see elsewhere.
258  * </pre>
259  */
260 void do_cmd_bash(player_type *creature_ptr)
261 {
262     POSITION y, x;
263     DIRECTION dir;
264     grid_type *g_ptr;
265     bool more = FALSE;
266     if (creature_ptr->wild_mode)
267         return;
268
269     if (creature_ptr->special_defense & KATA_MUSOU)
270         set_action(creature_ptr, ACTION_NONE);
271
272     if (command_arg) {
273         command_rep = command_arg - 1;
274         creature_ptr->redraw |= (PR_STATE);
275         command_arg = 0;
276     }
277
278     if (get_rep_dir(creature_ptr, &dir, FALSE)) {
279         FEAT_IDX feat;
280         y = creature_ptr->y + ddy[dir];
281         x = creature_ptr->x + ddx[dir];
282         g_ptr = &creature_ptr->current_floor_ptr->grid_array[y][x];
283         feat = get_feat_mimic(g_ptr);
284         if (!has_flag(f_info[feat].flags, FF_BASH)) {
285             msg_print(_("そこには体当たりするものが見当たらない。", "You see nothing there to bash."));
286         } else if (g_ptr->m_idx) {
287             take_turn(creature_ptr, 100);
288             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
289             do_cmd_attack(creature_ptr, y, x, 0);
290         } else {
291             more = exe_bash(creature_ptr, y, x, dir);
292         }
293     }
294
295     if (!more)
296         disturb(creature_ptr, FALSE, FALSE);
297 }
298
299
300 /*!
301  * @brief 「くさびを打つ」ために必要なオブジェクトを所持しているかどうかの判定を返す /
302  * Find the index of some "spikes", if possible.
303  * @param ip くさびとして打てるオブジェクトのID
304  * @return オブジェクトがある場合TRUEを返す
305  * @details
306  * <pre>
307  * Let user choose a pile of spikes, perhaps?
308  * </pre>
309  */
310 static bool get_spike(player_type *creature_ptr, INVENTORY_IDX *ip)
311 {
312     for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
313         object_type *o_ptr = &creature_ptr->inventory_list[i];
314         if (!o_ptr->k_idx)
315             continue;
316
317         if (o_ptr->tval == TV_SPIKE) {
318             *ip = i;
319             return TRUE;
320         }
321     }
322
323     return FALSE;
324 }
325
326 /*!
327  * @brief 「くさびを打つ」動作コマンドのメインルーチン /
328  * Jam a closed door with a spike
329  * @param creature_ptr プレーヤーへの参照ポインタ
330  * @return なし
331  * @details
332  * <pre>
333  * This command may NOT be repeated
334  * </pre>
335  */
336 void do_cmd_spike(player_type *creature_ptr)
337 {
338     DIRECTION dir;
339     if (creature_ptr->wild_mode)
340         return;
341
342     if (creature_ptr->special_defense & KATA_MUSOU)
343         set_action(creature_ptr, ACTION_NONE);
344
345     if (!get_rep_dir(creature_ptr, &dir, FALSE))
346         return;
347
348     POSITION y = creature_ptr->y + ddy[dir];
349     POSITION x = creature_ptr->x + ddx[dir];
350     grid_type *g_ptr;
351     g_ptr = &creature_ptr->current_floor_ptr->grid_array[y][x];
352     FEAT_IDX feat = get_feat_mimic(g_ptr);
353     INVENTORY_IDX item;
354     if (!has_flag(f_info[feat].flags, FF_SPIKE)) {
355         msg_print(_("そこにはくさびを打てるものが見当たらない。", "You see nothing there to spike."));
356     } else if (!get_spike(creature_ptr, &item)) {
357         msg_print(_("くさびを持っていない!", "You have no spikes!"));
358     } else if (g_ptr->m_idx) {
359         take_turn(creature_ptr, 100);
360         msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
361         do_cmd_attack(creature_ptr, y, x, 0);
362     } else {
363         take_turn(creature_ptr, 100);
364         msg_format(_("%sにくさびを打ち込んだ。", "You jam the %s with a spike."), f_name + f_info[feat].name);
365         cave_alter_feat(creature_ptr, y, x, FF_SPIKE);
366         vary_item(creature_ptr, item, -1);
367     }
368 }