From d2a97ab43cb331b84bbe29cfc8a3fbd8dd49d913 Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 27 Jan 2021 22:50:31 +0000 Subject: [PATCH] Implement scenario select window --- src/openrct2-ui/scripting/ScUi.hpp | 79 ++++++++++++++++++++++ src/openrct2-ui/windows/ScenarioSelect.cpp | 37 +++++----- src/openrct2-ui/windows/Window.h | 1 + src/openrct2/scenario/Scenario.h | 2 +- src/openrct2/scripting/Duktape.hpp | 19 ++++++ 5 files changed, 121 insertions(+), 17 deletions(-) diff --git a/src/openrct2-ui/scripting/ScUi.hpp b/src/openrct2-ui/scripting/ScUi.hpp index 3f870f7a6b..75d4225f04 100644 --- a/src/openrct2-ui/scripting/ScUi.hpp +++ b/src/openrct2-ui/scripting/ScUi.hpp @@ -22,6 +22,7 @@ # include # include # include +# include # include # include # include @@ -38,6 +39,37 @@ namespace OpenRCT2::Ui::Windows namespace OpenRCT2::Scripting { + static const DukEnumMap ScenarioCategoryMap({ + { "beginner", SCENARIO_CATEGORY_BEGINNER }, + { "challenging", SCENARIO_CATEGORY_CHALLENGING }, + { "expert", SCENARIO_CATEGORY_EXPERT }, + { "real", SCENARIO_CATEGORY_REAL }, + { "other", SCENARIO_CATEGORY_OTHER }, + { "dlc", SCENARIO_CATEGORY_DLC }, + { "build_your_own", SCENARIO_CATEGORY_BUILD_YOUR_OWN }, + }); + + static const DukEnumMap ScenarioSourceMap({ + { "rct1", ScenarioSource::RCT1 }, + { "rct1_aa", ScenarioSource::RCT1_AA }, + { "rct1_ll", ScenarioSource::RCT1_LL }, + { "rct2", ScenarioSource::RCT2 }, + { "rct2_ww", ScenarioSource::RCT2_WW }, + { "rct2_tt", ScenarioSource::RCT2_TT }, + { "real", ScenarioSource::Real }, + { "other", ScenarioSource::Other }, + }); + + template<> inline DukValue ToDuk(duk_context* ctx, const SCENARIO_CATEGORY& value) + { + return ToDuk(ctx, ScenarioCategoryMap[value]); + } + + template<> inline DukValue ToDuk(duk_context* ctx, const ScenarioSource& value) + { + return ToDuk(ctx, ScenarioSourceMap[value]); + } + class ScTool { private: @@ -250,6 +282,19 @@ namespace OpenRCT2::Scripting } } + void showScenarioSelect(const DukValue& desc) + { + auto plugin = _scriptEngine.GetExecInfo().GetCurrentPlugin(); + auto callback = desc["callback"]; + + window_scenarioselect_open( + [this, plugin, callback](std::string_view path) { + auto dukValue = GetScenarioFile(path); + _scriptEngine.ExecutePluginCall(plugin, callback, { dukValue }, false); + }, + false, true); + } + void activateTool(const DukValue& desc) { InitialiseCustomTool(_scriptEngine, desc); @@ -278,6 +323,7 @@ namespace OpenRCT2::Scripting dukglue_register_method(ctx, &ScUi::showError, "showError"); dukglue_register_method(ctx, &ScUi::showTextInput, "showTextInput"); dukglue_register_method(ctx, &ScUi::showFileBrowse, "showFileBrowse"); + dukglue_register_method(ctx, &ScUi::showScenarioSelect, "showScenarioSelect"); dukglue_register_method(ctx, &ScUi::activateTool, "activateTool"); dukglue_register_method(ctx, &ScUi::registerMenuItem, "registerMenuItem"); } @@ -287,6 +333,39 @@ namespace OpenRCT2::Scripting { return WC_NULL; } + + DukValue GetScenarioFile(std::string_view path) + { + auto ctx = _scriptEngine.GetContext(); + DukObject obj(ctx); + obj.Set("path", path); + + auto* scenarioRepo = GetScenarioRepository(); + auto entry = scenarioRepo->GetByPath(std::string(path).c_str()); + if (entry != nullptr) + { + obj.Set("id", entry->sc_id); + obj.Set("category", ToDuk(ctx, static_cast(entry->category))); + obj.Set("sourceGame", ToDuk(ctx, entry->source_game)); + obj.Set("internalName", entry->internal_name); + obj.Set("name", entry->name); + obj.Set("details", entry->details); + + auto* highscore = entry->highscore; + if (highscore == nullptr) + { + obj.Set("highscore", nullptr); + } + else + { + DukObject dukHighscore(ctx); + dukHighscore.Set("name", highscore->name); + dukHighscore.Set("companyValue", highscore->company_value); + obj.Set("highscore", dukHighscore.Take()); + } + } + return obj.Take(); + } }; } // namespace OpenRCT2::Scripting diff --git a/src/openrct2-ui/windows/ScenarioSelect.cpp b/src/openrct2-ui/windows/ScenarioSelect.cpp index dd3697f843..096781ca85 100644 --- a/src/openrct2-ui/windows/ScenarioSelect.cpp +++ b/src/openrct2-ui/windows/ScenarioSelect.cpp @@ -130,32 +130,40 @@ static void initialise_list_items(rct_window* w); static bool is_scenario_visible(rct_window* w, const scenario_index_entry* scenario); static bool is_locking_enabled(rct_window* w); -static scenarioselect_callback _callback; +static std::function _callback; static bool _showLockedInformation = false; static bool _titleEditor = false; +static bool _disableLocking{}; -/** - * - * rct2: 0x006781B5 - */ rct_window* window_scenarioselect_open(scenarioselect_callback callback, bool titleEditor) { - rct_window* window; - int32_t windowWidth; - int32_t windowHeight = 334; - - _callback = callback; - if (_titleEditor != titleEditor) { _titleEditor = titleEditor; window_close_by_class(WC_SCENARIO_SELECT); } - window = window_bring_to_front_by_class(WC_SCENARIO_SELECT); + auto window = window_bring_to_front_by_class(WC_SCENARIO_SELECT); if (window != nullptr) return window; + return window_scenarioselect_open( + [callback](std::string_view scenario) { callback(std::string(scenario).c_str()); }, titleEditor, titleEditor); +} + +/** + * + * rct2: 0x006781B5 + */ +rct_window* window_scenarioselect_open(std::function callback, bool titleEditor, bool disableLocking) +{ + rct_window* window; + int32_t windowWidth; + int32_t windowHeight = 334; + + _callback = callback; + _disableLocking = disableLocking; + // Load scenario list scenario_repository_scan(); @@ -328,10 +336,7 @@ static void window_scenarioselect_scrollmousedown(rct_window* w, int32_t scrollI OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, w->windowPos.x + (w->width / 2)); gFirstTimeSaving = true; _callback(listItem.scenario.scenario->path); - if (_titleEditor) - { - window_close(w); - } + window_close(w); } break; } diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 906615aaed..02191b58c1 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -105,6 +105,7 @@ rct_window* window_staff_fire_prompt_open(Peep* peep); void window_title_editor_open(int32_t tab); void window_title_command_editor_open(struct TitleSequence* sequence, int32_t command, bool insert); rct_window* window_scenarioselect_open(scenarioselect_callback callback, bool titleEditor); +rct_window* window_scenarioselect_open(std::function callback, bool titleEditor, bool disableLocking); rct_window* window_error_open(rct_string_id title, rct_string_id message, const class Formatter& formatter); rct_window* window_error_open(std::string_view title, std::string_view message); diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index e4ac2d5254..be881c5a52 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -318,7 +318,7 @@ enum #define S6_RCT2_VERSION 120001 #define S6_MAGIC_NUMBER 0x00031144 -enum +enum SCENARIO_CATEGORY { // RCT2 categories (keep order) SCENARIO_CATEGORY_BEGINNER, diff --git a/src/openrct2/scripting/Duktape.hpp b/src/openrct2/scripting/Duktape.hpp index 856fb2a317..ff9c30c02b 100644 --- a/src/openrct2/scripting/Duktape.hpp +++ b/src/openrct2/scripting/Duktape.hpp @@ -80,6 +80,13 @@ namespace OpenRCT2::Scripting PopObjectIfExists(); } + void Set(const char* name, std::nullptr_t) + { + EnsureObjectPushed(); + duk_push_null(_ctx); + duk_put_prop_string(_ctx, _idx, name); + } + void Set(const char* name, bool value) { EnsureObjectPushed(); @@ -101,6 +108,13 @@ namespace OpenRCT2::Scripting duk_put_prop_string(_ctx, _idx, name); } + void Set(const char* name, uint64_t value) + { + EnsureObjectPushed(); + duk_push_number(_ctx, value); + duk_put_prop_string(_ctx, _idx, name); + } + void Set(const char* name, std::string_view value) { EnsureObjectPushed(); @@ -108,6 +122,11 @@ namespace OpenRCT2::Scripting duk_put_prop_string(_ctx, _idx, name); } + void Set(const char* name, const char* value) + { + Set(name, std::string_view(value)); + } + void Set(const char* name, const DukValue& value) { EnsureObjectPushed();