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:
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -91,4 +91,6 @@ namespace CommandLine
|
||||
|
||||
void PrintHelp(bool allCommands = false);
|
||||
exitcode_t HandleCommandDefault();
|
||||
|
||||
exitcode_t HandleCommandConvert(CommandLineArgEnumerator * enumerator);
|
||||
}
|
||||
|
||||
177
src/cmdline/ConvertCommand.cpp
Normal file
177
src/cmdline/ConvertCommand.cpp
Normal 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;
|
||||
}
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
13
src/rct2.c
13
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;
|
||||
}
|
||||
21
src/rct2.h
21
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user