game: add ${[type:]var} string replacements for scripts

This commit is contained in:
Crypto City 2020-11-25 13:53:55 +00:00
parent fd38e8a202
commit 302a26c299
12 changed files with 152 additions and 43 deletions

View File

@ -7,7 +7,7 @@ TBLayout: axis: x, size: "available", distribution: "gravity", skin: "script-row
TBTextField: id: "name", text-align: "left", gravity: "left right"
TBButton: id: "view-source", text: "View source"
TBWidget: gravity: "left right"
TBToggleContainer: id: "details-container", toggle: "expanded", value: 0
TBToggleContainer: id: "details-container", toggle: "expanded", value: 1
TBEditField: id: "desc", text: "", multiline: 0, readonly: 1, adapt-to-content: 1, is-focusable: 0, skin: "TBEditField.script-description", gravity: "left right"
TBToggleContainer: id: "available-container", toggle: "expanded", value: 1, gravity: "right"
TBLayout: axis: y

View File

@ -1,9 +1,12 @@
#include <memory>
#include <boost/regex.hpp>
#include "reg_exp_definer.h"
#include "cc/cc_discoveries.h"
#include "cc/cc_food.h"
#include "cc/cc_script.h"
#include "cc/cc_special_events.h"
#include "cc/cc_city_specialization.h"
#include "cc/cc_temperature.h"
#include "game-state.h"
#include "game-wallet.h"
#include "game-util.h"
@ -196,4 +199,75 @@ int32_t get_crop_yield(const GameState *game, const std::shared_ptr<GameWallet>
return cc::get_crop_yield(crop, CROP_START_YIELD, temperatures, frost_resistant_vegetables, fast_frost_damage_recovery);
}
static void replace_string(std::string &s, size_t start, size_t len, const std::string &replacement)
{
s = s.substr(0, start) + replacement + s.substr(start + len);
}
void process_overrides(const GameState *game, std::string &s, const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides, bool in_script)
{
TRY_ENTRY();
STATIC_REGEXP_EXPR_1(rexp_match_vars, "\\${([a-z]+:)?([^\"}\r\n]+)}", boost::regex::icase | boost::regex::normal);
boost::smatch result; // 1 2
unsigned max_loops = 32;
while (boost::regex_search(s, result, rexp_match_vars, boost::match_default) && result[0].matched && max_loops-- > 0)
{
const std::string &local = result[2];
char *endptr = NULL;
unsigned long long idx = strtoull(local.c_str(), &endptr, 10);
if (endptr && *endptr)
{
// not a number, but a local var
uint64_t value = 0;
if (in_script)
{
const auto i = game->playerState.script_local_variables.find(local);
if (i != game->playerState.script_local_variables.end())
value = i->second;
}
else
{
for (const auto &e: overrides)
{
if (std::get<0>(e) == cc::script::override_local && local == std::get<2>(e))
{
value = std::get<1>(e);
break;
}
}
}
std::string replacement;
if (result[1].matched)
{
if (result[1] == "gold:")
replacement = cryptonote::print_money(value);
else if (result[1] == "item:")
replacement = game->get_item_name(value);
else if (result[1] == "temperature:")
replacement = cc::print_temperature(value);
else
replacement = std::to_string(value);
}
else
replacement = std::to_string(value);
replace_string(s, result.position(), result.length(), replacement);
}
else
{
for (const auto &e: overrides)
{
if (std::get<0>(e) == cc::script::override_string && idx == std::get<1>(e))
{
replace_string(s, result.position(), result.length(), std::get<2>(e));
break;
}
}
}
}
CATCH_ENTRY_L0("ProcessOverrides", void());
}
}

View File

@ -17,5 +17,6 @@ std::string get_building_name(const GameState *game, const std::shared_ptr<Flag>
std::string get_building_name(const GameState *game, uint32_t flag_id);
std::string get_command_string(const GameState *game, const cryptonote::cc_command_t &cmd);
int32_t get_crop_yield(const GameState *game, const std::shared_ptr<GameWallet> &w, uint8_t crop, uint64_t sow_height, uint8_t geothermal_heating, bool frost_resistant_vegetables, bool fast_frost_damage_recovery);
void process_overrides(const GameState *game, std::string &s, const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides, bool in_script);
}

