OSDN Git Service

c8ffd8f580135c2677ebb3f52b9ef7468629fa48
[hengbandforosx/hengbandosx.git] / src / cmd-action / cmd-move.cpp
1 #include "cmd-action/cmd-move.h"
2 #include "action/action-limited.h"
3 #include "action/movement-execution.h"
4 #include "action/run-execution.h"
5 #include "avatar/avatar.h"
6 #include "cmd-io/cmd-save.h"
7 #include "core/asking-player.h"
8 #include "core/disturbance.h"
9 #include "core/player-redraw-types.h"
10 #include "core/player-update-types.h"
11 #include "core/stuff-handler.h"
12 #include "dungeon/dungeon.h"
13 #include "dungeon/quest.h"
14 #include "floor/cave.h"
15 #include "floor/floor-mode-changer.h"
16 #include "floor/wild.h"
17 #include "game-option/birth-options.h"
18 #include "game-option/input-options.h"
19 #include "game-option/map-screen-options.h"
20 #include "game-option/play-record-options.h"
21 #include "game-option/special-options.h"
22 #include "grid/feature.h"
23 #include "info-reader/fixed-map-parser.h"
24 #include "io/input-key-requester.h"
25 #include "io/write-diary.h"
26 #include "mind/mind-ninja.h"
27 #include "main/sound-definitions-table.h"
28 #include "main/sound-of-music.h"
29 #include "player-base/player-class.h"
30 #include "player-info/samurai-data-type.h"
31 #include "player-status/player-energy.h"
32 #include "player/attack-defense-types.h"
33 #include "player/player-move.h"
34 #include "player/player-status.h"
35 #include "player/special-defense-types.h"
36 #include "spell-realm/spells-hex.h"
37 #include "spell-realm/spells-song.h"
38 #include "status/action-setter.h"
39 #include "system/floor-type-definition.h"
40 #include "system/grid-type-definition.h"
41 #include "system/player-type-definition.h"
42 #include "target/target-getter.h"
43 #include "timed-effect/player-cut.h"
44 #include "timed-effect/player-stun.h"
45 #include "timed-effect/timed-effects.h"
46 #include "util/bit-flags-calculator.h"
47 #include "view/display-messages.h"
48
49 /*!
50  * @brief フロア脱出時に出戻りが不可能だった場合に警告を加える処理
51  * @param down_stair TRUEならば階段を降りる処理、FALSEなら階段を昇る処理による内容
52  * @return フロア移動を実際に行うならTRUE、キャンセルする場合はFALSE
53  */
54 static bool confirm_leave_level(player_type *player_ptr, bool down_stair)
55 {
56     quest_type *q_ptr = &quest[player_ptr->current_floor_ptr->inside_quest];
57     if (confirm_quest && player_ptr->current_floor_ptr->inside_quest
58         && (q_ptr->type == QUEST_TYPE_RANDOM || (q_ptr->flags & QUEST_FLAG_ONCE && q_ptr->status != QUEST_STATUS_COMPLETED)
59             || (q_ptr->flags & QUEST_FLAG_TOWER
60                 && ((q_ptr->status != QUEST_STATUS_STAGE_COMPLETED) || (down_stair && (quest[QUEST_TOWER1].status != QUEST_STATUS_COMPLETED)))))) {
61         msg_print(_("この階を一度去ると二度と戻って来られません。", "You can't come back here once you leave this floor."));
62         return get_check(_("本当にこの階を去りますか?", "Really leave this floor? "));
63     }
64
65     return true;
66 }
67
68 /*!
69  * @brief 階段を使って階層を昇る処理 / Go up one level
70  */
71 void do_cmd_go_up(player_type *player_ptr)
72 {
73     bool go_up = false;
74     grid_type *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
75     feature_type *f_ptr = &f_info[g_ptr->feat];
76     int up_num = 0;
77     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStance::MUSOU });
78
79     if (f_ptr->flags.has_not(FF::LESS)) {
80         msg_print(_("ここには上り階段が見当たらない。", "I see no up staircase here."));
81         return;
82     }
83
84     if (f_ptr->flags.has(FF::QUEST)) {
85         if (!confirm_leave_level(player_ptr, false))
86             return;
87
88         if (is_echizen(player_ptr))
89             msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
90         else
91             msg_print(_("上の階に登った。", "You enter the up staircase."));
92
93         sound(SOUND_STAIRWAY);
94
95         leave_quest_check(player_ptr);
96         player_ptr->current_floor_ptr->inside_quest = g_ptr->special;
97         if (!quest[player_ptr->current_floor_ptr->inside_quest].status) {
98             if (quest[player_ptr->current_floor_ptr->inside_quest].type != QUEST_TYPE_RANDOM) {
99                 init_flags = INIT_ASSIGN;
100                 parse_fixed_map(player_ptr, "q_info.txt", 0, 0, 0, 0);
101             }
102
103             quest[player_ptr->current_floor_ptr->inside_quest].status = QUEST_STATUS_TAKEN;
104         }
105
106         if (!player_ptr->current_floor_ptr->inside_quest) {
107             player_ptr->current_floor_ptr->dun_level = 0;
108             player_ptr->word_recall = 0;
109         }
110
111         player_ptr->leaving = true;
112         player_ptr->oldpx = 0;
113         player_ptr->oldpy = 0;
114         PlayerEnergy(player_ptr).set_player_turn_energy(100);
115         return;
116     }
117
118     if (!is_in_dungeon(player_ptr))
119         go_up = true;
120     else
121         go_up = confirm_leave_level(player_ptr, false);
122
123     if (!go_up)
124         return;
125
126     PlayerEnergy(player_ptr).set_player_turn_energy(100);
127
128     if (autosave_l)
129         do_cmd_save_game(player_ptr, true);
130
131     if (player_ptr->current_floor_ptr->inside_quest && quest[player_ptr->current_floor_ptr->inside_quest].type == QUEST_TYPE_RANDOM) {
132         leave_quest_check(player_ptr);
133         player_ptr->current_floor_ptr->inside_quest = 0;
134     }
135
136     if (player_ptr->current_floor_ptr->inside_quest && quest[player_ptr->current_floor_ptr->inside_quest].type != QUEST_TYPE_RANDOM) {
137         leave_quest_check(player_ptr);
138         player_ptr->current_floor_ptr->inside_quest = g_ptr->special;
139         player_ptr->current_floor_ptr->dun_level = 0;
140         up_num = 0;
141     } else {
142         if (f_ptr->flags.has(FF::SHAFT)) {
143             prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_UP | CFM_SHAFT);
144             up_num = 2;
145         } else {
146             prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_UP);
147             up_num = 1;
148         }
149
150         if (player_ptr->current_floor_ptr->dun_level - up_num < d_info[player_ptr->dungeon_idx].mindepth)
151             up_num = player_ptr->current_floor_ptr->dun_level;
152     }
153
154     if (record_stair)
155         exe_write_diary(player_ptr, DIARY_STAIR, 0 - up_num, _("階段を上った", "climbed up the stairs to"));
156
157     if (up_num == player_ptr->current_floor_ptr->dun_level) {
158         if (is_echizen(player_ptr))
159             msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
160         else
161             msg_print(_("地上に戻った。", "You go back to the surface."));
162         player_ptr->word_recall = 0;
163     } else {
164         if (is_echizen(player_ptr))
165             msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
166         else
167             msg_print(_("階段を上って新たなる迷宮へと足を踏み入れた。", "You enter a maze of up staircases."));
168     }
169
170     sound(SOUND_STAIRWAY);
171
172     player_ptr->leaving = true;
173 }
174
175 /*!
176  * @brief 階段を使って階層を降りる処理 / Go down one level
177  * @param player_ptr プレイヤーへの参照ポインタ
178  */
179 void do_cmd_go_down(player_type *player_ptr)
180 {
181     bool fall_trap = false;
182     int down_num = 0;
183     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStance::MUSOU });
184
185     grid_type *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
186     feature_type *f_ptr = &f_info[g_ptr->feat];
187     if (f_ptr->flags.has_not(FF::MORE)) {
188         msg_print(_("ここには下り階段が見当たらない。", "I see no down staircase here."));
189         return;
190     }
191
192     if (f_ptr->flags.has(FF::TRAP))
193         fall_trap = true;
194
195     if (f_ptr->flags.has(FF::QUEST_ENTER)) {
196         do_cmd_quest(player_ptr);
197         return;
198     }
199
200     if (f_ptr->flags.has(FF::QUEST)) {
201         if (!confirm_leave_level(player_ptr, true))
202             return;
203
204         if (is_echizen(player_ptr))
205             msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
206         else
207             msg_print(_("下の階に降りた。", "You enter the down staircase."));
208
209         sound(SOUND_STAIRWAY);
210
211         leave_quest_check(player_ptr);
212         leave_tower_check(player_ptr);
213         player_ptr->current_floor_ptr->inside_quest = g_ptr->special;
214         if (!quest[player_ptr->current_floor_ptr->inside_quest].status) {
215             if (quest[player_ptr->current_floor_ptr->inside_quest].type != QUEST_TYPE_RANDOM) {
216                 init_flags = INIT_ASSIGN;
217                 parse_fixed_map(player_ptr, "q_info.txt", 0, 0, 0, 0);
218             }
219
220             quest[player_ptr->current_floor_ptr->inside_quest].status = QUEST_STATUS_TAKEN;
221         }
222
223         if (!player_ptr->current_floor_ptr->inside_quest) {
224             player_ptr->current_floor_ptr->dun_level = 0;
225             player_ptr->word_recall = 0;
226         }
227
228         player_ptr->leaving = true;
229         player_ptr->oldpx = 0;
230         player_ptr->oldpy = 0;
231         PlayerEnergy(player_ptr).set_player_turn_energy(100);
232         return;
233     }
234
235     DUNGEON_IDX target_dungeon = 0;
236     if (!is_in_dungeon(player_ptr)) {
237         target_dungeon = f_ptr->flags.has(FF::ENTRANCE) ? g_ptr->special : DUNGEON_ANGBAND;
238         if (ironman_downward && (target_dungeon != DUNGEON_ANGBAND)) {
239             msg_print(_("ダンジョンの入口は塞がれている!", "The entrance of this dungeon is closed!"));
240             return;
241         }
242
243         if (!max_dlv[target_dungeon]) {
244             msg_format(_("ここには%sの入り口(%d階相当)があります", "There is the entrance of %s (Danger level: %d)"), d_info[target_dungeon].name.c_str(),
245                 d_info[target_dungeon].mindepth);
246             if (!get_check(_("本当にこのダンジョンに入りますか?", "Do you really get in this dungeon? ")))
247                 return;
248         }
249
250         player_ptr->oldpx = player_ptr->x;
251         player_ptr->oldpy = player_ptr->y;
252         player_ptr->dungeon_idx = target_dungeon;
253         prepare_change_floor_mode(player_ptr, CFM_FIRST_FLOOR);
254     }
255
256     PlayerEnergy(player_ptr).set_player_turn_energy(100);
257     if (autosave_l)
258         do_cmd_save_game(player_ptr, true);
259
260     if (f_ptr->flags.has(FF::SHAFT))
261         down_num += 2;
262     else
263         down_num += 1;
264
265     if (!is_in_dungeon(player_ptr)) {
266         player_ptr->enter_dungeon = true;
267         down_num = d_info[player_ptr->dungeon_idx].mindepth;
268     }
269
270     if (record_stair) {
271         if (fall_trap)
272             exe_write_diary(player_ptr, DIARY_STAIR, down_num, _("落とし戸に落ちた", "fell through a trap door"));
273         else
274             exe_write_diary(player_ptr, DIARY_STAIR, down_num, _("階段を下りた", "climbed down the stairs to"));
275     }
276
277     if (fall_trap) {
278         msg_print(_("わざと落とし戸に落ちた。", "You deliberately jump through the trap door."));
279     } else {
280         if (target_dungeon) {
281             msg_format(_("%sへ入った。", "You entered %s."), d_info[player_ptr->dungeon_idx].text.c_str());
282         } else {
283             if (is_echizen(player_ptr))
284                 msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
285             else
286                 msg_print(_("階段を下りて新たなる迷宮へと足を踏み入れた。", "You enter a maze of down staircases."));
287         }
288
289         sound(SOUND_STAIRWAY);
290     }
291
292     player_ptr->leaving = true;
293
294     if (fall_trap) {
295         prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT);
296         return;
297     }
298
299     if (f_ptr->flags.has(FF::SHAFT))
300         prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_SHAFT);
301     else
302         prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN);
303 }
304
305 /*!
306  * @brief 「歩く」動作コマンドのメインルーチン /
307  * Support code for the "Walk" and "Jump" commands
308  * @param player_ptr プレイヤーへの参照ポインタ
309  * @param pickup アイテムの自動拾いを行うならTRUE
310  */
311 void do_cmd_walk(player_type *player_ptr, bool pickup)
312 {
313     if (command_arg) {
314         command_rep = command_arg - 1;
315         player_ptr->redraw |= PR_STATE;
316         command_arg = 0;
317     }
318
319     bool more = false;
320     DIRECTION dir;
321     if (get_rep_dir(player_ptr, &dir, false)) {
322         PlayerEnergy energy(player_ptr);
323         energy.set_player_turn_energy(100);
324         if (dir != 5) {
325             PlayerClass(player_ptr).break_samurai_stance({ SamuraiStance::MUSOU });
326         }
327
328         if (player_ptr->wild_mode) {
329             energy.mul_player_turn_energy((MAX_HGT + MAX_WID) / 2);
330         }
331
332         if (player_ptr->action == ACTION_HAYAGAKE) {
333             auto energy_use = (ENERGY)(player_ptr->energy_use * (45 - (player_ptr->lev / 2)) / 100);
334             energy.set_player_turn_energy(energy_use);
335         }
336
337         exe_movement(player_ptr, dir, pickup, false);
338         more = true;
339     }
340
341     if (player_ptr->wild_mode && !cave_has_flag_bold(player_ptr->current_floor_ptr, player_ptr->y, player_ptr->x, FF::TOWN)) {
342         int tmp = 120 + player_ptr->lev * 10 - wilderness[player_ptr->y][player_ptr->x].level + 5;
343         if (tmp < 1)
344             tmp = 1;
345
346         if (((wilderness[player_ptr->y][player_ptr->x].level + 5) > (player_ptr->lev / 2)) && randint0(tmp) < (21 - player_ptr->skill_stl)) {
347             msg_print(_("襲撃だ!", "You are ambushed !"));
348             player_ptr->oldpy = randint1(MAX_HGT - 2);
349             player_ptr->oldpx = randint1(MAX_WID - 2);
350             change_wild_mode(player_ptr, true);
351             PlayerEnergy(player_ptr).set_player_turn_energy(100);
352         }
353     }
354
355     if (!more)
356         disturb(player_ptr, false, false);
357 }
358
359 /*!
360  * @brief 「走る」動作コマンドのメインルーチン /
361  * Start running.
362  * @param player_ptr プレイヤーへの参照ポインタ
363  */
364 void do_cmd_run(player_type *player_ptr)
365 {
366     DIRECTION dir;
367     if (cmd_limit_confused(player_ptr))
368         return;
369
370     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStance::MUSOU });
371
372     if (get_rep_dir(player_ptr, &dir, false)) {
373         player_ptr->running = (command_arg ? command_arg : 1000);
374         run_step(player_ptr, dir);
375     }
376 }
377
378 /*!
379  * @brief 「留まる」動作コマンドのメインルーチン /
380  * Stay still.  Search.  Enter stores.
381  * Pick up treasure if "pickup" is true.
382  * @param player_ptr プレイヤーへの参照ポインタ
383  * @param pickup アイテムの自動拾いを行うならTRUE
384  */
385 void do_cmd_stay(player_type *player_ptr, bool pickup)
386 {
387     uint32_t mpe_mode = MPE_STAYING | MPE_ENERGY_USE;
388     if (command_arg) {
389         command_rep = command_arg - 1;
390         player_ptr->redraw |= (PR_STATE);
391         command_arg = 0;
392     }
393
394     PlayerEnergy(player_ptr).set_player_turn_energy(100);
395     if (pickup)
396         mpe_mode |= MPE_DO_PICKUP;
397
398     (void)move_player_effect(player_ptr, player_ptr->y, player_ptr->x, mpe_mode);
399 }
400
401 /*!
402  * @brief 「休む」動作コマンドのメインルーチン /
403  * Resting allows a player to safely restore his hp     -RAK-
404  * @param player_ptr プレイヤーへの参照ポインタ
405  */
406 void do_cmd_rest(player_type *player_ptr)
407 {
408     set_action(player_ptr, ACTION_NONE);
409     if ((player_ptr->pclass == CLASS_BARD) && ((get_singing_song_effect(player_ptr) != 0) || (get_interrupting_song_effect(player_ptr) != 0)))
410         stop_singing(player_ptr);
411
412     SpellHex spell_hex(player_ptr);
413     if (spell_hex.is_spelling_any()) {
414         (void)spell_hex.stop_all_spells();
415     }
416
417     if (command_arg <= 0) {
418         concptr p = _("休憩 (0-9999, '*' で HP/MP全快, '&' で必要なだけ): ", "Rest (0-9999, '*' for HP/SP, '&' as needed): ");
419         char out_val[80];
420         strcpy(out_val, "&");
421         if (!get_string(p, out_val, 4))
422             return;
423
424         if (out_val[0] == '&') {
425             command_arg = COMMAND_ARG_REST_UNTIL_DONE;
426         } else if (out_val[0] == '*') {
427             command_arg = COMMAND_ARG_REST_FULL_HEALING;
428         } else {
429             command_arg = (COMMAND_ARG)atoi(out_val);
430             if (command_arg <= 0)
431                 return;
432         }
433     }
434
435     if (command_arg > 9999)
436         command_arg = 9999;
437
438     if (player_ptr->special_defense & NINJA_S_STEALTH)
439         set_superstealth(player_ptr, false);
440
441     PlayerEnergy(player_ptr).set_player_turn_energy(100);
442     if (command_arg > 100)
443         chg_virtue(player_ptr, V_DILIGENCE, -1);
444
445     auto effects = player_ptr->effects();
446     auto is_stunned = effects->stun()->is_stunned();
447     auto is_cut = effects->cut()->is_cut();
448     if ((player_ptr->chp == player_ptr->mhp) && (player_ptr->csp == player_ptr->msp) && !player_ptr->blind && !player_ptr->confused
449         && !player_ptr->poisoned && !player_ptr->afraid && !is_stunned && !is_cut && !player_ptr->slow && !player_ptr->paralyzed
450         && !player_ptr->hallucinated && !player_ptr->word_recall && !player_ptr->alter_reality)
451         chg_virtue(player_ptr, V_DILIGENCE, -1);
452
453     player_ptr->resting = command_arg;
454     player_ptr->action = ACTION_REST;
455     player_ptr->update |= PU_BONUS;
456     player_ptr->redraw |= (PR_STATE);
457     handle_stuff(player_ptr);
458     term_fresh();
459 }