2 * @brief 死亡・引退・切腹時の画面表示
6 * core、files、view-mainwindowの参照禁止。コールバックで対応すること
9 #include "process-death.h"
10 #include "core/asking-player.h"
11 #include "core/player-update-types.h"
12 #include "core/stuff-handler.h"
13 #include "flavor/flavor-describer.h"
14 #include "floor/floor-town.h"
15 #include "game-option/game-play-options.h"
16 #include "inventory/inventory-slot-types.h"
17 #include "io/input-key-acceptor.h"
18 #include "object/item-tester-hooker.h"
19 #include "object/item-use-flags.h"
20 #include "perception/object-perception.h"
21 #include "player/player-class.h"
22 #include "store/store-util.h"
23 #include "store/store.h"
24 #include "system/floor-type-definition.h"
25 #include "system/object-type-definition.h"
26 #include "system/player-type-definition.h"
27 #include "term/gameterm.h"
28 #include "term/screen-processor.h"
29 #include "util/buffer-shaper.h"
30 #include "util/int-char-converter.h"
31 #include "util/string-processor.h"
32 #include "view/display-inventory.h"
33 #include "view/display-messages.h"
34 #include "world/world.h"
36 #define GRAVE_LINE_WIDTH 31
39 * @brief 墓石の真ん中に文字列を書き込む /
40 * Centers a string within a GRAVE_LINE_WIDTH character string -JWT-
43 static void center_string(char *buf, concptr str)
46 int j = GRAVE_LINE_WIDTH / 2 - i / 2;
47 (void)sprintf(buf, "%*s%s%*s", j, "", str, GRAVE_LINE_WIDTH - i - j, "");
52 * @param dead_ptr プレーヤーへの参照ポインタ
55 static void show_basic_params(player_type *dead_ptr, char *buf)
57 char tomb_message[160];
58 (void)sprintf(tomb_message, _("レベル: %d", "Level: %d"), (int)dead_ptr->lev);
59 center_string(buf, tomb_message);
62 (void)sprintf(tomb_message, _("経験値: %ld", "Exp: %ld"), (long)dead_ptr->exp);
63 center_string(buf, tomb_message);
66 (void)sprintf(tomb_message, _("所持金: %ld", "AU: %ld"), (long)dead_ptr->au);
67 center_string(buf, tomb_message);
73 * @brief プレーヤーを殺したモンスターを表示する (日本語版専用)
74 * @param dead_ptr プレーヤーへの参照ポインタ
76 * @param tomb_message 墓碑に刻む言葉
79 static int show_killing_monster(player_type *dead_ptr, char *buf, char *tomb_message, size_t tomb_message_size)
81 shape_buffer(dead_ptr->died_from, GRAVE_LINE_WIDTH + 1, tomb_message, tomb_message_size);
83 t = tomb_message + strlen(tomb_message) + 1;
87 char killer[MAX_MONSTER_NAME];
88 strcpy(killer, t); /* 2nd line */
89 if (*(t + strlen(t) + 1)) /* Does 3rd line exist? */
91 for (t = killer + strlen(killer) - 2; iskanji(*(t - 1)); t--) /* Loop */
94 } else if (angband_strstr(tomb_message, "『") && suffix(killer, "』")) {
95 char killer2[MAX_MONSTER_NAME];
96 char *name_head = angband_strstr(tomb_message, "『");
97 sprintf(killer2, "%s%s", name_head, killer);
98 if (strlen(killer2) <= GRAVE_LINE_WIDTH) {
99 strcpy(killer, killer2);
102 } else if (angband_strstr(tomb_message, "「") && suffix(killer, "」")) {
103 char killer2[MAX_MONSTER_NAME];
104 char *name_head = angband_strstr(tomb_message, "「");
105 sprintf(killer2, "%s%s", name_head, killer);
106 if (strlen(killer2) <= GRAVE_LINE_WIDTH) {
107 strcpy(killer, killer2);
112 center_string(buf, killer);
113 put_str(buf, 15, 11);
118 * @brief どこで死んだかを表示する (日本語版専用)
119 * @param dead_ptr プレーヤーへの参照ポインタ
121 * @param tomb_message 表示する文字列
122 * @param extra_line 追加の行数
124 static void show_dead_place(player_type *dead_ptr, char *buf, char *tomb_message, int extra_line)
126 if (streq(dead_ptr->died_from, "ripe") || streq(dead_ptr->died_from, "Seppuku"))
129 if (dead_ptr->current_floor_ptr->dun_level == 0) {
130 concptr field_name = dead_ptr->town_num ? "街" : "荒野";
131 if (streq(dead_ptr->died_from, "途中終了")) {
132 sprintf(tomb_message, "%sで死んだ", field_name);
134 sprintf(tomb_message, "に%sで殺された", field_name);
137 if (streq(dead_ptr->died_from, "途中終了")) {
138 sprintf(tomb_message, "地下 %d 階で死んだ", (int)dead_ptr->current_floor_ptr->dun_level);
140 sprintf(tomb_message, "に地下 %d 階で殺された", (int)dead_ptr->current_floor_ptr->dun_level);
144 center_string(buf, tomb_message);
145 put_str(buf, 15 + extra_line, 11);
149 * @brief 墓に刻む言葉を細かく表示 (日本語版専用)
150 * @param dead_ptr プレーヤーへの参照ポインタ
153 static void show_tomb_detail(player_type *dead_ptr, char *buf)
155 char tomb_message[160];
157 if (streq(dead_ptr->died_from, "途中終了")) {
158 strcpy(tomb_message, "<自殺>");
159 } else if (streq(dead_ptr->died_from, "ripe")) {
160 strcpy(tomb_message, "引退後に天寿を全う");
161 } else if (streq(dead_ptr->died_from, "Seppuku")) {
162 strcpy(tomb_message, "勝利の後、切腹");
164 extra_line = show_killing_monster(dead_ptr, buf, tomb_message, sizeof(tomb_message));
167 center_string(buf, tomb_message);
168 put_str(buf, 14, 11);
170 show_dead_place(dead_ptr, buf, tomb_message, extra_line);
175 * @brief Detailed display of words engraved on the tomb (English version only)
176 * @param dead_ptr reference pointer to the player
177 * @param buf template of the tomb
180 static void show_tomb_detail(player_type *dead_ptr, char *buf)
182 char tomb_message[160];
183 (void)sprintf(tomb_message, "Killed on Level %d", dead_ptr->current_floor_ptr->dun_level);
184 center_string(buf, tomb_message);
185 put_str(buf, 14, 11);
187 shape_buffer(format("by %s.", dead_ptr->died_from), GRAVE_LINE_WIDTH + 1, tomb_message, sizeof(tomb_message));
188 center_string(buf, tomb_message);
190 put_str(buf, 15, 11);
191 t = tomb_message + strlen(tomb_message) + 1;
195 char killer[MAX_MONSTER_NAME];
196 strcpy(killer, t); /* 2nd line */
197 if (*(t + strlen(t) + 1)) /* Does 3rd line exist? */
199 int dummy_len = strlen(killer);
200 strcpy(killer + MIN(dummy_len, GRAVE_LINE_WIDTH - 3), "...");
203 center_string(buf, killer);
204 put_str(buf, 16, 11);
209 * @brief 墓石のアスキーアート表示 /
210 * Display a "tomb-stone"
211 * @param creature_ptr プレーヤーへの参照ポインタ
213 void print_tomb(player_type *dead_ptr)
217 read_dead_file(buf, sizeof(buf));
218 concptr p = (current_world_ptr->total_winner || (dead_ptr->lev > PY_MAX_LEVEL)) ? _("偉大なる者", "Magnificent")
219 : player_title[dead_ptr->pclass][(dead_ptr->lev - 1) / 5];
221 center_string(buf, dead_ptr->name);
226 center_string(buf, "the");
230 center_string(buf, p);
233 center_string(buf, cp_ptr->title);
234 put_str(buf, 10, 11);
236 show_basic_params(dead_ptr, buf);
237 show_tomb_detail(dead_ptr, buf);
239 char current_time[80];
240 time_t ct = time((time_t *)0);
241 (void)sprintf(current_time, "%-.24s", ctime(&ct));
242 center_string(buf, current_time);
243 put_str(buf, 17, 11);
244 msg_format(_("さようなら、%s!", "Goodbye, %s!"), dead_ptr->name);
248 * @brief 死亡/引退/切腹時にインベントリ内のアイテムを*鑑定*する
249 * @param creature_ptr プレーヤーへの参照ポインタ
251 static void inventory_aware(player_type *creature_ptr)
254 for (int i = 0; i < INVEN_TOTAL; i++) {
255 o_ptr = &creature_ptr->inventory_list[i];
259 object_aware(creature_ptr, o_ptr);
265 * @brief 死亡/引退/切腹時に我が家のアイテムを*鑑定*する
266 * @param creature_ptr プレーヤーへの参照ポインタ
268 static void home_aware(player_type *creature_ptr)
271 store_type *store_ptr;
272 for (int i = 1; i < max_towns; i++) {
273 store_ptr = &town_info[i].store[STORE_HOME];
274 for (int j = 0; j < store_ptr->stock_num; j++) {
275 o_ptr = &store_ptr->stock[j];
279 object_aware(creature_ptr, o_ptr);
286 * @brief プレーヤーの持ち物を表示する
287 * @param creature_ptr プレーヤーへの参照ポインタ
288 * @return Escキーでゲームを終了する時TRUE
290 static bool show_dead_player_items(player_type *creature_ptr)
292 if (creature_ptr->equip_cnt) {
294 (void)show_equipment(creature_ptr, 0, USE_FULL, AllMatchItemTester());
295 prt(_("装備していたアイテム: -続く-", "You are using: -more-"), 0, 0);
296 if (inkey() == ESCAPE)
300 if (creature_ptr->inven_cnt) {
302 (void)show_inventory(creature_ptr, 0, USE_FULL, AllMatchItemTester());
303 prt(_("持っていたアイテム: -続く-", "You are carrying: -more-"), 0, 0);
305 if (inkey() == ESCAPE)
313 * @brief 我が家にあったアイテムを表示する
314 * @param creature_ptr プレーヤーへの参照ポインタ
316 static void show_dead_home_items(player_type *creature_ptr)
318 for (int l = 1; l < max_towns; l++) {
319 store_type *store_ptr;
320 store_ptr = &town_info[l].store[STORE_HOME];
321 if (store_ptr->stock_num == 0)
324 for (int i = 0, k = 0; i < store_ptr->stock_num; k++) {
326 for (int j = 0; (j < 12) && (i < store_ptr->stock_num); j++, i++) {
327 GAME_TEXT o_name[MAX_NLEN];
330 o_ptr = &store_ptr->stock[i];
331 sprintf(tmp_val, "%c) ", I2A(j));
332 prt(tmp_val, j + 2, 4);
333 describe_flavor(creature_ptr, o_name, o_ptr, 0);
334 c_put_str(tval_to_attr[o_ptr->tval], o_name, j + 2, 7);
337 prt(format(_("我が家に置いてあったアイテム ( %d ページ): -続く-", "Your home contains (page %d): -more-"), k + 1), 0, 0);
338 if (inkey() == ESCAPE)
345 * @brief キャラクタ情報をファイルに書き出す
346 * @param creature_ptr プレーヤーへの参照ポインタ
347 * @param file_character ステータスダンプへのコールバック
349 static void export_player_info(player_type *creature_ptr, display_player_pf display_player)
351 prt(_("キャラクターの記録をファイルに書き出すことができます。", "You may now dump a character record to one or more files."), 21, 0);
352 prt(_("リターンキーでキャラクターを見ます。ESCで中断します。", "Then, hit RETURN to see the character, or ESC to abort."), 22, 0);
355 put_str(_("ファイルネーム: ", "Filename: "), 23, 0);
357 if (!askfor(out_val, 60))
363 (void)file_character(creature_ptr, out_val, display_player);
369 * @brief 自動的にプレイヤーステータスをファイルダンプ出力する
371 static void file_character_auto(player_type *creature_ptr, display_player_pf display_player)
373 time_t now_t = time(nullptr);
374 struct tm *now_tm = localtime(&now_t);
379 strftime(datetime, sizeof(datetime), "%Y-%m-%d_%H%M%S", now_tm);
380 strnfmt(filename, sizeof(filename), "%s_Autodump_%s.txt", p_ptr->name, datetime);
383 (void)file_character(creature_ptr, filename, display_player);
388 * @brief 死亡、引退時の簡易ステータス表示
389 * @param creature_ptr プレーヤーへの参照ポインタ
390 * @param display_player ステータス表示へのコールバック
392 void show_death_info(player_type *creature_ptr, display_player_pf display_player)
394 inventory_aware(creature_ptr);
395 home_aware(creature_ptr);
397 creature_ptr->update |= (PU_BONUS);
398 handle_stuff(creature_ptr);
403 file_character_auto(creature_ptr, display_player);
405 export_player_info(creature_ptr, display_player);
406 (*display_player)(creature_ptr, 0);
407 prt(_("何かキーを押すとさらに情報が続きます (ESCで中断): ", "Hit any key to see more information (ESC to abort): "), 23, 0);
408 if (inkey() == ESCAPE)
410 if (show_dead_player_items(creature_ptr))
413 show_dead_home_items(creature_ptr);