1 #include "wizard/monster-info-spoiler.h"
2 #include "io/files-util.h"
3 #include "monster-race/monster-race.h"
4 #include "monster-race/race-flags1.h"
5 #include "monster-race/race-flags7.h"
6 #include "monster-race/race-flags8.h"
7 #include "system/angband-version.h"
8 #include "system/monster-race-info.h"
9 #include "term/term-color-types.h"
10 #include "term/z-form.h"
11 #include "util/angband-files.h"
12 #include "util/bit-flags-calculator.h"
13 #include "util/sort.h"
14 #include "util/string-processor.h"
15 #include "view/display-lore.h"
16 #include "view/display-messages.h"
17 #include "wizard/spoiler-util.h"
20 * @brief シンボル職の記述名を返す /
21 * Extract a textual representation of an attribute
22 * @param r_ptr モンスター種族の構造体ポインタ
25 static concptr attr_to_text(MonsterRaceInfo *r_ptr)
27 if (r_ptr->visual_flags.has(MonsterVisualType::CLEAR_COLOR)) {
28 return _("透明な", "Clear");
31 if (r_ptr->visual_flags.has(MonsterVisualType::MULTI_COLOR)) {
32 return _("万色の", "Multi");
35 if (r_ptr->visual_flags.has(MonsterVisualType::RANDOM_COLOR)) {
36 return _("準ランダムな", "S.Rand");
39 switch (r_ptr->d_attr) {
41 return _("黒い", "Dark");
43 return _("白い", "White");
45 return _("青灰色の", "Slate");
47 return _("オレンジの", "Orange");
49 return _("赤い", "Red");
51 return _("緑の", "Green");
53 return _("青い", "Blue");
55 return _("琥珀色の", "Umber");
57 return _("灰色の", "L.Dark");
59 return _("明るい青灰色の", "L.Slate");
61 return _("紫の", "Violet");
63 return _("黄色の", "Yellow");
65 return _("明るい赤の", "L.Red");
67 return _("明るい緑の", "L.Green");
69 return _("明るい青の", "L.Blue");
71 return _("明るい琥珀色の", "L.Umber");
74 return _("変な色の", "Icky");
77 SpoilerOutputResultType spoil_mon_desc(std::string_view filename, std::function<bool(const MonsterRaceInfo *)> filter_monster)
81 const auto &path = path_build(ANGBAND_DIR_USER, filename);
82 std::ofstream ofs(path);
84 return SpoilerOutputResultType::FILE_OPEN_FAILED;
87 ofs << format("Monster Spoilers for %s\n", get_version().data());
88 ofs << "------------------------------------------\n\n";
89 ofs << format("%-45.45s%4s %4s %4s %7s %7s %19.19s\n", "Name", "Lev", "Rar", "Spd", "Hp", "Ac", "Visual Info");
90 ofs << format("%-45.45s%4s %4s %4s %7s %7s %4.19s\n",
91 "---------------------------------------------"
94 "---", "---", "---", "-----", "-----", "-------------------");
96 std::vector<MonsterRaceId> who;
97 for (const auto &[monrace_id, monrace] : monraces_info) {
98 if (MonsterRace(monrace_id).is_valid()) {
99 who.push_back(monrace_id);
103 ang_sort(&dummy, who.data(), &why, who.size(), ang_sort_comp_hook, ang_sort_swap_hook);
104 for (auto r_idx : who) {
105 auto *r_ptr = &monraces_info[r_idx];
106 if (filter_monster && !filter_monster(r_ptr)) {
110 if (r_ptr->misc_flags.has(MonsterMiscType::KAGE)) {
114 const auto name = str_separate(r_ptr->name, 40);
116 if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
118 } else if (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) {
121 nam = _(" ", "The ");
123 nam.append(name.front());
125 const auto lev = format("%d", r_ptr->level);
126 const auto rar = format("%d", (int)r_ptr->rarity);
127 const auto spd = format("%+d", r_ptr->speed - STANDARD_SPEED);
128 const auto ac = format("%d", r_ptr->ac);
130 if (r_ptr->misc_flags.has(MonsterMiscType::FORCE_MAXHP) || (r_ptr->hside == 1)) {
131 hp = format("%d", r_ptr->hdice * r_ptr->hside);
133 hp = format("%dd%d", r_ptr->hdice, r_ptr->hside);
136 const auto symbol = format("%s '%c'", attr_to_text(r_ptr), r_ptr->d_char);
137 ofs << format("%-45.45s%4s %4s %4s %7s %7s %19.19s\n",
138 nam.data(), lev.data(), rar.data(), spd.data(), hp.data(),
139 ac.data(), symbol.data());
141 for (auto i = 1U; i < name.size(); ++i) {
142 ofs << format(" %s\n", name[i].data());
147 return ofs.good() ? SpoilerOutputResultType::SUCCESSFUL : SpoilerOutputResultType::FILE_CLOSE_FAILED;
151 * @brief 関数ポインタ用の出力関数 /
152 * Hook function used in spoil_mon_info()
154 * @param str 文字列参照ポインタ
156 static void roff_func(TERM_COLOR attr, std::string_view str)
163 * @brief モンスター詳細情報をスポイラー出力するメインルーチン /
164 * Create a spoiler file for monsters (-SHAWN-)
167 SpoilerOutputResultType spoil_mon_info()
170 const auto &path = path_build(ANGBAND_DIR_USER, "mon-info.txt");
171 spoiler_file = angband_fopen(path, FileOpenMode::WRITE);
173 return SpoilerOutputResultType::FILE_OPEN_FAILED;
176 spoil_out(std::string("Monster Spoilers for ").append(get_version()).append("\n"));
177 spoil_out("------------------------------------------\n\n");
179 std::vector<MonsterRaceId> who;
180 for (const auto &[monrace_id, monrace] : monraces_info) {
181 if (MonsterRace(monrace_id).is_valid()) {
182 who.push_back(monrace_id);
187 ang_sort(&dummy, who.data(), &why, who.size(), ang_sort_comp_hook, ang_sort_swap_hook);
188 for (auto r_idx : who) {
189 auto *r_ptr = &monraces_info[r_idx];
190 if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
192 } else if (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) {
196 spoil_out(format(_("%s/%s (", "%s%s ("), r_ptr->name.data(), _(r_ptr->E_name.data(), ""))); /* ---)--- */
197 spoil_out(attr_to_text(r_ptr));
198 spoil_out(format(" '%c')\n", r_ptr->d_char));
200 spoil_out(format("Num:%d ", enum2i(r_idx)));
201 spoil_out(format("Lev:%d ", (int)r_ptr->level));
202 spoil_out(format("Rar:%d ", r_ptr->rarity));
203 spoil_out(format("Spd:%+d ", r_ptr->speed - STANDARD_SPEED));
204 if (r_ptr->misc_flags.has(MonsterMiscType::FORCE_MAXHP) || (r_ptr->hside == 1)) {
205 spoil_out(format("Hp:%d ", r_ptr->hdice * r_ptr->hside));
207 spoil_out(format("Hp:%dd%d ", r_ptr->hdice, r_ptr->hside));
210 spoil_out(format("Ac:%d ", r_ptr->ac));
211 spoil_out(format("Exp:%ld\n", (long)(r_ptr->mexp)));
212 output_monster_spoiler(r_idx, roff_func);
216 return ferror(spoiler_file) || angband_fclose(spoiler_file) ? SpoilerOutputResultType::FILE_CLOSE_FAILED
217 : SpoilerOutputResultType::SUCCESSFUL;