OSDN Git Service

[Refactor] #969 Reshaped process_downward()
[hengbandforosx/hengbandosx.git] / src / world / world-turn-processor.cpp
1 #include "world/world-turn-processor.h"
2 #include "cmd-building/cmd-building.h"
3 #include "cmd-io/cmd-save.h"
4 #include "core/disturbance.h"
5 #include "core/magic-effects-timeout-reducer.h"
6 #include "dungeon/dungeon.h"
7 #include "floor/floor-events.h"
8 #include "floor/floor-mode-changer.h"
9 #include "floor/wild.h"
10 #include "game-option/birth-options.h"
11 #include "game-option/cheat-options.h"
12 #include "game-option/special-options.h"
13 #include "game-option/text-display-options.h"
14 #include "grid/feature.h"
15 #include "grid/grid.h"
16 #include "hpmp/hp-mp-processor.h"
17 #include "hpmp/hp-mp-regenerator.h"
18 #include "inventory/inventory-curse.h"
19 #include "inventory/recharge-processor.h"
20 #include "io/write-diary.h"
21 #include "market/arena.h"
22 #include "market/bounty.h"
23 #include "monster-floor/monster-generator.h"
24 #include "monster-floor/monster-summon.h"
25 #include "monster/monster-describer.h"
26 #include "monster/monster-status.h"
27 #include "mutation/mutation-processor.h"
28 #include "object/lite-processor.h"
29 #include "perception/simple-perception.h"
30 #include "player-status/player-energy.h"
31 #include "player/digestion-processor.h"
32 #include "store/store-owners.h"
33 #include "store/store-util.h"
34 #include "store/store.h"
35 #include "system/floor-type-definition.h"
36 #include "system/monster-type-definition.h"
37 #include "system/player-type-definition.h"
38 #include "term/screen-processor.h"
39 #include "term/term-color-types.h"
40 #include "util/bit-flags-calculator.h"
41 #include "view/display-messages.h"
42 #include "window/main-window-row-column.h"
43 #include "world/world-movement-processor.h"
44 #include "world/world.h"
45
46 WorldTurnProcessor::WorldTurnProcessor(player_type *player_ptr)
47     : player_ptr(player_ptr)
48 {
49 }
50
51 /*!
52  * @brief 10ゲームターンが進行する毎にゲーム世界全体の処理を行う。
53  * / Handle certain things once every 10 game turns
54  * @param player_ptr プレーヤーへの参照ポインタ
55  */
56 void WorldTurnProcessor::process_world()
57 {
58     const s32b a_day = TURNS_PER_TICK * TOWN_DAWN;
59     s32b prev_turn_in_today = ((current_world_ptr->game_turn - TURNS_PER_TICK) % a_day + a_day / 4) % a_day;
60     int prev_min = (1440 * prev_turn_in_today / a_day) % 60;
61
62     int dummy_day;
63     extract_day_hour_min(this->player_ptr, &dummy_day, &this->hour, &this->min);
64     update_dungeon_feeling(this->player_ptr);
65     process_downward();
66     process_monster_arena();
67     if (current_world_ptr->game_turn % TURNS_PER_TICK)
68         return;
69
70     if (autosave_t && autosave_freq && !this->player_ptr->phase_out) {
71         if (!(current_world_ptr->game_turn % ((s32b)autosave_freq * TURNS_PER_TICK)))
72             do_cmd_save_game(this->player_ptr, TRUE);
73     }
74
75     auto *floor_ptr = this->player_ptr->current_floor_ptr;
76     if (floor_ptr->monster_noise && !ignore_unview) {
77         msg_print(_("何かが聞こえた。", "You hear noise."));
78     }
79
80     if (!floor_ptr->dun_level && !floor_ptr->inside_quest && !this->player_ptr->phase_out && !floor_ptr->inside_arena) {
81         if (!(current_world_ptr->game_turn % ((TURNS_PER_TICK * TOWN_DAWN) / 2))) {
82             bool dawn = (!(current_world_ptr->game_turn % (TURNS_PER_TICK * TOWN_DAWN)));
83             if (dawn)
84                 day_break(this->player_ptr);
85             else
86                 night_falls(this->player_ptr);
87         }
88     } else if ((vanilla_town || (lite_town && !floor_ptr->inside_quest && !this->player_ptr->phase_out && !floor_ptr->inside_arena)) && floor_ptr->dun_level) {
89         if (!(current_world_ptr->game_turn % (TURNS_PER_TICK * STORE_TICKS))) {
90             if (one_in_(STORE_SHUFFLE)) {
91                 int n;
92                 do {
93                     n = randint0(MAX_STORES);
94                 } while ((n == STORE_HOME) || (n == STORE_MUSEUM));
95
96                 for (FEAT_IDX i = 1; i < max_f_idx; i++) {
97                     feature_type *f_ptr = &f_info[i];
98                     if (f_ptr->name.empty())
99                         continue;
100                     if (!has_flag(f_ptr->flags, FF_STORE))
101                         continue;
102
103                     if (f_ptr->subtype == n) {
104                         if (cheat_xtra)
105                             msg_format(_("%sの店主をシャッフルします。", "Shuffle a Shopkeeper of %s."), f_ptr->name.c_str());
106
107                         store_shuffle(this->player_ptr, n);
108                         break;
109                     }
110                 }
111             }
112         }
113     }
114
115     if (one_in_(d_info[this->player_ptr->dungeon_idx].max_m_alloc_chance) && !floor_ptr->inside_arena && !floor_ptr->inside_quest && !this->player_ptr->phase_out) {
116         (void)alloc_monster(this->player_ptr, MAX_SIGHT + 5, 0, summon_specific);
117     }
118
119     if (!(current_world_ptr->game_turn % (TURNS_PER_TICK * 10)) && !this->player_ptr->phase_out)
120         regenerate_monsters(this->player_ptr);
121     if (!(current_world_ptr->game_turn % (TURNS_PER_TICK * 3)))
122         regenerate_captured_monsters(this->player_ptr);
123
124     if (!this->player_ptr->leaving) {
125         for (int i = 0; i < MAX_MTIMED; i++) {
126             if (floor_ptr->mproc_max[i] > 0)
127                 process_monsters_mtimed(this->player_ptr, i);
128         }
129     }
130
131     if (!this->hour && !this->min) {
132         if (this->min != prev_min) {
133             exe_write_diary(this->player_ptr, DIARY_DIALY, 0, NULL);
134             determine_daily_bounty(this->player_ptr, FALSE);
135         }
136     }
137
138     /*
139      * Nightmare mode activates the TY_CURSE at midnight
140      * Require exact minute -- Don't activate multiple times in a minute
141      */
142     if (ironman_nightmare && (this->min != prev_min)) {
143         if ((this->hour == 23) && !(this->min % 15)) {
144             disturb(this->player_ptr, FALSE, TRUE);
145             switch (this->min / 15) {
146             case 0:
147                 msg_print(_("遠くで不気味な鐘の音が鳴った。", "You hear a distant bell toll ominously."));
148                 break;
149
150             case 1:
151                 msg_print(_("遠くで鐘が二回鳴った。", "A distant bell sounds twice."));
152                 break;
153
154             case 2:
155                 msg_print(_("遠くで鐘が三回鳴った。", "A distant bell sounds three times."));
156                 break;
157
158             case 3:
159                 msg_print(_("遠くで鐘が四回鳴った。", "A distant bell tolls four times."));
160                 break;
161             }
162         }
163
164         if (!this->hour && !this->min) {
165             disturb(this->player_ptr, TRUE, TRUE);
166             msg_print(_("遠くで鐘が何回も鳴り、死んだような静けさの中へ消えていった。", "A distant bell tolls many times, fading into an deathly silence."));
167             if (this->player_ptr->wild_mode) {
168                 this->player_ptr->oldpy = randint1(MAX_HGT - 2);
169                 this->player_ptr->oldpx = randint1(MAX_WID - 2);
170                 change_wild_mode(this->player_ptr, TRUE);
171                 PlayerEnergy(this->player_ptr).set_player_turn_energy(100);
172             }
173
174             this->player_ptr->invoking_midnight_curse = TRUE;
175         }
176     }
177
178     starve_player(this->player_ptr);
179     process_player_hp_mp(this->player_ptr);
180     reduce_magic_effects_timeout(this->player_ptr);
181     reduce_lite_life(this->player_ptr);
182     process_world_aux_mutation(this->player_ptr);
183     execute_cursed_items_effect(this->player_ptr);
184     recharge_magic_items(this->player_ptr);
185     sense_inventory1(this->player_ptr);
186     sense_inventory2(this->player_ptr);
187     execute_recall(this->player_ptr);
188     execute_floor_reset(this->player_ptr);
189 }
190
191 /*!
192  * @brief ゲーム時刻を表示する /
193  * Print time
194  */
195 void WorldTurnProcessor::print_time()
196 {
197     int day;
198     c_put_str(TERM_WHITE, "             ", ROW_DAY, COL_DAY);
199     extract_day_hour_min(this->player_ptr, &day, &this->hour, &this->min);
200     if (day < 1000)
201         c_put_str(TERM_WHITE, format(_("%2d日目", "Day%3d"), day), ROW_DAY, COL_DAY);
202     else
203         c_put_str(TERM_WHITE, _("***日目", "Day***"), ROW_DAY, COL_DAY);
204
205     c_put_str(TERM_WHITE, format("%2d:%02d", this->hour, this->min), ROW_DAY, COL_DAY + 7);
206 }
207
208 void WorldTurnProcessor::process_downward()
209 {
210     /* 帰還無しモード時のレベルテレポバグ対策 / Fix for level teleport bugs on ironman_downward.*/
211     if (!ironman_downward || (this->player_ptr->dungeon_idx == DUNGEON_ANGBAND) || (this->player_ptr->dungeon_idx == 0)) {
212         return;    
213     }
214
215     auto *floor_ptr = this->player_ptr->current_floor_ptr;
216     floor_ptr->dun_level = 0;
217     this->player_ptr->dungeon_idx = 0;
218     prepare_change_floor_mode(this->player_ptr, CFM_FIRST_FLOOR | CFM_RAND_PLACE);
219     floor_ptr->inside_arena = FALSE;
220     this->player_ptr->wild_mode = FALSE;
221     this->player_ptr->leaving = TRUE;
222 }
223
224 void WorldTurnProcessor::process_monster_arena()
225 {
226     if (!this->player_ptr->phase_out || this->player_ptr->leaving) {
227         return;
228     }
229
230     auto win_m_idx = 0;
231     auto number_mon = 0;
232     auto *floor_ptr = this->player_ptr->current_floor_ptr;
233     for (auto x = 0; x < floor_ptr->width; ++x) {
234         for (auto y = 0; y < floor_ptr->height; y++) {
235             auto *g_ptr = &floor_ptr->grid_array[y][x];
236             if ((g_ptr->m_idx > 0) && (g_ptr->m_idx != this->player_ptr->riding)) {
237                 number_mon++;
238                 win_m_idx = g_ptr->m_idx;
239             }
240         }
241     }
242
243     if (number_mon == 0) {
244         msg_print(_("相打ちに終わりました。", "Nothing survived."));
245         msg_print(NULL);
246         this->player_ptr->energy_need = 0;
247         update_gambling_monsters(this->player_ptr);
248         return;
249     }
250     
251     if (number_mon == 1) {
252         process_monster_arena_winner(win_m_idx);
253         return;
254     }
255
256     process_monster_arena_draw();
257 }
258
259 void WorldTurnProcessor::process_monster_arena_winner(int win_m_idx)
260 {
261     GAME_TEXT m_name[MAX_NLEN];
262     auto *wm_ptr = &this->player_ptr->current_floor_ptr->m_list[win_m_idx];
263     monster_desc(this->player_ptr, m_name, wm_ptr, 0);
264     msg_format(_("%sが勝利した!", "%s won!"), m_name);
265     msg_print(NULL);
266
267     if (win_m_idx == (sel_monster + 1)) {
268         msg_print(_("おめでとうございます。", "Congratulations."));
269         msg_format(_("%d$を受け取った。", "You received %d gold."), battle_odds);
270         this->player_ptr->au += battle_odds;
271     } else {
272         msg_print(_("残念でした。", "You lost gold."));
273     }
274
275     msg_print(NULL);
276     this->player_ptr->energy_need = 0;
277     update_gambling_monsters(this->player_ptr);
278 }
279
280 void WorldTurnProcessor::process_monster_arena_draw()
281 {
282     auto turn = this->player_ptr->current_floor_ptr->generated_turn;
283     if (current_world_ptr->game_turn - turn != 150 * TURNS_PER_TICK) {
284         return;
285     }
286
287     msg_print(_("申し訳ありませんが、この勝負は引き分けとさせていただきます。", "Sorry, but this battle ended in a draw."));
288     this->player_ptr->au += kakekin;
289     msg_print(NULL);
290     this->player_ptr->energy_need = 0;
291     update_gambling_monsters(this->player_ptr);
292 }