diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 76de164e44..4241dea9f4 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -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 = ""; }; + C650B2161CCABBDD00B4D91C /* S4Importer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S4Importer.h; sourceTree = ""; }; + C650B2171CCABBDD00B4D91C /* tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tables.cpp; sourceTree = ""; }; + C650B2181CCABBDD00B4D91C /* Tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tables.h; sourceTree = ""; }; + C650B21B1CCABC4400B4D91C /* ConvertCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConvertCommand.cpp; sourceTree = ""; }; 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 */, diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 2b727d7a99..b8ad4d525a 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -24,6 +24,7 @@ + @@ -95,6 +96,8 @@ + + @@ -268,6 +271,8 @@ + + diff --git a/openrct2.vcxproj.filters b/openrct2.vcxproj.filters index bf277acd45..1e67da3095 100644 --- a/openrct2.vcxproj.filters +++ b/openrct2.vcxproj.filters @@ -50,6 +50,9 @@ {4bf369d2-3df8-40c9-a878-f484b0a0afd3} + + {f59cd7d6-b58d-4a6f-9118-34f94de84766} + @@ -591,6 +594,15 @@ Source\Windows + + Source\RCT1 + + + Source\RCT1 + + + Source\CommandLine + @@ -902,9 +914,15 @@ Source\Core + + Source\RCT1 + Resource Files + + Source\RCT1 + 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/Diagnostics.cpp b/src/core/Diagnostics.cpp index 644cb59892..210dad85cb 100644 --- a/src/core/Diagnostics.cpp +++ b/src/core/Diagnostics.cpp @@ -13,7 +13,8 @@ namespace Debug { #if DEBUG #if __WINDOWS__ - if (IsDebuggerPresent()) { + if (IsDebuggerPresent()) + { DebugBreak(); } #endif 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/List.hpp b/src/core/List.hpp index 80fdf724f6..f22825ee1d 100644 --- a/src/core/List.hpp +++ b/src/core/List.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "../common.h" @@ -22,6 +23,8 @@ public: List() : std::vector() { } + List(std::initializer_list initializerList) : std::vector(initializerList) { } + List(size_t capacity) : std::vector(capacity) { } List(const T * items, size_t count) : std::vector(items, items + count) { } @@ -46,6 +49,11 @@ public: this->push_back(item); } + void AddRange(std::initializer_list 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::operator[](index); } + + size_t IndexOf(std::function predicate) + { + for (size_t i = 0; i < this->size(); i++) + { + T item = std::vector::operator[](i); + if (predicate(item)) + { + return i; + } + } + return SIZE_MAX; + } + + size_t IndexOf(T item, std::function comparer) + { + for (size_t i = 0; i < this->size(); i++) + { + T element = std::vector::operator[](i); + if (comparer(item, element)) + { + return i; + } + } + return SIZE_MAX; + } + + bool Contains(std::function predicate) + { + return IndexOf(predicate) != SIZE_MAX; + } + + bool Contains(T item, std::function comparer) + { + return IndexOf(item, comparer) != SIZE_MAX; + } }; diff --git a/src/core/Path.cpp b/src/core/Path.cpp index 514f53ddeb..2af2208949 100644 --- a/src/core/Path.cpp +++ b/src/core/Path.cpp @@ -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__ diff --git a/src/core/Path.hpp b/src/core/Path.hpp index b3aa163f72..3c5aa4f994 100644 --- a/src/core/Path.hpp +++ b/src/core/Path.hpp @@ -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); } diff --git a/src/editor.c b/src/editor.c index 1ec2ecd4a8..f3a22b84de 100644 --- a/src/editor.c +++ b/src/editor.c @@ -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 diff --git a/src/interface/viewport.c b/src/interface/viewport.c index 075c85c265..6bbe90d92a 100644 --- a/src/interface/viewport.c +++ b/src/interface/viewport.c @@ -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, diff --git a/src/management/research.c b/src/management/research.c index fe9de1bd54..db17ceca8d 100644 --- a/src/management/research.c +++ b/src/management/research.c @@ -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); +} diff --git a/src/management/research.h b/src/management/research.h index f8cf061082..737efea96c 100644 --- a/src/management/research.h +++ b/src/management/research.h @@ -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 diff --git a/src/object.h b/src/object.h index 7d0dc72b0e..b3aa0159dd 100644 --- a/src/object.h +++ b/src/object.h @@ -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); diff --git a/src/object_list.c b/src/object_list.c index 082764e7cb..9b8dbcd6cd 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -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) { diff --git a/src/rct1.c b/src/rct1.c index cb2db19731..caa9d35f51 100644 --- a/src/rct1.c +++ b/src/rct1.c @@ -20,50 +20,9 @@ #include "addresses.h" #include "config.h" -#include "editor.h" -#include "interface/viewport.h" -#include "interface/window.h" -#include "localisation/localisation.h" -#include "management/finance.h" -#include "object.h" #include "rct1.h" -#include "ride/ride.h" -#include "scenario.h" #include "util/sawyercoding.h" #include "util/util.h" -#include "world/climate.h" -#include "world/footpath.h" -#include "world/map.h" -#include "world/map_animation.h" -#include "world/scenery.h" - -typedef struct { - const rct_object_entry* entries; - int count; -} RCT1DefaultObjectsGroup; - -static const uint8 RCT1TerrainConvertTable[16]; -static const uint8 RCT1TerrainEdgeConvertTable[16]; -static const uint8 RCT1PathTypeConversionTable[96]; -static const uint8 RCT1PathAdditionConversionTable[15]; -static const RCT1DefaultObjectsGroup RCT1DefaultObjects[10]; - -static void rct1_remove_rides(); -static void rct1_load_default_objects(); -static void rct1_fix_terrain(); -static void rct1_fix_scenery(); -static void rct1_fix_entrance_positions(); -static void rct1_reset_research(); - -static void rct1_process_scenario_flags(); -static void rct1_reset_park_entrance_path_type(); -static void rct1_clear_extra_sprite_entries(); -static void rct1_clear_extra_tile_entries(); -static void rct1_fix_colours(); -static void rct1_fix_z(); -static void rct1_fix_paths(); -static void rct1_fix_walls(); -static void sub_69E891(); bool rct1_read_sc4(const char *path, rct1_s4 *s4) { @@ -121,1710 +80,114 @@ bool rct1_read_sv4(const char *path, rct1_s4 *s4) return success; } -/** - * - * rct2: 0x0069EEA0 - */ -void rct1_import_s4(rct1_s4 *s4) +bool rideTypeShouldLoseSeparateFlag(rct_ride_entry *rideEntry) { - int i; - rct_banner *banner; - - memcpy((void*)RCT2_ADDRESS_CURRENT_MONTH_YEAR, &s4->month, 16); - memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, 0x30000 * sizeof(rct_map_element)); - memcpy((void*)RCT2_ADDRESS_MAP_ELEMENTS, s4->map_elements, sizeof(s4->map_elements)); - memcpy((void*)0x010E63B8, &s4->unk_counter, 4 + sizeof(s4->sprites)); - - for (i = 0; i < MAX_BANNERS; i++) - gBanners[i].type = 255; - - memcpy((void*)0x013573BC, &s4->next_sprite_index, 12424); - - for (i = 0; i < MAX_BANNERS; i++) { - banner = &gBanners[i]; - if (banner->type != 255 && banner->string_idx != 3458) - banner->string_idx = 778; - } - - memcpy((void*)0x0135A8F4, &s4->string_table, 0x2F51C); - memset((void*)RCT2_ADDRESS_STAFF_MODE_ARRAY, 0, 204); - memcpy((void*)0x0138B580, &s4->map_animations, 0x258F2); - memcpy((void*)0x013C6A72, &s4->patrol_areas, sizeof(s4->patrol_areas)); - - char *esi = (char*)0x13C6A72; - char *edi = (char*)RCT2_ADDRESS_STAFF_PATROL_AREAS; - int ebx, edx = 116; - do { - ebx = 32; - do { - memcpy(edi, esi, 4); esi += 4; edi += 4; - memset(edi, 0, 4); edi += 4; - } while (--ebx > 0); - memset(edi, 0, 64); edi += 64; - } while (--edx > 0); - edi += 0xA800; - - edx = 4; - do { - ebx = 32; - do { - memcpy(edi, esi, 4); esi += 4; edi += 4; - memset(edi, 0, 4); edi += 4; - } while (--ebx); - memset(edi, 0, 64); edi += 64; - } while (--edx); - - memcpy((void*)RCT2_ADDRESS_STAFF_MODE_ARRAY, &s4->unk_1F42AA, 116); - memcpy((void*)0x013CA73A, &s4->unk_1F431E, 4); - memcpy((void*)0x013CA73E, &s4->unk_1F4322, 0x41EA); -} - -/** - * - * rct2: 0x006A2B62 - */ -void rct1_fix_landscape() -{ - int i; - rct_sprite *sprite; - rct_ride *ride; - - rct1_clear_extra_sprite_entries(); - - // Free sprite user strings - for (i = 0; i < MAX_SPRITES; i++) { - sprite = &g_sprite_list[i]; - if (sprite->unknown.sprite_identifier != 255) - user_string_free(sprite->unknown.name_string_idx); - } - - reset_sprite_list(); - - // Free ride user strings - FOR_ALL_RIDES(i, ride) - user_string_free(ride->name); - - ride_init_all(); - 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, uint8) = 0; - rct1_clear_extra_tile_entries(); - rct1_process_scenario_flags(); - rct1_fix_colours(); - rct1_fix_z(); - rct1_fix_paths(); - rct1_remove_rides(); - object_unload_all(); - rct1_load_default_objects(); - reset_loaded_objects(); - rct1_fix_walls(); - rct1_fix_scenery(); - rct1_fix_terrain(); - rct1_fix_entrance_positions(); - rct1_reset_research(); - research_populate_list_random(); - research_remove_non_separate_vehicle_types(); - - climate_reset(RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8)); - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR; - viewport_init_all(); - news_item_init_queue(); - window_editor_main_open(); - - rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; - rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - - s6Info->editor_step = EDITOR_STEP_LANDSCAPE_EDITOR; - s6Info->category = 4; - format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); - s6Info->name[0] = 0; - 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; - } - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) == MONEY_FREE) { - 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, money32) = min( - MONEY(10000,00), - RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) - ); - 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 - ); - - if ( - RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_NONE || - RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_HAVE_FUN || - RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_BUILD_THE_BEST - ) { - RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) = OBJECTIVE_GUESTS_BY; - RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) = 4; - RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) = 1000; - } - - RCT2_GLOBAL(0x01358774, uint16) = 0; -} - -static void rct1_remove_rides() -{ - map_element_iterator it; - - map_element_iterator_begin(&it); - do { - switch (map_element_get_type(it.element)) { - case MAP_ELEMENT_TYPE_PATH: - if (it.element->type & 1) { - it.element->properties.path.type &= 0xF7; - it.element->properties.path.ride_index = 255; - } - break; - - case MAP_ELEMENT_TYPE_TRACK: - sub_6A7594(); - footpath_remove_edges_at(it.x * 32, it.y * 32, it.element); - map_element_remove(it.element); - map_element_iterator_restart_for_tile(&it); - break; - - case MAP_ELEMENT_TYPE_ENTRANCE: - if (it.element->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) { - sub_6A7594(); - footpath_remove_edges_at(it.x * 32, it.y * 32, it.element); - map_element_remove(it.element); - map_element_iterator_restart_for_tile(&it); - } - break; - } - } while (map_element_iterator_next(&it)); -} - -static bool is_object_name_blank(rct_object_entry *entry) -{ - for (int i = 0; i < 8; i++) { - if (entry->name[i] != ' ') { - return false; - } - } - return true; -} - -/** - * - * rct2: 0x0069F53D - */ -static void rct1_load_default_objects() -{ - for (int i = 0; i < 9; i++) { - rct_object_entry *entries = (rct_object_entry*)RCT1DefaultObjects[i].entries; - for (int j = 0; j < RCT1DefaultObjects[i].count; j++) { - if (is_object_name_blank(&entries[j])) { - continue; - } - - if (!object_load_chunk(j, &entries[j], NULL)) { - error_string_quit(0x99990000 + (i * 0x100) + j, -1); - return; - } - } - } - - // Water is a special case - rct_object_entry *waterEntries = (rct_object_entry*)RCT1DefaultObjects[9].entries; - rct_object_entry *waterEntry = &waterEntries[RCT2_GLOBAL(0x01358841, uint8) == 0 ? 0 : 1]; - if (!object_load_chunk(0, waterEntry, NULL)) { - error_string_quit(0x99990900, -1); - return; - } -} - -/** - * - * rct2: 0x006A29B9 - */ -static void rct1_fix_terrain() -{ - rct_map_element *element; - map_element_iterator it; - - map_element_iterator_begin(&it); - while (map_element_iterator_next(&it)) { - element = it.element; - - if (map_element_get_type(element) != MAP_ELEMENT_TYPE_SURFACE) - continue; - - // Convert terrain - map_element_set_terrain(element, RCT1TerrainConvertTable[map_element_get_terrain(element)]); - map_element_set_terrain_edge(element, RCT1TerrainEdgeConvertTable[map_element_get_terrain_edge(element)]); - } -} - -/** - * - * rct2: 0x006A2956 - */ -static void rct1_fix_scenery() -{ - rct_map_element *element; - map_element_iterator it; - - map_element_iterator_begin(&it); - while (map_element_iterator_next(&it)) { - element = it.element; - - if (map_element_get_type(element) != MAP_ELEMENT_TYPE_SCENERY) - continue; - - switch (element->properties.scenery.type) { - case 157: // TGE1 (Geometric Sculpture) - case 162: // TGE2 (Geometric Sculpture) - case 168: // TGE3 (Geometric Sculpture) - case 170: // TGE4 (Geometric Sculpture) - case 171: // TGE5 (Geometric Sculpture) - element->properties.scenery.colour_2 = 2; - break; - } - } -} - -/** - * This isn't really RCT1 specific anymore. - * rct2: 0x006A2A68 - */ -static void rct1_fix_entrance_positions() -{ - rct_map_element *element; - map_element_iterator it; - - for (int i = 0; i < 4; i++) - RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] = 0x8000; - - int entranceIndex = 0; - - map_element_iterator_begin(&it); - while (map_element_iterator_next(&it)) { - element = it.element; - - if (map_element_get_type(element) != MAP_ELEMENT_TYPE_ENTRANCE) - continue; - if (element->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) - continue; - if ((element->properties.entrance.index & 0x0F) != 0) - continue; - - RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[entranceIndex] = it.x * 32; - RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, uint16)[entranceIndex] = it.y * 32; - RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, uint16)[entranceIndex] = element->base_height * 8; - RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION, uint8)[entranceIndex] = element->type & 3; - entranceIndex++; - - // Prevent overflow - if (entranceIndex == 4) - return; - } -} - -/** - * - * rct2: 0x0069F509 - */ -static void rct1_reset_research() -{ - rct_research_item *researchItem; - - researchItem = gResearchItems; - researchItem->entryIndex = RESEARCHED_ITEMS_SEPARATOR; - researchItem++; - researchItem->entryIndex = RESEARCHED_ITEMS_END; - researchItem++; - researchItem->entryIndex = RESEARCHED_ITEMS_END_2; - RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, sint32) = -1; - news_item_init_queue(); -} - -/** - * - * rct2: 0x0069F06A - */ -static void rct1_process_scenario_flags() -{ - uint32 scenarioFlags = RCT2_GLOBAL(0x013CE770, uint32); - - if (!(scenarioFlags & RCT1_SCENARIO_FLAG_ENABLE_BANNERS)) { - banner_init(); - } - if (!(scenarioFlags & (1 << 6))) { - sub_69E891(); - } - if (!(scenarioFlags & RCT1_SCENARIO_FLAG_CUSTOM_PARK_ENTRANCE_PATH)) { - rct1_reset_park_entrance_path_type(); - } - if (!(scenarioFlags & RCT1_SCENARIO_FLAG_NO_CASH_RESET)) { - finance_reset_cash_to_initial(); - } - if (!(scenarioFlags & RCT1_SCENARIO_FLAG_CUSTOM_MAP_SIZE)) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) = 127 * 32; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, uint16) = 4350; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) = 128; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16) = 4095; - } - if (!(scenarioFlags & (1 << 15))) { - RCT2_GLOBAL(0x01358838, uint32) = 0; - } -} - -/** - * - * rct2: 0x00666DFD - */ -static void rct1_reset_park_entrance_path_type() -{ - int x, y; - rct_map_element *mapElement; - - x = RCT2_GLOBAL(0x013573EA, uint16); - y = RCT2_GLOBAL(0x013573EC, uint16); - if (x == (sint16)0x8000) - return; - - mapElement = map_get_first_element_at(x >> 5, y >> 5); - do { - if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { - if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) { - mapElement->properties.entrance.path_type = 0; - break; - } - } - } while (!map_element_is_last_for_tile(mapElement++)); -} - -/** - * - * rct2: 0x0069F007 - */ -static void rct1_clear_extra_sprite_entries() -{ - rct_unk_sprite *sprite; - - for (int i = 5000; i < MAX_SPRITES; i++) { - sprite = &(g_sprite_list[i].unknown); - - memset(&g_sprite_list[i], 0, sizeof(rct_sprite)); - - sprite->sprite_identifier = 255; - sprite->sprite_index = i; - sprite->linked_list_type_offset = SPRITE_LINKEDLIST_OFFSET_NULL; - sprite->previous = SPRITE_INDEX_NULL; - sprite->next = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_NEXT_INDEX, uint16); - RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_NEXT_INDEX, uint16) = i; - - sprite = &(g_sprite_list[sprite->next].unknown); - sprite->previous = i; - } - RCT2_GLOBAL(0x013573C8, uint16) += 5000; -} - -/** - * - * rct2: 0x0069F44B - */ -static void rct1_clear_extra_tile_entries() -{ - // Reset the map tile pointers - for (int i = 0; i < 0x10000; i++) { - gMapElementTilePointers[i] = (rct_map_element*)-1; - } - - // Get the first free map element - rct_map_element *nextFreeMapElement = gMapElements; - for (int i = 0; i < 128 * 128; i++) { - do { - - } while (!map_element_is_last_for_tile(nextFreeMapElement++)); - } - - rct_map_element *mapElement = gMapElements; - rct_map_element **tilePointer = gMapElementTilePointers; - - // 128 rows of map data from RCT1 map - for (int x = 0; x < 128; x++) { - // Assign the first half of this row - for (int y = 0; y < 128; y++) { - *tilePointer++ = mapElement; - do { - - } while (!map_element_is_last_for_tile(mapElement++)); - } - - // Fill the rest of the row with blank tiles - for (int y = 0; y < 128; y++) { - nextFreeMapElement->type = MAP_ELEMENT_TYPE_SURFACE; - nextFreeMapElement->flags = MAP_ELEMENT_FLAG_LAST_TILE; - nextFreeMapElement->base_height = 2; - nextFreeMapElement->clearance_height = 0; - nextFreeMapElement->properties.surface.slope = 0; - nextFreeMapElement->properties.surface.terrain = 0; - nextFreeMapElement->properties.surface.grass_length = GRASS_LENGTH_CLEAR_0; - nextFreeMapElement->properties.surface.ownership = 0; - *tilePointer++ = nextFreeMapElement++; - } - } - - // 128 extra rows left to fill with blank tiles - for (int y = 0; y < 128 * 256; y++) { - nextFreeMapElement->type = MAP_ELEMENT_TYPE_SURFACE; - nextFreeMapElement->flags = MAP_ELEMENT_FLAG_LAST_TILE; - nextFreeMapElement->base_height = 2; - nextFreeMapElement->clearance_height = 0; - nextFreeMapElement->properties.surface.slope = 0; - nextFreeMapElement->properties.surface.terrain = 0; - nextFreeMapElement->properties.surface.grass_length = GRASS_LENGTH_CLEAR_0; - nextFreeMapElement->properties.surface.ownership = 0; - *tilePointer++ = nextFreeMapElement++; - } - - RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*) = nextFreeMapElement; -} - -/** - * - * rct2: 0x0069F143 - */ -static void rct1_fix_colours() -{ - int rideIndex, colour; - rct_ride *ride; - rct_unk_sprite *sprite; - rct_peep *peep; - rct_balloon *balloon; - rct_map_element *mapElement; - - FOR_ALL_RIDES(rideIndex, ride) { - for (int i = 0; i < 4; i++) { - ride->track_colour_main[i] = RCT1ColourConversionTable[ride->track_colour_main[i]]; - ride->track_colour_additional[i] = RCT1ColourConversionTable[ride->track_colour_additional[i]]; - ride->track_colour_supports[i] = RCT1ColourConversionTable[ride->track_colour_supports[i]]; - } - - for (int i = 0; i < 32; i++) { - ride->vehicle_colours[i].body_colour = RCT1ColourConversionTable[ride->vehicle_colours[i].body_colour]; - ride->vehicle_colours[i].trim_colour = RCT1ColourConversionTable[ride->vehicle_colours[i].trim_colour]; - } - } - - for (int i = 0; i < MAX_SPRITES; i++) { - sprite = &(g_sprite_list[i].unknown); - switch (sprite->sprite_identifier) { - case SPRITE_IDENTIFIER_PEEP: - peep = (rct_peep*)sprite; - peep->tshirt_colour = RCT1ColourConversionTable[peep->tshirt_colour]; - peep->trousers_colour = RCT1ColourConversionTable[peep->trousers_colour]; - peep->balloon_colour = RCT1ColourConversionTable[peep->balloon_colour]; - peep->umbrella_colour = RCT1ColourConversionTable[peep->umbrella_colour]; - peep->hat_colour = RCT1ColourConversionTable[peep->hat_colour]; - break; - case SPRITE_IDENTIFIER_MISC: - balloon = (rct_balloon*)sprite; - balloon->colour = RCT1ColourConversionTable[balloon->colour]; - balloon->var_2D = RCT1ColourConversionTable[balloon->var_2D]; - break; - } - } - - mapElement = gMapElements; - while (mapElement < RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*)) { - if (mapElement->base_height != 255) { - switch (map_element_get_type(mapElement)) { - case MAP_ELEMENT_TYPE_SCENERY: - colour = RCT1ColourConversionTable[mapElement->properties.scenery.colour_1 & 0x1F]; - mapElement->properties.scenery.colour_1 &= 0xE0; - mapElement->properties.scenery.colour_1 |= colour; - break; - case MAP_ELEMENT_TYPE_FENCE: - colour = RCT1ColourConversionTable[ - ((mapElement->type & 0xC0) >> 3) | - ((mapElement->properties.fence.type & 0xE0) >> 5) - ]; - - mapElement->type &= 0x3F; - mapElement->properties.fence.type &= 0x1F; - mapElement->type |= (colour & 0x18) << 3; - mapElement->properties.fence.type |= (colour & 7) << 5; - break; - case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: - colour = RCT1ColourConversionTable[mapElement->properties.scenerymultiple.colour[0] & 0x1F]; - mapElement->properties.scenerymultiple.colour[0] &= 0xE0; - mapElement->properties.scenerymultiple.colour[0] |= colour; - - colour = RCT1ColourConversionTable[mapElement->properties.scenerymultiple.colour[1] & 0x1F]; - mapElement->properties.scenerymultiple.colour[1] &= 0xE0; - mapElement->properties.scenerymultiple.colour[1] |= colour; - break; - } - } - mapElement++; - } -} - -/** - * - * rct2: 0x0069F2D0 - */ -static void rct1_fix_z() -{ - int i; - rct_ride *ride; - rct_unk_sprite *sprite; - rct_peep *peep; - rct_ride_measurement *rideMeasurement; - rct_map_element *mapElement; - - FOR_ALL_RIDES(i, ride) { - for (int i = 0; i < 4; i++) { - ride->station_heights[i] /= 2; - } - ride->start_drop_height /= 2; - ride->highest_drop_height = 1; - if (ride->cur_test_track_z != 255) { - ride->cur_test_track_z /= 2; - } - ride->chairlift_bullwheel_z[0] /= 2; - ride->chairlift_bullwheel_z[1] /= 2; - } - - for (int i = 0; i < RCT2_GLOBAL(0x0138B580, uint16); i++) { - gAnimatedObjects[i].baseZ /= 2; - } - - for (int i = 0; i < MAX_SPRITES; i++) { - sprite = &(g_sprite_list[i].unknown); - if (sprite->sprite_identifier == SPRITE_IDENTIFIER_PEEP) { - peep = (rct_peep*)sprite; - peep->next_z /= 2; - RCT2_GLOBAL((int)peep + 0xCE, uint8) /= 2; - } - } - - for (int i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { - rideMeasurement = get_ride_measurement(i); - if (rideMeasurement->ride_index == 255) - continue; - - for (int i = 0; i < RIDE_MEASUREMENT_MAX_ITEMS; i++) { - rideMeasurement->altitude[i] /= 2; - } - } - - mapElement = gMapElements; - while (mapElement < RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*)) { - if (mapElement->base_height != 255) { - mapElement->base_height /= 2; - mapElement->clearance_height /= 2; - } - mapElement++; - } - RCT2_GLOBAL(0x01359208, uint16) = 7; -} - -/** - * - * rct2: 0x0069F3AB - */ -static void rct1_fix_paths() -{ - rct_map_element *mapElement; - int pathType, secondaryType, additions; - - mapElement = gMapElements; - while (mapElement < RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*)) { - switch (map_element_get_type(mapElement)) { - case MAP_ELEMENT_TYPE_PATH: - // Type - pathType = ((mapElement->properties.path.type & 0xF0) >> 2) | (mapElement->type & 3); - secondaryType = (mapElement->flags & 0x60) >> 5; - pathType = RCT1PathTypeConversionTable[pathType * 4 + secondaryType]; - - mapElement->type &= 0xFC; - mapElement->flags &= ~0x60; - mapElement->properties.path.type &= 0x0F; - footpath_scenery_set_is_ghost(mapElement, false); - if (pathType & 0x80) { - mapElement->type |= 1; - } - mapElement->properties.path.type |= pathType << 4; - - // Additions - additions = RCT1PathAdditionConversionTable[footpath_element_get_path_scenery(mapElement)]; - if (footpath_element_path_scenery_is_ghost(mapElement)) { - footpath_scenery_set_is_ghost(mapElement, false); - mapElement->flags |= MAP_ELEMENT_FLAG_BROKEN; - } else { - mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; - } - - footpath_element_set_path_scenery(mapElement, additions); - break; - case MAP_ELEMENT_TYPE_ENTRANCE: - if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) { - pathType = mapElement->properties.entrance.path_type; - mapElement->properties.entrance.path_type = RCT1PathTypeConversionTable[pathType * 4] & 0x7F; - } - break; - } - mapElement++; - } -} - -/** - * - * rct2: 0x006A28F5 - */ -static void rct1_convert_wall(int *type, int *colourA, int *colourB, int *colourC) -{ - switch (*type) { - case 12: // creepy gate - *colourA = 24; - break; - case 26: // white wooden fence - *type = 12; - *colourA = 2; - break; - case 27: // red wooden fence - *type = 12; - *colourA = 25; - break; - case 50: // plate glass - *colourA = 24; - break; - case 13: - *colourB = *colourA; - *colourA = 24; - break; - case 11: // tall castle wall with grey gate - case 22: // brick wall with gate - *colourB = 2; - break; - case 35: // wood post fence - case 42: // tall grey castle wall - case 43: // wooden fence with snow - case 44: - case 45: - case 46: - *colourA = 1; - break; - } -} - -/** - * - * rct2: 0x006A2730 - */ -static void rct1_fix_walls() -{ - rct_map_element *mapElement, originalMapElement; - - for (int x = 0; x < 128; x++) { - for (int y = 0; y < 128; y++) { - mapElement = map_get_first_element_at(x, y); - do { - if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_FENCE) { - originalMapElement = *mapElement; - map_element_remove(mapElement); - - uint8 var_05 = originalMapElement.properties.fence.item[0]; - uint16 var_06 = ( - originalMapElement.properties.fence.item[1] | - (originalMapElement.properties.fence.item[2] << 8) - ); - - for (int edge = 0; edge < 4; edge++) { - int typeA = (var_05 >> (edge * 2)) & 3; - int typeB = (var_06 >> (edge * 4)) & 0x0F; - if (typeB != 0x0F) { - int type = typeA | (typeB << 2); - int colourA = ( - ((originalMapElement.type & 0xC0) >> 3) | - (originalMapElement.properties.fence.type >> 5) - ); - int colourB = 0; - int colourC = 0; - rct1_convert_wall(&type, &colourA, &colourB, &colourC); - map_place_fence(type, x * 32, y * 32, 0, edge, colourA, colourB, colourC, 169); - } - } - break; - } - } while (!map_element_is_last_for_tile(mapElement++)); - } - } -} - -/** - * - * rct2: 0x0069E891 - */ -static void sub_69E891() -{ - RCT2_GLOBAL(0x013587D8, uint16) = 63; -} - -#pragma region Tables - -/** - * - * rct2: 0x0097F0BC, 0x0098BC60 - */ -const uint8 RCT1ColourConversionTable[32] = { - 0, 1, 2, 4, 5, 6, 7, 9, - 11, 12, 13, 14, 15, 16, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, - 28, 30, 31, 29, 3, 10, 17, 8 -}; - -static const uint8 RCT1TerrainConvertTable[16] = { - TERRAIN_GRASS, - TERRAIN_SAND, - TERRAIN_DIRT, - TERRAIN_ROCK, - TERRAIN_MARTIAN, - TERRAIN_CHECKERBOARD, - TERRAIN_GRASS_CLUMPS, - TERRAIN_DIRT, // Originally TERRAIN_ROOF_BROWN - TERRAIN_ICE, - TERRAIN_DIRT, // Originally TERRAIN_ROOF_LOG - TERRAIN_DIRT, // Originally TERRAIN_ROOF_IRON - TERRAIN_DIRT, // Originally TERRAIN_ROOF_GREY - TERRAIN_GRID_RED, - TERRAIN_GRID_YELLOW, - TERRAIN_GRID_BLUE, - TERRAIN_GRID_GREEN -}; - -static const uint8 RCT1TerrainEdgeConvertTable[16] = { - TERRAIN_EDGE_ROCK, - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_BRICK - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_IRON - TERRAIN_EDGE_WOOD_RED, - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_GREY - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_YELLOW - TERRAIN_EDGE_WOOD_BLACK, - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_RED - TERRAIN_EDGE_ICE, - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_PURPLE - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_GREEN - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_STONE_BROWN - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_STONE_GREY - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_SKYSCRAPER_A - TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_SKYSCRAPER_B - TERRAIN_EDGE_ROCK // Unused -}; - -// rct2: 0x0098BC9F -static const uint8 RCT1PathTypeConversionTable[96] = { - 0x80 | 0, 0x80 | 1, 0x80 | 2, 0x80 | 3, - 0x80 | 0, 0x80 | 1, 0x80 | 2, 0x80 | 3, - 0x80 | 0, 0x80 | 1, 0x80 | 2, 0x80 | 3, - 0x80 | 0, 0x80 | 1, 0x80 | 2, 0x80 | 3, - 0, 0, 0, 0, - 2, 2, 2, 2, - 1, 1, 1, 1, - 0, 0, 0, 0, - 3, 3, 3, 3, - 6, 6, 6, 6, - 0, 0, 0, 0, - 0, 0, 0, 0, - 5, 5, 5, 5, - 5, 5, 5, 5, - 5, 5, 5, 5, - 5, 5, 5, 5, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, -}; - -// rct2: 0x0098BCFF -static const uint8 RCT1PathAdditionConversionTable[15] = { - 0, - 1, 2, 3, 4, 5, 6, 7, - 0x80 | 1, 0x80 | 2, 0x80 | 3, 0x80 | 4, 0x80 | 6, 0x80 | 7, - 8, -}; - -#pragma endregion - -#pragma region RCT1 Default Objects - -static const rct_object_entry RCT1DefaultObjectsRides[] = { - { 0x00008000, { "PTCT1 " }, 0 }, - { 0x00008000, { "TOGST " }, 0 }, - { 0x00008000, { "ARRSW1 " }, 0 }, - { 0x00008000, { "NEMT " }, 0 }, - { 0x00008000, { "ZLDB " }, 0 }, - { 0x00008000, { "NRL " }, 0 }, - { 0x00008000, { "MONO2 " }, 0 }, - { 0x00008000, { "BATFL " }, 0 }, - { 0x00008000, { "RBOAT " }, 0 }, - { 0x00008000, { "WMOUSE " }, 0 }, - { 0x00008000, { "STEEP1 " }, 0 }, - { 0x00008000, { "SPCAR " }, 0 }, - { 0x00008000, { "SSC1 " }, 0 }, - { 0x00008000, { "BOB1 " }, 0 }, - { 0x00008000, { "OBS1 " }, 0 }, - { 0x00008000, { "SCHT1 " }, 0 }, - { 0x00008000, { "DING1 " }, 0 }, - { 0x00008000, { "AMT1 " }, 0 }, - { 0x00008000, { "CLIFT1 " }, 0 }, - { 0x00008000, { "ARRT1 " }, 0 }, - { 0x00008000, { "HMAZE " }, 0 }, - { 0x00008000, { "HSKELT " }, 0 }, - { 0x00008000, { "KART1 " }, 0 }, - { 0x00008000, { "LFB1 " }, 0 }, - { 0x00008000, { "RAPBOAT " }, 0 }, - { 0x00008000, { "DODG1 " }, 0 }, - { 0x00008000, { "SWSH1 " }, 0 }, - { 0x00008000, { "SWSH2 " }, 0 }, - { 0x00008000, { "ICECR1 " }, 0 }, - { 0x00008000, { "CHPSH " }, 0 }, - { 0x00008000, { "DRNKS " }, 0 }, - { 0x00008000, { "CNDYF " }, 0 }, - { 0x00008000, { "BURGB " }, 0 }, - { 0x00008000, { "MGR1 " }, 0 }, - { 0x00008000, { "BALLN " }, 0 }, - { 0x00008000, { "INFOK " }, 0 }, - { 0x00008000, { "TLT1 " }, 0 }, - { 0x00008000, { "FWH1 " }, 0 }, - { 0x00008000, { "SIMPOD " }, 0 }, - { 0x00008000, { "C3D " }, 0 }, - { 0x00008000, { "TOPSP1 " }, 0 }, - { 0x00008000, { "SRINGS " }, 0 }, - { 0x00008000, { "REVF1 " }, 0 }, - { 0x00008000, { "SOUVS " }, 0 }, - { 0x00008000, { "BMVD " }, 0 }, - { 0x00008000, { "PIZZS " }, 0 }, - { 0x00008000, { "TWIST1 " }, 0 }, - { 0x00008000, { "HHBUILD " }, 0 }, - { 0x00008000, { "POPCS " }, 0 }, - { 0x00008000, { "CIRCUS1 " }, 0 }, - { 0x00008000, { "GTC " }, 0 }, - { 0x00008000, { "BMSD " }, 0 }, - { 0x00008000, { "PTCT1 " }, 0 }, - { 0x00008000, { "SFRIC1 " }, 0 }, - { 0x00008000, { "SMC1 " }, 0 }, - { 0x00008000, { "HOTDS " }, 0 }, - { 0x00008000, { "SQDST " }, 0 }, - { 0x00008000, { "HATST " }, 0 }, - { 0x00008000, { "TOFFS " }, 0 }, - { 0x00008000, { "VREEL " }, 0 }, - { 0x00008000, { "SPBOAT " }, 0 }, - { 0x00008000, { "MONBK " }, 0 }, - { 0x00008000, { "BMAIR " }, 0 }, - { 0x00008000, { "SMONO " }, 0 }, - { 0x00000000, { " " }, 0 }, - { 0x00008000, { "REVCAR " }, 0 }, - { 0x00008000, { "UTCAR " }, 0 }, - { 0x00008000, { "GOLF1 " }, 0 }, - { 0x00000000, { " " }, 0 }, - { 0x00008000, { "GDROP1 " }, 0 }, - { 0x00008000, { "FSAUC " }, 0 }, - { 0x00008000, { "CHBUILD " }, 0 }, - { 0x00008000, { "HELICAR " }, 0 }, - { 0x00008000, { "SLCT " }, 0 }, - { 0x00008000, { "CSTBOAT " }, 0 }, - { 0x00008000, { "THCAR " }, 0 }, - { 0x00008000, { "IVMC1 " }, 0 }, - { 0x00008000, { "JSKI " }, 0 }, - { 0x00008000, { "TSHRT " }, 0 }, - { 0x00008000, { "RFTBOAT " }, 0 }, - { 0x00008000, { "DOUGH " }, 0 }, - { 0x00008000, { "ENTERP " }, 0 }, - { 0x00008000, { "COFFS " }, 0 }, - { 0x00008000, { "CHCKS " }, 0 }, - { 0x00008000, { "LEMST " }, 0 } -}; - -// rct2: 0x0098BD0E -static const rct_object_entry RCT1DefaultObjectsSmallScenery[] = { - { 0x00000081, { "TL0 " }, 0 }, - { 0x00000081, { "TL1 " }, 0 }, - { 0x00000081, { "TL2 " }, 0 }, - { 0x00000081, { "TL3 " }, 0 }, - { 0x00000081, { "TM0 " }, 0 }, - { 0x00000081, { "TM1 " }, 0 }, - { 0x00000081, { "TM2 " }, 0 }, - { 0x00000081, { "TM3 " }, 0 }, - { 0x00000081, { "TS0 " }, 0 }, - { 0x00000081, { "TS1 " }, 0 }, - { 0x00000081, { "TS2 " }, 0 }, - { 0x00000081, { "TS3 " }, 0 }, - { 0x00000081, { "TS4 " }, 0 }, - { 0x00000081, { "TS5 " }, 0 }, - { 0x00000081, { "TS6 " }, 0 }, - { 0x00000081, { "TIC " }, 0 }, - { 0x00000081, { "TLC " }, 0 }, - { 0x00000081, { "TMC " }, 0 }, - { 0x00000081, { "TMP " }, 0 }, - { 0x00000081, { "TITC " }, 0 }, - { 0x00000081, { "TGHC " }, 0 }, - { 0x00000081, { "TAC " }, 0 }, - { 0x00000081, { "TGHC2 " }, 0 }, - { 0x00000081, { "TCJ " }, 0 }, - { 0x00000081, { "TMBJ " }, 0 }, - { 0x00000081, { "TCF " }, 0 }, - { 0x00000081, { "TCL " }, 0 }, - { 0x00000081, { "TRF " }, 0 }, - { 0x00000081, { "TRF2 " }, 0 }, - { 0x00000081, { "TEL " }, 0 }, - { 0x00000081, { "TAP " }, 0 }, - { 0x00000081, { "TSP " }, 0 }, - { 0x00000081, { "TMZP " }, 0 }, - { 0x00000081, { "TCRP " }, 0 }, - { 0x00000081, { "TBP " }, 0 }, - { 0x00000081, { "TLP " }, 0 }, - { 0x00000081, { "TWP " }, 0 }, - { 0x00000081, { "TAS " }, 0 }, - { 0x00000081, { "TMG " }, 0 }, - { 0x00000081, { "TWW " }, 0 }, - { 0x00000081, { "TSB " }, 0 }, - { 0x00000081, { "TVL " }, 0 }, - { 0x00000081, { "TCT " }, 0 }, - { 0x00000081, { "TEF " }, 0 }, - { 0x00000081, { "TAL " }, 0 }, - { 0x00000081, { "TSQ " }, 0 }, - { 0x00000081, { "THT " }, 0 }, - { 0x00000081, { "TCB " }, 0 }, - { 0x00000081, { "TDM " }, 0 }, - { 0x00000081, { "TSD " }, 0 }, - { 0x00000081, { "TGS " }, 0 }, - { 0x00000081, { "TUS " }, 0 }, - { 0x00000081, { "TH1 " }, 0 }, - { 0x00000081, { "TBC " }, 0 }, - { 0x00000081, { "TH2 " }, 0 }, - { 0x00000081, { "TPM " }, 0 }, - { 0x00000081, { "TSC " }, 0 }, - { 0x00000081, { "TG1 " }, 0 }, - { 0x00000081, { "TWF " }, 0 }, - { 0x00000081, { "TSH0 " }, 0 }, - { 0x00000081, { "TSH1 " }, 0 }, - { 0x00000081, { "TSH2 " }, 0 }, - { 0x00000081, { "TSH3 " }, 0 }, - { 0x00000081, { "TSH4 " }, 0 }, - { 0x00000081, { "TSH5 " }, 0 }, - { 0x00000081, { "TG2 " }, 0 }, - { 0x00000081, { "TG3 " }, 0 }, - { 0x00000081, { "TG4 " }, 0 }, - { 0x00000081, { "TG5 " }, 0 }, - { 0x00000081, { "TG6 " }, 0 }, - { 0x00000081, { "TG7 " }, 0 }, - { 0x00000081, { "TG8 " }, 0 }, - { 0x00000081, { "TG9 " }, 0 }, - { 0x00000081, { "TG10 " }, 0 }, - { 0x00000081, { "TG11 " }, 0 }, - { 0x00000081, { "TG12 " }, 0 }, - { 0x00000081, { "TG13 " }, 0 }, - { 0x00000081, { "TG14 " }, 0 }, - { 0x00000081, { "TT1 " }, 0 }, - { 0x00000081, { "TDF " }, 0 }, - { 0x00000081, { "TSH " }, 0 }, - { 0x00000081, { "THRS " }, 0 }, - { 0x00000081, { "TSTD " }, 0 }, - { 0x00000081, { "TRMS " }, 0 }, - { 0x00000081, { "TRWS " }, 0 }, - { 0x00000081, { "TRC " }, 0 }, - { 0x00000081, { "TQF " }, 0 }, - { 0x00000081, { "TES1 " }, 0 }, - { 0x00000081, { "TEN " }, 0 }, - { 0x00000081, { "TERS " }, 0 }, - { 0x00000081, { "TERB " }, 0 }, - { 0x00000081, { "TEP " }, 0 }, - { 0x00000081, { "TST1 " }, 0 }, - { 0x00000081, { "TST2 " }, 0 }, - { 0x00000081, { "TMS1 " }, 0 }, - { 0x00000081, { "TAS1 " }, 0 }, - { 0x00000081, { "TAS2 " }, 0 }, - { 0x00000081, { "TAS3 " }, 0 }, - { 0x00000081, { "TST3 " }, 0 }, - { 0x00000081, { "TST4 " }, 0 }, - { 0x00000081, { "TST5 " }, 0 }, - { 0x00000081, { "TAS4 " }, 0 }, - { 0x00000081, { "TCY " }, 0 }, - { 0x00000081, { "TBW " }, 0 }, - { 0x00000081, { "TBR1 " }, 0 }, - { 0x00000081, { "TBR2 " }, 0 }, - { 0x00000081, { "TML " }, 0 }, - { 0x00000081, { "TMW " }, 0 }, - { 0x00000081, { "TBR3 " }, 0 }, - { 0x00000081, { "TBR4 " }, 0 }, - { 0x00000081, { "TMJ " }, 0 }, - { 0x00000081, { "TBR " }, 0 }, - { 0x00000081, { "TMO1 " }, 0 }, - { 0x00000081, { "TMO2 " }, 0 }, - { 0x00000081, { "TMO3 " }, 0 }, - { 0x00000081, { "TMO4 " }, 0 }, - { 0x00000081, { "TMO5 " }, 0 }, - { 0x00000081, { "TWH1 " }, 0 }, - { 0x00000081, { "TWH2 " }, 0 }, - { 0x00000081, { "TNS " }, 0 }, - { 0x00000081, { "TP1 " }, 0 }, - { 0x00000081, { "TP2 " }, 0 }, - { 0x00000081, { "TK1 " }, 0 }, - { 0x00000081, { "TK2 " }, 0 }, - { 0x00000081, { "TR1 " }, 0 }, - { 0x00000081, { "TR2 " }, 0 }, - { 0x00000081, { "TQ1 " }, 0 }, - { 0x00000081, { "TQ2 " }, 0 }, - { 0x00000081, { "TWN " }, 0 }, - { 0x00000081, { "TCE " }, 0 }, - { 0x00000081, { "TCO " }, 0 }, - { 0x00000081, { "THL " }, 0 }, - { 0x00000081, { "TCC " }, 0 }, - { 0x00000081, { "TB1 " }, 0 }, - { 0x00000081, { "TB2 " }, 0 }, - { 0x00000081, { "TK3 " }, 0 }, - { 0x00000081, { "TK4 " }, 0 }, - { 0x00000081, { "TBN " }, 0 }, - { 0x00000081, { "TBN1 " }, 0 }, - { 0x00000081, { "TDT1 " }, 0 }, - { 0x00000081, { "TDT2 " }, 0 }, - { 0x00000081, { "TDT3 " }, 0 }, - { 0x00000081, { "TMM1 " }, 0 }, - { 0x00000081, { "TMM2 " }, 0 }, - { 0x00000081, { "TMM3 " }, 0 }, - { 0x00000081, { "TGS1 " }, 0 }, - { 0x00000081, { "TGS2 " }, 0 }, - { 0x00000081, { "TGS3 " }, 0 }, - { 0x00000081, { "TGS4 " }, 0 }, - { 0x00000081, { "TDN4 " }, 0 }, - { 0x00000081, { "TDN5 " }, 0 }, - { 0x00000081, { "TJT1 " }, 0 }, - { 0x00000081, { "TJT2 " }, 0 }, - { 0x00000081, { "TJB1 " }, 0 }, - { 0x00000081, { "TTF " }, 0 }, - { 0x00000081, { "TF1 " }, 0 }, - { 0x00000081, { "TF2 " }, 0 }, - { 0x00000081, { "TGE1 " }, 0 }, - { 0x00000081, { "TJT3 " }, 0 }, - { 0x00000081, { "TJT4 " }, 0 }, - { 0x00000081, { "TJP1 " }, 0 }, - { 0x00000081, { "TJB2 " }, 0 }, - { 0x00000081, { "TGE2 " }, 0 }, - { 0x00000081, { "TJT5 " }, 0 }, - { 0x00000081, { "TJB3 " }, 0 }, - { 0x00000081, { "TJB4 " }, 0 }, - { 0x00000081, { "TJT6 " }, 0 }, - { 0x00000081, { "TJP2 " }, 0 }, - { 0x00000081, { "TGE3 " }, 0 }, - { 0x00000081, { "TCK " }, 0 }, - { 0x00000081, { "TGE4 " }, 0 }, - { 0x00000081, { "TGE5 " }, 0 }, - { 0x00000081, { "TG15 " }, 0 }, - { 0x00000081, { "TG16 " }, 0 }, - { 0x00000081, { "TG17 " }, 0 }, - { 0x00000081, { "TG18 " }, 0 }, - { 0x00000081, { "TG19 " }, 0 }, - { 0x00000081, { "TG20 " }, 0 }, - { 0x00000081, { "TG21 " }, 0 }, - { 0x00000081, { "TSM " }, 0 }, - { 0x00000081, { "TIG " }, 0 }, - { 0x00000081, { "TCFS " }, 0 }, - { 0x00000081, { "TRFS " }, 0 }, - { 0x00000081, { "TRF3 " }, 0 }, - { 0x00000081, { "TNSS " }, 0 }, - { 0x00000081, { "TCT1 " }, 0 }, - { 0x00000081, { "TCT2 " }, 0 }, - { 0x00000081, { "TSF1 " }, 0 }, - { 0x00000081, { "TSF2 " }, 0 }, - { 0x00000081, { "TSF3 " }, 0 }, - { 0x00000081, { "TCN " }, 0 }, - { 0x00000081, { "TTG " }, 0 }, - { 0x00000081, { "TSNC " }, 0 }, - { 0x00000081, { "TSNB " }, 0 }, - { 0x00000081, { "TSCP " }, 0 }, - { 0x00000081, { "TCD " }, 0 }, - { 0x00000081, { "TSG " }, 0 }, - { 0x00000081, { "TSK " }, 0 }, - { 0x00000081, { "TGH1 " }, 0 }, - { 0x00000081, { "TGH2 " }, 0 }, - { 0x00000081, { "TSMP " }, 0 }, - { 0x00000081, { "TJF " }, 0 }, - { 0x00000081, { "TLY " }, 0 }, - { 0x00000081, { "TGC1 " }, 0 }, - { 0x00000081, { "TGC2 " }, 0 }, - { 0x00000081, { "TGG " }, 0 }, - { 0x00000081, { "TSPH " }, 0 }, - { 0x00000081, { "TOH1 " }, 0 }, - { 0x00000081, { "TOH2 " }, 0 }, - { 0x00000081, { "TOT1 " }, 0 }, - { 0x00000081, { "TOT2 " }, 0 }, - { 0x00000081, { "TOS " }, 0 }, - { 0x00000081, { "TOT3 " }, 0 }, - { 0x00000081, { "TOT4 " }, 0 }, - { 0x00000081, { "TSC2 " }, 0 }, - { 0x00000081, { "TSP1 " }, 0 }, - { 0x00000081, { "TOH3 " }, 0 }, - { 0x00000081, { "TSP2 " }, 0 }, - { 0x00000081, { "ROMROOF1" }, 0 }, - { 0x00000081, { "GEOROOF1" }, 0 }, - { 0x00000081, { "TNTROOF1" }, 0 }, - { 0x00000081, { "JNGROOF1" }, 0 }, - { 0x00000081, { "MINROOF1" }, 0 }, - { 0x00000081, { "ROMROOF2" }, 0 }, - { 0x00000081, { "GEOROOF2" }, 0 }, - { 0x00000081, { "PAGROOF1" }, 0 }, - { 0x00000081, { "SPCROOF1" }, 0 }, - { 0x00000081, { "ROOF1 " }, 0 }, - { 0x00000081, { "ROOF2 " }, 0 }, - { 0x00000081, { "ROOF3 " }, 0 }, - { 0x00000081, { "ROOF4 " }, 0 }, - { 0x00000081, { "ROOF5 " }, 0 }, - { 0x00000081, { "ROOF6 " }, 0 }, - { 0x00000081, { "ROOF7 " }, 0 }, - { 0x00000081, { "ROOF8 " }, 0 }, - { 0x00000081, { "ROOF9 " }, 0 }, - { 0x00000081, { "ROOF10 " }, 0 }, - { 0x00000081, { "ROOF11 " }, 0 }, - { 0x00000081, { "ROOF12 " }, 0 }, - { 0x00000081, { "ROOF13 " }, 0 }, - { 0x00000081, { "ROOF14 " }, 0 }, - { 0x00000081, { "IGROOF " }, 0 }, - { 0x00000081, { "CORROOF " }, 0 }, - { 0x00000081, { "CORROOF2" }, 0 } -}; - -static const rct_object_entry RCT1DefaultObjectsLargeScenery[] = { - { 0x00000082, { "SCOL " }, 0 }, - { 0x00000082, { "SHS1 " }, 0 }, - { 0x00000082, { "SSPX " }, 0 }, - { 0x00000082, { "SHS2 " }, 0 }, - { 0x00000082, { "SCLN " }, 0 }, - { 0x00000082, { "SMH1 " }, 0 }, - { 0x00000082, { "SMH2 " }, 0 }, - { 0x00000082, { "SVLC " }, 0 }, - { 0x00000082, { "SPYR " }, 0 }, - { 0x00000082, { "SMN1 " }, 0 }, - { 0x00000082, { "SMB " }, 0 }, - { 0x00000082, { "SSK1 " }, 0 }, - { 0x00000082, { "SDN1 " }, 0 }, - { 0x00000082, { "SDN2 " }, 0 }, - { 0x00000082, { "SDN3 " }, 0 }, - { 0x00000082, { "SIP " }, 0 }, - { 0x00000082, { "STB1 " }, 0 }, - { 0x00000082, { "STB2 " }, 0 }, - { 0x00000082, { "STG1 " }, 0 }, - { 0x00000082, { "STG2 " }, 0 }, - { 0x00000082, { "SCT " }, 0 }, - { 0x00000082, { "SOH1 " }, 0 }, - { 0x00000082, { "SOH2 " }, 0 }, - { 0x00000082, { "SOH3 " }, 0 }, - { 0x00000082, { "SGP " }, 0 }, - { 0x00000082, { "SSR " }, 0 }, - { 0x00000082, { "STH " }, 0 }, - { 0x00000082, { "SAH " }, 0 }, - { 0x00000082, { "SPS " }, 0 }, - { 0x00000082, { "SPG " }, 0 }, - { 0x00000082, { "SOB " }, 0 }, - { 0x00000082, { "SAH2 " }, 0 }, - { 0x00000082, { "SST " }, 0 }, - { 0x00000082, { "SSH " }, 0 }, - { 0x00000082, { "SAH3 " }, 0 }, - { 0x00000082, { "SSIG1 " }, 0 }, - { 0x00000082, { "SSIG2 " }, 0 }, - { 0x00000082, { "SSIG3 " }, 0 }, - { 0x00000082, { "SSIG4 " }, 0 } -}; - -static const rct_object_entry RCT1DefaultObjectsWall[] = { - { 0x00000083, { "WMF " }, 0 }, - { 0x00000083, { "WMFG " }, 0 }, - { 0x00000083, { "WRW " }, 0 }, - { 0x00000083, { "WEW " }, 0 }, - { 0x00000083, { "WHG " }, 0 }, - { 0x00000083, { "WHGG " }, 0 }, - { 0x00000083, { "WCW1 " }, 0 }, - { 0x00000083, { "WCW2 " }, 0 }, - { 0x00000083, { "WSW " }, 0 }, - { 0x00000083, { "WSWG " }, 0 }, - { 0x00000083, { "WMW " }, 0 }, - { 0x00000083, { "WALLGL16" }, 0 }, - { 0x00000083, { "WFW1 " }, 0 }, - { 0x00000083, { "WFWG " }, 0 }, - { 0x00000083, { "WPW1 " }, 0 }, - { 0x00000083, { "WPW2 " }, 0 }, - { 0x00000083, { "WPF " }, 0 }, - { 0x00000083, { "WPFG " }, 0 }, - { 0x00000083, { "WWTW " }, 0 }, - { 0x00000083, { "WMWW " }, 0 }, - { 0x00000083, { "WSW1 " }, 0 }, - { 0x00000083, { "WSW2 " }, 0 }, - { 0x00000083, { "WGW2 " }, 0 }, - { 0x00000083, { "WBW " }, 0 }, - { 0x00000083, { "WBR1 " }, 0 }, - { 0x00000083, { "WBRG " }, 0 }, - { 0x00000083, { "WALLCFAR" }, 0 }, // Slot taken by white wooden fence in RCT1 - { 0x00000083, { "WALLPOST" }, 0 }, // Slot taken by red wooden fence in RCT1 - { 0x00000083, { "WBR2 " }, 0 }, - { 0x00000083, { "WBR3 " }, 0 }, - { 0x00000083, { "WPW3 " }, 0 }, - { 0x00000083, { "WJF " }, 0 }, - { 0x00000083, { "WCH " }, 0 }, - { 0x00000083, { "WCHG " }, 0 }, - { 0x00000083, { "WC1 " }, 0 }, - { 0x00000083, { "WC2 " }, 0 }, - { 0x00000083, { "WC3 " }, 0 }, - { 0x00000083, { "WC4 " }, 0 }, - { 0x00000083, { "WC5 " }, 0 }, - { 0x00000083, { "WC6 " }, 0 }, - { 0x00000083, { "WC7 " }, 0 }, - { 0x00000083, { "WC8 " }, 0 }, - { 0x00000083, { "WC9 " }, 0 }, - { 0x00000083, { "WC10 " }, 0 }, - { 0x00000083, { "WC11 " }, 0 }, - { 0x00000083, { "WC12 " }, 0 }, - { 0x00000083, { "WC13 " }, 0 }, - { 0x00000083, { "WC14 " }, 0 }, - { 0x00000083, { "WC15 " }, 0 }, - { 0x00000083, { "WC16 " }, 0 }, - { 0x00000083, { "WC17 " }, 0 }, - { 0x00000083, { "WC18 " }, 0 }, - { 0x00000083, { "WALLBRDR" }, 0 }, - { 0x00000083, { "WALLBR32" }, 0 }, - { 0x00000083, { "WALLBR16" }, 0 }, - { 0x00000083, { "WALLBR8 " }, 0 }, - { 0x00000083, { "WALLCF8 " }, 0 }, - { 0x00000083, { "WALLCF16" }, 0 }, - { 0x00000083, { "WALLCF32" }, 0 }, - { 0x00000083, { "WALLBB8 " }, 0 }, - { 0x00000083, { "WALLBB16" }, 0 }, - { 0x00000083, { "WALLBB32" }, 0 }, - { 0x00000083, { "WALLRS8 " }, 0 }, - { 0x00000083, { "WALLRS16" }, 0 }, - { 0x00000083, { "WALLRS32" }, 0 }, - { 0x00000083, { "WALLCB8 " }, 0 }, - { 0x00000083, { "WALLCB16" }, 0 }, - { 0x00000083, { "WALLCB32" }, 0 }, - { 0x00000083, { "WALLGL8 " }, 0 }, - { 0x00000083, { "WALLGL32" }, 0 }, - { 0x00000083, { "WALLWD8 " }, 0 }, - { 0x00000083, { "WALLWD16" }, 0 }, - { 0x00000083, { "WALLWD32" }, 0 }, - { 0x00000083, { "WALLTN32" }, 0 }, - { 0x00000083, { "WALLJN32" }, 0 }, - { 0x00000083, { "WALLMN32" }, 0 }, - { 0x00000083, { "WALLSP32" }, 0 }, - { 0x00000083, { "WALLPG32" }, 0 }, - { 0x00000083, { "WALLU132" }, 0 }, - { 0x00000083, { "WALLU232" }, 0 }, - { 0x00000083, { "WALLCZ32" }, 0 }, - { 0x00000083, { "WALLCW32" }, 0 }, - { 0x00000083, { "WALLCY32" }, 0 }, - { 0x00000083, { "WALLCX32" }, 0 }, - { 0x00000083, { "WBR1A " }, 0 }, - { 0x00000083, { "WBR2A " }, 0 }, - { 0x00000083, { "WRWA " }, 0 }, - { 0x00000083, { "WWTWA " }, 0 }, - { 0x00000083, { "WALLIG16" }, 0 }, - { 0x00000083, { "WALLIG24" }, 0 }, - { 0x00000083, { "WALLCO16" }, 0 }, - { 0x00000083, { "WALLCFDR" }, 0 }, - { 0x00000083, { "WALLCBDR" }, 0 }, - { 0x00000083, { "WALLBRWN" }, 0 }, - { 0x00000083, { "WALLCFWN" }, 0 }, - { 0x00000083, { "WALLCBWN" }, 0 } -}; - -static const rct_object_entry RCT1DefaultObjectsBanner[] = { - { 0x00000084, { "BN1 " }, 0 }, - { 0x00000084, { "BN2 " }, 0 }, - { 0x00000084, { "BN3 " }, 0 }, - { 0x00000084, { "BN4 " }, 0 }, - { 0x00000084, { "BN5 " }, 0 }, - { 0x00000084, { "BN6 " }, 0 }, - { 0x00000084, { "BN7 " }, 0 }, - { 0x00000084, { "BN8 " }, 0 }, - { 0x00000084, { "BN9 " }, 0 } -}; - -static const rct_object_entry RCT1DefaultObjectsPath[] = { - { 0x00000085, { "TARMAC " }, 0 }, - { 0x00000085, { "TARMACB " }, 0 }, - { 0x00000085, { "PATHSPCE" }, 0 }, - { 0x00000085, { "PATHDIRT" }, 0 }, - { 0x00000085, { "ROAD " }, 0 }, - { 0x00000085, { "PATHCRZY" }, 0 }, - { 0x00000085, { "PATHASH " }, 0 } -}; - -static const rct_object_entry RCT1DefaultObjectsPathBits[] = { - { 0x00000086, { "LAMP1 " }, 0 }, - { 0x00000086, { "LAMP2 " }, 0 }, - { 0x00000086, { "LITTER1 " }, 0 }, - { 0x00000086, { "BENCH1 " }, 0 }, - { 0x00000086, { "JUMPFNT1" }, 0 }, - { 0x00000086, { "LAMP3 " }, 0 }, - { 0x00000086, { "LAMP4 " }, 0 }, - { 0x00000086, { "JUMPSNW1" }, 0 } -}; - -static const rct_object_entry RCT1DefaultObjectsSceneryGroup[] = { - { 0x00000087, { "SCGTREES" }, 0 }, - { 0x00000087, { "SCGSHRUB" }, 0 }, - { 0x00000087, { "SCGGARDN" }, 0 }, - { 0x00000087, { "SCGPATHX" }, 0 }, - { 0x00000087, { "SCGFENCE" }, 0 }, - { 0x00000087, { "SCGMART " }, 0 }, - { 0x00000087, { "SCGWOND " }, 0 }, - { 0x00000087, { "SCGSNOW " }, 0 }, - { 0x00000087, { "SCGWALLS" }, 0 } -}; - -static const rct_object_entry RCT1DefaultObjectsParkEntrance[] = { - { 0x00000088, { "PKENT1 " }, 0 } -}; - -static const rct_object_entry RCT1DefaultObjectsWater[] = { - { 0x00000089, { "WTRCYAN " }, 0 }, - { 0x00000089, { "WTRORNG " }, 0 } -}; - -static const RCT1DefaultObjectsGroup RCT1DefaultObjects[10] = { - { RCT1DefaultObjectsRides, countof(RCT1DefaultObjectsRides) }, - { RCT1DefaultObjectsSmallScenery, countof(RCT1DefaultObjectsSmallScenery) }, - { RCT1DefaultObjectsLargeScenery, countof(RCT1DefaultObjectsLargeScenery) }, - { RCT1DefaultObjectsWall, countof(RCT1DefaultObjectsWall) }, - { RCT1DefaultObjectsBanner, countof(RCT1DefaultObjectsBanner) }, - { RCT1DefaultObjectsPath, countof(RCT1DefaultObjectsPath) }, - { RCT1DefaultObjectsPathBits, countof(RCT1DefaultObjectsPathBits) }, - { RCT1DefaultObjectsSceneryGroup, countof(RCT1DefaultObjectsSceneryGroup) }, - { RCT1DefaultObjectsParkEntrance, countof(RCT1DefaultObjectsParkEntrance) }, - { RCT1DefaultObjectsWater, countof(RCT1DefaultObjectsWater) } -}; - -// Keep these in the same order as gVehicleHierarchies -const char *SpiralRCObjectOrder[] = { "SPDRCR "}; -const char *StandupRCObjectOrder[] = { "TOGST "}; -const char *SuspendedSWRCObjectOrder[] = { "ARRSW1 ", "VEKVAMP ", "ARRSW2 "}; -const char *InvertedRCObjectOrder[] = { "NEMT "}; -const char *JuniorCoasterObjectOrder[] = { "ZLDB ", "ZLOG "}; -const char *MiniatureRailwayObjectOrder[] = { "NRL ", "NRL2 ", "AML1 ", "TRAM1 "}; -const char *MonorailObjectOrder[] = { "MONO1 ", "MONO2 ", "MONO3 "}; -const char *MiniSuspendedRCObjectOrder[] = { "BATFL ", "SKYTR "}; -const char *BoatRideObjectOrder[] = { "RBOAT ", "BBOAT ", "CBOAT ", "SWANS ", "TRIKE ","JSKI "}; -const char *WoodenWMObjectOrder[] = { "WMOUSE ", "WMMINE "}; -const char *SteeplechaseObjectOrder[] = { "STEEP1 ", "STEEP2 ", "SBOX "}; -const char *CarRideObjectOrder[] = { "SPCAR ", "RCR ", "TRUCK1 ", "VCR ", "CTCAR "}; -const char *LaunchedFFObjectOrder[] = { "SSC1 "}; -const char *BobsleighRCObjectOrder[] = { "BOB1 ", "INTBOB "}; -const char *ObservationTowerObjectOrder[] = { "OBS1 ", "OBS2 "}; -const char *LoopingRCObjectOrder[] = { "SCHT1 "}; -const char *DinghySlideObjectOrder[] = { "DING1 "}; -const char *MineTrainRCObjectOrder[] = { "AMT1 "}; -const char *ChairliftObjectOrder[] = { "CLIFT1 ", "CLIFT2 "}; -const char *CorkscrewRCObjectOrder[] = { "ARRT1 ", "ARRT2 "}; -const char *GoKartsObjectOrder[] = { "KART1 "}; -const char *LogFlumeObjectOrder[] = { "LFB1 "}; -const char *RiverRapidsObjectOrder[] = { "RAPBOAT "}; -const char *ReverseFreefallRCObjectOrder[] = { "REVF1 "}; -const char *LiftObjectOrder[] = { "LIFT1 "}; -const char *VerticalDropRCObjectOrder[] = { "BMVD "}; -const char *GhostTrainObjectOrder[] = { "GTC ", "HMCAR "}; -const char *TwisterRCObjectOrder[] = { "BMSD ", "BMSU ", "BMFL ", "BMRB ", "GOLTR "}; -const char *WoodenRCObjectOrder[] = { "PTCT1 ", "MFT ", "PTCT2 "}; -const char *SideFrictionRCObjectOrder[] = { "SFRIC1 "}; -const char *SteelWildMouseObjectOrder[] = { "SMC1 ", "SMC2 ", "WMSPIN "}; -const char *MultiDimensionRCObjectOrder[] = { "ARRX "}; -const char *FlyingRCObjectOrder[] = { "BMAIR "}; -const char *VirginiaReelRCObjectOrder[] = { "VREEL "}; -const char *SplashBoatsObjectOrder[] = { "SPBOAT "}; -const char *MiniHelicoptersObjectOrder[] = { "HELICAR "}; -const char *LayDownRCObjectOrder[] = { "VEKST "}; -const char *SuspendedMonorailObjectOrder[] = { "SMONO "}; -const char *ReverserRCObjectOrder[] = { "REVCAR "}; -const char *HeartlineTwisterObjectOrder[] = { "UTCAR ", "UTCARR "}; -const char *GigaRCObjectOrder[] = { "INTST "}; -const char *RotoDropObjectOrder[] = { "GDROP1 "}; -const char *MonorailCyclesObjectOrder[] = { "MONBK "}; -const char *CompactInvertedRCObjectOrder[] = { "SLCT ", "SLCFO ", "VEKDV "}; -const char *WaterRCObjectOrder[] = { "CSTBOAT "}; -const char *AirPoweredRCObjectOrder[] = { "THCAR "}; -const char *InvertedHairpinRCObjectOrder[] = { "IVMC1 "}; -const char *SubmarineRideObjectOrder[] = { "SUBMAR "}; -const char *RiverRaftsObjectOrder[] = { "RFTBOAT "}; -const char *InvertedImpulseRCObjectOrder[] = { "INTINV "}; -const char *MiniRCObjectOrder[] = { "WCATC ", "RCKC ", "JSTAR1 "}; -const char *MineRideRCObjectOrder[] = { "PMT1 "}; -const char *LIMLaunchedRCObjectOrder[] = { "PREMT1 "}; - -typedef struct { - const char **entries; - int count; -} RCT1VehicleHierarchiesGroup; - -RCT1VehicleHierarchiesGroup gVehicleHierarchies[0x60] = { - { SpiralRCObjectOrder, countof(SpiralRCObjectOrder) }, // 0 Spiral Roller coaster - { StandupRCObjectOrder, countof(StandupRCObjectOrder) }, // 1 Stand Up Coaster - { SuspendedSWRCObjectOrder, countof(SuspendedSWRCObjectOrder) }, // 2 Suspended Swinging - { InvertedRCObjectOrder, countof(InvertedRCObjectOrder) }, // 3 Inverted - { JuniorCoasterObjectOrder, countof(JuniorCoasterObjectOrder) }, // 4 Junior RC / Steel Mini Coaster - { MiniatureRailwayObjectOrder, countof(MiniatureRailwayObjectOrder) }, // 5 Mini Railroad - { MonorailObjectOrder, countof(MonorailObjectOrder) }, // 6 Monorail - { MiniSuspendedRCObjectOrder, countof(MiniSuspendedRCObjectOrder) }, // 7 Mini Suspended Coaster - { BoatRideObjectOrder, countof(BoatRideObjectOrder) }, // 8 Boat ride - { WoodenWMObjectOrder, countof(WoodenWMObjectOrder) }, // 9 Wooden Wild Mine/Mouse - { SteeplechaseObjectOrder, countof(SteeplechaseObjectOrder) }, // a Steeplechase/Motorbike/Soap Box Derby - { CarRideObjectOrder, countof(CarRideObjectOrder) }, // b Car Ride - { LaunchedFFObjectOrder, countof(LaunchedFFObjectOrder) }, // c Launched Freefall - { BobsleighRCObjectOrder, countof(BobsleighRCObjectOrder) }, // d Bobsleigh Coaster - { ObservationTowerObjectOrder, countof(ObservationTowerObjectOrder) }, // e Observation Tower - { LoopingRCObjectOrder, countof(LoopingRCObjectOrder) }, // f Looping Roller Coaster - { DinghySlideObjectOrder, countof(DinghySlideObjectOrder) }, // 10 Dinghy Slide - { MineTrainRCObjectOrder, countof(MineTrainRCObjectOrder) }, // 11 Mine Train Coaster - { ChairliftObjectOrder, countof(ChairliftObjectOrder) }, // 12 Chairlift - { CorkscrewRCObjectOrder, countof(CorkscrewRCObjectOrder) }, // 13 Corkscrew Roller Coaster - { NULL, 0 }, // 14 Maze, N/A - { NULL, 0 }, // 15 Spiral Slide, N/A - { GoKartsObjectOrder, countof(GoKartsObjectOrder) }, // 16 Go Karts - { LogFlumeObjectOrder, countof(LogFlumeObjectOrder) }, // 17 Log Flume - { RiverRapidsObjectOrder, countof(RiverRapidsObjectOrder) }, // 18 River Rapids - { NULL, 0 }, // 19 Dodgems, N/A - { NULL, 0 }, // 1a Pirate Ship, N/A - { NULL, 0 }, // 1b Swinging Inverter Ship, N/A - { NULL, 0 }, // 1c Food Stall, N/A - { NULL, 0 }, // 1d (none), N/A - { NULL, 0 }, // 1e Drink Stall, N/A - { NULL, 0 }, // 1f (none), N/A - { NULL, 0 }, // 20 Shop (all types), N/A - { NULL, 0 }, // 21 Merry Go Round, N/A - { NULL, 0 }, // 22 Balloon Stall (maybe), N/A - { NULL, 0 }, // 23 Information Kiosk, N/A - { NULL, 0 }, // 24 Bathroom, N/A - { NULL, 0 }, // 25 Ferris Wheel, N/A - { NULL, 0 }, // 26 Motion Simulator, N/A - { NULL, 0 }, // 27 3D Cinema, N/A - { NULL, 0 }, // 28 Top Spin, N/A - { NULL, 0 }, // 29 Space Rings, N/A - { ReverseFreefallRCObjectOrder, countof(ReverseFreefallRCObjectOrder) }, // 2a Reverse Freefall Coaster - { LiftObjectOrder, countof(LiftObjectOrder) }, // 2b Lift - { VerticalDropRCObjectOrder, countof(VerticalDropRCObjectOrder) }, // 2c Vertical Drop Roller Coaster - { NULL, 0 }, // 2d ATM, N/A - { NULL, 0 }, // 2e Twist, N/A - { NULL, 0 }, // 2f Haunted House, N/A - { NULL, 0 }, // 30 First Aid, N/A - { NULL, 0 }, // 31 Circus Show, N/A - { GhostTrainObjectOrder, countof(GhostTrainObjectOrder) }, // 32 Ghost Train - { TwisterRCObjectOrder, countof(TwisterRCObjectOrder) }, // 33 Twister Roller Coaster - { WoodenRCObjectOrder, countof(WoodenRCObjectOrder) }, // 34 Wooden Roller Coaster - { SideFrictionRCObjectOrder, countof(SideFrictionRCObjectOrder) }, // 35 Side-Friction Roller Coaster - { SteelWildMouseObjectOrder, countof(SteelWildMouseObjectOrder) }, // 36 Steel Wild Mouse - { MultiDimensionRCObjectOrder, countof(MultiDimensionRCObjectOrder) }, // 37 Multi Dimension Coaster - { NULL, 0 }, // 38 (none), N/A - { FlyingRCObjectOrder, countof(FlyingRCObjectOrder) }, // 39 Flying Roller Coaster - { NULL, 0 }, // 3a (none), N/A - { VirginiaReelRCObjectOrder, countof(VirginiaReelRCObjectOrder) }, // 3b Virginia Reel - { SplashBoatsObjectOrder, countof(SplashBoatsObjectOrder) }, // 3c Splash Boats - { MiniHelicoptersObjectOrder, countof(MiniHelicoptersObjectOrder) }, // 3d Mini Helicopters - { LayDownRCObjectOrder, countof(LayDownRCObjectOrder) }, // 3e Lay-down Roller Coaster - { SuspendedMonorailObjectOrder, countof(SuspendedMonorailObjectOrder) }, // 3f Suspended Monorail - { NULL, 0 }, // 40 (none), N/A - { ReverserRCObjectOrder, countof(ReverserRCObjectOrder) }, // 41 Reverser Roller Coaster - { HeartlineTwisterObjectOrder, countof(HeartlineTwisterObjectOrder) }, // 42 Heartline Twister Roller Coaster - { NULL, 0 }, // 43 Mini Golf, N/A - { GigaRCObjectOrder, countof(GigaRCObjectOrder) }, // 44 Giga Coaster - { RotoDropObjectOrder, countof(RotoDropObjectOrder) }, // 45 Roto-Drop - { NULL, 0 }, // 46 Flying Saucers, N/A - { NULL, 0 }, // 47 Crooked House, N/A - { MonorailCyclesObjectOrder, countof(MonorailCyclesObjectOrder) }, // 48 Monorail Cycles - { CompactInvertedRCObjectOrder, countof(CompactInvertedRCObjectOrder) }, // 49 Compact Inverted Coaster - { WaterRCObjectOrder, countof(WaterRCObjectOrder) }, // 4a Water Coaster - { AirPoweredRCObjectOrder, countof(AirPoweredRCObjectOrder) }, // 4b Air Powered Vertical Coaster - { InvertedHairpinRCObjectOrder, countof(InvertedHairpinRCObjectOrder) }, // 4c Inverted Hairpin Coaster - { NULL, 0 }, // 4d Magic Carpet, N/A - { SubmarineRideObjectOrder, countof(SubmarineRideObjectOrder) }, // 4e Submarine Ride - { RiverRaftsObjectOrder, countof(RiverRaftsObjectOrder) }, // 4f River Rafts - { NULL, 0 }, // 50 (none), N/A - { NULL, 0 }, // 51 Enterprise, N/A - { NULL, 0 }, // 52 (none), N/A - { NULL, 0 }, // 53 (none), N/A - { NULL, 0 }, // 54 (none), N/A - { NULL, 0 }, // 55 (none), N/A - { InvertedImpulseRCObjectOrder, countof(InvertedImpulseRCObjectOrder) }, // 56 Inverted Impulse Coaster - { MiniRCObjectOrder, countof(MiniRCObjectOrder) }, // 57 Mini Roller Coaster - { MineRideRCObjectOrder, countof(MineRideRCObjectOrder) }, // 58 Mine Ride - { NULL, 0 }, // 59 Unknown Ride - { LIMLaunchedRCObjectOrder, countof(LIMLaunchedRCObjectOrder) }, // 60 LIM Launched Roller Coaster -}; - -const uint8 gRideCategories[0x60] = { - 2, // Spiral Roller coaster - 2, // Stand Up Coaster - 2, // Suspended Swinging - 2, // Inverted - 2, // Steel Mini Coaster - 0, // Mini Railroad - 0, // Monorail - 2, // Mini Suspended Coaster - 4, // Boat ride - 2, // Wooden Wild Mine/Mouse - 2, // Steeplechase/Motorbike/Soap Box Derby - 1, // Car Ride - 3, // Launched Freefall - 2, // Bobsleigh Coaster - 1, // Observation Tower - 2, // Looping Roller Coaster - 4, // Dinghy Slide - 2, // Mine Train Coaster - 0, // Chairlift - 2, // Corkscrew Roller Coaster - 1, // Maze - 1, // Spiral Slide - 3, // Go Karts - 4, // Log Flume - 4, // River Rapids - 1, // Dodgems - 3, // Pirate Ship - 3, // Swinging Inverter Ship - 5, // Food Stall - 255, // (none) - 5, // Drink Stall - 255, // (none) - 5, // Shop (all types) - 1, // Merry Go Round - 5, // Balloon Stall (maybe) - 5, // Information Kiosk - 5, // Bathroom - 1, // Ferris Wheel - 3, // Motion Simulator - 3, // 3D Cinema - 3, // Top Spin - 1, // Space Rings - 2, // Reverse Freefall Coaster - 0, // Elevator - 2, // Vertical Drop Roller Coaster - 5, // ATM - 3, // Twist - 1, // Haunted House - 5, // First Aid - 1, // Circus Show - 1, // Ghost Train - 2, // Twister Roller Coaster - 2, // Wooden Roller Coaster - 2, // Side-Friction Roller Coaster - 2, // Wild Mouse - 2, // Multi Dimension Coaster - 255, // (none) - 2, // Flying Roller Coaster - 255, // (none) - 2, // Virginia Reel - 4, // Splash Boats - 1, // Mini Helicopters - 2, // Lay-down Roller Coaster - 0, // Suspended Monorail - 255, // (none) - 2, // Reverser Roller Coaster - 2, // Heartline Twister Roller Coaster - 1, // Mini Golf - 2, // Giga Coaster - 3, // Roto-Drop - 1, // Flying Saucers - 1, // Crooked House - 1, // Monorail Cycles - 2, // Compact Inverted Coaster - 2, // Water Coaster - 2, // Air Powered Vertical Coaster - 2, // Inverted Hairpin Coaster - 3, // Magic Carpet - 4, // Submarine Ride - 4, // River Rafts - 255, // (none) - 3, // Enterprise - 255, // (none) - 255, // (none) - 255, // (none) - 255, // (none) - 2, // Inverted Impulse Coaster - 2, // Mini Roller Coaster - 2, // Mine Ride - 255, //59 Unknown Ride - 2 // LIM Launched Roller Coaster -}; - -/* This function keeps a list of the preferred vehicle for every generic track type, out of the available vehicle types in the current game. - It determines which picture is shown on the new ride tab and which train type is selected by default.*/ -bool vehicleIsHigherInHierarchy(int track_type, char *currentVehicleName, char *comparedVehicleName) -{ - if(currentVehicleName==NULL || comparedVehicleName==NULL || gVehicleHierarchies[track_type].entries==NULL) { + if (!gConfigInterface.select_by_track_type) { return false; } - int currentVehicleHierarchy; - int comparedVehicleHierarchy; - - currentVehicleHierarchy=255; - comparedVehicleHierarchy=255; - - for(int i = 0; i < gVehicleHierarchies[track_type].count; i++) { - if(gVehicleHierarchies[track_type].entries[i]==NULL) - continue; - - if(strcmp(comparedVehicleName,gVehicleHierarchies[track_type].entries[i])==0) - comparedVehicleHierarchy=i; - - if(strcmp(currentVehicleName,gVehicleHierarchies[track_type].entries[i])==0) - currentVehicleHierarchy=i; - } - - if(comparedVehicleHierarchyride_type[j], RIDE_TYPE_FLAG_FLAT_RIDE)) - remove_flag=false; - if(ride->ride_type[j]==RIDE_TYPE_MAZE || ride->ride_type[j]==RIDE_TYPE_MINI_GOLF) - remove_flag=false; + bool remove_flag = true; + for (int j = 0; j < 3; j++) { + if (ride_type_has_flag(rideEntry->ride_type[j], RIDE_TYPE_FLAG_FLAT_RIDE)) { + remove_flag = false; + } + if (rideEntry->ride_type[j] == RIDE_TYPE_MAZE || rideEntry->ride_type[j] == RIDE_TYPE_MINI_GOLF) { + remove_flag = false; + } } return remove_flag; } -#pragma endregion +const uint8 gRideCategories[] = { + 2, // Spiral Roller coaster + 2, // Stand Up Coaster + 2, // Suspended Swinging + 2, // Inverted + 2, // Steel Mini Coaster + 0, // Mini Railroad + 0, // Monorail + 2, // Mini Suspended Coaster + 4, // Boat ride + 2, // Wooden Wild Mine/Mouse + 2, // Steeplechase/Motorbike/Soap Box Derby + 1, // Car Ride + 3, // Launched Freefall + 2, // Bobsleigh Coaster + 1, // Observation Tower + 2, // Looping Roller Coaster + 4, // Dinghy Slide + 2, // Mine Train Coaster + 0, // Chairlift + 2, // Corkscrew Roller Coaster + 1, // Maze + 1, // Spiral Slide + 3, // Go Karts + 4, // Log Flume + 4, // River Rapids + 1, // Dodgems + 3, // Pirate Ship + 3, // Swinging Inverter Ship + 5, // Food Stall + 255, // (none) + 5, // Drink Stall + 255, // (none) + 5, // Shop (all types) + 1, // Merry Go Round + 5, // Balloon Stall (maybe) + 5, // Information Kiosk + 5, // Bathroom + 1, // Ferris Wheel + 3, // Motion Simulator + 3, // 3D Cinema + 3, // Top Spin + 1, // Space Rings + 2, // Reverse Freefall Coaster + 0, // Elevator + 2, // Vertical Drop Roller Coaster + 5, // ATM + 3, // Twist + 1, // Haunted House + 5, // First Aid + 1, // Circus Show + 1, // Ghost Train + 2, // Twister Roller Coaster + 2, // Wooden Roller Coaster + 2, // Side-Friction Roller Coaster + 2, // Wild Mouse + 2, // Multi Dimension Coaster + 255, // (none) + 2, // Flying Roller Coaster + 255, // (none) + 2, // Virginia Reel + 4, // Splash Boats + 1, // Mini Helicopters + 2, // Lay-down Roller Coaster + 0, // Suspended Monorail + 255, // (none) + 2, // Reverser Roller Coaster + 2, // Heartline Twister Roller Coaster + 1, // Mini Golf + 2, // Giga Coaster + 3, // Roto-Drop + 1, // Flying Saucers + 1, // Crooked House + 1, // Monorail Cycles + 2, // Compact Inverted Coaster + 2, // Water Coaster + 2, // Air Powered Vertical Coaster + 2, // Inverted Hairpin Coaster + 3, // Magic Carpet + 4, // Submarine Ride + 4, // River Rafts + 255, // (none) + 3, // Enterprise + 255, // (none) + 255, // (none) + 255, // (none) + 255, // (none) + 2, // Inverted Impulse Coaster + 2, // Mini Roller Coaster + 2, // Mine Ride + 255, //59 Unknown Ride + 2 // LIM Launched Roller Coaster +}; diff --git a/src/rct1.h b/src/rct1.h index 0307647a52..39fb4768b7 100644 --- a/src/rct1.h +++ b/src/rct1.h @@ -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 diff --git a/src/rct1/S4Importer.cpp b/src/rct1/S4Importer.cpp new file mode 100644 index 0000000000..ac654b2311 --- /dev/null +++ b/src/rct1/S4Importer.cpp @@ -0,0 +1,1577 @@ +#include "S4Importer.h" + +#include "../core/Exception.hpp" +#include "../core/Guard.hpp" +#include "../core/List.hpp" +#include "../core/Path.hpp" +#include "../core/String.hpp" +#include "../core/Util.hpp" +#include "Tables.h" + +extern "C" +{ + #include "../audio/audio.h" + #include "../cheats.h" + #include "../game.h" + #include "../interface/window.h" + #include "../localisation/date.h" + #include "../localisation/localisation.h" + #include "../management/finance.h" + #include "../management/marketing.h" + #include "../object.h" + #include "../peep/staff.h" + #include "../rct1.h" + #include "../util/sawyercoding.h" + #include "../util/util.h" + #include "../world/footpath.h" + #include "../world/map_animation.h" + #include "../world/park.h" + #include "../world/scenery.h" +} + +static bool ObjectNameComparer(const char * a, const char * b) +{ + return String::Equals(a, b, true); +} + +void S4Importer::LoadSavedGame(const utf8 * path) +{ + if (!rct1_read_sv4(path, &_s4)) { + throw Exception("Unable to load SV4."); + } + _s4Path = path; +} + +void S4Importer::LoadScenario(const utf8 * path) +{ + if (!rct1_read_sc4(path, &_s4)) { + throw Exception("Unable to load SC4."); + } + _s4Path = path; +} + +void S4Importer::Import() +{ + Initialise(); + + CreateAvailableObjectMappings(); + LoadObjects(); + + ImportRides(); + ImportRideMeasurements(); + ImportMapElements(); + ImportMapAnimations(); + ImportPeepSpawns(); + ImportFinance(); + ImportResearch(); + ImportParkName(); + ImportParkFlags(); + ImportClimate(); + ImportScenarioNameDetails(); + ImportScenarioObjective(); + ImportSavedView(); + + game_convert_strings_to_utf8(); +} + +void S4Importer::Initialise() +{ + _gameVersion = sawyercoding_detect_rct1_version(_s4.game_version) & FILE_VERSION_MASK; + + Memory::Set(_rideTypeToRideEntryMap, 255, sizeof(_rideTypeToRideEntryMap)); + Memory::Set(_vehicleTypeToRideEntryMap, 255, sizeof(_vehicleTypeToRideEntryMap)); + Memory::Set(_smallSceneryTypeToEntryMap, 255, sizeof(_smallSceneryTypeToEntryMap)); + Memory::Set(_largeSceneryTypeToEntryMap, 255, sizeof(_largeSceneryTypeToEntryMap)); + Memory::Set(_wallTypeToEntryMap, 255, sizeof(_wallTypeToEntryMap)); + Memory::Set(_pathTypeToEntryMap, 255, sizeof(_pathTypeToEntryMap)); + Memory::Set(_pathAdditionTypeToEntryMap, 255, sizeof(_pathAdditionTypeToEntryMap)); + Memory::Set(_sceneryThemeTypeToEntryMap, 255, sizeof(_sceneryThemeTypeToEntryMap)); + + uint16 mapSize = _s4.map_size == 0 ? 128 : _s4.map_size; + + // Do map initialisation, same kind of stuff done when loading scenario editor + audio_pause_sounds(); + audio_unpause_sounds(); + object_unload_all(); + map_init(mapSize); + banner_init(); + reset_park_entrances(); + user_string_clear_all(); + reset_sprite_list(); + ride_init_all(); + window_guest_list_init_vars_a(); + staff_reset_modes(); + park_init(); + finance_init(); + date_reset(); + window_guest_list_init_vars_b(); + window_staff_list_init_vars(); + RCT2_GLOBAL(0x0141F570, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; + window_new_ride_init_vars(); + RCT2_GLOBAL(0x0141F571, uint8) = 4; + news_item_init_queue(); +} + +void S4Importer::CreateAvailableObjectMappings() +{ + AddDefaultEntries(); + AddAvailableEntriesFromResearchList(); + AddAvailableEntriesFromMap(); + AddAvailableEntriesFromRides(); + AddAvailableEntriesFromSceneryGroups(); +} + +void S4Importer::AddDefaultEntries() +{ + // Add default scenery groups + _sceneryGroupEntries.AddRange({ + "SCGTREES", + "SCGSHRUB", + "SCGGARDN", + "SCGFENCE", + "SCGWALLS", + "SCGPATHX", + }); + + // Add default footpaths + _pathEntries.AddRange({ + "TARMAC ", + "TARMACG ", + "TARMACB ", + "PATHCRZY", + "PATHSPCE", + "PATHDIRT", + "PATHASH ", + "ROAD ", + }); +} + +void S4Importer::AddAvailableEntriesFromResearchList() +{ + size_t researchListCount; + const rct1_research_item * researchList = GetResearchList(&researchListCount); + for (size_t i = 0; i < researchListCount; i++) + { + const rct1_research_item * researchItem = &researchList[i]; + if (researchItem->item == RCT1_RESEARCH_END_RESEARCHABLE || + researchItem->item == RCT1_RESEARCH_END) + { + break; + } + if (researchItem->item == RCT1_RESEARCH_END_AVAILABLE) + { + continue; + } + + switch (researchItem->category) { + case RCT1_RESEARCH_CATEGORY_THEME: + AddEntriesForSceneryTheme(researchItem->item); + break; + case RCT1_RESEARCH_CATEGORY_RIDE: + { + uint8 rideType = researchItem->item; + + // Add all vehicles for this ride type + uint32 numVehicles = 0; + for (size_t j = 0; j < researchListCount; j++) + { + const rct1_research_item *researchItem2 = &researchList[j]; + if (researchItem2->item == RCT1_RESEARCH_END_RESEARCHABLE || + researchItem2->item == RCT1_RESEARCH_END_AVAILABLE) + { + break; + } + + if (researchItem2->category == RCT1_RESEARCH_CATEGORY_VEHICLE && + researchItem2->related_ride == rideType) + { + AddEntryForVehicleType(rideType, researchItem2->item); + numVehicles++; + } + } + + // If no vehicles found so just add the default for this ride + if (numVehicles == 0) + { + AddEntryForRideType(rideType); + } + break; + } + } + } +} + +void S4Importer::AddAvailableEntriesFromMap() +{ + size_t maxTiles = 128 * 128; + size_t tileIndex = 0; + rct_map_element * mapElement = _s4.map_elements; + + while (tileIndex < maxTiles) + { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_PATH: + { + uint8 pathColour = mapElement->type & 3; + uint8 pathType = (mapElement->properties.path.type & 0xF0) >> 4; + uint8 supportsType = (mapElement->flags & 0x60) >> 5; + + pathType = (pathType << 2) | pathColour; + uint8 pathAdditionsType = mapElement->properties.path.additions & 0x0F; + + AddEntryForPath(pathType); + AddEntryForPathAddition(pathAdditionsType); + break; + } + case MAP_ELEMENT_TYPE_SCENERY: + AddEntryForSmallScenery(mapElement->properties.scenery.type); + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + AddEntryForLargeScenery(mapElement->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK); + break; + case MAP_ELEMENT_TYPE_FENCE: + { + uint8 var_05 = mapElement->properties.fence.item[0]; + uint16 var_06 = mapElement->properties.fence.item[1] | + (mapElement->properties.fence.item[2] << 8); + + for (int edge = 0; edge < 4; edge++) + { + int typeA = (var_05 >> (edge * 2)) & 3; + int typeB = (var_06 >> (edge * 4)) & 0x0F; + if (typeB != 0x0F) + { + uint8 type = typeA | (typeB << 2); + AddEntryForWall(type); + } + } + break; + } + } + + if (map_element_is_last_for_tile(mapElement++)) + { + tileIndex++; + } + } +} + +void S4Importer::AddAvailableEntriesFromRides() +{ + for (size_t i = 0; i < Util::CountOf(_s4.rides); i++) + { + rct1_ride * ride = &_s4.rides[i]; + if (ride->type != RCT1_RIDE_TYPE_NULL) + { + // TODO might need to check if ride type has a vehicle type + AddEntryForVehicleType(ride->type, ride->vehicle_type); + } + } +} + +void S4Importer::AddAvailableEntriesFromSceneryGroups() +{ + for (int sceneryTheme = 0; sceneryTheme <= RCT1_SCENERY_THEME_PAGODA; sceneryTheme++) + { + if (sceneryTheme != 0 && + _sceneryThemeTypeToEntryMap[sceneryTheme] == 255) continue; + + List objects = RCT1::GetSceneryObjects(sceneryTheme); + for (const char * objectName : objects) + { + rct_object_entry * foundEntry = object_list_find_by_name(objectName); + if (foundEntry != nullptr) + { + uint8 objectType = foundEntry->flags & 0x0F; + switch (objectType) { + case OBJECT_TYPE_SMALL_SCENERY: + case OBJECT_TYPE_LARGE_SCENERY: + case OBJECT_TYPE_WALLS: + case OBJECT_TYPE_PATHS: + case OBJECT_TYPE_PATH_BITS: + { + List * entries = GetEntryList(objectType); + + // Ran out of available entries + if (entries->GetCount() >= (size_t)object_entry_group_counts[objectType]) + { + break; + } + + if (!entries->Contains(objectName, ObjectNameComparer)) + { + entries->Add(objectName); + } + break; + } + } + } + } + } +} + +void S4Importer::AddEntryForRideType(uint8 rideType) +{ + if (_rideTypeToRideEntryMap[rideType] == 255) + { + const char * entryName = RCT1::GetRideTypeObject(rideType); + _rideTypeToRideEntryMap[rideType] = (uint8)_rideEntries.GetCount(); + _rideEntries.Add(entryName); + } +} + +void S4Importer::AddEntryForVehicleType(uint8 rideType, uint8 vehicleType) +{ + if (_vehicleTypeToRideEntryMap[vehicleType] == 255) + { + const char * entryName = RCT1::GetVehicleObject(vehicleType); + + uint8 rideEntryIndex = (uint8)_rideEntries.GetCount(); + _vehicleTypeToRideEntryMap[vehicleType] = rideEntryIndex; + _rideEntries.Add(entryName); + + // Just overwrite this with the vehicle entry for now... + _rideTypeToRideEntryMap[rideType] = rideEntryIndex; + } +} + +void S4Importer::AddEntryForSmallScenery(uint8 smallSceneryType) +{ + if (_smallSceneryTypeToEntryMap[smallSceneryType] == 255) + { + const char * entryName = RCT1::GetSmallSceneryObject(smallSceneryType); + _smallSceneryTypeToEntryMap[smallSceneryType] = (uint8)_smallSceneryEntries.GetCount(); + _smallSceneryEntries.Add(entryName); + } +} + +void S4Importer::AddEntryForLargeScenery(uint8 largeSceneryType) +{ + if (_largeSceneryTypeToEntryMap[largeSceneryType] == 255) + { + const char * entryName = RCT1::GetLargeSceneryObject(largeSceneryType); + _largeSceneryTypeToEntryMap[largeSceneryType] = (uint8)_largeSceneryEntries.GetCount(); + _largeSceneryEntries.Add(entryName); + } +} + +void S4Importer::AddEntryForWall(uint8 wallType) +{ + if (_wallTypeToEntryMap[wallType] == 255) + { + const char * entryName = RCT1::GetWallObject(wallType); + _wallTypeToEntryMap[wallType] = (uint8)_wallEntries.GetCount(); + _wallEntries.Add(entryName); + } +} + +void S4Importer::AddEntryForPath(uint8 pathType) +{ + if (_pathTypeToEntryMap[pathType] == 255) + { + const char * entryName = RCT1::GetPathObject(pathType); + + size_t index = _pathEntries.IndexOf(entryName, ObjectNameComparer); + if (index != SIZE_MAX) + { + _pathTypeToEntryMap[pathType] = (uint8)index; + } + else + { + _pathTypeToEntryMap[pathType] = (uint8)_pathEntries.GetCount(); + _pathEntries.Add(entryName); + } + } +} + +void S4Importer::AddEntryForPathAddition(uint8 pathAdditionType) +{ + if (pathAdditionType == RCT1_PATH_ADDITION_NONE) return; + + if (_pathAdditionTypeToEntryMap[pathAdditionType] == 255) + { + uint8 normalisedPathAdditionType = RCT1::NormalisePathAddition(pathAdditionType); + if (_pathAdditionTypeToEntryMap[normalisedPathAdditionType] == 255) + { + const char * entryName = RCT1::GetPathAddtionObject(normalisedPathAdditionType); + _pathAdditionTypeToEntryMap[normalisedPathAdditionType] = (uint8)_pathAdditionEntries.GetCount(); + _pathAdditionEntries.Add(entryName); + } + + _pathAdditionTypeToEntryMap[pathAdditionType] = _pathAdditionTypeToEntryMap[normalisedPathAdditionType]; + } +} + +void S4Importer::AddEntriesForSceneryTheme(uint8 sceneryThemeType) +{ + if (sceneryThemeType == RCT1_SCENERY_THEME_GENERAL || + sceneryThemeType == RCT1_SCENERY_THEME_JUMPING_FOUNTAINS || + sceneryThemeType == RCT1_SCENERY_THEME_GARDEN_CLOCK) + { + _sceneryThemeTypeToEntryMap[sceneryThemeType] = 254; + } + else + { + const char * entryName = RCT1::GetSceneryGroupObject(sceneryThemeType); + + _sceneryThemeTypeToEntryMap[sceneryThemeType] = (uint8)_sceneryGroupEntries.GetCount(); + _sceneryGroupEntries.Add(entryName); + } +} + +void S4Importer::ImportRides() +{ + for (int i = 0; i < MAX_RIDES; i++) + { + if (_s4.rides[i].type != RIDE_TYPE_NULL) + { + ImportRide(get_ride(i), &_s4.rides[i]); + } + } +} + +void S4Importer::ImportRide(rct_ride * dst, rct1_ride * src) +{ + memset(dst, 0, sizeof(rct_ride)); + + dst->type = RCT1::GetRideType(src->type); + if (RCT1::RideTypeUsesVehicles(src->type)) + { + dst->subtype = _vehicleTypeToRideEntryMap[src->vehicle_type]; + } + else + { + dst->subtype = _rideTypeToRideEntryMap[src->type]; + } + + rct_ride_entry * rideEntry = get_ride_entry(dst->subtype); + + // Ride name + dst->name = 0; + if (is_user_string_id(src->name)) + { + const char * rideName = GetUserString(src->name); + if (rideName[0] != 0) + { + rct_string_id rideNameStringId = user_string_allocate(4, rideName); + if (rideNameStringId != 0) + { + dst->name = rideNameStringId; + } + } + } + if (dst->name == 0) + { + dst->name = 1; + + uint16 * args = (uint16*)&dst->name_arguments; + args[0] = 2 + dst->type; + args[1] = src->name_argument_number; + } + + // We can't convert vehicles yet so just close the ride + dst->status = RIDE_STATUS_CLOSED; + + // Flags + if (src->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) dst->lifecycle_flags |= RIDE_LIFECYCLE_ON_RIDE_PHOTO; + if (src->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) dst->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; + if (src->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE) dst->lifecycle_flags |= RIDE_LIFECYCLE_INDESTRUCTIBLE; + if (src->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) dst->lifecycle_flags |= RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK; + + // Station + dst->overall_view = src->overall_view; + for (int i = 0; i < 4; i++) + { + dst->station_starts[i] = src->station_starts[i]; + dst->station_heights[i] = src->station_height[i] / 2; + dst->station_length[i] = src->station_length[i]; + dst->station_depart[i] = src->station_light[i]; + + // Use src->station_depart[i] when we import with guests and vehicles intact + dst->train_at_station[i] = 0xFF; + + dst->entrances[i] = src->entrance[i]; + dst->exits[i] = src->exit[i]; + dst->queue_time[i] = src->queue_time[i]; + dst->last_peep_in_queue[i] = 0xFFFF; + } + dst->num_stations = src->num_stations; + + for (int i = 0; i < 32; i++) + { + dst->vehicles[i] = SPRITE_INDEX_NULL; + } + dst->num_vehicles = src->num_trains; + dst->num_cars_per_train = src->num_cars_per_train + rideEntry->zero_cars; + dst->proposed_num_vehicles = src->num_trains; + dst->max_trains = 32; + dst->proposed_num_cars_per_train = src->num_cars_per_train + rideEntry->zero_cars; + + // Operation + dst->depart_flags = src->depart_flags; + dst->min_waiting_time = src->min_waiting_time; + dst->max_waiting_time = src->max_waiting_time; + dst->operation_option = src->operation_option; + dst->num_circuits = 1; + dst->min_max_cars_per_train = (rideEntry->min_cars_in_train << 4) | rideEntry->max_cars_in_train; + + // RCT1 used 5mph / 8 km/h for every lift hill + dst->lift_hill_speed = 5; + + if (_gameVersion == FILE_VERSION_RCT1) + { + // Original RCT had no music settings, take default style + dst->music = RCT2_ADDRESS(0x0097D4F4, uint8)[dst->type * 8]; + } + else + { + dst->music = src->music; + } + + if (src->operating_mode == RCT1_RIDE_MODE_POWERED_LAUNCH) + { + // Launched rides never passed through the station in RCT1. + dst->mode = RIDE_MODE_POWERED_LAUNCH; + } + else + { + dst->mode = src->operating_mode; + } + + // Colours + dst->colour_scheme_type = src->colour_scheme; + if (_gameVersion == FILE_VERSION_RCT1) + { + dst->track_colour_main[0] = RCT1::GetColour(src->track_primary_colour); + dst->track_colour_additional[0] = RCT1::GetColour(src->track_secondary_colour); + dst->track_colour_supports[0] = RCT1::GetColour(src->track_support_colour); + } + else + { + for (int i = 0; i < 4; i++) + { + dst->track_colour_main[i] = RCT1::GetColour(src->track_colour_main[i]); + dst->track_colour_additional[i] = RCT1::GetColour(src->track_colour_additional[i]); + dst->track_colour_supports[i] = RCT1::GetColour(src->track_colour_supports[i]); + } + // Entrance styles were introduced with AA. They correspond directly with those in RCT2. + dst->entrance_style = src->entrance_style; + } + + if (_gameVersion < FILE_VERSION_RCT1_LL && dst->type == RIDE_TYPE_MERRY_GO_ROUND) + { + // The merry-go-round in pre-LL versions was always yellow with red + dst->vehicle_colours[0].body_colour = COLOUR_YELLOW; + dst->vehicle_colours[0].trim_colour = COLOUR_BRIGHT_RED; + } + else + { + for (int i = 0; i < 12; i++) + { + dst->vehicle_colours[i].body_colour = RCT1::GetColour(src->vehicle_colours[i].body); + dst->vehicle_colours[i].trim_colour = RCT1::GetColour(src->vehicle_colours[i].trim); + } + } + + // Fix other Z + // dst->start_drop_height /= 2; + // dst->highest_drop_height = 1; + // if (dst->cur_test_track_z != 255) + // { + // dst->cur_test_track_z /= 2; + // } + // dst->chairlift_bullwheel_z[0] /= 2; + // dst->chairlift_bullwheel_z[1] /= 2; + + // Maintenance + dst->build_date = src->build_date; + dst->inspection_interval = src->inspection_interval; + dst->last_inspection = src->last_inspection; + dst->reliability = src->reliability; + dst->unreliability_factor = src->unreliability_factor; + dst->breakdown_reason = src->breakdown_reason; + + // Finance + dst->upkeep_cost = src->upkeep_cost; + dst->price = src->price; + dst->income_per_hour = src->income_per_hour; + + dst->value = src->value; + dst->satisfaction = 255; + dst->satisfaction_time_out = 0; + dst->satisfaction_next = 0; + dst->popularity = src->popularity; + dst->popularity_next = src->popularity_next; + dst->popularity_time_out = src->popularity_time_out; + + dst->music_tune_id = 255; + dst->measurement_index = 255; + dst->excitement = (ride_rating)-1; +} + +void S4Importer::ImportRideMeasurements() +{ + for (int i = 0; i < MAX_RIDE_MEASUREMENTS; i++) + { + rct_ride_measurement * dst = get_ride_measurement(i); + rct_ride_measurement * src = &_s4.ride_measurements[i]; + ImportRideMeasurement(dst, src); + } +} + +void S4Importer::ImportRideMeasurement(rct_ride_measurement * dst, rct_ride_measurement * src) +{ + // Not yet supported + // *dst = *src; + // for (int i = 0; i < RIDE_MEASUREMENT_MAX_ITEMS; i++) + // { + // dst->altitude[i] /= 2; + // } +} + +void S4Importer::ImportPeepSpawns() +{ + for (int i = 0; i < 2; i++) + { + gPeepSpawns[i] = _s4.peep_spawn[i]; + } +} + +void S4Importer::ImportMapAnimations() +{ + // This is sketchy, ideally we should try to re-create them + rct_map_animation * s4Animations = (rct_map_animation*)_s4.map_animations; + for (int i = 0; i < 1000; i++) + { + gAnimatedObjects[i] = s4Animations[i]; + gAnimatedObjects[i].baseZ /= 2; + } + RCT2_GLOBAL(0x0138B580, uint16) = _s4.num_map_animations; +} + +void S4Importer::ImportFinance() +{ + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) = _s4.park_entrance_fee; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) = _s4.land_price; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money16) = _s4.construction_rights_price; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, uint32) = ENCRYPT_MONEY(_s4.cash); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = _s4.loan; + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = _s4.max_loan; + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) = _s4.cash; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_COMPANY_VALUE, money32) = _s4.company_value; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32) = _s4.park_value; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PROFIT, money32) = _s4.profit; + + for (int i = 0; i < 128; i++) + { + gCashHistory[i] = _s4.cash_history[i]; + gParkValueHistory[i] = _s4.park_value_history[i]; + gWeeklyProfitHistory[i] = _s4.weekly_profit_history[i]; + } + + for (int i = 0; i < 14 * 16; i++) + { + RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[i] = _s4.expenditure[i]; + } + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_EXPENDITURE, money32) = _s4.total_expenditure; + + RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_ADMISSIONS, uint32) = _s4.num_admissions; + RCT2_GLOBAL(RCT2_ADDRESS_INCOME_FROM_ADMISSIONS, money32) = _s4.admission_total_income; + + // TODO marketing campaigns not working + for (int i = 0; i < 6; i++) + { + gMarketingCampaignDaysLeft[i] = _s4.marketing_status[i]; + gMarketingCampaignRideIndex[i] = _s4.marketing_assoc[i]; + } +} + +void S4Importer::LoadObjects() +{ + LoadObjects(OBJECT_TYPE_RIDE, _rideEntries); + LoadObjects(OBJECT_TYPE_SMALL_SCENERY, _smallSceneryEntries); + LoadObjects(OBJECT_TYPE_LARGE_SCENERY, _largeSceneryEntries); + LoadObjects(OBJECT_TYPE_WALLS, _wallEntries); + LoadObjects(OBJECT_TYPE_PATHS, _pathEntries); + LoadObjects(OBJECT_TYPE_PATH_BITS, _pathAdditionEntries); + LoadObjects(OBJECT_TYPE_SCENERY_SETS, _sceneryGroupEntries); + LoadObjects(OBJECT_TYPE_BANNERS, List({ + "BN1 ", + "BN2 ", + "BN3 ", + "BN4 ", + "BN5 ", + "BN6 ", + "BN7 ", + "BN8 ", + "BN9 " + })); + LoadObjects(OBJECT_TYPE_PARK_ENTRANCE, List({ "PKENT1 " })); + LoadObjects(OBJECT_TYPE_WATER, List({ "WTRCYAN " })); + + reset_loaded_objects(); +} + +void S4Importer::LoadObjects(uint8 objectType, List entries) +{ + uint32 entryIndex = 0; + for (const char * objectName : entries) + { + rct_object_entry entry; + entry.flags = 0x00008000 + objectType; + Memory::Copy(entry.name, objectName, 8); + entry.checksum = 0; + + if (!object_load_chunk(entryIndex, &entry, NULL)) + { + log_error("Failed to load %s.", objectName); + throw Exception("Failed to load object."); + } + + entryIndex++; + } +} + +void S4Importer::ImportMapElements() +{ + memcpy(gMapElements, _s4.map_elements, 0xC000 * sizeof(rct_map_element)); + ClearExtraTileEntries(); + FixColours(); + FixZ(); + FixPaths(); + FixWalls(); + FixBanners(); + FixTerrain(); + FixEntrancePositions(); + FixMapElementEntryTypes(); +} + +void S4Importer::ImportResearch() +{ + // All available objects must be loaded before this method is called as it + // requires them to correctly insert objects into the research list + + research_reset_items(); + + size_t researchListCount; + const rct1_research_item * researchList = GetResearchList(&researchListCount); + + // Initialise the "seen" tables + Memory::Set(_researchRideEntryUsed, 0, sizeof(_researchRideEntryUsed)); + Memory::Set(_researchRideTypeUsed, 0, sizeof(_researchRideTypeUsed)); + + // The first six scenery groups are always available + for (int i = 0; i < 6; i++) + { + research_insert_scenery_group_entry(i, true); + } + + bool researched = true; + for (size_t i = 0; i < researchListCount; i++) + { + const rct1_research_item * researchItem = &researchList[i]; + if (researchItem->item == RCT1_RESEARCH_END_AVAILABLE) + { + researched = false; + } + else if (researchItem->item == RCT1_RESEARCH_END_RESEARCHABLE || + researchItem->item == RCT1_RESEARCH_END) + { + break; + } + + switch (researchItem->category) { + case RCT1_RESEARCH_CATEGORY_THEME: + { + uint8 rct1SceneryTheme = researchItem->item; + if (rct1SceneryTheme != RCT1_SCENERY_THEME_GENERAL && + rct1SceneryTheme != RCT1_SCENERY_THEME_JUMPING_FOUNTAINS && + rct1SceneryTheme != RCT1_SCENERY_THEME_GARDEN_CLOCK) + { + uint8 sceneryGroupEntryIndex = _sceneryThemeTypeToEntryMap[rct1SceneryTheme]; + research_insert_scenery_group_entry(sceneryGroupEntryIndex, researched); + } + break; + } + case RCT1_RESEARCH_CATEGORY_RIDE: + { + uint8 rct1RideType = researchItem->item; + + // Add all vehicles for this ride type that are researched or before this research item + uint32 numVehicles = 0; + for (size_t j = 0; j < researchListCount; j++) + { + const rct1_research_item *researchItem2 = &researchList[j]; + if (researchItem2->item == RCT1_RESEARCH_END_RESEARCHABLE || + researchItem2->item == RCT1_RESEARCH_END_AVAILABLE) + { + break; + } + + if (researchItem2->category == RCT1_RESEARCH_CATEGORY_VEHICLE && + researchItem2->related_ride == rct1RideType) + { + // Only add the vehicles that were listed before this ride, otherwise we might + // change the research order + if (j < i) + { + InsertResearchVehicle(researchItem2, researched); + } + numVehicles++; + } + } + + if (numVehicles == 0) + { + // No vehicles found so just add the default for this ride + uint8 rideEntryIndex = _rideTypeToRideEntryMap[rct1RideType]; + Guard::Assert(rideEntryIndex != 255, "rideEntryIndex was 255"); + + if (!_researchRideEntryUsed[rideEntryIndex]) + { + _researchRideEntryUsed[rideEntryIndex] = true; + research_insert_ride_entry(rideEntryIndex, researched); + } + } + break; + } + case RCT1_RESEARCH_CATEGORY_VEHICLE: + // Only add vehicle if the related ride has been seen, this to make sure that vehicles + // are researched only after the ride has been researched + if (_researchRideTypeUsed[researchItem->related_ride]) + { + InsertResearchVehicle(researchItem, researched); + } + break; + case RCT1_RESEARCH_CATEGORY_SPECIAL: + // Not supported + break; + } + } + + research_remove_non_separate_vehicle_types(); + + // Research funding / priority + uint16 activeResearchTypes = 0; + if (_s4.research_priority & RCT1_RESEARCH_EXPENDITURE_ROLLERCOASTERS) + { + activeResearchTypes |= (1 << RESEARCH_CATEGORY_ROLLERCOASTER); + } + if (_s4.research_priority & RCT1_RESEARCH_EXPENDITURE_THRILL_RIDES) + { + activeResearchTypes |= (1 << RESEARCH_CATEGORY_THRILL); + activeResearchTypes |= (1 << RESEARCH_CATEGORY_WATER); + } + if (_s4.research_priority & RCT1_RESEARCH_EXPENDITURE_GENTLE_TRANSPORT_RIDES) + { + activeResearchTypes |= (1 << RESEARCH_CATEGORY_GENTLE); + activeResearchTypes |= (1 << RESEARCH_CATEGORY_TRANSPORT); + } + if (_s4.research_priority & RCT1_RESEARCH_EXPENDITURE_SHOPS) + { + activeResearchTypes |= (1 << RESEARCH_CATEGORY_SHOP); + } + if (_s4.research_priority & RCT1_RESEARCH_EXPENDITURE_SCENERY_THEMEING) + { + activeResearchTypes |= (1 << RESEARCH_CATEGORY_SCENERYSET); + } + RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16) = activeResearchTypes; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8) = _s4.research_level; + + // Research history + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint8) = _s4.research_progress; + // RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, uint8) = _s4.next_research_item; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8) = _s4.next_research_category; + // RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8) = + // RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8) = + +} + +void S4Importer::InsertResearchVehicle(const rct1_research_item * researchItem, bool researched) +{ + uint8 vehicle = researchItem->item; + uint8 rideEntryIndex = _vehicleTypeToRideEntryMap[vehicle]; + if (!_researchRideEntryUsed[rideEntryIndex]) + { + _researchRideEntryUsed[rideEntryIndex] = true; + research_insert_ride_entry(rideEntryIndex, researched); + } +} + +void S4Importer::ImportParkName() +{ + const char * parkName = _s4.scenario_name; + if (is_user_string_id((rct_string_id)_s4.park_name_string_index)) + { + const char * userString = GetUserString(_s4.park_name_string_index); + if (userString[0] != '\0') + { + parkName = userString; + } + } + + rct_string_id stringId = user_string_allocate(4, parkName); + if (stringId != 0) + { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id) = stringId; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32) = 0; + } +} + +void S4Importer::ImportParkFlags() +{ + // Date and srand + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) = _s4.ticks; + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32) = _s4.random_a; + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) = _s4.random_b; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) = _s4.month; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16) = _s4.day; + + // Park rating + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) = _s4.park_rating; + for (int i = 0; i < 32; i++) + { + gParkRatingHistory[i] = _s4.park_rating_history[i]; + } + + // Awards + for (int i = 0; i < 4; i++) + { + gCurrentAwards[i] = _s4.awards[i]; + } + + // Number of guests history + for (int i = 0; i < 32; i++) + { + gGuestsInParkHistory[i] = _s4.guests_in_park_history[i]; + } + + // News items + rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); + for (int i = 0; i < 61; i++) + { + newsItems[i] = _s4.messages[i]; + } + + // Initial guest status + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) = _s4.guest_initial_cash; + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8) = _s4.guest_initial_hunger; + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8) = _s4.guest_initial_thirst; + + // Staff colours + RCT2_GLOBAL(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8) = RCT1::GetColour(_s4.handman_colour); + RCT2_GLOBAL(RCT2_ADDRESS_MECHANIC_COLOUR, uint8) = RCT1::GetColour(_s4.mechanic_colour); + RCT2_GLOBAL(RCT2_ADDRESS_SECURITY_COLOUR, uint8) = RCT1::GetColour(_s4.security_guard_colour); + + // Flags + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = _s4.park_flags; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_ANTI_CHEAT_DEPRECATED; + if (!(_s4.park_flags & PARK_FLAGS_PARK_FREE_ENTRY)) + { + gCheatsUnlockAllPrices = true; + } +} + +void S4Importer::ImportClimate() +{ + RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8) = _s4.climate; + RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE_UPDATE_TIMER, uint16) = _s4.climate_timer; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TEMPERATURE, sint8) = _s4.temperature; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER, uint8) = _s4.weather; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_EFFECT, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_GLOOM, sint8) = _s4.weather_gloom; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, sint8) = _s4.rain; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_TEMPERATURE, uint8) = _s4.target_temperature; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_WEATHER, uint8) = _s4.target_weather; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_WEATHER_EFFECT, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_WEATHER_GLOOM, uint8) = _s4.target_weather_gloom; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RAIN_LEVEL, uint8) = _s4.target_rain; +} + +void S4Importer::ImportScenarioNameDetails() +{ + rct_s6_info * s6Info = (rct_s6_info*)0x0141F570; + + String::Set(s6Info->name, sizeof(s6Info->name), _s4.scenario_name); + String::Set(s6Info->details, sizeof(s6Info->details), ""); + + int scNumber = GetSCNumber(); + if (scNumber != -1) + { + source_desc sourceDesc; + if (scenario_get_source_desc_by_id(scNumber, &sourceDesc)) + { + rct_string_id localisedStringIds[3]; + if (language_get_localised_scenario_strings(sourceDesc.title, localisedStringIds)) + { + if (localisedStringIds[0] != STR_NONE) + { + String::Set(s6Info->name, sizeof(s6Info->name), language_get_string(localisedStringIds[0])); + } + if (localisedStringIds[2] != STR_NONE) + { + String::Set(s6Info->details, sizeof(s6Info->details), language_get_string(localisedStringIds[2])); + } + } + } + } +} + +void S4Importer::ImportScenarioObjective() +{ + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) = _s4.scenario_objective_type; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) = _s4.scenario_objective_years; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, uint32) = _s4.scenario_objective_currency; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) = _s4.scenario_objective_num_guests; +} + +void S4Importer::ImportSavedView() +{ + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, uint16) = _s4.view_x; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, uint16) = _s4.view_y; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint8) = _s4.view_zoom; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION + 1, uint8) = _s4.view_rotation; +} + +void S4Importer::ClearExtraTileEntries() +{ + // Reset the map tile pointers + for (int i = 0; i < 0x10000; i++) + { + gMapElementTilePointers[i] = (rct_map_element *)-1; + } + + // Get the first free map element + rct_map_element * nextFreeMapElement = gMapElements; + for (int i = 0; i < 128 * 128; i++) + { + do { } while (!map_element_is_last_for_tile(nextFreeMapElement++)); + } + + rct_map_element * mapElement = gMapElements; + rct_map_element * * tilePointer = gMapElementTilePointers; + + // 128 rows of map data from RCT1 map + for (int x = 0; x < 128; x++) + { + // Assign the first half of this row + for (int y = 0; y < 128; y++) + { + *tilePointer++ = mapElement; + do { } while (!map_element_is_last_for_tile(mapElement++)); + } + + // Fill the rest of the row with blank tiles + for (int y = 0; y < 128; y++) + { + nextFreeMapElement->type = MAP_ELEMENT_TYPE_SURFACE; + nextFreeMapElement->flags = MAP_ELEMENT_FLAG_LAST_TILE; + nextFreeMapElement->base_height = 2; + nextFreeMapElement->clearance_height = 0; + nextFreeMapElement->properties.surface.slope = 0; + nextFreeMapElement->properties.surface.terrain = 0; + nextFreeMapElement->properties.surface.grass_length = GRASS_LENGTH_CLEAR_0; + nextFreeMapElement->properties.surface.ownership = 0; + *tilePointer++ = nextFreeMapElement++; + } + } + + // 128 extra rows left to fill with blank tiles + for (int y = 0; y < 128 * 256; y++) + { + nextFreeMapElement->type = MAP_ELEMENT_TYPE_SURFACE; + nextFreeMapElement->flags = MAP_ELEMENT_FLAG_LAST_TILE; + nextFreeMapElement->base_height = 2; + nextFreeMapElement->clearance_height = 0; + nextFreeMapElement->properties.surface.slope = 0; + nextFreeMapElement->properties.surface.terrain = 0; + nextFreeMapElement->properties.surface.grass_length = GRASS_LENGTH_CLEAR_0; + nextFreeMapElement->properties.surface.ownership = 0; + *tilePointer++ = nextFreeMapElement++; + } + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*) = nextFreeMapElement; +} + +void S4Importer::FixColours() +{ + colour_t colour; + + // The following code would be worth doing if we were able to import sprites + // for (int i = 0; i < MAX_SPRITES; i++) + // { + // rct_unk_sprite * sprite = &(g_sprite_list[i].unknown); + // switch (sprite->sprite_identifier) { + // case SPRITE_IDENTIFIER_PEEP: + // { + // rct_peep * peep = (rct_peep*)sprite; + // peep->tshirt_colour = RCT1ColourConversionTable[peep->tshirt_colour]; + // peep->trousers_colour = RCT1ColourConversionTable[peep->trousers_colour]; + // peep->balloon_colour = RCT1ColourConversionTable[peep->balloon_colour]; + // peep->umbrella_colour = RCT1ColourConversionTable[peep->umbrella_colour]; + // peep->hat_colour = RCT1ColourConversionTable[peep->hat_colour]; + // break; + // } + // case SPRITE_IDENTIFIER_MISC: + // { + // rct_balloon * balloon = (rct_balloon*)sprite; + // balloon->colour = RCT1ColourConversionTable[balloon->colour]; + // balloon->var_2D = RCT1ColourConversionTable[balloon->var_2D]; + // break; + // } + // } + // } + + rct_map_element * mapElement = gMapElements; + while (mapElement < RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*)) + { + if (mapElement->base_height != 255) + { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SCENERY: + colour = RCT1::GetColour(mapElement->properties.scenery.colour_1 & 0x1F); + mapElement->properties.scenery.colour_1 &= 0xE0; + mapElement->properties.scenery.colour_1 |= colour; + + // Copied from [rct2: 0x006A2956] + switch (mapElement->properties.scenery.type) { + case 157: // TGE1 (Geometric Sculpture) + case 162: // TGE2 (Geometric Sculpture) + case 168: // TGE3 (Geometric Sculpture) + case 170: // TGE4 (Geometric Sculpture) + case 171: // TGE5 (Geometric Sculpture) + mapElement->properties.scenery.colour_2 = COLOUR_WHITE; + break; + } + break; + case MAP_ELEMENT_TYPE_FENCE: + colour = ((mapElement->type & 0xC0) >> 3) | + ((mapElement->properties.fence.type & 0xE0) >> 5); + colour = RCT1::GetColour(colour); + + mapElement->type &= 0x3F; + mapElement->properties.fence.type &= 0x1F; + mapElement->type |= (colour & 0x18) << 3; + mapElement->properties.fence.type |= (colour & 7) << 5; + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + colour = RCT1::GetColour(mapElement->properties.scenerymultiple.colour[0] & 0x1F); + mapElement->properties.scenerymultiple.colour[0] &= 0xE0; + mapElement->properties.scenerymultiple.colour[0] |= colour; + + colour = RCT1::GetColour(mapElement->properties.scenerymultiple.colour[1] & 0x1F); + mapElement->properties.scenerymultiple.colour[1] &= 0xE0; + mapElement->properties.scenerymultiple.colour[1] |= colour; + break; + } + } + mapElement++; + } +} + +void S4Importer::FixZ() +{ + // The following code would be useful if we imported sprites + // for (int i = 0; i < MAX_SPRITES; i++) + // { + // rct_unk_sprite * sprite = &(g_sprite_list[i].unknown); + // if (sprite->sprite_identifier == SPRITE_IDENTIFIER_PEEP) { + // rct_peep * peep = (rct_peep*)sprite; + // peep->next_z /= 2; + // RCT2_GLOBAL((int)peep + 0xCE, uint8) /= 2; + // } + // } + + rct_map_element * mapElement = gMapElements; + while (mapElement < RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*)) + { + if (mapElement->base_height != 255) + { + mapElement->base_height /= 2; + mapElement->clearance_height /= 2; + } + mapElement++; + } + RCT2_GLOBAL(0x01359208, uint16) = 7; +} + +void S4Importer::FixPaths() +{ + rct_map_element * mapElement = gMapElements; + while (mapElement < RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*)) + { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_PATH: + { + // Type + uint8 pathColour = mapElement->type & 3; + uint8 pathType = (mapElement->properties.path.type & 0xF0) >> 4; + uint8 supportsType = (mapElement->flags & 0x60) >> 5; + + pathType = (pathType << 2) | pathColour; + uint8 entryIndex = _pathTypeToEntryMap[pathType]; + + mapElement->type &= 0xFC; + mapElement->flags &= ~0x60; + mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + mapElement->properties.path.type &= 0x0F; + footpath_scenery_set_is_ghost(mapElement, false); + if (RCT1::PathIsQueue(pathType)) + { + mapElement->type |= 1; + } + mapElement->properties.path.type |= entryIndex << 4; + + // Additions + uint8 additionType = footpath_element_get_path_scenery(mapElement); + if (additionType != RCT1_PATH_ADDITION_NONE) + { + uint8 normalisedType = RCT1::NormalisePathAddition(additionType); + uint8 entryIndex = _pathAdditionTypeToEntryMap[normalisedType]; + if (additionType != normalisedType) + { + mapElement->flags |= MAP_ELEMENT_FLAG_BROKEN; + } + footpath_element_set_path_scenery(mapElement, entryIndex + 1); + } + break; + } + case MAP_ELEMENT_TYPE_ENTRANCE: + if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) + { + uint8 pathType = mapElement->properties.entrance.path_type; + if (pathType == 0) + { + pathType = RCT1_FOOTPATH_TYPE_TARMAC_GRAY; + } + uint8 entryIndex = _pathTypeToEntryMap[pathType]; + mapElement->properties.entrance.path_type = entryIndex & 0x7F; + } + break; + } + mapElement++; + } +} + +void S4Importer::FixWalls() +{ + for (int x = 0; x < 128; x++) + { + for (int y = 0; y < 128; y++) + { + rct_map_element * mapElement = map_get_first_element_at(x, y); + do + { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_FENCE) + { + rct_map_element originalMapElement = *mapElement; + map_element_remove(mapElement); + + uint8 var_05 = originalMapElement.properties.fence.item[0]; + uint16 var_06 = originalMapElement.properties.fence.item[1] | + (originalMapElement.properties.fence.item[2] << 8); + + for (int edge = 0; edge < 4; edge++) + { + int typeA = (var_05 >> (edge * 2)) & 3; + int typeB = (var_06 >> (edge * 4)) & 0x0F; + if (typeB != 0x0F) + { + int type = typeA | (typeB << 2); + int colourA = ((originalMapElement.type & 0xC0) >> 3) | + (originalMapElement.properties.fence.type >> 5); + int colourB = 0; + int colourC = 0; + ConvertWall(&type, &colourA, &colourB, &colourC); + + type = _wallTypeToEntryMap[type]; + map_place_fence(type, x * 32, y * 32, 0, edge, colourA, colourB, colourC, 169); + } + } + break; + } + } + while (!map_element_is_last_for_tile(mapElement++)); + } + } +} + +void S4Importer::ConvertWall(int * type, int * colourA, int * colourB, int * colourC) +{ + switch (*type) { + case 12: // creepy gate + *colourA = 24; + break; + case 26: // white wooden fence + *type = 12; + *colourA = 2; + break; + case 27: // red wooden fence + *type = 12; + *colourA = 25; + break; + case 50: // plate glass + *colourA = 24; + break; + case 13: + *colourB = *colourA; + *colourA = 24; + break; + case 11: // tall castle wall with grey gate + case 22: // brick wall with gate + *colourB = 2; + break; + case 35: // wood post fence + case 42: // tall grey castle wall + case 43: // wooden fence with snow + case 44: + case 45: + case 46: + *colourA = 1; + break; + } +} + +void S4Importer::FixBanners() +{ + for (int x = 0; x < 128; x++) + { + for (int y = 0; y < 128; y++) + { + rct_map_element * mapElement = map_get_first_element_at(x, y); + do + { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_BANNER) + { + uint8 index = mapElement->properties.banner.index; + rct_banner * src = &_s4.banners[index]; + rct_banner * dst = &gBanners[index]; + ImportBanner(dst, src); + } + } + while (!map_element_is_last_for_tile(mapElement++)); + } + } +} + +void S4Importer::ImportBanner(rct_banner * dst, rct_banner * src) +{ + *dst = *src; + dst->colour = RCT1::GetColour(src->colour); + + dst->string_idx = 778; + if (is_user_string_id(src->string_idx)) + { + const char * bannerText = GetUserString(src->string_idx); + if (!String::IsNullOrEmpty(bannerText)) + { + rct_string_id bannerTextStringId = user_string_allocate(128, bannerText); + if (bannerTextStringId != 0) + { + dst->string_idx = bannerTextStringId; + } + } + } +} + +void S4Importer::FixTerrain() +{ + map_element_iterator it; + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it)) + { + rct_map_element * element = it.element; + if (map_element_get_type(element) == MAP_ELEMENT_TYPE_SURFACE) + { + map_element_set_terrain(element, RCT1::GetTerrain(map_element_get_terrain(element))); + map_element_set_terrain_edge(element, RCT1::GetTerrainEdge(map_element_get_terrain_edge(element))); + } + } +} + +void S4Importer::FixEntrancePositions() +{ + for (int i = 0; i < 4; i++) + { + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] = 0x8000; + } + + uint8 entranceIndex = 0; + + map_element_iterator it; + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it) && entranceIndex < 4) + { + rct_map_element * element = it.element; + + if (map_element_get_type(element) != MAP_ELEMENT_TYPE_ENTRANCE) continue; + if (element->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) continue; + if ((element->properties.entrance.index & 0x0F) != 0) continue; + + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[entranceIndex] = it.x * 32; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, uint16)[entranceIndex] = it.y * 32; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, uint16)[entranceIndex] = element->base_height * 8; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION, uint8)[entranceIndex] = element->type & 3; + entranceIndex++; + } +} + +void S4Importer::FixMapElementEntryTypes() +{ + map_element_iterator it; + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it)) + { + rct_map_element * mapElement = it.element; + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SCENERY: + mapElement->properties.scenery.type = _smallSceneryTypeToEntryMap[mapElement->properties.scenery.type]; + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + { + uint8 type = mapElement->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK; + mapElement->properties.scenerymultiple.type &= ~MAP_ELEMENT_LARGE_TYPE_MASK; + mapElement->properties.scenerymultiple.type |= _largeSceneryTypeToEntryMap[type]; + break; + } + } + } +} + +List * S4Importer::GetEntryList(uint8 objectType) +{ + switch (objectType) { + case OBJECT_TYPE_RIDE: return &_rideEntries; + case OBJECT_TYPE_SMALL_SCENERY: return &_smallSceneryEntries; + case OBJECT_TYPE_LARGE_SCENERY: return &_largeSceneryEntries; + case OBJECT_TYPE_WALLS: return &_wallEntries; + case OBJECT_TYPE_PATHS: return &_pathEntries; + case OBJECT_TYPE_PATH_BITS: return &_pathAdditionEntries; + case OBJECT_TYPE_SCENERY_SETS: return &_sceneryGroupEntries; + } + return nullptr; +} + +const rct1_research_item * S4Importer::GetResearchList(size_t * count) +{ + // Loopy Landscapes stores research items in a different place + if (_gameVersion == FILE_VERSION_RCT1_LL) + { + *count = Util::CountOf(_s4.research_items_LL); + return _s4.research_items_LL; + } + else + { + *count = Util::CountOf(_s4.research_items); + return _s4.research_items; + } +} + +int S4Importer::GetSCNumber() +{ + const utf8 * fileName = Path::GetFileName(_s4Path); + if (tolower(fileName[0]) == 's' && tolower(fileName[1]) == 'c') { + constexpr size_t maxDigits = 7; + utf8 digitBuffer[maxDigits + 1]; + utf8 * dst = digitBuffer; + const utf8 * src = fileName + 2; + for (int i = 0; i < maxDigits && *src != '.'; i++) + { + *dst++ = *src++; + } + *dst++ = 0; + + if (digitBuffer[0] == '0' && digitBuffer[1] == '\0') + { + return 0; + } + else + { + int digits = atoi(digitBuffer); + return digits == 0 ? -1 : digits; + } + } + else + { + return -1; + } +} + +const char * S4Importer::GetUserString(rct_string_id stringId) +{ + return _s4.string_table[(stringId - 0x8000) % 1024]; +} + +///////////////////////////////////////// +// C -> C++ transfer +///////////////////////////////////////// +extern "C" +{ + bool rct1_load_saved_game(const utf8 * path) + { + bool result; + + auto s4Importer = new S4Importer(); + try + { + s4Importer->LoadSavedGame(path); + s4Importer->Import(); + result = true; + } catch (Exception ex) + { + result = false; + } + delete s4Importer; + return result; + } + + bool rct1_load_scenario(const utf8 * path) + { + bool result; + + auto s4Importer = new S4Importer(); + try + { + s4Importer->LoadScenario(path); + s4Importer->Import(); + result = true; + } catch (Exception ex) + { + result = false; + } + delete s4Importer; + return result; + } + + colour_t rct1_get_colour(colour_t colour) + { + return RCT1::GetColour(colour); + } + + /** + * This function keeps a list of the preferred vehicle for every generic track + * type, out of the available vehicle types in the current game. It determines + * which picture is shown on the new ride tab and which train type is selected + * by default. + */ + int vehicle_preference_compare(uint8 rideType, const char * a, const char * b) + { + List rideEntryOrder = RCT1::GetPreferedRideEntryOrder(rideType); + for (const char * object : rideEntryOrder) + { + if (String::Equals(object, a, true)) + { + return -1; + } + if (String::Equals(object, b, true)) + { + return 1; + } + } + return 0; + } +} diff --git a/src/rct1/S4Importer.h b/src/rct1/S4Importer.h new file mode 100644 index 0000000000..396a48867a --- /dev/null +++ b/src/rct1/S4Importer.h @@ -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 _rideEntries; + List _smallSceneryEntries; + List _largeSceneryEntries; + List _wallEntries; + List _pathEntries; + List _pathAdditionEntries; + List _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 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 * GetEntryList(uint8 objectType); + const rct1_research_item * GetResearchList(size_t * count); + int GetSCNumber(); + const char * GetUserString(rct_string_id stringId); +}; diff --git a/src/rct1/Tables.h b/src/rct1/Tables.h new file mode 100644 index 0000000000..ca84dc3ba2 --- /dev/null +++ b/src/rct1/Tables.h @@ -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 GetSceneryObjects(uint8 sceneryType); + + const List GetPreferedRideEntryOrder(uint8 rideType); +} diff --git a/src/rct1/tables.cpp b/src/rct1/tables.cpp new file mode 100644 index 0000000000..6a49303cc3 --- /dev/null +++ b/src/rct1/tables.cpp @@ -0,0 +1,1095 @@ +#include "../common.h" +#include "../core/List.hpp" +#include "../core/Util.hpp" +#include "Tables.h" + +extern "C" +{ + #include "../interface/colour.h" + #include "../rct1.h" + #include "../ride/ride.h" +} + +namespace RCT1 +{ + const char * DefaultParkEntranceObject = "PKENT1 "; + + colour_t GetColour(colour_t colour) + { + static const uint8 map[] = + { + COLOUR_BLACK, + COLOUR_GREY, + COLOUR_WHITE, + COLOUR_LIGHT_PURPLE, + COLOUR_BRIGHT_PURPLE, + COLOUR_DARK_BLUE, + COLOUR_LIGHT_BLUE, + COLOUR_TEAL, + COLOUR_SATURATED_GREEN, + COLOUR_DARK_GREEN, + COLOUR_MOSS_GREEN, + COLOUR_BRIGHT_GREEN, + COLOUR_OLIVE_GREEN, + COLOUR_DARK_OLIVE_GREEN, + COLOUR_YELLOW, + COLOUR_DARK_YELLOW, + COLOUR_LIGHT_ORANGE, + COLOUR_DARK_ORANGE, + COLOUR_LIGHT_BROWN, + COLOUR_SATURATED_BROWN, + COLOUR_DARK_BROWN, + COLOUR_SALMON_PINK, + COLOUR_BORDEAUX_RED, + COLOUR_SATURATED_RED, + COLOUR_BRIGHT_RED, + COLOUR_BRIGHT_PINK, + COLOUR_LIGHT_PINK, + COLOUR_DARK_PINK, + COLOUR_DARK_PURPLE, + COLOUR_AQUAMARINE, + COLOUR_BRIGHT_YELLOW, + COLOUR_ICY_BLUE + }; + return map[colour]; + } + + uint8 GetTerrain(uint8 terrain) + { + static const uint8 map[] = + { + TERRAIN_GRASS, + TERRAIN_SAND, + TERRAIN_DIRT, + TERRAIN_ROCK, + TERRAIN_MARTIAN, + TERRAIN_CHECKERBOARD, + TERRAIN_GRASS_CLUMPS, + TERRAIN_DIRT, // Originally TERRAIN_ROOF_BROWN + TERRAIN_ICE, + TERRAIN_DIRT, // Originally TERRAIN_ROOF_LOG + TERRAIN_DIRT, // Originally TERRAIN_ROOF_IRON + TERRAIN_ROCK, // Originally TERRAIN_ROOF_GREY + TERRAIN_GRID_RED, + TERRAIN_GRID_YELLOW, + TERRAIN_GRID_BLUE, + TERRAIN_GRID_GREEN + }; + return map[terrain]; + } + + uint8 GetTerrainEdge(uint8 terrainEdge) + { + static const uint8 map[] = + { + TERRAIN_EDGE_ROCK, + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_BRICK + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_IRON + TERRAIN_EDGE_WOOD_RED, + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_GREY + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_YELLOW + TERRAIN_EDGE_WOOD_BLACK, + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_RED + TERRAIN_EDGE_ICE, + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_PURPLE + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_GREEN + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_STONE_BROWN + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_STONE_GREY + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_SKYSCRAPER_A + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_SKYSCRAPER_B + TERRAIN_EDGE_ROCK // Unused + }; + return map[terrainEdge]; + } + + uint8 GetRideType(uint8 rideType) + { + static uint8 map[] = + { + RIDE_TYPE_WOODEN_ROLLER_COASTER, + RIDE_TYPE_STAND_UP_ROLLER_COASTER, + RIDE_TYPE_SUSPENDED_SWINGING_COASTER, + RIDE_TYPE_INVERTED_ROLLER_COASTER, + RIDE_TYPE_JUNIOR_ROLLER_COASTER, + RIDE_TYPE_MINIATURE_RAILWAY, + RIDE_TYPE_MONORAIL, + RIDE_TYPE_MINI_SUSPENDED_COASTER, + RIDE_TYPE_BOAT_RIDE, + RIDE_TYPE_WOODEN_WILD_MOUSE, + RIDE_TYPE_STEEPLECHASE, + RIDE_TYPE_CAR_RIDE, + RIDE_TYPE_LAUNCHED_FREEFALL, + RIDE_TYPE_BOBSLEIGH_COASTER, + RIDE_TYPE_OBSERVATION_TOWER, + RIDE_TYPE_LOOPING_ROLLER_COASTER, + RIDE_TYPE_DINGHY_SLIDE, + RIDE_TYPE_MINE_TRAIN_COASTER, + RIDE_TYPE_CHAIRLIFT, + RIDE_TYPE_CORKSCREW_ROLLER_COASTER, + RIDE_TYPE_MAZE, + RIDE_TYPE_SPIRAL_SLIDE, + RIDE_TYPE_GO_KARTS, + RIDE_TYPE_LOG_FLUME, + RIDE_TYPE_RIVER_RAPIDS, + RIDE_TYPE_DODGEMS, + RIDE_TYPE_PIRATE_SHIP, + RIDE_TYPE_SWINGING_INVERTER_SHIP, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_DRINK_STALL, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_SHOP, + RIDE_TYPE_MERRY_GO_ROUND, + RIDE_TYPE_SHOP, + RIDE_TYPE_INFORMATION_KIOSK, + RIDE_TYPE_TOILETS, + RIDE_TYPE_FERRIS_WHEEL, + RIDE_TYPE_MOTION_SIMULATOR, + RIDE_TYPE_3D_CINEMA, + RIDE_TYPE_TOP_SPIN, + RIDE_TYPE_SPACE_RINGS, + RIDE_TYPE_REVERSE_FREEFALL_COASTER, + RIDE_TYPE_SHOP, + RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_TWIST, + RIDE_TYPE_HAUNTED_HOUSE, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_CIRCUS_SHOW, + RIDE_TYPE_GHOST_TRAIN, + RIDE_TYPE_TWISTER_ROLLER_COASTER, + RIDE_TYPE_WOODEN_ROLLER_COASTER, + RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER, + RIDE_TYPE_WILD_MOUSE, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_SHOP, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_VIRGINIA_REEL, + RIDE_TYPE_SPLASH_BOATS, + RIDE_TYPE_MINI_HELICOPTERS, + RIDE_TYPE_LAY_DOWN_ROLLER_COASTER, + RIDE_TYPE_SUSPENDED_MONORAIL, + RIDE_TYPE_NULL, + RIDE_TYPE_REVERSER_ROLLER_COASTER, + RIDE_TYPE_HEARTLINE_TWISTER_COASTER, + RIDE_TYPE_MINI_GOLF, + RIDE_TYPE_NULL, + RIDE_TYPE_ROTO_DROP, + RIDE_TYPE_FLYING_SAUCERS, + RIDE_TYPE_CROOKED_HOUSE, + RIDE_TYPE_MONORAIL_CYCLES, + RIDE_TYPE_COMPACT_INVERTED_COASTER, + RIDE_TYPE_WATER_COASTER, + RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER, + RIDE_TYPE_INVERTED_HAIRPIN_COASTER, + RIDE_TYPE_BOAT_RIDE, + RIDE_TYPE_SHOP, + RIDE_TYPE_RIVER_RAFTS, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_ENTERPRISE, + RIDE_TYPE_DRINK_STALL, + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_DRINK_STALL + }; + return map[rideType]; + } + + bool RideTypeUsesVehicles(uint8 rideType) + { + switch (rideType) { + case RCT1_RIDE_TYPE_HEDGE_MAZE: + case RCT1_RIDE_TYPE_SPIRAL_SLIDE: + case RCT1_RIDE_TYPE_ICE_CREAM_STALL: + case RCT1_RIDE_TYPE_FRIES_STALL: + case RCT1_RIDE_TYPE_DRINK_STALL: + case RCT1_RIDE_TYPE_COTTON_CANDY_STALL: + case RCT1_RIDE_TYPE_BURGER_BAR: + case RCT1_RIDE_TYPE_BALLOON_STALL: + case RCT1_RIDE_TYPE_INFORMATION_KIOSK: + case RCT1_RIDE_TYPE_TOILETS: + case RCT1_RIDE_TYPE_SOUVENIR_STALL: + case RCT1_RIDE_TYPE_PIZZA_STALL: + case RCT1_RIDE_TYPE_POPCORN_STALL: + case RCT1_RIDE_TYPE_HOT_DOG_STALL: + case RCT1_RIDE_TYPE_EXOTIC_SEA_FOOD_STALL: + case RCT1_RIDE_TYPE_HAT_STALL: + case RCT1_RIDE_TYPE_CANDY_APPLE_STAND: + case RCT1_RIDE_TYPE_40: + case RCT1_RIDE_TYPE_44: + case RCT1_RIDE_TYPE_T_SHIRT_STALL: + case RCT1_RIDE_TYPE_DOUGHNUT_SHOP: + case RCT1_RIDE_TYPE_COFFEE_SHOP: + case RCT1_RIDE_TYPE_FRIED_CHICKEN_STALL: + case RCT1_RIDE_TYPE_LEMONADE_STALL: + return false; + default: + return true; + } + } + + bool PathIsQueue(uint8 pathType) + { + switch (pathType) { + case RCT1_FOOTPATH_TYPE_QUEUE_BLUE: + case RCT1_FOOTPATH_TYPE_QUEUE_RED: + case RCT1_FOOTPATH_TYPE_QUEUE_YELLOW: + case RCT1_FOOTPATH_TYPE_QUEUE_GREEN: + return true; + } + return false; + } + + uint8 NormalisePathAddition(uint8 pathAdditionType) + { + switch (pathAdditionType) { + case RCT1_PATH_ADDITION_BROKEN_LAMP_1: return RCT1_PATH_ADDITION_LAMP_1; + case RCT1_PATH_ADDITION_BROKEN_LAMP_2: return RCT1_PATH_ADDITION_LAMP_2; + case RCT1_PATH_ADDITION_BROKEN_BIN: return RCT1_PATH_ADDITION_BIN; + case RCT1_PATH_ADDITION_BROKEN_BENCH: return RCT1_PATH_ADDITION_BENCH; + case RCT1_PATH_ADDITION_BROKEN_LAMP_3: return RCT1_PATH_ADDITION_LAMP_3; + case RCT1_PATH_ADDITION_BROKEN_LAMP_4: return RCT1_PATH_ADDITION_LAMP_4; + } + return pathAdditionType; + } + + const char * GetRideTypeObject(uint8 rideType) + { + static const char * map[] = + { + "PTCT1 ", // RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER + "TOGST ", // RCT1_RIDE_TYPE_STAND_UP_STEEL_ROLLER_COASTER + "ARRSW1 ", // RCT1_RIDE_TYPE_SUSPENDED_ROLLER_COASTER + "NEMT ", // RCT1_RIDE_TYPE_INVERTED_ROLLER_COASTER + "ZLDB ", // RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER + "NRL ", // RCT1_RIDE_TYPE_MINIATURE_RAILROAD + "MONO2 ", // RCT1_RIDE_TYPE_MONORAIL + "BATFL ", // RCT1_RIDE_TYPE_SUSPENDED_SINGLE_RAIL_ROLLER_COASTER + "RBOAT ", // RCT1_RIDE_TYPE_BOAT_HIRE + "WMOUSE ", // RCT1_RIDE_TYPE_WOODEN_CRAZY_RODENT_ROLLER_COASTER + "STEEP1 ", // RCT1_RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER + "SPCAR ", // RCT1_RIDE_TYPE_CAR_RIDE + "SSC1 ", // RCT1_RIDE_TYPE_LAUNCHED_FREEFALL + "BOB1 ", // RCT1_RIDE_TYPE_BOBSLED_ROLLER_COASTER + "OBS1 ", // RCT1_RIDE_TYPE_OBSERVATION_TOWER + "SCHT1 ", // RCT1_RIDE_TYPE_STEEL_ROLLER_COASTER + "DING1 ", // RCT1_RIDE_TYPE_WATER_SLIDE + "AMT1 ", // RCT1_RIDE_TYPE_MINE_TRAIN_ROLLER_COASTER + "CLIFT1 ", // RCT1_RIDE_TYPE_CHAIRLIFT + "ARRT1 ", // RCT1_RIDE_TYPE_STEEL_CORKSCREW_ROLLER_COASTER + "HMAZE ", // RCT1_RIDE_TYPE_HEDGE_MAZE + "HSKELT ", // RCT1_RIDE_TYPE_SPIRAL_SLIDE + "KART1 ", // RCT1_RIDE_TYPE_GO_KARTS + "LFB1 ", // RCT1_RIDE_TYPE_LOG_FLUME + "RAPBOAT ", // RCT1_RIDE_TYPE_RIVER_RAPIDS + "DODG1 ", // RCT1_RIDE_TYPE_DODGEMS + "SWSH1 ", // RCT1_RIDE_TYPE_SWINGING_SHIP + "SWSH2 ", // RCT1_RIDE_TYPE_SWINGING_INVERTER_SHIP + "ICECR1 ", // RCT1_RIDE_TYPE_ICE_CREAM_STALL + "CHPSH ", // RCT1_RIDE_TYPE_FRIES_STALL + "DRNKS ", // RCT1_RIDE_TYPE_DRINK_STALL + "CNDYF ", // RCT1_RIDE_TYPE_COTTON_CANDY_STALL + "BURGB ", // RCT1_RIDE_TYPE_BURGER_BAR + "MGR1 ", // RCT1_RIDE_TYPE_MERRY_GO_ROUND + "BALLN ", // RCT1_RIDE_TYPE_BALLOON_STALL + "INFOK ", // RCT1_RIDE_TYPE_INFORMATION_KIOSK + "TLT1 ", // RCT1_RIDE_TYPE_TOILETS + "FWH1 ", // RCT1_RIDE_TYPE_FERRIS_WHEEL + "SIMPOD ", // RCT1_RIDE_TYPE_MOTION_SIMULATOR + "C3D ", // RCT1_RIDE_TYPE_3D_CINEMA + "TOPSP1 ", // RCT1_RIDE_TYPE_GRAVITRON + "SRINGS ", // RCT1_RIDE_TYPE_SPACE_RINGS + "REVF1 ", // RCT1_RIDE_TYPE_REVERSE_WHOA_BELLY_ROLLER_COASTER + "SOUVS ", // RCT1_RIDE_TYPE_SOUVENIR_STALL + "BMVD ", // RCT1_RIDE_TYPE_VERTICAL_ROLLER_COASTER + "PIZZS ", // RCT1_RIDE_TYPE_PIZZA_STALL + "TWIST1 ", // RCT1_RIDE_TYPE_SCRAMBLED_EGGS + "HHBUILD ", // RCT1_RIDE_TYPE_HAUNTED_HOUSE + "POPCS ", // RCT1_RIDE_TYPE_POPCORN_STALL + "CIRCUS1 ", // RCT1_RIDE_TYPE_CIRCUS_SHOW + "GTC ", // RCT1_RIDE_TYPE_GHOST_TRAIN + "BMSD ", // RCT1_RIDE_TYPE_STEEL_TWISTER_ROLLER_COASTER + "MFT ", // RCT1_RIDE_TYPE_WOODEN_TWISTER_ROLLER_COASTER + "SFRIC1 ", // RCT1_RIDE_TYPE_WOODEN_SIDE_FRICTION_ROLLER_COASTER + "SMC1 ", // RCT1_RIDE_TYPE_STEEL_WILD_MOUSE_ROLLER_COASTER + "HOTDS ", // RCT1_RIDE_TYPE_HOT_DOG_STALL + "SQDST ", // RCT1_RIDE_TYPE_EXOTIC_SEA_FOOD_STALL + "HATST ", // RCT1_RIDE_TYPE_HAT_STALL + "TOFFS ", // RCT1_RIDE_TYPE_CANDY_APPLE_STAND + "VREEL ", // RCT1_RIDE_TYPE_VIRGINIA_REEL + "SPBOAT ", // RCT1_RIDE_TYPE_RIVER_RIDE + "MONBK ", // RCT1_RIDE_TYPE_CYCLE_MONORAIL + "BMAIR ", // RCT1_RIDE_TYPE_FLYING_ROLLER_COASTER + "SMONO ", // RCT1_RIDE_TYPE_SUSPENDED_MONORAIL + " ", // RCT1_RIDE_TYPE_40 + "REVCAR ", // RCT1_RIDE_TYPE_WOODEN_REVERSER_ROLLER_COASTER + "UTCAR ", // RCT1_RIDE_TYPE_HEARTLINE_TWISTER_ROLLER_COASTER + "GOLF1 ", // RCT1_RIDE_TYPE_MINIATURE_GOLF + " ", // RCT1_RIDE_TYPE_44 + "GDROP1 ", // RCT1_RIDE_TYPE_ROTO_DROP + "FSAUC ", // RCT1_RIDE_TYPE_FLYING_SAUCERS + "CHBUILD ", // RCT1_RIDE_TYPE_CROOKED_HOUSE + "HELICAR ", // RCT1_RIDE_TYPE_CYCLE_RAILWAY + "SLCT ", // RCT1_RIDE_TYPE_SUSPENDED_LOOPING_ROLLER_COASTER + "CSTBOAT ", // RCT1_RIDE_TYPE_WATER_COASTER + "THCAR ", // RCT1_RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER + "IVMC1 ", // RCT1_RIDE_TYPE_INVERTED_WILD_MOUSE_COASTER + "JSKI ", // RCT1_RIDE_TYPE_JET_SKIS + "TSHRT ", // RCT1_RIDE_TYPE_T_SHIRT_STALL + "RFTBOAT ", // RCT1_RIDE_TYPE_RAFT_RIDE + "DOUGH ", // RCT1_RIDE_TYPE_DOUGHNUT_SHOP + "ENTERP ", // RCT1_RIDE_TYPE_ENTERPRISE + "COFFS ", // RCT1_RIDE_TYPE_COFFEE_SHOP + "CHCKS ", // RCT1_RIDE_TYPE_FRIED_CHICKEN_STALL + "LEMST ", // RCT1_RIDE_TYPE_LEMONADE_STALL + }; + + Guard::ArgumentInRange(rideType, 0, Util::CountOf(map), ""); + return map[rideType]; + } + + const char * GetVehicleObject(uint8 vehicleType) + { + static const char * map[] = + { + "SCHT1 ", // RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN + "SCHT1 ", // RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN_BACKWARDS + "PTCT1 ", // RCT1_VEHICLE_TYPE_WOODEN_ROLLER_COASTER_TRAIN + "SLCT ", // RCT1_VEHICLE_TYPE_INVERTED_COASTER_TRAIN (Not in RCT2) + "ARRSW1 ", // RCT1_VEHICLE_TYPE_SUSPENDED_SWINGING_CARS + "ZLDB ", // RCT1_VEHICLE_TYPE_LADYBIRD_CARS + "TOGST ", // RCT1_VEHICLE_TYPE_STANDUP_ROLLER_COASTER_CARS + "WMSPIN ", // RCT1_VEHICLE_TYPE_SPINNING_CARS + "BATFL ", // RCT1_VEHICLE_TYPE_SINGLE_PERSON_SWINGING_CHAIRS + "SWANS ", // RCT1_VEHICLE_TYPE_SWANS_PEDAL_BOATS + "MONO1 ", // RCT1_VEHICLE_TYPE_LARGE_MONORAIL_TRAIN + "CBOAT ", // RCT1_VEHICLE_TYPE_CANOES + "RBOAT ", // RCT1_VEHICLE_TYPE_ROWING_BOATS + "NRL ", // RCT1_VEHICLE_TYPE_STEAM_TRAIN + "WMOUSE ", // RCT1_VEHICLE_TYPE_WOODEN_MOUSE_CARS + "BBOAT ", // RCT1_VEHICLE_TYPE_BUMPER_BOATS + "PTCT1 ", // RCT1_VEHICLE_TYPE_WOODEN_ROLLER_COASTER_TRAIN_BACKWARDS + "RCKC ", // RCT1_VEHICLE_TYPE_ROCKET_CARS + "STEEP1 ", // RCT1_VEHICLE_TYPE_HORSES // Steeplechase + "SPCAR ", // RCT1_VEHICLE_TYPE_SPORTSCARS + "SKYTR ", // RCT1_VEHICLE_TYPE_LYING_DOWN_SWINGING_CARS (Inverted single-rail) + "WMMINE ", // RCT1_VEHICLE_TYPE_WOODEN_MINE_CARS + "ARRSW2 ", // RCT1_VEHICLE_TYPE_SUSPENDED_SWINGING_AIRPLANE_CARS + "MONO2 ", // RCT1_VEHICLE_TYPE_SMALL_MONORAIL_CARS + "TRIKE ", // RCT1_VEHICLE_TYPE_WATER_TRICYCLES + "SSC1 ", // RCT1_VEHICLE_TYPE_LAUNCHED_FREEFALL_CAR + "BOB1 ", // RCT1_VEHICLE_TYPE_BOBSLEIGH_CARS + "DING1 ", // RCT1_VEHICLE_TYPE_DINGHIES + "OBS1 ", // RCT1_VEHICLE_TYPE_ROTATING_CABIN + "AMT1 ", // RCT1_VEHICLE_TYPE_MINE_TRAIN + "CLIFT1 ", // RCT1_VEHICLE_TYPE_CHAIRLIFT_CARS + "ARRT1 ", // RCT1_VEHICLE_TYPE_CORKSCREW_ROLLER_COASTER_TRAIN + "STEEP2 ", // RCT1_VEHICLE_TYPE_MOTORBIKES + "RCR ", // RCT1_VEHICLE_TYPE_RACING_CARS + "TRUCK1 ", // RCT1_VEHICLE_TYPE_TRUCKS + "KART1 ", // RCT1_VEHICLE_TYPE_GO_KARTS + "RAPBOAT ", // RCT1_VEHICLE_TYPE_RAPIDS_BOATS + "LFB1 ", // RCT1_VEHICLE_TYPE_LOG_FLUME_BOATS + "DODG1 ", // RCT1_VEHICLE_TYPE_DODGEMS + "SWSH1 ", // RCT1_VEHICLE_TYPE_SWINGING_SHIP + "SWSH2 ", // RCT1_VEHICLE_TYPE_SWINGING_INVERTER_SHIP + "MGR1 ", // RCT1_VEHICLE_TYPE_MERRY_GO_ROUND + "FWH1 ", // RCT1_VEHICLE_TYPE_FERRIS_WHEEL + "SIMPOD ", // RCT1_VEHICLE_TYPE_SIMULATOR_POD + "C3D ", // RCT1_VEHICLE_TYPE_CINEMA_BUILDING + "TOPSP1 ", // RCT1_VEHICLE_TYPE_TOPSPIN_CAR + "SRINGS ", // RCT1_VEHICLE_TYPE_SPACE_RINGS + "REVF1 ", // RCT1_VEHICLE_TYPE_REVERSE_FREEFALL_ROLLER_COASTER_CAR + "BMVD ", // RCT1_VEHICLE_TYPE_VERTICAL_ROLLER_COASTER_CARS + "CTCAR ", // RCT1_VEHICLE_TYPE_CAT_CARS + "TWIST1 ", // RCT1_VEHICLE_TYPE_TWIST_ARMS_AND_CARS + "HHBUILD ", // RCT1_VEHICLE_TYPE_HAUNTED_HOUSE_BUILDING + "ZLOG ", // RCT1_VEHICLE_TYPE_LOG_CARS + "CIRCUS1 ", // RCT1_VEHICLE_TYPE_CIRCUS_TENT + "GTC ", // RCT1_VEHICLE_TYPE_GHOST_TRAIN_CARS + "BMSD ", // RCT1_VEHICLE_TYPE_STEEL_TWISTER_ROLLER_COASTER_TRAIN + "MFT ", // RCT1_VEHICLE_TYPE_WOODEN_TWISTER_ROLLER_COASTER_TRAIN + "SFRIC1 ", // RCT1_VEHICLE_TYPE_WOODEN_SIDE_FRICTION_CARS + "VCR ", // RCT1_VEHICLE_TYPE_VINTAGE_CARS + "NRL2 ", // RCT1_VEHICLE_TYPE_STEAM_TRAIN_COVERED_CARS + "BMSU ", // RCT1_VEHICLE_TYPE_STAND_UP_STEEL_TWISTER_ROLLER_COASTER_TRAIN + "BMFL ", // RCT1_VEHICLE_TYPE_FLOORLESS_STEEL_TWISTER_ROLLER_COASTER_TRAIN + "SMC1 ", // RCT1_VEHICLE_TYPE_STEEL_MOUSE_CARS + "CLIFT2 ", // RCT1_VEHICLE_TYPE_CHAIRLIFT_CARS_ALTERNATIVE + "SMONO ", // RCT1_VEHICLE_TYPE_SUSPENDED_MONORAIL_TRAIN + "HELICAR ", // RCT1_VEHICLE_TYPE_HELICOPTER_CARS + "VREEL ", // RCT1_VEHICLE_TYPE_VIRGINIA_REEL_TUBS + "REVCAR ", // RCT1_VEHICLE_TYPE_REVERSER_CARS + "GOLF1 ", // RCT1_VEHICLE_TYPE_GOLFERS + "SPBOAT ", // RCT1_VEHICLE_TYPE_RIVER_RIDE_BOATS + "BMAIR ", // RCT1_VEHICLE_TYPE_FLYING_ROLLER_COASTER_TRAIN + "BMRB ", // RCT1_VEHICLE_TYPE_NON_LOOPING_STEEL_TWISTER_ROLLER_COASTER_TRAIN + "UTCAR ", // RCT1_VEHICLE_TYPE_HEARTLINE_TWISTER_CARS + "UTCARR ", // RCT1_VEHICLE_TYPE_HEARTLINE_TWISTER_CARS_REVERSED + " ", // RCT1_VEHICLE_TYPE_RESERVED + "GDROP1 ", // RCT1_VEHICLE_TYPE_ROTODROP_CAR + "FSAUC ", // RCT1_VEHICLE_TYPE_FLYING_SAUCERS + "CHBUILD ", // RCT1_VEHICLE_TYPE_CROOKED_HOUSE_BUILDING + "MONBK ", // RCT1_VEHICLE_TYPE_BICYCLES + "ARRT2 ", // RCT1_VEHICLE_TYPE_HYPERCOASTER_TRAIN + "NEMT ", // RCT1_VEHICLE_TYPE_4_ACROSS_INVERTED_COASTER_TRAIN + "CSTBOAT ", // RCT1_VEHICLE_TYPE_WATER_COASTER_BOATS + "SLCFO ", // RCT1_VEHICLE_TYPE_FACEOFF_CARS + "JSKI ", // RCT1_VEHICLE_TYPE_JET_SKIS + "RFTBOAT ", // RCT1_VEHICLE_TYPE_RAFT_BOATS + "AML1 ", // RCT1_VEHICLE_TYPE_AMERICAN_STYLE_STEAM_TRAIN + "THCAR ", // RCT1_VEHICLE_TYPE_AIR_POWERED_COASTER_TRAIN + "IVMC1 ", // RCT1_VEHICLE_TYPE_SUSPENDED_WILD_MOUSE_CARS (Inverted Hairpin in RCT2) + "ENTERP ", // RCT1_VEHICLE_TYPE_ENTERPRISE_WHEEL + }; + + Guard::ArgumentInRange(vehicleType, 0, Util::CountOf(map), ""); + return map[vehicleType]; + } + + const char * GetSmallSceneryObject(uint8 smallSceneryType) + { + static const char * map[] = + { + "TL0 ", + "TL1 ", + "TL2 ", + "TL3 ", + "TM0 ", + "TM1 ", + "TM2 ", + "TM3 ", + "TS0 ", + "TS1 ", + "TS2 ", + "TS3 ", + "TS4 ", + "TS5 ", + "TS6 ", + "TIC ", + "TLC ", + "TMC ", + "TMP ", + "TITC ", + "TGHC ", + "TAC ", + "TGHC2 ", + "TCJ ", + "TMBJ ", + "TCF ", + "TCL ", + "TRF ", + "TRF2 ", + "TEL ", + "TAP ", + "TSP ", + "TMZP ", + "TCRP ", + "TBP ", + "TLP ", + "TWP ", + "TAS ", + "TMG ", + "TWW ", + "TSB ", + "TVL ", + "TCT ", + "TEF ", + "TAL ", + "TSQ ", + "THT ", + "TCB ", + "TDM ", + "TSD ", + "TGS ", + "TUS ", + "TH1 ", + "TBC ", + "TH2 ", + "TPM ", + "TSC ", + "TG1 ", + "TWF ", + "TSH0 ", + "TSH1 ", + "TSH2 ", + "TSH3 ", + "TSH4 ", + "TSH5 ", + "TG2 ", + "TG3 ", + "TG4 ", + "TG5 ", + "TG6 ", + "TG7 ", + "TG8 ", + "TG9 ", + "TG10 ", + "TG11 ", + "TG12 ", + "TG13 ", + "TG14 ", + "TT1 ", + "TDF ", + "TSH ", + "THRS ", + "TSTD ", + "TRMS ", + "TRWS ", + "TRC ", + "TQF ", + "TES1 ", + "TEN ", + "TERS ", + "TERB ", + "TEP ", + "TST1 ", + "TST2 ", + "TMS1 ", + "TAS1 ", + "TAS2 ", + "TAS3 ", + "TST3 ", + "TST4 ", + "TST5 ", + "TAS4 ", + "TCY ", + "TBW ", + "TBR1 ", + "TBR2 ", + "TML ", + "TMW ", + "TBR3 ", + "TBR4 ", + "TMJ ", + "TBR ", + "TMO1 ", + "TMO2 ", + "TMO3 ", + "TMO4 ", + "TMO5 ", + "TWH1 ", + "TWH2 ", + "TNS ", + "TP1 ", + "TP2 ", + "TK1 ", + "TK2 ", + "TR1 ", + "TR2 ", + "TQ1 ", + "TQ2 ", + "TWN ", + "TCE ", + "TCO ", + "THL ", + "TCC ", + "TB1 ", + "TB2 ", + "TK3 ", + "TK4 ", + "TBN ", + "TBN1 ", + "TDT1 ", + "TDT2 ", + "TDT3 ", + "TMM1 ", + "TMM2 ", + "TMM3 ", + "TGS1 ", + "TGS2 ", + "TGS3 ", + "TGS4 ", + "TDN4 ", + "TDN5 ", + "TJT1 ", + "TJT2 ", + "TJB1 ", + "TTF ", + "TF1 ", + "TF2 ", + "TGE1 ", + "TJT3 ", + "TJT4 ", + "TJP1 ", + "TJB2 ", + "TGE2 ", + "TJT5 ", + "TJB3 ", + "TJB4 ", + "TJT6 ", + "TJP2 ", + "TGE3 ", + "TCK ", + "TGE4 ", + "TGE5 ", + "TG15 ", + "TG16 ", + "TG17 ", + "TG18 ", + "TG19 ", + "TG20 ", + "TG21 ", + "TSM ", + "TIG ", + "TCFS ", + "TRFS ", + "TRF3 ", + "TNSS ", + "TCT1 ", + "TCT2 ", + "TSF1 ", + "TSF2 ", + "TSF3 ", + "TCN ", + "TTG ", + "TSNC ", + "TSNB ", + "TSCP ", + "TCD ", + "TSG ", + "TSK ", + "TGH1 ", + "TGH2 ", + "TSMP ", + "TJF ", + "TLY ", + "TGC1 ", + "TGC2 ", + "TGG ", + "TSPH ", + "TOH1 ", + "TOH2 ", + "TOT1 ", + "TOT2 ", + "TOS ", + "TOT3 ", + "TOT4 ", + "TSC2 ", + "TSP1 ", + "TOH3 ", + "TSP2 ", + "ROMROOF1", + "GEOROOF1", + "TNTROOF1", + "JNGROOF1", + "MINROOF1", + "ROMROOF2", + "GEOROOF2", + "PAGROOF1", + "SPCROOF1", + "ROOF1 ", + "ROOF2 ", + "ROOF3 ", + "ROOF4 ", + "ROOF5 ", + "ROOF6 ", + "ROOF7 ", + "ROOF8 ", + "ROOF9 ", + "ROOF10 ", + "ROOF11 ", + "ROOF12 ", + "ROOF13 ", + "ROOF14 ", + "IGROOF ", + "CORROOF ", + "CORROOF2", + }; + return map[smallSceneryType]; + } + + const char * GetLargeSceneryObject(uint8 largeSceneryType) + { + static const char * map[] = + { + "SCOL ", + "SHS1 ", + "SSPX ", + "SHS2 ", + "SCLN ", + "SMH1 ", + "SMH2 ", + "SVLC ", + "SPYR ", + "SMN1 ", + "SMB ", + "SSK1 ", + "SDN1 ", + "SDN2 ", + "SDN3 ", + "SIP ", + "STB1 ", + "STB2 ", + "STG1 ", + "STG2 ", + "SCT ", + "SOH1 ", + "SOH2 ", + "SOH3 ", + "SGP ", + "SSR ", + "STH ", + "SAH ", + "SPS ", + "SPG ", + "SOB ", + "SAH2 ", + "SST ", + "SSH ", + "SAH3 ", + "SSIG1 ", + "SSIG2 ", + "SSIG3 ", + "SSIG4 ", + }; + return map[largeSceneryType]; + } + + const char * GetWallObject(uint8 wallType) + { + static const char * map[] = + { + "WMF ", + "WMFG ", + "WRW ", + "WEW ", + "WHG ", + "WHGG ", + "WCW1 ", + "WCW2 ", + "WSW ", + "WSWG ", + "WMW ", + "WALLGL16", + "WFW1 ", + "WFWG ", + "WPW1 ", + "WPW2 ", + "WPF ", + "WPFG ", + "WWTW ", + "WMWW ", + "WSW1 ", + "WSW2 ", + "WGW2 ", + "WBW ", + "WBR1 ", + "WBRG ", + "WALLCFAR", + "WALLPOST", + "WBR2 ", + "WBR3 ", + "WPW3 ", + "WJF ", + "WCH ", + "WCHG ", + "WC1 ", + "WC2 ", + "WC3 ", + "WC4 ", + "WC5 ", + "WC6 ", + "WC7 ", + "WC8 ", + "WC9 ", + "WC10 ", + "WC11 ", + "WC12 ", + "WC13 ", + "WC14 ", + "WC15 ", + "WC16 ", + "WC17 ", + "WC18 ", + "WALLBRDR", + "WALLBR32", + "WALLBR16", + "WALLBR8 ", + "WALLCF8 ", + "WALLCF16", + "WALLCF32", + "WALLBB8 ", + "WALLBB16", + "WALLBB32", + "WALLRS8 ", + "WALLRS16", + "WALLRS32", + "WALLCB8 ", + "WALLCB16", + "WALLCB32", + "WALLGL8 ", + "WALLGL32", + "WALLWD8 ", + "WALLWD16", + "WALLWD32", + "WALLTN32", + "WALLJN32", + "WALLMN32", + "WALLSP32", + "WALLPG32", + "WALLU132", + "WALLU232", + "WALLCZ32", + "WALLCW32", + "WALLCY32", + "WALLCX32", + "WBR1A ", + "WBR2A ", + "WRWA ", + "WWTWA ", + "WALLIG16", + "WALLIG24", + "WALLCO16", + "WALLCFDR", + "WALLCBDR", + "WALLBRWN", + "WALLCFWN", + "WALLCBWN", + }; + return map[wallType]; + } + + const char * GetPathObject(uint8 pathType) + { + static const char * map[] = + { + "TARMAC ", // RCT1_FOOTPATH_TYPE_QUEUE_BLUE + "PATHSPCE", // RCT1_FOOTPATH_TYPE_QUEUE_RED + "PATHDIRT", // RCT1_FOOTPATH_TYPE_QUEUE_YELLOW + "TARMACG ", // RCT1_FOOTPATH_TYPE_QUEUE_GREEN + + "TARMAC ", // RCT1_FOOTPATH_TYPE_TARMAC_GRAY + "PATHSPCE", // RCT1_FOOTPATH_TYPE_TARMAC_RED + "TARMACB ", // RCT1_FOOTPATH_TYPE_TARMAC_BROWN + "TARMACG ", // RCT1_FOOTPATH_TYPE_TARMAC_GREEN + + "PATHDIRT", // RCT1_FOOTPATH_TYPE_DIRT_RED + "PATHASH ", // RCT1_FOOTPATH_TYPE_DIRT_BLACK + " ", + " ", + + "PATHCRZY", // RCT1_FOOTPATH_TYPE_CRAZY_PAVING + " ", + " ", + " ", + + "ROAD ", // RCT1_FOOTPATH_TYPE_ROADS + " ", + " ", + " ", + + "PATHCRZY", // RCT1_FOOTPATH_TYPE_TILE_PINK + "PATHCRZY", // RCT1_FOOTPATH_TYPE_TILE_GRAY + "PATHCRZY", // RCT1_FOOTPATH_TYPE_TILE_RED + "PATHCRZY", // RCT1_FOOTPATH_TYPE_TILE_GREEN + }; + return map[pathType]; + } + + const char * GetPathAddtionObject(uint8 pathAdditionType) + { + static const char * map[] = + { + " ", // RCT1_PATH_ADDITION_NONE + "LAMP1 ", // RCT1_PATH_ADDITION_LAMP_1 + "LAMP2 ", // RCT1_PATH_ADDITION_LAMP_2 + "LITTER1 ", // RCT1_PATH_ADDITION_BIN + "BENCH1 ", // RCT1_PATH_ADDITION_BENCH + "JUMPFNT1", // RCT1_PATH_ADDITION_JUMPING_FOUNTAIN + "LAMP3 ", // RCT1_PATH_ADDITION_LAMP_3 + "LAMP4 ", // RCT1_PATH_ADDITION_LAMP_4 + "LAMP1 ", // RCT1_PATH_ADDITION_BROKEN_LAMP_1 + "LAMP2 ", // RCT1_PATH_ADDITION_BROKEN_LAMP_2 + "LITTER1 ", // RCT1_PATH_ADDITION_BROKEN_BIN + "BENCH1 ", // RCT1_PATH_ADDITION_BROKEN_BENCH + "LAMP3 ", // RCT1_PATH_ADDITION_BROKEN_LAMP_3 + "LAMP4 ", // RCT1_PATH_ADDITION_BROKEN_LAMP_4 + "JUMPSNW1", // RCT1_PATH_ADDITION_JUMPING_SNOW + }; + return map[pathAdditionType]; + } + + const char * GetSceneryGroupObject(uint8 sceneryGroupType) + { + static const char * map[] = + { + " ", // RCT1_SCENERY_THEME_GENERAL + "SCGMINE ", // RCT1_SCENERY_THEME_MINE + "SCGCLASS", // RCT1_SCENERY_THEME_CLASSICAL_ROMAN + "SCGEGYPT", // RCT1_SCENERY_THEME_EGYPTIAN + "SCGMART ", // RCT1_SCENERY_THEME_MARTIAN + " ", // RCT1_SCENERY_THEME_JUMPING_FOUNTAINS + "SCGWOND ", // RCT1_SCENERY_THEME_WONDERLAND + "SCGJURAS", // RCT1_SCENERY_THEME_JURASSIC + "SCGSPOOK", // RCT1_SCENERY_THEME_SPOOKY + "SCGJUNGL", // RCT1_SCENERY_THEME_JUNGLE + "SCGABSTR", // RCT1_SCENERY_THEME_ABSTRACT + " ", // RCT1_SCENERY_THEME_GARDEN_CLOCK + "SCGSNOW ", // RCT1_SCENERY_THEME_SNOW_ICE + "SCGMEDIE", // RCT1_SCENERY_THEME_MEDIEVAL + "SCGSPACE", // RCT1_SCENERY_THEME_SPACE + "SCGHALLO", // RCT1_SCENERY_THEME_CREEPY + "SCGURBAN", // RCT1_SCENERY_THEME_URBAN + "SCGORIEN", // RCT1_SCENERY_THEME_PAGODA + }; + return map[sceneryGroupType]; + } + + const char * GetWaterObject(uint8 waterType) + { + static const char * map[] = + { + "WTRCYAN ", + "WTRORNG ", + }; + return map[waterType]; + } + + const List GetPreferedRideEntryOrder(uint8 rideType) + { + static const List preferedRideEntryOrder[] = + { + { "SPDRCR "}, // RIDE_TYPE_SPIRAL_ROLLER_COASTER + { "TOGST "}, // RIDE_TYPE_STAND_UP_ROLLER_COASTER + { "ARRSW1 ", "VEKVAMP ", "ARRSW2 "}, // RIDE_TYPE_SUSPENDED_SWINGING_COASTER + { "NEMT "}, // RIDE_TYPE_INVERTED_ROLLER_COASTER + { "ZLDB ", "ZLOG "}, // RIDE_TYPE_JUNIOR_ROLLER_COASTER + { "NRL ", "NRL2 ", "AML1 ", "TRAM1 "}, // RIDE_TYPE_MINIATURE_RAILWAY + { "MONO1 ", "MONO2 ", "MONO3 "}, // RIDE_TYPE_MONORAIL + { "BATFL ", "SKYTR "}, // RIDE_TYPE_MINI_SUSPENDED_COASTER + { "RBOAT ", "BBOAT ", "CBOAT ", "SWANS ", "TRIKE ", "JSKI " }, // RIDE_TYPE_BOAT_RIDE + { "WMOUSE ", "WMMINE "}, // RIDE_TYPE_WOODEN_WILD_MOUSE + { "STEEP1 ", "STEEP2 ", "SBOX "}, // RIDE_TYPE_STEEPLECHASE + { "SPCAR ", "RCR ", "TRUCK1 ", "VCR ", "CTCAR " }, // RIDE_TYPE_CAR_RIDE + { "SSC1 " }, // RIDE_TYPE_LAUNCHED_FREEFALL + { "BOB1 ", "INTBOB " }, // RIDE_TYPE_BOBSLEIGH_COASTER + { "OBS1 ", "OBS2 " }, // RIDE_TYPE_OBSERVATION_TOWER + { "SCHT1 " }, // RIDE_TYPE_LOOPING_ROLLER_COASTER + { "DING1 " }, // RIDE_TYPE_DINGHY_SLIDE + { "AMT1 " }, // RIDE_TYPE_MINE_TRAIN_COASTER + { "CLIFT1 ", "CLIFT2 " }, // RIDE_TYPE_CHAIRLIFT + { "ARRT1 ", "ARRT2 " }, // RIDE_TYPE_CORKSCREW_ROLLER_COASTER + { }, // RIDE_TYPE_MAZE + { }, // RIDE_TYPE_SPIRAL_SLIDE + { "KART1 " }, // RIDE_TYPE_GO_KARTS + { "LFB1 " }, // RIDE_TYPE_LOG_FLUME + { "RAPBOAT " }, // RIDE_TYPE_RIVER_RAPIDS + { }, // RIDE_TYPE_DODGEMS + { }, // RIDE_TYPE_PIRATE_SHIP + { }, // RIDE_TYPE_SWINGING_INVERTER_SHIP + { }, // RIDE_TYPE_FOOD_STALL + { }, // RIDE_TYPE_1D + { }, // RIDE_TYPE_DRINK_STALL + { }, // RIDE_TYPE_1F + { }, // RIDE_TYPE_SHOP + { }, // RIDE_TYPE_MERRY_GO_ROUND + { }, // RIDE_TYPE_22 + { }, // RIDE_TYPE_INFORMATION_KIOSK + { }, // RIDE_TYPE_TOILETS + { }, // RIDE_TYPE_FERRIS_WHEEL + { }, // RIDE_TYPE_MOTION_SIMULATOR + { }, // RIDE_TYPE_3D_CINEMA + { }, // RIDE_TYPE_TOP_SPIN + { }, // RIDE_TYPE_SPACE_RINGS + { "REVF1 " }, // RIDE_TYPE_REVERSE_FREEFALL_COASTER + { "LIFT1 " }, // RIDE_TYPE_LIFT + { "BMVD " }, // RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER + { }, // RIDE_TYPE_CASH_MACHINE + { }, // RIDE_TYPE_TWIST + { }, // RIDE_TYPE_HAUNTED_HOUSE + { }, // RIDE_TYPE_FIRST_AID + { }, // RIDE_TYPE_CIRCUS_SHOW + { "GTC ", "HMCAR " }, // RIDE_TYPE_GHOST_TRAIN + { "BMSD ", "BMSU ", "BMFL ", "BMRB ", "GOLTR " }, // RIDE_TYPE_TWISTER_ROLLER_COASTER + { "PTCT1 ", "MFT ", "PTCT2 " }, // RIDE_TYPE_WOODEN_ROLLER_COASTER + { "SFRIC1 " }, // RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER + { "SMC1 ", "SMC2 ", "WMSPIN " }, // RIDE_TYPE_WILD_MOUSE + { "ARRX " }, // RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER + { }, // RIDE_TYPE_38 + { "BMAIR " }, // RIDE_TYPE_FLYING_ROLLER_COASTER + { }, // RIDE_TYPE_3A + { "VREEL " }, // RIDE_TYPE_VIRGINIA_REEL + { "SPBOAT " }, // RIDE_TYPE_SPLASH_BOATS + { "HELICAR " }, // RIDE_TYPE_MINI_HELICOPTERS + { "VEKST " }, // RIDE_TYPE_LAY_DOWN_ROLLER_COASTER + { "SMONO " }, // RIDE_TYPE_SUSPENDED_MONORAIL + { }, // RIDE_TYPE_40 + { "REVCAR " }, // RIDE_TYPE_REVERSER_ROLLER_COASTER + { "UTCAR ", "UTCARR " }, // RIDE_TYPE_HEARTLINE_TWISTER_COASTER + { }, // RIDE_TYPE_MINI_GOLF + { "INTST " }, // RIDE_TYPE_GIGA_COASTER + { "GDROP1 " }, // RIDE_TYPE_ROTO_DROP + { }, // RIDE_TYPE_FLYING_SAUCERS + { }, // RIDE_TYPE_CROOKED_HOUSE + { "MONBK " }, // RIDE_TYPE_MONORAIL_CYCLES + { "SLCT ", "SLCFO ", "VEKDV " }, // RIDE_TYPE_COMPACT_INVERTED_COASTER + { "CSTBOAT " }, // RIDE_TYPE_WATER_COASTER + { "THCAR " }, // RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER + { "IVMC1 " }, // RIDE_TYPE_INVERTED_HAIRPIN_COASTER + { }, // RIDE_TYPE_MAGIC_CARPET + { "SUBMAR " }, // RIDE_TYPE_SUBMARINE_RIDE + { "RFTBOAT " }, // RIDE_TYPE_RIVER_RAFTS + { }, // RIDE_TYPE_50 + { }, // RIDE_TYPE_ENTERPRISE + { }, // RIDE_TYPE_52 + { }, // RIDE_TYPE_53 + { }, // RIDE_TYPE_54 + { }, // RIDE_TYPE_55 + { "INTINV " }, // RIDE_TYPE_INVERTED_IMPULSE_COASTER + { "WCATC ", "RCKC ", "JSTAR1 " }, // RIDE_TYPE_MINI_ROLLER_COASTER + { "PMT1 " }, // RIDE_TYPE_MINE_RIDE + { "PREMT1 " }, // RIDE_TYPE_59 + }; // RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER + return preferedRideEntryOrder[rideType]; + } + + const List GetSceneryObjects(uint8 sceneryType) + { + static const List map[] = + { + // RCT1_SCENERY_THEME_GENERAL (trees, shrubs, garden, walls, fence, path accessories) + { "TIC ", "TLC ", "TMC ", "TMP ", "TITC ", "TGHC ", "TAC ", "TGHC2 ", "TCJ ", "TMBJ ", "TCF ", "TCL ", "TRF ", "TRF2 ", "TEL ", "TAP ", "TSP ", "TMZP ", "TCRP ", "TBP ", "TLP ", "TWP ", "TAS ", "TMG ", "TWW ", "TSB ", "TVL ", "TCY ", "TNS ", "TWN ", "TCE ", "TCO ", "THL ", "TCC ", "TF1 ", "TF2 ", "TCT ", "TH1 ", "TH2 ", "TPM ", "TROPT1 ", + "TS0 ", "TS1 ", "TS2 ", "TS3 ", "TS4 ", "TS5 ", "TS6 ", "TEF ", "TAL ", "TSQ ", "THT ", "TCB ", "TDM ", "TSD ", "TORN1 ", "TORN2 ", "TGS ", "TUS ", "TBC ", "TSC ", "TWF ", "TSH0 ", "TSH1 ", "TSH2 ", "TSH3 ", "TSH4 ", "TSH5 ", "TDF ", "TSH ", "THRS ", "TSTD ", "TBR ", "TTF ", "WHG ", "WHGG ", "WCH ", "WCHG ", + "TG1 ", "TG2 ", "TG3 ", "TG4 ", "TG5 ", "TG6 ", "TG7 ", "TG8 ", "TG9 ", "TG10 ", "TG11 ", "TG12 ", "TG13 ", "TG14 ", "TG15 ", "TG16 ", "TG17 ", "TG18 ", "TG19 ", "TG20 ", "TG21 ", + "WBR1A ", "WBR2A ", "WALLBB34", "WALLTN32", "TNTROOF1", "WALLBB33", "WALLBB32", "WALLBB16", "WALLBB8 ", "ROOF5 ", "ROOF7 ", "WALLRS32", "WALLRS16", "WALLRS8 ", "WALLBR32", "WALLBR16", "WALLBR8 ", "WALLBRDR", "WALLBRWN", "BRBASE ", "ROOF1 ", "ROOF2 ", "ROOF3 ", "ROOF4 ", "WALLCB32", "WALLCB16", "WALLCB8 ", "WALLCBDR", "WALLCBWN", "BRBASE2 ", "CWBCRV33", "CWBCRV32", "BRCRRF1 ", "ROOF6 ", "ROOF8 ", "WALLCF32", "WALLCF16", "WALLCF8 ", "WALLCFDR", "WALLCFWN", "WALLCFAR", "BRBASE3 ", "CWFCRV33", "CWFCRV32", "BRCRRF2 ", "ROOF9 ", "ROOF11 ", "ROOF10 ", "ROOF12 ", "CORROOF2", "WALLCO16", "CORROOF ", "WALLLT32", "WALLSK16", "WALLSK32", "SKTDW2 ", "SKTDW ", "SKTBASE ", "SKTBASET", "SUPPW2 ", "SUPPW1 ", "SUPPW3 ", "SUPPLEG1", "SUPPLEG2", "SUMRF ", "WALLRH32" + "WMF ", "WMFG ", "WSW ", "WSWG ", "WFW1 ", "WFWG ", "WPF ", "WPFG ", "WSW1 ", "WSW2 ", "WBR1 ", "WBRG ", "WBR2 ", "WBR3 ", "WALLMM16", "WALLMM17", + "LAMP1 ", "LAMP2 ", "LITTER1 ", "BENCH1 ", "QTV1 ", "BN1 ", "WALLPOST", "WALLSIGN", "SSIG1 ", "SSIG2 ", "SSIG3 ", "SSIG4 " }, + // RCT1_SCENERY_THEME_MINE + { "SMH1 ", "SMH2 ", "SMN1 ", "TBW ", "TBR1 ", "TBR2 ", "TML ", "TMW ", "TBR3 ", "TBR4 ", "TMJ ", "BN5 ", "WALLWD8 ", "WALLWD16", "WALLWD32", "WALLWD33", "WALLMN32", "WDBASE ", "MINROOF1", "ROOF13 ", "LITTERMN" }, + // RCT1_SCENERY_THEME_CLASSICAL_ROMAN + { "SCOL ", "TT1 ", "TRMS ", "TRWS ", "TRC ", "TQF ", "WRW ", "WRWA ", "ROMROOF2", "WC3 ", "ROMROOF1", "BN3 " }, + // RCT1_SCENERY_THEME_EGYPTIAN + { "SSPX ", "SCLN ", "SPYR ", "TES1 ", "TEN ", "TERS ", "TERB ", "TEP ", "WEW ", "LAMP3 ", "BN4 ", "BENCHSTN" }, + // RCT1_SCENERY_THEME_MARTIAN + { "SMB ", "TMO1 ", "TMO2 ", "TMO3 ", "TMO4 ", "TMO5 ", "SVLC ", "WMW ", "LAMP4 " }, + // RCT1_SCENERY_THEME_JUMPING_FOUNTAINS (Single researchable scenery item) + { "JUMPFNT1" }, + // RCT1_SCENERY_THEME_WONDERLAND + { "TWH1 ", "TWH2 ", "TST1 ", "TST2 ", "TMS1 ", "TST3 ", "TST4 ", "TST5 ", "TAS1 ", "TAS2 ", "TAS3 ", "TAS4 ", "CHBBASE ", "TP1 ", "TP2 ", "TK1 ", "TK2 ", "TR1 ", "TR2 ", "TQ1 ", "TQ2 ", "TB1 ", "TB2 ", "TK3 ", "TK4 ", "WCW1 ", "WCW2 " }, + // RCT1_SCENERY_THEME_JURASSIC + { "TBN ", "TBN1 ", "TDN4 ", "TDN5 ", "SDN1 ", "SDN2 ", "SDN3 ", "WWTW ", "WMWW ", "WWTWA ", "WBW ", "BN6 " }, + // RCT1_SCENERY_THEME_SPOOKY, + { "SSK1 ", "TDT1 ", "TDT2 ", "TDT3 ", "TMM1 ", "TMM2 ", "TMM3 ", "TGS1 ", "TGS2 ", "TGS3 ", "TGS4 ", "SMSKULL ", "WALLRK32" }, + // RCT1_SCENERY_THEME_JUNGLE + { "TJT1 ", "TJT2 ", "TJB1 ", "TJT3 ", "TJT4 ", "TJP1 ", "TJB2 ", "TJT5 ", "TJB3 ", "TJB4 ", "TJT6 ", "TJP2 ", "TJF ", "WPW1 ", "WPW2 ", "WJF ", "BN2 ", "WALLJN32", "JNGROOF1", "ROOF14 ", "BENCHLOG" }, + // RCT1_SCENERY_THEME_ABSTRACT + { "TGE1 ", "TGE2 ", "TGE3 ", "TGE4 ", "TGE5 ", "TGC1 ", "TGC2 ", "WALLGL8 ", "WALLGL16", "WALLGL32", "GEOROOF1", "WGW2 ", "GEOROOF2" }, + // RCT1_SCENERY_THEME_GARDEN_CLOCK (Single researchable scenery item) + { "TCK " }, + // RCT1_SCENERY_THEME_SNOW_ICE + { "SIP ", "TSM ", "TIG ", "TSF1 ", "TSF2 ", "TSF3 ", "TSNC ", "TSNB ", "WC16 ", "WC17 ", "WC18 ", "JUMPSNW1", "TCFS ", "TRFS ", "TRF3 ", "TNSS ", "BN8 ", "WALLIG16", "WALLIG24", "IGROOF " }, + // RCT1_SCENERY_THEME_MEDIEVAL + { "TCT1 ", "STB1 ", "STB2 ", "WC1 ", "WC4 ", "WC5 ", "WC6 ", "WC7 ", "WC8 ", "WALLCZ32", "WALLCY32", "TCT2 ", "STG1 ", "STG2 ", "WC2 ", "WC9 ", "WC10 ", "WC11 ", "WC12 ", "WC13 ", "WALLCW32", "WALLCX32", "TCN ", "TTG ", "SCT ", "SOH1 ", "SOH2 ", "SOH3 ", "WPW3 ", "WALLCFPC", "WALLCBPC" }, + // RCT1_SCENERY_THEME_SPACE + { "SSR ", "SST ", "SSH ", "TSCP ", "TSPH ", "TSC2 ", "TSP1 ", "TSP2 ", "WALLSP32", "SPCROOF1", "BN9 ", "BENCHSPC", "LITTERSP" }, + // RCT1_SCENERY_THEME_CREEPY + { "TCD ", "TSG ", "TSK ", "TGH1 ", "TGH2 ", "TSMP ", "SGP ", "WC14 ", "WC15 ", "TL0 ", "TL1 ", "TL2 ", "TL3 ", "TM0 ", "TM1 ", "TM2 ", "TM3 " }, + // RCT1_SCENERY_THEME_URBAN + { "SHS1 ", "SHS2 ", "STH ", "SAH ", "SPS ", "SAH2 ", "SAH3 ", "SOB ", "WALLU132", "WALLU232" }, + // RCT1_SCENERY_THEME_PAGODA + { "SPG ", "TLY ", "TGG ", "TOH1 ", "TOH2 ", "TOT1 ", "TOT2 ", "TOS ", "TOT3 ", "TOT4 ", "TOH3 ", "WALLPG32", "PAGROOF1", "BN7 " } + }; + return map[sceneryType]; + } +} diff --git a/src/rct2.c b/src/rct2.c index e862f2d89a..c1d274873c 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -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; +} \ 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/ride/track.c b/src/ride/track.c index 8fa3602930..19cf1890a1 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -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]; } 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; diff --git a/src/scenario.h b/src/scenario.h index bb480a41c0..500f9ab6c1 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -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]; diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index 1a6ba9b15d..847fb79efc 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -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; } diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index 80e3c756ed..46c4d01cdb 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -21,6 +21,7 @@ #ifndef _SAWYERCODING_H_ #define _SAWYERCODING_H_ +#include #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 diff --git a/src/windows/new_ride.c b/src/windows/new_ride.c index 4410bad6cf..ea38244d8f 100644 --- a/src/windows/new_ride.c +++ b/src/windows/new_ride.c @@ -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; } }