Merge pull request #3320 from OpenRCT2/rct1-import

Import RCT1 saved games / scenarios
This commit is contained in:
Ted John 2016-04-22 22:14:14 +01:00
commit 6a1500a1af
32 changed files with 3741 additions and 1927 deletions

View File

@ -7,6 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
C650B2191CCABBDD00B4D91C /* S4Importer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B2151CCABBDD00B4D91C /* S4Importer.cpp */; };
C650B21A1CCABBDD00B4D91C /* tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B2171CCABBDD00B4D91C /* tables.cpp */; };
C650B21C1CCABC4400B4D91C /* ConvertCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B21B1CCABC4400B4D91C /* ConvertCommand.cpp */; };
D41B73EF1C2101890080A7B9 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B73EE1C2101890080A7B9 /* libcurl.tbd */; };
D41B73F11C21018C0080A7B9 /* libssl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B73F01C21018C0080A7B9 /* libssl.tbd */; };
D41B741D1C210A7A0080A7B9 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B741C1C210A7A0080A7B9 /* libiconv.tbd */; };
@ -226,6 +229,11 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
C650B2151CCABBDD00B4D91C /* S4Importer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = S4Importer.cpp; sourceTree = "<group>"; };
C650B2161CCABBDD00B4D91C /* S4Importer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S4Importer.h; sourceTree = "<group>"; };
C650B2171CCABBDD00B4D91C /* tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tables.cpp; sourceTree = "<group>"; };
C650B2181CCABBDD00B4D91C /* Tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tables.h; sourceTree = "<group>"; };
C650B21B1CCABC4400B4D91C /* ConvertCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConvertCommand.cpp; sourceTree = "<group>"; };
D41B73EE1C2101890080A7B9 /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; };
D41B73F01C21018C0080A7B9 /* libssl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libssl.tbd; path = usr/lib/libssl.tbd; sourceTree = SDKROOT; };
D41B741C1C210A7A0080A7B9 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
@ -608,6 +616,18 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C650B2141CCABBDD00B4D91C /* rct1 */ = {
isa = PBXGroup;
children = (
C650B2151CCABBDD00B4D91C /* S4Importer.cpp */,
C650B2161CCABBDD00B4D91C /* S4Importer.h */,
C650B2171CCABBDD00B4D91C /* tables.cpp */,
C650B2181CCABBDD00B4D91C /* Tables.h */,
);
name = rct1;
path = src/rct1;
sourceTree = SOURCE_ROOT;
};
D41B72431C21015A0080A7B9 /* Sources */ = {
isa = PBXGroup;
children = (
@ -621,6 +641,7 @@
D442714F1CC81B3200D84D28 /* network */,
D442715B1CC81B3200D84D28 /* peep */,
D44271601CC81B3200D84D28 /* platform */,
C650B2141CCABBDD00B4D91C /* rct1 */,
D442716E1CC81B3200D84D28 /* ride */,
D44271881CC81B3200D84D28 /* util */,
D442718E1CC81B3200D84D28 /* windows */,
@ -697,6 +718,7 @@
children = (
D44270D71CC81B3200D84D28 /* CommandLine.cpp */,
D44270D81CC81B3200D84D28 /* CommandLine.hpp */,
C650B21B1CCABC4400B4D91C /* ConvertCommand.cpp */,
D44270D91CC81B3200D84D28 /* RootCommands.cpp */,
D44270DA1CC81B3200D84D28 /* ScreenshotCommands.cpp */,
D44270DB1CC81B3200D84D28 /* SpriteCommands.cpp */,
@ -1359,6 +1381,7 @@
D442729C1CC81B3200D84D28 /* duck.c in Sources */,
D442724E1CC81B3200D84D28 /* scenario_sources.c in Sources */,
D442729A1CC81B3200D84D28 /* banner.c in Sources */,
C650B21C1CCABC4400B4D91C /* ConvertCommand.cpp in Sources */,
D44272211CC81B3200D84D28 /* viewport_interaction.c in Sources */,
D442721B1CC81B3200D84D28 /* graph.c in Sources */,
D44272101CC81B3200D84D28 /* sprite.c in Sources */,
@ -1419,6 +1442,7 @@
D44272891CC81B3200D84D28 /* themes.c in Sources */,
D44272791CC81B3200D84D28 /* publisher_credits.c in Sources */,
D442723B1CC81B3200D84D28 /* crash.cpp in Sources */,
C650B21A1CCABBDD00B4D91C /* tables.cpp in Sources */,
D44272291CC81B3200D84D28 /* LanguagePack.cpp in Sources */,
D44272901CC81B3200D84D28 /* title_options.c in Sources */,
D44272A01CC81B3200D84D28 /* map_animation.c in Sources */,
@ -1434,6 +1458,7 @@
D44272351CC81B3200D84D28 /* twitch.cpp in Sources */,
D44272691CC81B3200D84D28 /* loadsave.c in Sources */,
D44272061CC81B3200D84D28 /* textinputbuffer.c in Sources */,
C650B2191CCABBDD00B4D91C /* S4Importer.cpp in Sources */,
D44272801CC81B3200D84D28 /* server_list.c in Sources */,
D44272911CC81B3200D84D28 /* title_scenarioselect.c in Sources */,
D44272411CC81B3200D84D28 /* rct1.c in Sources */,

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" />
@ -95,6 +96,8 @@
<ClCompile Include="src\platform\shared.c" />
<ClCompile Include="src\platform\windows.c" />
<ClCompile Include="src\rct1.c" />
<ClCompile Include="src\rct1\S4Importer.cpp" />
<ClCompile Include="src\rct1\Tables.cpp" />
<ClCompile Include="src\rct2.c" />
<ClCompile Include="src\ride\cable_lift.c" />
<ClCompile Include="src\ride\ride.c" />
@ -268,6 +271,8 @@
<ClInclude Include="src\platform\crash.h" />
<ClInclude Include="src\platform\platform.h" />
<ClInclude Include="src\rct1.h" />
<ClInclude Include="src\rct1\Tables.h" />
<ClInclude Include="src\rct1\S4Importer.h" />
<ClInclude Include="src\rct2.h" />
<ClInclude Include="src\ride\cable_lift.h" />
<ClInclude Include="src\ride\ride.h" />

View File

@ -50,6 +50,9 @@
<Filter Include="Source\CommandLine">
<UniqueIdentifier>{4bf369d2-3df8-40c9-a878-f484b0a0afd3}</UniqueIdentifier>
</Filter>
<Filter Include="Source\RCT1">
<UniqueIdentifier>{f59cd7d6-b58d-4a6f-9118-34f94de84766}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="openrct2.exe">
@ -591,6 +594,15 @@
<ClCompile Include="src\windows\themes.c">
<Filter>Source\Windows</Filter>
</ClCompile>
<ClCompile Include="src\rct1\S4Importer.cpp">
<Filter>Source\RCT1</Filter>
</ClCompile>
<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">
@ -902,9 +914,15 @@
<ClInclude Include="src\core\List.hpp">
<Filter>Source\Core</Filter>
</ClInclude>
<ClInclude Include="src\rct1\S4Importer.h">
<Filter>Source\RCT1</Filter>
</ClInclude>
<ClInclude Include="resources\resource.h">
<Filter>Resource Files</Filter>
</ClInclude>
<ClInclude Include="src\rct1\Tables.h">
<Filter>Source\RCT1</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="resources\logo\icon.ico">

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

@ -13,7 +13,8 @@ namespace Debug
{
#if DEBUG
#if __WINDOWS__
if (IsDebuggerPresent()) {
if (IsDebuggerPresent())
{
DebugBreak();
}
#endif

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

@ -1,5 +1,6 @@
#pragma once
#include <functional>
#include <vector>
#include "../common.h"
@ -22,6 +23,8 @@ public:
List() : std::vector<T>() { }
List(std::initializer_list<T> initializerList) : std::vector<T>(initializerList) { }
List(size_t capacity) : std::vector<T>(capacity) { }
List(const T * items, size_t count) : std::vector<T>(items, items + count) { }
@ -46,6 +49,11 @@ public:
this->push_back(item);
}
void AddRange(std::initializer_list<T> initializerList)
{
this->insert(this->end(), initializerList.begin(), initializerList.end());
}
void Insert(T item, size_t index)
{
Guard::ArgumentInRange(index, (size_t)0, this->size());
@ -87,4 +95,40 @@ public:
Guard::ArgumentInRange(index, (size_t)0, this->size() - 1);
return std::vector<T>::operator[](index);
}
size_t IndexOf(std::function<bool(T)> predicate)
{
for (size_t i = 0; i < this->size(); i++)
{
T item = std::vector<T>::operator[](i);
if (predicate(item))
{
return i;
}
}
return SIZE_MAX;
}
size_t IndexOf(T item, std::function<bool(T, T)> comparer)
{
for (size_t i = 0; i < this->size(); i++)
{
T element = std::vector<T>::operator[](i);
if (comparer(item, element))
{
return i;
}
}
return SIZE_MAX;
}
bool Contains(std::function<bool(T)> predicate)
{
return IndexOf(predicate) != SIZE_MAX;
}
bool Contains(T item, std::function<bool(T, T)> comparer)
{
return IndexOf(item, comparer) != SIZE_MAX;
}
};

View File

@ -33,6 +33,29 @@ namespace Path
return buffer;
}
const utf8 * GetFileName(const utf8 * path)
{
const utf8 * lastPathSeperator = nullptr;
for (const utf8 * ch = path; *ch != '\0'; ch++)
{
if (*ch == platform_get_path_separator())
{
lastPathSeperator = ch;
}
#ifdef __WINDOWS__
// Windows also allows forward slashes in paths
else if (*ch == '/')
{
lastPathSeperator = ch;
}
#endif
}
return lastPathSeperator == nullptr ?
path :
lastPathSeperator + 1;
}
utf8 * GetFileNameWithoutExtension(utf8 * buffer, size_t bufferSize, const utf8 * path)
{
const utf8 * lastDot = nullptr;
@ -56,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

@ -9,7 +9,9 @@ namespace Path
{
utf8 * Append(utf8 * buffer, size_t bufferSize, const utf8 * src);
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

@ -51,6 +51,7 @@ static int editor_load_landscape_from_sv4(const char *path);
static int editor_load_landscape_from_sc4(const char *path);
static void editor_finalise_main_view();
static int editor_read_s6(const char *path);
static void editor_clear_map_for_editing();
/**
*
@ -260,37 +261,29 @@ bool editor_load_landscape(const utf8 *path)
*/
static int editor_load_landscape_from_sv4(const char *path)
{
rct1_s4 *s4;
rct1_load_saved_game(path);
editor_clear_map_for_editing();
s4 = malloc(sizeof(rct1_s4));
if (!rct1_read_sv4(path, s4)) {
free(s4);
return 0;
}
rct1_import_s4(s4);
free(s4);
rct1_fix_landscape();
editor_finalise_main_view();
g_editor_step = EDITOR_STEP_LANDSCAPE_EDITOR;
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR;
viewport_init_all();
window_editor_main_open();
editor_finalise_main_view();
return 1;
}
static int editor_load_landscape_from_sc4(const char *path)
{
rct1_s4 *s4;
rct1_load_scenario(path);
editor_clear_map_for_editing();
s4 = malloc(sizeof(rct1_s4));
if (!rct1_read_sc4(path, s4)) {
free(s4);
return 0;
}
rct1_import_s4(s4);
free(s4);
rct1_fix_landscape();
editor_finalise_main_view();
g_editor_step = EDITOR_STEP_LANDSCAPE_EDITOR;
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR;
viewport_init_all();
window_editor_main_open();
editor_finalise_main_view();
return 1;
}
@ -388,95 +381,12 @@ static int editor_read_s6(const char *path)
reset_loaded_objects();
map_update_tile_pointers();
map_remove_all_rides();
//
for (i = 0; i < MAX_BANNERS; i++)
if (gBanners[i].type == 255)
gBanners[i].flags &= ~BANNER_FLAG_2;
//
rct_ride *ride;
FOR_ALL_RIDES(i, ride)
user_string_free(ride->name);
ride_init_all();
//
for (i = 0; i < MAX_SPRITES; i++) {
rct_sprite *sprite = &g_sprite_list[i];
user_string_free(sprite->unknown.name_string_idx);
}
reset_sprite_list();
staff_reset_modes();
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_GUEST_CHANGE_MODIFIER, uint16) = 0;
if (s6Header->type != S6_TYPE_SCENARIO) {
research_populate_list_random();
research_remove_non_separate_vehicle_types();
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_NO_MONEY_SCENARIO;
else
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_NO_MONEY_SCENARIO;
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_NO_MONEY;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) == 0)
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_PARK_FREE_ENTRY;
else
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_PARK_FREE_ENTRY;
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18;
RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) = clamp(
MONEY(10,00),
RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16),
MONEY(100,00)
);
RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, uint32) = min(RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, uint32), 100000);
finance_reset_cash_to_initial();
finance_update_loan_hash();
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = clamp(
MONEY(0,00),
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32),
MONEY(5000000,00)
);
RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = clamp(
MONEY(0,00),
RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32),
MONEY(5000000,00)
);
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, uint8) = clamp(
5,
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, uint8),
80
);
}
climate_reset(RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8));
rct_stex_entry* stex = g_stexEntries[0];
if ((int)stex != 0xFFFFFFFF) {
object_unload_chunk((rct_object_entry*)&object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]);
reset_loaded_objects();
format_string(s6Info->details, STR_NO_DETAILS_YET, NULL);
s6Info->name[0] = 0;
}
game_convert_strings_to_utf8();
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR;
viewport_init_all();
news_item_init_queue();
window_editor_main_open();
editor_finalise_main_view();
game_convert_strings_to_utf8();
return 1;
}
@ -486,6 +396,103 @@ static int editor_read_s6(const char *path)
return 0;
}
static void editor_clear_map_for_editing()
{
rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4;
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
map_remove_all_rides();
//
for (int i = 0; i < MAX_BANNERS; i++) {
if (gBanners[i].type == 255) {
gBanners[i].flags &= ~BANNER_FLAG_2;
}
}
//
{
int i;
rct_ride *ride;
FOR_ALL_RIDES(i, ride) {
user_string_free(ride->name);
}
}
ride_init_all();
//
for (int i = 0; i < MAX_SPRITES; i++) {
rct_sprite *sprite = &g_sprite_list[i];
user_string_free(sprite->unknown.name_string_idx);
}
reset_sprite_list();
staff_reset_modes();
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_GUEST_CHANGE_MODIFIER, uint16) = 0;
if (s6Header->type != S6_TYPE_SCENARIO) {
research_populate_list_random();
research_remove_non_separate_vehicle_types();
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_NO_MONEY_SCENARIO;
else
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_NO_MONEY_SCENARIO;
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_NO_MONEY;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) == 0)
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_PARK_FREE_ENTRY;
else
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_PARK_FREE_ENTRY;
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18;
RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) = clamp(
MONEY(10,00),
RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16),
MONEY(100,00)
);
RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, uint32) = min(RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, uint32), 100000);
finance_reset_cash_to_initial();
finance_update_loan_hash();
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = clamp(
MONEY(0,00),
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32),
MONEY(5000000,00)
);
RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = clamp(
MONEY(0,00),
RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32),
MONEY(5000000,00)
);
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, uint8) = clamp(
5,
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, uint8),
80
);
}
climate_reset(RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8));
rct_stex_entry* stex = g_stexEntries[0];
if ((int)stex != 0xFFFFFFFF) {
object_unload_chunk((rct_object_entry*)&object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]);
reset_loaded_objects();
format_string(s6Info->details, STR_NO_DETAILS_YET, NULL);
s6Info->name[0] = 0;
}
news_item_init_queue();
}
/**
*
* rct2: 0x0067009A

View File

@ -1601,9 +1601,29 @@ void viewport_track_paint_setup(uint8 direction, int height, rct_map_element *ma
RCT2_GLOBAL(0x00F441A4, uint32) = ghost_id;
}
TRACK_PAINT_FUNCTION **trackTypeList = (TRACK_PAINT_FUNCTION**)RideTypeTrackPaintFunctionsOld[ride->type];
int rideType = ride->type;
if (rideType == RIDE_TYPE_JUNIOR_ROLLER_COASTER) {
switch (trackType) {
case TRACK_ELEM_60_DEG_UP:
case TRACK_ELEM_25_DEG_UP_TO_60_DEG_UP:
case TRACK_ELEM_60_DEG_UP_TO_25_DEG_UP:
case TRACK_ELEM_60_DEG_DOWN:
case TRACK_ELEM_25_DEG_DOWN_TO_60_DEG_DOWN:
case TRACK_ELEM_60_DEG_DOWN_TO_25_DEG_DOWN:
rideType = RIDE_TYPE_WATER_COASTER;
break;
case TRACK_ELEM_FLAT_TO_60_DEG_UP:
case TRACK_ELEM_60_DEG_UP_TO_FLAT:
case TRACK_ELEM_FLAT_TO_60_DEG_DOWN:
case TRACK_ELEM_60_DEG_DOWN_TO_FLAT:
return;
}
}
TRACK_PAINT_FUNCTION **trackTypeList = (TRACK_PAINT_FUNCTION**)RideTypeTrackPaintFunctionsOld[rideType];
if (trackTypeList == NULL) {
TRACK_PAINT_FUNCTION_GETTER paintFunctionGetter = RideTypeTrackPaintFunctions[ride->type];
TRACK_PAINT_FUNCTION_GETTER paintFunctionGetter = RideTypeTrackPaintFunctions[rideType];
TRACK_PAINT_FUNCTION paintFunction = paintFunctionGetter(trackType, direction);
if (paintFunction != NULL) {
paintFunction(rideIndex, trackSequence, direction, height, mapElement);
@ -1615,7 +1635,7 @@ void viewport_track_paint_setup(uint8 direction, int height, rct_map_element *ma
// Have to call from this point as it pushes esi and expects callee to pop it
RCT2_CALLPROC_X(
0x006C4934,
ride->type,
rideType,
(int)trackDirectionList,
direction,
height,

View File

@ -576,3 +576,21 @@ void game_command_set_research_funding(int* eax, int* ebx, int* ecx, int* edx, i
*ebx = 0;
}
void research_insert_ride_entry(uint8 entryIndex, bool researched)
{
rct_ride_entry *rideEntry = get_ride_entry(entryIndex);
uint8 category = rideEntry->category[0];
for (int i = 0; i < 3; i++) {
uint8 rideType = rideEntry->ride_type[i];
if (rideType != 255) {
research_insert(researched, 0x10000 | (rideType << 8) | entryIndex, category);
}
}
}
void research_insert_scenery_group_entry(uint8 entryIndex, bool researched)
{
rct_scenery_set_entry *scenerySetEntry = g_scenerySetEntries[entryIndex];
research_insert(researched, entryIndex, RESEARCH_CATEGORY_SCENERYSET);
}

View File

@ -85,4 +85,7 @@ void research_finish_item(sint32 entryIndex);
void research_insert(int researched, int entryIndex, int category);
void research_remove(sint32 entryIndex);
void research_insert_ride_entry(uint8 entryIndex, bool researched);
void research_insert_scenery_group_entry(uint8 entryIndex, bool researched);
#endif

View File

@ -127,6 +127,7 @@ void reset_loaded_objects();
int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index);
void object_create_identifier_name(char* string_buffer, const rct_object_entry* object);
rct_object_entry *object_list_find_by_name(const char *name);
rct_object_entry *object_list_find(rct_object_entry *entry);
char *object_get_name(rct_object_entry *entry);

View File

@ -606,10 +606,7 @@ uint32 _installedObjectHashTableCollisions;
uint32 object_get_hash_code(rct_object_entry *object)
{
uint32 hash = 5381;
uint8 *byte = (uint8*)object;
int i;
for (i = 0; i < 8; i++)
for (int i = 0; i < 8; i++)
hash = ((hash << 5) + hash) + object->name[i];
return hash;
@ -672,6 +669,24 @@ int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8
return 1;
}
rct_object_entry *object_list_find_by_name(const char * name)
{
rct_object_entry entry;
memcpy(entry.name, name, 8);
uint32 hash = object_get_hash_code(&entry);
uint32 index = hash % _installedObjectHashTableSize;
while (_installedObjectHashTable[index] != NULL) {
if (memcmp(_installedObjectHashTable[index]->name, entry.name, 8) == 0)
return _installedObjectHashTable[index];
index++;
if (index >= _installedObjectHashTableSize) index = 0;
}
return NULL;
}
rct_object_entry *object_list_find(rct_object_entry *entry)
{

1843
src/rct1.c

File diff suppressed because it is too large Load Diff

View File

@ -47,10 +47,13 @@ typedef struct {
uint16 lifecycle_flags;
uint8 operating_mode;
uint8 colour_scheme;
uint16 vehicle_colours[12];
uint8 track_primary_colour;
uint8 track_secondary_colour;
uint8 track_support_colour;
struct {
colour_t body;
colour_t trim;
} vehicle_colours[12];
colour_t track_primary_colour;
colour_t track_secondary_colour;
colour_t track_support_colour;
uint8 status;
uint16 name;
uint16 name_argument_ride;
@ -154,14 +157,22 @@ typedef struct {
money32 income_per_hour;
money32 profit;
uint8 queue_time[4];
uint8 track_colour_main[4];
uint8 track_colour_additional[4];
uint8 track_colour_supports[4];
colour_t track_colour_main[4];
colour_t track_colour_additional[4];
colour_t track_colour_supports[4];
uint8 music;
uint8 entrance_style;
uint8 unk_17A[230];
} rct1_ride;
typedef struct {
uint8 item;
uint8 related_ride;
uint8 category;
uint8 flags;
uint8 expenditure_area;
} rct1_research_item;
/**
* RCT1,AA,LL scenario / saved game structure.
* size: 0x1F850C
@ -208,9 +219,9 @@ typedef struct {
money32 expenditure[14 * 16];
uint32 guests_in_park_2;
uint8 unk_199024;
uint8 handman_colour;
uint8 mechanic_colour;
uint8 security_guard_colour;
colour_t handman_colour;
colour_t mechanic_colour;
colour_t security_guard_colour;
uint8 available_scenery[128];
uint16 available_banners;
uint8 unk_1990AA[94];
@ -223,7 +234,7 @@ typedef struct {
uint8 last_research_ride;
uint8 last_research_category;
uint8 last_research_flag;
rct_research_item research_items[200];
rct1_research_item research_items[200];
uint8 next_research_item;
uint8 next_research_ride;
uint8 next_research_category;
@ -288,7 +299,7 @@ typedef struct {
uint8 unk_199C96[3];
uint8 water_colour;
uint16 unk_199C9A;
rct_research_item research_items_LL[180];
rct1_research_item research_items_LL[180];
uint8 unk_19A020[5468];
rct_banner banners[100];
char string_table[1024][32];
@ -348,7 +359,7 @@ enum {
RCT1_RIDE_TYPE_WOODEN_CRAZY_RODENT_ROLLER_COASTER,
RCT1_RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER,
RCT1_RIDE_TYPE_CAR_RIDE,
RCT1_RIDE_TYPE_WHOA_BELLY,
RCT1_RIDE_TYPE_LAUNCHED_FREEFALL,
RCT1_RIDE_TYPE_BOBSLED_ROLLER_COASTER,
RCT1_RIDE_TYPE_OBSERVATION_TOWER,
RCT1_RIDE_TYPE_STEEL_ROLLER_COASTER,
@ -423,6 +434,98 @@ enum {
RCT1_RIDE_TYPE_LEMONADE_STALL
};
enum {
RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN = 0,
RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN_BACKWARDS,
RCT1_VEHICLE_TYPE_WOODEN_ROLLER_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_INVERTED_COASTER_TRAIN, // Not in RCT2
RCT1_VEHICLE_TYPE_SUSPENDED_SWINGING_CARS,
RCT1_VEHICLE_TYPE_LADYBIRD_CARS,
RCT1_VEHICLE_TYPE_STANDUP_ROLLER_COASTER_CARS,
RCT1_VEHICLE_TYPE_SPINNING_CARS,
RCT1_VEHICLE_TYPE_SINGLE_PERSON_SWINGING_CHAIRS,
RCT1_VEHICLE_TYPE_SWANS_PEDAL_BOATS,
RCT1_VEHICLE_TYPE_LARGE_MONORAIL_TRAIN,
RCT1_VEHICLE_TYPE_CANOES,
RCT1_VEHICLE_TYPE_ROWING_BOATS,
RCT1_VEHICLE_TYPE_STEAM_TRAIN,
RCT1_VEHICLE_TYPE_WOODEN_MOUSE_CARS,
RCT1_VEHICLE_TYPE_BUMPER_BOATS,
RCT1_VEHICLE_TYPE_WOODEN_ROLLER_COASTER_TRAIN_BACKWARDS,
RCT1_VEHICLE_TYPE_ROCKET_CARS,
RCT1_VEHICLE_TYPE_HORSES, // Steeplechase
RCT1_VEHICLE_TYPE_SPORTSCARS,
RCT1_VEHICLE_TYPE_LYING_DOWN_SWINGING_CARS, // Inverted single-rail
RCT1_VEHICLE_TYPE_WOODEN_MINE_CARS,
RCT1_VEHICLE_TYPE_SUSPENDED_SWINGING_AIRPLANE_CARS,
RCT1_VEHICLE_TYPE_SMALL_MONORAIL_CARS,
RCT1_VEHICLE_TYPE_WATER_TRICYCLES,
RCT1_VEHICLE_TYPE_LAUNCHED_FREEFALL_CAR,
RCT1_VEHICLE_TYPE_BOBSLEIGH_CARS,
RCT1_VEHICLE_TYPE_DINGHIES,
RCT1_VEHICLE_TYPE_ROTATING_CABIN,
RCT1_VEHICLE_TYPE_MINE_TRAIN,
RCT1_VEHICLE_TYPE_CHAIRLIFT_CARS,
RCT1_VEHICLE_TYPE_CORKSCREW_ROLLER_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_MOTORBIKES,
RCT1_VEHICLE_TYPE_RACING_CARS,
RCT1_VEHICLE_TYPE_TRUCKS,
RCT1_VEHICLE_TYPE_GO_KARTS,
RCT1_VEHICLE_TYPE_RAPIDS_BOATS,
RCT1_VEHICLE_TYPE_LOG_FLUME_BOATS,
RCT1_VEHICLE_TYPE_DODGEMS,
RCT1_VEHICLE_TYPE_SWINGING_SHIP,
RCT1_VEHICLE_TYPE_SWINGING_INVERTER_SHIP,
RCT1_VEHICLE_TYPE_MERRY_GO_ROUND,
RCT1_VEHICLE_TYPE_FERRIS_WHEEL,
RCT1_VEHICLE_TYPE_SIMULATOR_POD,
RCT1_VEHICLE_TYPE_CINEMA_BUILDING,
RCT1_VEHICLE_TYPE_TOPSPIN_CAR,
RCT1_VEHICLE_TYPE_SPACE_RINGS,
RCT1_VEHICLE_TYPE_REVERSE_FREEFALL_ROLLER_COASTER_CAR,
RCT1_VEHICLE_TYPE_VERTICAL_ROLLER_COASTER_CARS,
RCT1_VEHICLE_TYPE_CAT_CARS,
RCT1_VEHICLE_TYPE_TWIST_ARMS_AND_CARS,
RCT1_VEHICLE_TYPE_HAUNTED_HOUSE_BUILDING,
RCT1_VEHICLE_TYPE_LOG_CARS,
RCT1_VEHICLE_TYPE_CIRCUS_TENT,
RCT1_VEHICLE_TYPE_GHOST_TRAIN_CARS,
RCT1_VEHICLE_TYPE_STEEL_TWISTER_ROLLER_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_WOODEN_TWISTER_ROLLER_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_WOODEN_SIDE_FRICTION_CARS,
RCT1_VEHICLE_TYPE_VINTAGE_CARS,
RCT1_VEHICLE_TYPE_STEAM_TRAIN_COVERED_CARS,
RCT1_VEHICLE_TYPE_STAND_UP_STEEL_TWISTER_ROLLER_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_FLOORLESS_STEEL_TWISTER_ROLLER_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_STEEL_MOUSE_CARS,
RCT1_VEHICLE_TYPE_CHAIRLIFT_CARS_ALTERNATIVE,
RCT1_VEHICLE_TYPE_SUSPENDED_MONORAIL_TRAIN,
RCT1_VEHICLE_TYPE_HELICOPTER_CARS,
RCT1_VEHICLE_TYPE_VIRGINIA_REEL_TUBS,
RCT1_VEHICLE_TYPE_REVERSER_CARS,
RCT1_VEHICLE_TYPE_GOLFERS,
RCT1_VEHICLE_TYPE_RIVER_RIDE_BOATS,
RCT1_VEHICLE_TYPE_FLYING_ROLLER_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_NON_LOOPING_STEEL_TWISTER_ROLLER_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_HEARTLINE_TWISTER_CARS,
RCT1_VEHICLE_TYPE_HEARTLINE_TWISTER_CARS_REVERSED,
RCT1_VEHICLE_TYPE_RESERVED,
RCT1_VEHICLE_TYPE_ROTODROP_CAR,
RCT1_VEHICLE_TYPE_FLYING_SAUCERS,
RCT1_VEHICLE_TYPE_CROOKED_HOUSE_BUILDING,
RCT1_VEHICLE_TYPE_BICYCLES,
RCT1_VEHICLE_TYPE_HYPERCOASTER_TRAIN,
RCT1_VEHICLE_TYPE_4_ACROSS_INVERTED_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_WATER_COASTER_BOATS,
RCT1_VEHICLE_TYPE_FACEOFF_CARS,
RCT1_VEHICLE_TYPE_JET_SKIS,
RCT1_VEHICLE_TYPE_RAFT_BOATS,
RCT1_VEHICLE_TYPE_AMERICAN_STYLE_STEAM_TRAIN,
RCT1_VEHICLE_TYPE_AIR_POWERED_COASTER_TRAIN,
RCT1_VEHICLE_TYPE_SUSPENDED_WILD_MOUSE_CARS, // Inverted Hairpin in RCT2
RCT1_VEHICLE_TYPE_ENTERPRISE_WHEEL
};
enum{
RCT1_TRACK_ELEM_BOOSTER = 100
};
@ -432,16 +535,130 @@ enum{
};
enum {
RCT1_SCENERY_THEME_GENERAL,
RCT1_SCENERY_THEME_MINE,
RCT1_SCENERY_THEME_CLASSICAL_ROMAN,
RCT1_SCENERY_THEME_EGYPTIAN,
RCT1_SCENERY_THEME_MARTIAN,
RCT1_SCENERY_THEME_JUMPING_FOUNTAINS, // Single researchable scenery item
RCT1_SCENERY_THEME_WONDERLAND,
RCT1_SCENERY_THEME_JURASSIC,
RCT1_SCENERY_THEME_SPOOKY,
RCT1_SCENERY_THEME_JUNGLE,
RCT1_SCENERY_THEME_ABSTRACT,
RCT1_SCENERY_THEME_GARDEN_CLOCK, // Single researchable scenery item
RCT1_SCENERY_THEME_SNOW_ICE,
RCT1_SCENERY_THEME_MEDIEVAL,
RCT1_SCENERY_THEME_SPACE,
RCT1_SCENERY_THEME_CREEPY,
RCT1_SCENERY_THEME_URBAN,
RCT1_SCENERY_THEME_PAGODA,
};
enum {
RCT1_FOOTPATH_TYPE_QUEUE_BLUE,
RCT1_FOOTPATH_TYPE_QUEUE_RED,
RCT1_FOOTPATH_TYPE_QUEUE_YELLOW,
RCT1_FOOTPATH_TYPE_QUEUE_GREEN,
RCT1_FOOTPATH_TYPE_TARMAC_GRAY,
RCT1_FOOTPATH_TYPE_TARMAC_RED,
RCT1_FOOTPATH_TYPE_TARMAC_BROWN,
RCT1_FOOTPATH_TYPE_TARMAC_GREEN,
RCT1_FOOTPATH_TYPE_DIRT_RED,
RCT1_FOOTPATH_TYPE_DIRT_BLACK,
RCT1_FOOTPATH_TYPE_CRAZY_PAVING = 12,
RCT1_FOOTPATH_TYPE_ROADS = 16,
RCT1_FOOTPATH_TYPE_TILE_PINK = 20,
RCT1_FOOTPATH_TYPE_TILE_GRAY,
RCT1_FOOTPATH_TYPE_TILE_RED,
RCT1_FOOTPATH_TYPE_TILE_GREEN,
};
enum {
FOOTPATH_SUPPORTS_WOODEN_TRUSS,
FOOTPATH_SUPPORTS_WOOD,
FOOTPATH_SUPPORTS_STEEL,
FOOTPATH_SUPPORTS_BAMBOO,
};
enum {
RCT1_PATH_ADDITION_NONE,
RCT1_PATH_ADDITION_LAMP_1,
RCT1_PATH_ADDITION_LAMP_2,
RCT1_PATH_ADDITION_BIN,
RCT1_PATH_ADDITION_BENCH,
RCT1_PATH_ADDITION_JUMPING_FOUNTAIN,
RCT1_PATH_ADDITION_LAMP_3,
RCT1_PATH_ADDITION_LAMP_4,
RCT1_PATH_ADDITION_BROKEN_LAMP_1,
RCT1_PATH_ADDITION_BROKEN_LAMP_2,
RCT1_PATH_ADDITION_BROKEN_BIN,
RCT1_PATH_ADDITION_BROKEN_BENCH,
RCT1_PATH_ADDITION_BROKEN_LAMP_3,
RCT1_PATH_ADDITION_BROKEN_LAMP_4,
RCT1_PATH_ADDITION_JUMPING_SNOW,
};
enum {
RCT1_RESEARCH_END_AVAILABLE = 0xFF,
RCT1_RESEARCH_END_RESEARCHABLE = 0xFE,
RCT1_RESEARCH_END = 0xFD,
};
enum {
RCT1_RESEARCH_CATEGORY_THEME,
RCT1_RESEARCH_CATEGORY_RIDE,
RCT1_RESEARCH_CATEGORY_VEHICLE,
RCT1_RESEARCH_CATEGORY_SPECIAL,
};
enum {
RCT1_RESEARCH_EXPENDITURE_ROLLERCOASTERS = 1 << 0,
RCT1_RESEARCH_EXPENDITURE_THRILL_RIDES = 1 << 1,
RCT1_RESEARCH_EXPENDITURE_GENTLE_TRANSPORT_RIDES = 1 << 2,
RCT1_RESEARCH_EXPENDITURE_SHOPS = 1 << 3,
RCT1_RESEARCH_EXPENDITURE_SCENERY_THEMEING = 1 << 4,
RCT1_RESEARCH_EXPENDITURE_RIDE_IMPROVEMENTS = 1 << 5,
};
// Unconfirmed special track elements for research
enum {
RCT1_RESEARCH_SPECIAL_BANKED_CURVES = 0x06,
RCT1_RESEARCH_SPECIAL_VERTICAL_LOOP = 0x07,
RCT1_RESEARCH_SPECIAL_STEEP_TWIST = 0x0C,
RCT1_RESEARCH_SPECIAL_INLINE_TWIST = 0x11,
RCT1_RESEARCH_SPECIAL_HALF_LOOP = 0x12,
RCT1_RESEARCH_SPECIAL_CORKSCREW = 0x13,
RCT1_RESEARCH_SPECIAL_BANKED_HELIX_A = 0x15,
RCT1_RESEARCH_SPECIAL_BANKED_HELIX_B = 0x16,
RCT1_RESEARCH_SPECIAL_HELIX = 0x17,
RCT1_RESEARCH_SPECIAL_ON_RIDE_PHOTO = 0x1A,
RCT1_RESEARCH_SPECIAL_WATER_SPLASH = 0x1B,
RCT1_RESEARCH_SPECIAL_VERTICAL_DROP = 0x1C,
RCT1_RESEARCH_SPECIAL_BARREL_ROLL = 0x1D,
RCT1_RESEARCH_SPECIAL_LAUNCHED_LIFT_HILL = 0x1E,
RCT1_RESEARCH_SPECIAL_LARGE_LOOP_AND_HALF = 0x1F,
RCT1_RESEARCH_SPECIAL_REVERSER_TURNTABLE = 0x21,
RCT1_RESEARCH_SPECIAL_HEARTLINE_ROLL = 0x22,
RCT1_RESEARCH_SPECIAL_REVERSING_SECTIONS = 0x23,
};
typedef struct{
uint8 type; // 0x00
uint8 vehicle_type; // 0x01
uint32 special_track_flags; // 0x02
uint8 operating_mode; // 0x06
uint8 vehicle_colour_version; // 0x07 Vehicle colour type in first two bits, Version in bits 3,4
uint8 body_trim_colour[24]; // 0x08
uint8 track_spine_colour_rct1; // 0x20
uint8 track_rail_colour_rct1; // 0x21
uint8 track_support_colour_rct1; // 0x22
colour_t body_trim_colour[24]; // 0x08
colour_t track_spine_colour_rct1; // 0x20
colour_t track_rail_colour_rct1; // 0x21
colour_t track_support_colour_rct1; // 0x22
uint8 departure_control_flags; // 0x23
uint8 number_of_trains; // 0x24
uint8 cars_per_train; // 0x25
@ -466,11 +683,11 @@ typedef struct{
uint8 pad_36[2];
union{
uint16 start_track_data_original; // 0x38
uint8 track_spine_colour[4]; // 0x38
colour_t track_spine_colour[4]; // 0x38
};
uint8 track_rail_colour[4]; // 0x3C
colour_t track_rail_colour[4]; // 0x3C
union{
uint8 track_support_colour[4]; // 0x40
colour_t track_support_colour[4]; // 0x40
uint8 wall_type[4]; // 0x40
};
uint8 pad_41[0x83];
@ -500,15 +717,18 @@ enum {
RCT1_SCENARIO_FLAG_19 = 1 << 19,
};
extern const uint8 RCT1ColourConversionTable[32];
extern const uint8 gRideCategories[0x60];
bool rct1_read_sc4(const char *path, rct1_s4 *s4);
bool rct1_read_sv4(const char *path, rct1_s4 *s4);
void rct1_import_s4(rct1_s4 *s4);
void rct1_fix_landscape();
bool vehicleIsHigherInHierarchy(int track_type, char *currentVehicleName, char *comparedVehicleName);
bool rideTypeShouldLoseSeparateFlag(rct_ride_entry *ride);
int vehicle_preference_compare(uint8 rideType, const char * a, const char * b);
bool rideTypeShouldLoseSeparateFlag(rct_ride_entry *rideEntry);
bool rct1_load_saved_game(const char *path);
bool rct1_load_scenario(const char *path);
colour_t rct1_get_colour(colour_t colour);
#endif

1577
src/rct1/S4Importer.cpp Normal file

File diff suppressed because it is too large Load Diff

107
src/rct1/S4Importer.h Normal file
View File

@ -0,0 +1,107 @@
#pragma once
#include "../common.h"
#include "../core/List.hpp"
extern "C"
{
#include "../rct1.h"
}
/**
* Class to import RollerCoaster Tycoon 1 scenarios (*.SC4) and saved games (*.SV4).
*/
class S4Importer
{
public:
void LoadSavedGame(const utf8 * path);
void LoadScenario(const utf8 * path);
void Import();
private:
const utf8 * _s4Path;
rct1_s4 _s4;
uint8 _gameVersion;
// Lists of dynamic object entries
List<const char *> _rideEntries;
List<const char *> _smallSceneryEntries;
List<const char *> _largeSceneryEntries;
List<const char *> _wallEntries;
List<const char *> _pathEntries;
List<const char *> _pathAdditionEntries;
List<const char *> _sceneryGroupEntries;
// Lookup tables for converting from RCT1 hard coded types to the new dynamic object entries
uint8 _rideTypeToRideEntryMap[96];
uint8 _vehicleTypeToRideEntryMap[96];
uint8 _smallSceneryTypeToEntryMap[256];
uint8 _largeSceneryTypeToEntryMap[256];
uint8 _wallTypeToEntryMap[256];
uint8 _pathTypeToEntryMap[16];
uint8 _pathAdditionTypeToEntryMap[16];
uint8 _sceneryThemeTypeToEntryMap[24];
// Research
uint8 _researchRideEntryUsed[128];
uint8 _researchRideTypeUsed[128];
void Initialise();
/**
* Scans the map and research list for all the object types used and builds lists and
* lookup tables for converting from hard coded RCT1 object types to dynamic object entries.
*/
void CreateAvailableObjectMappings();
void AddDefaultEntries();
void AddAvailableEntriesFromResearchList();
void AddAvailableEntriesFromMap();
void AddAvailableEntriesFromRides();
void AddAvailableEntriesFromSceneryGroups();
void AddEntryForRideType(uint8 rideType);
void AddEntryForVehicleType(uint8 rideType, uint8 vehicleType);
void AddEntryForSmallScenery(uint8 smallSceneryType);
void AddEntryForLargeScenery(uint8 largeSceneryType);
void AddEntryForWall(uint8 wallType);
void AddEntryForPath(uint8 pathType);
void AddEntryForPathAddition(uint8 pathAdditionType);
void AddEntriesForSceneryTheme(uint8 sceneryThemeType);
void LoadObjects();
void LoadObjects(uint8 objectType, List<const char *> entries);
void ImportMapElements();
void ImportRides();
void ImportRide(rct_ride * dst, rct1_ride * src);
void ImportRideMeasurements();
void ImportRideMeasurement(rct_ride_measurement * dst, rct_ride_measurement * src);
void ImportPeepSpawns();
void ImportMapAnimations();
void ImportFinance();
void ImportResearch();
void InsertResearchVehicle(const rct1_research_item * researchItem, bool researched);
void ImportParkName();
void ImportParkFlags();
void ImportClimate();
void ImportScenarioNameDetails();
void ImportScenarioObjective();
void ImportSavedView();
void ClearExtraTileEntries();
void FixColours();
void FixZ();
void FixPaths();
void FixWalls();
void ConvertWall(int * type, int * colourA, int * colourB, int * colourC);
void FixBanners();
void ImportBanner(rct_banner * dst, rct_banner * src);
void FixTerrain();
void FixEntrancePositions();
void FixMapElementEntryTypes();
List<const char *> * GetEntryList(uint8 objectType);
const rct1_research_item * GetResearchList(size_t * count);
int GetSCNumber();
const char * GetUserString(rct_string_id stringId);
};

