OSDN Git Service

[Refactor] #38862 Moved angband-version.h from core/ to system/
[hengband/hengband.git] / src / core / game-play.c
1 /*!
2  * @brief ゲームプレイのメインルーチン
3  * @date 2020/05/10
4  * @author Hourier
5  * @details
6  * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
7  * This software may be copied and distributed for educational, research, and
8  * not for profit purposes provided that this copyright and statement are
9  * included in all such copies.
10  * 2013 Deskull rearranged comment for Doxygen.
11  */
12
13 #include "system/angband.h"
14 #include "core/game-play.h"
15 #include "io/signal-handlers.h"
16 #include "util.h"
17 #include "system/angband-version.h"
18 #include "core/stuff-handler.h"
19 #include "inet.h"
20 #include "term/gameterm.h"
21 #include "chuukei.h"
22 #include "birth/birth.h"
23 #include "monster/creature.h"
24 #include "grid/feature.h"
25 #include "floor/floor-events.h"
26 #include "floor/floor-save.h"
27 #include "floor/floor.h"
28 #include "grid/grid.h"
29 #include "io/write-diary.h"
30 #include "market/arena-info-table.h"
31 #include "market/building.h"
32 #include "market/store-util.h"
33 #include "market/store.h"
34 #include "object/object-flavor.h"
35 #include "player/player-class.h"
36 #include "player/player-effects.h"
37 #include "player/player-personality.h"
38 #include "player/player-race.h"
39 #include "player/player-skill.h"
40 #include "player/process-name.h"
41 #include "spell/technic-info-table.h"
42 #include "spell/spells-status.h"
43 #include "view/display-player.h"
44 #include "floor/wild.h"
45 #include "world/world.h"
46 #include "autopick/autopick-pref-processor.h"
47 #include "core/game-closer.h"
48 #include "core/output-updater.h"
49 #include "core/player-processor.h"
50 #include "dungeon/dungeon-file.h"
51 #include "dungeon/dungeon-processor.h"
52 #include "io/input-key-processor.h"
53 #include "io/read-pref-file.h"
54 #include "realm/realm.h"
55 #include "io/save.h"
56 #include "scores.h"
57 #include "targeting.h"
58 #include "view/display-main-window.h"
59 #include "system/system-variables.h"
60
61 /*!
62  * @brief 1ゲームプレイの主要ルーチン / Actually play a game
63  * @return なし
64  * @note
65  * If the "new_game" parameter is true, then, after loading the
66  * savefile, we will commit suicide, if necessary, to allow the
67  * player to start a new game.
68  */
69 void play_game(player_type* player_ptr, bool new_game)
70 {
71     bool load_game = TRUE;
72     bool init_random_seed = FALSE;
73
74 #ifdef CHUUKEI
75     if (chuukei_client) {
76         reset_visuals(player_ptr, process_autopick_file_command);
77         browse_chuukei();
78         return;
79     }
80
81     else if (chuukei_server) {
82         prepare_chuukei_hooks();
83     }
84 #endif
85
86     if (browsing_movie) {
87         reset_visuals(player_ptr, process_autopick_file_command);
88         browse_movie();
89         return;
90     }
91
92     player_ptr->hack_mutation = FALSE;
93     current_world_ptr->character_icky = TRUE;
94     Term_activate(angband_term[0]);
95     angband_term[0]->resize_hook = resize_map;
96     for (MONSTER_IDX i = 1; i < 8; i++) {
97         if (angband_term[i]) {
98             angband_term[i]->resize_hook = redraw_window;
99         }
100     }
101
102     (void)Term_set_cursor(0);
103     if (!load_player(player_ptr)) {
104         quit(_("セーブファイルが壊れています", "broken savefile"));
105     }
106
107     extract_option_vars();
108     if (player_ptr->wait_report_score) {
109         char buf[1024];
110         bool success;
111
112         if (!get_check_strict(_("待機していたスコア登録を今行ないますか?", "Do you register score now? "), CHECK_NO_HISTORY))
113             quit(0);
114
115         player_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS);
116         update_creature(player_ptr);
117         player_ptr->is_dead = TRUE;
118         current_world_ptr->start_time = (u32b)time(NULL);
119         signals_ignore_tstp();
120         current_world_ptr->character_icky = TRUE;
121         path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
122         highscore_fd = fd_open(buf, O_RDWR);
123
124         /* 町名消失バグ対策(#38205)のためここで世界マップ情報を読み出す */
125         process_dungeon_file(player_ptr, "w_info.txt", 0, 0, current_world_ptr->max_wild_y, current_world_ptr->max_wild_x);
126         success = send_world_score(player_ptr, TRUE, update_playtime, display_player, map_name);
127
128         if (!success && !get_check_strict(_("スコア登録を諦めますか?", "Do you give up score registration? "), CHECK_NO_HISTORY)) {
129             prt(_("引き続き待機します。", "standing by for future registration..."), 0, 0);
130             (void)inkey();
131         } else {
132             player_ptr->wait_report_score = FALSE;
133             top_twenty(player_ptr);
134             if (!save_player(player_ptr))
135                 msg_print(_("セーブ失敗!", "death save failed!"));
136         }
137
138         (void)fd_close(highscore_fd);
139         highscore_fd = -1;
140         signals_handle_tstp();
141
142         quit(0);
143     }
144
145     current_world_ptr->creating_savefile = new_game;
146
147     if (!current_world_ptr->character_loaded) {
148         new_game = TRUE;
149         current_world_ptr->character_dungeon = FALSE;
150         init_random_seed = TRUE;
151         init_saved_floors(player_ptr, FALSE);
152     } else if (new_game) {
153         init_saved_floors(player_ptr, TRUE);
154     }
155
156     if (!new_game) {
157         process_player_name(player_ptr, FALSE);
158     }
159
160     if (init_random_seed) {
161         Rand_state_init();
162     }
163
164     floor_type* floor_ptr = player_ptr->current_floor_ptr;
165     if (new_game) {
166         current_world_ptr->character_dungeon = FALSE;
167
168         floor_ptr->dun_level = 0;
169         floor_ptr->inside_quest = 0;
170         floor_ptr->inside_arena = FALSE;
171         player_ptr->phase_out = FALSE;
172         write_level = TRUE;
173
174         current_world_ptr->seed_flavor = randint0(0x10000000);
175         current_world_ptr->seed_town = randint0(0x10000000);
176
177         player_birth(player_ptr, process_autopick_file_command);
178         counts_write(player_ptr, 2, 0);
179         player_ptr->count = 0;
180         load = FALSE;
181         determine_bounty_uniques(player_ptr);
182         determine_daily_bounty(player_ptr, FALSE);
183         wipe_o_list(floor_ptr);
184     } else {
185         write_level = FALSE;
186         exe_write_diary(player_ptr, DIARY_GAMESTART, 1,
187             _("                            ----ゲーム再開----",
188                 "                            --- Restarted Game ---"));
189
190         /*
191                  * todo もう2.2.Xなので互換性は打ち切ってもいいのでは?
192                  * 1.0.9 以前はセーブ前に player_ptr->riding = -1 としていたので、再設定が必要だった。
193                  * もう不要だが、以前のセーブファイルとの互換のために残しておく。
194                  */
195         if (player_ptr->riding == -1) {
196             player_ptr->riding = 0;
197             for (MONSTER_IDX i = floor_ptr->m_max; i > 0; i--) {
198                 if (player_bold(player_ptr, floor_ptr->m_list[i].fy, floor_ptr->m_list[i].fx)) {
199                     player_ptr->riding = i;
200                     break;
201                 }
202             }
203         }
204     }
205
206     current_world_ptr->creating_savefile = FALSE;
207
208     player_ptr->teleport_town = FALSE;
209     player_ptr->sutemi = FALSE;
210     current_world_ptr->timewalk_m_idx = 0;
211     player_ptr->now_damaged = FALSE;
212     now_message = 0;
213     current_world_ptr->start_time = time(NULL) - 1;
214     record_o_name[0] = '\0';
215
216     panel_row_min = floor_ptr->height;
217     panel_col_min = floor_ptr->width;
218     if (player_ptr->pseikaku == SEIKAKU_SEXY)
219         s_info[player_ptr->pclass].w_max[TV_HAFTED - TV_WEAPON_BEGIN][SV_WHIP] = WEAPON_EXP_MASTER;
220
221     set_floor_and_wall(player_ptr->dungeon_idx);
222     flavor_init();
223     prt(_("お待ち下さい...", "Please wait..."), 0, 0);
224     Term_fresh();
225
226     if (arg_wizard) {
227         if (enter_wizard_mode(player_ptr)) {
228             current_world_ptr->wizard = TRUE;
229
230             if (player_ptr->is_dead || !player_ptr->y || !player_ptr->x) {
231                 init_saved_floors(player_ptr, TRUE);
232                 floor_ptr->inside_quest = 0;
233                 player_ptr->y = player_ptr->x = 10;
234             }
235         } else if (player_ptr->is_dead) {
236             quit("Already dead.");
237         }
238     }
239
240     if (!floor_ptr->dun_level && !floor_ptr->inside_quest) {
241         process_dungeon_file(player_ptr, "w_info.txt", 0, 0, current_world_ptr->max_wild_y, current_world_ptr->max_wild_x);
242         init_flags = INIT_ONLY_BUILDINGS;
243         process_dungeon_file(player_ptr, "t_info.txt", 0, 0, MAX_HGT, MAX_WID);
244         select_floor_music(player_ptr);
245     }
246
247     if (!current_world_ptr->character_dungeon) {
248         change_floor(player_ptr);
249     } else {
250         if (player_ptr->panic_save) {
251             if (!player_ptr->y || !player_ptr->x) {
252                 msg_print(_("プレイヤーの位置がおかしい。フロアを再生成します。", "What a strange player location, regenerate the dungeon floor."));
253                 change_floor(player_ptr);
254             }
255
256             if (!player_ptr->y || !player_ptr->x)
257                 player_ptr->y = player_ptr->x = 10;
258
259             player_ptr->panic_save = 0;
260         }
261     }
262
263     current_world_ptr->character_generated = TRUE;
264     current_world_ptr->character_icky = FALSE;
265
266     if (new_game) {
267         char buf[80];
268         sprintf(buf, _("%sに降り立った。", "arrived in %s."), map_name(player_ptr));
269         exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, buf);
270     }
271
272     player_ptr->playing = TRUE;
273     reset_visuals(player_ptr, process_autopick_file_command);
274     load_all_pref_files(player_ptr);
275     if (new_game) {
276         player_outfit(player_ptr);
277     }
278
279     Term_xtra(TERM_XTRA_REACT, 0);
280
281     player_ptr->window |= (PW_INVEN | PW_EQUIP | PW_SPELL | PW_PLAYER);
282     player_ptr->window |= (PW_MESSAGE | PW_OVERHEAD | PW_DUNGEON | PW_MONSTER | PW_OBJECT);
283     handle_stuff(player_ptr);
284
285     if (arg_force_original)
286         rogue_like_commands = FALSE;
287     if (arg_force_roguelike)
288         rogue_like_commands = TRUE;
289
290     if (player_ptr->chp < 0)
291         player_ptr->is_dead = TRUE;
292
293     if (player_ptr->prace == RACE_ANDROID)
294         calc_android_exp(player_ptr);
295
296     if (new_game && ((player_ptr->pclass == CLASS_CAVALRY) || (player_ptr->pclass == CLASS_BEASTMASTER))) {
297         monster_type* m_ptr;
298         MONRACE_IDX pet_r_idx = ((player_ptr->pclass == CLASS_CAVALRY) ? MON_HORSE : MON_YASE_HORSE);
299         monster_race* r_ptr = &r_info[pet_r_idx];
300         place_monster_aux(player_ptr, 0, player_ptr->y, player_ptr->x - 1, pet_r_idx,
301             (PM_FORCE_PET | PM_NO_KAGE));
302         m_ptr = &floor_ptr->m_list[hack_m_idx_ii];
303         m_ptr->mspeed = r_ptr->speed;
304         m_ptr->maxhp = r_ptr->hdice * (r_ptr->hside + 1) / 2;
305         m_ptr->max_maxhp = m_ptr->maxhp;
306         m_ptr->hp = r_ptr->hdice * (r_ptr->hside + 1) / 2;
307         m_ptr->dealt_damage = 0;
308         m_ptr->energy_need = ENERGY_NEED() + ENERGY_NEED();
309     }
310
311     (void)combine_and_reorder_home(STORE_HOME);
312     (void)combine_and_reorder_home(STORE_MUSEUM);
313     select_floor_music(player_ptr);
314
315     while (TRUE) {
316         process_dungeon(player_ptr, load_game);
317         current_world_ptr->character_xtra = TRUE;
318         handle_stuff(player_ptr);
319
320         current_world_ptr->character_xtra = FALSE;
321         target_who = 0;
322         health_track(player_ptr, 0);
323         forget_lite(floor_ptr);
324         forget_view(floor_ptr);
325         clear_mon_lite(floor_ptr);
326         if (!player_ptr->playing && !player_ptr->is_dead)
327             break;
328
329         wipe_o_list(floor_ptr);
330         if (!player_ptr->is_dead)
331             wipe_monsters_list(player_ptr);
332
333         msg_print(NULL);
334         load_game = FALSE;
335         if (player_ptr->playing && player_ptr->is_dead) {
336             if (floor_ptr->inside_arena) {
337                 floor_ptr->inside_arena = FALSE;
338                 if (player_ptr->arena_number > MAX_ARENA_MONS)
339                     player_ptr->arena_number++;
340                 else
341                     player_ptr->arena_number = -1 - player_ptr->arena_number;
342                 player_ptr->is_dead = FALSE;
343                 player_ptr->chp = 0;
344                 player_ptr->chp_frac = 0;
345                 player_ptr->exit_bldg = TRUE;
346                 reset_tim_flags(player_ptr);
347                 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_RAND_CONNECT);
348                 leave_floor(player_ptr);
349             } else {
350                 if ((current_world_ptr->wizard || cheat_live) && !get_check(_("死にますか? ", "Die? "))) {
351                     cheat_death(player_ptr);
352                 }
353             }
354         }
355
356         if (player_ptr->is_dead)
357             break;
358
359         change_floor(player_ptr);
360     }
361
362     close_game(player_ptr);
363     quit(NULL);
364 }