From a3c64bb1462bdc19f175588f694b1efbaecbe24b Mon Sep 17 00:00:00 2001 From: Robert Jordan Date: Mon, 30 Oct 2017 07:07:01 -0400 Subject: [PATCH] Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry. --- distribution/changelog.txt | 1 + src/openrct2-ui/windows/Options.cpp | 2 +- .../windows/TitleCommandEditor.cpp | 2 +- src/openrct2-ui/windows/TitleEditor.cpp | 31 +++- src/openrct2/Context.cpp | 157 +++++++++--------- src/openrct2/Context.h | 4 + src/openrct2/game.c | 15 +- src/openrct2/game.h | 2 + src/openrct2/interface/viewport.c | 8 +- src/openrct2/interface/viewport.h | 2 + src/openrct2/scenario/scenario.c | 2 +- src/openrct2/title/TitleScreen.cpp | 19 ++- src/openrct2/title/TitleScreen.h | 5 +- src/openrct2/title/TitleSequencePlayer.cpp | 76 ++++++++- src/openrct2/title/TitleSequencePlayer.h | 3 + 15 files changed, 226 insertions(+), 103 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index c1e6c7971b..2d590c17e5 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -17,6 +17,7 @@ - Feature: [#6414] Raise maximum launch speed of the Corkscrew RC back to 96 km/h (for RCT1 parity). - Feature: [#6433] Turn 'unlock all prices' into a regular (non-cheat, persistent) option. - Feature: Allow using object files from RCT Classic. +- Feature: Title sequences now testable in-game. - Fix: [#816] In the map window, there are more peeps flickering than there are selected (original bug). - Fix: [#1833, #4937, #6138] 'Too low!' warning when building rides and shops on the lowest land level (original bug). - Fix: [#6199] Inverted Hairpin Coaster vehicle tab is not centred. diff --git a/src/openrct2-ui/windows/Options.cpp b/src/openrct2-ui/windows/Options.cpp index f2fdbc054f..a8bde8473d 100644 --- a/src/openrct2-ui/windows/Options.cpp +++ b/src/openrct2-ui/windows/Options.cpp @@ -1962,7 +1962,7 @@ static void window_options_paint(rct_window *w, rct_drawpixelinfo *dpi) w->y + window_options_misc_widgets[WIDX_AUTOSAVE].top ); - const utf8 * name = title_sequence_manager_get_name(title_get_current_sequence()); + const utf8 * name = title_sequence_manager_get_name(title_get_config_sequence()); set_format_arg(0, uintptr_t, (uintptr_t)name); gfx_draw_string_left(dpi, STR_TITLE_SEQUENCE, w, w->colours[1], w->x + 10, w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top + 1); gfx_draw_string_left_clipped( diff --git a/src/openrct2-ui/windows/TitleCommandEditor.cpp b/src/openrct2-ui/windows/TitleCommandEditor.cpp index 3aa19ed60b..b3c13c7c7b 100644 --- a/src/openrct2-ui/windows/TitleCommandEditor.cpp +++ b/src/openrct2-ui/windows/TitleCommandEditor.cpp @@ -171,7 +171,7 @@ static LocationXY16 get_location() sint32 interactionType; rct_map_element *mapElement; - get_map_coordinates_from_pos(w->viewport->view_width / 2, w->viewport->view_height / 2, VIEWPORT_INTERACTION_MASK_TERRAIN, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, nullptr); + get_map_coordinates_from_pos_window(w, w->viewport->view_width / 2, w->viewport->view_height / 2, VIEWPORT_INTERACTION_MASK_TERRAIN, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, nullptr); mapCoord.x -= 16; mapCoord.x /= 32; mapCoord.y -= 16; diff --git a/src/openrct2-ui/windows/TitleEditor.cpp b/src/openrct2-ui/windows/TitleEditor.cpp index 81b319ea87..31a35cb82e 100644 --- a/src/openrct2-ui/windows/TitleEditor.cpp +++ b/src/openrct2-ui/windows/TitleEditor.cpp @@ -280,6 +280,15 @@ void window_title_editor_open(sint32 tab) static void window_title_editor_close(rct_window *w) { + uint16 preset = title_get_config_sequence(); + title_set_current_sequence(preset, false); + if (!gTestingTitleSequenceInGame) + { + ITitleSequencePlayer * player = window_title_editor_get_player(); + player->Begin(preset); + } + gTestingTitleSequenceInGame = false; + // Close the related windows window_close_by_class(WC_TITLE_COMMAND_EDITOR); @@ -447,14 +456,26 @@ static void window_title_editor_mouseup(rct_window *w, rct_widgetindex widgetInd break; case WIDX_TITLE_EDITOR_STOP: if (_isSequencePlaying) { - title_set_current_sequence(0); + uint16 preset = title_get_config_sequence(); + title_set_current_sequence(preset, false); + if (!gTestingTitleSequenceInGame) + { + ITitleSequencePlayer * player = window_title_editor_get_player(); + player->Begin(preset); + } _isSequencePlaying = false; + gTestingTitleSequenceInGame = false; } break; case WIDX_TITLE_EDITOR_PLAY: - if (!_isSequencePlaying && (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) { - title_set_current_sequence((uint16)_selectedTitleSequence); + if (!_isSequencePlaying || _selectedTitleSequence != title_get_current_sequence()) { + ITitleSequencePlayer * player = window_title_editor_get_player(); + title_set_current_sequence((uint16)_selectedTitleSequence, true); + player->Begin((uint32)_selectedTitleSequence); _isSequencePlaying = true; + if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) { + gTestingTitleSequenceInGame = true; + } } break; case WIDX_TITLE_EDITOR_SKIP: @@ -747,7 +768,7 @@ static void window_title_editor_invalidate(rct_window *w) window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].top = w->height - 32; window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].bottom = w->height - 16; - if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) { + if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) && gScreenFlags != SCREEN_FLAGS_PLAYING) { w->disabled_widgets |= (1 << WIDX_TITLE_EDITOR_PLAY); } else { w->disabled_widgets &= ~(1 << WIDX_TITLE_EDITOR_PLAY); @@ -840,7 +861,7 @@ static void window_title_editor_scrollpaint_saves(rct_window *w, rct_drawpixelin static void window_title_editor_scrollpaint_commands(rct_window *w, rct_drawpixelinfo *dpi) { sint32 position = -1; - if (_isSequencePlaying) { + if (_isSequencePlaying && (uint16)_selectedTitleSequence == title_get_current_sequence()) { ITitleSequencePlayer * player = window_title_editor_get_player(); position = title_sequence_player_get_current_position(player); } diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 1657e64705..544e81efb6 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -377,12 +377,87 @@ namespace OpenRCT2 return true; } - bool LoadParkFromFile(const std::string &path, bool loadTitleScreenOnFail = false) final override + bool LoadParkFromFile(const std::string &path, bool loadTitleScreenOnFail) final override { auto fs = FileStream(path, FILE_MODE_OPEN); return LoadParkFromStream(&fs, path, loadTitleScreenOnFail); } + bool LoadParkFromStream(IStream * stream, const std::string &path, bool loadTitleScreenFirstOnFail) final override + { + ClassifiedFileInfo info; + if (TryClassifyFile(stream, &info)) + { + if (info.Type == FILE_TYPE::SAVED_GAME || + info.Type == FILE_TYPE::SCENARIO) + { + std::unique_ptr parkImporter; + if (info.Version <= FILE_TYPE_S4_CUTOFF) + { + // Save is an S4 (RCT1 format) + parkImporter.reset(ParkImporter::CreateS4()); + } + else + { + // Save is an S6 (RCT2 format) + parkImporter.reset(ParkImporter::CreateS6(_objectRepository, _objectManager)); + } + + auto result = parkImporter->LoadFromStream(stream, info.Type == FILE_TYPE::SCENARIO, false, path.c_str()); + if (result.Error == PARK_LOAD_ERROR_OK) + { + parkImporter->Import(); + game_fix_save_vars(); + sprite_position_tween_reset(); + gScreenAge = 0; + gLastAutoSaveUpdate = AUTOSAVE_PAUSE; + if (info.Type == FILE_TYPE::SAVED_GAME) + { + if (network_get_mode() == NETWORK_MODE_CLIENT) + { + network_close(); + } + game_load_init(); + if (network_get_mode() == NETWORK_MODE_SERVER) + { + network_send_map(); + } + } + else + { + scenario_begin(); + if (network_get_mode() == NETWORK_MODE_SERVER) + { + network_send_map(); + } + if (network_get_mode() == NETWORK_MODE_CLIENT) + { + network_close(); + } + } + // This ensures that the newly loaded save reflects the user's + // 'show real names of guests' option, now that it's a global setting + peep_update_names(gConfigGeneral.show_real_names_of_guests); + return true; + } + else + { + handle_park_load_failure_with_title_opt(&result, path.c_str(), loadTitleScreenFirstOnFail); + } + + } + else + { + Console::Error::WriteLine("Invalid file type."); + } + } + else + { + Console::Error::WriteLine("Unable to detect file type."); + } + return false; + } + private: std::string GetOrPromptRCT2Path() { @@ -701,81 +776,6 @@ namespace OpenRCT2 console_update(); } - bool LoadParkFromStream(IStream * stream, const std::string &path, bool loadTitleScreenFirstOnFail) - { - ClassifiedFileInfo info; - if (TryClassifyFile(stream, &info)) - { - if (info.Type == FILE_TYPE::SAVED_GAME || - info.Type == FILE_TYPE::SCENARIO) - { - std::unique_ptr parkImporter; - if (info.Version <= FILE_TYPE_S4_CUTOFF) - { - // Save is an S4 (RCT1 format) - parkImporter.reset(ParkImporter::CreateS4()); - } - else - { - // Save is an S6 (RCT2 format) - parkImporter.reset(ParkImporter::CreateS6(_objectRepository, _objectManager)); - } - - auto result = parkImporter->LoadFromStream(stream, info.Type == FILE_TYPE::SCENARIO, false, path.c_str()); - if (result.Error == PARK_LOAD_ERROR_OK) - { - parkImporter->Import(); - game_fix_save_vars(); - sprite_position_tween_reset(); - gScreenAge = 0; - gLastAutoSaveUpdate = AUTOSAVE_PAUSE; - if (info.Type == FILE_TYPE::SAVED_GAME) - { - if (network_get_mode() == NETWORK_MODE_CLIENT) - { - network_close(); - } - game_load_init(); - if (network_get_mode() == NETWORK_MODE_SERVER) - { - network_send_map(); - } - } - else - { - scenario_begin(); - if (network_get_mode() == NETWORK_MODE_SERVER) - { - network_send_map(); - } - if (network_get_mode() == NETWORK_MODE_CLIENT) - { - network_close(); - } - } - // This ensures that the newly loaded save reflects the user's - // 'show real names of guests' option, now that it's a global setting - peep_update_names(gConfigGeneral.show_real_names_of_guests); - return true; - } - else - { - handle_park_load_failure_with_title_opt(&result, path.c_str(), loadTitleScreenFirstOnFail); - } - - } - else - { - Console::Error::WriteLine("Invalid file type."); - } - } - else - { - Console::Error::WriteLine("Unable to detect file type."); - } - return false; - } - /** * Copy saved games and landscapes to user directory */ @@ -880,6 +880,11 @@ extern "C" return GetContext()->LoadParkFromFile(path); } + bool context_load_park_from_stream(void * stream) + { + return GetContext()->LoadParkFromStream((IStream*)stream, ""); + } + void openrct2_write_full_version_info(utf8 * buffer, size_t bufferSize) { String::Set(buffer, bufferSize, gVersionInfoFull); diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index d56dcc7995..5f492c285a 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -69,6 +69,8 @@ enum #include +interface IStream; + namespace OpenRCT2 { interface IPlatformEnvironment; @@ -97,6 +99,7 @@ namespace OpenRCT2 virtual bool Initialise() abstract; virtual bool LoadParkFromFile(const std::string &path, bool loadTitleScreenOnFail = false) abstract; + virtual bool LoadParkFromStream(IStream * stream, const std::string &path, bool loadTitleScreenFirstOnFail = false) abstract; virtual void Finish() abstract; virtual void Quit() abstract; @@ -221,6 +224,7 @@ extern "C" void context_quit(); const utf8 * context_get_path_legacy(sint32 pathId); bool context_load_park_from_file(const utf8 * path); + bool context_load_park_from_stream(void * stream); #ifdef __cplusplus } #endif diff --git a/src/openrct2/game.c b/src/openrct2/game.c index 10973e6b7c..d49330cfea 100644 --- a/src/openrct2/game.c +++ b/src/openrct2/game.c @@ -46,6 +46,7 @@ #include "ride/Vehicle.h" #include "scenario/scenario.h" #include "title/TitleScreen.h" +#include "title/TitleSequencePlayer.h" #include "util/sawyercoding.h" #include "util/util.h" #include "windows/Intent.h" @@ -73,6 +74,8 @@ sint32 gGameCommandNestLevel; bool gGameCommandIsNetworked; char gCurrentLoadedPath[MAX_PATH]; +bool gLoadKeepWindowsOpen = false; + uint8 gUnk13CA740; uint8 gUnk141F568; @@ -292,6 +295,11 @@ void game_update() screenshot_check(); game_handle_keyboard_input(); + if (game_is_not_paused() && gTestingTitleSequenceInGame) + { + title_sequence_player_update((ITitleSequencePlayer*)title_get_sequence_player()); + } + // Determine how many times we need to update the game if (gGameSpeed > 1) { numUpdates = 1 << (gGameSpeed - 1); @@ -1161,8 +1169,11 @@ void game_load_init() gScreenFlags = SCREEN_FLAGS_PLAYING; audio_stop_all_music_and_sounds(); - viewport_init_all(); - game_create_windows(); + if (!gLoadKeepWindowsOpen) + { + viewport_init_all(); + game_create_windows(); + } mainWindow = window_get_main(); if (mainWindow != NULL) diff --git a/src/openrct2/game.h b/src/openrct2/game.h index a0a10a094c..4d86b7f775 100644 --- a/src/openrct2/game.h +++ b/src/openrct2/game.h @@ -156,6 +156,8 @@ extern sint32 gGameCommandNestLevel; extern bool gGameCommandIsNetworked; extern char gCurrentLoadedPath[260]; +extern bool gLoadKeepWindowsOpen; + extern uint8 gUnk13CA740; extern uint8 gUnk141F568; diff --git a/src/openrct2/interface/viewport.c b/src/openrct2/interface/viewport.c index 18140ae932..d33f1e73cc 100644 --- a/src/openrct2/interface/viewport.c +++ b/src/openrct2/interface/viewport.c @@ -1348,10 +1348,16 @@ static void sub_68862C(rct_drawpixelinfo * dpi, paint_struct * ps) * viewport: edi */ void get_map_coordinates_from_pos(sint32 screenX, sint32 screenY, sint32 flags, sint16 *x, sint16 *y, sint32 *interactionType, rct_map_element **mapElement, rct_viewport **viewport) +{ + rct_window* window = window_find_from_point(screenX, screenY); + get_map_coordinates_from_pos_window(window, screenX, screenY, flags, x, y, interactionType, mapElement, viewport); +} + +void get_map_coordinates_from_pos_window(rct_window * window, sint32 screenX, sint32 screenY, sint32 flags, sint16 * x, sint16 * y, + sint32 * interactionType, rct_map_element ** mapElement, rct_viewport ** viewport) { _unk9AC154 = flags & 0xFFFF; _interactionSpriteType = 0; - rct_window* window = window_find_from_point(screenX, screenY); if (window != NULL && window->viewport != NULL) { rct_viewport* myviewport = window->viewport; diff --git a/src/openrct2/interface/viewport.h b/src/openrct2/interface/viewport.h index f4eaafd667..f5656479ff 100644 --- a/src/openrct2/interface/viewport.h +++ b/src/openrct2/interface/viewport.h @@ -143,6 +143,8 @@ void hide_construction_rights(); void viewport_set_visibility(uint8 mode); void get_map_coordinates_from_pos(sint32 screenX, sint32 screenY, sint32 flags, sint16 *x, sint16 *y, sint32 *interactionType, rct_map_element **mapElement, rct_viewport **viewport); +void get_map_coordinates_from_pos_window(rct_window * window, sint32 screenX, sint32 screenY, sint32 flags, sint16 * x, sint16 * y, + sint32 * interactionType, rct_map_element ** mapElement, rct_viewport ** viewport); sint32 viewport_interaction_get_item_left(sint32 x, sint32 y, viewport_interaction_info *info); sint32 viewport_interaction_left_over(sint32 x, sint32 y); diff --git a/src/openrct2/scenario/scenario.c b/src/openrct2/scenario/scenario.c index 86750037c8..9111a8c928 100644 --- a/src/openrct2/scenario/scenario.c +++ b/src/openrct2/scenario/scenario.c @@ -105,7 +105,7 @@ void scenario_begin() research_reset_current_item(); scenery_set_default_placement_configuration(); news_item_init_queue(); - if (gScenarioObjectiveType != OBJECTIVE_NONE) + if (gScenarioObjectiveType != OBJECTIVE_NONE && !gLoadKeepWindowsOpen) context_open_window_view(WV_PARK_OBJECTIVE); gParkRating = calculate_park_rating(); diff --git a/src/openrct2/title/TitleScreen.cpp b/src/openrct2/title/TitleScreen.cpp index 5eeae7ff74..91d4da15ae 100644 --- a/src/openrct2/title/TitleScreen.cpp +++ b/src/openrct2/title/TitleScreen.cpp @@ -58,9 +58,13 @@ uint16 TitleScreen::GetCurrentSequence() return _currentSequence; } -void TitleScreen::SetCurrentSequence(uint16 value) +void TitleScreen::SetCurrentSequence(uint16 value, bool loadSequence) { _currentSequence = value; + if (loadSequence) + { + TryLoadSequence(); + } } bool TitleScreen::ShouldHideVersionInfo() @@ -103,7 +107,7 @@ void TitleScreen::Load() if (_sequencePlayer != nullptr) { - _sequencePlayer->Reset(); + _sequencePlayer->Begin(_currentSequence); // Force the title sequence to load / update so we // don't see a blank screen for a split second. @@ -187,7 +191,7 @@ void TitleScreen::TitleInitialise() IScenarioRepository * scenarioRepository = GetScenarioRepository(); _sequencePlayer = CreateTitleSequencePlayer(scenarioRepository); } - size_t seqId = title_sequence_manager_get_index_for_config_id(gConfigInterface.current_title_sequence_preset); + size_t seqId = title_get_config_sequence(); if (seqId == SIZE_MAX) { seqId = title_sequence_manager_get_index_for_config_id("*OPENRCT2"); @@ -283,6 +287,11 @@ extern "C" } } + uint16 title_get_config_sequence() + { + return (uint16)title_sequence_manager_get_index_for_config_id(gConfigInterface.current_title_sequence_preset); + } + uint16 title_get_current_sequence() { uint16 result = 0; @@ -293,11 +302,11 @@ extern "C" return result; } - void title_set_current_sequence(uint16 value) + void title_set_current_sequence(uint16 value, bool loadSequence) { if (_singleton != nullptr) { - _singleton->SetCurrentSequence(value); + _singleton->SetCurrentSequence(value, loadSequence); } } diff --git a/src/openrct2/title/TitleScreen.h b/src/openrct2/title/TitleScreen.h index 6dd3701c78..f609ed1754 100644 --- a/src/openrct2/title/TitleScreen.h +++ b/src/openrct2/title/TitleScreen.h @@ -28,7 +28,7 @@ class TitleScreen final public: ITitleSequencePlayer * GetSequencePlayer(); uint16 GetCurrentSequence(); - void SetCurrentSequence(uint16 value); + void SetCurrentSequence(uint16 value, bool loadSequence); bool ShouldHideVersionInfo(); void SetHideVersionInfo(bool value); @@ -61,8 +61,9 @@ extern "C" void title_sequence_change_preset(sint32 preset); bool title_should_hide_version_info(); void title_set_hide_version_info(bool value); + uint16 title_get_config_sequence(); uint16 title_get_current_sequence(); - void title_set_current_sequence(uint16 value); + void title_set_current_sequence(uint16 value, bool loadSequence); void DrawOpenRCT2(rct_drawpixelinfo *dpi, sint32 x, sint32 y); #ifdef __cplusplus } diff --git a/src/openrct2/title/TitleSequencePlayer.cpp b/src/openrct2/title/TitleSequencePlayer.cpp index 5ed4896619..95084451fc 100644 --- a/src/openrct2/title/TitleSequencePlayer.cpp +++ b/src/openrct2/title/TitleSequencePlayer.cpp @@ -27,6 +27,7 @@ #include "../ParkImporter.h" #include "../scenario/ScenarioRepository.h" #include "../scenario/ScenarioSources.h" +#include "TitleScreen.h" #include "TitleSequence.h" #include "TitleSequenceManager.h" #include "TitleSequencePlayer.h" @@ -187,12 +188,17 @@ public: Reset(); } + if (_sequence->Commands[targetPosition].Type == TITLE_SCRIPT_RESTART) + { + targetPosition = 0; + } // Set position to the last LOAD command before target position for (sint32 i = targetPosition; i >= 0; i--) { const TitleCommand * command = &_sequence->Commands[i]; - if (TitleSequenceIsLoadCommand(command)) + if ((_position == i && _position != targetPosition) || TitleSequenceIsLoadCommand(command)) { + // Break if we have a new load command or if we're already in the range of the correct load command _position = i; break; } @@ -363,9 +369,18 @@ private: bool success = false; try { - auto parkImporter = std::unique_ptr(ParkImporter::Create(path)); - parkImporter->Load(path); - parkImporter->Import(); + if (gTestingTitleSequenceInGame) + { + gLoadKeepWindowsOpen = true; + CloseParkSpecificWindows(); + context_load_park_from_file(path); + } + else + { + auto parkImporter = std::unique_ptr(ParkImporter::Create(path)); + parkImporter->Load(path); + parkImporter->Import(); + } PrepareParkForPlayback(); success = true; } @@ -373,6 +388,7 @@ private: { Console::Error::WriteLine("Unable to load park: %s", path); } + gLoadKeepWindowsOpen = false; return success; } @@ -386,11 +402,20 @@ private: bool success = false; try { - std::string extension = Path::GetExtension(hintPath); - bool isScenario = ParkImporter::ExtensionIsScenario(hintPath); - auto parkImporter = std::unique_ptr(ParkImporter::Create(hintPath)); - parkImporter->LoadFromStream(stream, isScenario); - parkImporter->Import(); + if (gTestingTitleSequenceInGame) + { + gLoadKeepWindowsOpen = true; + CloseParkSpecificWindows(); + context_load_park_from_stream(stream); + } + else + { + std::string extension = Path::GetExtension(hintPath); + bool isScenario = ParkImporter::ExtensionIsScenario(hintPath); + auto parkImporter = std::unique_ptr(ParkImporter::Create(hintPath)); + parkImporter->LoadFromStream(stream, isScenario); + parkImporter->Import(); + } PrepareParkForPlayback(); success = true; } @@ -398,9 +423,34 @@ private: { Console::Error::WriteLine("Unable to load park: %s", hintPath.c_str()); } + gLoadKeepWindowsOpen = false; return success; } + void CloseParkSpecificWindows() + { + window_close_by_class(WC_CONSTRUCT_RIDE); + window_close_by_class(WC_DEMOLISH_RIDE_PROMPT); + window_close_by_class(WC_EDITOR_INVENTION_LIST_DRAG); + window_close_by_class(WC_EDITOR_INVENTION_LIST); + window_close_by_class(WC_EDITOR_OBJECT_SELECTION); + window_close_by_class(WC_EDTIOR_OBJECTIVE_OPTIONS); + window_close_by_class(WC_EDITOR_SCENARIO_OPTIONS); + window_close_by_class(WC_FINANCES); + window_close_by_class(WC_FIRE_PROMPT); + window_close_by_class(WC_GUEST_LIST); + window_close_by_class(WC_INSTALL_TRACK); + window_close_by_class(WC_PEEP); + window_close_by_class(WC_RIDE); + window_close_by_class(WC_RIDE_CONSTRUCTION); + window_close_by_class(WC_RIDE_LIST); + window_close_by_class(WC_SCENERY); + window_close_by_class(WC_STAFF); + window_close_by_class(WC_TRACK_DELETE_PROMPT); + window_close_by_class(WC_TRACK_DESIGN_LIST); + window_close_by_class(WC_TRACK_DESIGN_PLACE); + } + void PrepareParkForPlayback() { rct_window * w = window_get_main(); @@ -452,7 +502,13 @@ private: if (w != nullptr) { sint32 z = map_element_height(x, y); + + // Prevent scroll adjustment due to window placement when in-game + auto oldScreenFlags = gScreenFlags; + gScreenFlags = SCREEN_FLAGS_TITLE_DEMO; window_set_location(w, x, y, z); + gScreenFlags = oldScreenFlags; + viewport_update_position(w); // Save known tile position in case of window resize @@ -487,6 +543,8 @@ ITitleSequencePlayer * CreateTitleSequencePlayer(IScenarioRepository * scenarioR extern "C" { + bool gTestingTitleSequenceInGame = false; + sint32 title_sequence_player_get_current_position(ITitleSequencePlayer * player) { return player->GetCurrentPosition(); diff --git a/src/openrct2/title/TitleSequencePlayer.h b/src/openrct2/title/TitleSequencePlayer.h index a7b4e95d0d..df4bf0666e 100644 --- a/src/openrct2/title/TitleSequencePlayer.h +++ b/src/openrct2/title/TitleSequencePlayer.h @@ -45,6 +45,9 @@ typedef struct ITitleSequencePlayer ITitleSequencePlayer; extern "C" { #endif + // When testing title sequences within a normal game + extern bool gTestingTitleSequenceInGame; + sint32 title_sequence_player_get_current_position(ITitleSequencePlayer * player); bool title_sequence_player_begin(ITitleSequencePlayer * player, uint32 titleSequenceId); void title_sequence_player_reset(ITitleSequencePlayer * player);