29
src/rct1/Tables.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "../common.h"
#include "../core/List.hpp"
namespace RCT1
{
colour_t GetColour(colour_t colour);
uint8 GetTerrain(uint8 terrain);
uint8 GetTerrainEdge(uint8 terrainEdge);
uint8 GetRideType(uint8 rideType);
bool RideTypeUsesVehicles(uint8 rideType);
bool PathIsQueue(uint8 pathType);
uint8 NormalisePathAddition(uint8 pathAdditionType);
const char * GetRideTypeObject(uint8 rideType);
const char * GetVehicleObject(uint8 vehicleType);
const char * GetSmallSceneryObject(uint8 smallSceneryType);
const char * GetLargeSceneryObject(uint8 largeSceneryType);
const char * GetWallObject(uint8 wallType);
const char * GetPathObject(uint8 pathType);
const char * GetPathAddtionObject(uint8 pathAdditionType);
const char * GetSceneryGroupObject(uint8 sceneryGroupType);
const List<const char *> GetSceneryObjects(uint8 sceneryType);
const List<const char *> GetPreferedRideEntryOrder(uint8 rideType);
}

1095
src/rct1/tables.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -365,10 +365,16 @@ bool rct2_open_file(const char *path)
scenario_load_and_play_from_path(scenarioBasic.path);
return true;
} else if (_stricmp(extension, "td6") == 0 || _stricmp(extension, "td4") == 0) {
return true;
} else if (!_stricmp(extension, "td6") || !_stricmp(extension, "td4")) {
// TODO track design install
return true;
} else if (_stricmp(extension, "sv4") == 0) {
if (rct1_load_saved_game(path)) {
game_load_init();
}
} else if (_stricmp(extension, "sc4") == 0) {
if (rct1_load_scenario(path)) {
scenario_begin();
}
}
return false;
@ -497,3 +503,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_EXTENSION_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

