OSDN Git Service

[Refactor] #2713 PlayerType::dungeon_idx をFloorType::dungeon_idx へ吸収合併した
[hengbandforosx/hengbandosx.git] / src / dungeon / dungeon-processor.cpp
1 #include "dungeon/dungeon-processor.h"
2 #include "cmd-building/cmd-building.h"
3 #include "cmd-io/cmd-dump.h"
4 #include "core/disturbance.h"
5 #include "core/object-compressor.h"
6 #include "core/player-processor.h"
7 #include "core/player-redraw-types.h"
8 #include "core/stuff-handler.h"
9 #include "core/turn-compensator.h"
10 #include "core/window-redrawer.h"
11 #include "dungeon/quest.h"
12 #include "floor/floor-leaver.h"
13 #include "floor/floor-save-util.h"
14 #include "floor/floor-save.h"
15 #include "game-option/cheat-options.h"
16 #include "game-option/map-screen-options.h"
17 #include "game-option/play-record-options.h"
18 #include "hpmp/hp-mp-regenerator.h"
19 #include "io/cursor.h"
20 #include "io/input-key-requester.h"
21 #include "io/write-diary.h"
22 #include "market/arena.h"
23 #include "mind/mind-ninja.h"
24 #include "monster-race/monster-race.h"
25 #include "monster-race/race-flags1.h"
26 #include "monster/monster-compaction.h"
27 #include "monster/monster-processor.h"
28 #include "monster/monster-status.h"
29 #include "monster/monster-util.h"
30 #include "pet/pet-util.h"
31 #include "player-base/player-class.h"
32 #include "player/special-defense-types.h"
33 #include "realm/realm-song-numbers.h"
34 #include "realm/realm-song.h"
35 #include "spell-realm/spells-song.h"
36 #include "system/dungeon-info.h"
37 #include "system/floor-type-definition.h"
38 #include "system/monster-race-info.h"
39 #include "system/player-type-definition.h"
40 #include "system/redrawing-flags-updater.h"
41 #include "target/target-checker.h"
42 #include "util/bit-flags-calculator.h"
43 #include "view/display-messages.h"
44 #include "world/world-turn-processor.h"
45 #include "world/world.h"
46
47 static void redraw_character_xtra(PlayerType *player_ptr)
48 {
49     w_ptr->character_xtra = true;
50     auto &rfu = RedrawingFlagsUpdater::get_instance();
51     auto flags_srf = {
52         StatusRedrawingFlag::BONUS,
53         StatusRedrawingFlag::HP,
54         StatusRedrawingFlag::MP,
55         StatusRedrawingFlag::SPELLS,
56         StatusRedrawingFlag::VIEW,
57         StatusRedrawingFlag::LITE,
58         StatusRedrawingFlag::MONSTER_LITE,
59         StatusRedrawingFlag::TORCH,
60         StatusRedrawingFlag::MONSTER_STATUSES,
61         StatusRedrawingFlag::DISTANCE,
62         StatusRedrawingFlag::FLOW,
63     };
64     set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_SPELL | PW_PLAYER | PW_MONSTER_LORE | PW_OVERHEAD | PW_DUNGEON);
65     set_bits(player_ptr->redraw, PR_WIPE | PR_BASIC | PR_EXTRA | PR_EQUIPPY | PR_MAP);
66     rfu.set_flags(flags_srf);
67     handle_stuff(player_ptr);
68     w_ptr->character_xtra = false;
69 }
70
71 /*!
72  * process_player()、process_world() をcore.c から移設するのが先.
73  * process_upkeep_with_speed() はこの関数と同じところでOK
74  * @brief 現在プレイヤーがいるダンジョンの全体処理 / Interact with the current dungeon level.
75  * @details
76  * <p>
77  * この関数から現在の階層を出る、プレイヤーがキャラが死ぬ、
78  * ゲームを終了するかのいずれかまでループする。
79  * </p>
80  * <p>
81  * This function will not exit until the level is completed,\n
82  * the user dies, or the game is terminated.\n
83  * </p>
84  */
85 void process_dungeon(PlayerType *player_ptr, bool load_game)
86 {
87     auto &floor = *player_ptr->current_floor_ptr;
88     floor.base_level = floor.dun_level;
89     w_ptr->is_loading_now = false;
90     player_ptr->leaving = false;
91
92     command_cmd = 0;
93     command_rep = 0;
94     command_arg = 0;
95     command_dir = 0;
96
97     target_who = 0;
98     player_ptr->pet_t_m_idx = 0;
99     player_ptr->riding_t_m_idx = 0;
100     player_ptr->ambush_flag = false;
101     health_track(player_ptr, 0);
102
103     disturb(player_ptr, true, true);
104     auto quest_num = quest_number(floor, floor.dun_level);
105     const auto &quest_list = QuestList::get_instance();
106     auto *questor_ptr = &monraces_info[quest_list[quest_num].r_idx];
107     if (inside_quest(quest_num)) {
108         set_bits(questor_ptr->flags1, RF1_QUESTOR);
109     }
110
111     if (player_ptr->max_plv < player_ptr->lev) {
112         player_ptr->max_plv = player_ptr->lev;
113     }
114
115     if ((max_dlv[floor.dungeon_idx] < floor.dun_level) && !inside_quest(floor.quest_number)) {
116         max_dlv[floor.dungeon_idx] = floor.dun_level;
117         if (record_maxdepth) {
118             exe_write_diary(player_ptr, DIARY_MAXDEAPTH, floor.dun_level, nullptr);
119         }
120     }
121
122     (void)calculate_upkeep(player_ptr);
123     panel_bounds_center();
124     verify_panel(player_ptr);
125     msg_erase();
126
127     redraw_character_xtra(player_ptr);
128     auto flags_srf = {
129         StatusRedrawingFlag::BONUS,
130         StatusRedrawingFlag::HP,
131         StatusRedrawingFlag::MP,
132         StatusRedrawingFlag::SPELLS,
133         StatusRedrawingFlag::COMBINATION,
134         StatusRedrawingFlag::REORDER,
135     };
136     RedrawingFlagsUpdater::get_instance().set_flags(flags_srf);
137     handle_stuff(player_ptr);
138     term_fresh();
139
140     auto no_feeling_quest = (quest_num == QuestId::OBERON);
141     no_feeling_quest |= (quest_num == QuestId::SERPENT);
142     no_feeling_quest |= none_bits(quest_list[quest_num].flags, QUEST_FLAG_PRESET);
143     if (inside_quest(quest_num) && QuestType::is_fixed(quest_num) && !no_feeling_quest) {
144         do_cmd_feeling(player_ptr);
145     }
146
147     if (player_ptr->phase_out) {
148         if (load_game) {
149             player_ptr->energy_need = 0;
150             update_gambling_monsters(player_ptr);
151         } else {
152             msg_print(_("試合開始!", "Ready..Fight!"));
153             msg_print(nullptr);
154         }
155     }
156
157     if (PlayerClass(player_ptr).equals(PlayerClassType::BARD) && (get_singing_song_effect(player_ptr) > MUSIC_DETECT)) {
158         set_singing_song_effect(player_ptr, MUSIC_DETECT);
159     }
160
161     if (!player_ptr->playing || player_ptr->is_dead) {
162         return;
163     }
164
165     if (!inside_quest(floor.quest_number) && (floor.dungeon_idx == DUNGEON_ANGBAND)) {
166         quest_discovery(random_quest_number(floor, floor.dun_level));
167         floor.quest_number = random_quest_number(floor, floor.dun_level);
168     }
169
170     const auto &dungeon = dungeons_info[floor.dungeon_idx];
171     const auto guardian = dungeon.final_guardian;
172     if ((floor.dun_level == dungeon.maxdepth) && MonsterRace(guardian).is_valid()) {
173         const auto &guardian_ref = monraces_info[guardian];
174         if (guardian_ref.max_num) {
175 #ifdef JP
176             msg_format("この階には%sの主である%sが棲んでいる。", dungeon.name.data(), guardian_ref.name.data());
177 #else
178             msg_format("%s^ lives in this level as the keeper of %s.", guardian_ref.name.data(), dungeon.name.data());
179 #endif
180         }
181     }
182
183     if (!load_game) {
184         set_superstealth(player_ptr, false);
185     }
186
187     floor.monster_level = floor.base_level;
188     floor.object_level = floor.base_level;
189     w_ptr->is_loading_now = true;
190     if (player_ptr->energy_need > 0 && !player_ptr->phase_out && (floor.dun_level || player_ptr->leaving_dungeon || floor.inside_arena)) {
191         player_ptr->energy_need = 0;
192     }
193
194     player_ptr->leaving_dungeon = false;
195     mproc_init(&floor);
196
197     while (true) {
198         if ((floor.m_cnt + 32 > w_ptr->max_m_idx) && !player_ptr->phase_out) {
199             compact_monsters(player_ptr, 64);
200         }
201
202         if ((floor.m_cnt + 32 < floor.m_max) && !player_ptr->phase_out) {
203             compact_monsters(player_ptr, 0);
204         }
205
206         if (floor.o_cnt + 32 > w_ptr->max_o_idx) {
207             compact_objects(player_ptr, 64);
208         }
209
210         if (floor.o_cnt + 32 < floor.o_max) {
211             compact_objects(player_ptr, 0);
212         }
213
214         process_player(player_ptr);
215         process_upkeep_with_speed(player_ptr);
216         handle_stuff(player_ptr);
217
218         move_cursor_relative(player_ptr->y, player_ptr->x);
219         if (fresh_after) {
220             term_fresh_force();
221         }
222
223         if (!player_ptr->playing || player_ptr->is_dead) {
224             break;
225         }
226
227         process_monsters(player_ptr);
228         handle_stuff(player_ptr);
229
230         move_cursor_relative(player_ptr->y, player_ptr->x);
231         if (fresh_after) {
232             term_fresh_force();
233         }
234
235         if (!player_ptr->playing || player_ptr->is_dead) {
236             break;
237         }
238
239         WorldTurnProcessor(player_ptr).process_world();
240         handle_stuff(player_ptr);
241
242         move_cursor_relative(player_ptr->y, player_ptr->x);
243         if (fresh_after) {
244             term_fresh_force();
245         }
246
247         if (!player_ptr->playing || player_ptr->is_dead) {
248             break;
249         }
250
251         w_ptr->game_turn++;
252         if (w_ptr->dungeon_turn < w_ptr->dungeon_turn_limit) {
253             if (!player_ptr->wild_mode || wild_regen) {
254                 w_ptr->dungeon_turn++;
255             } else if (player_ptr->wild_mode && !(w_ptr->game_turn % ((MAX_HGT + MAX_WID) / 2))) {
256                 w_ptr->dungeon_turn++;
257             }
258         }
259
260         prevent_turn_overflow(player_ptr);
261
262         if (player_ptr->leaving) {
263             break;
264         }
265
266         if (wild_regen) {
267             wild_regen--;
268         }
269     }
270
271     if ((inside_quest(quest_num)) && questor_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
272         reset_bits(questor_ptr->flags1, RF1_QUESTOR);
273     }
274
275     if (player_ptr->playing && !player_ptr->is_dead) {
276         /*
277          * Maintain Unique monsters and artifact, save current
278          * floor, then prepare next floor
279          */
280         leave_floor(player_ptr);
281         reinit_wilderness = false;
282     }
283
284     write_level = true;
285 }