diff --git a/src/openrct2-ui/input/KeyboardShortcut.cpp b/src/openrct2-ui/input/KeyboardShortcut.cpp index 99324a88ba..291fc6cc0e 100644 --- a/src/openrct2-ui/input/KeyboardShortcut.cpp +++ b/src/openrct2-ui/input/KeyboardShortcut.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -729,7 +730,8 @@ static void shortcut_load_game() { if (!(gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))) { - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); + auto loadOrQuitAction = LoadOrQuitAction(LoadOrQuitModes::OpenSavePrompt); + GameActions::Execute(&loadOrQuitAction); } } diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index 1c3dae22f2..a00d519cdf 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -467,7 +468,8 @@ static void window_editor_object_selection_mouseup(rct_window* w, rct_widgetinde case WIDX_CLOSE: if (gScreenFlags & SCREEN_FLAGS_EDITOR) { - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); + auto loadOrQuitAction = LoadOrQuitAction(LoadOrQuitModes::OpenSavePrompt, PM_SAVE_BEFORE_QUIT); + GameActions::Execute(&loadOrQuitAction); } else { diff --git a/src/openrct2-ui/windows/TitleMenu.cpp b/src/openrct2-ui/windows/TitleMenu.cpp index 630d94ed02..54ed089a81 100644 --- a/src/openrct2-ui/windows/TitleMenu.cpp +++ b/src/openrct2-ui/windows/TitleMenu.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -153,7 +154,8 @@ static void window_title_menu_mouseup(rct_window* w, rct_widgetindex widgetIndex { window_close_by_class(WC_SCENARIO_SELECT); window_close_by_class(WC_SERVER_LIST); - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); + auto loadOrQuitAction = LoadOrQuitAction(LoadOrQuitModes::OpenSavePrompt); + GameActions::Execute(&loadOrQuitAction); } break; case WIDX_MULTIPLAYER: diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 48280cd28b..49e5aaabb9 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -587,8 +588,11 @@ static void window_top_toolbar_dropdown(rct_window* w, rct_widgetindex widgetInd break; } case DDIDX_LOAD_GAME: - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); + { + auto loadOrQuitAction = LoadOrQuitAction(LoadOrQuitModes::OpenSavePrompt); + GameActions::Execute(&loadOrQuitAction); break; + } case DDIDX_SAVE_GAME: tool_cancel(); save_game(); @@ -620,10 +624,13 @@ static void window_top_toolbar_dropdown(rct_window* w, rct_widgetindex widgetInd screenshot_giant(); break; case DDIDX_QUIT_TO_MENU: + { window_close_by_class(WC_MANAGE_TRACK_DESIGN); window_close_by_class(WC_TRACK_DELETE_PROMPT); - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); + auto loadOrQuitAction = LoadOrQuitAction(LoadOrQuitModes::OpenSavePrompt, PM_SAVE_BEFORE_QUIT); + GameActions::Execute(&loadOrQuitAction); break; + } case DDIDX_EXIT_OPENRCT2: context_quit(); break; @@ -3054,7 +3061,8 @@ static void window_top_toolbar_tool_drag(rct_window* w, rct_widgetindex widgetIn game_do_command( gMapSelectPositionA.x, 1, gMapSelectPositionA.y, gLandToolTerrainSurface | (gLandToolTerrainEdge << 8), GAME_COMMAND_CHANGE_SURFACE_STYLE, gMapSelectPositionB.x, gMapSelectPositionB.y); - // The tool is set to 12 here instead of 3 so that the dragging cursor is not the elevation change cursor + // The tool is set to 12 here instead of 3 so that the dragging cursor is not the elevation change + // cursor gCurrentToolId = TOOL_CROSSHAIR; } } diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 0b206b8174..6c51562849 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -17,6 +17,7 @@ #include "OpenRCT2.h" #include "ParkImporter.h" #include "ReplayManager.h" +#include "actions/LoadOrQuitAction.hpp" #include "audio/audio.h" #include "config/Config.h" #include "core/FileScanner.h" @@ -467,20 +468,16 @@ int32_t game_do_command_p( && !(flags & GAME_COMMAND_FLAG_GHOST) && !(flags & GAME_COMMAND_FLAG_5) && gGameCommandNestLevel == 1) /* Send only top-level commands */ { - // Disable these commands over the network - if (command != GAME_COMMAND_LOAD_OR_QUIT) + network_send_gamecmd( + *eax, *ebx, *ecx, *edx, *esi, *edi, *ebp, game_command_callback_get_index(game_command_callback)); + if (network_get_mode() == NETWORK_MODE_CLIENT) { - network_send_gamecmd( - *eax, *ebx, *ecx, *edx, *esi, *edi, *ebp, game_command_callback_get_index(game_command_callback)); - if (network_get_mode() == NETWORK_MODE_CLIENT) - { - // Client sent the command to the server, do not run it locally, just return. It will run when server - // sends it. - game_command_callback = nullptr; - // Decrement nest count - gGameCommandNestLevel--; - return cost; - } + // Client sent the command to the server, do not run it locally, just return. It will run when server + // sends it. + game_command_callback = nullptr; + // Decrement nest count + gGameCommandNestLevel--; + return cost; } } @@ -753,33 +750,6 @@ bool game_is_not_paused() return gGamePaused == 0; } -/** - * - * rct2: 0x0066DB5F - */ -static void game_load_or_quit( - [[maybe_unused]] int32_t* eax, int32_t* ebx, [[maybe_unused]] int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, - int32_t* edi, [[maybe_unused]] int32_t* ebp) -{ - if (*ebx & GAME_COMMAND_FLAG_APPLY) - { - switch (*edx & 0xFF) - { - case 0: - gSavePromptMode = *edi & 0xFF; - context_open_window(WC_SAVE_PROMPT); - break; - case 1: - window_close_by_class(WC_SAVE_PROMPT); - break; - default: - game_load_or_quit_no_save_prompt(); - break; - } - } - *ebx = 0; -} - /** * * rct2: 0x0066DC0F @@ -1280,7 +1250,9 @@ void game_load_or_quit_no_save_prompt() switch (gSavePromptMode) { case PM_SAVE_BEFORE_LOAD: - game_do_command(0, 1, 0, 1, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); + { + auto loadOrQuitAction = LoadOrQuitAction(LoadOrQuitModes::CloseSavePrompt); + GameActions::Execute(&loadOrQuitAction); tool_cancel(); if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) { @@ -1294,8 +1266,11 @@ void game_load_or_quit_no_save_prompt() context_open_intent(&intent); } break; + } case PM_SAVE_BEFORE_QUIT: - game_do_command(0, 1, 0, 1, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); + { + auto loadOrQuitAction = LoadOrQuitAction(LoadOrQuitModes::CloseSavePrompt); + GameActions::Execute(&loadOrQuitAction); tool_cancel(); if (input_test_flag(INPUT_FLAG_5)) { @@ -1305,6 +1280,7 @@ void game_load_or_quit_no_save_prompt() gFirstTimeSaving = true; title_load(); break; + } default: openrct2_finish(); break; @@ -1317,7 +1293,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { nullptr, nullptr, nullptr, - game_load_or_quit, + nullptr, game_command_create_ride, game_command_demolish_ride, game_command_set_ride_status, diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index f57d7db4ae..38dd427d2b 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -23,10 +23,10 @@ enum GAME_COMMAND GAME_COMMAND_TOGGLE_PAUSE, // GA GAME_COMMAND_PLACE_TRACK, // GA GAME_COMMAND_REMOVE_TRACK, // GA - GAME_COMMAND_LOAD_OR_QUIT, - GAME_COMMAND_CREATE_RIDE, // GA - GAME_COMMAND_DEMOLISH_RIDE, - GAME_COMMAND_SET_RIDE_STATUS, // GA + GAME_COMMAND_LOAD_OR_QUIT, // GA + GAME_COMMAND_CREATE_RIDE, // GA + GAME_COMMAND_DEMOLISH_RIDE, // GA + GAME_COMMAND_SET_RIDE_STATUS, // GA GAME_COMMAND_SET_RIDE_VEHICLES, GAME_COMMAND_SET_RIDE_NAME, // GA GAME_COMMAND_SET_RIDE_SETTING, diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index ccd395562e..c1e08d744a 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -15,6 +15,7 @@ #include "GuestSetNameAction.hpp" #include "LandSetHeightAction.hpp" #include "LargeSceneryRemoveAction.hpp" +#include "LoadOrQuitAction.hpp" #include "MazeSetTrackAction.hpp" #include "ParkMarketingAction.hpp" #include "ParkSetLoanAction.hpp" @@ -79,5 +80,6 @@ namespace GameActions Register(); Register(); Register(); + Register(); } } // namespace GameActions diff --git a/src/openrct2/actions/LoadOrQuitAction.hpp b/src/openrct2/actions/LoadOrQuitAction.hpp new file mode 100644 index 0000000000..a5de08df20 --- /dev/null +++ b/src/openrct2/actions/LoadOrQuitAction.hpp @@ -0,0 +1,74 @@ +/***************************************************************************** + * Copyright (c) 2014-2019 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../Context.h" +#include "../OpenRCT2.h" +#include "GameAction.h" + +enum class LoadOrQuitModes : uint8_t +{ + OpenSavePrompt, + CloseSavePrompt +}; + +DEFINE_GAME_ACTION(LoadOrQuitAction, GAME_COMMAND_LOAD_OR_QUIT, GameActionResult) +{ +private: + uint8_t _mode{ 0 }; + uint8_t _savePromptMode{ PM_SAVE_BEFORE_LOAD }; + +public: + LoadOrQuitAction() + { + } + + LoadOrQuitAction(LoadOrQuitModes mode, uint8_t savePromptMode = PM_SAVE_BEFORE_LOAD) + : _mode(static_cast(mode)) + , _savePromptMode(savePromptMode) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags() | GA_FLAGS::CLIENT_ONLY | GA_FLAGS::ALLOW_WHILE_PAUSED; + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_mode) << DS_TAG(_savePromptMode); + } + + GameActionResult::Ptr Query() const override + { + return std::make_unique(); + } + + GameActionResult::Ptr Execute() const override + { + auto mode = static_cast(_mode); + switch (mode) + { + case LoadOrQuitModes::OpenSavePrompt: + gSavePromptMode = _savePromptMode; + context_open_window(WC_SAVE_PROMPT); + break; + case LoadOrQuitModes::CloseSavePrompt: + window_close_by_class(WC_SAVE_PROMPT); + break; + default: + game_load_or_quit_no_save_prompt(); + break; + } + return std::make_unique(); + } +}; diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index af2e46e7dc..5e265ee925 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -13,6 +13,7 @@ #include "../Game.h" #include "../OpenRCT2.h" #include "../PlatformEnvironment.h" +#include "../actions/LoadOrQuitAction.hpp" #include "../core/Guard.hpp" #include "../platform/platform.h" #include "../ui/UiContext.h" @@ -2557,7 +2558,8 @@ void Network::Client_Handle_MAP([[maybe_unused]] NetworkConnection& connection, else { // Something went wrong, game is not loaded. Return to main screen. - game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); + auto loadOrQuitAction = LoadOrQuitAction(LoadOrQuitModes::OpenSavePrompt, PM_SAVE_BEFORE_QUIT); + GameActions::Execute(&loadOrQuitAction); } if (has_to_free) { @@ -2875,11 +2877,6 @@ void Network::Server_Handle_GAMECMD(NetworkConnection& connection, NetworkPacket return; } } - // Don't let clients send pause or quit - else if (commandCommand == GAME_COMMAND_TOGGLE_PAUSE || commandCommand == GAME_COMMAND_LOAD_OR_QUIT) - { - return; - } game_command_queue.emplace(tick, args, playerid, callback, _commandId++); }