@ -616,12 +616,12 @@ rct_track_td6* load_track_design(const char *path)
// Unsure why it is 67
edi = (uint8*)&track_design->vehicle_colours;
for (i = 0; i < 67; i++, edi++)
*edi = RCT1ColourConversionTable[*edi];
*edi = rct1_get_colour(*edi);
// Edit the colours to use the new versions
edi = (uint8*)&track_design->track_spine_colour;
for (i = 0; i < 12; i++, edi++)
*edi = RCT1ColourConversionTable[*edi];
*edi = rct1_get_colour(*edi);
// Highest drop height is 1bit = 3/4 a meter in td6
// Highest drop height is 1bit = 1/3 a meter in td4
@ -632,9 +632,6 @@ rct_track_td6* load_track_design(const char *path)
if (td4_track_has_boosters(track_design, track_elements))
track_design->type = RIDE_TYPE_NULL;
if (track_design->type == RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER)
track_design->type = RIDE_TYPE_NULL;
if (track_design->type == RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER)
track_design->type = RIDE_TYPE_WOODEN_ROLLER_COASTER;
@ -654,8 +651,8 @@ rct_track_td6* load_track_design(const char *path)
vehicle_object = RCT2_ADDRESS(0x0097F66C, rct_object_entry);
} else {
int vehicle_type = track_design->vehicle_type;
if (vehicle_type == 3 && track_design->type == RIDE_TYPE_INVERTED_ROLLER_COASTER)
vehicle_type = 80;
if (vehicle_type == RCT1_VEHICLE_TYPE_INVERTED_COASTER_TRAIN && track_design->type == RIDE_TYPE_INVERTED_ROLLER_COASTER)
vehicle_type = RCT1_VEHICLE_TYPE_4_ACROSS_INVERTED_COASTER_TRAIN;
vehicle_object = &RCT2_ADDRESS(0x0097F0DC, rct_object_entry)[vehicle_type];
}

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;

