1 #include "wizard/spoiler-util.h"
2 #include "system/item-entity.h"
5 const char item_separator = ',';
6 const char list_separator = _(',', ';');
7 const int max_evolution_depth = 64;
8 const std::string spoiler_indent = " ";
10 /* The spoiler file being created */
11 FILE *spoiler_file = nullptr;
14 * @brief 特性フラグ定義から表記すべき特性を抽出する
15 * @param art_flags 出力するアーティファクトの特性一覧
16 * @param definitions 表記対象の特性一覧
19 std::vector<std::string> extract_spoiler_flags(const TrFlags &art_flags, const std::vector<flag_desc> &definitions)
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);
32 * @brief ファイルポインタ先に同じ文字を複数出力する /
33 * Write out `n' of the character `c' to the spoiler file
37 static void spoiler_out_n_chars(int n, char c, std::ofstream &ofs)
39 for (auto i = 0; i < n; i++) {
45 * @brief ファイルポインタ先に改行を複数出力する /
46 * Write out `n' blank lines to the spoiler file
49 void spoiler_blanklines(int n, std::ofstream &ofs)
51 spoiler_out_n_chars(n, '\n', ofs);
55 * @brief ファイルポインタ先に複数のハイフンで装飾した文字列を出力する /
56 * Write a line to the spoiler file and then "underline" it with hypens
59 void spoiler_underline(std::string_view str, std::ofstream &ofs)
61 ofs << str.data() << '\n';
62 spoiler_out_n_chars(str.length(), '-', ofs);
67 * @brief 文字列をファイルポインタに出力する /
68 * Buffer text to the given file. (-SHAWN-)
69 * This is basically c_roff() from mon-desc.c with a few changes.
71 * @param flush_buffer trueならバッファの内容をフラッシュし、改行を書き込む。strは無視される。
73 void spoil_out(std::string_view sv, bool flush_buffer)
76 static char roff_buf[256]{};
77 static char roff_waiting_buf[256]{};
80 bool iskanji_flag = false;
83 static char *roff_p = roff_buf;
84 static char *roff_s = nullptr;
85 static bool waiting_output = false;
88 fputs(roff_waiting_buf, spoiler_file);
89 waiting_output = false;
92 if (roff_p != roff_buf) {
95 while (*roff_p == ' ' && roff_p != roff_buf) {
99 if (roff_p == roff_buf) {
100 fprintf(spoiler_file, "\n");
102 *(roff_p + 1) = '\0';
103 fprintf(spoiler_file, "%s\n\n", roff_buf);
112 for (auto str = sv.data(); *str != '\0'; ++str) {
115 bool k_flag = iskanji((unsigned char)(*str));
118 bool wrap = (ch == '\n');
121 if (!isprint((unsigned char)ch) && !k_flag && !iskanji_flag) {
125 iskanji_flag = k_flag && !iskanji_flag;
132 if (waiting_output) {
133 fputs(roff_waiting_buf, spoiler_file);
135 fputc('\n', spoiler_file);
138 waiting_output = false;
143 if (roff_p >= roff_buf + (iskanji_flag ? 74 : 75)) {
145 } else if ((ch == ' ') && (roff_p >= roff_buf + (iskanji_flag ? 72 : 73))) {
149 if (roff_p >= roff_buf + 75) {
151 } else if ((ch == ' ') && (roff_p >= roff_buf + 73)) {
159 bool iskanji_flag_local = false;
160 concptr tail = str + (iskanji_flag ? 2 : 1);
162 concptr tail = str + 1;
165 for (; *tail; tail++) {
171 k_flag_local = iskanji((unsigned char)(*tail));
172 if (isprint((unsigned char)*tail) || k_flag_local || iskanji_flag_local) {
176 iskanji_flag_local = k_flag_local && !iskanji_flag_local;
178 if (isprint(*tail)) {
185 waiting_output = true;
196 if (roff_s && (ch != ' ')) {
204 if (!waiting_output) {
205 fprintf(spoiler_file, "%s\n", roff_buf);
207 strcpy(roff_waiting_buf, roff_buf);
222 if ((roff_p <= roff_buf) && (ch == ' ')) {
228 if ((ch == ' ') || (ch == '(')) {
232 if (iskanji_flag && strncmp(str, "。", 2) != 0 && strncmp(str, "、", 2) != 0 && strncmp(str, "ィ", 2) != 0 && strncmp(str, "ー", 2) != 0) {
246 void ParameterValueInfo::analyze(const ItemEntity &item)
248 if (item.pval == 0) {
252 auto flags = item.get_flags();
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());
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());