View File

@ -352,7 +352,7 @@ public:
bool get_invitation_status(const std::string &pkey, bool &used, bool &balance_ok) const;
bool generate_invitation(uint64_t amount, uint64_t expiration, std::string &invitation) const;
std::vector<uint64_t> get_item_count(const std::vector<uint32_t> &id) const;
bool get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> &scripts, uint32_t script, uint32_t owner) const;
bool get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> &scripts, uint32_t script, uint32_t owner) const;
bool get_cc_script(uint32_t script, std::string &name, std::string &icon, std::string &desc, std::string &blob) const;
bool get_cc_script_state(uint32_t account, uint32_t script, uint32_t owner, uint32_t state, uint32_t city, std::string &script_name, std::string &ui, std::string &text, std::string &image, std::vector<std::tuple<uint32_t, std::string, std::string>> &choices, std::string &choices_ui, std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides) const;
bool get_cc_global_variable(const std::string &name, uint64_t &value) const;
@ -1232,7 +1232,7 @@ std::vector<uint64_t> GameWalletInternal::get_item_count(const std::vector<uint3
return counts;
}
bool GameWalletInternal::get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> &scripts, uint32_t script, uint32_t owner) const
bool GameWalletInternal::get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> &scripts, uint32_t script, uint32_t owner) const
{
return w->get_cc_scripts(account, city, flag, dx, dy, h, include_requirements, scripts, script, owner);
}
@ -1961,12 +1961,12 @@ std::vector<uint64_t> GameWallet::get_item_count(const std::vector<uint32_t> &id
return internal->get_item_count(id);
}
bool GameWallet::get_cc_scripts(uint32_t account, uint32_t city, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> &scripts, uint32_t script, uint32_t owner) const
bool GameWallet::get_cc_scripts(uint32_t account, uint32_t city, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> &scripts, uint32_t script, uint32_t owner) const
{
return internal->get_cc_scripts(account, city, 0, 0, 0, 0, include_requirements, scripts, script, owner);
}
bool GameWallet::get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> &scripts, uint32_t script, uint32_t owner) const
bool GameWallet::get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> &scripts, uint32_t script, uint32_t owner) const
{
return internal->get_cc_scripts(account, city, flag, dx, dy, h, true, scripts, script, owner);
}

View File

@ -98,8 +98,8 @@ public:
uint32_t lookup_account(const std::string &pkey);
bool get_invitation_status(const std::string &pkey, bool &used, bool &balance_ok) const;
std::vector<uint64_t> get_item_count(const std::vector<uint32_t> &id) const;
bool get_cc_scripts(uint32_t account, uint32_t city, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> &scripts, uint32_t script = 0, uint32_t owner = 0) const;
bool get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> &scripts, uint32_t script = 0, uint32_t owner = 0) const;
bool get_cc_scripts(uint32_t account, uint32_t city, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> &scripts, uint32_t script = 0, uint32_t owner = 0) const;
bool get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> &scripts, uint32_t script = 0, uint32_t owner = 0) const;
bool get_cc_script(uint32_t script, std::string &name, std::string &icon, std::string &desc, std::string &blob) const;
bool get_cc_script_state(uint32_t account, uint32_t script, uint32_t owner, uint32_t state, uint32_t city, std::string &script_name, std::string &ui, std::string &text, std::string &image, std::vector<std::tuple<uint32_t, std::string, std::string>> &choices, std::string &choices_ui, std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides) const;
bool get_cc_global_variable(const std::string &name, uint64_t &value) const;

View File

