OSDN Git Service

[Fix] #39962 read_dead_file() にsize_t 引数を追加 / Added size_t argument to read_dead_file()
[hengband/hengband.git] / src / view / process-death.c
1 /*!
2  * @brief 死亡・引退・切腹時の画面表示
3  * @date 2020/02/24
4  * @author Hourier
5  * @details
6  * core、files、view-mainwindowの参照禁止。コールバックで対応すること
7  */
8
9 #include "process-death.h"
10 #include "world.h"
11 #include "floor-town.h"
12 #include "player-inventory.h"
13 #include "object-flavor.h"
14 #include "store.h"
15 #include "term.h"
16
17 #define GRAVE_LINE_WIDTH 31
18
19 /*!
20  * @brief 墓石の真ん中に文字列を書き込む /
21  * Centers a string within a GRAVE_LINE_WIDTH character string          -JWT-
22  * @return なし
23  * @details
24  */
25 static void center_string(char *buf, concptr str)
26 {
27         int i = strlen(str);
28         int j = GRAVE_LINE_WIDTH / 2 - i / 2;
29         (void)sprintf(buf, "%*s%s%*s", j, "", str, GRAVE_LINE_WIDTH - i - j, "");
30 }
31
32
33 /*!
34  * @brief プレーヤーを殺したモンスターを表示する
35  * @param dead_ptr プレーヤーへの参照ポインタ
36  * @param buf 墓テンプレへのバッファ
37  * @return 追加の行数
38  */
39 static int show_killing_monster(player_type *dead_ptr, char *buf, char *tmp)
40 {
41         roff_to_buf(dead_ptr->died_from, GRAVE_LINE_WIDTH + 1, tmp, sizeof(tmp));
42         char *t;
43         t = tmp + strlen(tmp) + 1;
44         if (!*t) return 0;
45
46         char dummy[80];
47         strcpy(dummy, t); /* 2nd line */
48         if (*(t + strlen(t) + 1)) /* Does 3rd line exist? */
49         {
50                 for (t = dummy + strlen(dummy) - 2; iskanji(*(t - 1)); t--) /* Loop */;
51                 strcpy(t, "…");
52         }
53         else if (my_strstr(tmp, "『") && suffix(dummy, "』"))
54         {
55                 char dummy2[80];
56                 char *name_head = my_strstr(tmp, "『");
57                 sprintf(dummy2, "%s%s", name_head, dummy);
58                 if (strlen(dummy2) <= GRAVE_LINE_WIDTH)
59                 {
60                         strcpy(dummy, dummy2);
61                         *name_head = '\0';
62                 }
63         }
64         else if (my_strstr(tmp, "「") && suffix(dummy, "」"))
65         {
66                 char dummy2[80];
67                 char *name_head = my_strstr(tmp, "「");
68                 sprintf(dummy2, "%s%s", name_head, dummy);
69                 if (strlen(dummy2) <= GRAVE_LINE_WIDTH)
70                 {
71                         strcpy(dummy, dummy2);
72                         *name_head = '\0';
73                 }
74         }
75
76         center_string(buf, dummy);
77         put_str(buf, 15, 11);
78         return 1;
79 }
80
81
82 /*!
83  * @brief 墓石のアスキーアート表示 /
84  * Display a "tomb-stone"
85  * @param creature_ptr プレーヤーへの参照ポインタ
86  * @return なし
87  */
88 void print_tomb(player_type *dead_ptr, void(*read_dead_file)(char*, size_t))
89 {
90         Term_clear();
91         char buf[1024];
92         (*read_dead_file)(buf, sizeof(buf));
93         concptr p = (current_world_ptr->total_winner || (dead_ptr->lev > PY_MAX_LEVEL))
94                 ? _("偉大なる者", "Magnificant")
95                 : player_title[dead_ptr->pclass][(dead_ptr->lev - 1) / 5];
96
97         center_string(buf, dead_ptr->name);
98         put_str(buf, 6, 11);
99
100 #ifdef JP
101 #else
102         center_string(buf, "the");
103         put_str(buf, 7, 11);
104 #endif
105
106         center_string(buf, p);
107         put_str(buf, 8, 11);
108
109         center_string(buf, cp_ptr->title);
110         put_str(buf, 10, 11);
111
112         char tmp[160];
113         (void)sprintf(tmp, _("レベル: %d", "Level: %d"), (int)dead_ptr->lev);
114         center_string(buf, tmp);
115         put_str(buf, 11, 11);
116
117         (void)sprintf(tmp, _("経験値: %ld", "Exp: %ld"), (long)dead_ptr->exp);
118         center_string(buf, tmp);
119         put_str(buf, 12, 11);
120
121         (void)sprintf(tmp, _("所持金: %ld", "AU: %ld"), (long)dead_ptr->au);
122         center_string(buf, tmp);
123         put_str(buf, 13, 11);
124
125 #ifdef JP
126         /* 墓に刻む言葉をオリジナルより細かく表示 */
127         int extra_line = 0;
128         if (streq(dead_ptr->died_from, "途中終了"))
129         {
130                 strcpy(tmp, "<自殺>");
131         }
132         else if (streq(dead_ptr->died_from, "ripe"))
133         {
134                 strcpy(tmp, "引退後に天寿を全う");
135         }
136         else if (streq(dead_ptr->died_from, "Seppuku"))
137         {
138                 strcpy(tmp, "勝利の後、切腹");
139         }
140         else
141         {
142                 extra_line = show_killing_monster(dead_ptr, buf, tmp);
143         }
144
145         center_string(buf, tmp);
146         put_str(buf, 14, 11);
147
148         if (!streq(dead_ptr->died_from, "ripe") && !streq(dead_ptr->died_from, "Seppuku"))
149         {
150                 if (dead_ptr->current_floor_ptr->dun_level == 0)
151                 {
152                         concptr field_name = dead_ptr->town_num ? "街" : "荒野";
153                         if (streq(dead_ptr->died_from, "途中終了"))
154                         {
155                                 sprintf(tmp, "%sで死んだ", field_name);
156                         }
157                         else
158                         {
159                                 sprintf(tmp, "に%sで殺された", field_name);
160                         }
161                 }
162                 else
163                 {
164                         if (streq(dead_ptr->died_from, "途中終了"))
165                         {
166                                 sprintf(tmp, "地下 %d 階で死んだ", (int)dead_ptr->current_floor_ptr->dun_level);
167                         }
168                         else
169                         {
170                                 sprintf(tmp, "に地下 %d 階で殺された", (int)dead_ptr->current_floor_ptr->dun_level);
171                         }
172                 }
173
174                 center_string(buf, tmp);
175                 put_str(buf, 15 + extra_line, 11);
176         }
177 #else
178         (void)sprintf(tmp, "Killed on Level %d", dead_ptr->current_floor_ptr->dun_level);
179         center_string(buf, tmp);
180         put_str(buf, 14, 11);
181
182         roff_to_buf(format("by %s.", dead_ptr->died_from), GRAVE_LINE_WIDTH + 1, tmp, sizeof tmp);
183         center_string(buf, tmp);
184         char *t;
185         put_str(buf, 15, 11);
186         t = tmp + strlen(tmp) + 1;
187         if (*t)
188         {
189                 char dummy[80];
190                 strcpy(dummy, t); /* 2nd line */
191                 if (*(t + strlen(t) + 1)) /* Does 3rd line exist? */
192                 {
193                         int dummy_len = strlen(dummy);
194                         strcpy(dummy + MIN(dummy_len, GRAVE_LINE_WIDTH - 3), "...");
195                 }
196                 center_string(buf, dummy);
197                 put_str(buf, 16, 11);
198         }
199 #endif
200         time_t ct = time((time_t*)0);
201         (void)sprintf(tmp, "%-.24s", ctime(&ct));
202         center_string(buf, tmp);
203         put_str(buf, 17, 11);
204         msg_format(_("さようなら、%s!", "Goodbye, %s!"), dead_ptr->name);
205 }
206
207
208 /*!
209  * todo handle_stuff、display_playerの引数は暫定。どのように設計し直すか少し考える
210  * @brief 死亡、引退時の簡易ステータス表示
211  * @param creature_ptr プレーヤーへの参照ポインタ
212  * @param handle_stuff 更新処理チェックへのコールバック
213  * @param file_character ステータスダンプへのコールバック
214  * @param update_playtime プレイ時間更新処理へのコールバック
215  * @param display_player ステータス表示へのコールバック
216  * @return なし
217  */
218 void show_info(player_type *creature_ptr, void(*handle_stuff)(player_type*), errr(*file_character)(player_type*, concptr), void(*update_playtime)(void), void(*display_player)(player_type*, int))
219 {
220         object_type *o_ptr;
221         for (int i = 0; i < INVEN_TOTAL; i++)
222         {
223                 o_ptr = &creature_ptr->inventory_list[i];
224                 if (!o_ptr->k_idx) continue;
225
226                 object_aware(creature_ptr, o_ptr);
227                 object_known(o_ptr);
228         }
229
230         store_type *st_ptr;
231         for (int i = 1; i < max_towns; i++)
232         {
233                 st_ptr = &town_info[i].store[STORE_HOME];
234                 for (int j = 0; j < st_ptr->stock_num; j++)
235                 {
236                         o_ptr = &st_ptr->stock[j];
237                         if (!o_ptr->k_idx) continue;
238
239                         object_aware(creature_ptr, o_ptr);
240                         object_known(o_ptr);
241                 }
242         }
243
244         creature_ptr->update |= (PU_BONUS);
245         handle_stuff(creature_ptr);
246         flush();
247         msg_erase();
248         prt(_("キャラクターの記録をファイルに書き出すことができます。", "You may now dump a character record to one or more files."), 21, 0);
249         prt(_("リターンキーでキャラクターを見ます。ESCで中断します。", "Then, hit RETURN to see the character, or ESC to abort."), 22, 0);
250         while (TRUE)
251         {
252                 char out_val[160];
253                 put_str(_("ファイルネーム: ", "Filename: "), 23, 0);
254                 strcpy(out_val, "");
255                 if (!askfor(out_val, 60)) return;
256                 if (!out_val[0]) break;
257                 screen_save();
258                 (void)file_character(creature_ptr, out_val);
259                 screen_load();
260         }
261
262         update_playtime();
263         display_player(creature_ptr, 0);
264         prt(_("何かキーを押すとさらに情報が続きます (ESCで中断): ", "Hit any key to see more information (ESC to abort): "), 23, 0);
265         if (inkey() == ESCAPE) return;
266
267         if (creature_ptr->equip_cnt)
268         {
269                 Term_clear();
270                 (void)show_equipment(creature_ptr, 0, USE_FULL, 0);
271                 prt(_("装備していたアイテム: -続く-", "You are using: -more-"), 0, 0);
272                 if (inkey() == ESCAPE) return;
273         }
274
275         if (creature_ptr->inven_cnt)
276         {
277                 Term_clear();
278                 (void)show_inventory(creature_ptr, 0, USE_FULL, 0);
279                 prt(_("持っていたアイテム: -続く-", "You are carrying: -more-"), 0, 0);
280
281                 if (inkey() == ESCAPE) return;
282         }
283
284         for (int l = 1; l < max_towns; l++)
285         {
286                 st_ptr = &town_info[l].store[STORE_HOME];
287                 if (st_ptr->stock_num == 0) continue;
288                 for (int i = 0, k = 0; i < st_ptr->stock_num; k++)
289                 {
290                         Term_clear();
291                         for (int j = 0; (j < 12) && (i < st_ptr->stock_num); j++, i++)
292                         {
293                                 GAME_TEXT o_name[MAX_NLEN];
294                                 char tmp_val[80];
295                                 o_ptr = &st_ptr->stock[i];
296                                 sprintf(tmp_val, "%c) ", I2A(j));
297                                 prt(tmp_val, j + 2, 4);
298                                 object_desc(creature_ptr, o_name, o_ptr, 0);
299                                 c_put_str(tval_to_attr[o_ptr->tval], o_name, j + 2, 7);
300                         }
301
302                         prt(format(_("我が家に置いてあったアイテム ( %d ページ): -続く-", "Your home contains (page %d): -more-"), k + 1), 0, 0);
303                         if (inkey() == ESCAPE) return;
304                 }
305         }
306 }