OSDN Git Service

Merge pull request #2940 from backwardsEric/sprintf-string-format
[hengbandforosx/hengbandosx.git] / src / io-dump / character-dump.cpp
1 #include "io-dump/character-dump.h"
2 #include "artifact/fixed-art-types.h"
3 #include "avatar/avatar.h"
4 #include "cmd-building/cmd-building.h"
5 #include "dungeon/quest.h"
6 #include "flavor/flavor-describer.h"
7 #include "floor/floor-town.h"
8 #include "game-option/birth-options.h"
9 #include "game-option/game-play-options.h"
10 #include "inventory/inventory-slot-types.h"
11 #include "io-dump/player-status-dump.h"
12 #include "io-dump/special-class-dump.h"
13 #include "io/mutations-dump.h"
14 #include "io/write-diary.h"
15 #include "knowledge/knowledge-quests.h"
16 #include "main/angband-headers.h"
17 #include "market/arena-info-table.h"
18 #include "monster-race/monster-race.h"
19 #include "monster-race/race-flags1.h"
20 #include "monster/monster-describer.h"
21 #include "monster/monster-description-types.h"
22 #include "monster/monster-info.h"
23 #include "monster/monster-status.h"
24 #include "monster/smart-learn-types.h"
25 #include "object/object-info.h"
26 #include "pet/pet-util.h"
27 #include "player-info/alignment.h"
28 #include "player/player-status-flags.h"
29 #include "player/player-status-table.h"
30 #include "player/race-info-table.h"
31 #include "realm/realm-names-table.h"
32 #include "store/store-util.h"
33 #include "store/store.h"
34 #include "system/angband-version.h"
35 #include "system/building-type-definition.h"
36 #include "system/dungeon-info.h"
37 #include "system/floor-type-definition.h"
38 #include "system/item-entity.h"
39 #include "system/monster-entity.h"
40 #include "system/monster-race-info.h"
41 #include "system/player-type-definition.h"
42 #include "term/z-form.h"
43 #include "util/enum-converter.h"
44 #include "util/int-char-converter.h"
45 #include "util/sort.h"
46 #include "util/string-processor.h"
47 #include "view/display-messages.h"
48 #include "world/world.h"
49 #include <numeric>
50 #include <string>
51
52 /*!
53  * @brief プレイヤーのペット情報をファイルにダンプする
54  * @param player_ptr プレイヤーへの参照ポインタ
55  * @param fff ファイルポインタ
56  */
57 static void dump_aux_pet(PlayerType *player_ptr, FILE *fff)
58 {
59     bool pet = false;
60     bool pet_settings = false;
61     for (int i = player_ptr->current_floor_ptr->m_max - 1; i >= 1; i--) {
62         auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
63
64         if (!m_ptr->is_valid()) {
65             continue;
66         }
67         if (!m_ptr->is_pet()) {
68             continue;
69         }
70         pet_settings = true;
71         if (!m_ptr->nickname && (player_ptr->riding != i)) {
72             continue;
73         }
74         if (!pet) {
75             fprintf(fff, _("\n\n  [主なペット]\n\n", "\n\n  [Leading Pets]\n\n"));
76             pet = true;
77         }
78
79         GAME_TEXT pet_name[MAX_NLEN];
80         monster_desc(player_ptr, pet_name, m_ptr, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE);
81         fprintf(fff, "%s\n", pet_name);
82     }
83
84     if (!pet_settings) {
85         return;
86     }
87
88     fprintf(fff, _("\n\n  [ペットへの命令]\n", "\n\n  [Command for Pets]\n"));
89
90     fprintf(fff, _("\n ドアを開ける:                       %s", "\n Pets open doors:                    %s"),
91         (player_ptr->pet_extra_flags & PF_OPEN_DOORS) ? "ON" : "OFF");
92
93     fprintf(fff, _("\n アイテムを拾う:                     %s", "\n Pets pick up items:                 %s"),
94         (player_ptr->pet_extra_flags & PF_PICKUP_ITEMS) ? "ON" : "OFF");
95
96     fprintf(fff, _("\n テレポート系魔法を使う:             %s", "\n Allow teleport:                     %s"),
97         (player_ptr->pet_extra_flags & PF_TELEPORT) ? "ON" : "OFF");
98
99     fprintf(fff, _("\n 攻撃魔法を使う:                     %s", "\n Allow cast attack spell:            %s"),
100         (player_ptr->pet_extra_flags & PF_ATTACK_SPELL) ? "ON" : "OFF");
101
102     fprintf(fff, _("\n 召喚魔法を使う:                     %s", "\n Allow cast summon spell:            %s"),
103         (player_ptr->pet_extra_flags & PF_SUMMON_SPELL) ? "ON" : "OFF");
104
105     fprintf(fff, _("\n プレイヤーを巻き込む範囲魔法を使う: %s", "\n Allow involve player in area spell: %s"),
106         (player_ptr->pet_extra_flags & PF_BALL_SPELL) ? "ON" : "OFF");
107
108     fputc('\n', fff);
109 }
110
111 /*!
112  * @brief クエスト情報をファイルにダンプする
113  * @param player_ptr プレイヤーへの参照ポインタ
114  * @param fff ファイルポインタ
115  */
116 static void dump_aux_quest(PlayerType *player_ptr, FILE *fff)
117 {
118     fprintf(fff, _("\n\n  [クエスト情報]\n", "\n\n  [Quest Information]\n"));
119
120     const auto &quest_list = QuestList::get_instance();
121     std::vector<QuestId> quest_numbers;
122     for (const auto &[q_idx, q_ref] : quest_list) {
123         quest_numbers.push_back(q_idx);
124     }
125     int dummy;
126     ang_sort(player_ptr, quest_numbers.data(), &dummy, quest_numbers.size(), ang_sort_comp_quest_num, ang_sort_swap_quest_num);
127
128     fputc('\n', fff);
129     do_cmd_knowledge_quests_completed(player_ptr, fff, quest_numbers);
130     fputc('\n', fff);
131     do_cmd_knowledge_quests_failed(player_ptr, fff, quest_numbers);
132     fputc('\n', fff);
133 }
134
135 /*!
136  * @brief 死の直前メッセージ並びに遺言をファイルにダンプする
137  * @param player_ptr プレイヤーへの参照ポインタ
138  * @param fff ファイルポインタ
139  */
140 static void dump_aux_last_message(PlayerType *player_ptr, FILE *fff)
141 {
142     if (!player_ptr->is_dead) {
143         return;
144     }
145
146     if (!w_ptr->total_winner) {
147         fprintf(fff, _("\n  [死ぬ直前のメッセージ]\n\n", "\n  [Last Messages]\n\n"));
148         for (int i = std::min(message_num(), 30); i >= 0; i--) {
149             fprintf(fff, "> %s\n", message_str((int16_t)i));
150         }
151
152         fputc('\n', fff);
153         return;
154     }
155
156     if (player_ptr->last_message) {
157         fprintf(fff, _("\n  [*勝利*メッセージ]\n\n", "\n  [*Winning* Message]\n\n"));
158         fprintf(fff, "  %s\n", player_ptr->last_message);
159         fputc('\n', fff);
160     }
161 }
162
163 /*!
164  * @brief 帰還場所情報をファイルにダンプする
165  * @param fff ファイルポインタ
166  */
167 static void dump_aux_recall(FILE *fff)
168 {
169     fprintf(fff, _("\n  [帰還場所]\n\n", "\n  [Recall Depth]\n\n"));
170     for (const auto &d_ref : dungeons_info) {
171         bool seiha = false;
172
173         if (d_ref.idx == 0 || !d_ref.maxdepth) {
174             continue;
175         }
176         if (!max_dlv[d_ref.idx]) {
177             continue;
178         }
179         if (MonsterRace(d_ref.final_guardian).is_valid()) {
180             if (!monraces_info[d_ref.final_guardian].max_num) {
181                 seiha = true;
182             }
183         } else if (max_dlv[d_ref.idx] == d_ref.maxdepth) {
184             seiha = true;
185         }
186
187         fprintf(fff, _("   %c%-12s: %3d 階\n", "   %c%-16s: level %3d\n"), seiha ? '!' : ' ', d_ref.name.data(), (int)max_dlv[d_ref.idx]);
188     }
189 }
190
191 /*!
192  * @brief オプション情報をファイルにダンプする
193  * @param fff ファイルポインタ
194  */
195 static void dump_aux_options(FILE *fff)
196 {
197     fprintf(fff, _("\n  [オプション設定]\n", "\n  [Option Settings]\n"));
198     if (preserve_mode) {
199         fprintf(fff, _("\n 保存モード:         ON", "\n Preserve Mode:      ON"));
200     } else {
201         fprintf(fff, _("\n 保存モード:         OFF", "\n Preserve Mode:      OFF"));
202     }
203
204     if (ironman_small_levels) {
205         fprintf(fff, _("\n 小さいダンジョン:   ALWAYS", "\n Small Levels:       ALWAYS"));
206     } else if (always_small_levels) {
207         fprintf(fff, _("\n 小さいダンジョン:   ON", "\n Small Levels:       ON"));
208     } else if (small_levels) {
209         fprintf(fff, _("\n 小さいダンジョン:   ENABLED", "\n Small Levels:       ENABLED"));
210     } else {
211         fprintf(fff, _("\n 小さいダンジョン:   OFF", "\n Small Levels:       OFF"));
212     }
213
214     if (vanilla_town) {
215         fprintf(fff, _("\n 元祖の町のみ:       ON", "\n Vanilla Town:       ON"));
216     } else if (lite_town) {
217         fprintf(fff, _("\n 小規模な町:         ON", "\n Lite Town:          ON"));
218     }
219
220     if (ironman_shops) {
221         fprintf(fff, _("\n 店なし:             ON", "\n No Shops:           ON"));
222     }
223
224     if (ironman_downward) {
225         fprintf(fff, _("\n 階段を上がれない:   ON", "\n Diving Only:        ON"));
226     }
227
228     if (ironman_rooms) {
229         fprintf(fff, _("\n 普通でない部屋:     ON", "\n Unusual Rooms:      ON"));
230     }
231
232     if (ironman_nightmare) {
233         fprintf(fff, _("\n 悪夢モード:         ON", "\n Nightmare Mode:     ON"));
234     }
235
236     if (ironman_empty_levels) {
237         fprintf(fff, _("\n アリーナ:           ALWAYS", "\n Arena Levels:       ALWAYS"));
238     } else if (empty_levels) {
239         fprintf(fff, _("\n アリーナ:           ENABLED", "\n Arena Levels:       ENABLED"));
240     } else {
241         fprintf(fff, _("\n アリーナ:           OFF", "\n Arena Levels:       OFF"));
242     }
243
244     fputc('\n', fff);
245
246     if (w_ptr->noscore) {
247         fprintf(fff, _("\n 何か不正なことをしてしまっています。\n", "\n You have done something illegal.\n"));
248     }
249
250     fputc('\n', fff);
251 }
252
253 /*!
254  * @brief 闘技場の情報をファイルにダンプする
255  * @param player_ptr プレイヤーへの参照ポインタ
256  * @param fff ファイルポインタ
257  */
258 static void dump_aux_arena(PlayerType *player_ptr, FILE *fff)
259 {
260     if (lite_town || vanilla_town) {
261         return;
262     }
263
264     if (player_ptr->arena_number < 0) {
265         if (player_ptr->arena_number <= ARENA_DEFEATED_OLD_VER) {
266             fprintf(fff, _("\n 闘技場: 敗北\n", "\n Arena: Defeated\n"));
267         } else {
268 #ifdef JP
269             fprintf(
270                 fff, "\n 闘技場: %d回戦で%sの前に敗北\n", -player_ptr->arena_number, monraces_info[arena_info[-1 - player_ptr->arena_number].r_idx].name.data());
271 #else
272             fprintf(fff, "\n Arena: Defeated by %s in the %d%s fight\n", monraces_info[arena_info[-1 - player_ptr->arena_number].r_idx].name.data(),
273                 -player_ptr->arena_number, get_ordinal_number_suffix(-player_ptr->arena_number));
274 #endif
275         }
276
277         fprintf(fff, "\n");
278         return;
279     }
280
281     if (player_ptr->arena_number > MAX_ARENA_MONS + 2) {
282         fprintf(fff, _("\n 闘技場: 真のチャンピオン\n", "\n Arena: True Champion\n"));
283         fprintf(fff, "\n");
284         return;
285     }
286
287     if (player_ptr->arena_number > MAX_ARENA_MONS - 1) {
288         fprintf(fff, _("\n 闘技場: チャンピオン\n", "\n Arena: Champion\n"));
289         fprintf(fff, "\n");
290         return;
291     }
292
293 #ifdef JP
294     fprintf(fff, "\n 闘技場: %2d勝\n", (player_ptr->arena_number > MAX_ARENA_MONS ? MAX_ARENA_MONS : player_ptr->arena_number));
295 #else
296     fprintf(fff, "\n Arena: %2d Victor%s\n", (player_ptr->arena_number > MAX_ARENA_MONS ? MAX_ARENA_MONS : player_ptr->arena_number),
297         (player_ptr->arena_number > 1) ? "ies" : "y");
298 #endif
299     fprintf(fff, "\n");
300 }
301
302 /*!
303  * @brief 撃破モンスターの情報をファイルにダンプする
304  * @param fff ファイルポインタ
305  */
306 static void dump_aux_monsters(PlayerType *player_ptr, FILE *fff)
307 {
308     fprintf(fff, _("\n  [倒したモンスター]\n\n", "\n  [Defeated Monsters]\n\n"));
309
310     /* Allocate the "who" array */
311     uint16_t why = 2;
312     std::vector<MonsterRaceId> who;
313
314     /* Count monster kills */
315     auto norm_total = 0;
316     for (const auto &[r_idx, r_ref] : monraces_info) {
317         /* Ignore unused index */
318         if (!MonsterRace(r_ref.idx).is_valid() || r_ref.name.empty()) {
319             continue;
320         }
321
322         if (r_ref.kind_flags.has(MonsterKindType::UNIQUE)) {
323             bool dead = (r_ref.max_num == 0);
324             if (dead) {
325                 norm_total++;
326
327                 /* Add a unique monster to the list */
328                 who.push_back(r_ref.idx);
329             }
330
331             continue;
332         }
333
334         if (r_ref.r_pkills > 0) {
335             norm_total += r_ref.r_pkills;
336         }
337     }
338
339     /* No monsters is defeated */
340     if (norm_total < 1) {
341         fprintf(fff, _("まだ敵を倒していません。\n", "You have defeated no enemies yet.\n"));
342         return;
343     }
344
345     auto uniq_total = static_cast<int>(who.size());
346     /* Defeated more than one normal monsters */
347     if (uniq_total == 0) {
348 #ifdef JP
349         fprintf(fff, "%d体の敵を倒しています。\n", norm_total);
350 #else
351         fprintf(fff, "You have defeated %d %s.\n", norm_total, norm_total == 1 ? "enemy" : "enemies");
352 #endif
353         return;
354     }
355
356     /* Defeated more than one unique monsters */
357 #ifdef JP
358     fprintf(fff, "%d体のユニーク・モンスターを含む、合計%d体の敵を倒しています。\n", uniq_total, norm_total);
359 #else
360     fprintf(fff, "You have defeated %d %s including %d unique monster%s in total.\n", norm_total, norm_total == 1 ? "enemy" : "enemies", uniq_total,
361         (uniq_total == 1 ? "" : "s"));
362 #endif
363
364     /* Sort the array by dungeon depth of monsters */
365     ang_sort(player_ptr, who.data(), &why, uniq_total, ang_sort_comp_hook, ang_sort_swap_hook);
366     fprintf(fff, _("\n《上位%d体のユニーク・モンスター》\n", "\n< Unique monsters top %d >\n"), std::min(uniq_total, 10));
367
368     char buf[80];
369     for (auto it = who.rbegin(); it != who.rend() && std::distance(who.rbegin(), it) < 10; it++) {
370         auto *r_ptr = &monraces_info[*it];
371         if (r_ptr->defeat_level && r_ptr->defeat_time) {
372             strnfmt(buf, sizeof(buf), _(" - レベル%2d - %d:%02d:%02d", " - level %2d - %d:%02d:%02d"), r_ptr->defeat_level, r_ptr->defeat_time / (60 * 60),
373                 (r_ptr->defeat_time / 60) % 60, r_ptr->defeat_time % 60);
374         } else {
375             buf[0] = '\0';
376         }
377
378         auto name = str_separate(r_ptr->name, 40);
379         fprintf(fff, _("  %-40s (レベル%3d)%s\n", "  %-40s (level %3d)%s\n"), name.front().data(), (int)r_ptr->level, buf);
380         for (auto i = 1U; i < name.size(); ++i) {
381             fprintf(fff, "  %s\n", name[i].data());
382         }
383     }
384 }
385
386 /*!
387  * @brief 元種族情報をファイルにダンプする
388  * @param player_ptr プレイヤーへの参照ポインタ
389  * @param fff ファイルポインタ
390  */
391 static void dump_aux_race_history(PlayerType *player_ptr, FILE *fff)
392 {
393     if (!player_ptr->old_race1 && !player_ptr->old_race2) {
394         return;
395     }
396
397     fprintf(fff, _("\n\n あなたは%sとして生まれた。", "\n\n You were born as %s."), race_info[enum2i(player_ptr->start_race)].title);
398     for (int i = 0; i < MAX_RACES; i++) {
399         if (enum2i(player_ptr->start_race) == i) {
400             continue;
401         }
402         if (i < 32) {
403             if (!(player_ptr->old_race1 & 1UL << i)) {
404                 continue;
405             }
406         } else {
407             if (!(player_ptr->old_race2 & 1UL << (i - 32))) {
408                 continue;
409             }
410         }
411
412         fprintf(fff, _("\n あなたはかつて%sだった。", "\n You were a %s before."), race_info[i].title);
413     }
414
415     fputc('\n', fff);
416 }
417
418 /*!
419  * @brief 元魔法領域情報をファイルにダンプする
420  * @param player_ptr プレイヤーへの参照ポインタ
421  * @param fff ファイルポインタ
422  */
423 static void dump_aux_realm_history(PlayerType *player_ptr, FILE *fff)
424 {
425     if (player_ptr->old_realm == 0) {
426         return;
427     }
428
429     fputc('\n', fff);
430     for (int i = 0; i < MAX_MAGIC; i++) {
431         if (!(player_ptr->old_realm & 1UL << i)) {
432             continue;
433         }
434         fprintf(fff, _("\n あなたはかつて%s魔法を使えた。", "\n You were able to use %s magic before."), realm_names[i + 1]);
435     }
436
437     fputc('\n', fff);
438 }
439
440 /*!
441  * @brief 徳の情報をファイルにダンプする
442  * @param player_ptr プレイヤーへの参照ポインタ
443  * @param fff ファイルポインタ
444  */
445 static void dump_aux_virtues(PlayerType *player_ptr, FILE *fff)
446 {
447     fprintf(fff, _("\n\n  [自分に関する情報]\n\n", "\n\n  [HP-rate & Max stat & Virtues]\n\n"));
448
449     int percent = (int)(((long)player_ptr->player_hp[PY_MAX_LEVEL - 1] * 200L) / (2 * player_ptr->hitdie + ((PY_MAX_LEVEL - 1 + 3) * (player_ptr->hitdie + 1))));
450
451 #ifdef JP
452     if (player_ptr->knowledge & KNOW_HPRATE) {
453         fprintf(fff, "現在の体力ランク : %d/100\n\n", percent);
454     } else {
455         fprintf(fff, "現在の体力ランク : ???\n\n");
456     }
457     fprintf(fff, "能力の最大値\n");
458 #else
459     if (player_ptr->knowledge & KNOW_HPRATE) {
460         fprintf(fff, "Your current Life Rating is %d/100.\n\n", percent);
461     } else {
462         fprintf(fff, "Your current Life Rating is ???.\n\n");
463     }
464     fprintf(fff, "Limits of maximum stats\n");
465 #endif
466     for (int v_nr = 0; v_nr < A_MAX; v_nr++) {
467         if ((player_ptr->knowledge & KNOW_STAT) || player_ptr->stat_max[v_nr] == player_ptr->stat_max_max[v_nr]) {
468             fprintf(fff, "%s 18/%d\n", stat_names[v_nr], player_ptr->stat_max_max[v_nr] - 18);
469         } else {
470             fprintf(fff, "%s ???\n", stat_names[v_nr]);
471         }
472     }
473
474     std::string alg = PlayerAlignment(player_ptr).get_alignment_description();
475     fprintf(fff, _("\n属性 : %s\n", "\nYour alignment : %s\n"), alg.data());
476     fprintf(fff, "\n");
477     dump_virtues(player_ptr, fff);
478 }
479
480 /*!
481  * @brief 突然変異の情報をファイルにダンプする
482  * @param player_ptr プレイヤーへの参照ポインタ
483  * @param fff ファイルポインタ
484  */
485 static void dump_aux_mutations(PlayerType *player_ptr, FILE *fff)
486 {
487     if (player_ptr->muta.any()) {
488         fprintf(fff, _("\n\n  [突然変異]\n\n", "\n\n  [Mutations]\n\n"));
489         dump_mutations(player_ptr, fff);
490     }
491 }
492
493 /*!
494  * @brief 所持品の情報をファイルにダンプする
495  * @param player_ptr プレイヤーへの参照ポインタ
496  * @param fff ファイルポインタ
497  */
498 static void dump_aux_equipment_inventory(PlayerType *player_ptr, FILE *fff)
499 {
500     GAME_TEXT o_name[MAX_NLEN];
501     if (player_ptr->equip_cnt) {
502         fprintf(fff, _("  [キャラクタの装備]\n\n", "  [Character Equipment]\n\n"));
503         for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
504             describe_flavor(player_ptr, o_name, &player_ptr->inventory_list[i], 0);
505             if ((((i == INVEN_MAIN_HAND) && can_attack_with_sub_hand(player_ptr)) || ((i == INVEN_SUB_HAND) && can_attack_with_main_hand(player_ptr))) && has_two_handed_weapons(player_ptr)) {
506                 strcpy(o_name, _("(武器を両手持ち)", "(wielding with two-hands)"));
507             }
508
509             fprintf(fff, "%c) %s\n", index_to_label(i), o_name);
510         }
511
512         fprintf(fff, "\n\n");
513     }
514
515     fprintf(fff, _("  [キャラクタの持ち物]\n\n", "  [Character Inventory]\n\n"));
516
517     for (int i = 0; i < INVEN_PACK; i++) {
518         if (!player_ptr->inventory_list[i].bi_id) {
519             break;
520         }
521         describe_flavor(player_ptr, o_name, &player_ptr->inventory_list[i], 0);
522         fprintf(fff, "%c) %s\n", index_to_label(i), o_name);
523     }
524
525     fprintf(fff, "\n\n");
526 }
527
528 /*!
529  * @brief 我が家と博物館のオブジェクト情報をファイルにダンプする
530  * @param fff ファイルポインタ
531  */
532 static void dump_aux_home_museum(PlayerType *player_ptr, FILE *fff)
533 {
534     store_type *store_ptr;
535     store_ptr = &town_info[1].store[enum2i(StoreSaleType::HOME)];
536
537     GAME_TEXT o_name[MAX_NLEN];
538     if (store_ptr->stock_num) {
539         fprintf(fff, _("  [我が家のアイテム]\n", "  [Home Inventory]\n"));
540
541         TERM_LEN x = 1;
542         for (int i = 0; i < store_ptr->stock_num; i++) {
543             if ((i % 12) == 0) {
544                 fprintf(fff, _("\n ( %d ページ )\n", "\n ( page %d )\n"), x++);
545             }
546             describe_flavor(player_ptr, o_name, &store_ptr->stock[i], 0);
547             fprintf(fff, "%c) %s\n", I2A(i % 12), o_name);
548         }
549
550         fprintf(fff, "\n\n");
551     }
552
553     store_ptr = &town_info[1].store[enum2i(StoreSaleType::MUSEUM)];
554
555     if (store_ptr->stock_num == 0) {
556         return;
557     }
558
559     fprintf(fff, _("  [博物館のアイテム]\n", "  [Museum]\n"));
560
561     TERM_LEN x = 1;
562     for (int i = 0; i < store_ptr->stock_num; i++) {
563         if ((i % 12) == 0) {
564             fprintf(fff, _("\n ( %d ページ )\n", "\n ( page %d )\n"), x++);
565         }
566         describe_flavor(player_ptr, o_name, &store_ptr->stock[i], 0);
567         fprintf(fff, "%c) %s\n", I2A(i % 12), o_name);
568     }
569
570     fprintf(fff, "\n\n");
571 }
572
573 /*!
574  * @brief チェックサム情報を出力 / Get check sum in string form
575  * @return チェックサム情報の文字列
576  */
577 static concptr get_check_sum(void)
578 {
579     return format("%02x%02x%02x%02x%02x%02x%02x%02x%02x", terrains_header.checksum, baseitems_header.checksum,
580         artifacts_header.checksum, egos_header.checksum, monraces_header.checksum, dungeons_header.checksum,
581         class_magics_header.checksum, class_skills_header.checksum, vaults_header.checksum);
582 }
583
584 /*!
585  * @brief ダンプ出力のメインルーチン
586  * Output the character dump to a file
587  * @param player_ptr プレイヤーへの参照ポインタ
588  * @param fff ファイルポインタ
589  * @return エラーコード
590  */
591 void make_character_dump(PlayerType *player_ptr, FILE *fff)
592 {
593     char title[127];
594     put_version(title);
595     fprintf(fff, _("  [%s キャラクタ情報]\n\n", "  [%s Character Dump]\n\n"), title);
596
597     dump_aux_player_status(player_ptr, fff);
598     dump_aux_last_message(player_ptr, fff);
599     dump_aux_options(fff);
600     dump_aux_recall(fff);
601     dump_aux_quest(player_ptr, fff);
602     dump_aux_arena(player_ptr, fff);
603     dump_aux_monsters(player_ptr, fff);
604     dump_aux_virtues(player_ptr, fff);
605     dump_aux_race_history(player_ptr, fff);
606     dump_aux_realm_history(player_ptr, fff);
607     dump_aux_class_special(player_ptr, fff);
608     dump_aux_mutations(player_ptr, fff);
609     dump_aux_pet(player_ptr, fff);
610     fputs("\n\n", fff);
611     dump_aux_equipment_inventory(player_ptr, fff);
612     dump_aux_home_museum(player_ptr, fff);
613
614     fprintf(fff, _("  [チェックサム: \"%s\"]\n\n", "  [Check Sum: \"%s\"]\n\n"), get_check_sum());
615 }