@ -11,6 +11,7 @@
#include "cc/cc_script.h"
#include "game-wallet.h"
#include "game-state.h"
#include "game-util.h"
#include "ui-new-script.h"
#include "ui-runestone-message.h"
@ -61,7 +62,7 @@ bool UIRunestoneMessageDialog::SetupScriptWidget(const std::shared_ptr<GameWalle
if (!cc::script::save_script_native(script, script_source, cc::script::save_flag_no_images))
return false;
std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> scripts;
std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> scripts;
if (!w->get_cc_scripts(game->playerState.id, game->cityState.id, runestone.flag, runestone.x, runestone.y, runestone.h, scripts, runestone.script, flag->owner))
return false;
if (scripts.size() != 1)
@ -73,12 +74,16 @@ bool UIRunestoneMessageDialog::SetupScriptWidget(const std::shared_ptr<GameWalle
return false;
const uint32_t owner = std::get<1>(e);
const bool is_public = std::get<2>(e);
const std::string &name = std::get<3>(e);
std::string name = std::get<3>(e);
const std::string &icon = std::get<4>(e);
const std::string &desc = std::get<5>(e);
std::string desc = std::get<5>(e);
const bool available = std::get<6>(e);
const bool enable = available && game->playerState.script == 0;
const std::vector<std::pair<std::string, bool>> &requirements = std::get<7>(e);
const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides = std::get<8>(e);
game_util::process_overrides(game, name, overrides, false);
game_util::process_overrides(game, desc, overrides, false);
TBWidget *sw = GetWidgetByIDAndType<TBWidget>(TBIDC("script"));

View File

@ -247,11 +247,16 @@ void UIScriptsDialog::FillScriptList(const std::shared_ptr<GameWallet> &w)
const uint32_t id = std::get<0>(e);
const uint32_t owner = std::get<1>(e);
const bool is_public = std::get<2>(e);
const std::string &name = std::get<3>(e);
std::string name = std::get<3>(e);
const std::string &icon = std::get<4>(e);
const std::string &desc = std::get<5>(e);
std::string desc = std::get<5>(e);
const bool available = std::get<6>(e);
const std::vector<std::pair<std::string, bool>> &requirements = std::get<7>(e);
const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides = std::get<8>(e);
game_util::process_overrides(game, name, overrides, false);
game_util::process_overrides(game, desc, overrides, false);
if (mode == mode_play)
{
if (owner != 0 || is_public)
@ -271,29 +276,17 @@ void UIScriptsDialog::FillScriptList(const std::shared_ptr<GameWallet> &w)
SetText("Scripts");
}
void UIScriptsDialog::ProcessOverrides(std::string &s, const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides)
{
for (const auto &e: overrides)
{
if (std::get<0>(e) == cc::script::override_string)
{
const std::string code = "${" + std::to_string(std::get<1>(e)) + "}";
boost::replace_all(s, code, std::get<2>(e));
}
}
}
void UIScriptsDialog::ProcessOverrides(tb::TBWidget *w, const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides)
void UIScriptsDialog::ProcessOverrides(tb::TBWidget *w, const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides, bool in_script)
{
if (!w)
return;
std::string s = w->GetText().CStr();
ProcessOverrides(s, overrides);
game_util::process_overrides(game, s, overrides, in_script);
w->SetText(s.c_str());
for (w = w->GetFirstChild(); w; w = w->GetNext())
ProcessOverrides(w, overrides);
ProcessOverrides(w, overrides, in_script);
}
void UIScriptsDialog::ProcessControlCodes(tb::TBWidget *w)
@ -337,6 +330,8 @@ void UIScriptsDialog::FillChoiceList(const std::shared_ptr<GameWallet> &w)
return;
}
game_util::process_overrides(game, script_name, overrides, true);
if (!image.empty())
{
TBImageWidget *imageWidget = new TBImageWidget();
@ -365,7 +360,6 @@ void UIScriptsDialog::FillChoiceList(const std::shared_ptr<GameWallet> &w)
if (!ui.empty())
{
ProcessOverrides(ui, overrides);
if (!g_widgets_reader->LoadData(choicesLayout, ui.c_str()))
{
new MessageBox(context_, "Failed to parse UI");
@ -375,7 +369,6 @@ void UIScriptsDialog::FillChoiceList(const std::shared_ptr<GameWallet> &w)
if (!choices_ui.empty())
{
ProcessOverrides(choices_ui, overrides);
if (!g_widgets_reader->LoadData(choicesLayout, choices_ui.c_str()))
{
new MessageBox(context_, "Failed to parse choices UI");
@ -404,6 +397,7 @@ void UIScriptsDialog::FillChoiceList(const std::shared_ptr<GameWallet> &w)
}
}
ProcessOverrides(choicesLayout, overrides, true);
ProcessControlCodes(choicesLayout);
ProcessWidgetValues(choicesLayout);

View File

@ -59,8 +59,7 @@ private:
void FillScriptList(const std::shared_ptr<GameWallet> &w);
void FillChoiceList(const std::shared_ptr<GameWallet> &w);
void UpdateDetailsVisibility();
void ProcessOverrides(std::string &s, const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides);
void ProcessOverrides(tb::TBWidget *w, const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides);
void ProcessOverrides(tb::TBWidget *w, const std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides, bool in_script);
void ProcessControlCodes(tb::TBWidget *w);
void ProcessWidgetValues(tb::TBWidget *w);
void ViewSource(const std::shared_ptr<GameWallet> &w, uint32_t script);
@ -118,7 +117,7 @@ private:
ScriptSource script_source;
std::string last_refresh_stop_hash;
std::vector<std::tuple<uint32_t, std::string, std::string>> choices;
std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> scripts;
std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> scripts;
uint32_t view_script_source;
};

View File

@ -5065,16 +5065,21 @@ namespace cryptonote
}
bool available = true;
cc::script::ScriptHandle script;
if (!cc::script::load_script_binary(sd.blob, script))
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error getting script";
return false;
}
std::vector<cryptonote::COMMAND_RPC_CC_GET_SCRIPTS::requirement_t> requirements;
std::vector<cryptonote::COMMAND_RPC_CC_GET_SCRIPTS::override_t> all_overrides;
const auto script_overrides = cc::script::get_script_overrides(script);
all_overrides.reserve(script_overrides.size());
for (const auto &e: script_overrides)
all_overrides.push_back({std::get<0>(e), std::get<1>(e), std::get<2>(e)});
if (req.account)
{
cc::script::ScriptHandle script;
if (!cc::script::load_script_binary(sd.blob, script))
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error getting script";
return false;
}
std::vector<std::pair<std::string, bool>> reqs;
const uint32_t owner = sd.is_public ? req.owner : sd.owner == 0 ? GAME_ACCOUNT : sd.owner;
const std::vector<std::tuple<uint8_t, uint32_t, std::string>> overrides = cc::script::get_script_overrides(script);
@ -5089,13 +5094,25 @@ namespace cryptonote
return false;
}
runestone_overrides = std::move(runestone.overrides);
for (const auto &e: runestone_overrides)
{
for (auto &f: all_overrides)
{
if (std::get<0>(e) != f.type)
continue;
if (f.type == cc::script::override_string && std::get<1>(e) == f.idx)
f.str = std::get<2>(e);
else if (f.type == cc::script::override_local && std::get<2>(e) == f.str)
f.idx = std::get<1>(e);
}
}
}
available = cc::script::is_available(db, script, overrides, runestone_overrides, req.account, owner, req.city, req.include_requirements ? &reqs : NULL);
requirements.reserve(reqs.size());
for (const auto &e: reqs)
requirements.push_back({e.first, e.second});
}
res.scripts.push_back({sd.id, std::move(sd.name), std::move(sd.icon), std::move(sd.desc), req.include_blob ? epee::string_tools::buff_to_hex_nodelimer(sd.blob) : std::string(), sd.owner, sd.is_public, available, std::move(requirements)});
res.scripts.push_back({sd.id, std::move(sd.name), std::move(sd.icon), std::move(sd.desc), req.include_blob ? epee::string_tools::buff_to_hex_nodelimer(sd.blob) : std::string(), sd.owner, sd.is_public, available, std::move(requirements), std::move(all_overrides)});
}
}
}

