From 3a71f363937a6cdd65183aecd26638eb7316380b Mon Sep 17 00:00:00 2001 From: glx22 Date: Fri, 1 Mar 2024 19:10:35 +0100 Subject: [PATCH] Change: [Script] Match FormatString behaviour more closely --- src/script/api/script_text.cpp | 88 +++++++++++++++++++++------------- src/script/api/script_text.hpp | 5 +- 2 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index 83869e1216..cff3d4dfd3 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -184,10 +184,19 @@ void ScriptText::_FillParamList(ParamList ¶ms, ScriptTextList &seen_texts) } seen_texts.pop_back(); + + /* Fill with dummy parameters to match FormatString() behaviour. */ + if (seen_texts.empty()) { + static Param dummy = 0; + int nb_extra = SCRIPT_TEXT_MAX_PARAMETERS - (int)params.size(); + for (int i = 0; i < nb_extra; i++) + params.emplace_back(-1, i, &dummy); + } } -void ScriptText::ParamCheck::Encode(std::back_insert_iterator &output) +void ScriptText::ParamCheck::Encode(std::back_insert_iterator &output, const char *cmd) { + if (this->cmd == nullptr) this->cmd = cmd; if (this->used) return; if (std::holds_alternative(*this->param)) fmt::format_to(output, ":\"{}\"", std::get(*this->param)); if (std::holds_alternative(*this->param)) fmt::format_to(output, ":{:X}", std::get(*this->param)); @@ -220,46 +229,57 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator &output, auto skip_args = [&](size_t nb) { idx += nb; }; for (const StringParam &cur_param : params) { - switch (cur_param.type) { - case StringParam::UNUSED: - skip_args(cur_param.consumes); - break; - - case StringParam::RAW_STRING: { - ParamCheck &p = *get_next_arg(); - p.Encode(output); - if (!std::holds_alternative(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd)); - break; - } + try { + switch (cur_param.type) { + case StringParam::UNUSED: + skip_args(cur_param.consumes); + break; - case StringParam::STRING: { - ParamCheck &p = *get_next_arg(); - p.Encode(output); - if (!std::holds_alternative(*p.param)){ - ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd)); + case StringParam::RAW_STRING: + { + ParamCheck &p = *get_next_arg(); + p.Encode(output, cur_param.cmd); + if (p.cmd != cur_param.cmd) throw 1; + if (!std::holds_alternative(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd)); break; } - int count = 0; - ScriptTextRef &ref = std::get(*p.param); - ref->_GetEncodedText(output, count, args.subspan(idx), false); - if (++count != cur_param.consumes) { - ScriptLog::Error(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1)); - /* Fill missing params if needed. */ - for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0"); - } - skip_args(cur_param.consumes - 1); - break; - } - default: - for (int i = 0; i < cur_param.consumes; i++) { + case StringParam::STRING: + { ParamCheck &p = *get_next_arg(); - p.Encode(output); - if (!std::holds_alternative(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd)); + p.Encode(output, cur_param.cmd); + if (p.cmd != cur_param.cmd) throw 1; + if (!std::holds_alternative(*p.param)) { + ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd)); + param_count++; + continue; + } + int count = 0; + ScriptTextRef &ref = std::get(*p.param); + ref->_GetEncodedText(output, count, args.subspan(idx), false); + if (++count != cur_param.consumes) { + ScriptLog::Warning(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1)); + /* Fill missing params if needed. */ + for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0"); + } + skip_args(cur_param.consumes - 1); + break; } - } - param_count += cur_param.consumes; + default: + for (int i = 0; i < cur_param.consumes; i++) { + ParamCheck &p = *get_next_arg(); + p.Encode(output, i == 0 ? cur_param.cmd : nullptr); + if (i == 0 && p.cmd != cur_param.cmd) throw 1; + if (!std::holds_alternative(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd)); + } + } + + param_count += cur_param.consumes; + } catch (int nb) { + param_count += nb; + ScriptLog::Warning(fmt::format("{}({}): Invalid parameter", name, param_count)); + } } } diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index 1b86f8f54b..dc9f1c1513 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -137,10 +137,11 @@ private: int idx; Param *param; bool used; + const char *cmd; - ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param), used(false) {} + ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param), used(false), cmd(nullptr) {} - void Encode(std::back_insert_iterator &output); + void Encode(std::back_insert_iterator &output, const char *cmd); }; using ParamList = std::vector;