OSDN Git Service

[Refactor/WIP] モンスター種族IDをenum class化
[hengbandforosx/hengbandosx.git] / src / knowledge / knowledge-uniques.cpp
1 /*!
2  * @brief 既知/存命のユニークを表示する
3  * @date 2020/04/23
4  * @author Hourier
5  */
6
7 #include "knowledge/knowledge-uniques.h"
8 #include "core/show-file.h"
9 #include "game-option/cheat-options.h"
10 #include "io-dump/dump-util.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"
17
18 struct unique_list_type {
19     bool is_alive;
20     uint16_t why;
21     std::vector<MonsterRaceId> who;
22     int num_uniques[10];
23     int num_uniques_surface;
24     int num_uniques_over100;
25     int num_uniques_total;
26     int max_lev;
27 };
28
29 unique_list_type *initialize_unique_lsit_type(unique_list_type *unique_list_ptr, bool is_alive)
30 {
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;
39     }
40
41     return unique_list_ptr;
42 }
43
44 /*!
45  * @brief モンスターリストを走査し、生きているか死んでいるユニークだけを抽出する
46  * @param r_ptr モンスター種別への参照ポインタ
47  * @param is_alive 生きているユニークのリストならばTRUE、撃破したユニークのリストならばFALSE
48  * @return is_aliveの条件に見合うユニークがいたらTRUE、それ以外はFALSE
49  * @details 闘技場のモンスターとは再戦できないので、生きているなら表示から外す
50  */
51 static bool sweep_uniques(monster_race *r_ptr, bool is_alive)
52 {
53     if (r_ptr->name.empty()) {
54         return false;
55     }
56
57     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
58
59         return false;
60     }
61
62     if (!cheat_know && !r_ptr->r_sights) {
63         return false;
64     }
65
66     bool is_except_arena = is_alive ? (r_ptr->rarity > 100) && ((r_ptr->flags1 & RF1_QUESTOR) == 0) : false;
67     if (!r_ptr->rarity || is_except_arena) {
68         return false;
69     }
70
71     if (is_alive) {
72         if (r_ptr->max_num == 0) {
73             return false;
74         }
75     } else {
76         if (r_ptr->max_num > 0) {
77             return false;
78         }
79     }
80
81     return true;
82 }
83
84 static void display_uniques(unique_list_type *unique_list_ptr, FILE *fff)
85 {
86     if (unique_list_ptr->num_uniques_surface) {
87         concptr surface_desc = unique_list_ptr->is_alive ? _("     地上  生存: %3d体\n", "      Surface  alive: %3d\n")
88                                                          : _("     地上  撃破: %3d体\n", "      Surface  dead: %3d\n");
89         fprintf(fff, surface_desc, unique_list_ptr->num_uniques_surface);
90         unique_list_ptr->num_uniques_total += unique_list_ptr->num_uniques_surface;
91     }
92
93     for (IDX i = 0; i <= unique_list_ptr->max_lev; i++) {
94         concptr dungeon_desc = unique_list_ptr->is_alive ? _("%3d-%3d階  生存: %3d体\n", "Level %3d-%3d  alive: %3d\n")
95                                                          : _("%3d-%3d階  撃破: %3d体\n", "Level %3d-%3d  dead: %3d\n");
96         fprintf(fff, dungeon_desc, 1 + i * 10, 10 + i * 10, unique_list_ptr->num_uniques[i]);
97         unique_list_ptr->num_uniques_total += unique_list_ptr->num_uniques[i];
98     }
99
100     if (unique_list_ptr->num_uniques_over100) {
101         concptr deep_desc = unique_list_ptr->is_alive ? _("101-   階  生存: %3d体\n", "Level 101-     alive: %3d\n")
102                                                       : _("101-   階  撃破: %3d体\n", "Level 101-     dead: %3d\n");
103         fprintf(fff, deep_desc, unique_list_ptr->num_uniques_over100);
104         unique_list_ptr->num_uniques_total += unique_list_ptr->num_uniques_over100;
105     }
106
107     if (unique_list_ptr->num_uniques_total) {
108         fputs(_("---------  -----------\n", "-------------  ----------\n"), fff);
109         concptr total_desc = unique_list_ptr->is_alive ? _("     合計  生存: %3d体\n\n", "        Total  alive: %3d\n\n")
110                                                        : _("     合計  撃破: %3d体\n\n", "        Total  dead: %3d\n\n");
111         fprintf(fff, total_desc, unique_list_ptr->num_uniques_total);
112     } else {
113         concptr no_unique_desc = unique_list_ptr->is_alive ? _("現在は既知の生存ユニークはいません。\n", "No known uniques alive.\n")
114                                                            : _("現在は既知の撃破ユニークはいません。\n", "No known uniques dead.\n");
115         fputs(no_unique_desc, fff);
116     }
117
118     char buf[80];
119     for (auto r_idx : unique_list_ptr->who) {
120         auto *r_ptr = &r_info[r_idx];
121
122         if (r_ptr->defeat_level && r_ptr->defeat_time) {
123             sprintf(buf, _(" - レベル%2d - %d:%02d:%02d", " - level %2d - %d:%02d:%02d"), r_ptr->defeat_level, r_ptr->defeat_time / (60 * 60),
124                 (r_ptr->defeat_time / 60) % 60, r_ptr->defeat_time % 60);
125         } else {
126             buf[0] = '\0';
127         }
128
129         fprintf(fff, _("     %s (レベル%d)%s\n", "     %s (level %d)%s\n"), r_ptr->name.c_str(), (int)r_ptr->level, buf);
130     }
131 }
132
133 /*!
134  * @brief 既知の生きているユニークまたは撃破済ユニークの一覧を表示させる
135  * @param player_ptr プレイヤーへの参照ポインタ
136  * @param is_alive 生きているユニークのリストならばTRUE、撃破したユニークのリストならばFALSE
137  */
138 void do_cmd_knowledge_uniques(PlayerType *player_ptr, bool is_alive)
139 {
140     unique_list_type tmp_list;
141     unique_list_type *unique_list_ptr = initialize_unique_lsit_type(&tmp_list, is_alive);
142     FILE *fff = nullptr;
143     GAME_TEXT file_name[FILE_NAME_SIZE];
144     if (!open_temporary_file(&fff, file_name)) {
145         return;
146     }
147
148     for (auto &[r_idx, r_ref] : r_info) {
149         if (!is_valid_monster_race(r_ref.idx)) {
150             continue;
151         }
152         if (!sweep_uniques(&r_ref, unique_list_ptr->is_alive)) {
153             continue;
154         }
155
156         if (r_ref.level) {
157             int lev = (r_ref.level - 1) / 10;
158             if (lev < 10) {
159                 unique_list_ptr->num_uniques[lev]++;
160                 if (unique_list_ptr->max_lev < lev) {
161                     unique_list_ptr->max_lev = lev;
162                 }
163             } else {
164                 unique_list_ptr->num_uniques_over100++;
165             }
166         } else {
167             unique_list_ptr->num_uniques_surface++;
168         }
169
170         unique_list_ptr->who.push_back(r_ref.idx);
171     }
172
173     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);
174     display_uniques(unique_list_ptr, fff);
175     angband_fclose(fff);
176     concptr title_desc = unique_list_ptr->is_alive ? _("まだ生きているユニーク・モンスター", "Alive Uniques") : _("もう撃破したユニーク・モンスター", "Dead Uniques");
177     (void)show_file(player_ptr, true, file_name, title_desc, 0, 0);
178     fd_kill(file_name);
179 }