OSDN Git Service

Merge branch 'master' of https://github.com/hengband/hengband
[hengbandforosx/hengbandosx.git] / src / wizard / fixed-artifacts-spoiler.cpp
1 #include "wizard/fixed-artifacts-spoiler.h"
2 #include "io/files-util.h"
3 #include "system/angband-system.h"
4 #include "system/artifact-type-definition.h"
5 #include "system/item-entity.h"
6 #include "system/player-type-definition.h"
7 #include "util/angband-files.h"
8 #include "view/display-messages.h"
9 #include "wizard/artifact-analyzer.h"
10 #include "wizard/spoiler-util.h"
11 #include <sstream>
12
13 /*!
14  * @brief フラグ名称を出力する汎用関数
15  * @param header ヘッダに出力するフラグ群の名前
16  * @param descriptions フラグ名リスト
17  * @param separator フラグ表示の区切り記号
18  */
19 void spoiler_outlist(std::string_view header, const std::vector<std::string> &descriptions, char separator, std::ofstream &ofs)
20 {
21     if (descriptions.empty()) {
22         return;
23     }
24
25     std::stringstream line;
26     line << spoiler_indent;
27     if (!header.empty()) {
28         line << header << " ";
29     }
30
31     std::stringstream ss;
32     ss << list_separator << ' ';
33     const auto last_separator = ss.str();
34     for (size_t i = 0; i < descriptions.size(); i++) {
35         std::stringstream element;
36         element << descriptions[i];
37         if (i < descriptions.size() - 1) {
38             element << separator << ' ';
39         }
40
41         const auto element_str = element.str();
42         const int line_length = line.tellp();
43         constexpr auto max_line_length = 75;
44         if (line_length + element_str.length() <= max_line_length) {
45             line << element_str;
46             continue;
47         }
48
49         const auto line_str = line.str();
50         if (line_str.ends_with(last_separator)) {
51             ofs << std::string_view(line_str).substr(0, line_str.length() - 2) << '\n';
52             line.str("");
53             line.clear(std::stringstream::goodbit);
54             line << spoiler_indent << element_str;
55         } else {
56             ofs << line_str << '\n';
57             line.str("");
58             line.clear(std::stringstream::goodbit);
59             line << "      " << element_str;
60         }
61     }
62
63     ofs << line.str() << '\n';
64 }
65
66 /*!
67  * @brief アーティファクト情報を出力するためにダミー生成を行う
68  * @param fa_id 生成するアーティファクトID
69  * @return 生成したアーティファクト (連番で埋まっているので不存在例外は吐かない)
70  */
71 static ItemEntity make_fake_artifact(FixedArtifactId fa_id)
72 {
73     const auto &artifact = ArtifactList::get_instance().get_artifact(fa_id);
74     ItemEntity item(artifact.bi_key);
75     item.fa_id = fa_id;
76     item.pval = artifact.pval;
77     item.ac = artifact.ac;
78     item.damage_dice = artifact.damage_dice;
79     item.to_a = artifact.to_a;
80     item.to_h = artifact.to_h;
81     item.to_d = artifact.to_d;
82     item.weight = artifact.weight;
83     return item;
84 }
85
86 /*!
87  * @brief アーティファクト一件をスポイラー出力する /
88  * Create a spoiler file entry for an artifact
89  * @param art_ptr アーティファクト情報をまとめた構造体の参照ポインタ
90  */
91 static void spoiler_print_art(const ArtifactsDumpInfo *art_ptr, std::ofstream &ofs)
92 {
93     const auto *pval_ptr = &art_ptr->pval_info;
94     ofs << art_ptr->description << '\n';
95     if (!pval_ptr->pval_desc.empty()) {
96         std::stringstream ss;
97         ss << pval_ptr->pval_desc << _("の修正:", " to");
98         spoiler_outlist(ss.str(), pval_ptr->pval_affects, item_separator, ofs);
99     }
100
101     spoiler_outlist(_("対:", "Slay"), art_ptr->slays, item_separator, ofs);
102     spoiler_outlist(_("武器属性:", ""), art_ptr->brands, list_separator, ofs);
103     spoiler_outlist(_("免疫:", "Immunity to"), art_ptr->immunities, item_separator, ofs);
104     spoiler_outlist(_("耐性:", "Resist"), art_ptr->resistances, item_separator, ofs);
105     spoiler_outlist(_("弱点:", "Vulnerable"), art_ptr->vulnerabilities, item_separator, ofs);
106     spoiler_outlist(_("維持:", "Sustain"), art_ptr->sustenances, item_separator, ofs);
107     spoiler_outlist("", art_ptr->misc_magic, list_separator, ofs);
108
109     if (!art_ptr->addition.empty()) {
110         ofs << format(_("%s追加: %s\n", "%sAdditional %s\n"), spoiler_indent.data(), art_ptr->addition.data());
111     }
112
113     if (!art_ptr->activation.empty()) {
114         ofs << format(_("%s発動: %s\n", "%sActivates for %s\n"), spoiler_indent.data(), art_ptr->activation.data());
115     }
116
117     ofs << format("%s%s\n\n", spoiler_indent.data(), art_ptr->misc_desc.data());
118 }
119
120 /*!
121  * @brief アーティファクト情報のスポイラー出力を行うメインルーチン
122  * @details エラーコードと実際のエラー処理が不一致だが、後でまとめて修正する.
123  */
124 SpoilerOutputResultType spoil_fixed_artifact()
125 {
126     const auto path = path_build(ANGBAND_DIR_USER, "artifact.txt");
127     std::ofstream ofs(path);
128     if (!ofs) {
129         return SpoilerOutputResultType::FILE_OPEN_FAILED;
130     }
131
132     std::stringstream ss;
133     ss << "Artifact Spoilers for Hengband Version " << AngbandSystem::get_instance().build_version_expression(VersionExpression::FULL);
134     spoiler_underline(ss.str(), ofs);
135     for (const auto &[tval_list, name] : group_artifact_list) {
136         spoiler_blanklines(2, ofs);
137         spoiler_underline(name, ofs);
138         spoiler_blanklines(1, ofs);
139
140         for (auto tval : tval_list) {
141             for (const auto &[fa_id, artifact] : ArtifactList::get_instance()) {
142                 if (artifact.bi_key.tval() != tval) {
143                     continue;
144                 }
145
146                 const auto item = make_fake_artifact(fa_id);
147                 PlayerType dummy;
148                 const auto artifacts_list = object_analyze(&dummy, &item);
149                 spoiler_print_art(&artifacts_list, ofs);
150             }
151         }
152     }
153
154     return ofs.good() ? SpoilerOutputResultType::SUCCESSFUL : SpoilerOutputResultType::FILE_CLOSE_FAILED;
155 }