diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 22fa969bc0..c471071417 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -24,6 +24,7 @@ + diff --git a/openrct2.vcxproj.filters b/openrct2.vcxproj.filters index 02f0fd2041..4bc24ee773 100644 --- a/openrct2.vcxproj.filters +++ b/openrct2.vcxproj.filters @@ -600,6 +600,9 @@ Source\RCT1 + + Source\CommandLine + diff --git a/openrct2.vcxproj.user b/openrct2.vcxproj.user index fd6680fbf4..a079535859 100644 --- a/openrct2.vcxproj.user +++ b/openrct2.vcxproj.user @@ -1,21 +1,19 @@  - true + false $(TargetDir)\openrct2.exe WindowsLocalDebugger $(TargetDir) - - + convert C:\Users\Ted\Documents\Projects\OpenRCT2\RCT1\LoopyLandscapes\Scenarios\sc0.sc4 ff.sc6 $(TargetDir) WindowsLocalDebugger $(TargetDir)\openrct2.exe - - + C:\Users\Ted\Desktop\rct1ll\Scenarios\sc1.sc4 $(TargetDir) diff --git a/src/cmdline/CommandLine.hpp b/src/cmdline/CommandLine.hpp index 3dc1f7a156..e96ef22931 100644 --- a/src/cmdline/CommandLine.hpp +++ b/src/cmdline/CommandLine.hpp @@ -91,4 +91,6 @@ namespace CommandLine void PrintHelp(bool allCommands = false); exitcode_t HandleCommandDefault(); + + exitcode_t HandleCommandConvert(CommandLineArgEnumerator * enumerator); } diff --git a/src/cmdline/ConvertCommand.cpp b/src/cmdline/ConvertCommand.cpp new file mode 100644 index 0000000000..fe5eda9ca6 --- /dev/null +++ b/src/cmdline/ConvertCommand.cpp @@ -0,0 +1,177 @@ +#include "../common.h" +#include "../core/Console.hpp" +#include "../core/Exception.hpp" +#include "../core/Path.hpp" +#include "../rct1/S4Importer.h" +#include "CommandLine.hpp" + +extern "C" +{ + #include "../game.h" + #include "../scenario.h" + #include "../openrct2.h" + #include "../interface/window.h" +} + +static void WriteConvertFromAndToMessage(uint32 sourceFileType, uint32 destinationFileType); +static const utf8 * GetFileTypeFriendlyName(uint32 fileType); + +exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator * enumerator) +{ + exitcode_t result = CommandLine::HandleCommandDefault(); + if (result != EXITCODE_CONTINUE) + { + return result; + } + + // Get the source path + const utf8 * rawSourcePath; + if (!enumerator->TryPopString(&rawSourcePath)) + { + Console::Error::WriteLine("Expected a source path."); + return EXITCODE_FAIL; + } + + utf8 sourcePath[MAX_PATH]; + Path::GetAbsolute(sourcePath, sizeof(sourcePath), rawSourcePath); + uint32 sourceFileType = get_file_extension_type(sourcePath); + + // Get the destination path + const utf8 * rawDestinationPath; + if (!enumerator->TryPopString(&rawDestinationPath)) + { + Console::Error::WriteLine("Expected a destination path."); + return EXITCODE_FAIL; + } + + utf8 destinationPath[MAX_PATH]; + Path::GetAbsolute(destinationPath, sizeof(sourcePath), rawDestinationPath); + uint32 destinationFileType = get_file_extension_type(destinationPath); + + // Validate target type + if (destinationFileType != FILE_EXTENSION_SC6 && + destinationFileType != FILE_EXTENSION_SV6) + { + Console::Error::WriteLine("Only conversion to .SC6 or .SV4 is supported."); + return EXITCODE_FAIL; + } + + // Validate the source type + switch (sourceFileType) { + case FILE_EXTENSION_SC4: + case FILE_EXTENSION_SV4: + break; + case FILE_EXTENSION_SC6: + if (destinationFileType == FILE_EXTENSION_SC6) + { + Console::Error::WriteLine("File is already a RollerCoaster Tycoon 2 scenario."); + return EXITCODE_FAIL; + } + break; + case FILE_EXTENSION_SV6: + if (destinationFileType == FILE_EXTENSION_SV6) + { + Console::Error::WriteLine("File is already a RollerCoaster Tycoon 2 saved game."); + return EXITCODE_FAIL; + } + break; + default: + Console::Error::WriteLine("Only conversion from .SC4, .SV4, .SC6 or .SV6 is supported."); + return EXITCODE_FAIL; + } + + // Perform conversion + WriteConvertFromAndToMessage(sourceFileType, destinationFileType); + + gOpenRCT2Headless = true; + if (!openrct2_initialise()) { + Console::Error::WriteLine("Error while initialising OpenRCT2."); + return EXITCODE_FAIL; + } + + if (sourceFileType == FILE_EXTENSION_SV4 || + sourceFileType == FILE_EXTENSION_SC4) + { + auto s4Importer = new S4Importer(); + try + { + if (sourceFileType == FILE_EXTENSION_SC4) + { + s4Importer->LoadScenario(sourcePath); + } + if (sourceFileType == FILE_EXTENSION_SV4) + { + s4Importer->LoadSavedGame(sourcePath); + } + + s4Importer->Import(); + + if (sourceFileType == FILE_EXTENSION_SC4) + { + // We are converting a scenario, so reset the park + scenario_begin(); + } + } + catch (Exception ex) + { + Console::Error::WriteLine(ex.GetMsg()); + return EXITCODE_FAIL; + } + } + else + { + if (sourceFileType == FILE_EXTENSION_SC6) + { + scenario_load_and_play_from_path(sourcePath); + } + if (sourceFileType == FILE_EXTENSION_SV6) + { + game_load_save(sourcePath); + } + } + + SDL_RWops* rw = SDL_RWFromFile(destinationPath, "wb+"); + if (rw != NULL) { + // HACK remove the main window so it saves the park with the + // correct initial view + window_close_by_class(WC_MAIN_WINDOW); + + if (destinationFileType == FILE_EXTENSION_SC6) + { + scenario_save(rw, 0x80000002); + } + else + { + scenario_save(rw, 0x80000001); + } + SDL_RWclose(rw); + Console::WriteLine("Conversion successful!"); + } + else + { + Console::Error::WriteLine("Unable to write destination file."); + return EXITCODE_FAIL; + } + return EXITCODE_OK; +} + +static void WriteConvertFromAndToMessage(uint32 sourceFileType, uint32 destinationFileType) +{ + const utf8 * sourceFileTypeName = GetFileTypeFriendlyName(sourceFileType); + const utf8 * destinationFileTypeName = GetFileTypeFriendlyName(destinationFileType); + Console::WriteFormat("Converting from a %s to a %s.", sourceFileTypeName, destinationFileTypeName); + Console::WriteLine(); +} + +static const utf8 * GetFileTypeFriendlyName(uint32 fileType) +{ + switch (fileType) { + case FILE_EXTENSION_SC4: return "RollerCoaster Tycoon 1 scenario"; + case FILE_EXTENSION_SV4: return "RollerCoaster Tycoon 1 saved game"; + case FILE_EXTENSION_SC6: return "RollerCoaster Tycoon 2 scenario"; + case FILE_EXTENSION_SV6: return "RollerCoaster Tycoon 2 saved game"; + } + + assert(false); + return nullptr; +} diff --git a/src/cmdline/RootCommands.cpp b/src/cmdline/RootCommands.cpp index df280935ce..c11fb76c5c 100644 --- a/src/cmdline/RootCommands.cpp +++ b/src/cmdline/RootCommands.cpp @@ -78,14 +78,15 @@ static void PrintLaunchInformation(); const CommandLineCommand CommandLine::RootCommands[] { // Main commands - DefineCommand("", "", StandardOptions, HandleNoCommand ), - DefineCommand("edit", "", StandardOptions, HandleCommandEdit ), - DefineCommand("intro", "", StandardOptions, HandleCommandIntro ), -#ifndef DISABLE_NETWORK - DefineCommand("host", "", StandardOptions, HandleCommandHost ), - DefineCommand("join", "", StandardOptions, HandleCommandJoin ), + DefineCommand("", "", StandardOptions, HandleNoCommand ), + DefineCommand("edit", "", StandardOptions, HandleCommandEdit ), + DefineCommand("intro", "", StandardOptions, HandleCommandIntro ), +#ifndef DISABLE_NETWORK + DefineCommand("host", "", StandardOptions, HandleCommandHost ), + DefineCommand("join", "", StandardOptions, HandleCommandJoin ), #endif - DefineCommand("set-rct2", "", StandardOptions, HandleCommandSetRCT2), + DefineCommand("set-rct2", "", StandardOptions, HandleCommandSetRCT2), + DefineCommand("convert", " ", StandardOptions, CommandLine::HandleCommandConvert), #if defined(__WINDOWS__) && !defined(__MINGW32__) DefineCommand("register-shell", "", RegisterShellOptions, HandleCommandRegisterShell), diff --git a/src/core/Exception.hpp b/src/core/Exception.hpp index ed96db621e..8d37d1c658 100644 --- a/src/core/Exception.hpp +++ b/src/core/Exception.hpp @@ -18,6 +18,7 @@ public: const char * what() const throw() override { return _message; } const char * GetMessage() const { return _message; } + const char * GetMsg() const { return _message; } private: const char * _message; diff --git a/src/core/Path.cpp b/src/core/Path.cpp index 21a11a94bc..2af2208949 100644 --- a/src/core/Path.cpp +++ b/src/core/Path.cpp @@ -79,6 +79,28 @@ namespace Path return buffer; } + const utf8 * GetExtension(const utf8 * path) + { + const utf8 * lastDot = nullptr; + const utf8 * ch = path; + for (; *ch != '\0'; ch++) + { + if (*ch == '.') + { + lastDot = ch; + } + } + + if (lastDot == nullptr) + { + // Return the null terminator, i.e. a blank extension + return ch; + } + + // Return the extension including the dot + return lastDot; + } + utf8 * GetAbsolute(utf8 *buffer, size_t bufferSize, const utf8 * relativePath) { #if __WINDOWS__ diff --git a/src/core/Path.hpp b/src/core/Path.hpp index a74079bf53..3c5aa4f994 100644 --- a/src/core/Path.hpp +++ b/src/core/Path.hpp @@ -11,6 +11,7 @@ namespace Path utf8 * GetDirectory(utf8 * buffer, size_t bufferSize, const utf8 * path); const utf8 * GetFileName(const utf8 * path); utf8 * GetFileNameWithoutExtension(utf8 * buffer, size_t bufferSize, const utf8 * path); + const utf8 * GetExtension(const utf8 * path); utf8 * GetAbsolute(utf8 * buffer, size_t bufferSize, const utf8 * relativePath); bool Equals(const utf8 * a, const utf8 * b); } diff --git a/src/rct2.c b/src/rct2.c index 3a03265152..396c5920ee 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -499,3 +499,16 @@ const utf8 *get_file_path(int pathId) return path; } + +uint32 get_file_extension_type(const utf8 *path) +{ + const utf8 *extension = path_get_extension(path); + if (strcicmp(extension, ".dat") == 0) return FILE_EXTENSION_DAT; + if (strcicmp(extension, ".sc4") == 0) return FILE_EXTENSION_SC4; + if (strcicmp(extension, ".sv4") == 0) return FILE_EXTENSION_SV4; + if (strcicmp(extension, ".td4") == 0) return FILE_EXTENSION_TD4; + if (strcicmp(extension, ".sc6") == 0) return FILE_EXTENSION_SC6; + if (strcicmp(extension, ".sv6") == 0) return FILE_EXTENSION_SV6; + if (strcicmp(extension, ".td6") == 0) return FILE_EXTENSION_TD6; + return FILE_TYPE_UNKNOWN; +} \ No newline at end of file diff --git a/src/rct2.h b/src/rct2.h index 195f8319f8..1249b87d61 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -262,6 +262,21 @@ enum { PATH_ID_END }; +enum { + FILE_EXTENSION_UNKNOWN, + FILE_EXTENSION_DAT, + FILE_EXTENSION_SC4, + FILE_EXTENSION_SV4, + FILE_EXTENSION_TD4, + FILE_EXTENSION_SC6, + FILE_EXTENSION_SV6, + FILE_EXTENSION_TD6, +}; + +#ifdef __cplusplus +extern "C" { +#endif + extern const char * const RCT2FilePaths[PATH_ID_END]; extern uint32 gCurrentDrawCount; @@ -280,4 +295,10 @@ void rct2_quit(); bool rct2_open_file(const char *path); +uint32 get_file_extension_type(const utf8 *path); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/scenario.c b/src/scenario.c index 1bd16aaac4..bc9b5a58a6 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -982,10 +982,10 @@ int scenario_save(SDL_RWops* rw, int flags) viewZoom = viewport->zoom; viewRotation = get_current_rotation(); } else { - viewX = 0; - viewY = 0; - viewZoom = 0; - viewRotation = 0; + viewX = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, uint16); + viewY = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, uint16); + viewZoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) & 0xFF; + viewRotation = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) >> 8; } RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, uint16) = viewX;