View File

@ -4341,6 +4341,19 @@ namespace cryptonote
};
typedef epee::misc_utils::struct_init<request_t> request;
struct override_t
{
uint8_t type;
uint32_t idx;
std::string str;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(type)
KV_SERIALIZE(idx)
KV_SERIALIZE(str)
END_KV_SERIALIZE_MAP()
};
struct script_t
{
uint32_t index;
@ -4352,6 +4365,7 @@ namespace cryptonote
bool is_public;
bool available;
std::vector<requirement_t> requirements;
std::vector<override_t> overrides;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(index)
@ -4363,6 +4377,7 @@ namespace cryptonote
KV_SERIALIZE(is_public)
KV_SERIALIZE(available)
KV_SERIALIZE(requirements)
KV_SERIALIZE(overrides)
END_KV_SERIALIZE_MAP()
};

View File

@ -1087,7 +1087,7 @@ private:
bool get_cc_invitation_status(const std::string &pkey, bool &used, bool &balance_ok);
bool get_cc_item_count(const std::vector<uint32_t> &id, std::vector<uint64_t> &count);
bool get_cc_nonces(uint32_t num_nonces, std::vector<uint64_t> &nonces);
bool get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> &scripts, uint32_t script = 0, uint32_t owner = 0);
bool get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> &scripts, uint32_t script = 0, uint32_t owner = 0);
bool get_cc_script_data(uint32_t script, std::string &name, std::string &icon, std::string &desc, std::string &blob);
bool get_cc_script_state(uint32_t account, uint32_t script, uint32_t owner, uint32_t state, uint32_t city, std::string &script_name, std::string &ui, std::string &text, std::string &image, std::vector<std::tuple<uint32_t, std::string, std::string>> &choices, std::string &choices_ui, std::vector<std::tuple<uint8_t, uint32_t, std::string>> &overrides);
bool get_cc_global_variable(const std::string &name, uint64_t &value);

