diff --git a/src/rct2/S6Importer.cpp b/src/rct2/S6Importer.cpp index fe53dddf4a..91b72db8d0 100644 --- a/src/rct2/S6Importer.cpp +++ b/src/rct2/S6Importer.cpp @@ -437,6 +437,41 @@ extern "C" return result; } + bool scenario_load_rw(SDL_RWops * rw) + { + bool result = false; + auto s6Importer = new S6Importer(); + try + { + s6Importer->FixIssues = true; + s6Importer->LoadScenario(rw); + s6Importer->Import(); + + openrct2_reset_object_tween_locations(); + result = true; + } + catch (ObjectLoadException) + { + gErrorType = ERROR_TYPE_FILE_LOAD; + gErrorStringId = STR_GAME_SAVE_FAILED; + } + catch (IOException) + { + gErrorType = ERROR_TYPE_FILE_LOAD; + gErrorStringId = STR_GAME_SAVE_FAILED; + } + catch (Exception) + { + gErrorType = ERROR_TYPE_FILE_LOAD; + gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA; + } + delete s6Importer; + + gScreenAge = 0; + gLastAutoSaveTick = SDL_GetTicks(); + return result; + } + /** * * rct2: 0x00676053 diff --git a/src/scenario.h b/src/scenario.h index 5b4531ebc4..014446b104 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -408,6 +408,7 @@ extern uint32 gLastAutoSaveTick; extern const char *_scenarioFileName; bool scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info); +bool scenario_load_rw(SDL_RWops * rw); int scenario_load(const char *path); int scenario_load_and_play_from_path(const char *path); void scenario_begin(); diff --git a/src/title.c b/src/title.c index 638c8fd8be..fa4cb46a03 100644 --- a/src/title.c +++ b/src/title.c @@ -98,6 +98,8 @@ static uint8 *generate_random_script(); #pragma endregion +static bool title_load_park(SDL_RWops * rw, bool isScenario); + /** * * rct2: 0x0068E8DA @@ -180,23 +182,35 @@ static void title_init_showcase() title_refresh_sequence(); } -static int title_load_park(const char *path) +static bool title_load_park_from_file(const char * path) +{ + bool success = false; + bool isScenario = _strcmpi(path_get_extension(path), ".sv6"); + SDL_RWops * rw = SDL_RWFromFile(path, "rb"); + if (rw != NULL) { + success = title_load_park(rw, isScenario); + SDL_RWclose(rw); + } + return success; +} + +static bool title_load_park_from_zip(const char * path) +{ + return false; +} + +static bool title_load_park(SDL_RWops * rw, bool isScenario) { rct_window* w; int successfulLoad = 0; - if (_strcmpi(path_get_extension(path), ".sv6") == 0) { - SDL_RWops* rw = SDL_RWFromFile(path, "rb"); - if (rw != NULL) { - successfulLoad = game_load_sv6(rw); - SDL_RWclose(rw); - } + if (isScenario) { + successfulLoad = scenario_load_rw(rw); } else { - successfulLoad = scenario_load(path); + successfulLoad = game_load_sv6(rw); } - if (!successfulLoad) - return 0; + return false; w = window_get_main(); w->viewport_target_sprite = -1; @@ -225,8 +239,9 @@ static int title_load_park(const char *path) reset_sprite_spatial_index(); reset_all_sprite_quadrant_placements(); window_new_ride_init_vars(); - if (_strcmpi(path_get_extension(path), ".sv6") != 0) + if (!isScenario) { sub_684AC3(); + } scenery_set_default_placement_configuration(); news_item_init_queue(); load_palette(); @@ -234,7 +249,7 @@ static int title_load_park(const char *path) window_tile_inspector_clear_clipboard(); gScreenAge = 0; gGameSpeed = 1; - return 1; + return true; } /** @@ -338,7 +353,7 @@ static void title_do_next_script_opcode() _scriptWaitCounter = (*_currentScript++) * 32; break; case TITLE_SCRIPT_LOADMM: - if (!title_load_park(get_file_path(PATH_ID_SIXFLAGS_MAGICMOUNTAIN))) { + if (!title_load_park_from_file(get_file_path(PATH_ID_SIXFLAGS_MAGICMOUNTAIN))) { log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario."); exit(-1); } @@ -379,22 +394,16 @@ static void title_do_next_script_opcode() break; case TITLE_SCRIPT_LOAD: { - char *ch, filename[32], path[MAX_PATH]; + uint8 saveIndex = _loadedTitleSequence->Commands[gTitleScriptCommand].SaveIndex; + TitleSequenceParkHandle * parkHandle = TitleSequenceGetParkHandle(_loadedTitleSequence, saveIndex); + bool loadSuccess = title_load_park(parkHandle->RWOps, parkHandle->IsScenario); + TitleSequenceCloseParkHandle(parkHandle); - // Get filename - ch = filename; - do { - *ch++ = *_currentScript++; - } while (*(_currentScript - 1) != 0); - - // Construct full relative path - safe_strcpy(path, _loadedTitleSequence->Path, sizeof(path)); - safe_strcat_path(path, filename, sizeof(path)); - if (title_load_park(path)) { + if (loadSuccess) { _scriptNoLoadsSinceRestart = 0; gTitleScriptSave = _loadedTitleSequence->Commands[gTitleScriptCommand].SaveIndex; } else { - log_error("Failed to load: \"%s\" for the title sequence.", path); + log_error("Failed to load: \"%s\" for the title sequence.", _loadedTitleSequence->Saves[saveIndex]); script_opcode = *_currentScript; while (script_opcode != TITLE_SCRIPT_LOADMM && script_opcode != TITLE_SCRIPT_LOAD && script_opcode != TITLE_SCRIPT_RESTART && script_opcode != TITLE_SCRIPT_END) { title_skip_opcode(); @@ -439,7 +448,7 @@ static void title_do_next_script_opcode() } } - if (path == NULL || !title_load_park(path)) { + if (path == NULL || !title_load_park_from_file(path)) { script_opcode = *_currentScript; while (script_opcode != TITLE_SCRIPT_LOADRCT1 && script_opcode != TITLE_SCRIPT_RESTART && script_opcode != TITLE_SCRIPT_END) { title_skip_opcode(); diff --git a/src/title/TitleSequence.cpp b/src/title/TitleSequence.cpp index 76963020f9..0946ee8139 100644 --- a/src/title/TitleSequence.cpp +++ b/src/title/TitleSequence.cpp @@ -19,6 +19,7 @@ #include #include #include "../core/Collections.hpp" +#include "../core/Guard.hpp" #include "../core/Math.hpp" #include "../core/Memory.hpp" #include "../core/Path.hpp" @@ -77,6 +78,33 @@ extern "C" Memory::Free(seq->Saves); } } + + TitleSequenceParkHandle * TitleSequenceGetParkHandle(TitleSequence * seq, size_t index) + { + int error; + zip_t * zip = zip_open(seq->Path, ZIP_RDONLY, &error); + if (zip == nullptr) + { + // Unable to open zip + return nullptr; + } + + Guard::Assert(index < seq->NumSaves, "Invalid park save index."); + utf8 * filename = seq->Saves[index]; + + auto handle = Memory::Allocate(); + handle->Data = GetZipFileData(zip, filename, &handle->DataSize); + handle->RWOps = SDL_RWFromMem(handle->Data, (int)handle->DataSize); + handle->IsScenario = String::Equals(Path::GetExtension(filename), ".sc6", true); + return handle; + } + + void TitleSequenceCloseParkHandle(TitleSequenceParkHandle * handle) + { + SDL_RWclose(handle->RWOps); + Memory::Free(handle->Data); + Memory::Free(handle); + } } static std::vector GetSaves(zip_t * zip) diff --git a/src/title/TitleSequence.h b/src/title/TitleSequence.h index 4f4d061970..ff29b50343 100644 --- a/src/title/TitleSequence.h +++ b/src/title/TitleSequence.h @@ -18,6 +18,8 @@ #include "../common.h" +struct SDL_RWops; + typedef struct TitleCommand { uint8 Type; @@ -47,6 +49,14 @@ typedef struct TitleSequence utf8 * * Saves; } TitleSequence; +typedef struct TitleSequenceParkHandle +{ + size_t DataSize; + void * Data; + struct SDL_RWops * RWOps; + bool IsScenario; +} TitleSequenceParkHandle; + enum TITLE_SCRIPT { TITLE_SCRIPT_UNDEFINED = 0xFF, @@ -70,6 +80,9 @@ extern "C" #endif TitleSequence * LoadTitleSequence(const utf8 * path); void FreeTitleSequence(TitleSequence * seq); + + TitleSequenceParkHandle * TitleSequenceGetParkHandle(TitleSequence * seq, size_t index); + void TitleSequenceCloseParkHandle(TitleSequenceParkHandle * handle); #ifdef __cplusplus } #endif