OSDN Git Service

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