From be8736ffaaaf42cf9b72751227e703409b4b5a43 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 22 Nov 2020 23:17:40 +0000 Subject: [PATCH] Fix: #13509 [Plugin] Add ability to format strings --- distribution/changelog.txt | 1 + distribution/openrct2.d.ts | 7 ++++ src/openrct2/localisation/Formatting.cpp | 8 +++++ src/openrct2/localisation/Formatting.h | 2 +- src/openrct2/scripting/ScContext.hpp | 45 ++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index df096a268a..bbfc14c06c 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -5,6 +5,7 @@ - Feature: [#13376] Open custom window at specified tab. - Feature: [#13398] Add pause button to the Track Designer. - Feature: [#13495] [Plugin] Add properties for park value, guests and company value. +- Feature: [#13509] [Plugin] Add ability to format strings using OpenRCT2 string framework. - Change: [#13346] Change FootpathScenery to FootpathAddition in all occurrences. - Fix: [#12895] Mechanics are called to repair rides that have already been fixed. - Fix: [#13257] Rides that are exactly the minimum objective length are not counted. diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index d21f2e8b2b..63e770429c 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -183,6 +183,13 @@ declare global { */ getRandom(min: number, max: number): number; + /** + * Formats a new string using the given format string and the arguments. + * @param fmt The format string, e.g. "Guests: {COMMA16}" + * @param args The arguments to insert into the string. + */ + formatString(fmt: string, ...args: any[]): string; + /** * Registers a new game action that allows clients to interact with the game. * @param action The unique name of the action. diff --git a/src/openrct2/localisation/Formatting.cpp b/src/openrct2/localisation/Formatting.cpp index e8486e3308..78f464de9c 100644 --- a/src/openrct2/localisation/Formatting.cpp +++ b/src/openrct2/localisation/Formatting.cpp @@ -594,6 +594,10 @@ namespace OpenRCT2 { ss << arg.c_str(); } + else if constexpr (std::is_same()) + { + ss << arg.c_str(); + } break; case FormatToken::Sprite: if constexpr (std::is_integral()) @@ -663,6 +667,10 @@ namespace OpenRCT2 { FormatArgument(ss, token, std::get(value)); } + else if (std::holds_alternative(value)) + { + FormatArgument(ss, token, std::get(value)); + } else { throw std::runtime_error("No support for format argument type."); diff --git a/src/openrct2/localisation/Formatting.h b/src/openrct2/localisation/Formatting.h index 0f325a50cd..9b039abd92 100644 --- a/src/openrct2/localisation/Formatting.h +++ b/src/openrct2/localisation/Formatting.h @@ -23,7 +23,7 @@ namespace OpenRCT2 { - using FormatArg_t = std::variant; + using FormatArg_t = std::variant; class FmtString { diff --git a/src/openrct2/scripting/ScContext.hpp b/src/openrct2/scripting/ScContext.hpp index f109440432..d565c82f70 100644 --- a/src/openrct2/scripting/ScContext.hpp +++ b/src/openrct2/scripting/ScContext.hpp @@ -13,6 +13,7 @@ # include "../actions/GameAction.h" # include "../interface/Screenshot.h" +# include "../localisation/Formatting.h" # include "../object/ObjectManager.h" # include "../scenario/Scenario.h" # include "Duktape.hpp" @@ -154,6 +155,49 @@ namespace OpenRCT2::Scripting return min + scenario_rand_max(range); } + duk_ret_t formatString(duk_context* ctx) + { + auto nargs = duk_get_top(ctx); + if (nargs >= 1) + { + auto dukFmt = DukValue::copy_from_stack(ctx, 0); + if (dukFmt.type() == DukValue::Type::STRING) + { + FmtString fmt(dukFmt.as_string()); + + std::vector args; + for (duk_idx_t i = 1; i < nargs; i++) + { + auto dukArg = DukValue::copy_from_stack(ctx, i); + switch (dukArg.type()) + { + case DukValue::Type::NUMBER: + args.push_back(dukArg.as_int()); + break; + case DukValue::Type::STRING: + args.push_back(dukArg.as_string()); + break; + default: + duk_error(ctx, DUK_ERR_ERROR, "Invalid format argument."); + break; + } + } + + auto result = FormatStringAny(fmt, args); + duk_push_lstring(ctx, result.c_str(), result.size()); + } + else + { + duk_error(ctx, DUK_ERR_ERROR, "Invalid format string."); + } + } + else + { + duk_error(ctx, DUK_ERR_ERROR, "Invalid format string."); + } + return 1; + } + std::shared_ptr subscribe(const std::string& hook, const DukValue& callback) { auto& scriptEngine = GetContext()->GetScriptEngine(); @@ -289,6 +333,7 @@ namespace OpenRCT2::Scripting dukglue_register_method(ctx, &ScContext::getObject, "getObject"); dukglue_register_method(ctx, &ScContext::getAllObjects, "getAllObjects"); dukglue_register_method(ctx, &ScContext::getRandom, "getRandom"); + dukglue_register_method_varargs(ctx, &ScContext::formatString, "formatString"); dukglue_register_method(ctx, &ScContext::subscribe, "subscribe"); dukglue_register_method(ctx, &ScContext::queryAction, "queryAction"); dukglue_register_method(ctx, &ScContext::executeAction, "executeAction");