OSDN Git Service

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