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 "hpmp/hp-mp-processor.h"
16 #include "hpmp/hp-mp-regenerator.h"
17 #include "inventory/inventory-curse.h"
18 #include "inventory/recharge-processor.h"
19 #include "io/write-diary.h"
20 #include "market/arena.h"
21 #include "market/bounty.h"
22 #include "monster-floor/monster-generator.h"
23 #include "monster-floor/monster-summon.h"
24 #include "monster/monster-describer.h"
25 #include "monster/monster-status.h"
26 #include "mutation/mutation-processor.h"
27 #include "object/lite-processor.h"
28 #include "perception/simple-perception.h"
29 #include "player-status/player-energy.h"
30 #include "player/digestion-processor.h"
31 #include "store/store-owners.h"
32 #include "store/store-util.h"
33 #include "store/store.h"
34 #include "system/floor-type-definition.h"
35 #include "system/grid-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"
46 WorldTurnProcessor::WorldTurnProcessor(PlayerType *player_ptr)
47 : player_ptr(player_ptr)
52 * @brief 10ゲームターンが進行する毎にゲーム世界全体の処理を行う。
53 * / Handle certain things once every 10 game turns
54 * @param player_ptr プレイヤーへの参照ポインタ
56 void WorldTurnProcessor::process_world()
58 const int32_t a_day = TURNS_PER_TICK * TOWN_DAWN;
59 int32_t prev_turn_in_today = ((w_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;
63 extract_day_hour_min(this->player_ptr, &dummy_day, &this->hour, &this->min);
64 update_dungeon_feeling(this->player_ptr);
66 process_monster_arena();
67 if (w_ptr->game_turn % TURNS_PER_TICK) {
72 auto *floor_ptr = this->player_ptr->current_floor_ptr;
73 if (floor_ptr->monster_noise && !ignore_unview) {
74 msg_print(_("何かが聞こえた。", "You hear noise."));
77 process_change_daytime_night();
78 process_world_monsters();
79 if (!this->hour && !this->min) {
80 if (this->min != prev_min) {
81 exe_write_diary(this->player_ptr, DIARY_DIALY, 0, nullptr);
82 determine_daily_bounty(this->player_ptr, false);
86 ring_nightmare_bell(prev_min);
87 starve_player(this->player_ptr);
88 process_player_hp_mp(this->player_ptr);
89 reduce_magic_effects_timeout(this->player_ptr);
90 reduce_lite_life(this->player_ptr);
91 process_world_aux_mutation(this->player_ptr);
92 execute_cursed_items_effect(this->player_ptr);
93 recharge_magic_items(this->player_ptr);
94 sense_inventory1(this->player_ptr);
95 sense_inventory2(this->player_ptr);
96 execute_recall(this->player_ptr);
97 execute_floor_reset(this->player_ptr);
101 * @brief ゲーム時刻を表示する /
104 void WorldTurnProcessor::print_time()
107 c_put_str(TERM_WHITE, " ", ROW_DAY, COL_DAY);
108 extract_day_hour_min(this->player_ptr, &day, &this->hour, &this->min);
110 c_put_str(TERM_WHITE, format(_("%2d日目", "Day%3d"), day), ROW_DAY, COL_DAY);
112 c_put_str(TERM_WHITE, _("***日目", "Day***"), ROW_DAY, COL_DAY);
115 c_put_str(TERM_WHITE, format("%2d:%02d", this->hour, this->min), ROW_DAY, COL_DAY + 7);
118 void WorldTurnProcessor::process_downward()
120 /* 帰還無しモード時のレベルテレポバグ対策 / Fix for level teleport bugs on ironman_downward.*/
121 if (!ironman_downward || (this->player_ptr->dungeon_idx == DUNGEON_ANGBAND) || (this->player_ptr->dungeon_idx == 0)) {
125 auto *floor_ptr = this->player_ptr->current_floor_ptr;
126 floor_ptr->dun_level = 0;
127 this->player_ptr->dungeon_idx = 0;
128 prepare_change_floor_mode(this->player_ptr, CFM_FIRST_FLOOR | CFM_RAND_PLACE);
129 floor_ptr->inside_arena = false;
130 this->player_ptr->wild_mode = false;
131 this->player_ptr->leaving = true;
134 void WorldTurnProcessor::process_monster_arena()
136 if (!this->player_ptr->phase_out || this->player_ptr->leaving) {
142 auto *floor_ptr = this->player_ptr->current_floor_ptr;
143 for (auto x = 0; x < floor_ptr->width; ++x) {
144 for (auto y = 0; y < floor_ptr->height; y++) {
145 auto *g_ptr = &floor_ptr->grid_array[y][x];
146 if ((g_ptr->m_idx > 0) && (g_ptr->m_idx != this->player_ptr->riding)) {
148 win_m_idx = g_ptr->m_idx;
153 if (number_mon == 0) {
154 msg_print(_("相打ちに終わりました。", "Nothing survived."));
156 this->player_ptr->energy_need = 0;
157 update_gambling_monsters(this->player_ptr);
161 if (number_mon == 1) {
162 process_monster_arena_winner(win_m_idx);
166 process_monster_arena_draw();
169 void WorldTurnProcessor::process_monster_arena_winner(int win_m_idx)
171 GAME_TEXT m_name[MAX_NLEN];
172 auto *wm_ptr = &this->player_ptr->current_floor_ptr->m_list[win_m_idx];
173 monster_desc(this->player_ptr, m_name, wm_ptr, 0);
174 msg_format(_("%sが勝利した!", "%s won!"), m_name);
177 if (win_m_idx == (sel_monster + 1)) {
178 msg_print(_("おめでとうございます。", "Congratulations."));
179 msg_format(_("%d$を受け取った。", "You received %d gold."), battle_odds);
180 this->player_ptr->au += battle_odds;
182 msg_print(_("残念でした。", "You lost gold."));
186 this->player_ptr->energy_need = 0;
187 update_gambling_monsters(this->player_ptr);
190 void WorldTurnProcessor::process_monster_arena_draw()
192 auto turn = this->player_ptr->current_floor_ptr->generated_turn;
193 if (w_ptr->game_turn - turn != 150 * TURNS_PER_TICK) {
197 msg_print(_("申し訳ありませんが、この勝負は引き分けとさせていただきます。", "Sorry, but this battle ended in a draw."));
198 this->player_ptr->au += kakekin;
200 this->player_ptr->energy_need = 0;
201 update_gambling_monsters(this->player_ptr);
204 void WorldTurnProcessor::decide_auto_save()
206 if (autosave_freq == 0) {
210 auto should_save = autosave_t;
211 should_save &= !this->player_ptr->phase_out;
212 should_save &= w_ptr->game_turn % ((int32_t)autosave_freq * TURNS_PER_TICK) == 0;
214 do_cmd_save_game(this->player_ptr, true);
218 void WorldTurnProcessor::process_change_daytime_night()
220 auto *floor_ptr = this->player_ptr->current_floor_ptr;
221 if (!floor_ptr->dun_level && !inside_quest(floor_ptr->quest_number) && !this->player_ptr->phase_out && !floor_ptr->inside_arena) {
222 if (!(w_ptr->game_turn % ((TURNS_PER_TICK * TOWN_DAWN) / 2))) {
223 auto dawn = w_ptr->game_turn % (TURNS_PER_TICK * TOWN_DAWN) == 0;
225 day_break(this->player_ptr);
227 night_falls(this->player_ptr);
234 auto is_in_dungeon = vanilla_town;
235 is_in_dungeon |= lite_town && (!inside_quest(floor_ptr->quest_number)) && !this->player_ptr->phase_out && !floor_ptr->inside_arena;
236 is_in_dungeon &= floor_ptr->dun_level != 0;
237 if (!is_in_dungeon) {
241 if ((w_ptr->game_turn % (TURNS_PER_TICK * STORE_TICKS)) != 0) {
245 shuffle_shopkeeper();
248 void WorldTurnProcessor::process_world_monsters()
250 decide_alloc_monster();
251 if (!(w_ptr->game_turn % (TURNS_PER_TICK * 10)) && !this->player_ptr->phase_out) {
252 regenerate_monsters(this->player_ptr);
255 if (!(w_ptr->game_turn % (TURNS_PER_TICK * 3))) {
256 regenerate_captured_monsters(this->player_ptr);
259 if (this->player_ptr->leaving) {
263 for (auto i = 0; i < MAX_MTIMED; i++) {
264 if (this->player_ptr->current_floor_ptr->mproc_max[i] > 0) {
265 process_monsters_mtimed(this->player_ptr, i);
270 void WorldTurnProcessor::shuffle_shopkeeper()
272 if (!one_in_(STORE_SHUFFLE)) {
278 n = randint0(MAX_STORES);
279 if ((n == enum2i(StoreSaleType::HOME)) || (n == enum2i(StoreSaleType::MUSEUM))) {
284 for (const auto &f_ref : f_info) {
285 if (f_ref.name.empty() || f_ref.flags.has_not(FloorFeatureType::STORE)) {
289 if (f_ref.subtype != n) {
294 msg_format(_("%sの店主をシャッフルします。", "Shuffle a Shopkeeper of %s."), f_ref.name.c_str());
297 store_shuffle(this->player_ptr, i2enum<StoreSaleType>(n));
302 void WorldTurnProcessor::decide_alloc_monster()
304 auto *floor_ptr = this->player_ptr->current_floor_ptr;
305 auto should_alloc = one_in_(d_info[this->player_ptr->dungeon_idx].max_m_alloc_chance);
306 should_alloc &= !floor_ptr->inside_arena;
307 should_alloc &= !inside_quest(floor_ptr->quest_number);
308 should_alloc &= !this->player_ptr->phase_out;
310 (void)alloc_monster(this->player_ptr, MAX_SIGHT + 5, 0, summon_specific);
315 * Nightmare mode activates the TY_CURSE at midnight
316 * Require exact minute -- Don't activate multiple times in a minute
318 void WorldTurnProcessor::ring_nightmare_bell(int prev_min)
320 if (!ironman_nightmare || (this->min == prev_min)) {
324 if ((this->hour == 23) && !(this->min % 15)) {
325 disturb(this->player_ptr, false, true);
326 switch (this->min / 15) {
328 msg_print(_("遠くで不気味な鐘の音が鳴った。", "You hear a distant bell toll ominously."));
332 msg_print(_("遠くで鐘が二回鳴った。", "A distant bell sounds twice."));
336 msg_print(_("遠くで鐘が三回鳴った。", "A distant bell sounds three times."));
340 msg_print(_("遠くで鐘が四回鳴った。", "A distant bell tolls four times."));
345 if ((this->hour > 0) || (this->min > 0)) {
349 disturb(this->player_ptr, true, true);
350 msg_print(_("遠くで鐘が何回も鳴り、死んだような静けさの中へ消えていった。", "A distant bell tolls many times, fading into an deathly silence."));
351 if (this->player_ptr->wild_mode) {
352 this->player_ptr->oldpy = randint1(MAX_HGT - 2);
353 this->player_ptr->oldpx = randint1(MAX_WID - 2);
354 change_wild_mode(this->player_ptr, true);
355 PlayerEnergy(this->player_ptr).set_player_turn_energy(100);
358 this->player_ptr->invoking_midnight_curse = true;