OSDN Git Service

[Refactor] #3453 spoiler_ident をconcptr からstring に変えた
[hengbandforosx/hengbandosx.git] / src / wizard / spoiler-util.cpp
1 #include "wizard/spoiler-util.h"
2 #include "object/object-flags.h"
3 #include "system/item-entity.h"
4
5 const char item_separator = ',';
6 const char list_separator = _(',', ';');
7 const int max_evolution_depth = 64;
8 const std::string spoiler_indent = "    ";
9
10 /* The spoiler file being created */
11 FILE *spoiler_file = nullptr;
12
13 /*!
14  * @brief 特性フラグ定義から表記すべき特性を抽出する
15  * @param art_flags 出力するアーティファクトの特性一覧
16  * @param definitions 表記対象の特性一覧
17  * @return 表記すべき特性一覧
18  */
19 std::vector<std::string> extract_spoiler_flags(const TrFlags &art_flags, const std::vector<flag_desc> &definitions)
20 {
21     std::vector<std::string> descriptions{};
22     for (const auto &definition : definitions) {
23         if (art_flags.has(definition.flag)) {
24             descriptions.push_back(definition.desc);
25         }
26     }
27
28     return descriptions;
29 }
30
31 /*!
32  * @brief ファイルポインタ先に同じ文字を複数出力する /
33  * Write out `n' of the character `c' to the spoiler file
34  * @param n 出力する数
35  * @param c 出力するキャラクタ
36  */
37 static void spoiler_out_n_chars(int n, char c)
38 {
39     while (--n >= 0) {
40         fputc(c, spoiler_file);
41     }
42 }
43
44 /*!
45  * @brief ファイルポインタ先に改行を複数出力する /
46  * Write out `n' blank lines to the spoiler file
47  * @param n 改行を出力する数
48  */
49 void spoiler_blanklines(int n)
50 {
51     spoiler_out_n_chars(n, '\n');
52 }
53
54 /*!
55  * @brief ファイルポインタ先に複数のハイフンで装飾した文字列を出力する /
56  * Write a line to the spoiler file and then "underline" it with hypens
57  * @param str 出力したい文字列
58  */
59 void spoiler_underline(concptr str)
60 {
61     fprintf(spoiler_file, "%s\n", str);
62     spoiler_out_n_chars(strlen(str), '-');
63     fprintf(spoiler_file, "\n");
64 }
65
66 /*!
67  * @brief 文字列をファイルポインタに出力する /
68  * Buffer text to the given file. (-SHAWN-)
69  * This is basically c_roff() from mon-desc.c with a few changes.
70  * @param sv 文字列
71  * @param flush_buffer trueならバッファの内容をフラッシュし、改行を書き込む。strは無視される。
72  */
73 void spoil_out(std::string_view sv, bool flush_buffer)
74 {
75     concptr r;
76     static char roff_buf[256]{};
77     static char roff_waiting_buf[256]{};
78
79 #ifdef JP
80     bool iskanji_flag = false;
81 #endif
82
83     static char *roff_p = roff_buf;
84     static char *roff_s = nullptr;
85     static bool waiting_output = false;
86     if (flush_buffer) {
87         if (waiting_output) {
88             fputs(roff_waiting_buf, spoiler_file);
89             waiting_output = false;
90         }
91
92         if (roff_p != roff_buf) {
93             roff_p--;
94         }
95         while (*roff_p == ' ' && roff_p != roff_buf) {
96             roff_p--;
97         }
98
99         if (roff_p == roff_buf) {
100             fprintf(spoiler_file, "\n");
101         } else {
102             *(roff_p + 1) = '\0';
103             fprintf(spoiler_file, "%s\n\n", roff_buf);
104         }
105
106         roff_p = roff_buf;
107         roff_s = nullptr;
108         roff_buf[0] = '\0';
109         return;
110     }
111
112     for (auto str = sv.data(); *str != '\0'; ++str) {
113 #ifdef JP
114         char cbak;
115         bool k_flag = iskanji((unsigned char)(*str));
116 #endif
117         char ch = *str;
118         bool wrap = (ch == '\n');
119
120 #ifdef JP
121         if (!isprint((unsigned char)ch) && !k_flag && !iskanji_flag) {
122             ch = ' ';
123         }
124
125         iskanji_flag = k_flag && !iskanji_flag;
126 #else
127         if (!isprint(ch)) {
128             ch = ' ';
129         }
130 #endif
131
132         if (waiting_output) {
133             fputs(roff_waiting_buf, spoiler_file);
134             if (!wrap) {
135                 fputc('\n', spoiler_file);
136             }
137
138             waiting_output = false;
139         }
140
141         if (!wrap) {
142 #ifdef JP
143             if (roff_p >= roff_buf + (iskanji_flag ? 74 : 75)) {
144                 wrap = true;
145             } else if ((ch == ' ') && (roff_p >= roff_buf + (iskanji_flag ? 72 : 73))) {
146                 wrap = true;
147             }
148 #else
149             if (roff_p >= roff_buf + 75) {
150                 wrap = true;
151             } else if ((ch == ' ') && (roff_p >= roff_buf + 73)) {
152                 wrap = true;
153             }
154 #endif
155
156             if (wrap) {
157 #ifdef JP
158                 bool k_flag_local;
159                 bool iskanji_flag_local = false;
160                 concptr tail = str + (iskanji_flag ? 2 : 1);
161 #else
162                 concptr tail = str + 1;
163 #endif
164
165                 for (; *tail; tail++) {
166                     if (*tail == ' ') {
167                         continue;
168                     }
169
170 #ifdef JP
171                     k_flag_local = iskanji((unsigned char)(*tail));
172                     if (isprint((unsigned char)*tail) || k_flag_local || iskanji_flag_local) {
173                         break;
174                     }
175
176                     iskanji_flag_local = k_flag_local && !iskanji_flag_local;
177 #else
178                     if (isprint(*tail)) {
179                         break;
180                     }
181 #endif
182                 }
183
184                 if (!*tail) {
185                     waiting_output = true;
186                 }
187             }
188         }
189
190         if (wrap) {
191             *roff_p = '\0';
192             r = roff_p;
193 #ifdef JP
194             cbak = ' ';
195 #endif
196             if (roff_s && (ch != ' ')) {
197 #ifdef JP
198                 cbak = *roff_s;
199 #endif
200                 *roff_s = '\0';
201                 r = roff_s + 1;
202             }
203
204             if (!waiting_output) {
205                 fprintf(spoiler_file, "%s\n", roff_buf);
206             } else {
207                 strcpy(roff_waiting_buf, roff_buf);
208             }
209
210             roff_s = nullptr;
211             roff_p = roff_buf;
212 #ifdef JP
213             if (cbak != ' ') {
214                 *roff_p++ = cbak;
215             }
216 #endif
217             while (*r) {
218                 *roff_p++ = *r++;
219             }
220         }
221
222         if ((roff_p <= roff_buf) && (ch == ' ')) {
223             continue;
224         }
225
226 #ifdef JP
227         if (!k_flag) {
228             if ((ch == ' ') || (ch == '(')) {
229                 roff_s = roff_p;
230             }
231         } else {
232             if (iskanji_flag && strncmp(str, "。", 2) != 0 && strncmp(str, "、", 2) != 0 && strncmp(str, "ィ", 2) != 0 && strncmp(str, "ー", 2) != 0) {
233                 roff_s = roff_p;
234             }
235         }
236 #else
237         if (ch == ' ') {
238             roff_s = roff_p;
239         }
240 #endif
241
242         *roff_p++ = ch;
243     }
244 }
245
246 void ParameterValueInfo::analyze(const ItemEntity &item)
247 {
248     if (item.pval == 0) {
249         return;
250     }
251
252     auto flags = object_flags(&item);
253     this->pval_desc = format("%+d", item.pval);
254     if (flags.has_all_of(EnumRange(TR_STR, TR_CHR))) {
255         this->pval_affects.push_back(_("全能力", "All stats"));
256     } else if (flags.has_any_of(EnumRange(TR_STR, TR_CHR))) {
257         const auto descriptions_stat = extract_spoiler_flags(flags, stat_flags_desc);
258         this->pval_affects.insert(this->pval_affects.end(), descriptions_stat.begin(), descriptions_stat.end());
259     }
260
261     const auto descriptions_pval1 = extract_spoiler_flags(flags, pval_flags1_desc);
262     this->pval_affects.insert(this->pval_affects.end(), descriptions_pval1.begin(), descriptions_pval1.end());
263 }