#include "info-reader/artifact-reader.h"
+#include "artifact/random-art-effects.h"
+#include "info-reader/info-reader-util.h"
#include "info-reader/kind-info-tokens-table.h"
+#include "info-reader/parse-error-types.h"
#include "main/angband-headers.h"
#include "object-enchant/tr-types.h"
#include "system/artifact-type-definition.h"
#include "util/bit-flags-calculator.h"
+#include "util/enum-converter.h"
#include "util/string-processor.h"
#include "view/display-messages.h"
-#include <string>
/*!
* @brief テキストトークンを走査してフラグを一つ得る(アーティファクト用) /
* Grab one activation index flag
* @param a_ptr 保管先のアーティファクト構造体参照ポインタ
* @param what 参照元の文字列ポインタ
- * @return エラーがあった場合1、エラーがない場合0を返す
+ * @return 見つかったらtrue
*/
-static errr grab_one_artifact_flag(artifact_type *a_ptr, concptr what)
+static bool grab_one_artifact_flag(ArtifactType *a_ptr, std::string_view what)
{
- if (k_info_flags.find(what) != k_info_flags.end()) {
- add_flag(a_ptr->flags, k_info_flags[what]);
- return 0;
+ if (TrFlags::grab_one_flag(a_ptr->flags, k_info_flags, what)) {
+ return true;
}
- if (EnumClassFlagGroup<TRG>::grab_one_flag(a_ptr->gen_flags, k_info_gen_flags, what))
- return 0;
+ if (EnumClassFlagGroup<ItemGenerationTraitType>::grab_one_flag(a_ptr->gen_flags, k_info_gen_flags, what)) {
+ return true;
+ }
- msg_format(_("未知の伝説のアイテム・フラグ '%s'。", "Unknown artifact flag '%s'."), what);
- return 1;
+ msg_format(_("未知の伝説のアイテム・フラグ '%s'。", "Unknown artifact flag '%s'."), what.data());
+ return false;
}
/*!
* @param head ヘッダ構造体
* @return エラーコード
*/
-errr parse_a_info(char *buf, angband_header *head)
+errr parse_a_info(std::string_view buf, angband_header *)
{
- static artifact_type *a_ptr = NULL;
- char *s, *t;
- if (buf[0] == 'N') {
- s = angband_strchr(buf + 2, ':');
- if (!s)
- return 1;
+ static ArtifactType *a_ptr = nullptr;
+ const auto &tokens = str_split(buf, ':', false, 10);
- *s++ = '\0';
-#ifdef JP
- if (!*s)
- return 1;
-#endif
- int i = atoi(buf + 2);
- if (i < error_idx)
- return 4;
- if (i >= head->info_num)
- return 2;
+ if (tokens[0] == "N") {
+ // N:index:name_ja
+ if (tokens.size() < 3 || tokens[1].size() == 0) {
+ return PARSE_ERROR_GENERIC;
+ }
+
+ auto i = std::stoi(tokens[1]);
+ if (i < error_idx) {
+ return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
+ }
+ if (i >= static_cast<int>(a_info.size())) {
+ a_info.resize(i + 1);
+ }
error_idx = i;
a_ptr = &a_info[i];
- add_flag(a_ptr->flags, TR_IGNORE_ACID);
- add_flag(a_ptr->flags, TR_IGNORE_ELEC);
- add_flag(a_ptr->flags, TR_IGNORE_FIRE);
- add_flag(a_ptr->flags, TR_IGNORE_COLD);
+ a_ptr->idx = i2enum<FixedArtifactId>(i);
+ a_ptr->flags.set(TR_IGNORE_ACID);
+ a_ptr->flags.set(TR_IGNORE_ELEC);
+ a_ptr->flags.set(TR_IGNORE_FIRE);
+ a_ptr->flags.set(TR_IGNORE_COLD);
+
#ifdef JP
- a_ptr->name = std::string(s);
+ a_ptr->name = tokens[2];
#endif
} else if (!a_ptr) {
- return 3;
- }
-#ifdef JP
- /* 英語名を読むルーチンを追加 */
- /* 'E' から始まる行は英語名としている */
- else if (buf[0] == 'E') {
- /* nothing to do */
- }
-#else
- else if (buf[0] == 'E') {
- s = buf + 2;
- a_ptr->name = std::string(s);
- }
+ return PARSE_ERROR_MISSING_RECORD_HEADER;
+ } else if (tokens[0] == "E") {
+ // E:name_en
+#ifndef JP
+ if (tokens[1].size() == 0) {
+ return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+ }
+ a_ptr->name = tokens[1];
#endif
- else if (buf[0] == 'D') {
+ } else if (tokens[0] == "D") {
+ // D:JapaneseText
+ // D:$EnglishText
+ if (tokens.size() < 2 || tokens[1].size() == 0) {
+ return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
+ }
#ifdef JP
- if (buf[2] == '$')
- return 0;
- s = buf + 2;
+ if (tokens[1][0] == '$') {
+ return PARSE_ERROR_NONE;
+ }
+ a_ptr->text.append(buf.substr(2));
#else
- if (buf[2] != '$')
- return 0;
- s = buf + 3;
+ if (tokens[1][0] != '$') {
+ return PARSE_ERROR_NONE;
+ }
+ append_english_text(a_ptr->text, buf.substr(3));
#endif
- a_ptr->text.append(s);
- } else if (buf[0] == 'I') {
- int tval, sval, pval;
- if (3 != sscanf(buf + 2, "%d:%d:%d", &tval, &sval, &pval))
- return 1;
+ } else if (tokens[0] == "I") {
+ // I:tval:sval:pval
+ if (tokens.size() < 4) {
+ return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+ }
- a_ptr->tval = (tval_type)tval;
- a_ptr->sval = (OBJECT_SUBTYPE_VALUE)sval;
- a_ptr->pval = (PARAMETER_VALUE)pval;
- } else if (buf[0] == 'W') {
- int level, rarity, wgt;
- long cost;
- if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", &level, &rarity, &wgt, &cost))
- return 1;
+ info_set_value(a_ptr->tval, tokens[1]);
+ info_set_value(a_ptr->sval, tokens[2]);
+ info_set_value(a_ptr->pval, tokens[3]);
+ } else if (tokens[0] == "W") {
+ // W:level:ratiry:weight:cost
+ if (tokens.size() < 5) {
+ return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+ }
- a_ptr->level = (DEPTH)level;
- a_ptr->rarity = (RARITY)rarity;
- a_ptr->weight = (WEIGHT)wgt;
- a_ptr->cost = (PRICE)cost;
- } else if (buf[0] == 'P') {
- int ac, hd1, hd2, th, td, ta;
- if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", &ac, &hd1, &hd2, &th, &td, &ta))
- return 1;
+ info_set_value(a_ptr->level, tokens[1]);
+ info_set_value(a_ptr->rarity, tokens[2]);
+ info_set_value(a_ptr->weight, tokens[3]);
+ info_set_value(a_ptr->cost, tokens[4]);
+ } else if (tokens[0] == "P") {
+ // P:ac:dd:ds:to_h:to_d:to_a
+ if (tokens.size() < 6) {
+ return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+ }
- a_ptr->ac = (ARMOUR_CLASS)ac;
- a_ptr->dd = (DICE_NUMBER)hd1;
- a_ptr->ds = (DICE_SID)hd2;
- a_ptr->to_h = (HIT_PROB)th;
- a_ptr->to_d = (HIT_POINT)td;
- a_ptr->to_a = (ARMOUR_CLASS)ta;
- } else if (buf[0] == 'U') {
- byte n;
- n = grab_one_activation_flag(buf + 2);
- if (n > 0) {
- a_ptr->act_idx = n;
- } else {
- return 5;
+ const auto &dice = str_split(tokens[2], 'd', false, 2);
+ if (dice.size() != 2) {
+ return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
}
- } else if (buf[0] == 'F') {
- for (s = buf + 2; *s;) {
- /* loop */
- for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
- ;
- if (*t) {
- *t++ = '\0';
- while ((*t == ' ') || (*t == '|'))
- t++;
- }
+ info_set_value(a_ptr->ac, tokens[1]);
+ info_set_value(a_ptr->dd, dice[0]);
+ info_set_value(a_ptr->ds, dice[1]);
+ info_set_value(a_ptr->to_h, tokens[3]);
+ info_set_value(a_ptr->to_d, tokens[4]);
+ info_set_value(a_ptr->to_a, tokens[5]);
+ } else if (tokens[0] == "U") {
+ // U:activation_flag
+ if (tokens.size() < 2 || tokens[1].size() == 0) {
+ return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+ }
+ auto n = grab_one_activation_flag(tokens[1].c_str());
+ if (n <= RandomArtActType::NONE) {
+ return PARSE_ERROR_INVALID_FLAG;
+ }
- if (0 != grab_one_artifact_flag(a_ptr, s))
- return 5;
+ a_ptr->act_idx = n;
+ } else if (tokens[0] == "F") {
+ // F:flags
+ if (tokens.size() < 2 || tokens[1].size() == 0) {
+ return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+ }
- s = t;
+ const auto &flags = str_split(tokens[1], '|', true, 10);
+ for (const auto &f : flags) {
+ if (f.size() == 0) {
+ continue;
+ }
+ if (!grab_one_artifact_flag(a_ptr, f)) {
+ return PARSE_ERROR_INVALID_FLAG;
+ }
}
} else {
- return 6;
+ return PARSE_ERROR_UNDEFINED_DIRECTIVE;
}
- return 0;
+ return PARSE_ERROR_NONE;
}