OSDN Git Service

[Refactor] enum spells-typeをenum class AttributeTypeに置換
[hengbandforosx/hengbandosx.git] / src / player / player-move.cpp
1 /*!
2  *  @brief プレイヤーの移動処理 / Movement commands
3  *  @date 2014/01/02
4  *  @author
5  *  Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  */
7
8 #include "player/player-move.h"
9 #include "core/disturbance.h"
10 #include "core/player-redraw-types.h"
11 #include "core/player-update-types.h"
12 #include "core/special-internal-keys.h"
13 #include "core/stuff-handler.h"
14 #include "core/window-redrawer.h"
15 #include "dungeon/dungeon-flag-types.h"
16 #include "dungeon/dungeon.h"
17 #include "dungeon/quest.h"
18 #include "effect/effect-characteristics.h"
19 #include "effect/effect-processor.h"
20 #include "floor/cave.h"
21 #include "floor/geometry.h"
22 #include "floor/floor-util.h"
23 #include "game-option/disturbance-options.h"
24 #include "grid/feature.h"
25 #include "grid/grid.h"
26 #include "grid/trap.h"
27 #include "inventory/player-inventory.h"
28 #include "io/input-key-requester.h"
29 #include "mind/mind-ninja.h"
30 #include "monster/monster-update.h"
31 #include "perception/object-perception.h"
32 #include "player-status/player-energy.h"
33 #include "player/attack-defense-types.h"
34 #include "player/player-status-flags.h"
35 #include "player/player-status.h"
36 #include "realm/realm-song-numbers.h"
37 #include "spell-kind/spells-floor.h"
38 #include "spell-realm/spells-song.h"
39 #include "effect/attribute-types.h"
40 #include "status/action-setter.h"
41 #include "system/floor-type-definition.h"
42 #include "system/grid-type-definition.h"
43 #include "system/monster-type-definition.h"
44 #include "system/object-type-definition.h"
45 #include "system/player-type-definition.h"
46 #include "target/target-checker.h"
47 #include "util/bit-flags-calculator.h"
48 #include "view/display-messages.h"
49
50 int flow_head = 0;
51 int flow_tail = 0;
52 POSITION temp2_x[MAX_SHORT];
53 POSITION temp2_y[MAX_SHORT];
54
55 /*!
56  * @brief 地形やその上のアイテムの隠された要素を全て明かす /
57  * Search for hidden things
58  * @param player_ptr プレイヤーへの参照ポインタ
59  * @param y 対象となるマスのY座標
60  * @param x 対象となるマスのX座標
61  */
62 static void discover_hidden_things(player_type *player_ptr, POSITION y, POSITION x)
63 {
64     grid_type *g_ptr;
65     floor_type *floor_ptr = player_ptr->current_floor_ptr;
66     g_ptr = &floor_ptr->grid_array[y][x];
67     if (g_ptr->mimic && is_trap(player_ptr, g_ptr->feat)) {
68         disclose_grid(player_ptr, y, x);
69         msg_print(_("トラップを発見した。", "You have found a trap."));
70         disturb(player_ptr, false, true);
71     }
72
73     if (is_hidden_door(player_ptr, g_ptr)) {
74         msg_print(_("隠しドアを発見した。", "You have found a secret door."));
75         disclose_grid(player_ptr, y, x);
76         disturb(player_ptr, false, false);
77     }
78
79     for (const auto this_o_idx : g_ptr->o_idx_list) {
80         object_type *o_ptr;
81         o_ptr = &floor_ptr->o_list[this_o_idx];
82         if (o_ptr->tval != ItemKindType::CHEST)
83             continue;
84         if (chest_traps[o_ptr->pval].none())
85             continue;
86         if (!o_ptr->is_known()) {
87             msg_print(_("箱に仕掛けられたトラップを発見した!", "You have discovered a trap on the chest!"));
88             object_known(o_ptr);
89             disturb(player_ptr, false, false);
90         }
91     }
92 }
93
94 /*!
95  * @brief プレイヤーの探索処理判定
96  * @param player_ptr プレイヤーへの参照ポインタ
97  */
98 void search(player_type *player_ptr)
99 {
100     PERCENTAGE chance = player_ptr->skill_srh;
101     if (player_ptr->blind || no_lite(player_ptr))
102         chance = chance / 10;
103
104     if (player_ptr->confused || player_ptr->hallucinated)
105         chance = chance / 10;
106
107     for (DIRECTION i = 0; i < 9; ++i)
108         if (randint0(100) < chance)
109             discover_hidden_things(player_ptr, player_ptr->y + ddy_ddd[i], player_ptr->x + ddx_ddd[i]);
110 }
111
112 /*!
113  * @brief 移動に伴うプレイヤーのステータス変化処理
114  * @param player_ptr プレイヤーへの参照ポインタ
115  * @param ny 移動先Y座標
116  * @param nx 移動先X座標
117  * @param mpe_mode 移動オプションフラグ
118  * @return プレイヤーが死亡やフロア離脱を行わず、実際に移動が可能ならばTRUEを返す。
119  */
120 bool move_player_effect(player_type *player_ptr, POSITION ny, POSITION nx, BIT_FLAGS mpe_mode)
121 {
122     POSITION oy = player_ptr->y;
123     POSITION ox = player_ptr->x;
124     floor_type *floor_ptr = player_ptr->current_floor_ptr;
125     grid_type *g_ptr = &floor_ptr->grid_array[ny][nx];
126     grid_type *oc_ptr = &floor_ptr->grid_array[oy][ox];
127     feature_type *f_ptr = &f_info[g_ptr->feat];
128     feature_type *of_ptr = &f_info[oc_ptr->feat];
129
130     if (!(mpe_mode & MPE_STAYING)) {
131         MONSTER_IDX om_idx = oc_ptr->m_idx;
132         MONSTER_IDX nm_idx = g_ptr->m_idx;
133         player_ptr->y = ny;
134         player_ptr->x = nx;
135         if (!(mpe_mode & MPE_DONT_SWAP_MON)) {
136             g_ptr->m_idx = om_idx;
137             oc_ptr->m_idx = nm_idx;
138             if (om_idx > 0) {
139                 monster_type *om_ptr = &floor_ptr->m_list[om_idx];
140                 om_ptr->fy = ny;
141                 om_ptr->fx = nx;
142                 update_monster(player_ptr, om_idx, true);
143             }
144
145             if (nm_idx > 0) {
146                 monster_type *nm_ptr = &floor_ptr->m_list[nm_idx];
147                 nm_ptr->fy = oy;
148                 nm_ptr->fx = ox;
149                 update_monster(player_ptr, nm_idx, true);
150             }
151         }
152
153         lite_spot(player_ptr, oy, ox);
154         lite_spot(player_ptr, ny, nx);
155         verify_panel(player_ptr);
156         if (mpe_mode & MPE_FORGET_FLOW) {
157             forget_flow(floor_ptr);
158             player_ptr->update |= PU_UN_VIEW;
159             player_ptr->redraw |= PR_MAP;
160         }
161
162         player_ptr->update |= PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_DISTANCE;
163         player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
164         if ((!player_ptr->blind && !no_lite(player_ptr)) || !is_trap(player_ptr, g_ptr->feat))
165             g_ptr->info &= ~(CAVE_UNSAFE);
166
167         if (floor_ptr->dun_level && d_info[player_ptr->dungeon_idx].flags.has(DF::FORGET))
168             wiz_dark(player_ptr);
169
170         if (mpe_mode & MPE_HANDLE_STUFF)
171             handle_stuff(player_ptr);
172
173         if (player_ptr->pclass == PlayerClassType::NINJA) {
174             if (g_ptr->info & (CAVE_GLOW))
175                 set_superstealth(player_ptr, false);
176             else if (player_ptr->cur_lite <= 0)
177                 set_superstealth(player_ptr, true);
178         }
179
180         if ((player_ptr->action == ACTION_HAYAGAKE)
181             && (f_ptr->flags.has_not(FF::PROJECT) || (!player_ptr->levitation && f_ptr->flags.has(FF::DEEP)))) {
182             msg_print(_("ここでは素早く動けない。", "You cannot run in here."));
183             set_action(player_ptr, ACTION_NONE);
184         }
185
186         if (player_ptr->prace == PlayerRaceType::MERFOLK) {
187             if (f_ptr->flags.has(FF::WATER) ^ of_ptr->flags.has(FF::WATER)) {
188                 player_ptr->update |= PU_BONUS;
189                 update_creature(player_ptr);
190             }
191         }
192     }
193
194     if (mpe_mode & MPE_ENERGY_USE) {
195         if (music_singing(player_ptr, MUSIC_WALL)) {
196             (void)project(player_ptr, 0, 0, player_ptr->y, player_ptr->x, (60 + player_ptr->lev), AttributeType::DISINTEGRATE, PROJECT_KILL | PROJECT_ITEM);
197             if (!player_bold(player_ptr, ny, nx) || player_ptr->is_dead || player_ptr->leaving)
198                 return false;
199         }
200
201         if ((player_ptr->skill_fos >= 50) || (0 == randint0(50 - player_ptr->skill_fos)))
202             search(player_ptr);
203
204         if (player_ptr->action == ACTION_SEARCH)
205             search(player_ptr);
206     }
207
208     if (!(mpe_mode & MPE_DONT_PICKUP))
209         carry(player_ptr, any_bits(mpe_mode, MPE_DO_PICKUP));
210
211     if (!player_ptr->running) {
212         // 自動拾い/自動破壊により床上のアイテムリストが変化した可能性があるので表示を更新
213         set_bits(player_ptr->window_flags, PW_FLOOR_ITEM_LIST);
214         window_stuff(player_ptr);
215     }
216
217     PlayerEnergy energy(player_ptr);
218     if (f_ptr->flags.has(FF::STORE)) {
219         disturb(player_ptr, false, true);
220         energy.reset_player_turn();
221         command_new = SPECIAL_KEY_STORE;
222     } else if (f_ptr->flags.has(FF::BLDG)) {
223         disturb(player_ptr, false, true);
224         energy.reset_player_turn();
225         command_new = SPECIAL_KEY_BUILDING;
226     } else if (f_ptr->flags.has(FF::QUEST_ENTER)) {
227         disturb(player_ptr, false, true);
228         energy.reset_player_turn();
229         command_new = SPECIAL_KEY_QUEST;
230     } else if (f_ptr->flags.has(FF::QUEST_EXIT)) {
231         if (quest[floor_ptr->inside_quest].type == QuestKindType::FIND_EXIT)
232             complete_quest(player_ptr, floor_ptr->inside_quest);
233
234         leave_quest_check(player_ptr);
235         floor_ptr->inside_quest = g_ptr->special;
236         floor_ptr->dun_level = 0;
237         if (!floor_ptr->inside_quest)
238             player_ptr->word_recall = 0;
239         player_ptr->oldpx = 0;
240         player_ptr->oldpy = 0;
241         player_ptr->leaving = true;
242     } else if (f_ptr->flags.has(FF::HIT_TRAP) && !(mpe_mode & MPE_STAYING)) {
243         disturb(player_ptr, false, true);
244         if (g_ptr->mimic || f_ptr->flags.has(FF::SECRET)) {
245             msg_print(_("トラップだ!", "You found a trap!"));
246             disclose_grid(player_ptr, player_ptr->y, player_ptr->x);
247         }
248
249         hit_trap(player_ptr, any_bits(mpe_mode, MPE_BREAK_TRAP));
250         if (!player_bold(player_ptr, ny, nx) || player_ptr->is_dead || player_ptr->leaving)
251             return false;
252     }
253
254     if (!(mpe_mode & MPE_STAYING) && (disturb_trap_detect || alert_trap_detect) && player_ptr->dtrap && !(g_ptr->info & CAVE_IN_DETECT)) {
255         player_ptr->dtrap = false;
256         if (!(g_ptr->info & CAVE_UNSAFE)) {
257             if (alert_trap_detect)
258                 msg_print(_("* 注意:この先はトラップの感知範囲外です! *", "*Leaving trap detect region!*"));
259
260             if (disturb_trap_detect)
261                 disturb(player_ptr, false, true);
262         }
263     }
264
265     return player_bold(player_ptr, ny, nx) && !player_ptr->is_dead && !player_ptr->leaving;
266 }
267
268 /*!
269  * @brief 該当地形のトラップがプレイヤーにとって無効かどうかを判定して返す
270  * @param player_ptr プレイヤーへの参照ポインタ
271  * @param feat 地形ID
272  * @return トラップが自動的に無効ならばTRUEを返す
273  */
274 bool trap_can_be_ignored(player_type *player_ptr, FEAT_IDX feat)
275 {
276     feature_type *f_ptr = &f_info[feat];
277     if (f_ptr->flags.has_not(FF::TRAP))
278         return true;
279
280     switch (f_ptr->subtype) {
281     case TRAP_TRAPDOOR:
282     case TRAP_PIT:
283     case TRAP_SPIKED_PIT:
284     case TRAP_POISON_PIT:
285         if (player_ptr->levitation)
286             return true;
287         break;
288     case TRAP_TELEPORT:
289         if (player_ptr->anti_tele)
290             return true;
291         break;
292     case TRAP_FIRE:
293         if (has_immune_fire(player_ptr))
294             return true;
295         break;
296     case TRAP_ACID:
297         if (has_immune_acid(player_ptr))
298             return true;
299         break;
300     case TRAP_BLIND:
301         if (has_resist_blind(player_ptr))
302             return true;
303         break;
304     case TRAP_CONFUSE:
305         if (has_resist_conf(player_ptr))
306             return true;
307         break;
308     case TRAP_POISON:
309         if (has_resist_pois(player_ptr))
310             return true;
311         break;
312     case TRAP_SLEEP:
313         if (player_ptr->free_act)
314             return true;
315         break;
316     }
317
318     return false;
319 }