1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-04 13:42:55 +01:00

add a CLI command for converting saved games <-> scenarios

This commit is contained in:
Ted John
2016-04-19 22:09:42 +01:00
parent f1b41bf51d
commit f3356caa39
12 changed files with 256 additions and 16 deletions

View File

@@ -24,6 +24,7 @@
<ClCompile Include="src\audio\mixer.cpp" />
<ClCompile Include="src\cheats.c" />
<ClCompile Include="src\cmdline\CommandLine.cpp" />
<ClCompile Include="src\cmdline\ConvertCommand.cpp" />
<ClCompile Include="src\cmdline\RootCommands.cpp" />
<ClCompile Include="src\cmdline\ScreenshotCommands.cpp" />
<ClCompile Include="src\cmdline\SpriteCommands.cpp" />

View File

@@ -600,6 +600,9 @@
<ClCompile Include="src\rct1\Tables.cpp">
<Filter>Source\RCT1</Filter>
</ClCompile>
<ClCompile Include="src\cmdline\ConvertCommand.cpp">
<Filter>Source\CommandLine</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\management\award.h">

View File

@@ -1,21 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ShowAllFiles>true</ShowAllFiles>
<ShowAllFiles>false</ShowAllFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>convert C:\Users\Ted\Documents\Projects\OpenRCT2\RCT1\LoopyLandscapes\Scenarios\sc0.sc4 ff.sc6</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>C:\Users\Ted\Desktop\rct1ll\Scenarios\sc1.sc4</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release XP|Win32'">
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>

View File

@@ -91,4 +91,6 @@ namespace CommandLine
void PrintHelp(bool allCommands = false);
exitcode_t HandleCommandDefault();
exitcode_t HandleCommandConvert(CommandLineArgEnumerator * enumerator);
}

View File

@@ -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;
}

View File

@@ -78,14 +78,15 @@ static void PrintLaunchInformation();
const CommandLineCommand CommandLine::RootCommands[]
{
// Main commands
DefineCommand("", "<uri>", StandardOptions, HandleNoCommand ),
DefineCommand("edit", "<uri>", StandardOptions, HandleCommandEdit ),
DefineCommand("intro", "", StandardOptions, HandleCommandIntro ),
#ifndef DISABLE_NETWORK
DefineCommand("host", "<uri>", StandardOptions, HandleCommandHost ),
DefineCommand("join", "<hostname>", StandardOptions, HandleCommandJoin ),
DefineCommand("", "<uri>", StandardOptions, HandleNoCommand ),
DefineCommand("edit", "<uri>", StandardOptions, HandleCommandEdit ),
DefineCommand("intro", "", StandardOptions, HandleCommandIntro ),
#ifndef DISABLE_NETWORK
DefineCommand("host", "<uri>", StandardOptions, HandleCommandHost ),
DefineCommand("join", "<hostname>", StandardOptions, HandleCommandJoin ),
#endif
DefineCommand("set-rct2", "<path>", StandardOptions, HandleCommandSetRCT2),
DefineCommand("set-rct2", "<path>", StandardOptions, HandleCommandSetRCT2),
DefineCommand("convert", "<source> <destination>", StandardOptions, CommandLine::HandleCommandConvert),
#if defined(__WINDOWS__) && !defined(__MINGW32__)
DefineCommand("register-shell", "", RegisterShellOptions, HandleCommandRegisterShell),

View File

@@ -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;

View File

@@ -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__

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;