OSDN Git Service

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