2 * @brief 既知/存命のユニークを表示する
7 #include "core/show-file.h"
8 #include "game-option/cheat-options.h"
9 #include "io-dump/dump-util.h"
10 #include "knowledge-items.h"
11 #include "monster-race/monster-race.h"
12 #include "monster-race/race-flags1.h"
13 #include "system/monster-race-definition.h"
14 #include "system/player-type-definition.h"
15 #include "util/angband-files.h"
16 #include "util/sort.h"
18 typedef struct unique_list_type {
21 std::vector<MONRACE_IDX> who;
23 int num_uniques_surface;
24 int num_uniques_over100;
25 int num_uniques_total;
29 unique_list_type *initialize_unique_lsit_type(unique_list_type *unique_list_ptr, bool is_alive)
31 unique_list_ptr->is_alive = is_alive;
32 unique_list_ptr->why = 2;
33 unique_list_ptr->num_uniques_surface = 0;
34 unique_list_ptr->num_uniques_over100 = 0;
35 unique_list_ptr->num_uniques_total = 0;
36 unique_list_ptr->max_lev = -1;
37 for (IDX i = 0; i < 10; i++)
38 unique_list_ptr->num_uniques[i] = 0;
40 return unique_list_ptr;
44 * @brief モンスターリストを走査し、生きているか死んでいるユニークだけを抽出する
45 * @param r_ptr モンスター種別への参照ポインタ
46 * @param is_alive 生きているユニークのリストならばTRUE、撃破したユニークのリストならばFALSE
47 * @return is_aliveの条件に見合うユニークがいたらTRUE、それ以外はFALSE
48 * @details 闘技場のモンスターとは再戦できないので、生きているなら表示から外す
50 static bool sweep_uniques(monster_race *r_ptr, bool is_alive)
52 if (r_ptr->name.empty())
55 if (!(r_ptr->flags1 & RF1_UNIQUE))
59 if (!cheat_know && !r_ptr->r_sights)
62 bool is_except_arena = is_alive ? (r_ptr->rarity > 100) && ((r_ptr->flags1 & RF1_QUESTOR) == 0) : false;
63 if (!r_ptr->rarity || is_except_arena)
67 if (r_ptr->max_num == 0)
70 if (r_ptr->max_num > 0)
77 static void display_uniques(unique_list_type *unique_list_ptr, FILE *fff)
79 if (unique_list_ptr->num_uniques_surface) {
80 concptr surface_desc = unique_list_ptr->is_alive ? _(" 地上 生存: %3d体\n", " Surface alive: %3d\n")
81 : _(" 地上 撃破: %3d体\n", " Surface dead: %3d\n");
82 fprintf(fff, surface_desc, unique_list_ptr->num_uniques_surface);
83 unique_list_ptr->num_uniques_total += unique_list_ptr->num_uniques_surface;
86 for (IDX i = 0; i <= unique_list_ptr->max_lev; i++) {
87 concptr dungeon_desc = unique_list_ptr->is_alive ? _("%3d-%3d階 生存: %3d体\n", "Level %3d-%3d alive: %3d\n")
88 : _("%3d-%3d階 撃破: %3d体\n", "Level %3d-%3d dead: %3d\n");
89 fprintf(fff, dungeon_desc, 1 + i * 10, 10 + i * 10, unique_list_ptr->num_uniques[i]);
90 unique_list_ptr->num_uniques_total += unique_list_ptr->num_uniques[i];
93 if (unique_list_ptr->num_uniques_over100) {
94 concptr deep_desc = unique_list_ptr->is_alive ? _("101- 階 生存: %3d体\n", "Level 101- alive: %3d\n")
95 : _("101- 階 撃破: %3d体\n", "Level 101- dead: %3d\n");
96 fprintf(fff, deep_desc, unique_list_ptr->num_uniques_over100);
97 unique_list_ptr->num_uniques_total += unique_list_ptr->num_uniques_over100;
100 if (unique_list_ptr->num_uniques_total) {
101 fputs(_("--------- -----------\n", "------------- ----------\n"), fff);
102 concptr total_desc = unique_list_ptr->is_alive ? _(" 合計 生存: %3d体\n\n", " Total alive: %3d\n\n")
103 : _(" 合計 撃破: %3d体\n\n", " Total dead: %3d\n\n");
104 fprintf(fff, total_desc, unique_list_ptr->num_uniques_total);
106 concptr no_unique_desc = unique_list_ptr->is_alive ? _("現在は既知の生存ユニークはいません。\n", "No known uniques alive.\n")
107 : _("現在は既知の撃破ユニークはいません。\n", "No known uniques dead.\n");
108 fputs(no_unique_desc, fff);
112 for (auto r_idx : unique_list_ptr->who) {
113 monster_race *r_ptr = &r_info[r_idx];
115 if (r_ptr->defeat_level && r_ptr->defeat_time)
116 sprintf(buf, _(" - レベル%2d - %d:%02d:%02d", " - level %2d - %d:%02d:%02d"), r_ptr->defeat_level, r_ptr->defeat_time / (60 * 60),
117 (r_ptr->defeat_time / 60) % 60, r_ptr->defeat_time % 60);
121 fprintf(fff, _(" %s (レベル%d)%s\n", " %s (level %d)%s\n"), r_ptr->name.c_str(), (int)r_ptr->level, buf);
126 * @brief 既知の生きているユニークまたは撃破済ユニークの一覧を表示させる
127 * @param player_ptr プレイヤーへの参照ポインタ
128 * @param is_alive 生きているユニークのリストならばTRUE、撃破したユニークのリストならばFALSE
130 void do_cmd_knowledge_uniques(PlayerType *player_ptr, bool is_alive)
132 unique_list_type tmp_list;
133 unique_list_type *unique_list_ptr = initialize_unique_lsit_type(&tmp_list, is_alive);
135 GAME_TEXT file_name[FILE_NAME_SIZE];
136 if (!open_temporary_file(&fff, file_name))
139 for (auto &r_ref : r_info) {
140 if (r_ref.idx == 0) {
143 if (!sweep_uniques(&r_ref, unique_list_ptr->is_alive))
147 int lev = (r_ref.level - 1) / 10;
149 unique_list_ptr->num_uniques[lev]++;
150 if (unique_list_ptr->max_lev < lev)
151 unique_list_ptr->max_lev = lev;
153 unique_list_ptr->num_uniques_over100++;
155 unique_list_ptr->num_uniques_surface++;
157 unique_list_ptr->who.push_back(r_ref.idx);
160 ang_sort(player_ptr, unique_list_ptr->who.data(), &unique_list_ptr->why, unique_list_ptr->who.size(), ang_sort_comp_hook, ang_sort_swap_hook);
161 display_uniques(unique_list_ptr, fff);
164 = unique_list_ptr->is_alive ? _("まだ生きているユニーク・モンスター", "Alive Uniques") : _("もう撃破したユニーク・モンスター", "Dead Uniques");
165 (void)show_file(player_ptr, true, file_name, title_desc, 0, 0);