View File

@ -168,11 +168,8 @@ typedef struct {
uint8 guest_count_change_modifier;
uint8 current_research_level;
uint8 pad_01357400[4];
uint32 dword_01357404;
uint32 dword_01357408;
uint32 dword_0135740C;
uint32 dword_01357410[5];
uint32 dword_01357424[8];
uint32 ride_types_researched[8];
uint32 ride_entries_researched[8];
uint32 dword_01357444[128];
uint32 dword_01357644[128];

View File

@ -483,14 +483,20 @@ int sawyercoding_detect_file_type(const uint8 *src, size_t length)
actualChecksum = rol32(actualChecksum, 3);
}
switch (checksum - actualChecksum) {
case +108156: return FILE_VERSION_RCT1 | FILE_TYPE_SV4;
case -108156: return FILE_VERSION_RCT1 | FILE_TYPE_SC4;
case +110001: return FILE_VERSION_RCT1_AA | FILE_TYPE_SV4;
case -110001: return FILE_VERSION_RCT1_AA | FILE_TYPE_SC4;
case +120001: return FILE_VERSION_RCT1_LL | FILE_TYPE_SV4;
case -120001: return FILE_VERSION_RCT1_LL | FILE_TYPE_SC4;
}
return sawyercoding_detect_rct1_version(checksum - actualChecksum);
}
int sawyercoding_detect_rct1_version(int gameVersion)
{
int fileType = (gameVersion) > 0 ? FILE_TYPE_SV4 : FILE_TYPE_SC4;
gameVersion=abs(gameVersion);
if (gameVersion >= 108000 && gameVersion < 110000)
return (FILE_VERSION_RCT1 | fileType);
else if (gameVersion >= 110000 && gameVersion < 120000)
return (FILE_VERSION_RCT1_AA | fileType);
else if (gameVersion >= 120000 && gameVersion < 130000)
return (FILE_VERSION_RCT1_LL | fileType);
return -1;
}

