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;