View File

@ -768,7 +768,7 @@ bool wallet2::get_cc_nonces(uint32_t num_nonces, std::vector<uint64_t> &nonces)
return true;
}
bool wallet2::get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>>> &scripts, uint32_t script, uint32_t owner)
bool wallet2::get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uint8_t dx, uint8_t dy, uint16_t h, bool include_requirements, std::vector<std::tuple<uint32_t, uint32_t, bool, std::string, std::string, std::string, bool, std::vector<std::pair<std::string, bool>>, std::vector<std::tuple<uint8_t, uint32_t, std::string>>>> &scripts, uint32_t script, uint32_t owner)
{
cryptonote::COMMAND_RPC_CC_GET_SCRIPTS::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_CC_GET_SCRIPTS::response res;
@ -795,10 +795,14 @@ bool wallet2::get_cc_scripts(uint32_t account, uint32_t city, uint32_t flag, uin
for (size_t i = 0; i < res.scripts.size(); ++i)
{
std::vector<std::pair<std::string, bool>> requirements;
std::vector<std::tuple<uint8_t, uint32_t, std::string>> overrides;
requirements.reserve(res.scripts[i].requirements.size());
for (const auto &e: res.scripts[i].requirements)
requirements.push_back(std::make_pair(e.text, e.met));
scripts[i] = std::make_tuple(res.scripts[i].index, res.scripts[i].owner, res.scripts[i].is_public, std::move(res.scripts[i].name), std::move(res.scripts[i].icon), std::move(res.scripts[i].desc), res.scripts[i].available, std::move(requirements));
overrides.reserve(res.scripts[i].overrides.size());
for (const auto &e: res.scripts[i].overrides)
overrides.push_back(std::make_tuple(e.type, e.idx, e.str));
scripts[i] = std::make_tuple(res.scripts[i].index, res.scripts[i].owner, res.scripts[i].is_public, std::move(res.scripts[i].name), std::move(res.scripts[i].icon), std::move(res.scripts[i].desc), res.scripts[i].available, std::move(requirements), std::move(overrides));
}
return true;