diff --git a/src/strings.cpp b/src/strings.cpp index ce2e51fc7b..39196ac541 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -331,6 +331,16 @@ void SetDParamStr(size_t n, std::string str) _global_string_params.SetParam(n, std::move(str)); } +/** + * This function is used to "bind" the SubStringWithParameters to a OpenTTD dparam slot. + * @param n slot of the string + * @param sub_string SubStringWithParameters to bind + */ +void SetDParamSubString(size_t n, const SubStringWithParameters &sub_string) +{ + _global_string_params.SetParam(n, sub_string); +} + /** * Format a number into a string. * @param buff the buffer to write to @@ -1119,6 +1129,18 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters &arg continue; } + auto handle_substring = [&]() -> bool { + if (!args.HasNextParameterSubString()) return false; + + const SubStringWithParameters &sub_string = args.GetNextParameterSubString(); + + if (game_script && GetStringTab(sub_string.string_id) != TEXT_TAB_GAMESCRIPT_START) return true; + StringParameters sub_args(sub_string); + buff = GetStringWithArgs(buff, sub_string.string_id, sub_args, last, next_substr_case_index, game_script); + next_substr_case_index = 0; + return true; + }; + args.SetTypeOfNextParameter(b); switch (b) { case SCC_ENCODED: { @@ -1313,6 +1335,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters &arg } case SCC_STRING: {// {STRING} + if (handle_substring()) break; StringID string_id = args.GetNextParameter(); if (game_script && GetStringTab(string_id) != TEXT_TAB_GAMESCRIPT_START) break; /* It's prohibited for the included string to consume any arguments. */ @@ -1330,6 +1353,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters &arg case SCC_STRING6: case SCC_STRING7: case SCC_STRING8: { // {STRING1..8} + if (handle_substring()) break; /* Strings that consume arguments */ StringID string_id = args.GetNextParameter(); if (game_script && GetStringTab(string_id) != TEXT_TAB_GAMESCRIPT_START) break; diff --git a/src/strings_func.h b/src/strings_func.h index 7e2ceb8c68..e730d27dcd 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -105,6 +105,8 @@ void SetDParamMaxDigits(size_t n, uint count, FontSize size = FS_NORMAL); void SetDParamStr(size_t n, const char *str); void SetDParamStr(size_t n, std::string str); +void SetDParamSubString(size_t n, const SubStringWithParameters &sub_string); + void CopyInDParam(const span backup, uint offset = 0); void CopyOutDParam(std::vector &backup, size_t num); bool HaveDParamChanged(const std::vector &backup); diff --git a/src/strings_internal.h b/src/strings_internal.h index 4933447e12..13cc90c35f 100644 --- a/src/strings_internal.h +++ b/src/strings_internal.h @@ -20,9 +20,17 @@ struct StringParameter; +/** The data representing a string ID with associated parameters, which can be used as a string parameter. */ +struct SubStringWithParameters { + StringID string_id; + span parameters; + + SubStringWithParameters(StringID string_id, span parameters) : string_id(string_id), parameters(parameters) {} +}; + /** The data required to format and validate a single parameter of a string. */ struct StringParameter { - std::variant> data; ///< The data of the parameter, non-owning string value, or owned string value. + std::variant, std::unique_ptr> data; ///< The data of the parameter, non-owning string value, owned string value, or nested parameter span. char32_t type; ///< The #StringControlCode to interpret this data with when it's the first parameter, otherwise '\0'. }; @@ -50,6 +58,15 @@ public: parameters(parent.parameters.subspan(parent.offset, size)) {} + StringParameters(const SubStringWithParameters &sub_string) : + parameters(sub_string.parameters) + {} + + SubStringWithParameters AsSubStringWithParameters(StringID string_id) const + { + return SubStringWithParameters(string_id, this->parameters); + } + void PrepareForNextRun(); void SetTypeOfNextParameter(char32_t type) { this->next_type = type; } @@ -122,6 +139,16 @@ public: } } + const SubStringWithParameters &GetNextParameterSubString() + { + return *std::get>(GetNextParameterPointer()->data); + } + + bool HasNextParameterSubString() const + { + return this->offset < this->parameters.size() && std::holds_alternative>(this->parameters[this->offset].data); + } + /** * Get a new instance of StringParameters that is a "range" into the * remaining existing parameters. Upon destruction the offset in the parent @@ -184,10 +211,10 @@ public: this->parameters[n].data = std::make_unique(std::move(str)); } - void SetParam(size_t n, span params) + void SetParam(size_t n, const SubStringWithParameters &sub_string) { assert(n < this->parameters.size()); - this->parameters[n].data = params; + this->parameters[n].data = std::make_unique(sub_string);; } uint64_t GetParam(size_t n) const