OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / floor / pattern-walk.cpp
1 #include "floor/pattern-walk.h"
2 #include "cmd-io/cmd-save.h"
3 #include "core/asking-player.h"
4 #include "dungeon/quest.h"
5 #include "floor/cave.h"
6 #include "floor/floor-mode-changer.h"
7 #include "game-option/birth-options.h"
8 #include "game-option/play-record-options.h"
9 #include "game-option/special-options.h"
10 #include "grid/feature.h"
11 #include "io/input-key-requester.h"
12 #include "io/write-diary.h"
13 #include "player-base/player-race.h"
14 #include "player-status/player-energy.h"
15 #include "player/player-damage.h"
16 #include "player/player-move.h"
17 #include "player/player-status.h"
18 #include "spell-kind/spells-teleport.h"
19 #include "spell/spells-status.h"
20 #include "status/bad-status-setter.h"
21 #include "status/experience.h"
22 #include "system/dungeon-info.h"
23 #include "system/floor-type-definition.h"
24 #include "system/grid-type-definition.h"
25 #include "system/player-type-definition.h"
26 #include "system/terrain-type-definition.h"
27 #include "term/z-form.h"
28 #include "timed-effect/player-confusion.h"
29 #include "timed-effect/player-cut.h"
30 #include "timed-effect/player-hallucination.h"
31 #include "timed-effect/player-stun.h"
32 #include "timed-effect/timed-effects.h"
33 #include "util/bit-flags-calculator.h"
34 #include "view/display-messages.h"
35 #include "world/world-movement-processor.h"
36 #include "world/world.h"
37 #include <algorithm>
38
39 /*!
40  * @brief パターン終点到達時のテレポート処理を行う
41  * @param player_ptr プレイヤーへの参照ポインタ
42  */
43 void pattern_teleport(PlayerType *player_ptr)
44 {
45     auto min_level = 0;
46     auto max_level = 99;
47     auto current_level = static_cast<short>(player_ptr->current_floor_ptr->dun_level);
48     if (input_check(_("他の階にテレポートしますか?", "Teleport level? "))) {
49         if (ironman_downward) {
50             min_level = current_level;
51         }
52
53         const auto &floor = *player_ptr->current_floor_ptr;
54         if (floor.dungeon_idx == DUNGEON_ANGBAND) {
55             if (floor.dun_level > 100) {
56                 max_level = MAX_DEPTH - 1;
57             } else if (current_level == 100) {
58                 max_level = 100;
59             }
60         } else {
61             const auto &dungeon = floor.get_dungeon_definition();
62             max_level = dungeon.maxdepth;
63             min_level = dungeon.mindepth;
64         }
65
66         constexpr auto prompt = _("テレポート先", "Teleport to level");
67         const auto input_level = input_numerics(prompt, min_level, max_level, current_level);
68         if (!input_level.has_value()) {
69             return;
70         }
71
72         command_arg = input_level.value();
73     } else if (input_check(_("通常テレポート?", "Normal teleport? "))) {
74         teleport_player(player_ptr, 200, TELEPORT_SPONTANEOUS);
75         return;
76     } else {
77         return;
78     }
79
80     msg_format(_("%d 階にテレポートしました。", "You teleport to dungeon level %d."), command_arg);
81     if (autosave_l) {
82         do_cmd_save_game(player_ptr, true);
83     }
84
85     player_ptr->current_floor_ptr->dun_level = command_arg;
86     leave_quest_check(player_ptr);
87     if (record_stair) {
88         exe_write_diary(player_ptr, DiaryKind::PAT_TELE, 0);
89     }
90
91     player_ptr->current_floor_ptr->quest_number = QuestId::NONE;
92     PlayerEnergy(player_ptr).reset_player_turn();
93
94     /*
95      * Clear all saved floors
96      * and create a first saved floor
97      */
98     prepare_change_floor_mode(player_ptr, CFM_FIRST_FLOOR);
99
100     check_random_quest_auto_failure(player_ptr);
101
102     player_ptr->leaving = true;
103 }
104
105 /*!
106  * @brief 各種パターン地形上の特別な処理 / Returns TRUE if we are on the Pattern...
107  * @return 実際にパターン地形上にプレイヤーが居た場合はTRUEを返す。
108  */
109 bool pattern_effect(PlayerType *player_ptr)
110 {
111     auto *floor_ptr = player_ptr->current_floor_ptr;
112     if (!pattern_tile(floor_ptr, player_ptr->y, player_ptr->x)) {
113         return false;
114     }
115
116     auto is_cut = player_ptr->effects()->cut()->is_cut();
117     if ((PlayerRace(player_ptr).equals(PlayerRaceType::AMBERITE)) && is_cut && one_in_(10)) {
118         wreck_the_pattern(player_ptr);
119     }
120
121     int pattern_type = terrains_info[floor_ptr->grid_array[player_ptr->y][player_ptr->x].feat].subtype;
122     switch (pattern_type) {
123     case PATTERN_TILE_END:
124         (void)BadStatusSetter(player_ptr).hallucination(0);
125         (void)restore_all_status(player_ptr);
126         (void)restore_level(player_ptr);
127         (void)cure_critical_wounds(player_ptr, 1000);
128
129         cave_set_feat(player_ptr, player_ptr->y, player_ptr->x, feat_pattern_old);
130         msg_print(_("「パターン」のこの部分は他の部分より強力でないようだ。", "This section of the Pattern looks less powerful."));
131
132         /*
133          * We could make the healing effect of the
134          * Pattern center one-time only to avoid various kinds
135          * of abuse, like luring the win monster into fighting you
136          * in the middle of the pattern...
137          */
138         break;
139
140     case PATTERN_TILE_OLD:
141         /* No effect */
142         break;
143
144     case PATTERN_TILE_TELEPORT:
145         pattern_teleport(player_ptr);
146         break;
147
148     case PATTERN_TILE_WRECKED:
149         if (!is_invuln(player_ptr)) {
150             take_hit(player_ptr, DAMAGE_NOESCAPE, 200, _("壊れた「パターン」を歩いたダメージ", "walking the corrupted Pattern"));
151         }
152         break;
153
154     default:
155         if (PlayerRace(player_ptr).equals(PlayerRaceType::AMBERITE) && !one_in_(2)) {
156             return true;
157         } else if (!is_invuln(player_ptr)) {
158             take_hit(player_ptr, DAMAGE_NOESCAPE, damroll(1, 3), _("「パターン」を歩いたダメージ", "walking the Pattern"));
159         }
160         break;
161     }
162
163     return true;
164 }
165
166 /*!
167  * @brief パターンによる移動制限処理
168  * @param player_ptr プレイヤーへの参照ポインタ
169  * @param c_y プレイヤーの移動元Y座標
170  * @param c_x プレイヤーの移動元X座標
171  * @param n_y プレイヤーの移動先Y座標
172  * @param n_x プレイヤーの移動先X座標
173  * @return 移動処理が可能である場合(可能な場合に選択した場合)TRUEを返す。
174  */
175 bool pattern_seq(PlayerType *player_ptr, POSITION c_y, POSITION c_x, POSITION n_y, POSITION n_x)
176 {
177     TerrainType *cur_f_ptr = &terrains_info[player_ptr->current_floor_ptr->grid_array[c_y][c_x].feat];
178     TerrainType *new_f_ptr = &terrains_info[player_ptr->current_floor_ptr->grid_array[n_y][n_x].feat];
179     bool is_pattern_tile_cur = cur_f_ptr->flags.has(TerrainCharacteristics::PATTERN);
180     bool is_pattern_tile_new = new_f_ptr->flags.has(TerrainCharacteristics::PATTERN);
181     if (!is_pattern_tile_cur && !is_pattern_tile_new) {
182         return true;
183     }
184
185     int pattern_type_cur = is_pattern_tile_cur ? cur_f_ptr->subtype : NOT_PATTERN_TILE;
186     int pattern_type_new = is_pattern_tile_new ? new_f_ptr->subtype : NOT_PATTERN_TILE;
187     if (pattern_type_new == PATTERN_TILE_START) {
188         auto effects = player_ptr->effects();
189         auto is_stunned = effects->stun()->is_stunned();
190         auto is_confused = effects->confusion()->is_confused();
191         auto is_hallucinated = effects->hallucination()->is_hallucinated();
192         if (!is_pattern_tile_cur && !is_confused && !is_stunned && !is_hallucinated) {
193             if (input_check(_("パターンの上を歩き始めると、全てを歩かなければなりません。いいですか?",
194                     "If you start walking the Pattern, you must walk the whole way. Ok? "))) {
195                 return true;
196             } else {
197                 return false;
198             }
199         } else {
200             return true;
201         }
202     }
203
204     if ((pattern_type_new == PATTERN_TILE_OLD) || (pattern_type_new == PATTERN_TILE_END) || (pattern_type_new == PATTERN_TILE_WRECKED)) {
205         if (is_pattern_tile_cur) {
206             return true;
207         } else {
208             msg_print(_("パターンの上を歩くにはスタート地点から歩き始めなくてはなりません。", "You must start walking the Pattern from the startpoint."));
209             return false;
210         }
211     }
212
213     if ((pattern_type_new == PATTERN_TILE_TELEPORT) || (pattern_type_cur == PATTERN_TILE_TELEPORT)) {
214         return true;
215     }
216
217     if (pattern_type_cur == PATTERN_TILE_START) {
218         if (is_pattern_tile_new) {
219             return true;
220         } else {
221             msg_print(_("パターンの上は正しい順序で歩かねばなりません。", "You must walk the Pattern in correct order."));
222             return false;
223         }
224     }
225
226     if ((pattern_type_cur == PATTERN_TILE_OLD) || (pattern_type_cur == PATTERN_TILE_END) || (pattern_type_cur == PATTERN_TILE_WRECKED)) {
227         if (!is_pattern_tile_new) {
228             msg_print(_("パターンを踏み外してはいけません。", "You may not step off from the Pattern."));
229             return false;
230         } else {
231             return true;
232         }
233     }
234
235     if (!is_pattern_tile_cur) {
236         msg_print(_("パターンの上を歩くにはスタート地点から歩き始めなくてはなりません。", "You must start walking the Pattern from the startpoint."));
237
238         return false;
239     }
240
241     byte ok_move = PATTERN_TILE_START;
242     switch (pattern_type_cur) {
243     case PATTERN_TILE_1:
244         ok_move = PATTERN_TILE_2;
245         break;
246     case PATTERN_TILE_2:
247         ok_move = PATTERN_TILE_3;
248         break;
249     case PATTERN_TILE_3:
250         ok_move = PATTERN_TILE_4;
251         break;
252     case PATTERN_TILE_4:
253         ok_move = PATTERN_TILE_1;
254         break;
255     default:
256         if (w_ptr->wizard) {
257             msg_format(_("おかしなパターン歩行、%d。", "Funny Pattern walking, %d."), pattern_type_cur);
258         }
259         return true;
260     }
261
262     if ((pattern_type_new == ok_move) || (pattern_type_new == pattern_type_cur)) {
263         return true;
264     }
265
266     if (!is_pattern_tile_new) {
267         msg_print(_("パターンを踏み外してはいけません。", "You may not step off from the Pattern."));
268     } else {
269         msg_print(_("パターンの上は正しい順序で歩かねばなりません。", "You must walk the Pattern in correct order."));
270     }
271
272     return false;
273 }