OSDN Git Service

[Refactor] #3281 fd_open() の引数をstring_view からpath に差し替えた
[hengbandforosx/hengbandosx.git] / src / core / game-closer.cpp
1 /*
2  * @file game-closer.cpp
3  * @brief ゲーム終了処理
4  * @author Hourier
5  * @date 2020/03/09
6  */
7
8 #include "core/game-closer.h"
9 #include "cmd-io/cmd-save.h"
10 #include "core/asking-player.h"
11 #include "core/score-util.h"
12 #include "core/scores.h"
13 #include "core/stuff-handler.h"
14 #include "floor/floor-save.h"
15 #include "game-option/cheat-options.h"
16 #include "io/files-util.h"
17 #include "io/input-key-acceptor.h"
18 #include "io/signal-handlers.h"
19 #include "io/uid-checker.h"
20 #include "io/write-diary.h"
21 #include "main/music-definitions-table.h"
22 #include "main/sound-of-music.h"
23 #include "player/player-sex.h"
24 #include "player/process-death.h"
25 #include "save/save.h"
26 #include "system/floor-type-definition.h"
27 #include "system/player-type-definition.h"
28 #include "term/gameterm.h"
29 #include "term/screen-processor.h"
30 #include "util/angband-files.h"
31 #include "util/int-char-converter.h"
32 #include "view/display-messages.h"
33 #include "view/display-player.h"
34 #include "view/display-scores.h"
35 #include "world/world.h"
36
37 static void clear_floor(PlayerType *player_ptr)
38 {
39     (void)fd_close(highscore_fd);
40     highscore_fd = -1;
41     clear_saved_floor_files(player_ptr);
42     signals_handle_tstp();
43 }
44
45 static void send_world_score_on_closing(PlayerType *player_ptr, bool do_send)
46 {
47     if (send_world_score(player_ptr, do_send)) {
48         return;
49     }
50
51     if (!get_check_strict(
52             player_ptr, _("後でスコアを登録するために待機しますか?", "Stand by for later score registration? "), (CHECK_NO_ESCAPE | CHECK_NO_HISTORY))) {
53         return;
54     }
55
56     player_ptr->wait_report_score = true;
57     player_ptr->is_dead = false;
58     if (!save_player(player_ptr, SaveType::CLOSE_GAME)) {
59         msg_print(_("セーブ失敗!", "death save failed!"));
60     }
61 }
62
63 /*!
64  * @brief ゲームクローズ時、プレイヤーが死亡しているかのチェックを行い死亡していないならば、確認キー入力とスコア表示、現フロアの初期化を行う。
65  * @param player_ptr プレイヤー構造体参照ポインタ。
66  * @return 死亡していればTRUE, まだ生きているならば各処理を済ませた上ででFALSE。
67  */
68 static bool check_death(PlayerType *player_ptr)
69 {
70     if (player_ptr->is_dead) {
71         return true;
72     }
73
74     do_cmd_save_game(player_ptr, false);
75     prt(_("リターンキーか ESC キーを押して下さい。", "Press Return (or Escape)."), 0, 40);
76     play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_EXIT);
77     if (inkey() != ESCAPE) {
78         predict_score(player_ptr);
79     }
80
81     clear_floor(player_ptr);
82     return false;
83 }
84
85 /*!
86  * @brief 勝利者用の引退演出処理 /
87  * Change the player into a King! -RAK-
88  */
89 static void kingly(PlayerType *player_ptr)
90 {
91     bool seppuku = streq(player_ptr->died_from, "Seppuku");
92     player_ptr->current_floor_ptr->dun_level = 0;
93     if (!seppuku) {
94         /* 引退したときの識別文字 */
95         player_ptr->died_from = _("ripe", "Ripe Old Age");
96     }
97
98     player_ptr->exp = player_ptr->max_exp;
99     player_ptr->lev = player_ptr->max_plv;
100     player_ptr->au += 10000000L;
101     term_clear();
102
103     put_str("#", 1, 39);
104     put_str("#####", 2, 37);
105     put_str("#", 3, 39);
106     put_str(",,,  $$$  ,,,", 4, 33);
107     put_str(",,=$   \"$$$$$\"   $=,,", 5, 29);
108     put_str(",$$        $$$        $$,", 6, 27);
109     put_str("*>         <*>         <*", 7, 27);
110     put_str("$$         $$$         $$", 8, 27);
111     put_str("\"$$        $$$        $$\"", 9, 27);
112     put_str("\"$$       $$$       $$\"", 10, 28);
113     put_str("*#########*#########*", 11, 29);
114     put_str("*#########*#########*", 12, 29);
115
116 #ifdef JP
117     put_str("Veni, Vidi, Vici!", 15, 31);
118     put_str("来た、見た、勝った!", 16, 30);
119     put_str(format("偉大なる%s万歳!", sp_ptr->winner), 17, 29);
120 #else
121     put_str("Veni, Vidi, Vici!", 15, 31);
122     put_str("I came, I saw, I conquered!", 16, 26);
123     put_str(format("All Hail the Mighty %s!", sp_ptr->winner), 17, 27);
124 #endif
125
126     if (!seppuku) {
127         exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, _("ダンジョンの探索から引退した。", "retired exploring dungeons."));
128         exe_write_diary(player_ptr, DIARY_GAMESTART, 1, _("-------- ゲームオーバー --------", "--------   Game  Over   --------"));
129         exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, "\n\n\n\n");
130     }
131
132     flush();
133     pause_line(MAIN_TERM_MIN_ROWS - 1);
134 }
135
136 /*!
137  * @brief ゲーム終了処理 /
138  * Close up the current game (player may or may not be dead)
139  * @param player_ptr プレイヤーへの参照ポインタ
140  * @details
141  * <pre>
142  * This function is called only from "main.c" and "signals.c".
143  * </pre>
144  */
145 void close_game(PlayerType *player_ptr)
146 {
147     handle_stuff(player_ptr);
148     msg_print(nullptr);
149     flush();
150     signals_ignore_tstp();
151
152     w_ptr->character_icky_depth = 1;
153     const auto &path = path_build(ANGBAND_DIR_APEX, "scores.raw");
154     safe_setuid_grab(player_ptr);
155     highscore_fd = fd_open(path, O_RDWR);
156     safe_setuid_drop();
157
158     if (!check_death(player_ptr)) {
159         return;
160     }
161
162     TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
163     if (w_ptr->total_winner) {
164         kingly(player_ptr);
165     }
166
167     auto do_send = true;
168     if (!cheat_save || get_check(_("死んだデータをセーブしますか? ", "Save death? "))) {
169         update_playtime();
170         w_ptr->sf_play_time += w_ptr->play_time;
171
172         if (!save_player(player_ptr, SaveType::CLOSE_GAME)) {
173             msg_print(_("セーブ失敗!", "death save failed!"));
174         }
175     } else {
176         do_send = false;
177     }
178
179     print_tomb(player_ptr);
180     flush();
181     show_death_info(player_ptr);
182     term_clear();
183     if (check_score(player_ptr)) {
184         send_world_score_on_closing(player_ptr, do_send);
185         if (!player_ptr->wait_report_score) {
186             (void)top_twenty(player_ptr);
187         }
188     } else if (highscore_fd >= 0) {
189         display_scores(0, 10, -1, nullptr);
190     }
191
192     clear_floor(player_ptr);
193 }