1 /*****************************************************************************
2  * Copyright (c) 2014-2020 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 
10 #include "../FileClassifier.h"
11 #include "../OpenRCT2.h"
12 #include "../ParkImporter.h"
13 #include "../common.h"
14 #include "../core/Console.hpp"
15 #include "../core/Path.hpp"
16 #include "../interface/Window.h"
17 #include "../rct2/S6Exporter.h"
18 #include "CommandLine.hpp"
19 
20 #include <memory>
21 
22 static void WriteConvertFromAndToMessage(uint32_t sourceFileType, uint32_t destinationFileType);
23 static const utf8* GetFileTypeFriendlyName(uint32_t fileType);
24 
HandleCommandConvert(CommandLineArgEnumerator * enumerator)25 exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator* enumerator)
26 {
27     exitcode_t result = CommandLine::HandleCommandDefault();
28     if (result != EXITCODE_CONTINUE)
29     {
30         return result;
31     }
32 
33     // Get the source path
34     const utf8* rawSourcePath;
35     if (!enumerator->TryPopString(&rawSourcePath))
36     {
37         Console::Error::WriteLine("Expected a source path.");
38         return EXITCODE_FAIL;
39     }
40 
41     utf8 sourcePath[MAX_PATH];
42     Path::GetAbsolute(sourcePath, sizeof(sourcePath), rawSourcePath);
43     uint32_t sourceFileType = get_file_extension_type(sourcePath);
44 
45     // Get the destination path
46     const utf8* rawDestinationPath;
47     if (!enumerator->TryPopString(&rawDestinationPath))
48     {
49         Console::Error::WriteLine("Expected a destination path.");
50         return EXITCODE_FAIL;
51     }
52 
53     utf8 destinationPath[MAX_PATH];
54     Path::GetAbsolute(destinationPath, sizeof(sourcePath), rawDestinationPath);
55     uint32_t destinationFileType = get_file_extension_type(destinationPath);
56 
57     // Validate target type
58     if (destinationFileType != FILE_EXTENSION_SC6 && destinationFileType != FILE_EXTENSION_SV6)
59     {
60         Console::Error::WriteLine("Only conversion to .SC6 or .SV4 is supported.");
61         return EXITCODE_FAIL;
62     }
63 
64     // Validate the source type
65     switch (sourceFileType)
66     {
67         case FILE_EXTENSION_SC4:
68         case FILE_EXTENSION_SV4:
69             break;
70         case FILE_EXTENSION_SC6:
71             if (destinationFileType == FILE_EXTENSION_SC6)
72             {
73                 Console::Error::WriteLine("File is already a RollerCoaster Tycoon 2 scenario.");
74                 return EXITCODE_FAIL;
75             }
76             break;
77         case FILE_EXTENSION_SV6:
78             if (destinationFileType == FILE_EXTENSION_SV6)
79             {
80                 Console::Error::WriteLine("File is already a RollerCoaster Tycoon 2 saved game.");
81                 return EXITCODE_FAIL;
82             }
83             break;
84         default:
85             Console::Error::WriteLine("Only conversion from .SC4, .SV4, .SC6 or .SV6 is supported.");
86             return EXITCODE_FAIL;
87     }
88 
89     // Perform conversion
90     WriteConvertFromAndToMessage(sourceFileType, destinationFileType);
91 
92     gOpenRCT2Headless = true;
93 
94     try
95     {
96         auto importer = ParkImporter::Create(sourcePath);
97         importer->Load(sourcePath);
98         importer->Import();
99     }
100     catch (const std::exception& ex)
101     {
102         Console::Error::WriteLine(ex.what());
103         return EXITCODE_FAIL;
104     }
105 
106     if (sourceFileType == FILE_EXTENSION_SC4 || sourceFileType == FILE_EXTENSION_SC6)
107     {
108         // We are converting a scenario, so reset the park
109         scenario_begin();
110     }
111 
112     try
113     {
114         auto exporter = std::make_unique<S6Exporter>();
115 
116         // HACK remove the main window so it saves the park with the
117         //      correct initial view
118         window_close_by_class(WC_MAIN_WINDOW);
119 
120         exporter->Export();
121         if (destinationFileType == FILE_EXTENSION_SC6)
122         {
123             exporter->SaveScenario(destinationPath);
124         }
125         else
126         {
127             exporter->SaveGame(destinationPath);
128         }
129     }
130     catch (const std::exception& ex)
131     {
132         Console::Error::WriteLine(ex.what());
133         return EXITCODE_FAIL;
134     }
135 
136     Console::WriteLine("Conversion successful!");
137     return EXITCODE_OK;
138 }
139 
WriteConvertFromAndToMessage(uint32_t sourceFileType,uint32_t destinationFileType)140 static void WriteConvertFromAndToMessage(uint32_t sourceFileType, uint32_t destinationFileType)
141 {
142     const utf8* sourceFileTypeName = GetFileTypeFriendlyName(sourceFileType);
143     const utf8* destinationFileTypeName = GetFileTypeFriendlyName(destinationFileType);
144     Console::WriteFormat("Converting from a %s to a %s.", sourceFileTypeName, destinationFileTypeName);
145     Console::WriteLine();
146 }
147 
GetFileTypeFriendlyName(uint32_t fileType)148 static const utf8* GetFileTypeFriendlyName(uint32_t fileType)
149 {
150     switch (fileType)
151     {
152         case FILE_EXTENSION_SC4:
153             return "RollerCoaster Tycoon 1 scenario";
154         case FILE_EXTENSION_SV4:
155             return "RollerCoaster Tycoon 1 saved game";
156         case FILE_EXTENSION_SC6:
157             return "RollerCoaster Tycoon 2 scenario";
158         case FILE_EXTENSION_SV6:
159             return "RollerCoaster Tycoon 2 saved game";
160     }
161 
162     assert(false);
163     return nullptr;
164 }
165