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 "object/tval-types.h"
16 #include "player-base/player-class.h"
17 #include "player-info/samurai-data-type.h"
18 #include "player-status/player-energy.h"
19 #include "player/attack-defense-types.h"
20 #include "player/special-defense-types.h"
21 #include "specific-object/chest.h"
22 #include "status/action-setter.h"
23 #include "status/experience.h"
24 #include "system/floor-type-definition.h"
25 #include "system/grid-type-definition.h"
26 #include "system/item-entity.h"
27 #include "system/player-type-definition.h"
28 #include "system/redrawing-flags-updater.h"
29 #include "system/terrain-type-definition.h"
30 #include "target/target-getter.h"
31 #include "term/screen-processor.h"
32 #include "timed-effect/player-blindness.h"
33 #include "timed-effect/player-confusion.h"
34 #include "timed-effect/player-hallucination.h"
35 #include "timed-effect/timed-effects.h"
36 #include "util/bit-flags-calculator.h"
37 #include "view/display-messages.h"
41 * Attempt to open the given chest at the given location
42 * @param y 箱の存在するマスのY座標
43 * @param x 箱の存在するマスのX座標
44 * @param o_idx 箱のオブジェクトID
45 * @return 箱が開かなかった場合TRUE / Returns TRUE if repeated commands may continue
47 * Assume there is no monster blocking the destination
49 static bool exe_open_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJECT_IDX o_idx)
53 auto *o_ptr = &player_ptr->current_floor_ptr->o_list[o_idx];
54 PlayerEnergy(player_ptr).set_player_turn_energy(100);
55 if (o_ptr->pval > 0) {
57 int i = player_ptr->skill_dis;
58 const auto effects = player_ptr->effects();
59 if (effects->blindness()->is_blind() || no_lite(player_ptr)) {
63 if (effects->confusion()->is_confused() || effects->hallucination()->is_hallucinated()) {
67 int j = i - o_ptr->pval;
72 if (randint0(100) < j) {
73 msg_print(_("鍵をはずした。", "You have picked the lock."));
74 gain_exp(player_ptr, 1);
82 msg_print(_("鍵をはずせなかった。", "You failed to pick the lock."));
87 Chest chest(player_ptr);
88 chest.chest_trap(y, x, o_idx);
89 chest.chest_death(false, y, x, o_idx);
96 * @brief 「開ける」コマンドのメインルーチン /
97 * Open a closed/locked/jammed door or a closed/locked chest.
99 * Unlocking a locked door/chest is worth one experience point.
101 void do_cmd_open(PlayerType *player_ptr)
107 if (player_ptr->wild_mode) {
111 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
114 int num_doors = count_dt(player_ptr, &y, &x, is_closed_door, false);
115 int num_chests = count_chests(player_ptr, &y, &x, false);
116 if (num_doors || num_chests) {
117 bool too_many = (num_doors && num_chests) || (num_doors > 1) || (num_chests > 1);
119 command_dir = coords_to_dir(player_ptr, y, x);
125 command_rep = command_arg - 1;
126 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
130 if (get_rep_dir(player_ptr, &dir, true)) {
133 y = player_ptr->y + ddy[dir];
134 x = player_ptr->x + ddx[dir];
135 g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
136 feat = g_ptr->get_feat_mimic();
137 o_idx = chest_check(player_ptr->current_floor_ptr, y, x, false);
138 if (terrains_info[feat].flags.has_not(TerrainCharacteristics::OPEN) && !o_idx) {
139 msg_print(_("そこには開けるものが見当たらない。", "You see nothing there to open."));
140 } else if (g_ptr->m_idx && player_ptr->riding != g_ptr->m_idx) {
141 PlayerEnergy(player_ptr).set_player_turn_energy(100);
142 msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
143 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
145 more = exe_open_chest(player_ptr, y, x, o_idx);
147 more = exe_open(player_ptr, y, x);
152 disturb(player_ptr, false, false);
157 * @brief 「閉じる」コマンドのメインルーチン /
158 * Close an open door.
160 * Unlocking a locked door/chest is worth one experience point.
162 void do_cmd_close(PlayerType *player_ptr)
167 if (player_ptr->wild_mode) {
171 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
173 if (easy_open && (count_dt(player_ptr, &y, &x, is_open, false) == 1)) {
174 command_dir = coords_to_dir(player_ptr, y, x);
178 command_rep = command_arg - 1;
179 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
183 if (get_rep_dir(player_ptr, &dir, false)) {
186 y = player_ptr->y + ddy[dir];
187 x = player_ptr->x + ddx[dir];
188 g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
189 feat = g_ptr->get_feat_mimic();
190 if (terrains_info[feat].flags.has_not(TerrainCharacteristics::CLOSE)) {
191 msg_print(_("そこには閉じるものが見当たらない。", "You see nothing there to close."));
192 } else if (g_ptr->m_idx) {
193 PlayerEnergy(player_ptr).set_player_turn_energy(100);
194 msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
195 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
197 more = exe_close(player_ptr, y, x);
202 disturb(player_ptr, false, false);
207 * @brief 箱、床のトラップ解除処理双方の統合メインルーチン /
208 * Disarms a trap, or chest
210 void do_cmd_disarm(PlayerType *player_ptr)
216 if (player_ptr->wild_mode) {
220 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
223 int num_traps = count_dt(player_ptr, &y, &x, is_trap, true);
224 int num_chests = count_chests(player_ptr, &y, &x, true);
225 if (num_traps || num_chests) {
226 bool too_many = (num_traps && num_chests) || (num_traps > 1) || (num_chests > 1);
228 command_dir = coords_to_dir(player_ptr, y, x);
234 command_rep = command_arg - 1;
235 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
239 if (get_rep_dir(player_ptr, &dir, true)) {
242 y = player_ptr->y + ddy[dir];
243 x = player_ptr->x + ddx[dir];
244 g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
245 feat = g_ptr->get_feat_mimic();
246 o_idx = chest_check(player_ptr->current_floor_ptr, y, x, true);
247 if (!is_trap(player_ptr, feat) && !o_idx) {
248 msg_print(_("そこには解除するものが見当たらない。", "You see nothing there to disarm."));
249 } else if (g_ptr->m_idx && player_ptr->riding != g_ptr->m_idx) {
250 msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
251 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
253 more = exe_disarm_chest(player_ptr, y, x, o_idx);
255 more = exe_disarm(player_ptr, y, x, dir);
260 disturb(player_ptr, false, false);
265 * @brief 「打ち破る」動作コマンドのメインルーチン /
266 * Bash open a door, success based on character strength
269 * For a closed door, pval is positive if locked; negative if stuck.
271 * For an open door, pval is positive for a broken door.
273 * A closed door can be opened - harder if locked. Any door might be
274 * bashed open (and thereby broken). Bashing a door is (potentially)
275 * faster! You move into the door way. To open a stuck door, it must
276 * be bashed. A closed door can be jammed (see do_cmd_spike()).
278 * Creatures can also open or bash doors, see elsewhere.
281 void do_cmd_bash(PlayerType *player_ptr)
287 if (player_ptr->wild_mode) {
291 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
294 command_rep = command_arg - 1;
295 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
299 if (get_rep_dir(player_ptr, &dir, false)) {
301 y = player_ptr->y + ddy[dir];
302 x = player_ptr->x + ddx[dir];
303 g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
304 feat = g_ptr->get_feat_mimic();
305 if (terrains_info[feat].flags.has_not(TerrainCharacteristics::BASH)) {
306 msg_print(_("そこには体当たりするものが見当たらない。", "You see nothing there to bash."));
307 } else if (g_ptr->m_idx) {
308 PlayerEnergy(player_ptr).set_player_turn_energy(100);
309 msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
310 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
312 more = exe_bash(player_ptr, y, x, dir);
317 disturb(player_ptr, false, false);
322 * @brief 「くさびを打つ」ために必要なオブジェクトを所持しているかどうかの判定を返す /
323 * Find the index of some "spikes", if possible.
324 * @param ip くさびとして打てるオブジェクトのID
325 * @return オブジェクトがある場合TRUEを返す
328 * Let user choose a pile of spikes, perhaps?
331 static bool get_spike(PlayerType *player_ptr, INVENTORY_IDX *ip)
333 for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
334 auto *o_ptr = &player_ptr->inventory_list[i];
335 if (!o_ptr->is_valid()) {
339 if (o_ptr->bi_key.tval() == ItemKindType::SPIKE) {
349 * @brief 「くさびを打つ」動作コマンドのメインルーチン /
350 * Jam a closed door with a spike
351 * @param player_ptr プレイヤーへの参照ポインタ
354 * This command may NOT be repeated
357 void do_cmd_spike(PlayerType *player_ptr)
360 if (player_ptr->wild_mode) {
364 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
366 if (!get_rep_dir(player_ptr, &dir, false)) {
370 POSITION y = player_ptr->y + ddy[dir];
371 POSITION x = player_ptr->x + ddx[dir];
373 g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
374 FEAT_IDX feat = g_ptr->get_feat_mimic();
376 if (terrains_info[feat].flags.has_not(TerrainCharacteristics::SPIKE)) {
377 msg_print(_("そこにはくさびを打てるものが見当たらない。", "You see nothing there to spike."));
378 } else if (!get_spike(player_ptr, &item)) {
379 msg_print(_("くさびを持っていない!", "You have no spikes!"));
380 } else if (g_ptr->m_idx) {
381 PlayerEnergy(player_ptr).set_player_turn_energy(100);
382 msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
383 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
385 PlayerEnergy(player_ptr).set_player_turn_energy(100);
386 msg_format(_("%sにくさびを打ち込んだ。", "You jam the %s with a spike."), terrains_info[feat].name.data());
387 cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::SPIKE);
388 vary_item(player_ptr, item, -1);