OSDN Git Service

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