OSDN Git Service

fbc2e69ac7e5e1662a7f5627040a4c641fe8511b
[hengband/hengband.git] / src / player / 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 "market/store-util.h"
15 #include "store.h"
16 #include "term.h"
17
18 #define GRAVE_LINE_WIDTH 31
19
20 /*!
21  * @brief 墓石の真ん中に文字列を書き込む /
22  * Centers a string within a GRAVE_LINE_WIDTH character string          -JWT-
23  * @return なし
24  * @details
25  */
26 static void center_string(char *buf, concptr str)
27 {
28         int i = strlen(str);
29         int j = GRAVE_LINE_WIDTH / 2 - i / 2;
30         (void)sprintf(buf, "%*s%s%*s", j, "", str, GRAVE_LINE_WIDTH - i - j, "");
31 }
32
33
34 /*!
35  * @brief 墓に基本情報を表示
36  * @param dead_ptr プレーヤーへの参照ポインタ
37  * @param buf 墓テンプレ
38  * @return なし
39  */
40 static void show_basic_params(player_type *dead_ptr, char *buf)
41 {
42         char tomb_message[160];
43         (void)sprintf(tomb_message, _("レベル: %d", "Level: %d"), (int)dead_ptr->lev);
44         center_string(buf, tomb_message);
45         put_str(buf, 11, 11);
46
47         (void)sprintf(tomb_message, _("経験値: %ld", "Exp: %ld"), (long)dead_ptr->exp);
48         center_string(buf, tomb_message);
49         put_str(buf, 12, 11);
50
51         (void)sprintf(tomb_message, _("所持金: %ld", "AU: %ld"), (long)dead_ptr->au);
52         center_string(buf, tomb_message);
53         put_str(buf, 13, 11);
54 }
55
56
57 #ifdef JP
58 /*!
59  * @brief プレーヤーを殺したモンスターを表示する (日本語版専用)
60  * @param dead_ptr プレーヤーへの参照ポインタ
61  * @param buf 墓テンプレ
62  * @param tomb_message 墓碑に刻む言葉
63  * @return 追加の行数
64  */
65 static int show_killing_monster(player_type *dead_ptr, char *buf, char *tomb_message, size_t tomb_message_size)
66 {
67         roff_to_buf(dead_ptr->died_from, GRAVE_LINE_WIDTH + 1, tomb_message, tomb_message_size);
68         char *t;
69         t = tomb_message + strlen(tomb_message) + 1;
70         if (!*t) return 0;
71
72         char dummy[80];
73         strcpy(dummy, t); /* 2nd line */
74         if (*(t + strlen(t) + 1)) /* Does 3rd line exist? */
75         {
76                 for (t = dummy + strlen(dummy) - 2; iskanji(*(t - 1)); t--) /* Loop */;
77                 strcpy(t, "…");
78         }
79         else if (my_strstr(tomb_message, "『") && suffix(dummy, "』"))
80         {
81                 char dummy2[80];
82                 char *name_head = my_strstr(tomb_message, "『");
83                 sprintf(dummy2, "%s%s", name_head, dummy);
84                 if (strlen(dummy2) <= GRAVE_LINE_WIDTH)
85                 {
86                         strcpy(dummy, dummy2);
87                         *name_head = '\0';
88                 }
89         }
90         else if (my_strstr(tomb_message, "「") && suffix(dummy, "」"))
91         {
92                 char dummy2[80];
93                 char *name_head = my_strstr(tomb_message, "「");
94                 sprintf(dummy2, "%s%s", name_head, dummy);
95                 if (strlen(dummy2) <= GRAVE_LINE_WIDTH)
96                 {
97                         strcpy(dummy, dummy2);
98                         *name_head = '\0';
99                 }
100         }
101
102         center_string(buf, dummy);
103         put_str(buf, 15, 11);
104         return 1;
105 }
106
107
108 /*!
109  * @brief どこで死んだかを表示する (日本語版専用)
110  * @param dead_ptr プレーヤーへの参照ポインタ
111  * @param buf 墓テンプレ
112  * @param tomb_message 表示する文字列
113  * @param extra_line 追加の行数
114  * @return なし
115  */
116 static void show_dead_place(player_type *dead_ptr, char *buf, char *tomb_message, int extra_line)
117 {
118         if (streq(dead_ptr->died_from, "ripe") || streq(dead_ptr->died_from, "Seppuku"))
119                 return;
120
121         if (dead_ptr->current_floor_ptr->dun_level == 0)
122         {
123                 concptr field_name = dead_ptr->town_num ? "街" : "荒野";
124                 if (streq(dead_ptr->died_from, "途中終了"))
125                 {
126                         sprintf(tomb_message, "%sで死んだ", field_name);
127                 }
128                 else
129                 {
130                         sprintf(tomb_message, "に%sで殺された", field_name);
131                 }
132         }
133         else
134         {
135                 if (streq(dead_ptr->died_from, "途中終了"))
136                 {
137                         sprintf(tomb_message, "地下 %d 階で死んだ", (int)dead_ptr->current_floor_ptr->dun_level);
138                 }
139                 else
140                 {
141                         sprintf(tomb_message, "に地下 %d 階で殺された", (int)dead_ptr->current_floor_ptr->dun_level);
142                 }
143         }
144
145         center_string(buf, tomb_message);
146         put_str(buf, 15 + extra_line, 11);
147 }
148
149
150 /*!
151  * @brief 墓に刻む言葉を細かく表示 (日本語版専用)
152  * @param dead_ptr プレーヤーへの参照ポインタ
153  * @param buf 墓テンプレ
154  * @return なし
155  */
156 static void show_tomb_detail(player_type *dead_ptr, char *buf)
157 {
158         char tomb_message[160];
159         int extra_line = 0;
160         if (streq(dead_ptr->died_from, "途中終了"))
161         {
162                 strcpy(tomb_message, "<自殺>");
163         }
164         else if (streq(dead_ptr->died_from, "ripe"))
165         {
166                 strcpy(tomb_message, "引退後に天寿を全う");
167         }
168         else if (streq(dead_ptr->died_from, "Seppuku"))
169         {
170                 strcpy(tomb_message, "勝利の後、切腹");
171         }
172         else
173         {
174                 extra_line = show_killing_monster(dead_ptr, buf, tomb_message, sizeof(tomb_message));
175         }
176
177         center_string(buf, tomb_message);
178         put_str(buf, 14, 11);
179
180         show_dead_place(dead_ptr, buf, tomb_message, extra_line);
181 }
182 #else
183
184
185 /*!
186  * @brief Detailed display of words engraved on the tomb (English version only)
187  * @param dead_ptr reference pointer to the player
188  * @param buf template of the tomb
189  * @return nothing
190  */
191 static void show_tomb_detail(player_type *dead_ptr, char *buf)
192 {
193         char tomb_message[160];
194         (void)sprintf(tomb_message, "Killed on Level %d", dead_ptr->current_floor_ptr->dun_level);
195         center_string(buf, tomb_message);
196         put_str(buf, 14, 11);
197
198         roff_to_buf(format("by %s.", dead_ptr->died_from), GRAVE_LINE_WIDTH + 1, tomb_message, sizeof(tomb_message));
199         center_string(buf, tomb_message);
200         char *t;
201         put_str(buf, 15, 11);
202         t = tomb_message + strlen(tomb_message) + 1;
203         if (!*t) return;
204
205         char dummy[80];
206         strcpy(dummy, t); /* 2nd line */
207         if (*(t + strlen(t) + 1)) /* Does 3rd line exist? */
208         {
209                 int dummy_len = strlen(dummy);
210                 strcpy(dummy + MIN(dummy_len, GRAVE_LINE_WIDTH - 3), "...");
211         }
212
213         center_string(buf, dummy);
214         put_str(buf, 16, 11);
215 }
216 #endif
217
218
219 /*!
220  * @brief 墓石のアスキーアート表示 /
221  * Display a "tomb-stone"
222  * @param creature_ptr プレーヤーへの参照ポインタ
223  * @return なし
224  */
225 void print_tomb(player_type *dead_ptr)
226 {
227         Term_clear();
228         char buf[1024];
229         read_dead_file(buf, sizeof(buf));
230         concptr p = (current_world_ptr->total_winner || (dead_ptr->lev > PY_MAX_LEVEL))
231                 ? _("偉大なる者", "Magnificant")
232                 : player_title[dead_ptr->pclass][(dead_ptr->lev - 1) / 5];
233
234         center_string(buf, dead_ptr->name);
235         put_str(buf, 6, 11);
236
237 #ifdef JP
238 #else
239         center_string(buf, "the");
240         put_str(buf, 7, 11);
241 #endif
242
243         center_string(buf, p);
244         put_str(buf, 8, 11);
245
246         center_string(buf, cp_ptr->title);
247         put_str(buf, 10, 11);
248
249         show_basic_params(dead_ptr, buf);
250         show_tomb_detail(dead_ptr, buf);
251
252         char current_time[80];
253         time_t ct = time((time_t*)0);
254         (void)sprintf(current_time, "%-.24s", ctime(&ct));
255         center_string(buf, current_time);
256         put_str(buf, 17, 11);
257         msg_format(_("さようなら、%s!", "Goodbye, %s!"), dead_ptr->name);
258 }
259
260
261 /*!
262  * @brief 死亡/引退/切腹時にインベントリ内のアイテムを*鑑定*する
263  * @param creature_ptr プレーヤーへの参照ポインタ
264  * @return なし
265  */
266 static void inventory_aware(player_type *creature_ptr)
267 {
268         object_type *o_ptr;
269         for (int i = 0; i < INVEN_TOTAL; i++)
270         {
271                 o_ptr = &creature_ptr->inventory_list[i];
272                 if (!o_ptr->k_idx) continue;
273
274                 object_aware(creature_ptr, o_ptr);
275                 object_known(o_ptr);
276         }
277 }
278
279
280 /*!
281  * @brief 死亡/引退/切腹時に我が家のアイテムを*鑑定*する
282  * @param creature_ptr プレーヤーへの参照ポインタ
283  * @return なし
284  */
285 static void home_aware(player_type *creature_ptr)
286 {
287         object_type *o_ptr;
288         store_type *st_ptr;
289         for (int i = 1; i < max_towns; i++)
290         {
291                 st_ptr = &town_info[i].store[STORE_HOME];
292                 for (int j = 0; j < st_ptr->stock_num; j++)
293                 {
294                         o_ptr = &st_ptr->stock[j];
295                         if (!o_ptr->k_idx) continue;
296
297                         object_aware(creature_ptr, o_ptr);
298                         object_known(o_ptr);
299                 }
300         }
301 }
302
303
304 /*!
305  * @brief プレーヤーの持ち物を表示する
306  * @param creature_ptr プレーヤーへの参照ポインタ
307  * @return Escキーでゲームを終了する時TRUE
308  */
309 static bool show_dead_player_items(player_type *creature_ptr)
310 {
311         if (creature_ptr->equip_cnt)
312         {
313                 Term_clear();
314                 (void)show_equipment(creature_ptr, 0, USE_FULL, 0);
315                 prt(_("装備していたアイテム: -続く-", "You are using: -more-"), 0, 0);
316                 if (inkey() == ESCAPE) return TRUE;
317         }
318
319         if (creature_ptr->inven_cnt)
320         {
321                 Term_clear();
322                 (void)show_inventory(creature_ptr, 0, USE_FULL, 0);
323                 prt(_("持っていたアイテム: -続く-", "You are carrying: -more-"), 0, 0);
324
325                 if (inkey() == ESCAPE) return TRUE;
326         }
327
328         return FALSE;
329 }
330
331
332 /*!
333  * @brief 我が家にあったアイテムを表示する
334  * @param creature_ptr プレーヤーへの参照ポインタ
335  * @return なし
336  */
337 static void show_dead_home_items(player_type *creature_ptr)
338 {
339         for (int l = 1; l < max_towns; l++)
340         {
341                 store_type *st_ptr;
342                 st_ptr = &town_info[l].store[STORE_HOME];
343                 if (st_ptr->stock_num == 0) continue;
344
345                 for (int i = 0, k = 0; i < st_ptr->stock_num; k++)
346                 {
347                         Term_clear();
348                         for (int j = 0; (j < 12) && (i < st_ptr->stock_num); j++, i++)
349                         {
350                                 GAME_TEXT o_name[MAX_NLEN];
351                                 char tmp_val[80];
352                                 object_type *o_ptr;
353                                 o_ptr = &st_ptr->stock[i];
354                                 sprintf(tmp_val, "%c) ", I2A(j));
355                                 prt(tmp_val, j + 2, 4);
356                                 object_desc(creature_ptr, o_name, o_ptr, 0);
357                                 c_put_str(tval_to_attr[o_ptr->tval], o_name, j + 2, 7);
358                         }
359
360                         prt(format(_("我が家に置いてあったアイテム ( %d ページ): -続く-", "Your home contains (page %d): -more-"), k + 1), 0, 0);
361                         if (inkey() == ESCAPE) return;
362                 }
363         }
364 }
365
366
367 /*!
368  * @brief キャラクタ情報をファイルに書き出す
369  * @param creature_ptr プレーヤーへの参照ポインタ
370  * @param file_character ステータスダンプへのコールバック
371  * @return なし
372  */
373 static void export_player_info(player_type *creature_ptr, update_playtime_pf update_playtime, display_player_pf display_player, map_name_pf map_name)
374 {
375         prt(_("キャラクターの記録をファイルに書き出すことができます。", "You may now dump a character record to one or more files."), 21, 0);
376         prt(_("リターンキーでキャラクターを見ます。ESCで中断します。", "Then, hit RETURN to see the character, or ESC to abort."), 22, 0);
377         while (TRUE)
378         {
379                 char out_val[160];
380                 put_str(_("ファイルネーム: ", "Filename: "), 23, 0);
381                 strcpy(out_val, "");
382                 if (!askfor(out_val, 60)) return;
383                 if (!out_val[0]) break;
384
385                 screen_save();
386                 (void)file_character(creature_ptr, out_val, update_playtime, display_player, map_name);
387                 screen_load();
388         }
389 }
390
391
392 /*!
393  * @brief 死亡、引退時の簡易ステータス表示
394  * @param creature_ptr プレーヤーへの参照ポインタ
395  * @param handle_stuff 更新処理チェックへのコールバック
396  * @param file_character ステータスダンプへのコールバック
397  * @param update_playtime プレイ時間更新処理へのコールバック
398  * @param display_player ステータス表示へのコールバック
399  * @return なし
400  */
401 void show_info(player_type *creature_ptr, void(*handle_stuff)(player_type*), update_playtime_pf update_playtime, display_player_pf display_player, map_name_pf map_name)
402 {
403         inventory_aware(creature_ptr);
404         home_aware(creature_ptr);
405
406         creature_ptr->update |= (PU_BONUS);
407         (*handle_stuff)(creature_ptr);
408         flush();
409         msg_erase();
410         
411         export_player_info(creature_ptr, update_playtime, display_player, map_name);
412         (*update_playtime)();
413         (*display_player)(creature_ptr, 0, map_name);
414         prt(_("何かキーを押すとさらに情報が続きます (ESCで中断): ", "Hit any key to see more information (ESC to abort): "), 23, 0);
415         if (inkey() == ESCAPE) return;
416         if (show_dead_player_items(creature_ptr)) return;
417
418         show_dead_home_items(creature_ptr);
419 }