View File

@ -21,6 +21,7 @@
#ifndef _SAWYERCODING_H_
#define _SAWYERCODING_H_
#include <SDL.h>
#include "../common.h"
typedef struct {
@ -59,5 +60,6 @@ size_t sawyercoding_encode_td6(const uint8 *src, uint8 *dst, size_t length);
int sawyercoding_validate_track_checksum(const uint8* src, size_t length);
int sawyercoding_detect_file_type(const uint8 *src, size_t length);
int sawyercoding_detect_rct1_version(int gameVersion);
#endif

View File

@ -334,17 +334,15 @@ static void window_new_ride_populate_list()
continue;
// Skip if the vehicle isn't the preferred vehicle for this generic track type
if(gConfigInterface.select_by_track_type && (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry))) {
if(strcmp(preferredVehicleName," \0")==0) {
strcpy(preferredVehicleName,rideEntryName);
preferredVehicleName[8]=0;
}
else {
if(vehicleIsHigherInHierarchy(rideType,preferredVehicleName,rideEntryName)) {
strcpy(preferredVehicleName,rideEntryName);
preferredVehicleName[8]=0;
}
else {
if (gConfigInterface.select_by_track_type && (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry))) {
if (strcmp(preferredVehicleName, " \0") == 0) {
strcpy(preferredVehicleName, rideEntryName);
preferredVehicleName[8] = 0;
} else {
if (vehicle_preference_compare(rideType, preferredVehicleName, rideEntryName) == 1) {
strcpy(preferredVehicleName, rideEntryName);
preferredVehicleName[8] = 0;
} else {
continue;
}
}