diff --git a/CMakeLists.txt b/CMakeLists.txt index 469ca4a1bc..10c5a523ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,9 +50,9 @@ set(OBJECTS_VERSION "1.2.1") set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip") set(OBJECTS_SHA1 "540e004abc683b3fe22211f5234e3d78ab023c5f") -set(REPLAYS_VERSION "0.0.49") +set(REPLAYS_VERSION "0.0.52") set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip") -set(REPLAYS_SHA1 "004AE4D38D1326913AF5DE7A90E8AF31DD31BF94") +set(REPLAYS_SHA1 "3A1A6B5B25ACA3B8AADC618A9D2BE44F8A23A7BB") option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.") option(WITH_TESTS "Build tests") diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 257c0ab0b4..adf52c7946 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -802,6 +802,7 @@ 258C212125F84FA2B4C3BCAE /* RideUseSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58DEACC694664E7C8DACB93D /* RideUseSystem.cpp */; }; E6C71B6165224F65AA87E65B /* RideUseSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DA720D496604387806AC168 /* RideUseSystem.h */; }; C8D612EB56BD4214BEC0F7FF /* GroupVector.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F4D523B8782E4C458AF1490D /* GroupVector.hpp */; }; + B2F44E535BD14A03BE8B9D14 /* ZipStream.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F28A181D311D4E078FDB090C /* ZipStream.hpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1688,7 +1689,6 @@ F76C838B1EC4E7CC00FA49E2 /* Memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Memory.hpp; sourceTree = ""; }; F76C838C1EC4E7CC00FA49E2 /* MemoryStream.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryStream.cpp; sourceTree = ""; }; F76C838D1EC4E7CC00FA49E2 /* MemoryStream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MemoryStream.h; sourceTree = ""; }; - F76C838E1EC4E7CC00FA49E2 /* Nullable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Nullable.hpp; sourceTree = ""; }; F76C838F1EC4E7CC00FA49E2 /* Path.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Path.cpp; sourceTree = ""; }; F76C83901EC4E7CC00FA49E2 /* Path.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Path.hpp; sourceTree = ""; }; F76C83921EC4E7CC00FA49E2 /* String.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = ""; }; @@ -1908,6 +1908,7 @@ 58DEACC694664E7C8DACB93D /* RideUseSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RideUseSystem.cpp; path = src/openrct2/peep/RideUseSystem.cpp; sourceTree = SOURCE_ROOT; }; 2DA720D496604387806AC168 /* RideUseSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RideUseSystem.h; path = src/openrct2/peep/RideUseSystem.h; sourceTree = SOURCE_ROOT; }; F4D523B8782E4C458AF1490D /* GroupVector.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = GroupVector.hpp; path = src/openrct2/core/GroupVector.hpp; sourceTree = SOURCE_ROOT; }; + F28A181D311D4E078FDB090C /* ZipStream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZipStream.hpp; path = src/openrct2/core/ZipStream.hpp; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -2581,6 +2582,7 @@ F76C839A1EC4E7CC00FA49E2 /* Zip.h */, BA2317BF6FB54E328DEB7055 /* EnumMap.hpp */, F4D523B8782E4C458AF1490D /* GroupVector.hpp */, + F28A181D311D4E078FDB090C /* ZipStream.hpp */, ); path = core; sourceTree = ""; @@ -3662,6 +3664,7 @@ DEC539DE402F4B8993E4C357 /* ScTileElement.hpp in Headers */, E6C71B6165224F65AA87E65B /* RideUseSystem.h in Headers */, C8D612EB56BD4214BEC0F7FF /* GroupVector.hpp in Headers */, + B2F44E535BD14A03BE8B9D14 /* ZipStream.hpp in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/contributors.md b/contributors.md index b12d3c4d21..302be0ee29 100644 --- a/contributors.md +++ b/contributors.md @@ -176,6 +176,7 @@ The following people are not part of the development team, but have been contrib * Kane Shaw (seifer7) * Saad Rehman (SaadRehmanCS) * (ocalhoun6) +* Sean Payne (seanmajorpayne) ## Toolchain * (Balletie) - macOS diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 9eb16b3d9d..2768444a80 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3651,6 +3651,8 @@ STR_6453 :Copy version info STR_6454 :Can’t rename banner… STR_6455 :Can’t rename sign… STR_6456 :Giant Screenshot +STR_6457 :Report a bug on GitHub +STR_6458 :Follow this on Main View ############# # Scenarios # diff --git a/data/language/eo-OO.txt b/data/language/eo-OO.txt index c516132598..f5d4b63906 100644 --- a/data/language/eo-OO.txt +++ b/data/language/eo-OO.txt @@ -3654,6 +3654,7 @@ STR_6453 :Kopii informojn de versio STR_6454 :Ne povas renomi rubandon… STR_6455 :Ne povas renomi surskribaĵon… STR_6456 :Giganta Ekrankopio +STR_6457 :Raporti cimon sur GitHub ############# # Scenarios # diff --git a/data/language/fi-FI.txt b/data/language/fi-FI.txt index 0df643a943..4607f77fb4 100644 --- a/data/language/fi-FI.txt +++ b/data/language/fi-FI.txt @@ -3660,6 +3660,8 @@ STR_6452 :{WINDOW_COLOUR_2}Myy: {BLACK}{STRING} STR_6453 :Kopioi versiotiedot STR_6454 :Banneria ei voi uudelleennimetä… STR_6455 :Kylttiä ei voi uudelleennimetä… +STR_6456 :Jättiruudunkaappaus +STR_6457 :Ilmoita viasta GitHubissa ############# # Scenarios # diff --git a/data/language/fr-FR.txt b/data/language/fr-FR.txt index 37fd6ffb0f..b3ddbd05ea 100644 --- a/data/language/fr-FR.txt +++ b/data/language/fr-FR.txt @@ -3661,6 +3661,7 @@ STR_6453 :Copier les informations de version STR_6454 :Impossible de renommer la bannière… STR_6455 :Impossible de renommer le panneau… STR_6456 :Capture d’écran géante +STR_6457 :Signaler un bug sur GitHub ############# # Scenarios # diff --git a/data/language/ko-KR.txt b/data/language/ko-KR.txt index 2e57f042b9..5224b36576 100644 --- a/data/language/ko-KR.txt +++ b/data/language/ko-KR.txt @@ -412,7 +412,7 @@ STR_1023 :1대당 차량 {POP16}{POP16}{POP16}{COMMA16}개 STR_1024 :1대당 차량 {COMMA16}개 STR_1025 :1대당 차량 {COMMA16}개 STR_1026 :탑승장이 너무 깁니다! -STR_1027 :여기로 이동합니다 +STR_1027 :이동 STR_1028 :지도 끝을 벗어납니다! STR_1029 :일부분만 수면 위로 나오도록 건설할 수 없습니다! STR_1030 :수중에만 건설할 수 있습니다! @@ -3657,6 +3657,8 @@ STR_6453 :버전 정보 복사 STR_6454 :팻말 이름을 변경할 수 없습니다… STR_6455 :팻말 이름을 변경할 수 없습니다… STR_6456 :초대형 스크린 샷 +STR_6457 :GitHub에 버그 제보 +STR_6458 :따라가기 ############# # Scenarios # @@ -3963,8 +3965,8 @@ STR_DTLS :파라다이스 부두는 바다 위의 산책로를 확장했습 STR_SCNR :Dragon’s Cove -STR_PARK :용의 동굴 -STR_DTLS :이번 롤러코스터 건설 도전에서는 해안 동굴이 무대가 됩니다. +STR_PARK :용의 만 +STR_DTLS :이번 롤러코스터 건설 도전에서는 바닷가 근처의 만이 무대가 됩니다. STR_SCNR :Good Knight Park diff --git a/data/language/nl-NL.txt b/data/language/nl-NL.txt index 9faa62b71a..1b022c114a 100644 --- a/data/language/nl-NL.txt +++ b/data/language/nl-NL.txt @@ -809,7 +809,7 @@ STR_1423 :Wachtrijpad STR_1424 :Voetpad STR_1425 :Voetpad STR_1426 :Wachtrij -STR_1427 :{WINDOW_COLOUR_2}Passagiers: {BLACK}{COMMA32} per uur +STR_1427 :{WINDOW_COLOUR_2}Bezoekers: {BLACK}{COMMA32} per uur STR_1428 :{WINDOW_COLOUR_2}Toegangsprijs: STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} STR_1430 :Gratis @@ -2969,9 +2969,9 @@ STR_5731 :Lineair STR_5734 :Rendering STR_5735 :Netwerkstatus STR_5736 :Speler -STR_5737 :Gesloten, nog {COMMA16} passagier -STR_5738 :Gesloten, nog {COMMA16} passagiers -STR_5739 :{WINDOW_COLOUR_2}Huidig aantal passagiers: {BLACK}{COMMA16} +STR_5737 :Gesloten, nog {COMMA16} bezoeker +STR_5738 :Gesloten, nog {COMMA16} bezoekers +STR_5739 :{WINDOW_COLOUR_2}Huidig aantal bezoekers: {BLACK}{COMMA16} STR_5740 :Oneindige marketingcampagnes STR_5741 :Marketingcampagnes verlopen nooit STR_5742 :Authenticeren… diff --git a/data/language/pt-BR.txt b/data/language/pt-BR.txt index 34266b9163..ab507675e4 100644 --- a/data/language/pt-BR.txt +++ b/data/language/pt-BR.txt @@ -3654,6 +3654,8 @@ STR_6453 :Copiar informações da versão STR_6454 :Não é possível renomear o banner… STR_6455 :Não é possível renomear a placa… STR_6456 :Captura Gigante de Tela +STR_6457 :Relatar um problema pelo GitHub +STR_6458 :Seguir isto na Visão Principal ############# # Scenarios # diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 564b7fc02b..160dcffa53 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,14 +1,19 @@ 0.3.4.1+ (in development) ------------------------------------------------------------------------ - Feature: [#3868] Initial support for using TTF in OpenGL mode (still contains bugs). +- Feature: [#7682] Follow ride/guest/staff in main window viewport. +- Feature: [#13407] Allow building chain lifts on enclosed dinghy slide pieces when cheats are on. - Feature: [#15084] [Plugin] Add "vehicle.crash" hook. - Feature: [#15143] Added a shortcut key for Giant Screenshot. - Feature: [#15164] Highlight elements selected by the Tile Inspector, tracks are currently not supported. - Feature: [#15165] [Plugin] Add the ability to create entities using "map.createEntity". - Feature: [#15194] [Plugin] Add guest properties, ride downtime and park casualty penalty. -- Feature: [#15294] New vehicle animation type: flying animal +- Feature: [#15195] Added a bug-report item in file dropdown menu. +- Feature: [#15294] New vehicle animation type: flying animal. - Fix: [#13465] Creating a scenario based on a won save game results in a scenario that’s instantly won. +- Fix: [#13912] “Dome park” no longer renders dome correctly. - Fix: [#14316] Closing the Track Designs Manager window causes broken state. +- Fix: [#14649] ImageImporter incorrectly remaps colours outside the RCT2 palette. - Fix: [#14667] “Extreme Hawaiian Island” has unpurchaseable land tiles (original bug). - Fix: [#15096] Crash when placing entrances in the scenario editor near the map corner. - Fix: [#15142] ToonTowner's mine roofs were moved into the pirate theme scenery group instead of the mine theme scenery group. @@ -18,6 +23,7 @@ - Fix: [#15193] Crash when rides/stalls are demolished. - Fix: [#15199] Construction window is not closed when a ride gets demolished. - Fix: [#15255] Tile Inspector shows banner information on walls that do not contain one. +- Fix: [#15257] Chat icon shows in scenario/track editor. Other icons don't disable when deactivated in options menu. - Fix: [#15289] Unexpected behavior with duplicated banners which also caused desyncs in multiplayer. - Improved: [#3417] Crash dumps are now placed in their own folder. - Change: [#8601] Revert ToonTower base block fix to re-enable support blocking. diff --git a/openrct2.common.props b/openrct2.common.props index 49e0395b7c..fb2f6a188f 100644 --- a/openrct2.common.props +++ b/openrct2.common.props @@ -74,6 +74,7 @@ MultiThreadedDebug MultiThreadedDebugDLL false + true DebugFull @@ -90,6 +91,7 @@ false NDEBUG;%(PreprocessorDefinitions) Speed + true DebugFull diff --git a/openrct2.proj b/openrct2.proj index 92c3f85094..2dad3d4aec 100644 --- a/openrct2.proj +++ b/openrct2.proj @@ -48,8 +48,8 @@ 304d13a126c15bf2c86ff13b81a2f2cc1856ac8d https://github.com/OpenRCT2/objects/releases/download/v1.2.1/objects.zip 540e004abc683b3fe22211f5234e3d78ab023c5f - https://github.com/OpenRCT2/replays/releases/download/v0.0.49/replays.zip - 004AE4D38D1326913AF5DE7A90E8AF31DD31BF94 + https://github.com/OpenRCT2/replays/releases/download/v0.0.52/replays.zip + 3A1A6B5B25ACA3B8AADC618A9D2BE44F8A23A7BB diff --git a/src/openrct2-ui/WindowManager.cpp b/src/openrct2-ui/WindowManager.cpp index 112d8d4e3f..0af8b13393 100644 --- a/src/openrct2-ui/WindowManager.cpp +++ b/src/openrct2-ui/WindowManager.cpp @@ -184,9 +184,9 @@ public: case WD_BANNER: return window_banner_open(id); case WD_DEMOLISH_RIDE: - return window_ride_demolish_prompt_open(get_ride(id)); + return window_ride_demolish_prompt_open(get_ride(static_cast(id))); case WD_REFURBISH_RIDE: - return window_ride_refurbish_prompt_open(get_ride(id)); + return window_ride_refurbish_prompt_open(get_ride(static_cast(id))); case WD_NEW_CAMPAIGN: return window_new_campaign_open(id); case WD_SIGN: @@ -264,7 +264,8 @@ public: } case WC_RIDE: { - auto ride = get_ride(intent->GetSIntExtra(INTENT_EXTRA_RIDE_ID)); + const auto rideId = static_cast(intent->GetSIntExtra(INTENT_EXTRA_RIDE_ID)); + auto ride = get_ride(rideId); return ride == nullptr ? nullptr : window_ride_main_open(ride); } case WC_TRACK_DESIGN_PLACE: @@ -343,13 +344,13 @@ public: if (w == nullptr || w->number != rideIndex) { window_close_construction_windows(); - _currentRideIndex = rideIndex; + _currentRideIndex = static_cast(rideIndex); w = OpenWindow(WC_RIDE_CONSTRUCTION); } else { ride_construction_invalidate_current_track(); - _currentRideIndex = rideIndex; + _currentRideIndex = static_cast(rideIndex); } break; } @@ -395,7 +396,7 @@ public: case INTENT_ACTION_INVALIDATE_VEHICLE_WINDOW: { auto vehicle = static_cast(intent.GetPointerExtra(INTENT_EXTRA_VEHICLE)); - auto w = window_find_by_number(WC_RIDE, vehicle->ride); + auto w = window_find_by_number(WC_RIDE, EnumValue(vehicle->ride)); if (w == nullptr) return; diff --git a/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp b/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp index b762f293ec..11fe0029c8 100644 --- a/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp @@ -221,10 +221,10 @@ void TextureCache::GeneratePaletteTexture() GLint y = PaletteToY(static_cast(i)); auto g1Index = GetPaletteG1Index(i); - if (g1Index) + if (g1Index.has_value()) { - auto element = gfx_get_g1_element(*g1Index); - gfx_draw_sprite_software(&dpi, ImageId(*g1Index), { -element->x_offset, y - element->y_offset }); + auto element = gfx_get_g1_element(g1Index.value()); + gfx_draw_sprite_software(&dpi, ImageId(g1Index.value()), { -element->x_offset, y - element->y_offset }); } } diff --git a/src/openrct2-ui/input/ShortcutInput.cpp b/src/openrct2-ui/input/ShortcutInput.cpp index 0e22095bba..c1a4c0f1a8 100644 --- a/src/openrct2-ui/input/ShortcutInput.cpp +++ b/src/openrct2-ui/input/ShortcutInput.cpp @@ -152,11 +152,11 @@ ShortcutInput::ShortcutInput(std::string_view value) else { auto number = String::Parse(rem); - if (number) + if (number.has_value()) { Kind = InputDeviceKind::JoyButton; Modifiers = modifiers; - Button = *number - 1; + Button = number.value() - 1; } } } diff --git a/src/openrct2-ui/input/ShortcutManager.cpp b/src/openrct2-ui/input/ShortcutManager.cpp index 6b53a5d39d..b6d59fa0db 100644 --- a/src/openrct2-ui/input/ShortcutManager.cpp +++ b/src/openrct2-ui/input/ShortcutManager.cpp @@ -167,10 +167,10 @@ void ShortcutManager::ProcessEvent(const InputEvent& e) if (shortcut != nullptr && shortcut->IsSuitableInputEvent(e)) { auto shortcutInput = ShortcutInput::FromInputEvent(e); - if (shortcutInput) + if (shortcutInput.has_value()) { shortcut->Current.clear(); - shortcut->Current.push_back(std::move(*shortcutInput)); + shortcut->Current.push_back(std::move(shortcutInput.value())); } _pendingShortcutChange.clear(); window_close_by_class(WC_CHANGE_KEYBOARD_SHORTCUT); @@ -234,23 +234,21 @@ std::optional ShortcutManager::ConvertLegacyBinding(uint16_t bind if (binding == nullBinding) { - return {}; - } - else - { - ShortcutInput result; - result.Kind = InputDeviceKind::Keyboard; - if (binding & shift) - result.Modifiers |= KMOD_SHIFT; - if (binding & ctrl) - result.Modifiers |= KMOD_CTRL; - if (binding & alt) - result.Modifiers |= KMOD_ALT; - if (binding & cmd) - result.Modifiers |= KMOD_GUI; - result.Button = SDL_GetKeyFromScancode(static_cast(binding & 0xFF)); - return result; + return std::nullopt; } + + ShortcutInput result; + result.Kind = InputDeviceKind::Keyboard; + if (binding & shift) + result.Modifiers |= KMOD_SHIFT; + if (binding & ctrl) + result.Modifiers |= KMOD_CTRL; + if (binding & alt) + result.Modifiers |= KMOD_ALT; + if (binding & cmd) + result.Modifiers |= KMOD_GUI; + result.Button = SDL_GetKeyFromScancode(static_cast(binding & 0xFF)); + return result; } void ShortcutManager::LoadLegacyBindings(const fs::path& path) @@ -273,9 +271,9 @@ void ShortcutManager::LoadLegacyBindings(const fs::path& path) { shortcut->Current.clear(); auto input = ConvertLegacyBinding(value); - if (input) + if (input.has_value()) { - shortcut->Current.push_back(std::move(*input)); + shortcut->Current.push_back(std::move(input.value())); } } } diff --git a/src/openrct2-ui/interface/ViewportInteraction.cpp b/src/openrct2-ui/interface/ViewportInteraction.cpp index 24f5914c2e..9b77d36303 100644 --- a/src/openrct2-ui/interface/ViewportInteraction.cpp +++ b/src/openrct2-ui/interface/ViewportInteraction.cpp @@ -375,7 +375,7 @@ InteractionInfo ViewportInteractionGetItemRight(const ScreenCoordsXY& screenCoor stationIndex = tileElement->AsTrack()->GetStationIndex(); for (i = stationIndex; i >= 0; i--) - if (ride->stations[i].Start.isNull()) + if (ride->stations[i].Start.IsNull()) stationIndex--; stationIndex++; ft.Add(stationIndex); @@ -761,7 +761,7 @@ CoordsXY ViewportInteractionGetTileStartAtCursor(const ScreenCoordsXY& screenCoo if (window == nullptr || window->viewport == nullptr) { CoordsXY ret{}; - ret.setNull(); + ret.SetNull(); return ret; } auto viewport = window->viewport; @@ -771,7 +771,7 @@ CoordsXY ViewportInteractionGetTileStartAtCursor(const ScreenCoordsXY& screenCoo if (info.SpriteType == ViewportInteractionItem::None) { - initialPos.setNull(); + initialPos.SetNull(); return initialPos; } diff --git a/src/openrct2-ui/scripting/ScTileSelection.hpp b/src/openrct2-ui/scripting/ScTileSelection.hpp index 850d180378..365c99f91c 100644 --- a/src/openrct2-ui/scripting/ScTileSelection.hpp +++ b/src/openrct2-ui/scripting/ScTileSelection.hpp @@ -139,7 +139,6 @@ namespace OpenRCT2::Scripting private: static std::optional GetCoordsXY(const DukValue& dukCoords) { - std::optional result; if (dukCoords.type() == DukValue::Type::OBJECT) { auto dukX = dukCoords["x"]; @@ -148,16 +147,15 @@ namespace OpenRCT2::Scripting auto dukY = dukCoords["y"]; if (dukY.type() == DukValue::Type::NUMBER) { - result = { dukX.as_int(), dukY.as_int() }; + return CoordsXY(dukX.as_int(), dukY.as_int()); } } } - return result; + return std::nullopt; } static std::optional GetMapRange(const DukValue& dukMapRange) { - std::optional result; if (dukMapRange.type() == DukValue::Type::OBJECT) { auto leftTop = GetCoordsXY(dukMapRange["leftTop"]); @@ -166,11 +164,11 @@ namespace OpenRCT2::Scripting auto rightBottom = GetCoordsXY(dukMapRange["rightBottom"]); if (rightBottom.has_value()) { - result = MapRange(leftTop->x, leftTop->y, rightBottom->x, rightBottom->y); + return MapRange(leftTop->x, leftTop->y, rightBottom->x, rightBottom->y); } } } - return result; + return std::nullopt; } }; } // namespace OpenRCT2::Scripting diff --git a/src/openrct2-ui/scripting/ScTitleSequence.hpp b/src/openrct2-ui/scripting/ScTitleSequence.hpp index a51742e577..0d9e80db33 100644 --- a/src/openrct2-ui/scripting/ScTitleSequence.hpp +++ b/src/openrct2-ui/scripting/ScTitleSequence.hpp @@ -248,7 +248,7 @@ namespace OpenRCT2::Scripting return i; } } - return {}; + return std::nullopt; } }; @@ -489,7 +489,7 @@ namespace OpenRCT2::Scripting return i; } } - return {}; + return std::nullopt; } const TitleSequenceManagerItem* GetItem() const diff --git a/src/openrct2-ui/windows/DemolishRidePrompt.cpp b/src/openrct2-ui/windows/DemolishRidePrompt.cpp index 395bd145cf..94fc63ea8a 100644 --- a/src/openrct2-ui/windows/DemolishRidePrompt.cpp +++ b/src/openrct2-ui/windows/DemolishRidePrompt.cpp @@ -84,7 +84,7 @@ rct_window* window_ride_demolish_prompt_open(Ride* ride) w->widgets = window_ride_demolish_widgets; w->enabled_widgets = (1ULL << WIDX_CLOSE) | (1ULL << WIDX_CANCEL) | (1ULL << WIDX_DEMOLISH); WindowInitScrollWidgets(w); - w->number = ride->id; + w->rideId = ride->id; _demolishRideCost = -ride_get_refund_price(ride); return w; @@ -109,7 +109,7 @@ rct_window* window_ride_refurbish_prompt_open(Ride* ride) w->widgets = window_ride_refurbish_widgets; w->enabled_widgets = (1ULL << WIDX_CLOSE) | (1ULL << WIDX_CANCEL) | (1ULL << WIDX_REFURBISH); WindowInitScrollWidgets(w); - w->number = ride->id; + w->rideId = ride->id; _demolishRideCost = -ride_get_refund_price(ride); return w; @@ -125,7 +125,7 @@ static void window_ride_demolish_mouseup(rct_window* w, rct_widgetindex widgetIn { case WIDX_DEMOLISH: { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); ride_action_modify(ride, RIDE_MODIFY_DEMOLISH, GAME_COMMAND_FLAG_APPLY); break; } @@ -142,7 +142,7 @@ static void window_ride_refurbish_mouseup(rct_window* w, rct_widgetindex widgetI { case WIDX_REFURBISH: { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); ride_action_modify(ride, RIDE_MODIFY_RENEW, GAME_COMMAND_FLAG_APPLY); break; } @@ -161,7 +161,7 @@ static void window_ride_demolish_paint(rct_window* w, rct_drawpixelinfo* dpi) { WindowDrawWidgets(w, dpi); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { auto stringId = (gParkFlags & PARK_FLAGS_NO_MONEY) ? STR_DEMOLISH_RIDE_ID : STR_DEMOLISH_RIDE_ID_MONEY; @@ -178,7 +178,7 @@ static void window_ride_refurbish_paint(rct_window* w, rct_drawpixelinfo* dpi) { WindowDrawWidgets(w, dpi); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { auto stringId = (gParkFlags & PARK_FLAGS_NO_MONEY) ? STR_REFURBISH_RIDE_ID_NO_MONEY : STR_REFURBISH_RIDE_ID_MONEY; diff --git a/src/openrct2-ui/windows/EditorMain.cpp b/src/openrct2-ui/windows/EditorMain.cpp index 2df57c7f7a..d38822ea9a 100644 --- a/src/openrct2-ui/windows/EditorMain.cpp +++ b/src/openrct2-ui/windows/EditorMain.cpp @@ -47,7 +47,7 @@ rct_window* window_editor_main_open() gShowGridLinesRefCount = 0; gShowLandRightsRefCount = 0; gShowConstuctionRightsRefCount = 0; - window_footpath_reset_selected_path(); + WindowFootpathResetSelectedPath(); context_open_window(WC_TOP_TOOLBAR); context_open_window_view(WV_EDITOR_BOTTOM_TOOLBAR); diff --git a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp index bd3c0357ae..5bd5919deb 100644 --- a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp +++ b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp @@ -972,7 +972,7 @@ static void window_editor_objective_options_rides_update(rct_window* w) { if (ride.IsRide()) { - w->list_item_positions[numItems] = ride.id; + w->list_item_positions[numItems] = EnumValue(ride.id); numItems++; } } @@ -1005,7 +1005,8 @@ static void window_editor_objective_options_rides_scrollmousedown( if (i < 0 || i >= w->no_list_items) return; - auto ride = get_ride(w->list_item_positions[i]); + const auto rideId = static_cast(w->list_item_positions[i]); + auto ride = get_ride(rideId); if (ride != nullptr) { ride->lifecycle_flags ^= RIDE_LIFECYCLE_INDESTRUCTIBLE; @@ -1098,7 +1099,8 @@ static void window_editor_objective_options_rides_scrollpaint(rct_window* w, rct } // Checkbox mark - auto ride = get_ride(w->list_item_positions[i]); + const auto rideId = static_cast(w->list_item_positions[i]); + auto ride = get_ride(rideId); if (ride != nullptr) { if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE) diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index 1e26d77843..17a25eb1f1 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -41,6 +41,8 @@ static uint8_t _footpathConstructionMode; static std::vector> _dropdownEntries; +static PathConstructFlags FootpathCreateConstructFlags(ObjectEntryIndex& type); + // clang-format off enum { @@ -49,12 +51,6 @@ enum PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL }; -enum -{ - SELECTED_PATH_TYPE_NORMAL, - SELECTED_PATH_TYPE_QUEUE -}; - enum WINDOW_FOOTPATH_WIDGET_IDX { WIDX_BACKGROUND, @@ -187,7 +183,7 @@ static void window_footpath_construct(); static void window_footpath_remove(); static void window_footpath_set_enabled_and_pressed_widgets(); static void footpath_get_next_path_info(ObjectEntryIndex* type, CoordsXYZ& footpathLoc, int32_t* slope); -static bool footpath_select_default(); +static bool FootpathSelectDefault(); /** * @@ -195,7 +191,7 @@ static bool footpath_select_default(); */ rct_window* window_footpath_open() { - if (!footpath_select_default()) + if (!FootpathSelectDefault()) { // No path objects to select from, don't open window return nullptr; @@ -451,8 +447,6 @@ static void window_footpath_toolup(rct_window* w, rct_widgetindex widgetIndex, c */ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window* w) { - int32_t slope; - if (_footpathConstructionMode != PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) { return; @@ -472,15 +466,9 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window* ObjectEntryIndex railings = gFootpathSelection.Railings; CoordsXYZ footpathLoc; + int32_t slope; footpath_get_next_path_info(&type, footpathLoc, &slope); - PathConstructFlags pathConstructFlags = 0; - if (gFootpathSelection.IsQueueSelected) - pathConstructFlags |= PathConstructFlag::IsQueue; - if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL) - { - pathConstructFlags |= PathConstructFlag::IsPathObject; - type = gFootpathSelection.LegacyPath; - } + auto pathConstructFlags = FootpathCreateConstructFlags(type); _window_footpath_cost = footpath_provisional_set(type, railings, footpathLoc, slope, pathConstructFlags); widget_invalidate(w, WIDX_CONSTRUCT); @@ -495,6 +483,7 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window* gProvisionalFootpath.Flags ^= PROVISIONAL_PATH_FLAG_SHOW_ARROW; CoordsXYZ footpathLoc; + int32_t slope; footpath_get_next_path_info(nullptr, footpathLoc, &slope); gMapSelectArrowPosition = footpathLoc; gMapSelectArrowDirection = _footpathConstructDirection; @@ -581,13 +570,13 @@ static void window_footpath_invalidate(rct_window* w) // Set footpath and queue type button images auto pathImage = static_cast(SPR_NONE); auto queueImage = static_cast(SPR_NONE); - auto pathEntry = get_path_surface_entry(gFootpathSelection.NormalSurface); + auto pathEntry = GetPathSurfaceEntry(gFootpathSelection.NormalSurface); if (pathEntry != nullptr) { pathImage = pathEntry->PreviewImageId; } - pathEntry = get_path_surface_entry(gFootpathSelection.QueueSurface); + pathEntry = GetPathSurfaceEntry(gFootpathSelection.QueueSurface); if (pathEntry != nullptr) { queueImage = pathEntry->PreviewImageId; @@ -598,7 +587,7 @@ static void window_footpath_invalidate(rct_window* w) // Set railing auto railingsImage = static_cast(SPR_NONE); - auto railingsEntry = get_path_railings_entry(gFootpathSelection.Railings); + auto railingsEntry = GetPathRailingsEntry(gFootpathSelection.Railings); if (railingsEntry != nullptr) { railingsImage = railingsEntry->PreviewImageId; @@ -657,7 +646,7 @@ static void window_footpath_paint(rct_window* w, rct_drawpixelinfo* dpi) if (gFootpathSelection.LegacyPath == OBJECT_ENTRY_INDEX_NULL) { auto selectedPath = gFootpathSelection.GetSelectedSurface(); - const auto* pathType = get_path_surface_entry(selectedPath); + const auto* pathType = GetPathSurfaceEntry(selectedPath); if (pathType != nullptr) { baseImage = pathType->BaseImageId; @@ -793,7 +782,7 @@ static void window_footpath_show_railings_types_dialog(rct_window* w, rct_widget std::optional defaultIndex; for (int32_t i = 0; i < MAX_FOOTPATH_RAILINGS_OBJECTS; i++) { - const auto* railingsEntry = get_path_railings_entry(i); + const auto* railingsEntry = GetPathRailingsEntry(i); if (railingsEntry == nullptr) { continue; @@ -911,17 +900,8 @@ static void window_footpath_set_provisional_path_at_point(const ScreenCoordsXY& z += PATH_HEIGHT_STEP; } - PathConstructFlags constructFlags = 0; auto pathType = gFootpathSelection.GetSelectedSurface(); - if (gFootpathSelection.IsQueueSelected) - { - constructFlags |= PathConstructFlag::IsQueue; - } - if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL) - { - constructFlags |= PathConstructFlag::IsPathObject; - pathType = gFootpathSelection.LegacyPath; - } + auto constructFlags = FootpathCreateConstructFlags(pathType); _window_footpath_cost = footpath_provisional_set( pathType, gFootpathSelection.Railings, { info.Loc, z }, slope, constructFlags); window_invalidate_by_class(WC_FOOTPATH); @@ -942,7 +922,7 @@ static void window_footpath_set_selection_start_bridge_at_point(const ScreenCoor gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW; auto mapCoords = footpath_bridge_get_info_from_pos(screenCoords, &direction, &tileElement); - if (mapCoords.isNull()) + if (mapCoords.IsNull()) { return; } @@ -1020,16 +1000,8 @@ static void window_footpath_place_path_at_point(const ScreenCoordsXY& screenCoor // Try and place path gGameCommandErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE; auto selectedType = gFootpathSelection.GetSelectedSurface(); - PathConstructFlags constructFlags = 0; - if (gFootpathSelection.IsQueueSelected) - { - constructFlags |= PathConstructFlag::IsQueue; - } - if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL) - { - constructFlags |= PathConstructFlag::IsPathObject; - selectedType = gFootpathSelection.LegacyPath; - } + PathConstructFlags constructFlags = FootpathCreateConstructFlags(selectedType); + auto footpathPlaceAction = FootpathPlaceAction( { info.Loc, z }, slope, selectedType, gFootpathSelection.Railings, INVALID_DIRECTION, constructFlags); footpathPlaceAction.SetCallback([](const GameAction* ga, const GameActions::Result* result) { @@ -1059,7 +1031,7 @@ static void window_footpath_start_bridge_at_point(const ScreenCoordsXY& screenCo TileElement* tileElement; auto mapCoords = footpath_bridge_get_info_from_pos(screenCoords, &direction, &tileElement); - if (mapCoords.isNull()) + if (mapCoords.IsNull()) { return; } @@ -1121,14 +1093,8 @@ static void window_footpath_construct() footpath_get_next_path_info(&type, footpathLoc, &slope); gGameCommandErrorTitle = STR_CANT_BUILD_FOOTPATH_HERE; - PathConstructFlags constructFlags = 0; - if (gFootpathSelection.IsQueueSelected) - constructFlags |= PathConstructFlag::IsQueue; - if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL) - { - constructFlags |= PathConstructFlag::IsPathObject; - type = gFootpathSelection.LegacyPath; - } + PathConstructFlags constructFlags = FootpathCreateConstructFlags(type); + auto footpathPlaceAction = FootpathPlaceAction( footpathLoc, slope, type, gFootpathSelection.Railings, _footpathConstructDirection, constructFlags); footpathPlaceAction.SetCallback([=](const GameAction* ga, const GameActions::Result* result) { @@ -1388,12 +1354,12 @@ static void footpath_get_next_path_info(ObjectEntryIndex* type, CoordsXYZ& footp } } -static ObjectEntryIndex footpath_get_default_surface(bool queue) +static ObjectEntryIndex FootpathGetDefaultSurface(bool queue) { bool showEditorPaths = ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode); for (ObjectEntryIndex i = 0; i < MAX_FOOTPATH_SURFACE_OBJECTS; i++) { - auto pathEntry = get_path_surface_entry(i); + auto pathEntry = GetPathSurfaceEntry(i); if (pathEntry != nullptr) { if (!showEditorPaths && (pathEntry->Flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR)) @@ -1409,11 +1375,11 @@ static ObjectEntryIndex footpath_get_default_surface(bool queue) return OBJECT_ENTRY_INDEX_NULL; } -static ObjectEntryIndex footpath_get_default_railing() +static ObjectEntryIndex FootpathGetDefaultRailings() { for (ObjectEntryIndex i = 0; i < MAX_FOOTPATH_RAILINGS_OBJECTS; i++) { - const auto* railingEntry = get_path_railings_entry(i); + const auto* railingEntry = GetPathRailingsEntry(i); if (railingEntry != nullptr) { return i; @@ -1422,9 +1388,9 @@ static ObjectEntryIndex footpath_get_default_railing() return OBJECT_ENTRY_INDEX_NULL; } -static bool footpath_is_surface_okay(ObjectEntryIndex index, bool queue) +static bool FootpathIsSurfaceEntryOkay(ObjectEntryIndex index, bool queue) { - auto pathEntry = get_path_surface_entry(index); + auto pathEntry = GetPathSurfaceEntry(index); if (pathEntry != nullptr) { bool showEditorPaths = ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode); @@ -1440,7 +1406,7 @@ static bool footpath_is_surface_okay(ObjectEntryIndex index, bool queue) return false; } -static bool footpath_is_legacy_path_okay(ObjectEntryIndex index) +static bool FootpathIsLegacyPathEntryOkay(ObjectEntryIndex index) { bool showEditorPaths = ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode); auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); @@ -1453,11 +1419,11 @@ static bool footpath_is_legacy_path_okay(ObjectEntryIndex index) return false; } -static ObjectEntryIndex footpath_get_default_legacy_path() +static ObjectEntryIndex FootpathGetDefaultLegacyPath() { for (ObjectEntryIndex i = 0; i < MAX_PATH_OBJECTS; i++) { - if (footpath_is_legacy_path_okay(i)) + if (FootpathIsLegacyPathEntryOkay(i)) { return i; } @@ -1465,35 +1431,35 @@ static ObjectEntryIndex footpath_get_default_legacy_path() return OBJECT_ENTRY_INDEX_NULL; } -static bool footpath_select_default() +static bool FootpathSelectDefault() { // Select default footpath - auto surfaceIndex = footpath_get_default_surface(false); - if (footpath_is_surface_okay(gFootpathSelection.NormalSurface, false)) + auto surfaceIndex = FootpathGetDefaultSurface(false); + if (FootpathIsSurfaceEntryOkay(gFootpathSelection.NormalSurface, false)) { surfaceIndex = gFootpathSelection.NormalSurface; } // Select default queue - auto queueIndex = footpath_get_default_surface(true); - if (footpath_is_surface_okay(gFootpathSelection.QueueSurface, true)) + auto queueIndex = FootpathGetDefaultSurface(true); + if (FootpathIsSurfaceEntryOkay(gFootpathSelection.QueueSurface, true)) { queueIndex = gFootpathSelection.QueueSurface; } // Select default railing - auto railingIndex = footpath_get_default_railing(); - const auto* railingEntry = get_path_railings_entry(gFootpathSelection.Railings); + auto railingIndex = FootpathGetDefaultRailings(); + const auto* railingEntry = GetPathRailingsEntry(gFootpathSelection.Railings); if (railingEntry != nullptr) { railingIndex = gFootpathSelection.Railings; } // Select default legacy path - auto legacyPathIndex = footpath_get_default_legacy_path(); + auto legacyPathIndex = FootpathGetDefaultLegacyPath(); if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL) { - if (footpath_is_legacy_path_okay(gFootpathSelection.LegacyPath)) + if (FootpathIsLegacyPathEntryOkay(gFootpathSelection.LegacyPath)) { // Keep legacy path selected legacyPathIndex = gFootpathSelection.LegacyPath; @@ -1525,6 +1491,19 @@ static bool footpath_select_default() return true; } +static PathConstructFlags FootpathCreateConstructFlags(ObjectEntryIndex& type) +{ + PathConstructFlags pathConstructFlags = 0; + if (gFootpathSelection.IsQueueSelected) + pathConstructFlags |= PathConstructFlag::IsQueue; + if (gFootpathSelection.LegacyPath != OBJECT_ENTRY_INDEX_NULL) + { + pathConstructFlags |= PathConstructFlag::IsLegacyPathObject; + type = gFootpathSelection.LegacyPath; + } + return pathConstructFlags; +} + void window_footpath_keyboard_shortcut_turn_left() { rct_window* w = window_find_by_class(WC_FOOTPATH); @@ -1620,7 +1599,7 @@ void window_footpath_keyboard_shortcut_build_current() window_event_mouse_up_call(w, WIDX_CONSTRUCT); } -void window_footpath_reset_selected_path() +void WindowFootpathResetSelectedPath() { gFootpathSelection = {}; } diff --git a/src/openrct2-ui/windows/GameBottomToolbar.cpp b/src/openrct2-ui/windows/GameBottomToolbar.cpp index 26e35e8d90..06b6aa9275 100644 --- a/src/openrct2-ui/windows/GameBottomToolbar.cpp +++ b/src/openrct2-ui/windows/GameBottomToolbar.cpp @@ -174,12 +174,12 @@ static void window_game_bottom_toolbar_mouseup(rct_window* w, rct_widgetindex wi auto subjectLoc = News::GetSubjectLocation(newsItem->Type, newsItem->Assoc); - if (subjectLoc == std::nullopt) + if (!subjectLoc.has_value()) break; rct_window* mainWindow = window_get_main(); if (mainWindow != nullptr) - window_scroll_to_location(mainWindow, *subjectLoc); + window_scroll_to_location(mainWindow, subjectLoc.value()); } break; case WIDX_RIGHT_OUTSET: @@ -315,7 +315,7 @@ static void window_game_bottom_toolbar_invalidate(rct_window* w) // Find out if the news item is no longer valid auto subjectLoc = News::GetSubjectLocation(newsItem->Type, newsItem->Assoc); - if (subjectLoc == std::nullopt) + if (!subjectLoc.has_value()) w->disabled_widgets |= (1ULL << WIDX_NEWS_LOCATE); if (!(newsItem->TypeHasSubject())) diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index dfc4568845..14538dce1e 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -7,6 +7,7 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include #include #include #include @@ -148,6 +149,8 @@ static void window_guest_common_invalidate(rct_window* w); static void window_guest_overview_close(rct_window *w); static void window_guest_overview_resize(rct_window *w); static void window_guest_overview_mouse_up(rct_window *w, rct_widgetindex widgetIndex); +static void window_guest_overview_mouse_down(rct_window *w, rct_widgetindex widgetIndex, rct_widget *widget); +static void window_guest_overview_dropdown(rct_window *w, rct_widgetindex widgetIndex, int32_t dropdownIndex); static void window_guest_overview_paint(rct_window *w, rct_drawpixelinfo *dpi); static void window_guest_overview_invalidate(rct_window *w); static void window_guest_overview_viewport_rotate(rct_window *w); @@ -156,6 +159,8 @@ static void window_guest_overview_text_input(rct_window *w, rct_widgetindex widg static void window_guest_overview_tool_update(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords); static void window_guest_overview_tool_down(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords); static void window_guest_overview_tool_abort(rct_window *w, rct_widgetindex widgetIndex); +static void window_guest_follow(rct_window *w); +static void window_guest_show_locate_dropdown(rct_window* w, rct_widget* widget); static void window_guest_mouse_up(rct_window *w, rct_widgetindex widgetIndex); @@ -186,6 +191,8 @@ static rct_window_event_list window_guest_overview_events([](auto& events) { events.close = &window_guest_overview_close; events.mouse_up = &window_guest_overview_mouse_up; + events.mouse_down = &window_guest_overview_mouse_down; + events.dropdown = &window_guest_overview_dropdown; events.resize = &window_guest_overview_resize; events.update = &window_guest_overview_update; events.tool_update = &window_guest_overview_tool_update; @@ -585,7 +592,7 @@ void window_guest_overview_mouse_up(rct_window* w, rct_widgetindex widgetIndex) } w->picked_peep_old_x = peep->x; CoordsXYZ nullLoc{}; - nullLoc.setNull(); + nullLoc.SetNull(); PeepPickupAction pickupAction{ PeepPickupType::Pickup, w->number, nullLoc, network_get_current_player_id() }; pickupAction.SetCallback([peepnum = w->number](const GameAction* ga, const GameActions::Result* result) { if (result->Error != GameActions::Status::Ok) @@ -606,9 +613,6 @@ void window_guest_overview_mouse_up(rct_window* w, rct_widgetindex widgetIndex) w, widgetIndex, STR_GUEST_RENAME_TITLE, STR_GUEST_RENAME_PROMPT, {}, peepName.c_str(), 32); break; } - case WIDX_LOCATE: - w->ScrollToViewport(); - break; case WIDX_TRACK: { uint32_t flags = peep->PeepFlags ^ PEEP_FLAGS_TRACKING; @@ -620,6 +624,51 @@ void window_guest_overview_mouse_up(rct_window* w, rct_widgetindex widgetIndex) } } +static void window_guest_overview_mouse_down(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) +{ + switch (widgetIndex) + { + case WIDX_LOCATE: + window_guest_show_locate_dropdown(w, widget); + break; + } +} + +static void window_guest_overview_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) +{ + switch (widgetIndex) + { + case WIDX_LOCATE: + { + if (dropdownIndex == 0) + { + w->ScrollToViewport(); + } + else if (dropdownIndex == 1) + { + window_guest_follow(w); + } + break; + } + } +} + +static void window_guest_show_locate_dropdown(rct_window* w, rct_widget* widget) +{ + gDropdownItemsFormat[0] = STR_LOCATE_SUBJECT_TIP; + gDropdownItemsFormat[1] = STR_FOLLOW_SUBJECT_TIP; + + WindowDropdownShowText( + { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, 2); + gDropdownDefaultIndex = 0; +} + +static void window_guest_follow(rct_window* w) +{ + rct_window* w_main = window_get_main(); + window_follow_sprite(w_main, w->number); +} + /** * * rct2: 0x696AA0 @@ -1130,7 +1179,7 @@ void window_guest_overview_tool_update(rct_window* w, rct_widgetindex widgetInde gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE; auto mapCoords = footpath_get_coordinates_from_pos({ screenCoords.x, screenCoords.y + 16 }, nullptr, nullptr); - if (!mapCoords.isNull()) + if (!mapCoords.IsNull()) { gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE; gMapSelectType = MAP_SELECT_TYPE_FULL; @@ -1178,7 +1227,7 @@ void window_guest_overview_tool_down(rct_window* w, rct_widgetindex widgetIndex, TileElement* tileElement; auto destCoords = footpath_get_coordinates_from_pos({ screenCoords.x, screenCoords.y + 16 }, nullptr, &tileElement); - if (destCoords.isNull()) + if (destCoords.IsNull()) return; PeepPickupAction pickupAction{ @@ -1454,7 +1503,7 @@ void window_guest_rides_update(rct_window* w) { if (ride.IsRide() && guest->HasRidden(&ride)) { - w->list_item_positions[curr_list_position] = ride.id; + w->list_item_positions[curr_list_position] = EnumValue(ride.id); curr_list_position++; } } @@ -1605,7 +1654,8 @@ void window_guest_rides_scroll_paint(rct_window* w, rct_drawpixelinfo* dpi, int3 stringId = STR_WINDOW_COLOUR_2_STRINGID; } - auto ride = get_ride(w->list_item_positions[list_index]); + const auto rideId = static_cast(w->list_item_positions[list_index]); + auto ride = get_ride(rideId); if (ride != nullptr) { auto ft = Formatter(); diff --git a/src/openrct2-ui/windows/GuestList.cpp b/src/openrct2-ui/windows/GuestList.cpp index 62eba8f01e..a276b5fad3 100644 --- a/src/openrct2-ui/windows/GuestList.cpp +++ b/src/openrct2-ui/windows/GuestList.cpp @@ -182,7 +182,7 @@ public: { case GuestListFilterType::GuestsOnRide: { - auto guestRide = get_ride(index); + auto guestRide = get_ride(static_cast(index)); if (guestRide != nullptr) { ft.Add( @@ -198,7 +198,7 @@ public: } case GuestListFilterType::GuestsInQueue: { - auto guestRide = get_ride(index); + auto guestRide = get_ride(static_cast(index)); if (guestRide != nullptr) { ft.Add(STR_QUEUING_FOR); @@ -213,7 +213,7 @@ public: } case GuestListFilterType::GuestsThinkingAboutRide: { - auto guestRide = get_ride(index); + auto guestRide = get_ride(static_cast(index)); if (guestRide != nullptr) { ft.Add(STR_NONE); diff --git a/src/openrct2-ui/windows/LandRights.cpp b/src/openrct2-ui/windows/LandRights.cpp index 2f61248a42..4a2d99326b 100644 --- a/src/openrct2-ui/windows/LandRights.cpp +++ b/src/openrct2-ui/windows/LandRights.cpp @@ -286,7 +286,7 @@ static void window_land_rights_tool_update_land_rights(const ScreenCoordsXY& scr auto mapTile = screen_get_map_xy(screenCoords, nullptr); - if (!mapTile) + if (!mapTile.has_value()) { if (_landRightsCost != MONEY32_UNDEFINED) { diff --git a/src/openrct2-ui/windows/Main.cpp b/src/openrct2-ui/windows/Main.cpp index a31f96226b..4013b9f1ae 100644 --- a/src/openrct2-ui/windows/Main.cpp +++ b/src/openrct2-ui/windows/Main.cpp @@ -47,7 +47,7 @@ rct_window* window_main_open() gShowGridLinesRefCount = 0; gShowLandRightsRefCount = 0; gShowConstuctionRightsRefCount = 0; - window_footpath_reset_selected_path(); + WindowFootpathResetSelectedPath(); return window; } diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index e0d3a1cd2e..9ad54b42e8 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -1187,7 +1187,7 @@ static void window_map_set_land_rights_tool_update(const ScreenCoordsXY& screenC map_invalidate_selection_rect(); gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE; auto mapCoords = screen_get_map_xy(screenCoords, &viewport); - if (!mapCoords) + if (!mapCoords.has_value()) return; gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE; @@ -1216,13 +1216,13 @@ static CoordsXYZD place_park_entrance_get_map_position(const ScreenCoordsXY& scr CoordsXYZD parkEntranceMapPosition{ 0, 0, 0, INVALID_DIRECTION }; const CoordsXY mapCoords = ViewportInteractionGetTileStartAtCursor(screenCoords); parkEntranceMapPosition = { mapCoords.x, mapCoords.y, 0, INVALID_DIRECTION }; - if (parkEntranceMapPosition.isNull()) + if (parkEntranceMapPosition.IsNull()) return parkEntranceMapPosition; auto surfaceElement = map_get_surface_element_at(mapCoords); if (surfaceElement == nullptr) { - parkEntranceMapPosition.setNull(); + parkEntranceMapPosition.SetNull(); return parkEntranceMapPosition; } @@ -1257,7 +1257,7 @@ static void window_map_place_park_entrance_tool_update(const ScreenCoordsXY& scr gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW; gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT; CoordsXYZD parkEntrancePosition = place_park_entrance_get_map_position(screenCoords); - if (parkEntrancePosition.isNull()) + if (parkEntrancePosition.IsNull()) { park_entrance_remove_ghost(); return; @@ -1298,7 +1298,7 @@ static void window_map_set_peep_spawn_tool_update(const ScreenCoordsXY& screenCo gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE; gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW; auto mapCoords = footpath_bridge_get_info_from_pos(screenCoords, &direction, &tileElement); - if (mapCoords.isNull()) + if (mapCoords.IsNull()) return; mapZ = tileElement->GetBaseZ(); @@ -1329,7 +1329,7 @@ static void window_map_place_park_entrance_tool_down(const ScreenCoordsXY& scree park_entrance_remove_ghost(); CoordsXYZD parkEntrancePosition = place_park_entrance_get_map_position(screenCoords); - if (!parkEntrancePosition.isNull()) + if (!parkEntrancePosition.IsNull()) { auto gameAction = PlaceParkEntranceAction(parkEntrancePosition, gFootpathSelectedId); auto result = GameActions::Execute(&gameAction); @@ -1351,7 +1351,7 @@ static void window_map_set_peep_spawn_tool_down(const ScreenCoordsXY& screenCoor // Verify footpath exists at location, and retrieve coordinates auto mapCoords = footpath_get_coordinates_from_pos(screenCoords, &direction, &tileElement); - if (mapCoords.isNull()) + if (mapCoords.IsNull()) return; mapZ = tileElement->GetBaseZ(); diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp index 93006dd0c6..e82f43edbc 100644 --- a/src/openrct2-ui/windows/MazeConstruction.cpp +++ b/src/openrct2-ui/windows/MazeConstruction.cpp @@ -130,7 +130,7 @@ rct_window* window_maze_construction_open() WindowInitScrollWidgets(w); - w->number = _currentRideIndex; + w->rideId = _currentRideIndex; window_push_others_right(w); show_gridlines(); @@ -159,7 +159,7 @@ static void window_maze_construction_close(rct_window* w) auto ride = get_ride(_currentRideIndex); if (ride != nullptr) { - if (ride->overall_view.isNull()) + if (ride->overall_view.IsNull()) { int32_t savedPausedState = gGamePaused; gGamePaused = 0; @@ -169,7 +169,7 @@ static void window_maze_construction_close(rct_window* w) else { auto intent = Intent(WC_RIDE); - intent.putExtra(INTENT_EXTRA_RIDE_ID, ride->id); + intent.putExtra(INTENT_EXTRA_RIDE_ID, EnumValue(ride->id)); context_open_intent(&intent); } } @@ -181,7 +181,7 @@ static void window_maze_construction_entrance_mouseup(rct_window* w, rct_widgeti return; gRideEntranceExitPlaceType = widgetIndex == WIDX_MAZE_ENTRANCE ? ENTRANCE_TYPE_RIDE_ENTRANCE : ENTRANCE_TYPE_RIDE_EXIT; - gRideEntranceExitPlaceRideIndex = static_cast(w->number); + gRideEntranceExitPlaceRideIndex = w->rideId; gRideEntranceExitPlaceStationIndex = 0; input_set_flag(INPUT_FLAG_6, true); @@ -331,7 +331,7 @@ static void window_maze_construction_update(rct_window* w) default: break; } - sub_6C94D8(); + UpdateGhostTrackAndArrow(); } /** @@ -366,7 +366,7 @@ static void window_maze_construction_entrance_tooldown(const ScreenCoordsXY& scr gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW; CoordsXYZD entranceOrExitCoords = ride_get_entrance_or_exit_position_from_screen_position(screenCoords); - if (entranceOrExitCoords.isNull()) + if (entranceOrExitCoords.IsNull()) return; if (gRideEntranceExitPlaceDirection == INVALID_DIRECTION) diff --git a/src/openrct2-ui/windows/NewCampaign.cpp b/src/openrct2-ui/windows/NewCampaign.cpp index d1ad6aa8d9..b091ac7a4a 100644 --- a/src/openrct2-ui/windows/NewCampaign.cpp +++ b/src/openrct2-ui/windows/NewCampaign.cpp @@ -22,7 +22,9 @@ static constexpr const rct_string_id WINDOW_TITLE = STR_NONE; static constexpr const int32_t WH = 109; static constexpr const int32_t WW = 350; -constexpr uint16_t SELECTED_RIDE_UNDEFINED = 0xFFFF; + +constexpr auto SELECTED_RIDE_UNDEFINED = RIDE_ID_NULL; +constexpr uint16_t SELECTED_ITEM_UNDEFINED = 0xFFFF; // clang-format off enum WINDOW_NEW_CAMPAIGN_WIDGET_IDX { @@ -205,9 +207,9 @@ public: else { int32_t numItems = 0; - for (auto rideId : RideList) + for (auto rideIndex : RideList) { - auto curRide = get_ride(rideId); + auto curRide = get_ride(rideIndex); if (curRide != nullptr) { // HACK until dropdown items have longer argument buffers @@ -252,7 +254,8 @@ public: break; case WIDX_START_BUTTON: { - auto gameAction = ParkMarketingAction(campaign.campaign_type, campaign.RideId, campaign.no_weeks); + auto gameAction = ParkMarketingAction( + campaign.campaign_type, static_cast(campaign.RideId), campaign.no_weeks); gameAction.SetCallback([](const GameAction* ga, const GameActions::Result* result) { if (result->Error == GameActions::Status::Ok) { @@ -322,7 +325,7 @@ public: widgets[WIDX_RIDE_DROPDOWN].type = WindowWidgetType::DropdownMenu; widgets[WIDX_RIDE_DROPDOWN_BUTTON].type = WindowWidgetType::Button; widgets[WIDX_RIDE_LABEL].text = STR_MARKETING_ITEM; - if (campaign.ShopItemId != SELECTED_RIDE_UNDEFINED) + if (campaign.ShopItemId != SELECTED_ITEM_UNDEFINED) { widgets[WIDX_RIDE_DROPDOWN].text = GetShopItemDescriptor(ShopItem(campaign.ShopItemId)).Naming.Plural; } diff --git a/src/openrct2-ui/windows/News.cpp b/src/openrct2-ui/windows/News.cpp index 2fa7db71f9..ade37acd2f 100644 --- a/src/openrct2-ui/windows/News.cpp +++ b/src/openrct2-ui/windows/News.cpp @@ -110,9 +110,9 @@ public: { static rct_window* _mainWindow; auto subjectLoc = News::GetSubjectLocation(newsItem.Type, newsItem.Assoc); - if (subjectLoc != std::nullopt && (_mainWindow = window_get_main()) != nullptr) + if (subjectLoc.has_value() && (_mainWindow = window_get_main()) != nullptr) { - window_scroll_to_location(_mainWindow, *subjectLoc); + window_scroll_to_location(_mainWindow, subjectLoc.value()); } } } diff --git a/src/openrct2-ui/windows/ObjectLoadError.cpp b/src/openrct2-ui/windows/ObjectLoadError.cpp index 438ae4602e..761084fcef 100644 --- a/src/openrct2-ui/windows/ObjectLoadError.cpp +++ b/src/openrct2-ui/windows/ObjectLoadError.cpp @@ -285,6 +285,10 @@ static rct_widget window_object_load_error_widgets[] = { { WIDGETS_END }, }; +<<<<<<< HEAD +======= +static rct_string_id get_object_type_string(ObjectType type); +>>>>>>> upstream/develop static void window_object_load_error_close(rct_window *w); static void window_object_load_error_update(rct_window *w); static void window_object_load_error_mouseup(rct_window *w, rct_widgetindex widgetIndex); @@ -372,6 +376,7 @@ static rct_string_id get_object_type_string(ObjectType type) */ static void copy_object_names_to_clipboard(rct_window* w) { +<<<<<<< HEAD std::stringstream ss; for (uint16_t i = 0; i < w->no_list_items; i++) { @@ -381,6 +386,17 @@ static void copy_object_names_to_clipboard(rct_window* w) } auto clip = ss.str(); +======= + std::stringstream stream; + for (uint16_t i = 0; i < w->no_list_items; i++) + { + const auto& entry = _invalid_entries[i]; + stream << entry.GetName(); + stream << PLATFORM_NEWLINE; + } + + auto clip = stream.str(); +>>>>>>> upstream/develop OpenRCT2::GetContext()->GetUiContext()->SetClipboardText(clip.c_str()); } diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp index 4e10af0025..bbbff05b0b 100644 --- a/src/openrct2-ui/windows/Player.cpp +++ b/src/openrct2-ui/windows/Player.cpp @@ -610,7 +610,7 @@ static void window_player_update_viewport(rct_window* w, bool scroll) if (coord.x != 0 || coord.y != 0 || coord.z != 0) { auto centreLoc = centre_2d_coordinates(coord, viewport); - if (!centreLoc) + if (!centreLoc.has_value()) { return; } @@ -620,13 +620,13 @@ static void window_player_update_viewport(rct_window* w, bool scroll) scroll = false; } - if (!scroll || w->savedViewPos != centreLoc) + if (!scroll || w->savedViewPos != centreLoc.value()) { w->flags |= WF_SCROLLING_TO_LOCATION; - w->savedViewPos = *centreLoc; + w->savedViewPos = centreLoc.value(); if (!scroll) { - w->viewport->viewPos = *centreLoc; + w->viewport->viewPos = centreLoc.value(); } widget_invalidate(w, WIDX_VIEWPORT); } diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index 26f8809c9c..cc55e456aa 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -537,6 +537,7 @@ static void window_ride_main_textinput(rct_window *w, rct_widgetindex widgetInde static void window_ride_main_viewport_rotate(rct_window *w); static void window_ride_main_invalidate(rct_window *w); static void window_ride_main_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_ride_main_follow_ride(rct_window *w); static void window_ride_vehicle_mouseup(rct_window *w, rct_widgetindex widgetIndex); static void window_ride_vehicle_resize(rct_window *w); @@ -958,7 +959,7 @@ static void window_ride_draw_tab_main(rct_drawpixelinfo* dpi, rct_window* w) rct_widgetindex widgetIndex = WIDX_TAB_1 + WINDOW_RIDE_PAGE_MAIN; if (!(w->disabled_widgets & (1LL << widgetIndex))) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { int32_t spriteIndex = 0; @@ -1014,7 +1015,7 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo* dpi, rct_window* w) screenCoords = ScreenCoordsXY{ widget->width() / 2, widget->height() - 12 }; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -1108,7 +1109,7 @@ static void window_ride_draw_tab_images(rct_drawpixelinfo* dpi, rct_window* w) static void window_ride_disable_tabs(rct_window* w) { uint32_t disabled_tabs = 0; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -1192,12 +1193,13 @@ static void window_ride_update_overall_view(Ride* ride) maxz = std::max(maxz, clearZ); } - if (ride->id >= ride_overall_views.size()) + const auto rideIndex = EnumValue(ride->id); + if (rideIndex >= ride_overall_views.size()) { - ride_overall_views.resize(ride->id + 1); + ride_overall_views.resize(rideIndex + 1); } - auto& view = ride_overall_views[ride->id]; + auto& view = ride_overall_views[rideIndex]; view.x = (minx + maxx) / 2 + 16; view.y = (miny + maxy) / 2 + 16; view.z = (minz + maxz) / 2 - 8; @@ -1234,7 +1236,7 @@ static rct_window* window_ride_open(Ride* ride) w->widgets = window_ride_page_widgets[WINDOW_RIDE_PAGE_MAIN]; w->enabled_widgets = window_ride_page_enabled_widgets[WINDOW_RIDE_PAGE_MAIN]; w->hold_down_widgets = window_ride_page_hold_down_widgets[WINDOW_RIDE_PAGE_MAIN]; - w->number = ride->id; + w->rideId = ride->id; w->page = WINDOW_RIDE_PAGE_MAIN; w->vehicleIndex = 0; @@ -1264,7 +1266,7 @@ rct_window* window_ride_main_open(Ride* ride) return nullptr; } - rct_window* w = window_bring_to_front_by_number(WC_RIDE, ride->id); + rct_window* w = window_bring_to_front_by_number(WC_RIDE, EnumValue(ride->id)); if (w == nullptr) { w = window_ride_open(ride); @@ -1305,7 +1307,7 @@ static rct_window* window_ride_open_station(Ride* ride, StationIndex stationInde if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_NO_VEHICLES)) return window_ride_main_open(ride); - auto w = window_bring_to_front_by_number(WC_RIDE, ride->id); + auto w = window_bring_to_front_by_number(WC_RIDE, EnumValue(ride->id)); if (w == nullptr) { w = window_ride_open(ride); @@ -1334,7 +1336,7 @@ static rct_window* window_ride_open_station(Ride* ride, StationIndex stationInde // View for (int32_t i = stationIndex; i >= 0; i--) { - if (ride->stations[i].Start.isNull()) + if (ride->stations[i].Start.IsNull()) { stationIndex--; } @@ -1407,7 +1409,7 @@ rct_window* window_ride_open_vehicle(Vehicle* vehicle) view++; } - rct_window* w = window_find_by_number(WC_RIDE, ride->id); + rct_window* w = window_find_by_number(WC_RIDE, EnumValue(ride->id)); if (w != nullptr) { w->Invalidate(); @@ -1442,7 +1444,8 @@ rct_window* window_ride_open_vehicle(Vehicle* vehicle) } } - w = openedPeepWindow ? window_find_by_number(WC_RIDE, ride->id) : window_bring_to_front_by_number(WC_RIDE, ride->id); + w = openedPeepWindow ? window_find_by_number(WC_RIDE, EnumValue(ride->id)) + : window_bring_to_front_by_number(WC_RIDE, EnumValue(ride->id)); } if (w == nullptr) @@ -1551,20 +1554,20 @@ static void window_ride_anchor_border_widgets(rct_window* w) static std::optional GetStationIndexFromViewSelection(const rct_window& w) { - const auto* ride = get_ride(w.number); + const auto* ride = get_ride(static_cast(w.number)); if (ride == nullptr) - return {}; + return std::nullopt; int32_t viewSelectionIndex = w.viewport_focus_coordinates.var_480 - 1 - ride->num_vehicles; if (viewSelectionIndex < 0) { - return {}; + return std::nullopt; } for (StationIndex index = 0; index < std::size(ride->stations); ++index) { const auto& station = ride->stations[index]; - if (!station.Start.isNull()) + if (!station.Start.IsNull()) { if (viewSelectionIndex-- == 0) { @@ -1572,7 +1575,7 @@ static std::optional GetStationIndexFromViewSelection(const rct_wi } } } - return {}; + return std::nullopt; } /** @@ -1584,7 +1587,7 @@ static void window_ride_init_viewport(rct_window* w) if (w->page != WINDOW_RIDE_PAGE_MAIN) return; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -1689,7 +1692,7 @@ static void window_ride_init_viewport(rct_window* w) w->viewport_focus_sprite.type = focus.sprite.type; // rct2: 0x006aec9c only used here so brought it into the function - if (!w->viewport && !ride->overall_view.isNull()) + if (!w->viewport && !ride->overall_view.IsNull()) { rct_widget* view_widget = &w->widgets[WIDX_VIEWPORT]; @@ -1716,7 +1719,7 @@ static void window_ride_init_viewport(rct_window* w) */ static void window_ride_rename(rct_window* w) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { auto rideName = ride->GetName(); @@ -1750,11 +1753,11 @@ static void window_ride_main_mouseup(rct_window* w, rct_widgetindex widgetIndex) break; case WIDX_CONSTRUCTION: { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { ride_construct(ride); - if (window_find_by_number(WC_RIDE_CONSTRUCTION, ride->id) != nullptr) + if (window_find_by_number(WC_RIDE_CONSTRUCTION, EnumValue(ride->id)) != nullptr) { window_close(w); } @@ -1764,9 +1767,6 @@ static void window_ride_main_mouseup(rct_window* w, rct_widgetindex widgetIndex) case WIDX_RENAME: window_ride_rename(w); break; - case WIDX_LOCATE: - w->ScrollToViewport(); - break; case WIDX_DEMOLISH: context_open_detail_window(WD_DEMOLISH_RIDE, w->number); break; @@ -1775,7 +1775,7 @@ static void window_ride_main_mouseup(rct_window* w, rct_widgetindex widgetIndex) case WIDX_TEST_LIGHT: case WIDX_OPEN_LIGHT: { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { RideStatus status; @@ -1813,7 +1813,7 @@ static void window_ride_main_resize(rct_window* w) { minHeight += 20 + RCT1_LIGHT_OFFSET; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { #ifdef __SIMULATE_IN_RIDE_WINDOW__ @@ -1845,7 +1845,7 @@ static void window_ride_main_resize(rct_window* w) static void window_ride_show_view_dropdown(rct_window* w, rct_widget* widget) { rct_widget* dropdownWidget = widget - 1; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -1961,7 +1961,7 @@ static void window_ride_set_dropdown(RideStatusDropdownInfo& info, RideStatus st static void window_ride_show_open_dropdown(rct_window* w, rct_widget* widget) { RideStatusDropdownInfo info; - info.Ride = get_ride(w->number); + info.Ride = get_ride(w->rideId); if (info.Ride == nullptr) return; @@ -2029,7 +2029,7 @@ static void populate_ride_type_dropdown() static void window_ride_show_ride_type_dropdown(rct_window* w, rct_widget* widget) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -2062,6 +2062,49 @@ static void window_ride_show_ride_type_dropdown(rct_window* w, rct_widget* widge Dropdown::SetChecked(pos, true); } +static void window_ride_show_locate_dropdown(rct_window* w, rct_widget* widget) +{ + auto ride = get_ride(w->rideId); + if (ride == nullptr) + return; + + gDropdownItemsFormat[0] = STR_LOCATE_SUBJECT_TIP; + gDropdownItemsFormat[1] = STR_FOLLOW_SUBJECT_TIP; + + WindowDropdownShowText( + { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, 2); + gDropdownDefaultIndex = 0; + if (!ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_TRACK)) + { + // Disable if we're a flat ride + Dropdown::SetDisabled(1, true); + } +} + +static void window_ride_main_follow_ride(rct_window* w) +{ + auto ride = get_ride(w->rideId); + if (ride != nullptr) + { + if (!(ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_MAIN)) + { + if (w->viewport_focus_coordinates.var_480 > 0) + { + if (w->viewport_focus_coordinates.var_480 <= ride->num_vehicles) + { + Vehicle* vehicle = GetEntity(ride->vehicles[w->viewport_focus_coordinates.var_480 - 1]); + if (vehicle != nullptr) + { + uint16_t headVehicleSpriteIndex = vehicle->sprite_index; + rct_window* w_main = window_get_main(); + window_follow_sprite(w_main, headVehicleSpriteIndex); + } + } + } + } + } +} + static void populate_vehicle_type_dropdown(Ride* ride) { auto& objManager = GetContext()->GetObjectManager(); @@ -2125,7 +2168,7 @@ static void populate_vehicle_type_dropdown(Ride* ride) static void window_ride_show_vehicle_type_dropdown(rct_window* w, rct_widget* widget) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -2177,6 +2220,9 @@ static void window_ride_main_mousedown(rct_window* w, rct_widgetindex widgetInde case WIDX_RIDE_TYPE_DROPDOWN: window_ride_show_ride_type_dropdown(w, widget); break; + case WIDX_LOCATE: + window_ride_show_locate_dropdown(w, widget); + break; } } @@ -2192,7 +2238,7 @@ static void window_ride_main_dropdown(rct_window* w, rct_widgetindex widgetIndex if (dropdownIndex == -1) { dropdownIndex = w->viewport_focus_coordinates.var_480 + 1; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { if (dropdownIndex != 0 && dropdownIndex <= ride->num_vehicles @@ -2213,7 +2259,7 @@ static void window_ride_main_dropdown(rct_window* w, rct_widgetindex widgetIndex break; case WIDX_OPEN: { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { auto status = RideStatus::Closed; @@ -2250,7 +2296,7 @@ static void window_ride_main_dropdown(rct_window* w, rct_widgetindex widgetIndex uint8_t rideType = RideDropdownData[rideLabelId].ride_type_id; if (rideType < RIDE_TYPE_COUNT) { - auto rideSetSetting = RideSetSettingAction(w->number, RideSetSetting::RideType, rideType); + auto rideSetSetting = RideSetSettingAction(w->rideId, RideSetSetting::RideType, rideType); rideSetSetting.SetCallback([](const GameAction* ga, const GameActions::Result* result) { // Reset ghost track if ride construction window is open, prevents a crash // Will get set to the correct Alternative variable during set_default_next_piece. @@ -2261,6 +2307,19 @@ static void window_ride_main_dropdown(rct_window* w, rct_widgetindex widgetIndex GameActions::Execute(&rideSetSetting); } } + break; + case WIDX_LOCATE: + { + if (dropdownIndex == 0) + { + w->ScrollToViewport(); + } + else if (dropdownIndex == 1) + { + window_ride_main_follow_ride(w); + } + break; + } } } @@ -2276,7 +2335,7 @@ static void window_ride_main_update(rct_window* w) widget_invalidate(w, WIDX_TAB_1); // Update status - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { if (!(ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_MAIN)) @@ -2311,7 +2370,7 @@ static void window_ride_main_textinput(rct_window* w, rct_widgetindex widgetInde if (widgetIndex != WIDX_RENAME || text == nullptr) return; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { ride_set_name(ride, text, 0); @@ -2345,7 +2404,7 @@ static void window_ride_main_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -2477,7 +2536,7 @@ static void window_ride_main_invalidate(rct_window* w) static rct_string_id window_ride_get_status_overall_view(rct_window* w, Formatter& ft) { auto stringId = STR_NONE; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { ride->FormatStatusTo(ft); @@ -2496,7 +2555,7 @@ static rct_string_id window_ride_get_status_overall_view(rct_window* w, Formatte */ static rct_string_id window_ride_get_status_vehicle(rct_window* w, Formatter& ft) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return STR_EMPTY; @@ -2544,7 +2603,7 @@ static rct_string_id window_ride_get_status_vehicle(rct_window* w, Formatter& ft */ static rct_string_id window_ride_get_status_station(rct_window* w, Formatter& ft) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return STR_NONE; @@ -2558,14 +2617,14 @@ static rct_string_id window_ride_get_status_station(rct_window* w, Formatter& ft // Entrance / exit if (ride->status == RideStatus::Closed) { - if (ride_get_entrance_location(ride, static_cast(*stationIndex)).isNull()) + if (ride_get_entrance_location(ride, static_cast(*stationIndex)).IsNull()) stringId = STR_NO_ENTRANCE; - else if (ride_get_exit_location(ride, static_cast(*stationIndex)).isNull()) + else if (ride_get_exit_location(ride, static_cast(*stationIndex)).IsNull()) stringId = STR_NO_EXIT; } else { - if (ride_get_entrance_location(ride, static_cast(*stationIndex)).isNull()) + if (ride_get_entrance_location(ride, static_cast(*stationIndex)).IsNull()) stringId = STR_EXIT_ONLY; } // Queue length @@ -2595,7 +2654,7 @@ static rct_string_id window_ride_get_status_station(rct_window* w, Formatter& ft */ static rct_string_id window_ride_get_status(rct_window* w, Formatter& ft) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (w->viewport_focus_coordinates.var_480 == 0) return window_ride_get_status_overall_view(w, ft); if (ride != nullptr && w->viewport_focus_coordinates.var_480 <= ride->num_vehicles) @@ -2625,7 +2684,7 @@ static void window_ride_main_paint(rct_window* w, rct_drawpixelinfo* dpi) } // View dropdown - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -2707,7 +2766,7 @@ static void window_ride_vehicle_resize(rct_window* w) */ static void window_ride_vehicle_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -2750,7 +2809,7 @@ static void window_ride_vehicle_dropdown(rct_window* w, rct_widgetindex widgetIn case WIDX_VEHICLE_TYPE_DROPDOWN: if (dropdownIndex >= 0 && static_cast(dropdownIndex) < VehicleDropdownData.size()) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { auto newRideType = VehicleDropdownData[dropdownIndex].subtype_id; @@ -2775,7 +2834,7 @@ static void window_ride_vehicle_update(rct_window* w) static OpenRCT2String window_ride_vehicle_tooltip( rct_window* const w, const rct_widgetindex widgetIndex, rct_string_id fallback) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return { STR_NONE, {} }; @@ -2842,7 +2901,7 @@ static void window_ride_vehicle_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -2922,7 +2981,7 @@ static void window_ride_vehicle_paint(rct_window* w, rct_drawpixelinfo* dpi) WindowDrawWidgets(w, dpi); window_ride_draw_tab_images(dpi, w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -2997,7 +3056,7 @@ static rct_vehicle_paintinfo _sprites_to_draw[144]; */ static void window_ride_vehicle_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3090,7 +3149,7 @@ static void window_ride_vehicle_scrollpaint(rct_window* w, rct_drawpixelinfo* dp */ static void window_ride_mode_tweak_increase(rct_window* w) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3106,7 +3165,7 @@ static void window_ride_mode_tweak_increase(rct_window* w) uint8_t increment = ride->mode == RideMode::Dodgems ? 10 : 1; set_operating_setting( - w->number, RideSetSetting::Operation, std::clamp(ride->operation_option + increment, minValue, maxValue)); + w->rideId, RideSetSetting::Operation, std::clamp(ride->operation_option + increment, minValue, maxValue)); } /** @@ -3115,7 +3174,7 @@ static void window_ride_mode_tweak_increase(rct_window* w) */ static void window_ride_mode_tweak_decrease(rct_window* w) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3130,7 +3189,7 @@ static void window_ride_mode_tweak_decrease(rct_window* w) uint8_t decrement = ride->mode == RideMode::Dodgems ? 10 : 1; set_operating_setting( - w->number, RideSetSetting::Operation, std::clamp(ride->operation_option - decrement, minValue, maxValue)); + w->rideId, RideSetSetting::Operation, std::clamp(ride->operation_option - decrement, minValue, maxValue)); } /** @@ -3142,7 +3201,7 @@ static void window_ride_mode_dropdown(rct_window* w, rct_widget* widget) rct_widget* dropdownWidget; dropdownWidget = widget - 1; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3181,7 +3240,7 @@ static void window_ride_mode_dropdown(rct_window* w, rct_widget* widget) */ static void window_ride_load_dropdown(rct_window* w, rct_widget* widget) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3204,7 +3263,8 @@ static void window_ride_load_dropdown(rct_window* w, rct_widget* widget) */ static void window_ride_operating_mouseup(rct_window* w, rct_widgetindex widgetIndex) { - auto ride = get_ride(w->number); + const auto rideId = w->rideId; + auto ride = get_ride(rideId); if (ride == nullptr) return; @@ -3226,23 +3286,21 @@ static void window_ride_operating_mouseup(rct_window* w, rct_widgetindex widgetI window_ride_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_LOAD_CHECKBOX: - set_operating_setting(w->number, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_LOAD); + set_operating_setting(rideId, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_LOAD); break; case WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX: set_operating_setting( - w->number, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_LEAVE_WHEN_ANOTHER_ARRIVES); + rideId, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_LEAVE_WHEN_ANOTHER_ARRIVES); break; case WIDX_MINIMUM_LENGTH_CHECKBOX: - set_operating_setting( - w->number, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH); + set_operating_setting(rideId, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH); break; case WIDX_MAXIMUM_LENGTH_CHECKBOX: - set_operating_setting( - w->number, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_MAXIMUM_LENGTH); + set_operating_setting(rideId, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_MAXIMUM_LENGTH); break; case WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX: set_operating_setting( - w->number, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS); + rideId, RideSetSetting::Departure, ride->depart_flags ^ RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS); break; } } @@ -3262,7 +3320,8 @@ static void window_ride_operating_resize(rct_window* w) */ static void window_ride_operating_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) { - auto ride = get_ride(w->number); + const auto rideId = w->rideId; + auto ride = get_ride(rideId); if (ride == nullptr) return; @@ -3279,42 +3338,42 @@ static void window_ride_operating_mousedown(rct_window* w, rct_widgetindex widge upper_bound = gCheatsUnlockOperatingLimits ? 255 : ride->GetRideTypeDescriptor().LiftData.maximum_speed; lower_bound = gCheatsUnlockOperatingLimits ? 0 : ride->GetRideTypeDescriptor().LiftData.minimum_speed; set_operating_setting( - w->number, RideSetSetting::LiftHillSpeed, + rideId, RideSetSetting::LiftHillSpeed, std::clamp(ride->lift_hill_speed + 1, lower_bound, upper_bound)); break; case WIDX_LIFT_HILL_SPEED_DECREASE: upper_bound = gCheatsUnlockOperatingLimits ? 255 : ride->GetRideTypeDescriptor().LiftData.maximum_speed; lower_bound = gCheatsUnlockOperatingLimits ? 0 : ride->GetRideTypeDescriptor().LiftData.minimum_speed; set_operating_setting( - w->number, RideSetSetting::LiftHillSpeed, + rideId, RideSetSetting::LiftHillSpeed, std::clamp(ride->lift_hill_speed - 1, lower_bound, upper_bound)); break; case WIDX_MINIMUM_LENGTH_INCREASE: upper_bound = 250; lower_bound = 0; set_operating_setting( - w->number, RideSetSetting::MinWaitingTime, + rideId, RideSetSetting::MinWaitingTime, std::clamp(ride->min_waiting_time + 1, lower_bound, upper_bound)); break; case WIDX_MINIMUM_LENGTH_DECREASE: upper_bound = 250; lower_bound = 0; set_operating_setting( - w->number, RideSetSetting::MinWaitingTime, + rideId, RideSetSetting::MinWaitingTime, std::clamp(ride->min_waiting_time - 1, lower_bound, upper_bound)); break; case WIDX_MAXIMUM_LENGTH_INCREASE: upper_bound = 250; lower_bound = 0; set_operating_setting( - w->number, RideSetSetting::MaxWaitingTime, + rideId, RideSetSetting::MaxWaitingTime, std::clamp(ride->max_waiting_time + 1, lower_bound, upper_bound)); break; case WIDX_MAXIMUM_LENGTH_DECREASE: upper_bound = 250; lower_bound = 0; set_operating_setting( - w->number, RideSetSetting::MaxWaitingTime, + rideId, RideSetSetting::MaxWaitingTime, std::clamp(ride->max_waiting_time - 1, lower_bound, upper_bound)); break; case WIDX_MODE_DROPDOWN: @@ -3327,13 +3386,13 @@ static void window_ride_operating_mousedown(rct_window* w, rct_widgetindex widge upper_bound = gCheatsUnlockOperatingLimits ? 255 : MAX_CIRCUITS_PER_RIDE; lower_bound = 1; set_operating_setting( - w->number, RideSetSetting::NumCircuits, std::clamp(ride->num_circuits + 1, lower_bound, upper_bound)); + rideId, RideSetSetting::NumCircuits, std::clamp(ride->num_circuits + 1, lower_bound, upper_bound)); break; case WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE: upper_bound = gCheatsUnlockOperatingLimits ? 255 : MAX_CIRCUITS_PER_RIDE; lower_bound = 1; set_operating_setting( - w->number, RideSetSetting::NumCircuits, std::clamp(ride->num_circuits - 1, lower_bound, upper_bound)); + rideId, RideSetSetting::NumCircuits, std::clamp(ride->num_circuits - 1, lower_bound, upper_bound)); break; } } @@ -3347,7 +3406,8 @@ static void window_ride_operating_dropdown(rct_window* w, rct_widgetindex widget if (dropdownIndex == -1) return; - auto ride = get_ride(w->number); + const auto rideId = w->rideId; + auto ride = get_ride(rideId); if (ride == nullptr) return; @@ -3371,12 +3431,12 @@ static void window_ride_operating_dropdown(rct_window* w, rct_widgetindex widget } } if (rideMode != RideMode::NullMode) - set_operating_setting(w->number, RideSetSetting::Mode, static_cast(rideMode)); + set_operating_setting(rideId, RideSetSetting::Mode, static_cast(rideMode)); break; } case WIDX_LOAD_DROPDOWN: set_operating_setting( - w->number, RideSetSetting::Departure, (ride->depart_flags & ~RIDE_DEPART_WAIT_FOR_LOAD_MASK) | dropdownIndex); + rideId, RideSetSetting::Departure, (ride->depart_flags & ~RIDE_DEPART_WAIT_FOR_LOAD_MASK) | dropdownIndex); break; } } @@ -3391,7 +3451,7 @@ static void window_ride_operating_update(rct_window* w) window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_3); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr && ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_OPERATING) { ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_OPERATING; @@ -3417,7 +3477,7 @@ static void window_ride_operating_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3658,7 +3718,7 @@ static void window_ride_operating_paint(rct_window* w, rct_drawpixelinfo* dpi) WindowDrawWidgets(w, dpi); window_ride_draw_tab_images(dpi, w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3690,7 +3750,7 @@ static void window_ride_operating_paint(rct_window* w, rct_drawpixelinfo* dpi) */ static void window_ride_locate_mechanic(rct_window* w) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3780,7 +3840,7 @@ static void window_ride_maintenance_resize(rct_window* w) */ static void window_ride_maintenance_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3884,7 +3944,7 @@ static void window_ride_maintenance_dropdown(rct_window* w, rct_widgetindex widg if (dropdownIndex == -1) return; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -3895,7 +3955,7 @@ static void window_ride_maintenance_dropdown(rct_window* w, rct_widgetindex widg switch (widgetIndex) { case WIDX_INSPECTION_INTERVAL_DROPDOWN: - set_operating_setting(w->number, RideSetSetting::InspectionInterval, dropdownIndex); + set_operating_setting(w->rideId, RideSetSetting::InspectionInterval, dropdownIndex); break; case WIDX_FORCE_BREAKDOWN: @@ -3990,7 +4050,7 @@ static void window_ride_maintenance_update(rct_window* w) window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_4); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr && ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_MAINTENANCE) { ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_MAINTENANCE; @@ -4013,7 +4073,7 @@ static void window_ride_maintenance_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -4055,7 +4115,7 @@ static void window_ride_maintenance_paint(rct_window* w, rct_drawpixelinfo* dpi) WindowDrawWidgets(w, dpi); window_ride_draw_tab_images(dpi, w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -4210,7 +4270,7 @@ static void window_ride_set_track_colour_scheme(rct_window* w, const ScreenCoord return; if (info.Element->GetType() != TILE_ELEMENT_TYPE_TRACK) return; - if (info.Element->AsTrack()->GetRideIndex() != w->number) + if (info.Element->AsTrack()->GetRideIndex() != w->rideId) return; if (info.Element->AsTrack()->GetColourScheme() == newColourScheme) return; @@ -4288,7 +4348,7 @@ static void window_ride_colour_mousedown(rct_window* w, rct_widgetindex widgetIn int32_t i, numItems; rct_string_id stringId; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -4421,6 +4481,7 @@ static void window_ride_colour_dropdown(rct_window* w, rct_widgetindex widgetInd if (dropdownIndex == -1) return; + const auto rideId = w->rideId; switch (widgetIndex) { case WIDX_TRACK_COLOUR_SCHEME_DROPDOWN: @@ -4430,28 +4491,28 @@ static void window_ride_colour_dropdown(rct_window* w, rct_widgetindex widgetInd case WIDX_TRACK_MAIN_COLOUR: { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::TrackColourMain, dropdownIndex, w->ride_colour); + rideId, RideSetAppearanceType::TrackColourMain, dropdownIndex, w->ride_colour); GameActions::Execute(&rideSetAppearanceAction); } break; case WIDX_TRACK_ADDITIONAL_COLOUR: { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::TrackColourAdditional, dropdownIndex, w->ride_colour); + rideId, RideSetAppearanceType::TrackColourAdditional, dropdownIndex, w->ride_colour); GameActions::Execute(&rideSetAppearanceAction); } break; case WIDX_TRACK_SUPPORT_COLOUR: { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::TrackColourSupports, dropdownIndex, w->ride_colour); + rideId, RideSetAppearanceType::TrackColourSupports, dropdownIndex, w->ride_colour); GameActions::Execute(&rideSetAppearanceAction); } break; case WIDX_MAZE_STYLE_DROPDOWN: { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::MazeStyle, dropdownIndex, w->ride_colour); + rideId, RideSetAppearanceType::MazeStyle, dropdownIndex, w->ride_colour); GameActions::Execute(&rideSetAppearanceAction); } break; @@ -4467,7 +4528,7 @@ static void window_ride_colour_dropdown(rct_window* w, rct_widgetindex widgetInd if (ddIndex == dropdownIndex) { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::EntranceStyle, ddIndex, 0); + rideId, RideSetAppearanceType::EntranceStyle, ddIndex, 0); GameActions::Execute(&rideSetAppearanceAction); break; } @@ -4479,7 +4540,7 @@ static void window_ride_colour_dropdown(rct_window* w, rct_widgetindex widgetInd case WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN: { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::VehicleColourScheme, dropdownIndex, 0); + rideId, RideSetAppearanceType::VehicleColourScheme, dropdownIndex, 0); GameActions::Execute(&rideSetAppearanceAction); w->vehicleIndex = 0; } @@ -4491,21 +4552,21 @@ static void window_ride_colour_dropdown(rct_window* w, rct_widgetindex widgetInd case WIDX_VEHICLE_MAIN_COLOUR: { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::VehicleColourBody, dropdownIndex, w->vehicleIndex); + rideId, RideSetAppearanceType::VehicleColourBody, dropdownIndex, w->vehicleIndex); GameActions::Execute(&rideSetAppearanceAction); } break; case WIDX_VEHICLE_ADDITIONAL_COLOUR_1: { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::VehicleColourTrim, dropdownIndex, w->vehicleIndex); + rideId, RideSetAppearanceType::VehicleColourTrim, dropdownIndex, w->vehicleIndex); GameActions::Execute(&rideSetAppearanceAction); } break; case WIDX_VEHICLE_ADDITIONAL_COLOUR_2: { auto rideSetAppearanceAction = RideSetAppearanceAction( - w->number, RideSetAppearanceType::VehicleColourTernary, dropdownIndex, w->vehicleIndex); + rideId, RideSetAppearanceType::VehicleColourTernary, dropdownIndex, w->vehicleIndex); GameActions::Execute(&rideSetAppearanceAction); } break; @@ -4562,7 +4623,7 @@ static void window_ride_colour_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -4788,7 +4849,7 @@ static void window_ride_colour_paint(rct_window* w, rct_drawpixelinfo* dpi) rct_drawpixelinfo clippedDpi; rct_widget* widget; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -4888,7 +4949,7 @@ static void window_ride_colour_paint(rct_window* w, rct_drawpixelinfo* dpi) */ static void window_ride_colour_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -4951,11 +5012,11 @@ static std::vector window_ride_current_music_style_order; */ static void window_ride_toggle_music(rct_window* w) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { int32_t activateMusic = (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) ? 0 : 1; - set_operating_setting(w->number, RideSetSetting::Music, activateMusic); + set_operating_setting(w->rideId, RideSetSetting::Music, activateMusic); } } @@ -5005,9 +5066,9 @@ static std::optional GetMusicStyleOrder(ObjectEntryIndex musicObjectInde // Get the index in the order list auto originalStyleId = musicObj->GetOriginalStyleId(); - if (originalStyleId) + if (originalStyleId.has_value()) { - auto it = std::find(std::begin(MusicStyleOrder), std::end(MusicStyleOrder), *originalStyleId); + auto it = std::find(std::begin(MusicStyleOrder), std::end(MusicStyleOrder), originalStyleId.value()); if (it != std::end(MusicStyleOrder)) { return std::distance(std::begin(MusicStyleOrder), it); @@ -5027,7 +5088,7 @@ static void window_ride_music_mousedown(rct_window* w, rct_widgetindex widgetInd return; auto dropdownWidget = widget - 1; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -5042,7 +5103,8 @@ static void window_ride_music_mousedown(rct_window* w, rct_widgetindex widgetInd { // Hide custom music if the WAV file does not exist auto originalStyleId = musicObj->GetOriginalStyleId(); - if (originalStyleId == MUSIC_STYLE_CUSTOM_MUSIC_1 || originalStyleId == MUSIC_STYLE_CUSTOM_MUSIC_2) + if (originalStyleId.has_value() + && (originalStyleId == MUSIC_STYLE_CUSTOM_MUSIC_1 || originalStyleId == MUSIC_STYLE_CUSTOM_MUSIC_2)) { auto numTracks = musicObj->GetTrackCount(); if (numTracks != 0) @@ -5106,7 +5168,7 @@ static void window_ride_music_dropdown(rct_window* w, rct_widgetindex widgetInde && static_cast(dropdownIndex) < window_ride_current_music_style_order.size()) { auto musicStyle = window_ride_current_music_style_order[dropdownIndex]; - set_operating_setting(w->number, RideSetSetting::MusicType, musicStyle); + set_operating_setting(w->rideId, RideSetSetting::MusicType, musicStyle); } } @@ -5136,7 +5198,7 @@ static void window_ride_music_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -5227,7 +5289,7 @@ static void setup_scenery_selection(rct_window* w) while (tool_set(w, WIDX_BACKGROUND, Tool::Crosshair)) ; - gTrackDesignSaveRideIndex = w->number; + gTrackDesignSaveRideIndex = w->rideId; track_design_save_init(); gGamePaused |= GAME_PAUSED_SAVING_TRACK; @@ -5290,7 +5352,7 @@ static void TrackDesignCallback(int32_t result, [[maybe_unused]] const utf8* pat */ static void window_ride_measurements_design_save(rct_window* w) { - Ride* ride = get_ride(w->number); + Ride* ride = get_ride(w->rideId); _trackDesign = ride->SaveToTrackDesign(); if (!_trackDesign) { @@ -5382,7 +5444,7 @@ static void window_ride_measurements_mousedown(rct_window* w, rct_widgetindex wi if (widgetIndex != WIDX_SAVE_TRACK_DESIGN) return; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -5508,7 +5570,8 @@ static void window_ride_measurements_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + const auto rideId = w->rideId; + auto ride = get_ride(rideId); if (ride == nullptr) return; @@ -5517,7 +5580,7 @@ static void window_ride_measurements_invalidate(rct_window* w) window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN_NOT_POSSIBLE; window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].type = WindowWidgetType::Empty; - if (gTrackDesignSaveMode && gTrackDesignSaveRideIndex == w->number) + if (gTrackDesignSaveMode && gTrackDesignSaveRideIndex == rideId) { window_ride_measurements_widgets[WIDX_SELECT_NEARBY_SCENERY].type = WindowWidgetType::Button; window_ride_measurements_widgets[WIDX_RESET_SELECTION].type = WindowWidgetType::Button; @@ -5570,7 +5633,7 @@ static void window_ride_measurements_paint(rct_window* w, rct_drawpixelinfo* dpi } else { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -5894,7 +5957,7 @@ static void window_ride_graphs_update(rct_window* w) x = w->scrolls[0].h_left; if (!(w->list_information_type & 0x8000)) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { RideMeasurement* measurement{}; @@ -5919,7 +5982,7 @@ static void window_ride_graphs_scrollgetheight(rct_window* w, int32_t scrollInde *width = window_ride_graphs_widgets[WIDX_GRAPH].width() - 2; // Get measurement size - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { RideMeasurement* measurement{}; @@ -5948,7 +6011,7 @@ static OpenRCT2String window_ride_graphs_tooltip(rct_window* w, const rct_widget { if (widgetIndex == WIDX_GRAPH) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { auto [measurement, message] = ride->GetMeasurement(); @@ -5988,7 +6051,7 @@ static void window_ride_graphs_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -6054,7 +6117,7 @@ static void window_ride_graphs_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi gfx_clear(dpi, ColourMapA[COLOUR_SATURATED_GREEN].darker); auto widget = &window_ride_graphs_widgets[WIDX_GRAPH]; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) { return; @@ -6247,7 +6310,8 @@ static void update_same_price_throughout_flags(ShopItem shop_item) */ static void window_ride_income_toggle_primary_price(rct_window* w) { - auto ride = get_ride(w->number); + const auto rideId = w->rideId; + auto ride = get_ride(rideId); if (ride == nullptr) return; @@ -6273,7 +6337,7 @@ static void window_ride_income_toggle_primary_price(rct_window* w) update_same_price_throughout_flags(shop_item); - auto rideSetPriceAction = RideSetPriceAction(w->number, ride->price[0], true); + auto rideSetPriceAction = RideSetPriceAction(rideId, ride->price[0], true); GameActions::Execute(&rideSetPriceAction); } @@ -6283,7 +6347,8 @@ static void window_ride_income_toggle_primary_price(rct_window* w) */ static void window_ride_income_toggle_secondary_price(rct_window* w) { - auto ride = get_ride(w->number); + const auto rideId = w->rideId; + auto ride = get_ride(rideId); if (ride == nullptr) return; @@ -6297,13 +6362,13 @@ static void window_ride_income_toggle_secondary_price(rct_window* w) update_same_price_throughout_flags(shop_item); - auto rideSetPriceAction = RideSetPriceAction(w->number, ride->price[1], false); + auto rideSetPriceAction = RideSetPriceAction(rideId, ride->price[1], false); GameActions::Execute(&rideSetPriceAction); } static void window_ride_income_set_primary_price(rct_window* w, money16 price) { - auto rideSetPriceAction = RideSetPriceAction(w->number, price, true); + auto rideSetPriceAction = RideSetPriceAction(w->rideId, price, true); GameActions::Execute(&rideSetPriceAction); } @@ -6316,7 +6381,7 @@ static void window_ride_income_increase_primary_price(rct_window* w) if (!window_ride_income_can_modify_primary_price(w)) return; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -6336,7 +6401,7 @@ static void window_ride_income_decrease_primary_price(rct_window* w) if (!window_ride_income_can_modify_primary_price(w)) return; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -6349,7 +6414,7 @@ static void window_ride_income_decrease_primary_price(rct_window* w) static money16 window_ride_income_get_secondary_price(rct_window* w) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return 0; @@ -6359,13 +6424,13 @@ static money16 window_ride_income_get_secondary_price(rct_window* w) static void window_ride_income_set_secondary_price(rct_window* w, money16 price) { - auto rideSetPriceAction = RideSetPriceAction((w->number & 0x00FF), price, false); + auto rideSetPriceAction = RideSetPriceAction(w->rideId, price, false); GameActions::Execute(&rideSetPriceAction); } static bool window_ride_income_can_modify_primary_price(rct_window* w) { - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return false; @@ -6430,7 +6495,7 @@ static void window_ride_income_mouseup(rct_window* w, rct_widgetindex widgetInde if (!window_ride_income_can_modify_primary_price(w)) return; - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { money_to_string(static_cast(ride->price[0]), _moneyInputText, MONEY_STRING_MAXLENGTH, true); @@ -6500,7 +6565,7 @@ static void window_ride_income_update(rct_window* w) window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_9); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr && ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_INCOME) { ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_INCOME; @@ -6547,7 +6612,7 @@ static void window_ride_income_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -6658,7 +6723,7 @@ static void window_ride_income_paint(rct_window* w, rct_drawpixelinfo* dpi) WindowDrawWidgets(w, dpi); window_ride_draw_tab_images(dpi, w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; @@ -6826,7 +6891,7 @@ static void window_ride_customer_update(rct_window* w) window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_10); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr && ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_CUSTOMER) { ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_CUSTOMER; @@ -6849,7 +6914,7 @@ static void window_ride_customer_invalidate(rct_window* w) window_ride_set_pressed_tab(w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride != nullptr) { auto ft = Formatter::Common(); @@ -6885,7 +6950,7 @@ static void window_ride_customer_paint(rct_window* w, rct_drawpixelinfo* dpi) WindowDrawWidgets(w, dpi); window_ride_draw_tab_images(dpi, w); - auto ride = get_ride(w->number); + auto ride = get_ride(w->rideId); if (ride == nullptr) return; diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 8879ec1607..b480d393a3 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -466,7 +466,7 @@ static void window_ride_construction_select_map_tiles( Ride* ride, int32_t trackType, int32_t trackDirection, const CoordsXY& tileCoords); static void window_ride_construction_show_special_track_dropdown(rct_window* w, rct_widget* widget); static void ride_selected_track_set_seat_rotation(int32_t seatRotation); -static void loc_6C7502(int32_t al); +static void UpdateLiftHillSelected(int32_t slope); static void ride_construction_set_brakes_speed(int32_t brakesSpeed); static void ride_construction_tooldown_entrance_exit(const ScreenCoordsXY& screenCoords); @@ -495,9 +495,9 @@ static int32_t ride_get_alternative_type(Ride* ride) } /* move to ride.c */ -static void close_ride_window_for_construction(rct_windownumber number) +static void close_ride_window_for_construction(ride_id_t rideId) { - rct_window* w = window_find_by_number(WC_RIDE, number); + rct_window* w = window_find_by_number(WC_RIDE, EnumValue(rideId)); if (w != nullptr && w->page == 1) window_close(w); } @@ -543,7 +543,7 @@ rct_window* window_ride_construction_open() w->colours[1] = COLOUR_DARK_BROWN; w->colours[2] = COLOUR_DARK_BROWN; - w->number = rideIndex; + w->rideId = rideIndex; window_push_others_right(w); show_gridlines(); @@ -620,7 +620,7 @@ static void window_ride_construction_close(rct_window* w) ride->SetToDefaultInspectionInterval(); auto intent = Intent(WC_RIDE); - intent.putExtra(INTENT_EXTRA_RIDE_ID, ride->id); + intent.putExtra(INTENT_EXTRA_RIDE_ID, EnumValue(ride->id)); context_open_intent(&intent); } else @@ -1376,11 +1376,11 @@ static void window_ride_construction_mousedown(rct_window* w, rct_widgetindex wi } if (w->widgets[WIDX_SLOPE_DOWN_STEEP].tooltip == STR_RIDE_CONSTRUCTION_STEEP_SLOPE_DOWN_TIP) { - loc_6C7502(8); + UpdateLiftHillSelected(TRACK_SLOPE_DOWN_60); } else { - loc_6C7502(10); + UpdateLiftHillSelected(TRACK_SLOPE_UP_90); } break; case WIDX_SLOPE_DOWN: @@ -1389,7 +1389,7 @@ static void window_ride_construction_mousedown(rct_window* w, rct_widgetindex wi { _currentTrackBankEnd = TRACK_BANK_NONE; } - loc_6C7502(6); + UpdateLiftHillSelected(TRACK_SLOPE_DOWN_25); break; case WIDX_LEVEL: ride_construction_invalidate_current_track(); @@ -1415,7 +1415,7 @@ static void window_ride_construction_mousedown(rct_window* w, rct_widgetindex wi _currentTrackBankEnd = TRACK_BANK_RIGHT; } } - loc_6C7502(0); + UpdateLiftHillSelected(TRACK_SLOPE_NONE); break; case WIDX_SLOPE_UP: ride_construction_invalidate_current_track(); @@ -1433,7 +1433,7 @@ static void window_ride_construction_mousedown(rct_window* w, rct_widgetindex wi } else { - loc_6C7502(2); + UpdateLiftHillSelected(TRACK_SLOPE_UP_25); } break; case WIDX_SLOPE_UP_STEEP: @@ -1508,20 +1508,18 @@ static void window_ride_construction_mousedown(rct_window* w, rct_widgetindex wi } if (w->widgets[WIDX_SLOPE_UP_STEEP].tooltip == STR_RIDE_CONSTRUCTION_STEEP_SLOPE_UP_TIP) { - loc_6C7502(4); + UpdateLiftHillSelected(TRACK_SLOPE_UP_60); } else { - loc_6C7502(18); + UpdateLiftHillSelected(TRACK_SLOPE_DOWN_90); } break; case WIDX_CHAIN_LIFT: ride_construction_invalidate_current_track(); _currentTrackLiftHill ^= CONSTRUCTION_LIFT_HILL_SELECTED; - if (_currentTrackLiftHill & CONSTRUCTION_LIFT_HILL_SELECTED) - { + if ((_currentTrackLiftHill & CONSTRUCTION_LIFT_HILL_SELECTED) && !gCheatsEnableChainLiftOnAllTrack) _currentTrackAlternative &= ~RIDE_TYPE_ALTERNATIVE_TRACK_PIECES; - } _currentTrackPrice = MONEY32_UNDEFINED; window_ride_construction_update_active_elements(); break; @@ -1599,7 +1597,8 @@ static void window_ride_construction_mousedown(rct_window* w, rct_widgetindex wi case WIDX_O_TRACK: ride_construction_invalidate_current_track(); _currentTrackAlternative |= RIDE_TYPE_ALTERNATIVE_TRACK_PIECES; - _currentTrackLiftHill &= ~CONSTRUCTION_LIFT_HILL_SELECTED; + if (!gCheatsEnableChainLiftOnAllTrack) + _currentTrackLiftHill &= ~CONSTRUCTION_LIFT_HILL_SELECTED; _currentTrackPrice = MONEY32_UNDEFINED; window_ride_construction_update_active_elements(); break; @@ -1888,8 +1887,9 @@ static void window_ride_construction_mouseup_demolish(rct_window* w) // Invalidate the selected track element or make sure it's at origin??? direction = _currentTrackPieceDirection; track_type_t type = _currentTrackPieceType; - auto newCoords = sub_6C683D({ _currentTrackBegin, static_cast(direction & 3) }, type, 0, &tileElement, 0); - if (newCoords == std::nullopt) + auto newCoords = GetTrackElementOriginAndApplyChanges( + { _currentTrackBegin, static_cast(direction & 3) }, type, 0, &tileElement, 0); + if (!newCoords.has_value()) { window_ride_construction_update_active_elements(); return; @@ -1918,9 +1918,10 @@ static void window_ride_construction_mouseup_demolish(rct_window* w) { direction = _currentTrackPieceDirection; type = _currentTrackPieceType; - newCoords = sub_6C683D({ _currentTrackBegin, static_cast(direction & 3) }, type, 0, &tileElement, 0); + newCoords = GetTrackElementOriginAndApplyChanges( + { _currentTrackBegin, static_cast(direction & 3) }, type, 0, &tileElement, 0); - if (newCoords == std::nullopt) + if (!newCoords.has_value()) { window_ride_construction_update_active_elements(); return; @@ -1936,7 +1937,7 @@ static void window_ride_construction_mouseup_demolish(rct_window* w) _currentTrackPieceType, 0, { _currentTrackBegin.x, _currentTrackBegin.y, _currentTrackBegin.z, _currentTrackPieceDirection }); - const auto rideId = w->number; + const auto rideId = w->rideId; trackRemoveAction.SetCallback([=](const GameAction* ga, const GameActions::Result* result) { if (result->Error != GameActions::Status::Ok) { @@ -1986,7 +1987,7 @@ static void window_ride_construction_entrance_click(rct_window* w) else { gRideEntranceExitPlaceType = ENTRANCE_TYPE_RIDE_ENTRANCE; - gRideEntranceExitPlaceRideIndex = static_cast(w->number); + gRideEntranceExitPlaceRideIndex = w->rideId; gRideEntranceExitPlaceStationIndex = 0; input_set_flag(INPUT_FLAG_6, true); ride_construction_invalidate_current_track(); @@ -2016,7 +2017,7 @@ static void window_ride_construction_exit_click(rct_window* w) else { gRideEntranceExitPlaceType = ENTRANCE_TYPE_RIDE_EXIT; - gRideEntranceExitPlaceRideIndex = w->number & 0xFF; + gRideEntranceExitPlaceRideIndex = w->rideId; gRideEntranceExitPlaceStationIndex = 0; input_set_flag(INPUT_FLAG_6, true); ride_construction_invalidate_current_track(); @@ -2089,7 +2090,7 @@ static void window_ride_construction_update(rct_window* w) break; } - sub_6C94D8(); + UpdateGhostTrackAndArrow(); } /** @@ -2158,7 +2159,7 @@ static std::optional ride_get_place_position_from_screen_position(Scre if (!_trackPlaceCtrlState) { mapCoords = ViewportInteractionGetTileStartAtCursor(screenCoords); - if (mapCoords.isNull()) + if (mapCoords.IsNull()) return std::nullopt; _trackPlaceZ = 0; @@ -2177,9 +2178,9 @@ static std::optional ride_get_place_position_from_screen_position(Scre { auto mapZ = _trackPlaceCtrlZ; auto mapXYCoords = screen_get_map_xy_with_z(screenCoords, mapZ); - if (mapXYCoords) + if (mapXYCoords.has_value()) { - mapCoords = *mapXYCoords; + mapCoords = mapXYCoords.value(); } else { @@ -2367,7 +2368,7 @@ static void window_ride_construction_draw_track_piece( mapCoords.y = 4112 + (rotatedMapCoords.y / 2); mapCoords.z = 1024 + mapCoords.z; - int16_t previewZOffset = TrackDefinitions[trackType].preview_z_offset; + int16_t previewZOffset = ted.Definition.preview_z_offset; mapCoords.z -= previewZOffset; const ScreenCoordsXY rotatedScreenCoords = translate_3d_to_2d_with_z(get_current_rotation(), mapCoords); @@ -2489,7 +2490,7 @@ void window_ride_construction_update_active_elements_impl() _selectedTrackType = TrackElemType::None; if (_rideConstructionState == RideConstructionState::Selected) { - if (sub_6C683D( + if (GetTrackElementOriginAndApplyChanges( { _currentTrackBegin, static_cast(_currentTrackPieceDirection & 3) }, _currentTrackPieceType, 0, &tileElement, 0) != std::nullopt) @@ -2527,7 +2528,7 @@ void window_ride_construction_update_enabled_track_pieces() * * rct2: 0x006C94D8 */ -void sub_6C94D8() +void UpdateGhostTrackAndArrow() { ride_id_t rideIndex; int32_t direction, type, liftHillAndAlternativeState; @@ -2551,6 +2552,7 @@ void sub_6C94D8() case RideConstructionState::Front: case RideConstructionState::Back: { + // place ghost piece if (!(_currentTrackSelectionFlags & TRACK_SELECTION_FLAG_TRACK)) { if (window_ride_construction_update_state( @@ -2565,7 +2567,7 @@ void sub_6C94D8() window_ride_construction_update_active_elements(); } } - + // update flashing arrow auto curTime = platform_get_ticks(); if (_rideConstructionNextArrowPulse >= curTime) break; @@ -2575,6 +2577,7 @@ void sub_6C94D8() trackPos = _currentTrackBegin; direction = _currentTrackPieceDirection; type = _currentTrackPieceType; + // diagonal pieces trigger this if (direction >= 4) direction += 4; if (_rideConstructionState == RideConstructionState::Back) @@ -2599,8 +2602,9 @@ void sub_6C94D8() type = _currentTrackPieceType; uint16_t flags = _currentTrackSelectionFlags & TRACK_SELECTION_FLAG_ARROW ? TRACK_ELEMENT_SET_HIGHLIGHT_TRUE : TRACK_ELEMENT_SET_HIGHLIGHT_FALSE; - auto newCoords = sub_6C683D({ _currentTrackBegin, static_cast(direction) }, type, 0, nullptr, flags); - if (newCoords == std::nullopt) + auto newCoords = GetTrackElementOriginAndApplyChanges( + { _currentTrackBegin, static_cast(direction) }, type, 0, nullptr, flags); + if (!newCoords.has_value()) { ride_construction_remove_ghosts(); _rideConstructionState = RideConstructionState::State0; @@ -2705,7 +2709,8 @@ static void window_ride_construction_update_possible_ride_configurations() _numCurrentPossibleSpecialTrackPieces = 0; for (trackType = 0; trackType < TrackElemType::Count; trackType++) { - int32_t trackTypeCategory = TrackDefinitions[trackType].type; + const auto& ted = GetTrackElementDescriptor(trackType); + int32_t trackTypeCategory = ted.Definition.type; if (trackTypeCategory == TRACK_NONE) continue; @@ -2718,13 +2723,13 @@ static void window_ride_construction_update_possible_ride_configurations() int32_t slope, bank; if (_rideConstructionState == RideConstructionState::Front || _rideConstructionState == RideConstructionState::Place) { - slope = TrackDefinitions[trackType].vangle_start; - bank = TrackDefinitions[trackType].bank_start; + slope = ted.Definition.vangle_start; + bank = ted.Definition.bank_start; } else if (_rideConstructionState == RideConstructionState::Back) { - slope = TrackDefinitions[trackType].vangle_end; - bank = TrackDefinitions[trackType].bank_end; + slope = ted.Definition.vangle_end; + bank = ted.Definition.bank_end; } else { @@ -2733,7 +2738,7 @@ static void window_ride_construction_update_possible_ride_configurations() if (!ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE)) { - if (TrackDefinitions[trackType].type == TRACK_HELIX_SMALL || TrackDefinitions[trackType].type == TRACK_HELIX_LARGE) + if (ted.Definition.type == TRACK_HELIX_SMALL || ted.Definition.type == TRACK_HELIX_LARGE) { if (bank != _previousTrackBankEnd) { @@ -3356,7 +3361,7 @@ static void window_ride_construction_show_special_track_dropdown(rct_window* w, */ static void ride_selected_track_set_seat_rotation(int32_t seatRotation) { - sub_6C683D( + GetTrackElementOriginAndApplyChanges( { _currentTrackBegin, static_cast(_currentTrackPieceDirection & 3) }, _currentTrackPieceType, seatRotation, nullptr, TRACK_ELEMENT_SET_SEAT_ROTATION); window_ride_construction_update_active_elements(); @@ -3366,15 +3371,21 @@ static void ride_selected_track_set_seat_rotation(int32_t seatRotation) * * rct2: 0x006C7502 */ -static void loc_6C7502(int32_t al) +static void UpdateLiftHillSelected(int32_t slope) { - _currentTrackSlopeEnd = al; + _currentTrackSlopeEnd = slope; _currentTrackPrice = MONEY32_UNDEFINED; if (_rideConstructionState == RideConstructionState::Front) { - if (al != 2 && al != 4 && al != 0) + switch (slope) { - _currentTrackLiftHill &= ~CONSTRUCTION_LIFT_HILL_SELECTED; + case TRACK_SLOPE_NONE: + case TRACK_SLOPE_UP_25: + case TRACK_SLOPE_UP_60: + break; + default: + _currentTrackLiftHill &= ~CONSTRUCTION_LIFT_HILL_SELECTED; + break; } } window_ride_construction_update_active_elements(); @@ -3388,7 +3399,7 @@ static void ride_construction_set_brakes_speed(int32_t brakesSpeed) { TileElement* tileElement; - if (sub_6C683D( + if (GetTrackElementOriginAndApplyChanges( { _currentTrackBegin, static_cast(_currentTrackPieceDirection & 3) }, _currentTrackPieceType, 0, &tileElement, 0) != std::nullopt) diff --git a/src/openrct2-ui/windows/RideList.cpp b/src/openrct2-ui/windows/RideList.cpp index aa932db73e..de3ecf4b09 100644 --- a/src/openrct2-ui/windows/RideList.cpp +++ b/src/openrct2-ui/windows/RideList.cpp @@ -443,7 +443,7 @@ static void window_ride_list_scrollmousedown(rct_window* w, int32_t scrollIndex, else { auto intent = Intent(WC_RIDE); - intent.putExtra(INTENT_EXTRA_RIDE_ID, rideIndex); + intent.putExtra(INTENT_EXTRA_RIDE_ID, EnumValue(rideIndex)); context_open_intent(&intent); } } diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp index 91fe22fc8c..5502f8494d 100644 --- a/src/openrct2-ui/windows/Staff.cpp +++ b/src/openrct2-ui/windows/Staff.cpp @@ -134,6 +134,8 @@ static void window_staff_overview_tool_up(rct_window* w, rct_widgetindex widgetI static void window_staff_overview_tool_abort(rct_window *w, rct_widgetindex widgetIndex); static void window_staff_overview_text_input(rct_window *w, rct_widgetindex widgetIndex, char *text); static void window_staff_overview_viewport_rotate(rct_window *w); +static void window_staff_follow(rct_window *w); +static void window_staff_show_locate_dropdown(rct_window* w, rct_widget* widget); static void window_staff_options_mouseup(rct_window *w, rct_widgetindex widgetIndex); static void window_staff_options_update(rct_window* w); @@ -408,14 +410,11 @@ void window_staff_overview_mouseup(rct_window* w, rct_widgetindex widgetIndex) case WIDX_TAB_3: window_staff_set_page(w, widgetIndex - WIDX_TAB_1); break; - case WIDX_LOCATE: - w->ScrollToViewport(); - break; case WIDX_PICKUP: { w->picked_peep_old_x = peep->x; CoordsXYZ nullLoc{}; - nullLoc.setNull(); + nullLoc.SetNull(); PeepPickupAction pickupAction{ PeepPickupType::Pickup, w->number, nullLoc, network_get_current_player_id() }; pickupAction.SetCallback([peepnum = w->number](const GameAction* ga, const GameActions::Result* result) { if (result->Error != GameActions::Status::Ok) @@ -509,30 +508,34 @@ void window_staff_overview_resize(rct_window* w) */ void window_staff_overview_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) { - if (widgetIndex != WIDX_PATROL) + switch (widgetIndex) { - return; - } + case WIDX_LOCATE: + window_staff_show_locate_dropdown(w, widget); + break; + case WIDX_PATROL: + { + // Dropdown names + gDropdownItemsFormat[0] = STR_SET_PATROL_AREA; + gDropdownItemsFormat[1] = STR_CLEAR_PATROL_AREA; - // Dropdown names - gDropdownItemsFormat[0] = STR_SET_PATROL_AREA; - gDropdownItemsFormat[1] = STR_CLEAR_PATROL_AREA; + auto dropdownPos = ScreenCoordsXY{ widget->left + w->windowPos.x, widget->top + w->windowPos.y }; + int32_t extray = widget->height() + 1; + WindowDropdownShowText(dropdownPos, extray, w->colours[1], 0, 2); + gDropdownDefaultIndex = 0; - auto dropdownPos = ScreenCoordsXY{ widget->left + w->windowPos.x, widget->top + w->windowPos.y }; - int32_t extray = widget->height() + 1; - WindowDropdownShowText(dropdownPos, extray, w->colours[1], 0, 2); - gDropdownDefaultIndex = 0; + const auto peep = GetStaff(w); + if (peep == nullptr) + { + return; + } - const auto peep = GetStaff(w); - if (peep == nullptr) - { - return; - } - - // Disable clear patrol area if no area is set. - if (!peep->HasPatrolArea()) - { - Dropdown::SetDisabled(1, true); + // Disable clear patrol area if no area is set. + if (!peep->HasPatrolArea()) + { + Dropdown::SetDisabled(1, true); + } + } } } @@ -542,31 +545,61 @@ void window_staff_overview_mousedown(rct_window* w, rct_widgetindex widgetIndex, */ void window_staff_overview_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) { - if (widgetIndex != WIDX_PATROL) + switch (widgetIndex) { - return; + case WIDX_LOCATE: + { + if (dropdownIndex == 0) + { + w->ScrollToViewport(); + } + else if (dropdownIndex == 1) + { + window_staff_follow(w); + } + break; + } + case WIDX_PATROL: + { + // Clear patrol + if (dropdownIndex == 1) + { + const auto staff = GetStaff(w); + if (staff != nullptr) + { + staff->ClearPatrolArea(); + gfx_invalidate_screen(); + staff_update_greyed_patrol_areas(); + } + } + else + { + if (!tool_set(w, widgetIndex, Tool::WalkDown)) + { + show_gridlines(); + gStaffDrawPatrolAreas = w->number; + gfx_invalidate_screen(); + } + } + break; + } } +} - // Clear patrol - if (dropdownIndex == 1) - { - const auto staff = GetStaff(w); - if (staff != nullptr) - { - staff->ClearPatrolArea(); - gfx_invalidate_screen(); - staff_update_greyed_patrol_areas(); - } - } - else - { - if (!tool_set(w, widgetIndex, Tool::WalkDown)) - { - show_gridlines(); - gStaffDrawPatrolAreas = w->number; - gfx_invalidate_screen(); - } - } +static void window_staff_show_locate_dropdown(rct_window* w, rct_widget* widget) +{ + gDropdownItemsFormat[0] = STR_LOCATE_SUBJECT_TIP; + gDropdownItemsFormat[1] = STR_FOLLOW_SUBJECT_TIP; + + WindowDropdownShowText( + { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, 2); + gDropdownDefaultIndex = 0; +} + +static void window_staff_follow(rct_window* w) +{ + rct_window* w_main = window_get_main(); + window_follow_sprite(w_main, w->number); } /** @@ -1131,7 +1164,7 @@ void window_staff_overview_tool_update(rct_window* w, rct_widgetindex widgetInde gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE; auto mapCoords = footpath_get_coordinates_from_pos({ screenCoords.x, screenCoords.y + 16 }, nullptr, nullptr); - if (!mapCoords.isNull()) + if (!mapCoords.IsNull()) { gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE; gMapSelectType = MAP_SELECT_TYPE_FULL; @@ -1178,7 +1211,7 @@ void window_staff_overview_tool_down(rct_window* w, rct_widgetindex widgetIndex, TileElement* tileElement; auto destCoords = footpath_get_coordinates_from_pos({ screenCoords.x, screenCoords.y + 16 }, nullptr, &tileElement); - if (destCoords.isNull()) + if (destCoords.IsNull()) return; PeepPickupAction pickupAction{ @@ -1196,7 +1229,7 @@ void window_staff_overview_tool_down(rct_window* w, rct_widgetindex widgetIndex, { auto destCoords = footpath_get_coordinates_from_pos(screenCoords, nullptr, nullptr); - if (destCoords.isNull()) + if (destCoords.IsNull()) return; auto staff = TryGetEntity(w->number); @@ -1232,7 +1265,7 @@ void window_staff_overview_tool_drag(rct_window* w, rct_widgetindex widgetIndex, auto destCoords = footpath_get_coordinates_from_pos(screenCoords, nullptr, nullptr); - if (destCoords.isNull()) + if (destCoords.IsNull()) return; auto staff = TryGetEntity(w->number); diff --git a/src/openrct2-ui/windows/StaffList.cpp b/src/openrct2-ui/windows/StaffList.cpp index 1899bdac1e..1f9a376317 100644 --- a/src/openrct2-ui/windows/StaffList.cpp +++ b/src/openrct2-ui/windows/StaffList.cpp @@ -552,7 +552,7 @@ private: int32_t direction{}; TileElement* tileElement{}; auto footpathCoords = footpath_get_coordinates_from_pos(screenCoords, &direction, &tileElement); - if (footpathCoords.isNull()) + if (footpathCoords.IsNull()) return nullptr; auto isPatrolAreaSet = staff_is_patrol_area_set_for_type(GetSelectedStaffType(), footpathCoords); diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index ff1847a068..aa76e620cf 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -1192,10 +1192,10 @@ static void window_tile_inspector_tool_update(rct_window* w, rct_widgetindex wid if (clickedElement == nullptr) { auto mouseCoords = screen_pos_to_map_pos(screenCoords, nullptr); - if (mouseCoords) + if (mouseCoords.has_value()) { mouseOnViewport = true; - mapCoords = *mouseCoords; + mapCoords = mouseCoords.value(); } } @@ -1245,12 +1245,12 @@ static void window_tile_inspector_update_selected_tile(rct_window* w, const Scre { auto mouseCoords = screen_pos_to_map_pos(screenCoords, nullptr); - if (!mouseCoords) + if (!mouseCoords.has_value()) { return; } - mapCoords = *mouseCoords; + mapCoords = mouseCoords.value(); // Tile is already selected if (windowTileInspectorTileSelected && mapCoords.x == windowTileInspectorToolMap.x && mapCoords.y == windowTileInspectorToolMap.y) @@ -1915,7 +1915,7 @@ static void window_tile_inspector_paint(rct_window* w, rct_drawpixelinfo* dpi) // Details // Ride auto trackElement = tileElement->AsTrack(); - int16_t rideId = trackElement->GetRideIndex(); + ride_id_t rideId = trackElement->GetRideIndex(); auto ride = get_ride(rideId); if (ride != nullptr) { diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index ce85997612..a84a2a0141 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -119,10 +121,12 @@ enum FILE_MENU_DDIDX { DDIDX_SCREENSHOT = 7, DDIDX_GIANT_SCREENSHOT = 8, // separator - DDIDX_QUIT_TO_MENU = 10, - DDIDX_EXIT_OPENRCT2 = 11, + DDIDX_FILE_BUG_ON_GITHUB = 10, // separator - DDIDX_UPDATE_AVAILABLE = 13, + DDIDX_QUIT_TO_MENU = 12, + DDIDX_EXIT_OPENRCT2 = 13, + // separator + DDIDX_UPDATE_AVAILABLE = 15, }; enum TOP_TOOLBAR_VIEW_MENU_DDIDX { @@ -423,60 +427,61 @@ static void window_top_toolbar_mouseup(rct_window* w, rct_widgetindex widgetInde */ static void window_top_toolbar_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) { - int32_t numItems; + int32_t numItems = 0; switch (widgetIndex) { case WIDX_FILE_MENU: if (gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { - gDropdownItemsFormat[0] = STR_ABOUT; - gDropdownItemsFormat[1] = STR_OPTIONS; - gDropdownItemsFormat[2] = STR_SCREENSHOT; - gDropdownItemsFormat[3] = STR_GIANT_SCREENSHOT; - gDropdownItemsFormat[4] = STR_EMPTY; - gDropdownItemsFormat[5] = STR_QUIT_TRACK_DESIGNS_MANAGER; - gDropdownItemsFormat[6] = STR_EXIT_OPENRCT2; + gDropdownItemsFormat[numItems++] = STR_ABOUT; + gDropdownItemsFormat[numItems++] = STR_OPTIONS; + gDropdownItemsFormat[numItems++] = STR_SCREENSHOT; + gDropdownItemsFormat[numItems++] = STR_GIANT_SCREENSHOT; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_FILE_BUG_ON_GITHUB; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_QUIT_TRACK_DESIGNS_MANAGER; + gDropdownItemsFormat[numItems++] = STR_EXIT_OPENRCT2; if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) - gDropdownItemsFormat[5] = STR_QUIT_ROLLERCOASTER_DESIGNER; - - numItems = 7; + gDropdownItemsFormat[numItems++] = STR_QUIT_ROLLERCOASTER_DESIGNER; } else if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) { - gDropdownItemsFormat[0] = STR_LOAD_LANDSCAPE; - gDropdownItemsFormat[1] = STR_SAVE_LANDSCAPE; - gDropdownItemsFormat[2] = STR_EMPTY; - gDropdownItemsFormat[3] = STR_ABOUT; - gDropdownItemsFormat[4] = STR_OPTIONS; - gDropdownItemsFormat[5] = STR_SCREENSHOT; - gDropdownItemsFormat[6] = STR_GIANT_SCREENSHOT; - gDropdownItemsFormat[7] = STR_EMPTY; - gDropdownItemsFormat[8] = STR_QUIT_SCENARIO_EDITOR; - gDropdownItemsFormat[9] = STR_EXIT_OPENRCT2; - numItems = 10; + gDropdownItemsFormat[numItems++] = STR_LOAD_LANDSCAPE; + gDropdownItemsFormat[numItems++] = STR_SAVE_LANDSCAPE; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_ABOUT; + gDropdownItemsFormat[numItems++] = STR_OPTIONS; + gDropdownItemsFormat[numItems++] = STR_SCREENSHOT; + gDropdownItemsFormat[numItems++] = STR_GIANT_SCREENSHOT; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_FILE_BUG_ON_GITHUB; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_QUIT_SCENARIO_EDITOR; + gDropdownItemsFormat[numItems++] = STR_EXIT_OPENRCT2; } else { - gDropdownItemsFormat[0] = STR_NEW_GAME; - gDropdownItemsFormat[1] = STR_LOAD_GAME; - gDropdownItemsFormat[2] = STR_SAVE_GAME; - gDropdownItemsFormat[3] = STR_SAVE_GAME_AS; - gDropdownItemsFormat[4] = STR_EMPTY; - gDropdownItemsFormat[5] = STR_ABOUT; - gDropdownItemsFormat[6] = STR_OPTIONS; - gDropdownItemsFormat[7] = STR_SCREENSHOT; - gDropdownItemsFormat[8] = STR_GIANT_SCREENSHOT; - gDropdownItemsFormat[9] = STR_EMPTY; - gDropdownItemsFormat[10] = STR_QUIT_TO_MENU; - gDropdownItemsFormat[11] = STR_EXIT_OPENRCT2; - numItems = 12; + gDropdownItemsFormat[numItems++] = STR_NEW_GAME; + gDropdownItemsFormat[numItems++] = STR_LOAD_GAME; + gDropdownItemsFormat[numItems++] = STR_SAVE_GAME; + gDropdownItemsFormat[numItems++] = STR_SAVE_GAME_AS; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_ABOUT; + gDropdownItemsFormat[numItems++] = STR_OPTIONS; + gDropdownItemsFormat[numItems++] = STR_SCREENSHOT; + gDropdownItemsFormat[numItems++] = STR_GIANT_SCREENSHOT; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_FILE_BUG_ON_GITHUB; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_QUIT_TO_MENU; + gDropdownItemsFormat[numItems++] = STR_EXIT_OPENRCT2; if (OpenRCT2::GetContext()->HasNewVersionInfo()) { - gDropdownItemsFormat[12] = STR_EMPTY; - gDropdownItemsFormat[13] = STR_UPDATE_AVAILABLE; - numItems += 2; + gDropdownItemsFormat[numItems++] = STR_EMPTY; + gDropdownItemsFormat[numItems++] = STR_UPDATE_AVAILABLE; } } WindowDropdownShowText( @@ -582,6 +587,15 @@ static void window_top_toolbar_dropdown(rct_window* w, rct_widgetindex widgetInd case DDIDX_GIANT_SCREENSHOT: screenshot_giant(); break; + case DDIDX_FILE_BUG_ON_GITHUB: + { + std::string url = "https://github.com/OpenRCT2/OpenRCT2/issues/" + "new?assignees=&labels=bug&template=bug_report.yaml"; + auto versionStr = String::URLEncode(gVersionInfoFull); + url.append("&openrct2_build=" + versionStr); + OpenRCT2::GetContext()->GetUiContext()->OpenURL(url); + } + break; case DDIDX_QUIT_TO_MENU: { window_close_by_class(WC_MANAGE_TRACK_DESIGN); @@ -661,13 +675,24 @@ static void window_top_toolbar_invalidate(rct_window* w) window_top_toolbar_widgets[WIDX_NETWORK].type = WindowWidgetType::TrnBtn; if (!gConfigInterface.toolbar_show_mute) - { window_top_toolbar_widgets[WIDX_MUTE].type = WindowWidgetType::Empty; - } if (!gConfigInterface.toolbar_show_chat) - { window_top_toolbar_widgets[WIDX_CHAT].type = WindowWidgetType::Empty; + + if (!gConfigInterface.toolbar_show_research) + window_top_toolbar_widgets[WIDX_RESEARCH].type = WindowWidgetType::Empty; + + if (!gConfigInterface.toolbar_show_cheats) + window_top_toolbar_widgets[WIDX_CHEATS].type = WindowWidgetType::Empty; + + if (!gConfigInterface.toolbar_show_news) + window_top_toolbar_widgets[WIDX_NEWS].type = WindowWidgetType::Empty; + + if (!gConfigInterface.toolbar_show_zoom) + { + window_top_toolbar_widgets[WIDX_ZOOM_IN].type = WindowWidgetType::Empty; + window_top_toolbar_widgets[WIDX_ZOOM_OUT].type = WindowWidgetType::Empty; } if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR || gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) @@ -675,6 +700,9 @@ static void window_top_toolbar_invalidate(rct_window* w) window_top_toolbar_widgets[WIDX_PAUSE].type = WindowWidgetType::Empty; } + if ((gParkFlags & PARK_FLAGS_NO_MONEY) || !gConfigInterface.toolbar_show_finances) + window_top_toolbar_widgets[WIDX_FINANCES].type = WindowWidgetType::Empty; + if (gScreenFlags & SCREEN_FLAGS_EDITOR) { window_top_toolbar_widgets[WIDX_PARK].type = WindowWidgetType::Empty; @@ -711,39 +739,19 @@ static void window_top_toolbar_invalidate(rct_window* w) window_top_toolbar_widgets[WIDX_VIEW_MENU].type = WindowWidgetType::Empty; } } - else + + switch (network_get_mode()) { - if ((gParkFlags & PARK_FLAGS_NO_MONEY) || !gConfigInterface.toolbar_show_finances) - window_top_toolbar_widgets[WIDX_FINANCES].type = WindowWidgetType::Empty; - - if (!gConfigInterface.toolbar_show_research) - window_top_toolbar_widgets[WIDX_RESEARCH].type = WindowWidgetType::Empty; - - if (!gConfigInterface.toolbar_show_cheats) - window_top_toolbar_widgets[WIDX_CHEATS].type = WindowWidgetType::Empty; - - if (!gConfigInterface.toolbar_show_news) - window_top_toolbar_widgets[WIDX_NEWS].type = WindowWidgetType::Empty; - - if (!gConfigInterface.toolbar_show_zoom) - { - window_top_toolbar_widgets[WIDX_ZOOM_IN].type = WindowWidgetType::Empty; - window_top_toolbar_widgets[WIDX_ZOOM_OUT].type = WindowWidgetType::Empty; - } - - switch (network_get_mode()) - { - case NETWORK_MODE_NONE: - window_top_toolbar_widgets[WIDX_NETWORK].type = WindowWidgetType::Empty; - window_top_toolbar_widgets[WIDX_CHAT].type = WindowWidgetType::Empty; - break; - case NETWORK_MODE_CLIENT: - window_top_toolbar_widgets[WIDX_PAUSE].type = WindowWidgetType::Empty; - [[fallthrough]]; - case NETWORK_MODE_SERVER: - window_top_toolbar_widgets[WIDX_FASTFORWARD].type = WindowWidgetType::Empty; - break; - } + case NETWORK_MODE_NONE: + window_top_toolbar_widgets[WIDX_NETWORK].type = WindowWidgetType::Empty; + window_top_toolbar_widgets[WIDX_CHAT].type = WindowWidgetType::Empty; + break; + case NETWORK_MODE_CLIENT: + window_top_toolbar_widgets[WIDX_PAUSE].type = WindowWidgetType::Empty; + [[fallthrough]]; + case NETWORK_MODE_SERVER: + window_top_toolbar_widgets[WIDX_FASTFORWARD].type = WindowWidgetType::Empty; + break; } enabledWidgets = 0; @@ -1233,7 +1241,7 @@ static void sub_6E1F34_small_scenery( if (w == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1259,12 +1267,12 @@ static void sub_6E1F34_small_scenery( if (!gSceneryCtrlPressed) { auto gridCoords = screen_get_map_xy_quadrant(screenPos, &quadrant); - if (!gridCoords) + if (!gridCoords.has_value()) { - gridPos.setNull(); + gridPos.SetNull(); return; } - gridPos = *gridCoords; + gridPos = gridCoords.value(); gSceneryPlaceZ = 0; @@ -1275,7 +1283,7 @@ static void sub_6E1F34_small_scenery( if (surfaceElement == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1292,12 +1300,12 @@ static void sub_6E1F34_small_scenery( int16_t z = gSceneryCtrlPressZ; auto mapCoords = screen_get_map_xy_quadrant_with_z(screenPos, z, &quadrant); - if (!mapCoords) + if (!mapCoords.has_value()) { - gridPos.setNull(); + gridPos.SetNull(); return; } - gridPos = *mapCoords; + gridPos = mapCoords.value(); // If SHIFT pressed if (gSceneryShiftPressed) @@ -1310,7 +1318,7 @@ static void sub_6E1F34_small_scenery( gSceneryPlaceZ = z; } - if (gridPos.isNull()) + if (gridPos.IsNull()) return; uint8_t rotation = gWindowSceneryRotation; @@ -1344,7 +1352,7 @@ static void sub_6E1F34_small_scenery( if (info.SpriteType == ViewportInteractionItem::None) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1358,7 +1366,7 @@ static void sub_6E1F34_small_scenery( if (surfaceElement == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1374,13 +1382,13 @@ static void sub_6E1F34_small_scenery( { int16_t z = gSceneryCtrlPressZ; auto coords = screen_get_map_xy_with_z(screenPos, z); - if (coords) + if (coords.has_value()) { gridPos = *coords; } else { - gridPos.setNull(); + gridPos.SetNull(); } // If SHIFT pressed if (gSceneryShiftPressed) @@ -1393,7 +1401,7 @@ static void sub_6E1F34_small_scenery( gSceneryPlaceZ = z; } - if (gridPos.isNull()) + if (gridPos.IsNull()) return; gridPos = gridPos.ToTileStart(); @@ -1423,7 +1431,7 @@ static void sub_6E1F34_path_item( if (w == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1437,7 +1445,7 @@ static void sub_6E1F34_path_item( if (info.SpriteType == ViewportInteractionItem::None) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1456,7 +1464,7 @@ static void sub_6E1F34_wall( if (w == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1477,12 +1485,12 @@ static void sub_6E1F34_wall( if (!gSceneryCtrlPressed) { auto gridCoords = screen_get_map_xy_side(screenPos, &edge); - if (!gridCoords) + if (!gridCoords.has_value()) { - gridPos.setNull(); + gridPos.SetNull(); return; } - gridPos = *gridCoords; + gridPos = gridCoords.value(); gSceneryPlaceZ = 0; @@ -1493,7 +1501,7 @@ static void sub_6E1F34_wall( if (surfaceElement == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1509,12 +1517,12 @@ static void sub_6E1F34_wall( { int16_t z = gSceneryCtrlPressZ; auto mapCoords = screen_get_map_xy_side_with_z(screenPos, z, &edge); - if (!mapCoords) + if (!mapCoords.has_value()) { - gridPos.setNull(); + gridPos.SetNull(); return; } - gridPos = *mapCoords; + gridPos = mapCoords.value(); // If SHIFT pressed if (gSceneryShiftPressed) @@ -1527,7 +1535,7 @@ static void sub_6E1F34_wall( gSceneryPlaceZ = z; } - if (gridPos.isNull()) + if (gridPos.IsNull()) return; if (gConfigGeneral.virtual_floor_style != VirtualFloorStyles::Off) @@ -1545,7 +1553,7 @@ static void sub_6E1F34_large_scenery( if (w == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1572,7 +1580,7 @@ static void sub_6E1F34_large_scenery( const CoordsXY mapCoords = ViewportInteractionGetTileStartAtCursor(screenPos); gridPos = mapCoords; - if (gridPos.isNull()) + if (gridPos.IsNull()) return; gSceneryPlaceZ = 0; @@ -1584,7 +1592,7 @@ static void sub_6E1F34_large_scenery( if (surfaceElement == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1600,13 +1608,13 @@ static void sub_6E1F34_large_scenery( { int16_t z = gSceneryCtrlPressZ; auto coords = screen_get_map_xy_with_z(screenPos, z); - if (coords) + if (coords.has_value()) { gridPos = *coords; } else { - gridPos.setNull(); + gridPos.SetNull(); } // If SHIFT pressed @@ -1620,7 +1628,7 @@ static void sub_6E1F34_large_scenery( gSceneryPlaceZ = z; } - if (gridPos.isNull()) + if (gridPos.IsNull()) return; gridPos = gridPos.ToTileStart(); @@ -1645,7 +1653,7 @@ static void sub_6E1F34_banner( if (w == nullptr) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1659,7 +1667,7 @@ static void sub_6E1F34_banner( if (info.SpriteType == ViewportInteractionItem::None) { - gridPos.setNull(); + gridPos.SetNull(); return; } @@ -1718,7 +1726,7 @@ static void window_top_toolbar_scenery_tool_down(const ScreenCoordsXY& windowPos uint8_t quadrant; Direction rotation; sub_6E1F34_small_scenery(windowPos, selectedScenery, gridPos, &quadrant, &rotation); - if (gridPos.isNull()) + if (gridPos.IsNull()) return; int32_t quantity = 1; @@ -1838,7 +1846,7 @@ static void window_top_toolbar_scenery_tool_down(const ScreenCoordsXY& windowPos { int32_t z; sub_6E1F34_path_item(windowPos, selectedScenery, gridPos, &z); - if (gridPos.isNull()) + if (gridPos.IsNull()) return; auto footpathAdditionPlaceAction = FootpathAdditionPlaceAction({ gridPos, z }, selectedScenery + 1); @@ -1857,7 +1865,7 @@ static void window_top_toolbar_scenery_tool_down(const ScreenCoordsXY& windowPos { uint8_t edges; sub_6E1F34_wall(windowPos, selectedScenery, gridPos, &edges); - if (gridPos.isNull()) + if (gridPos.IsNull()) return; uint8_t zAttemptRange = 1; @@ -1909,7 +1917,7 @@ static void window_top_toolbar_scenery_tool_down(const ScreenCoordsXY& windowPos { Direction direction; sub_6E1F34_large_scenery(windowPos, selectedScenery, gridPos, &direction); - if (gridPos.isNull()) + if (gridPos.IsNull()) return; uint8_t zAttemptRange = 1; @@ -1967,17 +1975,18 @@ static void window_top_toolbar_scenery_tool_down(const ScreenCoordsXY& windowPos int32_t z; Direction direction; sub_6E1F34_banner(windowPos, selectedScenery, gridPos, &z, &direction); - if (gridPos.isNull()) + if (gridPos.IsNull()) return; CoordsXYZD loc{ gridPos, z, direction }; auto primaryColour = gWindowSceneryPrimaryColour; auto bannerPlaceAction = BannerPlaceAction(loc, selectedScenery, primaryColour); - bannerPlaceAction.SetCallback([=](const GameAction* ga, const BannerPlaceActionResult* result) { + bannerPlaceAction.SetCallback([=](const GameAction* ga, const GameActions::Result* result) { if (result->Error == GameActions::Status::Ok) { + auto data = result->GetData(); OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::PlaceItem, result->Position); - context_open_detail_window(WD_BANNER, result->bannerId); + context_open_detail_window(WD_BANNER, data.bannerId); } }); GameActions::Execute(&bannerPlaceAction); @@ -1995,7 +2004,7 @@ static uint8_t top_toolbar_tool_update_land_paint(const ScreenCoordsXY& screenPo auto mapTile = screen_get_map_xy(screenPos, nullptr); - if (!mapTile) + if (!mapTile.has_value()) { if (gClearSceneryCost != MONEY64_UNDEFINED) { @@ -2114,7 +2123,7 @@ static void top_toolbar_tool_update_land(const ScreenCoordsXY& screenPos) screen_pos_to_map_pos(screenPos, &selectionType); mapTile = screen_get_map_xy_side(screenPos, &side); - if (!mapTile) + if (!mapTile.has_value()) { money64 lower_cost = MONEY64_UNDEFINED; money64 raise_cost = MONEY64_UNDEFINED; @@ -2191,7 +2200,7 @@ static void top_toolbar_tool_update_land(const ScreenCoordsXY& screenPos) // Get map coordinates and the side of the tile that is being hovered over mapTile = screen_get_map_xy_side(screenPos, &side); - if (!mapTile) + if (!mapTile.has_value()) { money64 lower_cost = MONEY64_UNDEFINED; money64 raise_cost = MONEY64_UNDEFINED; @@ -2623,7 +2632,7 @@ static void top_toolbar_tool_update_scenery(const ScreenCoordsXY& screenPos) sub_6E1F34_small_scenery(screenPos, selection.EntryIndex, mapTile, &quadrant, &rotation); - if (mapTile.isNull()) + if (mapTile.IsNull()) { scenery_remove_ghost_tool_placement(); return; @@ -2701,7 +2710,7 @@ static void top_toolbar_tool_update_scenery(const ScreenCoordsXY& screenPos) sub_6E1F34_path_item(screenPos, selection.EntryIndex, mapTile, &z); - if (mapTile.isNull()) + if (mapTile.IsNull()) { scenery_remove_ghost_tool_placement(); return; @@ -2736,7 +2745,7 @@ static void top_toolbar_tool_update_scenery(const ScreenCoordsXY& screenPos) sub_6E1F34_wall(screenPos, selection.EntryIndex, mapTile, &edge); - if (mapTile.isNull()) + if (mapTile.IsNull()) { scenery_remove_ghost_tool_placement(); return; @@ -2791,7 +2800,7 @@ static void top_toolbar_tool_update_scenery(const ScreenCoordsXY& screenPos) sub_6E1F34_large_scenery(screenPos, selection.EntryIndex, mapTile, &direction); - if (mapTile.isNull()) + if (mapTile.IsNull()) { scenery_remove_ghost_tool_placement(); return; @@ -2858,7 +2867,7 @@ static void top_toolbar_tool_update_scenery(const ScreenCoordsXY& screenPos) sub_6E1F34_banner(screenPos, selection.EntryIndex, mapTile, &z, &direction); - if (mapTile.isNull()) + if (mapTile.IsNull()) { scenery_remove_ghost_tool_placement(); return; diff --git a/src/openrct2-ui/windows/TrackDesignPlace.cpp b/src/openrct2-ui/windows/TrackDesignPlace.cpp index 58da05f5bd..9cc6a33cc7 100644 --- a/src/openrct2-ui/windows/TrackDesignPlace.cpp +++ b/src/openrct2-ui/windows/TrackDesignPlace.cpp @@ -152,7 +152,7 @@ rct_window* window_track_place_open(const track_design_file_ref* tdFileRef) window_push_others_right(w); show_gridlines(); _window_track_place_last_cost = MONEY32_UNDEFINED; - _windowTrackPlaceLast.setNull(); + _windowTrackPlaceLast.SetNull(); _currentTrackPieceDirection = (2 - get_current_rotation()) & 3; window_track_place_clear_mini_preview(); @@ -193,14 +193,14 @@ static void window_track_place_mouseup(rct_window* w, rct_widgetindex widgetInde window_track_place_clear_provisional(); _currentTrackPieceDirection = (_currentTrackPieceDirection + 1) & 3; w->Invalidate(); - _windowTrackPlaceLast.setNull(); + _windowTrackPlaceLast.SetNull(); window_track_place_draw_mini_preview(_trackDesign.get()); break; case WIDX_MIRROR: track_design_mirror(_trackDesign.get()); _currentTrackPieceDirection = (0 - _currentTrackPieceDirection) & 3; w->Invalidate(); - _windowTrackPlaceLast.setNull(); + _windowTrackPlaceLast.SetNull(); window_track_place_draw_mini_preview(_trackDesign.get()); break; case WIDX_SELECT_DIFFERENT_DESIGN: @@ -259,7 +259,7 @@ static void window_track_place_toolupdate(rct_window* w, rct_widgetindex widgetI // Get the tool map position CoordsXY mapCoords = ViewportInteractionGetTileStartAtCursor(screenCoords); - if (mapCoords.isNull()) + if (mapCoords.IsNull()) { window_track_place_clear_provisional(); return; @@ -268,7 +268,8 @@ static void window_track_place_toolupdate(rct_window* w, rct_widgetindex widgetI // Check if tool map position has changed since last update if (mapCoords == _windowTrackPlaceLast) { - place_virtual_track(_trackDesign.get(), PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(0), { mapCoords, 0 }); + place_virtual_track( + _trackDesign.get(), PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(PreviewRideId), { mapCoords, 0 }); return; } @@ -308,7 +309,7 @@ static void window_track_place_toolupdate(rct_window* w, rct_widgetindex widgetI widget_invalidate(w, WIDX_PRICE); } - place_virtual_track(_trackDesign.get(), PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(0), trackLoc); + place_virtual_track(_trackDesign.get(), PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(PreviewRideId), trackLoc); } /** @@ -324,7 +325,7 @@ static void window_track_place_tooldown(rct_window* w, rct_widgetindex widgetInd gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW; const CoordsXY mapCoords = ViewportInteractionGetTileStartAtCursor(screenCoords); - if (mapCoords.isNull()) + if (mapCoords.IsNull()) return; // Try increasing Z until a feasible placement is found @@ -348,7 +349,7 @@ static void window_track_place_tooldown(rct_window* w, rct_widgetindex widgetInd if (track_design_are_entrance_and_exit_placed()) { auto intent = Intent(WC_RIDE); - intent.putExtra(INTENT_EXTRA_RIDE_ID, result->rideIndex); + intent.putExtra(INTENT_EXTRA_RIDE_ID, static_cast(result->rideIndex)); context_open_intent(&intent); auto wnd = window_find_by_class(WC_TRACK_DESIGN_PLACE); window_close(wnd); @@ -469,7 +470,9 @@ static int32_t window_track_place_get_base_z(const CoordsXY& loc) if (surfaceElement->GetWaterHeight() > 0) z = std::max(z, surfaceElement->GetWaterHeight()); - return z + place_virtual_track(_trackDesign.get(), PTD_OPERATION_GET_PLACE_Z, true, GetOrAllocateRide(0), { loc, z }); + return z + + place_virtual_track( + _trackDesign.get(), PTD_OPERATION_GET_PLACE_Z, true, GetOrAllocateRide(PreviewRideId), { loc, z }); } /** diff --git a/src/openrct2-ui/windows/ViewClipping.cpp b/src/openrct2-ui/windows/ViewClipping.cpp index 52da8f5083..922b51d1b2 100644 --- a/src/openrct2-ui/windows/ViewClipping.cpp +++ b/src/openrct2-ui/windows/ViewClipping.cpp @@ -303,12 +303,12 @@ static void window_view_clipping_tool_update(rct_window* w, rct_widgetindex widg int32_t direction; auto mapCoords = screen_pos_to_map_pos(screenCoords, &direction); - if (mapCoords) + if (mapCoords.has_value()) { gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE; map_invalidate_tile_full(gMapSelectPositionA); - gMapSelectPositionA = gMapSelectPositionB = *mapCoords; - map_invalidate_tile_full(*mapCoords); + gMapSelectPositionA = gMapSelectPositionB = mapCoords.value(); + map_invalidate_tile_full(mapCoords.value()); gMapSelectType = MAP_SELECT_TYPE_FULL; } } @@ -317,10 +317,10 @@ static void window_view_clipping_tool_down(rct_window* w, rct_widgetindex widget { int32_t direction; auto mapCoords = screen_pos_to_map_pos(screenCoords, &direction); - if (mapCoords) + if (mapCoords.has_value()) { _dragging = true; - _selectionStart = *mapCoords; + _selectionStart = mapCoords.value(); } } diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index e1f5ab0b98..b0fbad775e 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -47,7 +47,7 @@ rct_window* window_editor_main_open(); rct_window* window_editor_objective_options_open(); rct_window* window_editor_scenario_options_open(); rct_window* window_footpath_open(); -void window_footpath_reset_selected_path(); +void WindowFootpathResetSelectedPath(); rct_window* window_guest_open(Peep* peep); rct_window* window_land_open(); rct_window* window_land_rights_open(); diff --git a/src/openrct2/CmdlineSprite.cpp b/src/openrct2/CmdlineSprite.cpp index 1d2459f7ee..2a0234db4a 100644 --- a/src/openrct2/CmdlineSprite.cpp +++ b/src/openrct2/CmdlineSprite.cpp @@ -545,7 +545,7 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc) } auto importResult = SpriteImageImport(imagePath, x_offset, y_offset, false, false, gSpriteMode); - if (importResult == std::nullopt) + if (!importResult.has_value()) return -1; auto spriteFile = SpriteFile::Open(spriteFilePath); diff --git a/src/openrct2/EditorObjectSelectionSession.cpp b/src/openrct2/EditorObjectSelectionSession.cpp index 92bacf8715..5a82635938 100644 --- a/src/openrct2/EditorObjectSelectionSession.cpp +++ b/src/openrct2/EditorObjectSelectionSession.cpp @@ -149,11 +149,11 @@ void setup_in_use_selection_flags() case TILE_ELEMENT_TYPE_PATH: { auto footpathEl = iter.element->AsPath(); - auto legacyPathEntryIndex = footpathEl->GetPathEntryIndex(); + auto legacyPathEntryIndex = footpathEl->GetLegacyPathEntryIndex(); if (legacyPathEntryIndex == OBJECT_ENTRY_INDEX_NULL) { auto surfaceEntryIndex = footpathEl->GetSurfaceEntryIndex(); - auto railingEntryIndex = footpathEl->GetRailingEntryIndex(); + auto railingEntryIndex = footpathEl->GetRailingsEntryIndex(); Editor::SetSelectedObject(ObjectType::FootpathSurface, surfaceEntryIndex, OBJECT_SELECTION_FLAG_SELECTED); Editor::SetSelectedObject(ObjectType::FootpathRailings, railingEntryIndex, OBJECT_SELECTION_FLAG_SELECTED); } @@ -184,7 +184,7 @@ void setup_in_use_selection_flags() if (parkEntranceEl->GetSequenceIndex() != 0) break; - auto legacyPathEntryIndex = parkEntranceEl->GetPathEntryIndex(); + auto legacyPathEntryIndex = parkEntranceEl->GetLegacyPathEntryIndex(); if (legacyPathEntryIndex == OBJECT_ENTRY_INDEX_NULL) { auto surfaceEntryIndex = parkEntranceEl->GetSurfaceEntryIndex(); @@ -217,15 +217,11 @@ void setup_in_use_selection_flags() } } while (tile_element_iterator_next(&iter)); - for (ride_id_t ride_index = 0; ride_index < MAX_RIDES; ride_index++) + for (auto& ride : GetRideManager()) { - auto ride = get_ride(ride_index); - if (ride != nullptr) - { - Editor::SetSelectedObject(ObjectType::Ride, ride->subtype, OBJECT_SELECTION_FLAG_SELECTED); - Editor::SetSelectedObject(ObjectType::Station, ride->entrance_style, OBJECT_SELECTION_FLAG_SELECTED); - Editor::SetSelectedObject(ObjectType::Music, ride->music, OBJECT_SELECTION_FLAG_SELECTED); - } + Editor::SetSelectedObject(ObjectType::Ride, ride.subtype, OBJECT_SELECTION_FLAG_SELECTED); + Editor::SetSelectedObject(ObjectType::Station, ride.entrance_style, OBJECT_SELECTION_FLAG_SELECTED); + Editor::SetSelectedObject(ObjectType::Music, ride.music, OBJECT_SELECTION_FLAG_SELECTED); } // Apply selected object status for hacked vehicles that may not have an associated ride @@ -289,7 +285,7 @@ void sub_6AB211() const ObjectRepositoryItem* items = object_repository_get_items(); for (int32_t i = 0; i < numObjects; i++) { - auto objectType = items[i].Type; + ObjectType objectType = items[i].Type; _numAvailableObjectsForType[EnumValue(objectType)]++; } @@ -431,6 +427,7 @@ static void ReplaceSelectedWaterPalette(const ObjectRepositoryItem* item) { auto& objectManager = OpenRCT2::GetContext()->GetObjectManager(); auto* oldPalette = objectManager.GetLoadedObject(ObjectType::Water, 0); + if (oldPalette != nullptr) { const std::vector oldEntries = { oldPalette->GetDescriptor() }; @@ -463,7 +460,7 @@ void reset_selected_object_count_and_size() const ObjectRepositoryItem* items = object_repository_get_items(); for (int32_t i = 0; i < numObjects; i++) { - auto objectType = items[i].Type; + ObjectType objectType = items[i].Type; if (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) { _numSelectedObjectsForType[EnumValue(objectType)]++; diff --git a/src/openrct2/ReplayManager.cpp b/src/openrct2/ReplayManager.cpp index f0d1ab95c5..436a146fb0 100644 --- a/src/openrct2/ReplayManager.cpp +++ b/src/openrct2/ReplayManager.cpp @@ -851,7 +851,7 @@ namespace OpenRCT2 } // Focus camera on event. - if (isPositionValid && !result->Position.isNull()) + if (isPositionValid && !result->Position.IsNull()) { auto* mainWindow = window_get_main(); if (mainWindow != nullptr) diff --git a/src/openrct2/actions/BannerPlaceAction.cpp b/src/openrct2/actions/BannerPlaceAction.cpp index 88e6860d27..5fcc570d31 100644 --- a/src/openrct2/actions/BannerPlaceAction.cpp +++ b/src/openrct2/actions/BannerPlaceAction.cpp @@ -18,26 +18,6 @@ using namespace OpenRCT2; -BannerPlaceActionResult::BannerPlaceActionResult() - : GameActions::Result(GameActions::Status::Ok, STR_CANT_POSITION_THIS_HERE) -{ -} - -BannerPlaceActionResult::BannerPlaceActionResult(GameActions::Status err) - : GameActions::Result(err, STR_CANT_POSITION_THIS_HERE) -{ -} - -BannerPlaceActionResult::BannerPlaceActionResult(GameActions::Status err, rct_string_id msg) - : GameActions::Result(err, STR_CANT_POSITION_THIS_HERE, msg) -{ -} - -BannerPlaceActionResult::BannerPlaceActionResult(GameActions::Status err, rct_string_id title, rct_string_id message) - : GameActions::Result(err, title, message) -{ -} - BannerPlaceAction::BannerPlaceAction(const CoordsXYZD& loc, ObjectEntryIndex bannerType, colour_t primaryColour) : _loc(loc) , _bannerType(bannerType) @@ -117,6 +97,7 @@ GameActions::Result::Ptr BannerPlaceAction::Query() const return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_POSITION_THIS_HERE); } res->Cost = bannerEntry->price; + return res; } @@ -155,8 +136,7 @@ GameActions::Result::Ptr BannerPlaceAction::Execute() const banner->colour = _primaryColour; banner->position = TileCoordsXY(_loc); - res->bannerId = banner->id; - + res->SetData(BannerPlaceActionResult{ banner->id }); auto* bannerElement = TileElementInsert({ _loc, _loc.z + (2 * COORDS_Z_STEP) }, 0b0000); Guard::Assert(bannerElement != nullptr); diff --git a/src/openrct2/actions/BannerPlaceAction.h b/src/openrct2/actions/BannerPlaceAction.h index c4195a18ca..5de3d37e82 100644 --- a/src/openrct2/actions/BannerPlaceAction.h +++ b/src/openrct2/actions/BannerPlaceAction.h @@ -11,18 +11,12 @@ #include "GameAction.h" -class BannerPlaceActionResult final : public GameActions::Result +struct BannerPlaceActionResult { -public: - BannerPlaceActionResult(); - BannerPlaceActionResult(GameActions::Status err); - BannerPlaceActionResult(GameActions::Status err, rct_string_id msg); - BannerPlaceActionResult(GameActions::Status err, rct_string_id title, rct_string_id message); - BannerIndex bannerId = BANNER_INDEX_NULL; }; -DEFINE_GAME_ACTION(BannerPlaceAction, GameCommand::PlaceBanner, BannerPlaceActionResult) +DEFINE_GAME_ACTION(BannerPlaceAction, GameCommand::PlaceBanner, GameActions::Result) { private: CoordsXYZD _loc; diff --git a/src/openrct2/actions/FootpathPlaceAction.cpp b/src/openrct2/actions/FootpathPlaceAction.cpp index d345846653..de6bda9fa8 100644 --- a/src/openrct2/actions/FootpathPlaceAction.cpp +++ b/src/openrct2/actions/FootpathPlaceAction.cpp @@ -162,23 +162,23 @@ bool FootpathPlaceAction::IsSameAsPathElement(const PathElement* pathElement) co if (pathElement->IsQueue() != ((_constructFlags & PathConstructFlag::IsQueue) != 0)) return false; - auto footpathObj = pathElement->GetPathEntry(); + auto footpathObj = pathElement->GetLegacyPathEntry(); if (footpathObj == nullptr) { - if (_constructFlags & PathConstructFlag::IsPathObject) + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) { return false; } else { - return pathElement->GetSurfaceEntryIndex() == _type && pathElement->GetRailingEntryIndex() == _railingsType; + return pathElement->GetSurfaceEntryIndex() == _type && pathElement->GetRailingsEntryIndex() == _railingsType; } } else { - if (_constructFlags & PathConstructFlag::IsPathObject) + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) { - return pathElement->GetPathEntryIndex() == _type; + return pathElement->GetLegacyPathEntryIndex() == _type; } else { @@ -187,6 +187,30 @@ bool FootpathPlaceAction::IsSameAsPathElement(const PathElement* pathElement) co } } +bool FootpathPlaceAction::IsSameAsEntranceElement(const EntranceElement& entranceElement) const +{ + if (entranceElement.HasLegacyPathEntry()) + { + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) + { + return entranceElement.GetLegacyPathEntryIndex() == _type; + } + else + { + return false; + } + } + + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) + { + return false; + } + else + { + return entranceElement.GetSurfaceEntryIndex() == _type; + } +} + GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateQuery(PathElement* pathElement, GameActions::Result::Ptr res) const { if (!IsSameAsPathElement(pathElement)) @@ -215,14 +239,14 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementUpdateExecute(PathElement* footpath_remove_edges_at(_loc, reinterpret_cast(pathElement)); } - if (_constructFlags & PathConstructFlag::IsPathObject) + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) { - pathElement->SetPathEntryIndex(_type); + pathElement->SetLegacyPathEntryIndex(_type); } else { pathElement->SetSurfaceEntryIndex(_type); - pathElement->SetRailingEntryIndex(_railingsType); + pathElement->SetRailingsEntryIndex(_railingsType); } pathElement->SetIsQueue((_constructFlags & PathConstructFlag::IsQueue) != 0); @@ -280,7 +304,7 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertQuery(GameActions::Re { entrancePath = true; // Make the price the same as replacing a path - if (entranceElement->GetSurfaceEntryIndex() == _type) + if (IsSameAsEntranceElement(*entranceElement)) entranceIsSamePath = true; else res->Cost -= MONEY(6, 00); @@ -346,7 +370,7 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions:: { entrancePath = true; // Make the price the same as replacing a path - if (entranceElement->GetSurfaceEntryIndex() == _type) + if (IsSameAsEntranceElement(*entranceElement)) entranceIsSamePath = true; else res->Cost -= MONEY(6, 00); @@ -380,9 +404,9 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions:: { if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) { - if (_constructFlags & PathConstructFlag::IsPathObject) + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) { - entranceElement->SetPathEntryIndex(_type); + entranceElement->SetLegacyPathEntryIndex(_type); } else { @@ -397,14 +421,14 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions:: Guard::Assert(pathElement != nullptr); pathElement->SetClearanceZ(zHigh); - if (_constructFlags & PathConstructFlag::IsPathObject) + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) { - pathElement->SetPathEntryIndex(_type); + pathElement->SetLegacyPathEntryIndex(_type); } else { pathElement->SetSurfaceEntryIndex(_type); - pathElement->SetRailingEntryIndex(_railingsType); + pathElement->SetRailingsEntryIndex(_railingsType); } pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED); diff --git a/src/openrct2/actions/FootpathPlaceAction.h b/src/openrct2/actions/FootpathPlaceAction.h index 2e208f24d7..94df946e20 100644 --- a/src/openrct2/actions/FootpathPlaceAction.h +++ b/src/openrct2/actions/FootpathPlaceAction.h @@ -27,7 +27,6 @@ public: FootpathPlaceAction( const CoordsXYZ& loc, uint8_t slope, ObjectEntryIndex type, ObjectEntryIndex railingsType, Direction direction = INVALID_DIRECTION, PathConstructFlags constructFlags = 0); - void AcceptParameters(GameActionParameterVisitor & visitor) override; uint16_t GetActionFlags() const override; @@ -45,4 +44,5 @@ private: void RemoveIntersectingWalls(PathElement * pathElement) const; PathElement* map_get_footpath_element_slope(const CoordsXYZ& footpathPos, int32_t slope) const; bool IsSameAsPathElement(const PathElement* pathElement) const; + bool IsSameAsEntranceElement(const EntranceElement& entranceElement) const; }; diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp b/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp index 55762b8f57..3a9e192aa6 100644 --- a/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp +++ b/src/openrct2/actions/FootpathPlaceFromTrackAction.cpp @@ -126,7 +126,7 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertQuery(GameAc { entrancePath = true; // Make the price the same as replacing a path - if (entranceElement->GetSurfaceEntryIndex() == _type) + if (IsSameAsEntranceElement(*entranceElement)) entranceIsSamePath = true; else res->Cost -= MONEY(6, 00); @@ -193,7 +193,7 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game { entrancePath = true; // Make the price the same as replacing a path - if (entranceElement->GetSurfaceEntryIndex() == _type) + if (IsSameAsEntranceElement(*entranceElement)) entranceIsSamePath = true; else res->Cost -= MONEY(6, 00); @@ -226,9 +226,9 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game { if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST) && !entranceIsSamePath) { - if (_constructFlags & PathConstructFlag::IsPathObject) + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) { - entranceElement->SetPathEntryIndex(_type); + entranceElement->SetLegacyPathEntryIndex(_type); } else { @@ -243,14 +243,14 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game Guard::Assert(pathElement != nullptr); pathElement->SetClearanceZ(zHigh); - if (_constructFlags & PathConstructFlag::IsPathObject) + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) { - pathElement->SetPathEntryIndex(_type); + pathElement->SetLegacyPathEntryIndex(_type); } else { pathElement->SetSurfaceEntryIndex(_type); - pathElement->SetRailingEntryIndex(_railingsType); + pathElement->SetRailingsEntryIndex(_railingsType); } pathElement->SetSlopeDirection(_slope & FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK); pathElement->SetSloped(_slope & FOOTPATH_PROPERTIES_FLAG_IS_SLOPED); @@ -272,3 +272,27 @@ GameActions::Result::Ptr FootpathPlaceFromTrackAction::ElementInsertExecute(Game return res; } + +bool FootpathPlaceFromTrackAction::IsSameAsEntranceElement(const EntranceElement& entranceElement) const +{ + if (entranceElement.HasLegacyPathEntry()) + { + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) + { + return entranceElement.GetLegacyPathEntryIndex() == _type; + } + else + { + return false; + } + } + + if (_constructFlags & PathConstructFlag::IsLegacyPathObject) + { + return false; + } + else + { + return entranceElement.GetSurfaceEntryIndex() == _type; + } +} diff --git a/src/openrct2/actions/FootpathPlaceFromTrackAction.h b/src/openrct2/actions/FootpathPlaceFromTrackAction.h index 273ab728cd..0eb0726dd7 100644 --- a/src/openrct2/actions/FootpathPlaceFromTrackAction.h +++ b/src/openrct2/actions/FootpathPlaceFromTrackAction.h @@ -36,4 +36,5 @@ public: private: GameActions::Result::Ptr ElementInsertQuery(GameActions::Result::Ptr res) const; GameActions::Result::Ptr ElementInsertExecute(GameActions::Result::Ptr res) const; + bool IsSameAsEntranceElement(const EntranceElement& entranceElement) const; }; diff --git a/src/openrct2/actions/GameAction.cpp b/src/openrct2/actions/GameAction.cpp index adc8606a62..0186df8e7e 100644 --- a/src/openrct2/actions/GameAction.cpp +++ b/src/openrct2/actions/GameAction.cpp @@ -492,7 +492,7 @@ namespace GameActions network_add_player_money_spent(playerIndex, result->Cost); } - if (!result->Position.isNull()) + if (!result->Position.IsNull()) { network_set_player_last_action_coord(playerIndex, result->Position); } diff --git a/src/openrct2/actions/GameAction.h b/src/openrct2/actions/GameAction.h index 856470f356..03ee95fe5f 100644 --- a/src/openrct2/actions/GameAction.h +++ b/src/openrct2/actions/GameAction.h @@ -16,6 +16,7 @@ #include "../localisation/StringIds.h" #include "../world/Map.h" +#include #include #include #include @@ -130,6 +131,7 @@ namespace GameActions CoordsXYZ Position = { LOCATION_NULL, LOCATION_NULL, LOCATION_NULL }; money32 Cost = 0; ExpenditureType Expenditure = ExpenditureType::Count; + std::any ResultData; Result() = default; Result(GameActions::Status error, rct_string_id message); @@ -140,6 +142,19 @@ namespace GameActions std::string GetErrorTitle() const; std::string GetErrorMessage() const; + + // It is recommended to use strong types since a type alias such as 'using MyType = uint32_t' + // is still just uint32_t, this guarantees the data is associated with the correct type. + template void SetData(const T&& data) + { + ResultData = std::forward(data); + } + + // This function will throw std::bad_any_cast if the type mismatches. + template T GetData() const + { + return std::any_cast(ResultData); + } }; class ConstructClearResult final : public Result diff --git a/src/openrct2/actions/MazeSetTrackAction.cpp b/src/openrct2/actions/MazeSetTrackAction.cpp index f0dd07396f..19e38f95d0 100644 --- a/src/openrct2/actions/MazeSetTrackAction.cpp +++ b/src/openrct2/actions/MazeSetTrackAction.cpp @@ -293,7 +293,7 @@ GameActions::Result::Ptr MazeSetTrackAction::Execute() const if ((tileElement->AsTrack()->GetMazeEntry() & 0x8888) == 0x8888) { tile_element_remove(tileElement); - sub_6CB945(ride); + ride->ValidateStations(); ride->maze_tiles--; } diff --git a/src/openrct2/actions/ParkMarketingAction.cpp b/src/openrct2/actions/ParkMarketingAction.cpp index aa9c2abda4..665f00fbc5 100644 --- a/src/openrct2/actions/ParkMarketingAction.cpp +++ b/src/openrct2/actions/ParkMarketingAction.cpp @@ -70,7 +70,7 @@ GameActions::Result::Ptr ParkMarketingAction::Execute() const campaign.Flags = MarketingCampaignFlags::FIRST_WEEK; if (campaign.Type == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign.Type == ADVERTISING_CAMPAIGN_RIDE) { - campaign.RideId = _item; + campaign.RideId = static_cast(_item); } else if (campaign.Type == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) { diff --git a/src/openrct2/actions/PeepPickupAction.cpp b/src/openrct2/actions/PeepPickupAction.cpp index bee844a0e0..db89689ddd 100644 --- a/src/openrct2/actions/PeepPickupAction.cpp +++ b/src/openrct2/actions/PeepPickupAction.cpp @@ -43,7 +43,7 @@ GameActions::Result::Ptr PeepPickupAction::Query() const return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); } - if (!_loc.isNull() && !LocationValid(_loc)) + if (!_loc.IsNull() && !LocationValid(_loc)) { return MakeResult(GameActions::Status::InvalidParameters, STR_ERR_CANT_PLACE_PERSON_HERE); } diff --git a/src/openrct2/actions/PlaceParkEntranceAction.cpp b/src/openrct2/actions/PlaceParkEntranceAction.cpp index 109fa8940d..5ef8207e34 100644 --- a/src/openrct2/actions/PlaceParkEntranceAction.cpp +++ b/src/openrct2/actions/PlaceParkEntranceAction.cpp @@ -152,7 +152,7 @@ GameActions::Result::Ptr PlaceParkEntranceAction::Execute() const } else { - entranceElement->SetPathEntryIndex(gFootpathSelection.LegacyPath); + entranceElement->SetLegacyPathEntryIndex(gFootpathSelection.LegacyPath); } if (!entranceElement->IsGhost()) diff --git a/src/openrct2/actions/RideCreateAction.cpp b/src/openrct2/actions/RideCreateAction.cpp index 4dcb4344b5..d6434c1b10 100644 --- a/src/openrct2/actions/RideCreateAction.cpp +++ b/src/openrct2/actions/RideCreateAction.cpp @@ -140,12 +140,12 @@ GameActions::Result::Ptr RideCreateAction::Execute() const ride->type = _rideType; ride->subtype = rideEntryIndex; ride->SetColourPreset(_colour1); - ride->overall_view.setNull(); + ride->overall_view.SetNull(); ride->SetNameToDefault(); for (int32_t i = 0; i < MAX_STATIONS; i++) { - ride->stations[i].Start.setNull(); + ride->stations[i].Start.SetNull(); ride_clear_entrance_location(ride, i); ride_clear_exit_location(ride, i); ride->stations[i].TrainAtStation = RideStation::NO_TRAIN; diff --git a/src/openrct2/actions/RideDemolishAction.cpp b/src/openrct2/actions/RideDemolishAction.cpp index ecc24ea6ce..2d063ce8f6 100644 --- a/src/openrct2/actions/RideDemolishAction.cpp +++ b/src/openrct2/actions/RideDemolishAction.cpp @@ -129,16 +129,18 @@ GameActions::Result::Ptr RideDemolishAction::DemolishRide(Ride* ride) const ride_remove_peeps(ride); ride->StopGuestsQueuing(); - sub_6CB945(ride); + ride->ValidateStations(); ride_clear_leftover_entrances(ride); - News::DisableNewsItems(News::ItemType::Ride, _rideIndex); - UnlinkAllBannersForRide(_rideIndex); + const auto rideId = ride->id; + News::DisableNewsItems(News::ItemType::Ride, EnumValue(rideId)); - RideUse::GetHistory().RemoveValue(_rideIndex); + UnlinkAllBannersForRide(ride->id); + + RideUse::GetHistory().RemoveValue(ride->id); for (auto peep : EntityList()) { - peep->RemoveRideFromMemory(_rideIndex); + peep->RemoveRideFromMemory(ride->id); } MarketingCancelCampaignsForRide(_rideIndex); @@ -147,7 +149,7 @@ GameActions::Result::Ptr RideDemolishAction::DemolishRide(Ride* ride) const res->Expenditure = ExpenditureType::RideConstruction; res->Cost = refundPrice; - if (!ride->overall_view.isNull()) + if (!ride->overall_view.IsNull()) { auto xy = ride->overall_view.ToTileCentre(); res->Position = { xy, tile_element_height(xy) }; @@ -157,9 +159,9 @@ GameActions::Result::Ptr RideDemolishAction::DemolishRide(Ride* ride) const gParkValue = GetContext()->GetGameState()->GetPark().CalculateParkValue(); // Close windows related to the demolished ride - window_close_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); - window_close_by_number(WC_RIDE, _rideIndex); - window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); + window_close_by_number(WC_RIDE_CONSTRUCTION, EnumValue(rideId)); + window_close_by_number(WC_RIDE, EnumValue(rideId)); + window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, EnumValue(rideId)); window_close_by_class(WC_NEW_CAMPAIGN); // Refresh windows that display the ride name @@ -266,13 +268,13 @@ GameActions::Result::Ptr RideDemolishAction::RefurbishRide(Ride* ride) const ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE | RIDE_INVALIDATE_RIDE_CUSTOMER; - if (!ride->overall_view.isNull()) + if (!ride->overall_view.IsNull()) { auto location = ride->overall_view.ToTileCentre(); res->Position = { location, tile_element_height(location) }; } - window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, _rideIndex); + window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, EnumValue(_rideIndex)); return res; } diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.cpp b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp index df2b87bf2c..df49331e73 100644 --- a/src/openrct2/actions/RideEntranceExitPlaceAction.cpp +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp @@ -54,7 +54,7 @@ GameActions::Result::Ptr RideEntranceExitPlaceAction::Query() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); + log_warning("Invalid game command for ride %d", EnumValue(_rideIndex)); return MakeResult(GameActions::Status::InvalidParameters, errorTitle); } @@ -76,7 +76,7 @@ GameActions::Result::Ptr RideEntranceExitPlaceAction::Query() const const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) : ride_get_entrance_location(ride, _stationNum); - if (!location.isNull()) + if (!location.IsNull()) { auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); rideEntranceExitRemove.SetFlags(GetFlags()); @@ -132,7 +132,7 @@ GameActions::Result::Ptr RideEntranceExitPlaceAction::Execute() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid game command for ride %d", static_cast(_rideIndex)); + log_warning("Invalid game command for ride %d", EnumValue(_rideIndex)); return MakeResult(GameActions::Status::InvalidParameters, errorTitle); } @@ -143,7 +143,7 @@ GameActions::Result::Ptr RideEntranceExitPlaceAction::Execute() const } const auto location = _isExit ? ride_get_exit_location(ride, _stationNum) : ride_get_entrance_location(ride, _stationNum); - if (!location.isNull()) + if (!location.IsNull()) { auto rideEntranceExitRemove = RideEntranceExitRemoveAction(location.ToCoordsXY(), _rideIndex, _stationNum, _isExit); rideEntranceExitRemove.SetFlags(GetFlags()); diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.cpp b/src/openrct2/actions/RideEntranceExitRemoveAction.cpp index f4fac8cae3..6144d29eda 100644 --- a/src/openrct2/actions/RideEntranceExitRemoveAction.cpp +++ b/src/openrct2/actions/RideEntranceExitRemoveAction.cpp @@ -74,7 +74,7 @@ GameActions::Result::Ptr RideEntranceExitRemoveAction::Query() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); + log_warning("Invalid ride id %d for entrance/exit removal", EnumValue(_rideIndex)); return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); } @@ -99,8 +99,8 @@ GameActions::Result::Ptr RideEntranceExitRemoveAction::Query() const if (entranceElement == nullptr) { log_warning( - "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, - static_cast(_rideIndex), _stationNum); + "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, EnumValue(_rideIndex), + _stationNum); return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); } @@ -112,7 +112,7 @@ GameActions::Result::Ptr RideEntranceExitRemoveAction::Execute() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid ride id %d for entrance/exit removal", static_cast(_rideIndex)); + log_warning("Invalid ride id %d for entrance/exit removal", EnumValue(_rideIndex)); return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); } @@ -130,8 +130,8 @@ GameActions::Result::Ptr RideEntranceExitRemoveAction::Execute() const if (entranceElement == nullptr) { log_warning( - "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, - static_cast(_rideIndex), _stationNum); + "Track Element not found. x = %d, y = %d, ride = %d, station = %d", _loc.x, _loc.y, EnumValue(_rideIndex), + _stationNum); return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); } diff --git a/src/openrct2/actions/RideSetAppearanceAction.cpp b/src/openrct2/actions/RideSetAppearanceAction.cpp index 551d1edd5e..d5355db520 100644 --- a/src/openrct2/actions/RideSetAppearanceAction.cpp +++ b/src/openrct2/actions/RideSetAppearanceAction.cpp @@ -139,10 +139,10 @@ GameActions::Result::Ptr RideSetAppearanceAction::Execute() const gfx_invalidate_screen(); break; } - window_invalidate_by_number(WC_RIDE, _rideIndex); + window_invalidate_by_number(WC_RIDE, EnumValue(_rideIndex)); auto res = std::make_unique(); - if (!ride->overall_view.isNull()) + if (!ride->overall_view.IsNull()) { auto location = ride->overall_view.ToTileCentre(); res->Position = { location, tile_element_height(location) }; diff --git a/src/openrct2/actions/RideSetColourSchemeAction.cpp b/src/openrct2/actions/RideSetColourSchemeAction.cpp index 8e245cc3df..064d30bb9c 100644 --- a/src/openrct2/actions/RideSetColourSchemeAction.cpp +++ b/src/openrct2/actions/RideSetColourSchemeAction.cpp @@ -61,7 +61,7 @@ GameActions::Result::Ptr RideSetColourSchemeAction::Execute() const res->Expenditure = ExpenditureType::RideConstruction; res->ErrorTitle = STR_CANT_SET_COLOUR_SCHEME; - sub_6C683D(_loc, _trackType, _newColourScheme, nullptr, TRACK_ELEMENT_SET_COLOUR_SCHEME); + GetTrackElementOriginAndApplyChanges(_loc, _trackType, _newColourScheme, nullptr, TRACK_ELEMENT_SET_COLOUR_SCHEME); return res; } diff --git a/src/openrct2/actions/RideSetPriceAction.cpp b/src/openrct2/actions/RideSetPriceAction.cpp index 374bd4d9a0..81b29ce432 100644 --- a/src/openrct2/actions/RideSetPriceAction.cpp +++ b/src/openrct2/actions/RideSetPriceAction.cpp @@ -87,7 +87,7 @@ GameActions::Result::Ptr RideSetPriceAction::Execute() const return MakeResult(GameActions::Status::InvalidParameters, STR_NONE); } - if (!ride->overall_view.isNull()) + if (!ride->overall_view.IsNull()) { auto location = ride->overall_view.ToTileCentre(); res->Position = { location, tile_element_height(location) }; @@ -180,7 +180,7 @@ void RideSetPriceAction::RideSetCommonPrice(ShopItem shopItem) const } if (invalidate) { - window_invalidate_by_number(WC_RIDE, ride.id); + window_invalidate_by_number(WC_RIDE, EnumValue(ride.id)); } } } diff --git a/src/openrct2/actions/RideSetSettingAction.cpp b/src/openrct2/actions/RideSetSettingAction.cpp index fb7b8d506b..1c5a5ac262 100644 --- a/src/openrct2/actions/RideSetSettingAction.cpp +++ b/src/openrct2/actions/RideSetSettingAction.cpp @@ -45,7 +45,7 @@ GameActions::Result::Ptr RideSetSettingAction::Query() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); + log_warning("Invalid ride: #%d.", EnumValue(_rideIndex)); return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); } @@ -153,7 +153,7 @@ GameActions::Result::Ptr RideSetSettingAction::Execute() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid ride: #%d.", static_cast(_rideIndex)); + log_warning("Invalid ride: #%d.", EnumValue(_rideIndex)); return MakeResult(GameActions::Status::InvalidParameters, STR_CANT_CHANGE_OPERATING_MODE); } @@ -228,12 +228,12 @@ GameActions::Result::Ptr RideSetSettingAction::Execute() const } auto res = std::make_unique(); - if (!ride->overall_view.isNull()) + if (!ride->overall_view.IsNull()) { auto location = ride->overall_view.ToTileCentre(); res->Position = { location, tile_element_height(location) }; } - window_invalidate_by_number(WC_RIDE, _rideIndex); + window_invalidate_by_number(WC_RIDE, EnumValue(_rideIndex)); return res; } diff --git a/src/openrct2/actions/RideSetStatusAction.cpp b/src/openrct2/actions/RideSetStatusAction.cpp index 2750d639f3..9743b311a0 100644 --- a/src/openrct2/actions/RideSetStatusAction.cpp +++ b/src/openrct2/actions/RideSetStatusAction.cpp @@ -59,7 +59,7 @@ GameActions::Result::Ptr RideSetStatusAction::Query() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid game command for ride %u", uint32_t(_rideIndex)); + log_warning("Invalid game command for ride %u", EnumValue(_rideIndex)); res->Error = GameActions::Status::InvalidParameters; res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; res->ErrorMessage = STR_NONE; @@ -68,7 +68,7 @@ GameActions::Result::Ptr RideSetStatusAction::Query() const if (_status >= RideStatus::Count) { - log_warning("Invalid ride status %u for ride %u", uint32_t(_status), uint32_t(_rideIndex)); + log_warning("Invalid ride status %u for ride %u", EnumValue(_status), EnumValue(_rideIndex)); res->Error = GameActions::Status::InvalidParameters; res->ErrorTitle = STR_RIDE_DESCRIPTION_UNKNOWN; res->ErrorMessage = STR_NONE; @@ -131,7 +131,7 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const Formatter ft(res->ErrorMessageArgs.data()); ft.Increment(6); ride->FormatNameTo(ft); - if (!ride->overall_view.isNull()) + if (!ride->overall_view.IsNull()) { auto location = ride->overall_view.ToTileCentre(); res->Position = { location, tile_element_height(location) }; @@ -154,7 +154,7 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; ride->race_winner = SPRITE_INDEX_NULL; ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); + window_invalidate_by_number(WC_RIDE, EnumValue(_rideIndex)); break; case RideStatus::Simulating: { @@ -176,7 +176,7 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const ride->last_issue_time = 0; ride->GetMeasurement(); ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); + window_invalidate_by_number(WC_RIDE, EnumValue(_rideIndex)); break; } case RideStatus::Testing: @@ -195,7 +195,7 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const // Fix #3183: Make sure we close the construction window so the ride finishes any editing code before opening // otherwise vehicles get added to the ride incorrectly (such as to a ghost station) - rct_window* constructionWindow = window_find_by_number(WC_RIDE_CONSTRUCTION, _rideIndex); + rct_window* constructionWindow = window_find_by_number(WC_RIDE_CONSTRUCTION, EnumValue(_rideIndex)); if (constructionWindow != nullptr) { window_close(constructionWindow); @@ -223,7 +223,7 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const ride->last_issue_time = 0; ride->GetMeasurement(); ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; - window_invalidate_by_number(WC_RIDE, _rideIndex); + window_invalidate_by_number(WC_RIDE, EnumValue(_rideIndex)); break; } default: diff --git a/src/openrct2/actions/RideSetVehicleAction.cpp b/src/openrct2/actions/RideSetVehicleAction.cpp index 167d2cb0b2..b03b792348 100644 --- a/src/openrct2/actions/RideSetVehicleAction.cpp +++ b/src/openrct2/actions/RideSetVehicleAction.cpp @@ -192,14 +192,14 @@ GameActions::Result::Ptr RideSetVehicleAction::Execute() const ride->UpdateMaxVehicles(); auto res = std::make_unique(); - if (!ride->overall_view.isNull()) + if (!ride->overall_view.IsNull()) { auto location = ride->overall_view.ToTileCentre(); res->Position = { location, tile_element_height(res->Position) }; } auto intent = Intent(INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE); - intent.putExtra(INTENT_EXTRA_RIDE_ID, _rideIndex); + intent.putExtra(INTENT_EXTRA_RIDE_ID, EnumValue(_rideIndex)); context_broadcast_intent(&intent); gfx_invalidate_screen(); diff --git a/src/openrct2/actions/TrackPlaceAction.cpp b/src/openrct2/actions/TrackPlaceAction.cpp index 2f36dfc5c8..f0fc1898cb 100644 --- a/src/openrct2/actions/TrackPlaceAction.cpp +++ b/src/openrct2/actions/TrackPlaceAction.cpp @@ -9,6 +9,7 @@ #include "TrackPlaceAction.h" +#include "../core/Numerics.hpp" #include "../management/Finance.h" #include "../ride/RideData.h" #include "../ride/Track.h" @@ -85,13 +86,13 @@ GameActions::Result::Ptr TrackPlaceAction::Query() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); + log_warning("Invalid ride for track placement, rideIndex = %d", EnumValue(_rideIndex)); return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); } rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); if (rideEntry == nullptr) { - log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); + log_warning("Invalid ride subtype for track placement, rideIndex = %d", EnumValue(_rideIndex)); return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); } @@ -379,14 +380,14 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const auto ride = get_ride(_rideIndex); if (ride == nullptr) { - log_warning("Invalid ride for track placement, rideIndex = %d", static_cast(_rideIndex)); + log_warning("Invalid ride for track placement, rideIndex = %d", EnumValue(_rideIndex)); return std::make_unique(GameActions::Status::InvalidParameters); } rct_ride_entry* rideEntry = get_ride_entry(ride->subtype); if (rideEntry == nullptr) { - log_warning("Invalid ride subtype for track placement, rideIndex = %d", static_cast(_rideIndex)); + log_warning("Invalid ride subtype for track placement, rideIndex = %d", EnumValue(_rideIndex)); return std::make_unique(GameActions::Status::InvalidParameters); } @@ -453,7 +454,7 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const // Remove walls in the directions this track intersects uint8_t intersectingDirections = wallEdges[blockIndex]; intersectingDirections ^= 0x0F; - intersectingDirections = rol4(intersectingDirections, _origin.direction); + intersectingDirections = Numerics::rol4(intersectingDirections, _origin.direction); for (int32_t i = 0; i < NumOrthogonalDirections; i++) { if (intersectingDirections & (1 << i)) @@ -534,7 +535,7 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const } int32_t entranceDirections = 0; - if (!ride->overall_view.isNull()) + if (!ride->overall_view.IsNull()) { if (!(GetFlags() & GAME_COMMAND_FLAG_NO_SPEND)) { @@ -542,7 +543,7 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const } } - if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN || ride->overall_view.isNull()) + if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN || ride->overall_view.IsNull()) { ride->overall_view = mapLoc; } @@ -550,7 +551,7 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const auto* trackElement = TileElementInsert(mapLoc, quarterTile.GetBaseQuarterOccupied()); if (trackElement == nullptr) { - log_warning("Cannot create track element for ride = %d", static_cast(_rideIndex)); + log_warning("Cannot create track element for ride = %d", EnumValue(_rideIndex)); return std::make_unique(GameActions::Status::NoFreeElements); } @@ -629,7 +630,7 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const { track_add_station_element({ mapLoc, _origin.direction }, _rideIndex, GAME_COMMAND_FLAG_APPLY, _fromTrackDesign); } - sub_6CB945(ride); + ride->ValidateStations(); ride->UpdateMaxVehicles(); } diff --git a/src/openrct2/actions/TrackRemoveAction.cpp b/src/openrct2/actions/TrackRemoveAction.cpp index 8e1bf2b942..65c1a1b1b1 100644 --- a/src/openrct2/actions/TrackRemoveAction.cpp +++ b/src/openrct2/actions/TrackRemoveAction.cpp @@ -426,7 +426,7 @@ GameActions::Result::Ptr TrackRemoveAction::Execute() const footpath_remove_edges_at(mapLoc, tileElement); } tile_element_remove(tileElement); - sub_6CB945(ride); + ride->ValidateStations(); if (!(GetFlags() & GAME_COMMAND_FLAG_GHOST)) { ride->UpdateMaxVehicles(); diff --git a/src/openrct2/actions/WallPlaceAction.cpp b/src/openrct2/actions/WallPlaceAction.cpp index 1d2e44916b..17bd70d98f 100644 --- a/src/openrct2/actions/WallPlaceAction.cpp +++ b/src/openrct2/actions/WallPlaceAction.cpp @@ -443,7 +443,7 @@ bool WallPlaceAction::WallCheckObstructionWithTrack( return false; } - if (TrackDefinitions[trackType].bank_start == 0) + if (ted.Definition.bank_start == 0) { if (!(ted.Coordinates.rotation_begin & 4)) { @@ -468,7 +468,7 @@ bool WallPlaceAction::WallCheckObstructionWithTrack( return false; } - if (TrackDefinitions[trackType].bank_end != 0) + if (ted.Definition.bank_end != 0) { return false; } diff --git a/src/openrct2/common.h b/src/openrct2/common.h index cc0e1d517a..5a5cae5ade 100644 --- a/src/openrct2/common.h +++ b/src/openrct2/common.h @@ -19,15 +19,12 @@ #endif #include "Diagnostic.h" -#include "core/Numerics.hpp" #include #include #include #include -using namespace Numerics; - using utf8 = char; using utf8string = utf8*; using const_utf8string = const utf8*; @@ -41,15 +38,6 @@ using const_utf8string = const utf8*; using codepoint_t = uint32_t; using colour_t = uint8_t; -const constexpr auto rol8 = rol; -const constexpr auto ror8 = ror; -const constexpr auto rol16 = rol; -const constexpr auto ror16 = ror; -const constexpr auto rol32 = rol; -const constexpr auto ror32 = ror; -const constexpr auto rol64 = rol; -const constexpr auto ror64 = ror; - namespace { [[maybe_unused]] constexpr bool is_power_of_2(int v) diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index 07ae19b21f..ae4d4ecaa2 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -38,19 +38,23 @@ template struct DataSerializerTraits_t template struct DataSerializerTraits_enum { + using TUnderlying = std::underlying_type_t; + static void encode(OpenRCT2::IStream* stream, const T& val) { - stream->Write(&val); + TUnderlying temp = ByteSwapBE(static_cast(val)); + stream->Write(&temp); } static void decode(OpenRCT2::IStream* stream, T& val) { - stream->Read(&val); + TUnderlying temp; + stream->Read(&temp); + val = static_cast(ByteSwapBE(temp)); } static void log(OpenRCT2::IStream* stream, const T& val) { - using underlying = std::underlying_type_t; std::stringstream ss; - ss << std::hex << std::setw(sizeof(underlying) * 2) << std::setfill('0') << static_cast(val); + ss << std::hex << std::setw(sizeof(TUnderlying) * 2) << std::setfill('0') << static_cast(val); std::string str = ss.str(); stream->Write(str.c_str(), str.size()); @@ -210,39 +214,6 @@ template<> struct DataSerializerTraits_t } }; -template<> struct DataSerializerTraits_t -{ - static void encode(OpenRCT2::IStream* stream, const NetworkRideId_t& val) - { - uint32_t temp = static_cast(val.id); - temp = ByteSwapBE(temp); - stream->Write(&temp); - } - static void decode(OpenRCT2::IStream* stream, NetworkRideId_t& val) - { - uint32_t temp; - stream->Read(&temp); - val.id = static_cast(ByteSwapBE(temp)); - } - static void log(OpenRCT2::IStream* stream, const NetworkRideId_t& val) - { - char rideId[28] = {}; - snprintf(rideId, sizeof(rideId), "%u", val.id); - - stream->Write(rideId, strlen(rideId)); - - auto ride = get_ride(val.id); - if (ride != nullptr) - { - auto rideName = ride->GetName(); - - stream->Write(" \"", 2); - stream->Write(rideName.c_str(), rideName.size()); - stream->Write("\"", 1); - } - } -}; - template struct DataSerializerTraits_t> { static void encode(OpenRCT2::IStream* stream, const DataSerialiserTag& tag) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index 0e5d570a47..0d01da1e42 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -16,6 +16,7 @@ #include "FileScanner.h" #include "FileStream.h" #include "JobPool.h" +#include "Numerics.hpp" #include "Path.hpp" #include @@ -156,7 +157,7 @@ private: stats.TotalFileSize += fileInfo->Size; stats.FileDateModifiedChecksum ^= static_cast(fileInfo->LastModified >> 32) ^ static_cast(fileInfo->LastModified & 0xFFFFFFFF); - stats.FileDateModifiedChecksum = ror32(stats.FileDateModifiedChecksum, 5); + stats.FileDateModifiedChecksum = Numerics::ror32(stats.FileDateModifiedChecksum, 5); stats.PathChecksum += GetPathChecksum(path); files.push_back(std::move(path)); diff --git a/src/openrct2/core/FileScanner.cpp b/src/openrct2/core/FileScanner.cpp index 9c79c500f7..07662b1134 100644 --- a/src/openrct2/core/FileScanner.cpp +++ b/src/openrct2/core/FileScanner.cpp @@ -25,6 +25,7 @@ #include "FileScanner.h" #include "Memory.hpp" +#include "Numerics.hpp" #include "Path.hpp" #include "String.hpp" @@ -363,7 +364,7 @@ void Path::QueryDirectory(QueryDirectoryResult* result, const std::string& patte result->TotalFileSize += fileInfo->Size; result->FileDateModifiedChecksum ^= static_cast(fileInfo->LastModified >> 32) ^ static_cast(fileInfo->LastModified & 0xFFFFFFFF); - result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5); + result->FileDateModifiedChecksum = Numerics::ror32(result->FileDateModifiedChecksum, 5); result->PathChecksum += GetPathChecksum(path); } } diff --git a/src/openrct2/core/Http.cURL.cpp b/src/openrct2/core/Http.cURL.cpp index d18a9c1750..41891a50a4 100644 --- a/src/openrct2/core/Http.cURL.cpp +++ b/src/openrct2/core/Http.cURL.cpp @@ -18,7 +18,7 @@ # include # include -# ifdef _WIN32 +# if defined(_WIN32) && !defined(WIN32_LEAN_AND_MEAN) // cURL includes windows.h, but we don't need all of it. # define WIN32_LEAN_AND_MEAN # endif diff --git a/src/openrct2/core/Nullable.hpp b/src/openrct2/core/Nullable.hpp deleted file mode 100644 index 96774e4c7d..0000000000 --- a/src/openrct2/core/Nullable.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../common.h" - -#include - -template struct Nullable -{ -public: - Nullable() - { - _value = T(); - _hasValue = false; - } - - Nullable(std::nullptr_t) - { - _value = T(); - _hasValue = false; - } - - Nullable(const T& value) - { - _value = value; - _hasValue = true; - } - - bool HasValue() const - { - return _hasValue; - } - - T GetValue() const - { - return _value; - } - - T GetValueOrDefault(T defaultValue) const - { - return _hasValue ? _value : defaultValue; - } - -private: - T _value; - bool _hasValue; -}; diff --git a/src/openrct2/core/Numerics.hpp b/src/openrct2/core/Numerics.hpp index 13c1b6a772..38855da2c4 100644 --- a/src/openrct2/core/Numerics.hpp +++ b/src/openrct2/core/Numerics.hpp @@ -68,4 +68,13 @@ namespace Numerics return (x >> shift | x << (4 - shift)) & 0x0F; } + const constexpr auto rol8 = rol; + const constexpr auto ror8 = ror; + const constexpr auto rol16 = rol; + const constexpr auto ror16 = ror; + const constexpr auto rol32 = rol; + const constexpr auto ror32 = ror; + const constexpr auto rol64 = rol; + const constexpr auto ror64 = ror; + } // namespace Numerics diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index bb773e5df9..1df821814f 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -14,7 +14,10 @@ #endif // __MINGW32__ #include +#include #include +#include +#include #include #include #ifndef _WIN32 @@ -818,11 +821,36 @@ namespace String { return trunc.substr(0, i); } - i += *length; + i += length.value(); } return trunc; } + + std::string URLEncode(std::string_view value) + { + std::ostringstream escaped; + escaped.fill('0'); + escaped << std::hex; + + for (auto c : value) + { + // Keep alphanumeric and other accepted characters intact + if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') + { + escaped << c; + } + else + { + // Any other characters are percent-escaped + escaped << std::uppercase; + escaped << '%' << std::setw(2) << int32_t(static_cast(c)); + escaped << std::nouppercase; + } + } + + return escaped.str(); + } } // namespace String char32_t CodepointView::iterator::GetNextCodepoint(const char* ch, const char** next) diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index 7525ca5c65..37efd683a1 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -170,7 +170,7 @@ namespace String { return { 4 }; } - return {}; + return std::nullopt; } /** @@ -179,6 +179,8 @@ namespace String */ std::string_view UTF8Truncate(std::string_view v, size_t size); + // Escapes special characters in a string to the percentage equivalent that can be used in URLs. + std::string URLEncode(std::string_view value); } // namespace String class CodepointView diff --git a/src/openrct2/core/Zip.cpp b/src/openrct2/core/Zip.cpp index 0ca6e6e533..10475bab1a 100644 --- a/src/openrct2/core/Zip.cpp +++ b/src/openrct2/core/Zip.cpp @@ -131,12 +131,12 @@ public: { std::vector result; auto index = GetIndexFromPath(path); - if (index) + if (index.has_value()) { - auto dataSize = GetFileSize(*index); + auto dataSize = GetFileSize(index.value()); if (dataSize > 0 && dataSize < SIZE_MAX) { - auto zipFile = zip_fopen_index(_zip, *index, 0); + auto zipFile = zip_fopen_index(_zip, index.value(), 0); if (zipFile != nullptr) { result.resize(static_cast(dataSize)); @@ -155,9 +155,9 @@ public: std::unique_ptr GetFileStream(std::string_view path) const override { auto index = GetIndexFromPath(path); - if (index) + if (index.has_value()) { - return std::make_unique(_zip, *index); + return std::make_unique(_zip, index.value()); } return {}; } @@ -171,9 +171,9 @@ public: auto source = zip_source_buffer(_zip, writeBuffer.data(), writeBuffer.size(), 0); auto index = GetIndexFromPath(path); - if (index) + if (index.has_value()) { - zip_replace(_zip, *index, source); + zip_replace(_zip, index.value(), source); } else { @@ -184,9 +184,9 @@ public: void DeleteFile(std::string_view path) override { auto index = GetIndexFromPath(path); - if (index) + if (index.has_value()) { - zip_delete(_zip, *index); + zip_delete(_zip, index.value()); } else { diff --git a/src/openrct2/core/ZipStream.hpp b/src/openrct2/core/ZipStream.hpp new file mode 100644 index 0000000000..0a2ede8bad --- /dev/null +++ b/src/openrct2/core/ZipStream.hpp @@ -0,0 +1,86 @@ +/***************************************************************************** + * Copyright (c) 2014-2021 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ +#pragma once + +#include "IStream.hpp" +#include "Zip.h" + +#include + +namespace OpenRCT2 +{ + /** + * Couples a zip archive and a zip item stream to ensure the lifetime of the zip archive is maintained + * for the lifetime of the stream. + */ + class ZipStreamWrapper final : public IStream + { + private: + std::unique_ptr _zipArchive; + std::unique_ptr _base; + + public: + ZipStreamWrapper(std::unique_ptr zipArchive, std::unique_ptr base) + : _zipArchive(std::move(zipArchive)) + , _base(std::move(base)) + { + } + + bool CanRead() const override + { + return _base->CanRead(); + } + + bool CanWrite() const override + { + return _base->CanWrite(); + } + + uint64_t GetLength() const override + { + return _base->GetLength(); + } + + uint64_t GetPosition() const override + { + return _base->GetPosition(); + } + + void SetPosition(uint64_t position) override + { + _base->SetPosition(position); + } + + void Seek(int64_t offset, int32_t origin) override + { + _base->Seek(offset, origin); + } + + void Read(void* buffer, uint64_t length) override + { + _base->Read(buffer, length); + } + + void Write(const void* buffer, uint64_t length) override + { + _base->Write(buffer, length); + } + + uint64_t TryRead(void* buffer, uint64_t length) override + { + return _base->TryRead(buffer, length); + } + + const void* GetData() const override + { + return _base->GetData(); + } + }; + +} // namespace OpenRCT2 diff --git a/src/openrct2/drawing/Drawing.Sprite.cpp b/src/openrct2/drawing/Drawing.Sprite.cpp index 786ec46fba..1bb8bfb66d 100644 --- a/src/openrct2/drawing/Drawing.Sprite.cpp +++ b/src/openrct2/drawing/Drawing.Sprite.cpp @@ -378,25 +378,27 @@ static std::optional FASTCALL gfx_draw_sprite_get_palette(ImageId im { paletteMap = PaletteMap(gOtherPalette); auto tertiaryPaletteMap = GetPaletteMapForColour(imageId.GetTertiary()); - if (tertiaryPaletteMap) + if (tertiaryPaletteMap.has_value()) { paletteMap.Copy( - PALETTE_OFFSET_REMAP_TERTIARY, *tertiaryPaletteMap, PALETTE_OFFSET_REMAP_PRIMARY, PALETTE_LENGTH_REMAP); + PALETTE_OFFSET_REMAP_TERTIARY, tertiaryPaletteMap.value(), PALETTE_OFFSET_REMAP_PRIMARY, + PALETTE_LENGTH_REMAP); } } auto primaryPaletteMap = GetPaletteMapForColour(imageId.GetPrimary()); - if (primaryPaletteMap) + if (primaryPaletteMap.has_value()) { paletteMap.Copy( - PALETTE_OFFSET_REMAP_PRIMARY, *primaryPaletteMap, PALETTE_OFFSET_REMAP_PRIMARY, PALETTE_LENGTH_REMAP); + PALETTE_OFFSET_REMAP_PRIMARY, primaryPaletteMap.value(), PALETTE_OFFSET_REMAP_PRIMARY, PALETTE_LENGTH_REMAP); } auto secondaryPaletteMap = GetPaletteMapForColour(imageId.GetSecondary()); - if (secondaryPaletteMap) + if (secondaryPaletteMap.has_value()) { paletteMap.Copy( - PALETTE_OFFSET_REMAP_SECONDARY, *secondaryPaletteMap, PALETTE_OFFSET_REMAP_PRIMARY, PALETTE_LENGTH_REMAP); + PALETTE_OFFSET_REMAP_SECONDARY, secondaryPaletteMap.value(), PALETTE_OFFSET_REMAP_PRIMARY, + PALETTE_LENGTH_REMAP); } return paletteMap; diff --git a/src/openrct2/drawing/Drawing.String.cpp b/src/openrct2/drawing/Drawing.String.cpp index 934c26e62f..78e8915014 100644 --- a/src/openrct2/drawing/Drawing.String.cpp +++ b/src/openrct2/drawing/Drawing.String.cpp @@ -57,7 +57,7 @@ int32_t gfx_get_string_width_new_lined(std::string_view text, FontSpriteBase fon if (token.kind == FormatToken::Newline || token.kind == FormatToken::NewlineSmall) { auto width = gfx_get_string_width(buffer, fontSpriteBase); - if (!maxWidth || maxWidth > width) + if (!maxWidth.has_value() || maxWidth.value() > width) { maxWidth = width; } @@ -68,11 +68,11 @@ int32_t gfx_get_string_width_new_lined(std::string_view text, FontSpriteBase fon buffer.append(token.text); } } - if (!maxWidth) + if (!maxWidth.has_value()) { maxWidth = gfx_get_string_width(buffer, fontSpriteBase); } - return *maxWidth; + return maxWidth.value(); } /** @@ -829,11 +829,11 @@ static void ttf_process_string_literal(rct_drawpixelinfo* dpi, std::string_view auto codepoint = *it; if (ShouldUseSpriteForCodepoint(codepoint)) { - if (ttfRunIndex) + if (ttfRunIndex.has_value()) { // Draw the TTF run - auto len = it.GetIndex() - *ttfRunIndex; - ttf_draw_string_raw_ttf(dpi, text.substr(*ttfRunIndex, len), info); + auto len = it.GetIndex() - ttfRunIndex.value(); + ttf_draw_string_raw_ttf(dpi, text.substr(ttfRunIndex.value(), len), info); ttfRunIndex = std::nullopt; } @@ -842,18 +842,18 @@ static void ttf_process_string_literal(rct_drawpixelinfo* dpi, std::string_view } else { - if (!ttfRunIndex) + if (!ttfRunIndex.has_value()) { ttfRunIndex = it.GetIndex(); } } } - if (ttfRunIndex) + if (ttfRunIndex.has_value()) { // Final TTF run auto len = text.size() - *ttfRunIndex; - ttf_draw_string_raw_ttf(dpi, text.substr(*ttfRunIndex, len), info); + ttf_draw_string_raw_ttf(dpi, text.substr(ttfRunIndex.value(), len), info); } } #endif // NO_TTF diff --git a/src/openrct2/drawing/Drawing.cpp b/src/openrct2/drawing/Drawing.cpp index 0894323ff4..96b51b7f84 100644 --- a/src/openrct2/drawing/Drawing.cpp +++ b/src/openrct2/drawing/Drawing.cpp @@ -750,9 +750,9 @@ std::optional GetPaletteG1Index(colour_t paletteId) std::optional GetPaletteMapForColour(colour_t paletteId) { auto g1Index = GetPaletteG1Index(paletteId); - if (g1Index) + if (g1Index.has_value()) { - auto g1 = gfx_get_g1_element(*g1Index); + auto g1 = gfx_get_g1_element(g1Index.value()); if (g1 != nullptr) { return PaletteMap(g1->offset, g1->height, g1->width); diff --git a/src/openrct2/drawing/ImageImporter.cpp b/src/openrct2/drawing/ImageImporter.cpp index d75a170108..007c431e01 100644 --- a/src/openrct2/drawing/ImageImporter.cpp +++ b/src/openrct2/drawing/ImageImporter.cpp @@ -235,24 +235,22 @@ int32_t ImageImporter::CalculatePaletteIndex( { auto& palette = StandardPalette; auto paletteIndex = GetPaletteIndex(palette, rgbaSrc); - if (mode == IMPORT_MODE::CLOSEST || mode == IMPORT_MODE::DITHERING) + if ((mode == IMPORT_MODE::CLOSEST || mode == IMPORT_MODE::DITHERING) && !IsInPalette(palette, rgbaSrc)) { - if (paletteIndex == PALETTE_TRANSPARENT && !IsTransparentPixel(rgbaSrc)) - { - paletteIndex = GetClosestPaletteIndex(palette, rgbaSrc); - } - } - if (mode == IMPORT_MODE::DITHERING) - { - if (!IsTransparentPixel(rgbaSrc) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc))) + paletteIndex = GetClosestPaletteIndex(palette, rgbaSrc); + if (mode == IMPORT_MODE::DITHERING) { auto dr = rgbaSrc[0] - static_cast(palette[paletteIndex].Red); auto dg = rgbaSrc[1] - static_cast(palette[paletteIndex].Green); auto db = rgbaSrc[2] - static_cast(palette[paletteIndex].Blue); + // We don't want to dither remappable colours with nonremappable colours, etc + PaletteIndexType thisIndexType = GetPaletteIndexType(paletteIndex); + if (x + 1 < width) { - if (!IsTransparentPixel(rgbaSrc + 4) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4))) + if (!IsInPalette(palette, rgbaSrc + 4) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4))) { // Right rgbaSrc[4] += dr * 7 / 16; @@ -265,8 +263,8 @@ int32_t ImageImporter::CalculatePaletteIndex( { if (x > 0) { - if (!IsTransparentPixel(rgbaSrc + 4 * (width - 1)) - && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * (width - 1)))) + if (!IsInPalette(palette, rgbaSrc + 4 * (width - 1)) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * (width - 1)))) { // Bottom left rgbaSrc[4 * (width - 1)] += dr * 3 / 16; @@ -276,7 +274,8 @@ int32_t ImageImporter::CalculatePaletteIndex( } // Bottom - if (!IsTransparentPixel(rgbaSrc + 4 * width) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * width))) + if (!IsInPalette(palette, rgbaSrc + 4 * width) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * width))) { rgbaSrc[4 * width] += dr * 5 / 16; rgbaSrc[4 * width + 1] += dg * 5 / 16; @@ -285,8 +284,8 @@ int32_t ImageImporter::CalculatePaletteIndex( if (x + 1 < width) { - if (!IsTransparentPixel(rgbaSrc + 4 * (width + 1)) - && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * (width + 1)))) + if (!IsInPalette(palette, rgbaSrc + 4 * (width + 1)) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * (width + 1)))) { // Bottom right rgbaSrc[4 * (width + 1)] += dr * 1 / 16; @@ -297,6 +296,7 @@ int32_t ImageImporter::CalculatePaletteIndex( } } } + return paletteIndex; } @@ -322,23 +322,40 @@ bool ImageImporter::IsTransparentPixel(const int16_t* colour) } /** - * @returns true if pixel index is an index not used for remapping. + * @returns true if this colour is in the standard palette. + */ +bool ImageImporter::IsInPalette(const GamePalette& palette, int16_t* colour) +{ + return !(GetPaletteIndex(palette, colour) == PALETTE_TRANSPARENT && !IsTransparentPixel(colour)); +} + +/** + * @returns true if palette index is an index not used for a special purpose. */ bool ImageImporter::IsChangablePixel(int32_t paletteIndex) { - if (paletteIndex == PALETTE_TRANSPARENT) - return true; - if (paletteIndex == 0) - return false; + PaletteIndexType entryType = GetPaletteIndexType(paletteIndex); + return entryType != PaletteIndexType::Special && entryType != PaletteIndexType::PrimaryRemap; +} + +/** + * @returns the type of palette entry this is. + */ +ImageImporter::PaletteIndexType ImageImporter::GetPaletteIndexType(int32_t paletteIndex) +{ + if (paletteIndex <= 9) + return PaletteIndexType::Special; + if (paletteIndex >= 230 && paletteIndex <= 239) + return PaletteIndexType::Special; + if (paletteIndex == 255) + return PaletteIndexType::Special; + if (paletteIndex >= 243 && paletteIndex <= 254) + return PaletteIndexType::PrimaryRemap; if (paletteIndex >= 202 && paletteIndex <= 213) - return false; - if (paletteIndex == 226) - return false; - if (paletteIndex >= 227 && paletteIndex <= 229) - return false; - if (paletteIndex >= 243) - return false; - return true; + return PaletteIndexType::SecondaryRemap; + if (paletteIndex >= 46 && paletteIndex <= 57) + return PaletteIndexType::TertiaryRemap; + return PaletteIndexType::Normal; } int32_t ImageImporter::GetClosestPaletteIndex(const GamePalette& palette, const int16_t* colour) diff --git a/src/openrct2/drawing/ImageImporter.h b/src/openrct2/drawing/ImageImporter.h index 3b2b26cd23..1ff1bc37d8 100644 --- a/src/openrct2/drawing/ImageImporter.h +++ b/src/openrct2/drawing/ImageImporter.h @@ -53,6 +53,15 @@ namespace OpenRCT2::Drawing IMPORT_MODE mode = IMPORT_MODE::DEFAULT) const; private: + enum class PaletteIndexType : uint8_t + { + Normal, + PrimaryRemap, + SecondaryRemap, + TertiaryRemap, + Special, + }; + static std::vector GetPixels( const uint8_t* pixels, uint32_t pitch, uint32_t srcX, uint32_t srcY, uint32_t width, uint32_t height, IMPORT_FLAGS flags, IMPORT_MODE mode); @@ -63,16 +72,18 @@ namespace OpenRCT2::Drawing IMPORT_MODE mode, int16_t* rgbaSrc, int32_t x, int32_t y, int32_t width, int32_t height); static int32_t GetPaletteIndex(const GamePalette& palette, int16_t* colour); static bool IsTransparentPixel(const int16_t* colour); + static bool IsInPalette(const GamePalette& palette, int16_t* colour); static bool IsChangablePixel(int32_t paletteIndex); + static PaletteIndexType GetPaletteIndexType(int32_t paletteIndex); static int32_t GetClosestPaletteIndex(const GamePalette& palette, const int16_t* colour); }; } // namespace OpenRCT2::Drawing constexpr const GamePalette StandardPalette = { { - // 0 (unused) + // 0 (Unused/Transparent) { 0, 0, 0, 255 }, - // 1 - 9 (misc. e.g. font and water) + // 1 - 9 (Misc. e.g. font, water, chain lift) { 1, 1, 1, 255 }, { 2, 2, 2, 255 }, { 3, 3, 3, 255 }, @@ -83,7 +94,7 @@ constexpr const GamePalette StandardPalette = { { { 8, 8, 8, 255 }, { 9, 9, 9, 255 }, - // + // 10 - 21 (Grey) { 35, 35, 23, 255 }, { 51, 51, 35, 255 }, { 67, 67, 47, 255 }, @@ -96,6 +107,8 @@ constexpr const GamePalette StandardPalette = { { { 195, 195, 183, 255 }, { 219, 219, 211, 255 }, { 243, 243, 239, 255 }, + + // 22 - 33 (Olive) { 0, 47, 51, 255 }, { 0, 59, 63, 255 }, { 11, 75, 79, 255 }, @@ -108,6 +121,8 @@ constexpr const GamePalette StandardPalette = { { { 115, 191, 187, 255 }, { 139, 207, 203, 255 }, { 163, 227, 223, 255 }, + + // 34 - 45 (Light Brown) { 7, 43, 67, 255 }, { 11, 59, 87, 255 }, { 23, 75, 111, 255 }, @@ -120,6 +135,8 @@ constexpr const GamePalette StandardPalette = { { { 135, 199, 219, 255 }, { 163, 219, 231, 255 }, { 195, 239, 247, 255 }, + + // 46 - 57 (Yellow, also used for tertiary remap) { 0, 27, 71, 255 }, { 0, 43, 95, 255 }, { 0, 63, 119, 255 }, @@ -132,6 +149,8 @@ constexpr const GamePalette StandardPalette = { { { 95, 243, 255, 255 }, { 143, 251, 255, 255 }, { 195, 255, 255, 255 }, + + // 58 - 69 (Indian Red) { 0, 0, 35, 255 }, { 0, 0, 79, 255 }, { 7, 7, 95, 255 }, @@ -144,6 +163,8 @@ constexpr const GamePalette StandardPalette = { { { 127, 127, 215, 255 }, { 159, 159, 235, 255 }, { 191, 191, 255, 255 }, + + // 70 - 81 (Grass Green) { 19, 51, 27, 255 }, { 23, 63, 35, 255 }, { 31, 79, 47, 255 }, @@ -156,6 +177,8 @@ constexpr const GamePalette StandardPalette = { { { 83, 187, 147, 255 }, { 95, 203, 163, 255 }, { 103, 219, 183, 255 }, + + // 82 - 93 (Olive Green) { 27, 55, 31, 255 }, { 35, 71, 47, 255 }, { 43, 83, 59, 255 }, @@ -168,6 +191,8 @@ constexpr const GamePalette StandardPalette = { { { 147, 219, 195, 255 }, { 167, 231, 207, 255 }, { 191, 247, 223, 255 }, + + // 94 - 105 (Green) { 0, 63, 15, 255 }, { 0, 83, 19, 255 }, { 0, 103, 23, 255 }, @@ -180,6 +205,8 @@ constexpr const GamePalette StandardPalette = { { { 115, 223, 139, 255 }, { 143, 239, 163, 255 }, { 179, 255, 195, 255 }, + + // 106 - 117 (Tan) { 19, 43, 79, 255 }, { 27, 55, 99, 255 }, { 43, 71, 119, 255 }, @@ -192,6 +219,8 @@ constexpr const GamePalette StandardPalette = { { { 151, 191, 239, 255 }, { 171, 207, 247, 255 }, { 195, 227, 255, 255 }, + + // 118 - 129 (Indigo) { 55, 19, 15, 255 }, { 87, 43, 39, 255 }, { 103, 55, 51, 255 }, @@ -204,6 +233,8 @@ constexpr const GamePalette StandardPalette = { { { 223, 183, 183, 255 }, { 239, 211, 211, 255 }, { 255, 239, 239, 255 }, + + // 130 - 141 (Blue) { 111, 27, 0, 255 }, { 151, 39, 0, 255 }, { 167, 51, 7, 255 }, @@ -216,6 +247,8 @@ constexpr const GamePalette StandardPalette = { { { 243, 211, 143, 255 }, { 251, 231, 175, 255 }, { 255, 247, 215, 255 }, + + // 142 - 153 (Sea Green) { 15, 43, 11, 255 }, { 23, 55, 15, 255 }, { 31, 71, 23, 255 }, @@ -228,6 +261,8 @@ constexpr const GamePalette StandardPalette = { { { 167, 199, 147, 255 }, { 195, 219, 175, 255 }, { 223, 243, 207, 255 }, + + // 154 - 165 (Purple) { 95, 0, 63, 255 }, { 115, 7, 75, 255 }, { 127, 15, 83, 255 }, @@ -240,6 +275,8 @@ constexpr const GamePalette StandardPalette = { { { 231, 155, 191, 255 }, { 243, 195, 215, 255 }, { 255, 235, 243, 255 }, + + // 166 - 177 (Red) { 0, 0, 63, 255 }, { 0, 0, 87, 255 }, { 0, 0, 115, 255 }, @@ -252,6 +289,8 @@ constexpr const GamePalette StandardPalette = { { { 115, 123, 255, 255 }, { 163, 171, 255, 255 }, { 215, 219, 255, 255 }, + + // 178 - 189 (Orange) { 0, 39, 79, 255 }, { 0, 51, 111, 255 }, { 0, 63, 147, 255 }, @@ -264,6 +303,8 @@ constexpr const GamePalette StandardPalette = { { { 107, 183, 255, 255 }, { 135, 203, 255, 255 }, { 163, 219, 255, 255 }, + + // 190 - 201 (Water Blue) { 47, 51, 0, 255 }, { 55, 63, 0, 255 }, { 67, 75, 0, 255 }, @@ -277,7 +318,7 @@ constexpr const GamePalette StandardPalette = { { { 231, 231, 171, 255 }, { 255, 255, 207, 255 }, - // 202 - 213 (Secondary remap) + // 202 - 213 (Pink, also used for secondary remap) { 27, 0, 63, 255 }, { 51, 0, 103, 255 }, { 63, 11, 123, 255 }, @@ -305,27 +346,29 @@ constexpr const GamePalette StandardPalette = { { { 195, 219, 231, 255 }, { 223, 243, 255, 255 }, - // 226 (unknown) + // 226 (Extra grey) { 75, 75, 55, 255 }, - // 227 - 229 (tertiary remap) + // 227 - 229 (Extra yellows) { 0, 183, 255, 255 }, { 0, 219, 255, 255 }, { 0, 255, 255, 255 }, - // 230 - 239 (water) + // 230 - 234 (Water waves) { 99, 107, 7, 255 }, { 99, 107, 7, 255 }, { 135, 143, 39, 255 }, { 123, 131, 27, 255 }, { 99, 107, 7, 255 }, + + // 235 - 249 (Water sparkles) { 151, 155, 55, 255 }, { 151, 155, 55, 255 }, { 227, 227, 155, 255 }, { 203, 203, 115, 255 }, { 151, 155, 55, 255 }, - // 240 - 242 (chain lift) + // 240 - 242 (Extra grey) { 91, 91, 67, 255 }, { 107, 107, 83, 255 }, { 123, 123, 99, 255 }, @@ -335,7 +378,7 @@ constexpr const GamePalette StandardPalette = { { // { 47, 47, 47, 255 }, // { 47, 71, 87, 255 }, - // 243 to 254 (primary remap) + // 243 to 254 (Primary remap) { 47, 51, 111, 255 }, { 47, 55, 131, 255 }, { 51, 63, 151, 255 }, @@ -349,6 +392,6 @@ constexpr const GamePalette StandardPalette = { { { 63, 183, 255, 255 }, { 75, 207, 255, 255 }, - // 255 (unused?) - { 0, 0, 0, 255 }, + // 255 (Used in a small number of cases for pure white) + { 255, 255, 255, 255 }, } }; diff --git a/src/openrct2/drawing/TTF.cpp b/src/openrct2/drawing/TTF.cpp index 7887bb8e6f..c32039e870 100644 --- a/src/openrct2/drawing/TTF.cpp +++ b/src/openrct2/drawing/TTF.cpp @@ -19,6 +19,7 @@ # include "../OpenRCT2.h" # include "../config/Config.h" +# include "../core/Numerics.hpp" # include "../core/String.hpp" # include "../localisation/Localisation.h" # include "../localisation/LocalisationService.h" @@ -186,7 +187,7 @@ static uint32_t ttf_surface_cache_hash(TTF_Font* font, std::string_view text) uint32_t hash = static_cast(((reinterpret_cast(font) * 23) ^ 0xAAAAAAAA) & 0xFFFFFFFF); for (auto c : text) { - hash = ror32(hash, 3) ^ (c * 13); + hash = Numerics::ror32(hash, 3) ^ (c * 13); } return hash; } diff --git a/src/openrct2/drawing/X8DrawingEngine.cpp b/src/openrct2/drawing/X8DrawingEngine.cpp index 528e236892..9cbbcdcf77 100644 --- a/src/openrct2/drawing/X8DrawingEngine.cpp +++ b/src/openrct2/drawing/X8DrawingEngine.cpp @@ -13,6 +13,7 @@ #include "../Game.h" #include "../Intro.h" #include "../config/Config.h" +#include "../core/Numerics.hpp" #include "../interface/Screenshot.h" #include "../interface/Viewport.h" #include "../interface/Window.h" @@ -583,7 +584,7 @@ void X8DrawingContext::FillRect(uint32_t colour, int32_t left, int32_t top, int3 for (int32_t i = 0; i < height; i++) { uint8_t* nextdst = dst + dpi->width + dpi->pitch; - uint32_t p = ror32(crossPattern, 1); + uint32_t p = Numerics::ror32(crossPattern, 1); p = (p & 0xFFFF0000) | width; // Fill every other pixel with the colour @@ -702,8 +703,9 @@ void X8DrawingContext::FilterRect(FilterPaletteID palette, int32_t left, int32_t // Find colour in colour table? auto paletteMap = GetPaletteMapForColour(EnumValue(palette)); - if (paletteMap) + if (paletteMap.has_value()) { + const auto& paletteEntries = paletteMap.value(); const int32_t scaled_width = width / dpi->zoom_level; const int32_t step = ((dpi->width / dpi->zoom_level) + dpi->pitch); @@ -715,7 +717,7 @@ void X8DrawingContext::FilterRect(FilterPaletteID palette, int32_t left, int32_t for (int32_t j = 0; j < scaled_width; j++) { auto index = *(nextdst + j); - *(nextdst + j) = (*paletteMap)[index]; + *(nextdst + j) = paletteEntries[index]; } } } diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp index 75c1a61e53..d05b4a8751 100644 --- a/src/openrct2/interface/InteractiveConsole.cpp +++ b/src/openrct2/interface/InteractiveConsole.cpp @@ -194,7 +194,7 @@ static int32_t cc_rides(InteractiveConsole& console, const arguments_t& argv) } else { - int32_t res = set_operating_setting(ride_index, RideSetSetting::RideType, type); + int32_t res = set_operating_setting(static_cast(ride_index), RideSetSetting::RideType, type); if (res == MONEY32_UNDEFINED) { if (!gCheatsAllowArbitraryRideTypeChanges) @@ -224,7 +224,7 @@ static int32_t cc_rides(InteractiveConsole& console, const arguments_t& argv) } else { - auto ride = get_ride(ride_index); + auto ride = get_ride(static_cast(ride_index)); if (mode >= static_cast(RideMode::Count)) { console.WriteFormatLine("Invalid ride mode."); @@ -256,7 +256,7 @@ static int32_t cc_rides(InteractiveConsole& console, const arguments_t& argv) } else { - auto ride = get_ride(ride_index); + auto ride = get_ride(static_cast(ride_index)); if (mass <= 0) { console.WriteFormatLine("Friction value must be strictly positive"); @@ -294,7 +294,7 @@ static int32_t cc_rides(InteractiveConsole& console, const arguments_t& argv) } else { - auto ride = get_ride(ride_index); + auto ride = get_ride(static_cast(ride_index)); if (excitement <= 0) { console.WriteFormatLine("Excitement value must be strictly positive"); @@ -325,7 +325,7 @@ static int32_t cc_rides(InteractiveConsole& console, const arguments_t& argv) } else { - auto ride = get_ride(ride_index); + auto ride = get_ride(static_cast(ride_index)); if (intensity <= 0) { console.WriteFormatLine("Intensity value must be strictly positive"); @@ -356,7 +356,7 @@ static int32_t cc_rides(InteractiveConsole& console, const arguments_t& argv) } else { - auto ride = get_ride(ride_index); + auto ride = get_ride(static_cast(ride_index)); if (nausea <= 0) { console.WriteFormatLine("Nausea value must be strictly positive"); @@ -426,7 +426,7 @@ static int32_t cc_rides(InteractiveConsole& console, const arguments_t& argv) } else { - auto rideSetPrice = RideSetPriceAction(rideId, price, true); + auto rideSetPrice = RideSetPriceAction(static_cast(rideId), price, true); GameActions::Execute(&rideSetPrice); } } diff --git a/src/openrct2/interface/Screenshot.cpp b/src/openrct2/interface/Screenshot.cpp index 850a23b84f..972dbc0f49 100644 --- a/src/openrct2/interface/Screenshot.cpp +++ b/src/openrct2/interface/Screenshot.cpp @@ -161,14 +161,14 @@ std::string screenshot_dump_png(rct_drawpixelinfo* dpi) // Get a free screenshot path auto path = screenshot_get_next_path(); - if (path == std::nullopt) + if (!path.has_value()) { return ""; } - if (WriteDpiToFile(path->c_str(), dpi, gPalette)) + if (WriteDpiToFile(path.value(), dpi, gPalette)) { - return *path; + return path.value(); } else { @@ -180,7 +180,7 @@ std::string screenshot_dump_png_32bpp(int32_t width, int32_t height, const void* { auto path = screenshot_get_next_path(); - if (path == std::nullopt) + if (!path.has_value()) { return ""; } @@ -196,8 +196,8 @@ std::string screenshot_dump_png_32bpp(int32_t width, int32_t height, const void* image.Depth = 32; image.Stride = width * 4; image.Pixels = std::vector(pixels8, pixels8 + pixelsLen); - Imaging::WriteToFile(path->c_str(), image, IMAGE_FORMAT::PNG_32); - return *path; + Imaging::WriteToFile(path.value(), image, IMAGE_FORMAT::PNG_32); + return path.value(); } catch (const std::exception& e) { @@ -384,7 +384,7 @@ void screenshot_giant() try { auto path = screenshot_get_next_path(); - if (path == std::nullopt) + if (!path.has_value()) { throw std::runtime_error("Giant screenshot failed, unable to find a suitable destination path."); } @@ -412,7 +412,7 @@ void screenshot_giant() dpi = CreateDPI(viewport); RenderViewport(nullptr, viewport, dpi); - WriteDpiToFile(path->c_str(), &dpi, gPalette); + WriteDpiToFile(path.value(), &dpi, gPalette); // Show user that screenshot saved successfully Formatter ft; @@ -792,7 +792,7 @@ static std::string ResolveFilenameForCapture(const fs::path& filename) void CaptureImage(const CaptureOptions& options) { rct_viewport viewport{}; - if (options.View) + if (options.View.has_value()) { viewport.width = options.View->Width; viewport.height = options.View->Height; diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp index 3b6fc35b4b..1f9fb894a5 100644 --- a/src/openrct2/interface/Viewport.cpp +++ b/src/openrct2/interface/Viewport.cpp @@ -106,7 +106,7 @@ std::optional centre_2d_coordinates(const CoordsXYZ& loc, rct_vi // If the start location was invalid // propagate the invalid location to the output. // This fixes a bug that caused the game to enter an infinite loop. - if (loc.isNull()) + if (loc.IsNull()) { return std::nullopt; } @@ -186,7 +186,7 @@ void viewport_create( } auto centreLoc = centre_2d_coordinates(centrePos, viewport); - if (!centreLoc) + if (!centreLoc.has_value()) { log_error("Invalid location for viewport."); return; @@ -519,7 +519,8 @@ static void viewport_move(const ScreenCoordsXY& coords, rct_window* w, rct_viewp // rct2: 0x006E7A15 static void viewport_set_underground_flag(int32_t underground, rct_window* window, rct_viewport* viewport) { - if (window->classification != WC_MAIN_WINDOW) + if (window->classification != WC_MAIN_WINDOW + || (window->classification == WC_MAIN_WINDOW && window->viewport_smart_follow_sprite != SPRITE_INDEX_NULL)) { if (!underground) { @@ -597,9 +598,9 @@ void viewport_update_position(rct_window* window) if (at_map_edge) { auto centreLoc = centre_2d_coordinates({ mapCoord, 0 }, viewport); - if (centreLoc) + if (centreLoc.has_value()) { - window->savedViewPos = *centreLoc; + window->savedViewPos = centreLoc.value(); } } @@ -658,7 +659,7 @@ void viewport_update_sprite_follow(rct_window* window) viewport_set_underground_flag(underground, window, window->viewport); auto centreLoc = centre_2d_coordinates({ sprite->x, sprite->y, sprite->z }, window->viewport); - if (centreLoc) + if (centreLoc.has_value()) { window->savedViewPos = *centreLoc; viewport_move(*centreLoc, window, window->viewport); @@ -669,44 +670,35 @@ void viewport_update_sprite_follow(rct_window* window) void viewport_update_smart_sprite_follow(rct_window* window) { auto entity = TryGetEntity(window->viewport_smart_follow_sprite); - if (entity == nullptr) + if (entity == nullptr || entity->Type == EntityType::Null) { window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; window->viewport_target_sprite = SPRITE_INDEX_NULL; + return; } - else if (entity->Type == EntityType::Guest || entity->Type == EntityType::Staff) - { - Peep* peep = TryGetEntity(window->viewport_smart_follow_sprite); - if (peep == nullptr) - { - // will never happen - window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; - window->viewport_target_sprite = SPRITE_INDEX_NULL; - return; - } - if (peep->Is()) - viewport_update_smart_guest_follow(window, peep); - else if (peep->Is()) - viewport_update_smart_staff_follow(window, peep); - } - else if (entity->Type == EntityType::Vehicle) + switch (entity->Type) { - viewport_update_smart_vehicle_follow(window); - } - else if (entity->Type != EntityType::Null) - { - window->viewport_focus_sprite.sprite_id = window->viewport_smart_follow_sprite; - window->viewport_target_sprite = window->viewport_smart_follow_sprite; - } - else - { - window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; - window->viewport_target_sprite = SPRITE_INDEX_NULL; + case EntityType::Vehicle: + viewport_update_smart_vehicle_follow(window); + break; + + case EntityType::Guest: + viewport_update_smart_guest_follow(window, entity->As()); + break; + + case EntityType::Staff: + viewport_update_smart_staff_follow(window, entity->As()); + break; + + default: // All other types don't need any "smart" following; steam particle, duck, money effect, etc. + window->viewport_focus_sprite.sprite_id = window->viewport_smart_follow_sprite; + window->viewport_target_sprite = window->viewport_smart_follow_sprite; + break; } } -viewport_focus viewport_update_smart_guest_follow(rct_window* window, Peep* peep) +viewport_focus viewport_update_smart_guest_follow(rct_window* window, const Guest* peep) { viewport_focus focus{}; focus.type = VIEWPORT_FOCUS_TYPE_SPRITE; @@ -719,54 +711,53 @@ viewport_focus viewport_update_smart_guest_follow(rct_window* window, Peep* peep window->viewport_target_sprite = SPRITE_INDEX_NULL; return focus; } - else + + bool overallFocus = true; + if (peep->State == PeepState::OnRide || peep->State == PeepState::EnteringRide + || (peep->State == PeepState::LeavingRide && peep->x == LOCATION_NULL)) { - bool overallFocus = true; - if (peep->State == PeepState::OnRide || peep->State == PeepState::EnteringRide - || (peep->State == PeepState::LeavingRide && peep->x == LOCATION_NULL)) + auto ride = get_ride(peep->CurrentRide); + if (ride != nullptr && (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) { - auto ride = get_ride(peep->CurrentRide); - if (ride != nullptr && (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) + auto train = GetEntity(ride->vehicles[peep->CurrentTrain]); + if (train != nullptr) { - auto train = GetEntity(ride->vehicles[peep->CurrentTrain]); - if (train != nullptr) + const auto car = train->GetCar(peep->CurrentCar); + if (car != nullptr) { - const auto car = train->GetCar(peep->CurrentCar); - if (car != nullptr) - { - focus.sprite.sprite_id = car->sprite_index; - overallFocus = false; - } + focus.sprite.sprite_id = car->sprite_index; + overallFocus = false; } } } - if (peep->x == LOCATION_NULL && overallFocus) - { - auto ride = get_ride(peep->CurrentRide); - if (ride != nullptr) - { - auto xy = ride->overall_view.ToTileCentre(); - focus.type = VIEWPORT_FOCUS_TYPE_COORDINATE; - focus.coordinate.x = xy.x; - focus.coordinate.y = xy.y; - focus.coordinate.z = tile_element_height(xy) + (4 * COORDS_Z_STEP); - focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE; - } - } - else - { - focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; - focus.sprite.pad_486 &= 0xFFFF; - } - focus.coordinate.rotation = get_current_rotation(); } + if (peep->x == LOCATION_NULL && overallFocus) + { + auto ride = get_ride(peep->CurrentRide); + if (ride != nullptr) + { + auto xy = ride->overall_view.ToTileCentre(); + focus.type = VIEWPORT_FOCUS_TYPE_COORDINATE; + focus.coordinate.x = xy.x; + focus.coordinate.y = xy.y; + focus.coordinate.z = tile_element_height(xy) + (4 * COORDS_Z_STEP); + focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE; + } + } + else + { + focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; + focus.sprite.pad_486 &= 0xFFFF; + } + focus.coordinate.rotation = get_current_rotation(); + window->viewport_focus_sprite = focus.sprite; window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id; return focus; } -void viewport_update_smart_staff_follow(rct_window* window, Peep* peep) +void viewport_update_smart_staff_follow(rct_window* window, const Staff* peep) { sprite_focus focus = {}; @@ -774,15 +765,12 @@ void viewport_update_smart_staff_follow(rct_window* window, Peep* peep) if (peep->State == PeepState::Picked) { - // focus.sprite.sprite_id = SPRITE_INDEX_NULL; window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; window->viewport_target_sprite = SPRITE_INDEX_NULL; return; } - else - { - focus.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; - } + + focus.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; window->viewport_focus_sprite = focus; window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id; @@ -790,9 +778,7 @@ void viewport_update_smart_staff_follow(rct_window* window, Peep* peep) void viewport_update_smart_vehicle_follow(rct_window* window) { - // Can be expanded in the future if needed sprite_focus focus = {}; - focus.sprite_id = window->viewport_smart_follow_sprite; window->viewport_focus_sprite = focus; @@ -1095,7 +1081,7 @@ static void viewport_paint_weather_gloom(rct_drawpixelinfo* dpi) std::optional screen_pos_to_map_pos(const ScreenCoordsXY& screenCoords, int32_t* direction) { auto mapCoords = screen_get_map_xy(screenCoords, nullptr); - if (!mapCoords) + if (!mapCoords.has_value()) return std::nullopt; int32_t my_direction; @@ -1628,9 +1614,9 @@ static bool is_sprite_interacted_with(rct_drawpixelinfo* dpi, int32_t imageId, c { index &= 0x1F; } - if (auto pm = GetPaletteMapForColour(index)) + if (auto pm = GetPaletteMapForColour(index); pm.has_value()) { - paletteMap = *pm; + paletteMap = pm.value(); } } else @@ -1880,7 +1866,7 @@ std::optional screen_get_map_xy_with_z(const ScreenCoordsXY& screenCoo std::optional screen_get_map_xy_quadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant) { auto mapCoords = screen_get_map_xy(screenCoords, nullptr); - if (!mapCoords) + if (!mapCoords.has_value()) return std::nullopt; *quadrant = map_get_tile_quadrant(*mapCoords); @@ -1894,7 +1880,7 @@ std::optional screen_get_map_xy_quadrant(const ScreenCoordsXY& screenC std::optional screen_get_map_xy_quadrant_with_z(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant) { auto mapCoords = screen_get_map_xy_with_z(screenCoords, z); - if (!mapCoords) + if (!mapCoords.has_value()) return std::nullopt; *quadrant = map_get_tile_quadrant(*mapCoords); @@ -1908,7 +1894,7 @@ std::optional screen_get_map_xy_quadrant_with_z(const ScreenCoordsXY& std::optional screen_get_map_xy_side(const ScreenCoordsXY& screenCoords, uint8_t* side) { auto mapCoords = screen_get_map_xy(screenCoords, nullptr); - if (!mapCoords) + if (!mapCoords.has_value()) return std::nullopt; *side = map_get_tile_side(*mapCoords); @@ -1922,7 +1908,7 @@ std::optional screen_get_map_xy_side(const ScreenCoordsXY& screenCoord std::optional screen_get_map_xy_side_with_z(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side) { auto mapCoords = screen_get_map_xy_with_z(screenCoords, z); - if (!mapCoords) + if (!mapCoords.has_value()) return std::nullopt; *side = map_get_tile_side(*mapCoords); diff --git a/src/openrct2/interface/Viewport.h b/src/openrct2/interface/Viewport.h index 3bd4f8880a..09091e511b 100644 --- a/src/openrct2/interface/Viewport.h +++ b/src/openrct2/interface/Viewport.h @@ -20,11 +20,12 @@ struct paint_session; struct RecordedPaintSession; struct paint_struct; struct rct_drawpixelinfo; -struct Peep; struct TileElement; struct rct_window; -union paint_entry; struct EntityBase; +struct Guest; +struct Staff; +union paint_entry; enum { @@ -111,8 +112,8 @@ void viewports_invalidate(int32_t left, int32_t top, int32_t right, int32_t bott void viewport_update_position(rct_window* window); void viewport_update_sprite_follow(rct_window* window); void viewport_update_smart_sprite_follow(rct_window* window); -viewport_focus viewport_update_smart_guest_follow(rct_window* window, Peep* peep); -void viewport_update_smart_staff_follow(rct_window* window, Peep* peep); +viewport_focus viewport_update_smart_guest_follow(rct_window* window, const Guest* peep); +void viewport_update_smart_staff_follow(rct_window* window, const Staff* peep); void viewport_update_smart_vehicle_follow(rct_window* window); void viewport_render( rct_drawpixelinfo* dpi, const rct_viewport* viewport, int32_t left, int32_t top, int32_t right, int32_t bottom, diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index 4e2c6aa70d..82a8f009c8 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -909,7 +909,7 @@ void window_rotate_camera(rct_window* w, int32_t direction) // other != viewport probably triggers on viewports in ride or guest window? // naoXYCoords is nullopt if middle of viewport is obstructed by another window? - if (!mapXYCoords || other != viewport) + if (!mapXYCoords.has_value() || other != viewport) { auto viewPos = ScreenCoordsXY{ (viewport->view_width >> 1), (viewport->view_height >> 1) } + viewport->viewPos; @@ -926,9 +926,9 @@ void window_rotate_camera(rct_window* w, int32_t direction) auto centreLoc = centre_2d_coordinates(coords, viewport); - if (centreLoc) + if (centreLoc.has_value()) { - w->savedViewPos = *centreLoc; + w->savedViewPos = centreLoc.value(); viewport->viewPos = *centreLoc; } @@ -976,7 +976,7 @@ void window_viewport_centre_tile_around_cursor(rct_window* w, int32_t map_x, int int32_t z = tile_element_height({ map_x, map_y }); auto centreLoc = centre_2d_coordinates({ map_x, map_y, z }, w->viewport); - if (!centreLoc) + if (!centreLoc.has_value()) { log_error("Invalid location."); return; diff --git a/src/openrct2/interface/Window_internal.h b/src/openrct2/interface/Window_internal.h index 4d145a480c..63239c0e39 100644 --- a/src/openrct2/interface/Window_internal.h +++ b/src/openrct2/interface/Window_internal.h @@ -45,10 +45,14 @@ struct rct_window int16_t max_width{}; int16_t min_height{}; int16_t max_height{}; - rct_windownumber number{}; + union + { + rct_windownumber number{}; + ride_id_t rideId; + }; uint16_t flags{}; rct_scroll scrolls[3]; - uint8_t list_item_positions[1024]{}; + uint32_t list_item_positions[1024]{}; uint16_t no_list_items{}; // 0 for no items int16_t selected_list_item{}; // -1 for none selected coordinate_focus viewport_focus_coordinates; diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index ce68dd142e..f88e448eb1 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -175,7 +175,6 @@ - @@ -185,6 +184,7 @@ + @@ -924,4 +924,4 @@ - + \ No newline at end of file diff --git a/src/openrct2/localisation/Formatter.h b/src/openrct2/localisation/Formatter.h index 7151fdbf94..fb392c9d97 100644 --- a/src/openrct2/localisation/Formatter.h +++ b/src/openrct2/localisation/Formatter.h @@ -16,6 +16,8 @@ extern thread_local uint8_t gCommonFormatArgs[80]; +enum class ride_id_t : uint16_t; + class Formatter { std::array Buffer{}; @@ -83,6 +85,7 @@ public: std::is_same_v::type, int32_t> || std::is_same_v::type, money32> || std::is_same_v::type, money64> || + std::is_same_v::type, ride_id_t> || std::is_same_v::type, rct_string_id> || std::is_same_v::type, uint16_t> || std::is_same_v::type, uint32_t> || @@ -92,7 +95,7 @@ public: // clang-format on uint64_t convertedValue; - if constexpr (std::is_integral_v) + if constexpr (std::is_integral_v || std::is_enum_v) { convertedValue = static_cast(value); } diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index 1a4243a460..eb0d5b6007 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3916,6 +3916,10 @@ enum STR_SHORTCUT_GIANT_SCREENSHOT = 6456, + STR_FILE_BUG_ON_GITHUB = 6457, + + STR_FOLLOW_SUBJECT_TIP = 6458, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings }; diff --git a/src/openrct2/management/NewsItem.cpp b/src/openrct2/management/NewsItem.cpp index c93eabe5af..bbd1d07af6 100644 --- a/src/openrct2/management/NewsItem.cpp +++ b/src/openrct2/management/NewsItem.cpp @@ -211,8 +211,8 @@ std::optional News::GetSubjectLocation(News::ItemType type, int32_t s { case News::ItemType::Ride: { - Ride* ride = get_ride(subject); - if (ride == nullptr || ride->overall_view.isNull()) + Ride* ride = get_ride(static_cast(subject)); + if (ride == nullptr || ride->overall_view.IsNull()) { break; } @@ -271,7 +271,7 @@ std::optional News::GetSubjectLocation(News::ItemType type, int32_t s auto subjectUnsigned = static_cast(subject); auto subjectXY = CoordsXY{ static_cast(subjectUnsigned & 0xFFFF), static_cast(subjectUnsigned >> 16) }; - if (!subjectXY.isNull()) + if (!subjectXY.IsNull()) { subjectLoc = CoordsXYZ{ subjectXY, tile_element_height(subjectXY) }; } diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index 2f4d2c35d9..fecfbacc30 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -40,7 +40,7 @@ // This string specifies which version of network stream current build uses. // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -#define NETWORK_STREAM_VERSION "7" +#define NETWORK_STREAM_VERSION "9" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr; @@ -64,7 +64,6 @@ static constexpr uint32_t MaxPacketsPerUpdate = 100; # include "../core/Console.hpp" # include "../core/FileStream.h" # include "../core/MemoryStream.h" -# include "../core/Nullable.hpp" # include "../core/Path.hpp" # include "../core/String.hpp" # include "../interface/Chat.h" @@ -914,9 +913,9 @@ uint8_t NetworkBase::GetGroupIDByHash(const std::string& keyhash) const NetworkUser* networkUser = _userManager.GetUserByHash(keyhash); uint8_t groupId = GetDefaultGroup(); - if (networkUser != nullptr && networkUser->GroupId.HasValue()) + if (networkUser != nullptr && networkUser->GroupId.has_value()) { - const uint8_t assignedGroup = networkUser->GroupId.GetValue(); + const uint8_t assignedGroup = *networkUser->GroupId; if (GetGroupByID(assignedGroup) != nullptr) { groupId = assignedGroup; @@ -1426,7 +1425,22 @@ std::vector NetworkBase::save_for_network(const std::vector result; auto ms = OpenRCT2::MemoryStream(); +<<<<<<< HEAD if (SaveMap(&ms, objects)) +======= + if (!SaveMap(&ms, objects)) + { + log_warning("Failed to export map."); + return header; + } + gUseRLE = RLEState; + + const void* data = ms.GetData(); + int32_t size = ms.GetLength(); + + auto compressed = util_zlib_deflate(static_cast(data), size); + if (compressed.has_value()) +>>>>>>> upstream/develop { result.resize(ms.GetLength()); std::memcpy(result.data(), ms.GetData(), result.size()); @@ -2062,7 +2076,7 @@ NetworkPlayer* NetworkBase::AddPlayer(const std::string& name, const std::string } else { - player->Group = networkUser->GroupId.GetValueOrDefault(GetDefaultGroup()); + player->Group = networkUser->GroupId.has_value() ? *networkUser->GroupId : GetDefaultGroup(); player->SetName(networkUser->Name); } diff --git a/src/openrct2/network/NetworkTypes.h b/src/openrct2/network/NetworkTypes.h index 6e4df2285b..c173fbfb16 100644 --- a/src/openrct2/network/NetworkTypes.h +++ b/src/openrct2/network/NetworkTypes.h @@ -126,10 +126,11 @@ template struct NetworkObjectId_t }; #pragma pack(pop) +using NetworkRideId_t = ride_id_t; + // NOTE: When adding new types make sure to have no duplicate _TypeID's otherwise // there is no way to specialize templates if they have the exact symbol. using NetworkPlayerId_t = NetworkObjectId_t; -using NetworkRideId_t = NetworkObjectId_t; using NetworkCheatType_t = NetworkObjectId_t; enum class NetworkStatisticsGroup : uint32_t diff --git a/src/openrct2/network/NetworkUser.cpp b/src/openrct2/network/NetworkUser.cpp index 456262e814..9d53100687 100644 --- a/src/openrct2/network/NetworkUser.cpp +++ b/src/openrct2/network/NetworkUser.cpp @@ -52,9 +52,9 @@ json_t NetworkUser::ToJson() const jsonData["name"] = Name; json_t jsonGroupId; - if (GroupId.HasValue()) + if (GroupId.has_value()) { - jsonGroupId = GroupId.GetValue(); + jsonGroupId = *GroupId; } jsonData["groupId"] = jsonGroupId; @@ -172,9 +172,9 @@ void NetworkUserManager::UnsetUsersOfGroup(uint8_t groupId) for (const auto& kvp : _usersByHash) { NetworkUser* networkUser = kvp.second; - if (networkUser->GroupId.HasValue() && networkUser->GroupId.GetValue() == groupId) + if (networkUser->GroupId.has_value() && *networkUser->GroupId == groupId) { - networkUser->GroupId = nullptr; + networkUser->GroupId = std::nullopt; } } } diff --git a/src/openrct2/network/NetworkUser.h b/src/openrct2/network/NetworkUser.h index 4cb750dd1d..4f114ecc2b 100644 --- a/src/openrct2/network/NetworkUser.h +++ b/src/openrct2/network/NetworkUser.h @@ -11,9 +11,9 @@ #include "../common.h" #include "../core/JsonFwd.hpp" -#include "../core/Nullable.hpp" #include +#include #include class NetworkUser final @@ -21,7 +21,7 @@ class NetworkUser final public: std::string Hash; std::string Name; - Nullable GroupId; + std::optional GroupId; bool Remove; /** diff --git a/src/openrct2/object/FootpathObject.cpp b/src/openrct2/object/FootpathObject.cpp index 827c3527c9..17df28d69c 100644 --- a/src/openrct2/object/FootpathObject.cpp +++ b/src/openrct2/object/FootpathObject.cpp @@ -40,23 +40,23 @@ void FootpathObject::Load() _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.bridge_image = _legacyType.image + 109; - _pathSurfaceEntry.string_idx = _legacyType.string_idx; - _pathSurfaceEntry.image = _legacyType.image; - _pathSurfaceEntry.preview = _legacyType.GetPreviewImage(); - _pathSurfaceEntry.flags = _legacyType.flags; + _pathSurfaceDescriptor.Name = _legacyType.string_idx; + _pathSurfaceDescriptor.Image = _legacyType.image; + _pathSurfaceDescriptor.PreviewImage = _legacyType.GetPreviewImage(); + _pathSurfaceDescriptor.Flags = _legacyType.flags; - _queueEntry.string_idx = _legacyType.string_idx; - _queueEntry.image = _legacyType.GetQueueImage(); - _queueEntry.preview = _legacyType.GetQueuePreviewImage(); - _queueEntry.flags = _legacyType.flags | FOOTPATH_ENTRY_FLAG_IS_QUEUE; + _queueSurfaceDescriptor.Name = _legacyType.string_idx; + _queueSurfaceDescriptor.Image = _legacyType.GetQueueImage(); + _queueSurfaceDescriptor.PreviewImage = _legacyType.GetQueuePreviewImage(); + _queueSurfaceDescriptor.Flags = _legacyType.flags | FOOTPATH_ENTRY_FLAG_IS_QUEUE; - _pathRailingsEntry.string_idx = _legacyType.string_idx; - _pathRailingsEntry.bridge_image = _legacyType.bridge_image; - _pathRailingsEntry.preview = _legacyType.GetPreviewImage(); - _pathRailingsEntry.flags = _legacyType.flags; - _pathRailingsEntry.scrolling_mode = _legacyType.scrolling_mode; - _pathRailingsEntry.support_type = _legacyType.support_type; - _pathRailingsEntry.railings_image = _legacyType.GetRailingsImage(); + _pathRailingsDescriptor.Name = _legacyType.string_idx; + _pathRailingsDescriptor.BridgeImage = _legacyType.bridge_image; + _pathRailingsDescriptor.PreviewImage = _legacyType.GetPreviewImage(); + _pathRailingsDescriptor.Flags = _legacyType.flags; + _pathRailingsDescriptor.ScrollingMode = _legacyType.scrolling_mode; + _pathRailingsDescriptor.SupportType = _legacyType.support_type; + _pathRailingsDescriptor.RailingsImage = _legacyType.GetRailingsImage(); } void FootpathObject::Unload() @@ -71,8 +71,8 @@ void FootpathObject::Unload() void FootpathObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t height) const { auto screenCoords = ScreenCoordsXY{ width / 2, height / 2 }; - gfx_draw_sprite(dpi, _pathSurfaceEntry.preview, screenCoords - ScreenCoordsXY{ 49, 17 }, 0); - gfx_draw_sprite(dpi, _queueEntry.preview, screenCoords + ScreenCoordsXY{ 4, -17 }, 0); + gfx_draw_sprite(dpi, _pathSurfaceDescriptor.PreviewImage, screenCoords - ScreenCoordsXY{ 49, 17 }, 0); + gfx_draw_sprite(dpi, _queueSurfaceDescriptor.PreviewImage, screenCoords + ScreenCoordsXY{ 4, -17 }, 0); } static RailingEntrySupportType ParseSupportType(const std::string& s) diff --git a/src/openrct2/object/FootpathObject.h b/src/openrct2/object/FootpathObject.h index c15fbfebe3..ebe409ae58 100644 --- a/src/openrct2/object/FootpathObject.h +++ b/src/openrct2/object/FootpathObject.h @@ -16,9 +16,9 @@ class FootpathObject final : public Object { private: rct_footpath_entry _legacyType = {}; - PathSurfaceEntry _pathSurfaceEntry = {}; - PathSurfaceEntry _queueEntry = {}; - PathRailingsEntry _pathRailingsEntry = {}; + PathSurfaceDescriptor _pathSurfaceDescriptor = {}; + PathSurfaceDescriptor _queueSurfaceDescriptor = {}; + PathRailingsDescriptor _pathRailingsDescriptor = {}; public: void* GetLegacyData() override @@ -26,19 +26,19 @@ public: return &_legacyType; } - PathSurfaceEntry* GetPathSurfaceEntry() + const PathSurfaceDescriptor& GetPathSurfaceDescriptor() const { - return &_pathSurfaceEntry; + return _pathSurfaceDescriptor; } - PathSurfaceEntry* GetQueueEntry() + const PathSurfaceDescriptor& GetQueueSurfaceDescriptor() const { - return &_queueEntry; + return _queueSurfaceDescriptor; } - PathRailingsEntry* GetPathRailingsEntry() + const PathRailingsDescriptor& GetPathRailingsDescriptor() const { - return &_pathRailingsEntry; + return _pathRailingsDescriptor; } void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; diff --git a/src/openrct2/object/FootpathRailingsObject.cpp b/src/openrct2/object/FootpathRailingsObject.cpp index ee16825968..b1045726f1 100644 --- a/src/openrct2/object/FootpathRailingsObject.cpp +++ b/src/openrct2/object/FootpathRailingsObject.cpp @@ -24,6 +24,15 @@ void FootpathRailingsObject::Load() BridgeImageId = PreviewImageId + 37; RailingsImageId = PreviewImageId + 1; } + + _descriptor.Name = NameStringId; + _descriptor.BridgeImage = BridgeImageId; + _descriptor.PreviewImage = PreviewImageId; + _descriptor.Flags = Flags; + _descriptor.ScrollingMode = ScrollingMode; + _descriptor.SupportType = SupportType; + _descriptor.SupportColour = Colour; + _descriptor.RailingsImage = RailingsImageId; } void FootpathRailingsObject::Unload() diff --git a/src/openrct2/object/FootpathRailingsObject.h b/src/openrct2/object/FootpathRailingsObject.h index 4eb2c705f7..15bc15edd0 100644 --- a/src/openrct2/object/FootpathRailingsObject.h +++ b/src/openrct2/object/FootpathRailingsObject.h @@ -23,6 +23,7 @@ public: uint8_t Flags{}; uint8_t ScrollingMode{}; colour_t Colour{}; + PathRailingsDescriptor _descriptor = {}; public: void ReadJson(IReadObjectContext* context, json_t& root) override; @@ -31,6 +32,11 @@ public: void DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t height) const override; + const PathRailingsDescriptor& GetDescriptor() const + { + return _descriptor; + } + private: RailingEntrySupportType ParseSupportType(std::string_view s); }; diff --git a/src/openrct2/object/FootpathSurfaceObject.cpp b/src/openrct2/object/FootpathSurfaceObject.cpp index 66b89b6727..bb20157c11 100644 --- a/src/openrct2/object/FootpathSurfaceObject.cpp +++ b/src/openrct2/object/FootpathSurfaceObject.cpp @@ -24,6 +24,11 @@ void FootpathSurfaceObject::Load() PreviewImageId = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); BaseImageId = PreviewImageId + 1; } + + _descriptor.Name = NameStringId; + _descriptor.Image = BaseImageId; + _descriptor.PreviewImage = PreviewImageId; + _descriptor.Flags = Flags; } void FootpathSurfaceObject::Unload() diff --git a/src/openrct2/object/FootpathSurfaceObject.h b/src/openrct2/object/FootpathSurfaceObject.h index c21ea2d1ab..b6c3e7cfa2 100644 --- a/src/openrct2/object/FootpathSurfaceObject.h +++ b/src/openrct2/object/FootpathSurfaceObject.h @@ -19,6 +19,7 @@ public: uint32_t PreviewImageId{}; uint32_t BaseImageId{}; uint8_t Flags{}; + PathSurfaceDescriptor _descriptor = {}; public: void ReadJson(IReadObjectContext* context, json_t& root) override; @@ -28,4 +29,9 @@ public: void DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t height) const override; void SetRepositoryItem(ObjectRepositoryItem* item) const override; + + const PathSurfaceDescriptor& GetDescriptor() const + { + return _descriptor; + } }; diff --git a/src/openrct2/object/Object.cpp b/src/openrct2/object/Object.cpp index 94e851647b..b845014eee 100644 --- a/src/openrct2/object/Object.cpp +++ b/src/openrct2/object/Object.cpp @@ -14,7 +14,7 @@ #include "../core/FileStream.h" #include "../core/Memory.hpp" #include "../core/String.hpp" -#include "../core/Zip.h" +#include "../core/ZipStream.hpp" #include "../localisation/Language.h" #include "../localisation/LocalisationService.h" #include "../localisation/StringIds.h" @@ -237,6 +237,7 @@ std::optional rct_object_entry::GetSceneryType() const } bool rct_object_entry::IsEmpty() const +<<<<<<< HEAD { uint64_t a, b; std::memcpy(&a, reinterpret_cast(this), 8); @@ -296,68 +297,61 @@ bool rct_object_entry::operator!=(const rct_object_entry& rhs) const * for the lifetime of the stream. */ class ZipStreamWrapper final : public IStream +======= +>>>>>>> upstream/develop { -private: - std::unique_ptr _zipArchive; - std::unique_ptr _base; + uint64_t a, b; + std::memcpy(&a, reinterpret_cast(this), 8); + std::memcpy(&b, reinterpret_cast(this) + 8, 8); -public: - ZipStreamWrapper(std::unique_ptr zipArchive, std::unique_ptr base) - : _zipArchive(std::move(zipArchive)) - , _base(std::move(base)) - { - } + if (a == 0xFFFFFFFFFFFFFFFF && b == 0xFFFFFFFFFFFFFFFF) + return true; + if (a == 0 && b == 0) + return true; + return false; +} - bool CanRead() const override - { - return _base->CanRead(); - } +bool rct_object_entry::operator==(const rct_object_entry& rhs) const +{ + const auto a = this; + const auto b = &rhs; - bool CanWrite() const override + // If an official object don't bother checking checksum + if ((a->flags & 0xF0) || (b->flags & 0xF0)) { - return _base->CanWrite(); + if (a->GetType() != b->GetType()) + { + return false; + } + int32_t match = memcmp(a->name, b->name, 8); + if (match) + { + return false; + } } + else + { + if (a->flags != b->flags) + { + return false; + } + int32_t match = memcmp(a->name, b->name, 8); + if (match) + { + return false; + } + if (a->checksum != b->checksum) + { + return false; + } + } + return true; +} - uint64_t GetLength() const override - { - return _base->GetLength(); - } - - uint64_t GetPosition() const override - { - return _base->GetPosition(); - } - - void SetPosition(uint64_t position) override - { - _base->SetPosition(position); - } - - void Seek(int64_t offset, int32_t origin) override - { - _base->Seek(offset, origin); - } - - void Read(void* buffer, uint64_t length) override - { - _base->Read(buffer, length); - } - - void Write(const void* buffer, uint64_t length) override - { - _base->Write(buffer, length); - } - - uint64_t TryRead(void* buffer, uint64_t length) override - { - return _base->TryRead(buffer, length); - } - - const void* GetData() const override - { - return _base->GetData(); - } -}; +bool rct_object_entry::operator!=(const rct_object_entry& rhs) const +{ + return !(*this == rhs); +} bool ObjectAsset::IsAvailable() const { @@ -384,9 +378,9 @@ uint64_t ObjectAsset::GetSize() const if (zipArchive != nullptr) { auto index = zipArchive->GetIndexFromPath(_path); - if (index) + if (index.has_value()) { - auto size = zipArchive->GetFileSize(*index); + auto size = zipArchive->GetFileSize(index.value()); return size; } } diff --git a/src/openrct2/object/Object.h b/src/openrct2/object/Object.h index be38e02194..2a5504af14 100644 --- a/src/openrct2/object/Object.h +++ b/src/openrct2/object/Object.h @@ -15,6 +15,7 @@ #include "ImageTable.h" #include "StringTable.h" +#include #include #include #include diff --git a/src/openrct2/object/ObjectList.cpp b/src/openrct2/object/ObjectList.cpp index 7f2c310a87..acf821b459 100644 --- a/src/openrct2/object/ObjectList.cpp +++ b/src/openrct2/object/ObjectList.cpp @@ -18,6 +18,7 @@ #include "ObjectRepository.h" #include +#include #include // 98DA00 @@ -41,6 +42,7 @@ int32_t object_entry_group_counts[] = { MAX_FOOTPATH_SURFACE_OBJECTS, MAX_FOOTPATH_RAILINGS_OBJECTS, }; +static_assert(std::size(object_entry_group_counts) == EnumValue(ObjectType::Count)); // 98DA2C int32_t object_entry_group_encoding[] = { @@ -87,6 +89,8 @@ void ObjectList::const_iterator::MoveToNextEntry() break; } } while (!_parent->_subLists[_subList][_index].HasValue()); +<<<<<<< HEAD +======= } ObjectList::const_iterator& ObjectList::const_iterator::operator++() @@ -186,6 +190,116 @@ ObjectEntryIndex ObjectList::Find(ObjectType type, std::string_view identifier) } } return OBJECT_ENTRY_INDEX_NULL; +>>>>>>> upstream/develop +} + +ObjectList::const_iterator& ObjectList::const_iterator::operator++() +{ + MoveToNextEntry(); + return *this; +} + +ObjectList::const_iterator ObjectList::const_iterator::operator++(int) +{ + return *this; +} + +const ObjectEntryDescriptor& ObjectList::const_iterator::operator*() +{ + return _parent->_subLists[_subList][_index]; +} + +bool ObjectList::const_iterator::operator==(const_iterator& rhs) +{ + return _parent == rhs._parent && _subList == rhs._subList && _index == rhs._index; +} + +bool ObjectList::const_iterator::operator!=(const_iterator& rhs) +{ + return !(*this == rhs); +} + +ObjectList::const_iterator ObjectList::begin() const +{ + return const_iterator(this, false); +} + +ObjectList::const_iterator ObjectList::end() const +{ + return const_iterator(this, true); +} + +std::vector& ObjectList::GetList(ObjectType type) +{ + auto index = static_cast(type); + while (_subLists.size() <= index) + { + _subLists.resize(static_cast(index) + 1); + } + return _subLists[index]; +} + +std::vector& ObjectList::GetList(ObjectType type) const +{ + return const_cast(this)->GetList(type); +} + +const ObjectEntryDescriptor& ObjectList::GetObject(ObjectType type, ObjectEntryIndex index) const +{ + const auto& subList = GetList(type); + if (subList.size() > index) + { + return subList[index]; + } + + static ObjectEntryDescriptor placeholder; + return placeholder; +} + +void ObjectList::Add(const ObjectEntryDescriptor& entry) +{ + auto& subList = GetList(entry.GetType()); + subList.push_back(entry); +} + +void ObjectList::SetObject(ObjectEntryIndex index, const ObjectEntryDescriptor& entry) +{ + auto& subList = GetList(entry.GetType()); + if (subList.size() <= index) + { + subList.resize(static_cast(index) + 1); + } + subList[index] = entry; +} + +void ObjectList::SetObject(ObjectType type, ObjectEntryIndex index, std::string_view identifier) +{ + auto entry = ObjectEntryDescriptor(identifier); + entry.Type = type; + SetObject(index, entry); +} + +ObjectEntryIndex ObjectList::Find(ObjectType type, std::string_view identifier) +{ + auto& subList = GetList(type); + for (size_t i = 0; i < subList.size(); i++) + { + if (subList[i].Identifier == identifier) + { +<<<<<<< HEAD + return static_cast(i); +======= + auto thisEntry = object_entry_get_object(objectType, i)->GetObjectEntry(); + if (thisEntry == *entry) + { + *entry_type = objectType; + *entryIndex = i; + return true; + } +>>>>>>> upstream/develop + } + } + return OBJECT_ENTRY_INDEX_NULL; } /** @@ -219,6 +333,7 @@ void get_type_entry_index(size_t index, ObjectType* outObjectType, ObjectEntryIn *outEntryIndex = static_cast(index); } +<<<<<<< HEAD void* get_loaded_object_chunk(size_t index) { ObjectType objectType; @@ -227,6 +342,8 @@ void* get_loaded_object_chunk(size_t index) return object_entry_get_chunk(objectType, entryIndex); } +======= +>>>>>>> upstream/develop void object_entry_get_name_fixed(utf8* buffer, size_t bufferSize, const rct_object_entry* entry) { bufferSize = std::min(static_cast(DAT_NAME_LENGTH) + 1, bufferSize); @@ -236,20 +353,13 @@ void object_entry_get_name_fixed(utf8* buffer, size_t bufferSize, const rct_obje void* object_entry_get_chunk(ObjectType objectType, ObjectEntryIndex index) { - ObjectEntryIndex objectIndex = index; - for (int32_t i = 0; i < EnumValue(objectType); i++) - { - objectIndex += object_entry_group_counts[i]; - } - - void* result = nullptr; auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager(); - auto obj = objectMgr.GetLoadedObject(objectIndex); - if (obj != nullptr) + auto* object = objectMgr.GetLoadedObject(objectType, index); + if (object != nullptr) { - result = obj->GetLegacyData(); + return object->GetLegacyData(); } - return result; + return nullptr; } const Object* object_entry_get_object(ObjectType objectType, ObjectEntryIndex index) diff --git a/src/openrct2/object/ObjectList.h b/src/openrct2/object/ObjectList.h index 5b00ec186d..9e100261c9 100644 --- a/src/openrct2/object/ObjectList.h +++ b/src/openrct2/object/ObjectList.h @@ -57,4 +57,7 @@ public: }; void get_type_entry_index(size_t index, ObjectType* outObjectType, ObjectEntryIndex* outEntryIndex); +<<<<<<< HEAD void* get_loaded_object_chunk(size_t index); +======= +>>>>>>> upstream/develop diff --git a/src/openrct2/object/ObjectManager.cpp b/src/openrct2/object/ObjectManager.cpp index f9ebc41317..8de2255e7a 100644 --- a/src/openrct2/object/ObjectManager.cpp +++ b/src/openrct2/object/ObjectManager.cpp @@ -36,7 +36,8 @@ class ObjectManager final : public IObjectManager { private: IObjectRepository& _objectRepository; - std::vector> _loadedObjects; + + std::vector _loadedObjects; std::array, RIDE_TYPE_COUNT> _rideTypeToObjectMap; // Used to return a safe empty vector back from GetAllRideEntries, can be removed when std::span is available @@ -63,11 +64,17 @@ public: { return nullptr; } - return _loadedObjects[index].get(); + return _loadedObjects[index]; } Object* GetLoadedObject(ObjectType objectType, size_t index) override { + // This is sometimes done deliberately (to avoid boilerplate), so no need to log_warn for this. + if (index == OBJECT_ENTRY_INDEX_NULL) + { + return nullptr; + } + if (index >= static_cast(object_entry_group_counts[EnumValue(objectType)])) { #ifdef DEBUG @@ -85,13 +92,11 @@ public: Object* GetLoadedObject(const ObjectEntryDescriptor& entry) override { - Object* loadedObject = nullptr; const ObjectRepositoryItem* ori = _objectRepository.FindObject(entry); - if (ori != nullptr) - { - loadedObject = ori->LoadedObject; - } - return loadedObject; + if (ori == nullptr) + return nullptr; + + return ori->LoadedObject.get(); } ObjectEntryIndex GetLoadedObjectEntryIndex(std::string_view identifier) override @@ -167,13 +172,18 @@ public: auto requiredObjects = GetRequiredObjects(objectList); // Load the required objects - size_t numNewLoadedObjects = 0; - auto loadedObjects = LoadObjects(requiredObjects, &numNewLoadedObjects); + LoadObjects(requiredObjects); +<<<<<<< HEAD SetNewLoadedObjectList(std::move(loadedObjects)); +======= + // Load defaults. + LoadDefaultObjects(); + + // Update indices. +>>>>>>> upstream/develop UpdateSceneryGroupIndexes(); ResetTypeToRideEntryIndexMap(); - log_verbose("%u / %u new objects loaded", numNewLoadedObjects, requiredObjects.size()); } void UnloadObjects(const std::vector& entries) override @@ -188,7 +198,11 @@ public: const auto* ori = _objectRepository.FindObject(descriptor); if (ori != nullptr) { +<<<<<<< HEAD auto* loadedObject = ori->LoadedObject; +======= + auto* loadedObject = ori->LoadedObject.get(); +>>>>>>> upstream/develop if (loadedObject != nullptr) { UnloadObject(loadedObject); @@ -206,9 +220,9 @@ public: void UnloadAll() override { - for (auto& object : _loadedObjects) + for (auto* object : _loadedObjects) { - UnloadObject(object.get()); + UnloadObject(object); } UpdateSceneryGroupIndexes(); ResetTypeToRideEntryIndexMap(); @@ -234,8 +248,14 @@ public: size_t numObjects = _objectRepository.GetNumObjects(); for (size_t i = 0; i < numObjects; i++) { + // TODO: remove ObjectGeneration::DAT check when the NSF is here const ObjectRepositoryItem* item = &_objectRepository.GetObjects()[i]; +<<<<<<< HEAD if (item->LoadedObject != nullptr && IsObjectCustom(item)) +======= + if (item->LoadedObject != nullptr && IsObjectCustom(item) && item->LoadedObject->GetLegacyData() != nullptr + && item->LoadedObject->GetGeneration() == ObjectGeneration::DAT) +>>>>>>> upstream/develop { objects.push_back(item); } @@ -285,12 +305,19 @@ private: Object* RepositoryItemToObject(const ObjectRepositoryItem* ori, std::optional slot = {}) { - Object* loadedObject = nullptr; - if (ori != nullptr) + if (ori == nullptr) + return nullptr; + + Object* loadedObject = ori->LoadedObject.get(); + if (loadedObject != nullptr) + return loadedObject; + + ObjectType objectType = ori->Type; + if (slot) { - loadedObject = ori->LoadedObject; - if (loadedObject == nullptr) + if (_loadedObjects.size() > static_cast(*slot) && _loadedObjects[*slot] != nullptr) { +<<<<<<< HEAD ObjectType objectType = ori->Type; if (slot) { @@ -305,20 +332,29 @@ private: slot = FindSpareSlot(objectType); } if (slot) +======= + // Slot already taken + return nullptr; + } + } + else + { + slot = FindSpareSlot(objectType); + } + if (slot.has_value()) + { + auto* object = GetOrLoadObject(ori); + if (object != nullptr) + { + if (_loadedObjects.size() <= static_cast(*slot)) +>>>>>>> upstream/develop { - auto object = GetOrLoadObject(ori); - if (object != nullptr) - { - if (_loadedObjects.size() <= static_cast(*slot)) - { - _loadedObjects.resize(*slot + 1); - } - loadedObject = object.get(); - _loadedObjects[*slot] = std::move(object); - UpdateSceneryGroupIndexes(); - ResetTypeToRideEntryIndexMap(); - } + _loadedObjects.resize(slot.value() + 1); } + loadedObject = object; + _loadedObjects[slot.value()] = object; + UpdateSceneryGroupIndexes(); + ResetTypeToRideEntryIndexMap(); } } return loadedObject; @@ -340,7 +376,7 @@ private: return static_cast(i); } } - return {}; + return std::nullopt; } size_t GetLoadedObjectIndex(const Object* object) @@ -348,8 +384,7 @@ private: Guard::ArgumentNotNull(object, GUARD_LINE); auto result = std::numeric_limits().max(); - auto it = std::find_if( - _loadedObjects.begin(), _loadedObjects.end(), [object](auto& obj) { return obj.get() == object; }); + auto it = std::find(_loadedObjects.begin(), _loadedObjects.end(), object); if (it != _loadedObjects.end()) { result = std::distance(_loadedObjects.begin(), it); @@ -357,24 +392,21 @@ private: return result; } - void SetNewLoadedObjectList(std::vector>&& newLoadedObjects) - { - if (newLoadedObjects.empty()) - { - UnloadAll(); - } - else - { - UnloadObjectsExcept(newLoadedObjects); - } - _loadedObjects = std::move(newLoadedObjects); - } - void UnloadObject(Object* object) { - if (object != nullptr) + if (object == nullptr) + return; + +<<<<<<< HEAD + // TODO try to prevent doing a repository search + const auto* ori = _objectRepository.FindObject(object->GetDescriptor()); + if (ori != nullptr) { - object->Unload(); + _objectRepository.UnregisterLoadedObject(ori, object); + } +======= + object->Unload(); +>>>>>>> upstream/develop // TODO try to prevent doing a repository search const auto* ori = _objectRepository.FindObject(object->GetDescriptor()); @@ -385,17 +417,10 @@ private: // Because it's possible to have the same loaded object for multiple // slots, we have to make sure find and set all of them to nullptr - for (auto& obj : _loadedObjects) - { - if (obj.get() == object) - { - obj = nullptr; - } - } - } + std::replace(_loadedObjects.begin(), _loadedObjects.end(), object, static_cast(nullptr)); } - void UnloadObjectsExcept(const std::vector>& newLoadedObjects) + void UnloadObjectsExcept(const std::vector& newLoadedObjects) { // Build a hash set for quick checking auto exceptSet = std::unordered_set(); @@ -403,77 +428,69 @@ private: { if (object != nullptr) { - exceptSet.insert(object.get()); + exceptSet.insert(object); } } // Unload objects that are not in the hash set size_t totalObjectsLoaded = 0; size_t numObjectsUnloaded = 0; - for (auto& object : _loadedObjects) + for (auto* object : _loadedObjects) { - if (object != nullptr) + if (object == nullptr) + continue; + + totalObjectsLoaded++; + if (exceptSet.find(object) == exceptSet.end()) { - totalObjectsLoaded++; - if (exceptSet.find(object.get()) == exceptSet.end()) - { - UnloadObject(object.get()); - numObjectsUnloaded++; - } + UnloadObject(object); + numObjectsUnloaded++; } } log_verbose("%u / %u objects unloaded", numObjectsUnloaded, totalObjectsLoaded); } + template void UpdateSceneryGroupIndexes(Object* object) + { + auto* sceneryEntry = static_cast(object->GetLegacyData()); + sceneryEntry->scenery_tab_id = GetPrimarySceneryGroupEntryIndex(object); + } + void UpdateSceneryGroupIndexes() { - for (auto& loadedObject : _loadedObjects) + for (auto* loadedObject : _loadedObjects) { - if (loadedObject != nullptr) + // The list can contain unused slots, skip them. + if (loadedObject == nullptr) + continue; + + switch (loadedObject->GetObjectType()) { - switch (loadedObject->GetObjectType()) + case ObjectType::SmallScenery: + UpdateSceneryGroupIndexes(loadedObject); + break; + case ObjectType::LargeScenery: + UpdateSceneryGroupIndexes(loadedObject); + break; + case ObjectType::Walls: + UpdateSceneryGroupIndexes(loadedObject); + break; + case ObjectType::Banners: + UpdateSceneryGroupIndexes(loadedObject); + break; + case ObjectType::PathBits: + UpdateSceneryGroupIndexes(loadedObject); + break; + case ObjectType::SceneryGroup: { - case ObjectType::SmallScenery: - { - auto* sceneryEntry = static_cast(loadedObject->GetLegacyData()); - sceneryEntry->scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get()); - break; - } - case ObjectType::LargeScenery: - { - auto* sceneryEntry = static_cast(loadedObject->GetLegacyData()); - sceneryEntry->scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get()); - break; - } - case ObjectType::Walls: - { - auto* wallEntry = static_cast(loadedObject->GetLegacyData()); - wallEntry->scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get()); - break; - } - case ObjectType::Banners: - { - auto* bannerEntry = static_cast(loadedObject->GetLegacyData()); - bannerEntry->scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get()); - break; - } - case ObjectType::PathBits: - { - auto* pathBitEntry = static_cast(loadedObject->GetLegacyData()); - pathBitEntry->scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject.get()); - break; - } - case ObjectType::SceneryGroup: - { - auto sgObject = dynamic_cast(loadedObject.get()); - sgObject->UpdateEntryIndexes(); - break; - } - default: - // This switch only handles scenery ObjectTypes. - break; + auto sgObject = dynamic_cast(loadedObject); + sgObject->UpdateEntryIndexes(); + break; } + default: + // This switch only handles scenery ObjectTypes. + break; } } @@ -484,7 +501,7 @@ private: ObjectEntryIndex GetPrimarySceneryGroupEntryIndex(Object* loadedObject) { - auto sceneryObject = dynamic_cast(loadedObject); + auto* sceneryObject = dynamic_cast(loadedObject); const auto& primarySGEntry = sceneryObject->GetPrimarySceneryGroup(); Object* sgObject = GetLoadedObject(primarySGEntry); @@ -496,46 +513,45 @@ private: return entryIndex; } - rct_object_entry* DuplicateObjectEntry(const rct_object_entry* original) - { - rct_object_entry* duplicate = Memory::Allocate(sizeof(rct_object_entry)); - duplicate->checksum = original->checksum; - strncpy(duplicate->name, original->name, 8); - duplicate->flags = original->flags; - return duplicate; - } - std::vector GetRequiredObjects(const ObjectList& objectList) { std::vector requiredObjects; std::vector missingObjects; - for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++) +<<<<<<< HEAD + std::vector GetRequiredObjects(const ObjectList& objectList) { - auto maxObjectsOfType = static_cast(object_entry_group_counts[EnumValue(objectType)]); - for (ObjectEntryIndex i = 0; i < maxObjectsOfType; i++) + std::vector requiredObjects; + std::vector missingObjects; + +======= +>>>>>>> upstream/develop + for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++) { - const ObjectRepositoryItem* ori = nullptr; - const auto& entry = objectList.GetObject(objectType, i); - if (entry.HasValue()) + auto maxObjectsOfType = static_cast(object_entry_group_counts[EnumValue(objectType)]); + for (ObjectEntryIndex i = 0; i < maxObjectsOfType; i++) { - ori = _objectRepository.FindObject(entry); - if (ori == nullptr && entry.GetType() != ObjectType::ScenarioText) + const ObjectRepositoryItem* ori = nullptr; + const auto& entry = objectList.GetObject(objectType, i); + if (entry.HasValue()) { - missingObjects.push_back(entry); - ReportMissingObject(entry); + ori = _objectRepository.FindObject(entry); + if (ori == nullptr && entry.GetType() != ObjectType::ScenarioText) + { + missingObjects.push_back(entry); + ReportMissingObject(entry); + } } + requiredObjects.push_back(ori); } - requiredObjects.push_back(ori); } - } - if (!missingObjects.empty()) - { - throw ObjectLoadException(std::move(missingObjects)); - } + if (!missingObjects.empty()) + { + throw ObjectLoadException(std::move(missingObjects)); + } - return requiredObjects; + return requiredObjects; } template static void ParallelFor(const std::vector& items, TFunc func) @@ -562,61 +578,56 @@ private: } } - std::vector> LoadObjects( - std::vector& requiredObjects, size_t* outNewObjectsLoaded) + void LoadObjects(std::vector & requiredObjects) { +<<<<<<< HEAD std::vector> objects; std::vector loadedObjects; +======= + std::vector objects; + std::vector newLoadedObjects; +>>>>>>> upstream/develop std::vector badObjects; objects.resize(OBJECT_ENTRY_COUNT); - loadedObjects.reserve(OBJECT_ENTRY_COUNT); + newLoadedObjects.reserve(OBJECT_ENTRY_COUNT); // Read objects std::mutex commonMutex; - ParallelFor(requiredObjects, [this, &commonMutex, requiredObjects, &objects, &badObjects, &loadedObjects](size_t i) { - auto requiredObject = requiredObjects[i]; - std::unique_ptr object; + ParallelFor(requiredObjects, [this, &commonMutex, requiredObjects, &objects, &badObjects, &newLoadedObjects](size_t i) { + auto* requiredObject = requiredObjects[i]; + Object* object = nullptr; if (requiredObject != nullptr) { - auto loadedObject = requiredObject->LoadedObject; + auto* loadedObject = requiredObject->LoadedObject.get(); if (loadedObject == nullptr) { // Object requires to be loaded, if the object successfully loads it will register it // as a loaded object otherwise placed into the badObjects list. - object = _objectRepository.LoadObject(requiredObject); + auto newObject = _objectRepository.LoadObject(requiredObject); std::lock_guard guard(commonMutex); - if (object == nullptr) + if (newObject == nullptr) { badObjects.push_back(ObjectEntryDescriptor(requiredObject->ObjectEntry)); ReportObjectLoadProblem(&requiredObject->ObjectEntry); } else { - loadedObjects.push_back(object.get()); + object = newObject.get(); + newLoadedObjects.push_back(object); // Connect the ori to the registered object - _objectRepository.RegisterLoadedObject(requiredObject, object.get()); + _objectRepository.RegisterLoadedObject(requiredObject, std::move(newObject)); } } else { - // The object is already loaded, given that the new list will be used as the next loaded object list, - // we can move the element out safely. This is required as the resulting list must contain all loaded - // objects and not just the newly loaded ones. - std::lock_guard guard(commonMutex); - auto it = std::find_if(_loadedObjects.begin(), _loadedObjects.end(), [loadedObject](const auto& obj) { - return obj.get() == loadedObject; - }); - if (it != _loadedObjects.end()) - { - object = std::move(*it); - } + object = loadedObject; } } - objects[i] = std::move(object); + objects[i] = object; }); // Load objects - for (auto obj : loadedObjects) + for (auto* obj : newLoadedObjects) { obj->Load(); } @@ -624,37 +635,47 @@ private: if (!badObjects.empty()) { // Unload all the new objects we loaded - for (auto object : loadedObjects) + for (auto* object : newLoadedObjects) { UnloadObject(object); } throw ObjectLoadException(std::move(badObjects)); } - if (outNewObjectsLoaded != nullptr) + // Unload objects which are not in the required list. + if (objects.empty()) { - *outNewObjectsLoaded = loadedObjects.size(); + UnloadAll(); } - return objects; + else + { + UnloadObjectsExcept(objects); + } + + _loadedObjects = std::move(objects); + + log_verbose("%u / %u new objects loaded", newLoadedObjects.size(), requiredObjects.size()); } - std::unique_ptr GetOrLoadObject(const ObjectRepositoryItem* ori) + Object* GetOrLoadObject(const ObjectRepositoryItem* ori) { - std::unique_ptr object; - auto loadedObject = ori->LoadedObject; - if (loadedObject == nullptr) - { - // Try to load object - object = _objectRepository.LoadObject(ori); - if (object != nullptr) - { - object->Load(); + auto* loadedObject = ori->LoadedObject.get(); + if (loadedObject != nullptr) + return loadedObject; - // Connect the ori to the registered object - _objectRepository.RegisterLoadedObject(ori, object.get()); - } + // Try to load object + auto object = _objectRepository.LoadObject(ori); + if (object != nullptr) + { + loadedObject = object.get(); + + object->Load(); + + // Connect the ori to the registered object + _objectRepository.RegisterLoadedObject(ori, std::move(object)); } - return object; + + return loadedObject; } void ResetTypeToRideEntryIndexMap() @@ -666,23 +687,23 @@ private: } // Build object lists - auto maxRideObjects = static_cast(object_entry_group_counts[EnumValue(ObjectType::Ride)]); + const auto maxRideObjects = static_cast(object_entry_group_counts[EnumValue(ObjectType::Ride)]); for (size_t i = 0; i < maxRideObjects; i++) { - auto rideObject = static_cast(GetLoadedObject(ObjectType::Ride, i)); - if (rideObject != nullptr) + auto* rideObject = static_cast(GetLoadedObject(ObjectType::Ride, i)); + if (rideObject == nullptr) + continue; + + const auto* entry = static_cast(rideObject->GetLegacyData()); + if (entry == nullptr) + continue; + + for (auto rideType : entry->ride_type) { - const auto entry = static_cast(rideObject->GetLegacyData()); - if (entry != nullptr) + if (rideType < _rideTypeToObjectMap.size()) { - for (auto rideType : entry->ride_type) - { - if (rideType < _rideTypeToObjectMap.size()) - { - auto& v = _rideTypeToObjectMap[rideType]; - v.push_back(static_cast(i)); - } - } + auto& v = _rideTypeToObjectMap[rideType]; + v.push_back(static_cast(i)); } } } @@ -718,13 +739,6 @@ std::unique_ptr CreateObjectManager(IObjectRepository& objectRep return std::make_unique(objectRepository); } -Object* object_manager_get_loaded_object_by_index(size_t index) -{ - auto& objectManager = OpenRCT2::GetContext()->GetObjectManager(); - Object* loadedObject = objectManager.GetLoadedObject(index); - return loadedObject; -} - Object* object_manager_get_loaded_object(const ObjectEntryDescriptor& entry) { auto& objectManager = OpenRCT2::GetContext()->GetObjectManager(); diff --git a/src/openrct2/object/ObjectManager.h b/src/openrct2/object/ObjectManager.h index d1a7c51798..8354cf1fa9 100644 --- a/src/openrct2/object/ObjectManager.h +++ b/src/openrct2/object/ObjectManager.h @@ -31,12 +31,19 @@ struct IObjectManager virtual ObjectEntryIndex GetLoadedObjectEntryIndex(std::string_view identifier) abstract; virtual ObjectEntryIndex GetLoadedObjectEntryIndex(const ObjectEntryDescriptor& descriptor) abstract; virtual ObjectEntryIndex GetLoadedObjectEntryIndex(const Object* object) abstract; +<<<<<<< HEAD virtual ObjectList GetLoadedObjects() abstract; +======= +>>>>>>> upstream/develop virtual Object* LoadObject(std::string_view identifier) abstract; virtual Object* LoadObject(const rct_object_entry* entry) abstract; virtual Object* LoadObject(const ObjectEntryDescriptor& descriptor) abstract; virtual void LoadObjects(const ObjectList& entries) abstract; +<<<<<<< HEAD +======= + virtual void LoadDefaultObjects() abstract; +>>>>>>> upstream/develop virtual void UnloadObjects(const std::vector& entries) abstract; virtual void UnloadAll() abstract; @@ -48,7 +55,6 @@ struct IObjectManager [[nodiscard]] std::unique_ptr CreateObjectManager(IObjectRepository& objectRepository); -[[nodiscard]] Object* object_manager_get_loaded_object_by_index(size_t index); [[nodiscard]] Object* object_manager_get_loaded_object(const ObjectEntryDescriptor& entry); [[nodiscard]] ObjectEntryIndex object_manager_get_loaded_object_entry_index(const Object* loadedObject); [[nodiscard]] ObjectEntryIndex object_manager_get_loaded_object_entry_index(const ObjectEntryDescriptor& entry); diff --git a/src/openrct2/object/ObjectRepository.cpp b/src/openrct2/object/ObjectRepository.cpp index 32bd4ecc06..3979bbf001 100644 --- a/src/openrct2/object/ObjectRepository.cpp +++ b/src/openrct2/object/ObjectRepository.cpp @@ -21,6 +21,7 @@ #include "../core/IStream.hpp" #include "../core/Memory.hpp" #include "../core/MemoryStream.h" +#include "../core/Numerics.hpp" #include "../core/Path.hpp" #include "../core/String.hpp" #include "../localisation/Localisation.h" @@ -273,18 +274,18 @@ public: } } - void RegisterLoadedObject(const ObjectRepositoryItem* ori, Object* object) override + void RegisterLoadedObject(const ObjectRepositoryItem* ori, std::unique_ptr&& object) override { ObjectRepositoryItem* item = &_items[ori->Id]; Guard::Assert(item->LoadedObject == nullptr, GUARD_LINE); - item->LoadedObject = object; + item->LoadedObject = std::move(object); } void UnregisterLoadedObject(const ObjectRepositoryItem* ori, Object* object) override { ObjectRepositoryItem* item = &_items[ori->Id]; - if (item->LoadedObject == object) + if (item->LoadedObject.get() == object) { item->LoadedObject = nullptr; } @@ -751,11 +752,11 @@ int32_t object_calculate_checksum(const rct_object_entry* entry, const void* dat uint32_t checksum = 0xF369A75B; checksum ^= entryBytePtr[0]; - checksum = rol32(checksum, 11); + checksum = Numerics::rol32(checksum, 11); for (int32_t i = 4; i < 12; i++) { checksum ^= entryBytePtr[i]; - checksum = rol32(checksum, 11); + checksum = Numerics::rol32(checksum, 11); } const uint8_t* dataBytes = reinterpret_cast(data); @@ -766,12 +767,12 @@ int32_t object_calculate_checksum(const rct_object_entry* entry, const void* dat { checksum ^= dataBytes[j]; } - checksum = rol32(checksum, 11); + checksum = Numerics::rol32(checksum, 11); } for (size_t i = dataLength32; i < dataLength; i++) { checksum ^= dataBytes[i]; - checksum = rol32(checksum, 11); + checksum = Numerics::rol32(checksum, 11); } return static_cast(checksum); diff --git a/src/openrct2/object/ObjectRepository.h b/src/openrct2/object/ObjectRepository.h index a62e43cf45..d77c8ec2b1 100644 --- a/src/openrct2/object/ObjectRepository.h +++ b/src/openrct2/object/ObjectRepository.h @@ -45,7 +45,7 @@ struct ObjectRepositoryItem std::string Name; std::vector Authors; std::vector Sources; - Object* LoadedObject{}; + std::shared_ptr LoadedObject{}; struct { uint8_t RideFlags; @@ -84,7 +84,7 @@ struct IObjectRepository [[nodiscard]] virtual const ObjectRepositoryItem* FindObject(const ObjectEntryDescriptor& oed) const abstract; [[nodiscard]] virtual std::unique_ptr LoadObject(const ObjectRepositoryItem* ori) abstract; - virtual void RegisterLoadedObject(const ObjectRepositoryItem* ori, Object* object) abstract; + virtual void RegisterLoadedObject(const ObjectRepositoryItem* ori, std::unique_ptr&& object) abstract; virtual void UnregisterLoadedObject(const ObjectRepositoryItem* ori, Object* object) abstract; virtual void AddObject(const rct_object_entry* objectEntry, const void* data, size_t dataSize) abstract; diff --git a/src/openrct2/object/SceneryGroupObject.cpp b/src/openrct2/object/SceneryGroupObject.cpp index 9fceac2048..8823c0958e 100644 --- a/src/openrct2/object/SceneryGroupObject.cpp +++ b/src/openrct2/object/SceneryGroupObject.cpp @@ -100,13 +100,13 @@ void SceneryGroupObject::UpdateEntryIndexes() if (ori->LoadedObject == nullptr) continue; - auto entryIndex = objectManager.GetLoadedObjectEntryIndex(ori->LoadedObject); + auto entryIndex = objectManager.GetLoadedObjectEntryIndex(ori->LoadedObject.get()); Guard::Assert(entryIndex != OBJECT_ENTRY_INDEX_NULL, GUARD_LINE); auto sceneryType = GetSceneryType(ori->Type); - if (sceneryType != std::nullopt) + if (sceneryType.has_value()) { - _legacyType.scenery_entries[_legacyType.entry_count] = { *sceneryType, entryIndex }; + _legacyType.scenery_entries[_legacyType.entry_count] = { sceneryType.value(), entryIndex }; _legacyType.entry_count++; } } diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index a27565383e..862a5a8b10 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -56,29 +56,39 @@ static void PaintPSImageWithBoundingBoxes(rct_drawpixelinfo* dpi, paint_struct* static void PaintPSImage(rct_drawpixelinfo* dpi, paint_struct* ps, uint32_t imageId, int32_t x, int32_t y); static uint32_t PaintPSColourifyImage(uint32_t imageId, ViewportInteractionItem spriteType, uint32_t viewFlags); -static constexpr int32_t CalculatePositionHash(const paint_struct& ps, uint8_t rotation) +static int32_t RemapPositionToQuadrant(const paint_struct& ps, uint8_t rotation) { - auto pos = CoordsXY{ ps.bounds.x, ps.bounds.y }.Rotate(rotation); - switch (rotation) + constexpr auto MapRangeMax = MaxPaintQuadrants * COORDS_XY_STEP; + constexpr auto MapRangeCenter = MapRangeMax / 2; + + const auto x = ps.bounds.x; + const auto y = ps.bounds.y; + // NOTE: We are not calling CoordsXY::Rotate on purpose to mix in the additional + // value without a secondary switch. + switch (rotation & 3) { case 0: - break; + return x + y; case 1: - case 3: - pos.x += 0x2000; - break; + // Because one component may be the maximum we add the center to be a positive value. + return (y - x) + MapRangeCenter; case 2: - pos.x += 0x4000; - break; + // If both components would be the maximum it would be the negative xy, to be positive add max. + return (-(y + x)) + MapRangeMax; + case 3: + // Same as 1 but inverted. + return (x - y) + MapRangeCenter; } - - return pos.x + pos.y; + return 0; } static void PaintSessionAddPSToQuadrant(paint_session* session, paint_struct* ps) { - auto positionHash = CalculatePositionHash(*ps, session->CurrentRotation); - uint32_t paintQuadrantIndex = std::clamp(positionHash / 32, 0, MAX_PAINT_QUADRANTS - 1); + const auto positionHash = RemapPositionToQuadrant(*ps, session->CurrentRotation); + + // Values below zero or above MaxPaintQuadrants are void, corners also share the same quadrant as void. + const uint32_t paintQuadrantIndex = std::clamp(positionHash / COORDS_XY_STEP, 0, MaxPaintQuadrants - 1); + ps->quadrant_index = paintQuadrantIndex; ps->next_quadrant_ps = session->Quadrants[paintQuadrantIndex]; session->Quadrants[paintQuadrantIndex] = ps; diff --git a/src/openrct2/paint/Paint.h b/src/openrct2/paint/Paint.h index bf1f72e38d..0117d4b2ad 100644 --- a/src/openrct2/paint/Paint.h +++ b/src/openrct2/paint/Paint.h @@ -14,6 +14,7 @@ #include "../drawing/Drawing.h" #include "../interface/Colour.h" #include "../world/Location.hpp" +#include "../world/Map.h" #include #include @@ -114,7 +115,10 @@ struct tunnel_entry uint8_t type; }; -#define MAX_PAINT_QUADRANTS 512 +// The maximum size must be MAXIMUM_MAP_SIZE_TECHNICAL multiplied by 2 because +// the quadrant index is based on the x and y components combined. +static constexpr int32_t MaxPaintQuadrants = MAXIMUM_MAP_SIZE_TECHNICAL * 2; + #define TUNNEL_MAX_COUNT 65 /** @@ -169,7 +173,7 @@ public: struct PaintSessionCore { - paint_struct* Quadrants[MAX_PAINT_QUADRANTS]; + paint_struct* Quadrants[MaxPaintQuadrants]; paint_struct* LastPS; paint_string_struct* PSStringHead; paint_string_struct* LastPSString; diff --git a/src/openrct2/paint/Supports.cpp b/src/openrct2/paint/Supports.cpp index 57f6b5c40a..c60a18ad63 100644 --- a/src/openrct2/paint/Supports.cpp +++ b/src/openrct2/paint/Supports.cpp @@ -1162,7 +1162,7 @@ bool metal_b_supports_paint_setup( * @param special (ax) * @param height (dx) * @param imageColourFlags (ebp) - * @param railingEntry (0x00F3EF6C) + * @param railingsDescriptor (0x00F3EF6C) * @param[out] underground (Carry Flag) * * @return Whether supports were drawn @@ -1315,7 +1315,7 @@ bool path_a_supports_paint_setup( * @param special (ax) * @param height (dx) * @param imageColourFlags (ebp) - * @param railingEntry (0x00F3EF6C) + * @param railingsDescriptor (0x00F3EF6C) * * @return Whether supports were drawn */ diff --git a/src/openrct2/paint/tile_element/Paint.Entrance.cpp b/src/openrct2/paint/tile_element/Paint.Entrance.cpp index 05aa6c6586..53f25d8b83 100644 --- a/src/openrct2/paint/tile_element/Paint.Entrance.cpp +++ b/src/openrct2/paint/tile_element/Paint.Entrance.cpp @@ -247,6 +247,14 @@ static void park_entrance_paint(paint_session* session, uint8_t direction, int32 // Index to which part of the entrance // Middle, left, right uint8_t part_index = tile_element.GetSequenceIndex(); + const PathSurfaceDescriptor* surfaceDescriptor = nullptr; + + // The left and right of the park entrance often have this set to 127. + // So only attempt to get the footpath type if we're dealing with the middle bit of the entrance. + if (part_index == 0) + { + surfaceDescriptor = tile_element.GetPathSurfaceDescriptor(); + } rct_entrance_type* entrance; uint8_t di = ((direction / 2 + part_index / 2) & 1) ? 0x1A : 0x20; @@ -254,23 +262,11 @@ static void park_entrance_paint(paint_session* session, uint8_t direction, int32 switch (part_index) { case 0: - { - auto footpathObj = tile_element.GetPathEntry(); - if (footpathObj != nullptr) + if (surfaceDescriptor != nullptr) { - auto footpathEntry = reinterpret_cast(footpathObj->GetLegacyData()); - image_id = (footpathEntry->image + 5 * (1 + (direction & 1))) | ghost_id; + image_id = (surfaceDescriptor->Image + 5 * (1 + (direction & 1))) | ghost_id; PaintAddImageAsParent(session, image_id, { 0, 0, height }, { 32, 0x1C, 0 }, { 0, 2, height }); } - else - { - auto footpathSurfaceObj = tile_element.GetSurfaceEntry(); - if (footpathSurfaceObj != nullptr) - { - image_id = (footpathSurfaceObj->BaseImageId + 5 * (1 + (direction & 1))) | ghost_id; - PaintAddImageAsParent(session, image_id, { 0, 0, height }, { 32, 0x1C, 0 }, { 0, 2, height }); - } - } entrance = static_cast(object_entry_get_chunk(ObjectType::ParkEntrance, 0)); if (entrance == nullptr) @@ -323,7 +319,6 @@ static void park_entrance_paint(paint_session* session, uint8_t direction, int32 PaintAddImageAsChild(session, stsetup, 0, 0, 0x1C, 0x1C, 0x2F, text_height, 2, 2, text_height); } break; - } case 1: case 2: entrance = static_cast(object_entry_get_chunk(ObjectType::ParkEntrance, 0)); diff --git a/src/openrct2/paint/tile_element/Paint.LargeScenery.cpp b/src/openrct2/paint/tile_element/Paint.LargeScenery.cpp index 5a332d641e..4e806ce90a 100644 --- a/src/openrct2/paint/tile_element/Paint.LargeScenery.cpp +++ b/src/openrct2/paint/tile_element/Paint.LargeScenery.cpp @@ -9,6 +9,7 @@ #include "../../Game.h" #include "../../config/Config.h" +#include "../../core/Numerics.hpp" #include "../../interface/Viewport.h" #include "../../localisation/Localisation.h" #include "../../object/LargeSceneryObject.h" @@ -278,7 +279,7 @@ void PaintLargeScenery(paint_session* session, uint8_t direction, uint16_t heigh if (edi & 0xF00) { edi &= 0xF000; - edi = rol16(edi, direction); + edi = Numerics::rol16(edi, direction); esi = (edi & 0xF) | (edi >> 12); } const CoordsXYZ bbOffset = { s98E3C4[esi].offset, height }; diff --git a/src/openrct2/paint/tile_element/Paint.Path.cpp b/src/openrct2/paint/tile_element/Paint.Path.cpp index a517bf00a5..1ea67cce27 100644 --- a/src/openrct2/paint/tile_element/Paint.Path.cpp +++ b/src/openrct2/paint/tile_element/Paint.Path.cpp @@ -10,6 +10,7 @@ #include "../../Context.h" #include "../../Game.h" #include "../../config/Config.h" +#include "../../core/Numerics.hpp" #include "../../drawing/LightFX.h" #include "../../interface/Viewport.h" #include "../../localisation/Localisation.h" @@ -179,7 +180,7 @@ static void path_bit_bins_paint( // Edges have been rotated around the rotation to check addition status // this will also need to be rotated. - binIsFull = !(pathElement.GetAdditionStatus() & ror8(0x3, (2 * session->CurrentRotation))); + binIsFull = !(pathElement.GetAdditionStatus() & Numerics::ror8(0x3, (2 * session->CurrentRotation))); if (binIsFull) imageId += 8; } @@ -200,7 +201,7 @@ static void path_bit_bins_paint( // Edges have been rotated around the rotation to check addition status // this will also need to be rotated. - binIsFull = !(pathElement.GetAdditionStatus() & ror8(0xC, (2 * session->CurrentRotation))); + binIsFull = !(pathElement.GetAdditionStatus() & Numerics::ror8(0xC, (2 * session->CurrentRotation))); if (binIsFull) imageId += 8; } @@ -222,7 +223,7 @@ static void path_bit_bins_paint( // Edges have been rotated around the rotation to check addition status // this will also need to be rotated. - binIsFull = !(pathElement.GetAdditionStatus() & ror8(0x30, (2 * session->CurrentRotation))); + binIsFull = !(pathElement.GetAdditionStatus() & Numerics::ror8(0x30, (2 * session->CurrentRotation))); if (binIsFull) imageId += 8; } @@ -244,7 +245,7 @@ static void path_bit_bins_paint( // Edges have been rotated around the rotation to check addition status // this will also need to be rotated. - binIsFull = !(pathElement.GetAdditionStatus() & ror8(0xC0, (2 * session->CurrentRotation))); + binIsFull = !(pathElement.GetAdditionStatus() & Numerics::ror8(0xC0, (2 * session->CurrentRotation))); if (binIsFull) imageId += 8; } @@ -669,7 +670,7 @@ static void sub_6A4101( * @param pathElement (esp[0]) * @param connectedEdges (bp) (relative to the camera's rotation) * @param height (dx) - * @param railingEntry (0x00F3EF6C) + * @param pathPaintInfo (0x00F3EF6C) * @param imageFlags (0x00F3EF70) * @param sceneryImageFlags (0x00F3EF74) */ @@ -808,46 +809,25 @@ static void sub_6A3F61( static FootpathPaintInfo GetFootpathPaintInfo(const PathElement& pathEl) { FootpathPaintInfo pathPaintInfo; - auto footpathObj = pathEl.GetPathEntry(); - if (footpathObj != nullptr) - { - auto footpathEntry = reinterpret_cast(footpathObj->GetLegacyData()); - if (pathEl.IsQueue()) - { - pathPaintInfo.SurfaceImageId = footpathEntry->GetQueueImage(); - pathPaintInfo.SurfaceFlags = footpathEntry->flags | FOOTPATH_ENTRY_FLAG_IS_QUEUE; - } - else - { - pathPaintInfo.SurfaceImageId = footpathEntry->image; - pathPaintInfo.SurfaceFlags = footpathEntry->flags; - } - pathPaintInfo.ScrollingMode = footpathEntry->scrolling_mode; - pathPaintInfo.SupportType = footpathEntry->support_type; - pathPaintInfo.BridgeImageId = footpathEntry->bridge_image; - pathPaintInfo.RailingFlags = footpathEntry->flags; - pathPaintInfo.RailingsImageId = footpathEntry->GetRailingsImage(); - } - else - { - auto footpathSurfaceObj = pathEl.GetSurfaceEntry(); - if (footpathSurfaceObj != nullptr) - { - pathPaintInfo.SurfaceImageId = footpathSurfaceObj->BaseImageId; - pathPaintInfo.SurfaceFlags = footpathSurfaceObj->Flags; - auto railingObj = pathEl.GetRailingEntry(); - if (railingObj != nullptr) - { - pathPaintInfo.BridgeImageId = railingObj->BridgeImageId; - pathPaintInfo.RailingsImageId = railingObj->RailingsImageId; - pathPaintInfo.RailingFlags = railingObj->Flags; - pathPaintInfo.ScrollingMode = railingObj->ScrollingMode; - pathPaintInfo.SupportType = railingObj->SupportType; - pathPaintInfo.SupportColour = railingObj->Colour; - } - } + const auto* surfaceDescriptor = pathEl.GetSurfaceDescriptor(); + if (surfaceDescriptor != nullptr) + { + pathPaintInfo.SurfaceImageId = surfaceDescriptor->Image; + pathPaintInfo.SurfaceFlags = surfaceDescriptor->Flags; } + + const auto* railingsDescriptor = pathEl.GetRailingsDescriptor(); + if (railingsDescriptor != nullptr) + { + pathPaintInfo.BridgeImageId = railingsDescriptor->BridgeImage; + pathPaintInfo.RailingsImageId = railingsDescriptor->RailingsImage; + pathPaintInfo.RailingFlags = railingsDescriptor->Flags; + pathPaintInfo.ScrollingMode = railingsDescriptor->ScrollingMode; + pathPaintInfo.SupportType = railingsDescriptor->SupportType; + pathPaintInfo.SupportColour = railingsDescriptor->SupportColour; + } + return pathPaintInfo; } diff --git a/src/openrct2/paint/tile_element/Paint.Surface.cpp b/src/openrct2/paint/tile_element/Paint.Surface.cpp index fb6f601787..ba9f146089 100644 --- a/src/openrct2/paint/tile_element/Paint.Surface.cpp +++ b/src/openrct2/paint/tile_element/Paint.Surface.cpp @@ -14,6 +14,7 @@ #include "../../OpenRCT2.h" #include "../../config/Config.h" #include "../../core/Guard.hpp" +#include "../../core/Numerics.hpp" #include "../../drawing/Drawing.h" #include "../../interface/Colour.h" #include "../../interface/Viewport.h" @@ -950,7 +951,7 @@ static std::pair surface_get_height_above_water( } else { - localSurfaceShape = ror4(surfaceShape ^ TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK, 2); + localSurfaceShape = Numerics::ror4(surfaceShape ^ TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK, 2); } } } @@ -1340,7 +1341,7 @@ void PaintSurface(paint_session* session, uint8_t direction, uint16_t height, co // Owned land boundary fences session->InteractionType = ViewportInteractionItem::ParkEntrance; - uint8_t rotatedFences = rol4(tileElement.GetParkFences(), rotation); + uint8_t rotatedFences = Numerics::rol4(tileElement.GetParkFences(), rotation); for (const auto& fenceData : _tileSurfaceBoundaries) { diff --git a/src/openrct2/paint/tile_element/Paint.TileElement.cpp b/src/openrct2/paint/tile_element/Paint.TileElement.cpp index ee5bb3ef58..4ddc9de714 100644 --- a/src/openrct2/paint/tile_element/Paint.TileElement.cpp +++ b/src/openrct2/paint/tile_element/Paint.TileElement.cpp @@ -12,6 +12,7 @@ #include "../../Game.h" #include "../../Input.h" #include "../../config/Config.h" +#include "../../core/Numerics.hpp" #include "../../drawing/Drawing.h" #include "../../interface/Viewport.h" #include "../../localisation/Localisation.h" @@ -418,7 +419,7 @@ void paint_util_set_segment_support_height(paint_session* session, int32_t segme uint16_t paint_util_rotate_segments(uint16_t segments, uint8_t rotation) { uint8_t temp = segments & 0xFF; - temp = rol8(temp, rotation * 2); + temp = Numerics::rol8(temp, rotation * 2); return (segments & 0xFF00) | temp; } diff --git a/src/openrct2/peep/Guest.cpp b/src/openrct2/peep/Guest.cpp index aee6754945..6190e585f7 100644 --- a/src/openrct2/peep/Guest.cpp +++ b/src/openrct2/peep/Guest.cpp @@ -13,6 +13,7 @@ #include "../audio/audio.h" #include "../config/Config.h" #include "../core/Guard.hpp" +#include "../core/Numerics.hpp" #include "../interface/Window_internal.h" #include "../localisation/Localisation.h" #include "../management/Finance.h" @@ -1822,7 +1823,8 @@ Ride* Guest::FindBestRideToGoOn() Ride* mostExcitingRide = nullptr; for (auto& ride : GetRideManager()) { - if (rideConsideration.size() > ride.id && rideConsideration[ride.id]) + const auto rideIndex = EnumValue(ride.id); + if (rideConsideration.size() > rideIndex && rideConsideration[rideIndex]) { if (!(ride.lifecycle_flags & RIDE_LIFECYCLE_QUEUE_FULL)) { @@ -1853,7 +1855,7 @@ std::bitset Guest::FindRidesToGoOn() { if (!HasRidden(&ride)) { - rideConsideration[ride.id] = true; + rideConsideration[EnumValue(ride.id)] = true; } } } @@ -1874,7 +1876,7 @@ std::bitset Guest::FindRidesToGoOn() for (auto* trackElement : TileElementsView(location)) { auto rideIndex = trackElement->GetRideIndex(); - rideConsideration[rideIndex] = true; + rideConsideration[EnumValue(rideIndex)] = true; } } } @@ -1884,7 +1886,7 @@ std::bitset Guest::FindRidesToGoOn() { if (ride.highest_drop_height > 66 || ride.excitement >= RIDE_RATING(8, 00)) { - rideConsideration[ride.id] = true; + rideConsideration[EnumValue(ride.id)] = true; } } } @@ -2454,7 +2456,7 @@ static void peep_choose_seat_from_car(Peep* peep, Ride* ride, Vehicle* vehicle) void Guest::GoToRideEntrance(Ride* ride) { TileCoordsXYZD tileLocation = ride_get_entrance_location(ride, CurrentRideStation); - if (tileLocation.isNull()) + if (tileLocation.IsNull()) { RemoveFromQueue(); return; @@ -3099,7 +3101,7 @@ template static void peep_head_for_nearest_ride(Guest* peep, bool co { if (predicate(ride)) { - rideConsideration[ride.id] = true; + rideConsideration[EnumValue(ride.id)] = true; } } } @@ -3127,18 +3129,18 @@ template static void peep_head_for_nearest_ride(Guest* peep, bool co if (!predicate(*ride)) continue; - rideConsideration[rideIndex] = true; + rideConsideration[EnumValue(ride->id)] = true; } } } } // Filter the considered rides - uint8_t potentialRides[MAX_RIDES]; + ride_id_t potentialRides[MAX_RIDES]; size_t numPotentialRides = 0; for (auto& ride : GetRideManager()) { - if (rideConsideration[ride.id]) + if (rideConsideration[EnumValue(ride.id)]) { if (!(ride.lifecycle_flags & RIDE_LIFECYCLE_QUEUE_FULL)) { @@ -3403,7 +3405,7 @@ void Guest::UpdateRideAtEntrance() if (DestinationTolerance != 0) { int16_t xy_distance; - if (auto loc = UpdateAction(xy_distance)) + if (auto loc = UpdateAction(xy_distance); loc.has_value()) { int16_t actionZ = z; if (xy_distance < 16) @@ -3411,7 +3413,7 @@ void Guest::UpdateRideAtEntrance() auto entrance = ride_get_entrance_location(ride, CurrentRideStation).ToCoordsXYZ(); actionZ = entrance.z + 2; } - MoveTo({ *loc, actionZ }); + MoveTo({ loc.value(), actionZ }); } else { @@ -3544,7 +3546,7 @@ static uint8_t peep_get_waypointed_seat_location( static void peep_update_ride_leave_entrance_waypoints(Peep* peep, Ride* ride) { TileCoordsXYZD entranceLocation = ride_get_entrance_location(ride, peep->CurrentRideStation); - Guard::Assert(!entranceLocation.isNull()); + Guard::Assert(!entranceLocation.IsNull()); uint8_t direction_entrance = entranceLocation.direction; CoordsXY waypoint = ride->stations[peep->CurrentRideStation].Start.ToTileCentre(); @@ -3592,7 +3594,7 @@ void Guest::UpdateRideAdvanceThroughEntrance() auto ride_entry = ride->GetRideEntry(); - if (auto loc = UpdateAction(xy_distance)) + if (auto loc = UpdateAction(xy_distance); loc.has_value()) { uint16_t distanceThreshold = 16; if (ride_entry != nullptr) @@ -3618,7 +3620,7 @@ void Guest::UpdateRideAdvanceThroughEntrance() actionZ += ride->GetRideTypeDescriptor().Heights.PlatformHeight; } - MoveTo({ *loc, actionZ }); + MoveTo({ loc.value(), actionZ }); return; } @@ -3626,7 +3628,7 @@ void Guest::UpdateRideAdvanceThroughEntrance() if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_NO_VEHICLES)) { auto entranceLocation = ride_get_entrance_location(ride, CurrentRideStation).ToCoordsXYZD(); - Guard::Assert(!entranceLocation.isNull()); + Guard::Assert(!entranceLocation.IsNull()); if (ride->type == RIDE_TYPE_MAZE) { @@ -3651,7 +3653,7 @@ void Guest::UpdateRideAdvanceThroughEntrance() ride->FormatNameTo(ft); if (gConfigNotifications.ride_warnings) { - News::AddItemToQueue(News::ItemType::Ride, STR_GUESTS_GETTING_STUCK_ON_RIDE, CurrentRide, ft); + News::AddItemToQueue(News::ItemType::Ride, STR_GUESTS_GETTING_STUCK_ON_RIDE, EnumValue(CurrentRide), ft); } } @@ -3738,7 +3740,7 @@ static void peep_go_to_ride_exit(Peep* peep, Ride* ride, int16_t x, int16_t y, i Guard::Assert(peep->CurrentRideStation < MAX_STATIONS); auto exit = ride_get_exit_location(ride, peep->CurrentRideStation); - Guard::Assert(!exit.isNull()); + Guard::Assert(!exit.IsNull()); x = exit.x; y = exit.y; x *= 32; @@ -3805,7 +3807,7 @@ void Guest::UpdateRideFreeVehicleEnterRide(Ride* ride) if (queueTime != ride->stations[CurrentRideStation].QueueTime) { ride->stations[CurrentRideStation].QueueTime = queueTime; - window_invalidate_by_number(WC_RIDE, CurrentRide); + window_invalidate_by_number(WC_RIDE, EnumValue(CurrentRide)); } if (PeepFlags & PEEP_FLAGS_TRACKING) @@ -3970,9 +3972,9 @@ void Guest::UpdateRideFreeVehicleCheck() void Guest::UpdateRideApproachVehicle() { - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } RideSubState = PeepRideSubState::EnterVehicle; @@ -4204,7 +4206,7 @@ void Guest::UpdateRideLeaveVehicle() } auto exitLocation = ride_get_exit_location(ride, CurrentRideStation).ToCoordsXYZD(); - Guard::Assert(!exitLocation.isNull()); + Guard::Assert(!exitLocation.IsNull()); auto waypointLoc = CoordsXYZ{ ride->stations[CurrentRideStation].Start.ToTileCentre(), exitLocation.z + ride->GetRideTypeDescriptor().Heights.PlatformHeight }; @@ -4302,9 +4304,9 @@ static void peep_update_ride_prepare_for_exit(Peep* peep) */ void Guest::UpdateRideApproachExit() { - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } @@ -4323,19 +4325,19 @@ void Guest::UpdateRideInExit() int16_t xy_distance; - if (auto loc = UpdateAction(xy_distance)) + if (auto loc = UpdateAction(xy_distance); loc.has_value()) { if (xy_distance >= 16) { int16_t actionZ = ride->stations[CurrentRideStation].GetBaseZ(); actionZ += ride->GetRideTypeDescriptor().Heights.PlatformHeight; - MoveTo({ *loc, actionZ }); + MoveTo({ loc.value(), actionZ }); return; } SwitchToSpecialSprite(0); - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); } if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) @@ -4362,7 +4364,7 @@ void Guest::UpdateRideApproachVehicleWaypoints() int16_t xy_distance; uint8_t waypoint = Var37 & 3; - if (auto loc = UpdateAction(xy_distance)) + if (auto loc = UpdateAction(xy_distance); loc.has_value()) { int16_t actionZ; // Motion simulators have steps this moves the peeps up the steps @@ -4386,7 +4388,7 @@ void Guest::UpdateRideApproachVehicleWaypoints() { actionZ = z; } - MoveTo({ *loc, actionZ }); + MoveTo({ loc.value(), actionZ }); return; } @@ -4440,7 +4442,7 @@ void Guest::UpdateRideApproachExitWaypoints() int16_t xy_distance; - if (auto loc = UpdateAction(xy_distance)) + if (auto loc = UpdateAction(xy_distance); loc.has_value()) { int16_t actionZ; if (ride->type == RIDE_TYPE_MOTION_SIMULATOR) @@ -4459,7 +4461,7 @@ void Guest::UpdateRideApproachExitWaypoints() { actionZ = z; } - MoveTo({ *loc, actionZ }); + MoveTo({ loc.value(), actionZ }); return; } @@ -4535,9 +4537,9 @@ void Guest::UpdateRideApproachSpiralSlide() if (ride == nullptr) return; - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } @@ -4668,9 +4670,9 @@ void Guest::UpdateRideOnSpiralSlide() } } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } @@ -4694,9 +4696,9 @@ void Guest::UpdateRideLeaveSpiralSlide() { // Iterates through the spiral slide waypoints until it reaches // waypoint 0. Then it readies to leave the ride by the entrance. - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } @@ -4767,9 +4769,9 @@ static constexpr const uint8_t _MazeCurrentDirectionToOpenHedge[][4] = { */ void Guest::UpdateRideMazePathfinding() { - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } @@ -4889,9 +4891,9 @@ void Guest::UpdateRideMazePathfinding() break; } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } } @@ -4904,11 +4906,11 @@ void Guest::UpdateRideLeaveExit() { auto ride = get_ride(CurrentRide); - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { if (ride != nullptr) { - MoveTo({ *loc, ride->stations[CurrentRideStation].GetBaseZ() }); + MoveTo({ loc.value(), ride->stations[CurrentRideStation].GetBaseZ() }); } return; } @@ -4953,9 +4955,9 @@ void Guest::UpdateRideLeaveExit() */ void Guest::UpdateRideShopApproach() { - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } @@ -5019,9 +5021,9 @@ void Guest::UpdateRideShopInteract() */ void Guest::UpdateRideShopLeave() { - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); if ((x & 0xFFE0) != NextLoc.x) return; @@ -5569,9 +5571,9 @@ void Guest::UpdateEnteringPark() } return; } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } SetState(PeepState::Falling); @@ -5600,9 +5602,9 @@ void Guest::UpdateLeavingPark() return; } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return; } @@ -5994,7 +5996,7 @@ bool Guest::UpdateWalkingFindBin() uint8_t bin_quantities = pathElement->GetAdditionStatus(); // Rotate the bin to the correct edge. Makes it easier for next calc. - bin_quantities = ror8(ror8(bin_quantities, chosen_edge), chosen_edge); + bin_quantities = Numerics::ror8(Numerics::ror8(bin_quantities, chosen_edge), chosen_edge); for (uint8_t free_edge = 4; free_edge != 0; free_edge--) { @@ -6005,7 +6007,7 @@ bool Guest::UpdateWalkingFindBin() break; } chosen_edge = (chosen_edge + 1) & 0x3; - bin_quantities = ror8(bin_quantities, 2); + bin_quantities = Numerics::ror8(bin_quantities, 2); if ((free_edge - 1) == 0) return 0; } @@ -6805,6 +6807,10 @@ void Guest::InsertNewThought(PeepThoughtType thought_type, ShopItem shopItem) InsertNewThought(thought_type, static_cast(shopItem)); } +void Guest::InsertNewThought(PeepThoughtType thought_type, ride_id_t rideId) +{ + InsertNewThought(thought_type, static_cast(rideId)); +} /** * * rct2: 0x699F5A diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 8a2f474810..91a3e633f7 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -1400,7 +1400,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) // Clear pathfinding history TileCoordsXYZD nullPos; - nullPos.setNull(); + nullPos.SetNull(); std::fill(std::begin(peep->PathfindHistory), std::end(peep->PathfindHistory), nullPos); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -1461,7 +1461,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) for (auto& entry : _peepPathFindHistory) { - entry.location.setNull(); + entry.location.SetNull(); entry.direction = INVALID_DIRECTION; } @@ -2095,8 +2095,8 @@ int32_t guest_path_finding(Guest* peep) if (!(adjustedEdges & (1 << chosenDirection))) continue; - ride_id_t rideIndex, pathSearchResult; - pathSearchResult = footpath_element_destination_in_direction(loc, pathElement, chosenDirection, &rideIndex); + ride_id_t rideIndex = RIDE_ID_NULL; + auto pathSearchResult = footpath_element_destination_in_direction(loc, pathElement, chosenDirection, &rideIndex); switch (pathSearchResult) { case PATH_SEARCH_DEAD_END: @@ -2185,7 +2185,7 @@ int32_t guest_path_finding(Guest* peep) for (StationIndex stationNum = 0; stationNum < MAX_STATIONS; ++stationNum) { // Skip if stationNum has no entrance (so presumably an exit only station) - if (ride_get_entrance_location(ride, stationNum).isNull()) + if (ride_get_entrance_location(ride, stationNum).IsNull()) continue; numEntranceStations++; @@ -2303,7 +2303,7 @@ void Peep::ResetPathfindGoal() } #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - PathfindGoal.setNull(); + PathfindGoal.SetNull(); PathfindGoal.direction = INVALID_DIRECTION; } diff --git a/src/openrct2/peep/Peep.cpp b/src/openrct2/peep/Peep.cpp index 34f498903d..69dd37e5e5 100644 --- a/src/openrct2/peep/Peep.cpp +++ b/src/openrct2/peep/Peep.cpp @@ -2296,7 +2296,7 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) } std::optional loc; - if (!(loc = UpdateAction())) + if (loc = UpdateAction(); !loc.has_value()) { pathing_result |= PATHING_DESTINATION_REACHED; uint8_t result = 0; @@ -2314,7 +2314,7 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) if (result != 0) return; - if (!(loc = UpdateAction())) + if (loc = UpdateAction(); !loc.has_value()) return; } diff --git a/src/openrct2/peep/Peep.h b/src/openrct2/peep/Peep.h index e14094921d..92b3639acd 100644 --- a/src/openrct2/peep/Peep.h +++ b/src/openrct2/peep/Peep.h @@ -774,6 +774,7 @@ public: void UpdateEasterEggInteractions(); void InsertNewThought(PeepThoughtType thought_type); void InsertNewThought(PeepThoughtType thought_type, ShopItem thought_arguments); + void InsertNewThought(PeepThoughtType thought_type, ride_id_t rideId); void InsertNewThought(PeepThoughtType thought_type, uint16_t thought_arguments); static Guest* Generate(const CoordsXYZ& coords); bool UpdateQueuePosition(PeepActionType previous_action); diff --git a/src/openrct2/peep/Staff.cpp b/src/openrct2/peep/Staff.cpp index 2831d4ff74..14f7cfa4b2 100644 --- a/src/openrct2/peep/Staff.cpp +++ b/src/openrct2/peep/Staff.cpp @@ -738,7 +738,7 @@ Direction Staff::MechanicDirectionSurface() const if (ride != nullptr && (State == PeepState::Answering || State == PeepState::HeadingToInspection) && (scenario_rand() & 1)) { auto location = ride_get_exit_location(ride, CurrentRideStation); - if (location.isNull()) + if (location.IsNull()) { location = ride_get_entrance_location(ride, CurrentRideStation); } @@ -819,12 +819,12 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat /* Find location of the exit for the target ride station * or if the ride has no exit, the entrance. */ TileCoordsXYZD location = ride_get_exit_location(ride, CurrentRideStation); - if (location.isNull()) + if (location.IsNull()) { location = ride_get_entrance_location(ride, CurrentRideStation); // If no entrance is present either. This is an incorrect state. - if (location.isNull()) + if (location.IsNull()) { return MechanicDirectionPathRand(pathDirections); } @@ -1176,10 +1176,10 @@ void Staff::UpdateMowing() while (true) { - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { int16_t checkZ = tile_element_height(*loc); - MoveTo({ *loc, checkZ }); + MoveTo({ loc.value(), checkZ }); return; } @@ -1374,10 +1374,10 @@ void Staff::UpdateSweeping() StaffLitterSwept++; WindowInvalidateFlags |= PEEP_INVALIDATE_STAFF_STATS; } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { int16_t actionZ = GetZOnSlope((*loc).x, (*loc).y); - MoveTo({ *loc, actionZ }); + MoveTo({ loc.value(), actionZ }); return; } @@ -1406,7 +1406,7 @@ void Staff::UpdateHeadingToInspect() return; } - if (ride_get_exit_location(ride, CurrentRideStation).isNull()) + if (ride_get_exit_location(ride, CurrentRideStation).IsNull()) { ride->lifecycle_flags &= ~RIDE_LIFECYCLE_DUE_INSPECTION; SetState(PeepState::Falling); @@ -1461,7 +1461,7 @@ void Staff::UpdateHeadingToInspect() if (pathingResult & PATHING_RIDE_ENTRANCE) { - if (!ride_get_exit_location(ride, exit_index).isNull()) + if (!ride_get_exit_location(ride, exit_index).IsNull()) { return; } @@ -1479,7 +1479,7 @@ void Staff::UpdateHeadingToInspect() } int16_t delta_y = abs(GetLocation().y - GetDestination().y); - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { int32_t newZ = ride->stations[CurrentRideStation].GetBaseZ(); @@ -1488,7 +1488,7 @@ void Staff::UpdateHeadingToInspect() newZ += ride->GetRideTypeDescriptor().Heights.PlatformHeight; } - MoveTo({ *loc, newZ }); + MoveTo({ loc.value(), newZ }); return; } @@ -1568,7 +1568,7 @@ void Staff::UpdateAnswering() if (pathingResult & PATHING_RIDE_ENTRANCE) { - if (!ride_get_exit_location(ride, exit_index).isNull()) + if (!ride_get_exit_location(ride, exit_index).IsNull()) { return; } @@ -1588,7 +1588,7 @@ void Staff::UpdateAnswering() } int16_t delta_y = abs(y - GetDestination().y); - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { int32_t newZ = ride->stations[CurrentRideStation].GetBaseZ(); @@ -1597,7 +1597,7 @@ void Staff::UpdateAnswering() newZ += ride->GetRideTypeDescriptor().Heights.PlatformHeight; } - MoveTo({ *loc, newZ }); + MoveTo({ loc.value(), newZ }); return; } @@ -2181,9 +2181,9 @@ bool Staff::UpdateFixingMoveToBrokenDownVehicle(bool firstRun, const Ride* ride) SetDestination(destination, 2); } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return false; } @@ -2301,7 +2301,7 @@ bool Staff::UpdateFixingMoveToStationEnd(bool firstRun, const Ride* ride) } auto stationPos = ride->stations[CurrentRideStation].GetStart(); - if (stationPos.isNull()) + if (stationPos.IsNull()) { return true; } @@ -2331,9 +2331,9 @@ bool Staff::UpdateFixingMoveToStationEnd(bool firstRun, const Ride* ride) SetDestination(stationPos, 2); } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return false; } @@ -2387,7 +2387,7 @@ bool Staff::UpdateFixingMoveToStationStart(bool firstRun, const Ride* ride) } auto stationPosition = ride->stations[CurrentRideStation].GetStart(); - if (stationPosition.isNull()) + if (stationPosition.IsNull()) { return true; } @@ -2437,9 +2437,9 @@ bool Staff::UpdateFixingMoveToStationStart(bool firstRun, const Ride* ride) SetDestination(destination, 2); } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return false; } @@ -2531,11 +2531,11 @@ bool Staff::UpdateFixingMoveToStationExit(bool firstRun, const Ride* ride) if (!firstRun) { auto stationPosition = ride_get_exit_location(ride, CurrentRideStation).ToCoordsXY(); - if (stationPosition.isNull()) + if (stationPosition.IsNull()) { stationPosition = ride_get_entrance_location(ride, CurrentRideStation).ToCoordsXY(); - if (stationPosition.isNull()) + if (stationPosition.IsNull()) { return true; } @@ -2550,9 +2550,9 @@ bool Staff::UpdateFixingMoveToStationExit(bool firstRun, const Ride* ride) SetDestination(stationPosition, 2); } - if (auto loc = UpdateAction()) + if (auto loc = UpdateAction(); loc.has_value()) { - MoveTo({ *loc, z }); + MoveTo({ loc.value(), z }); return false; } else @@ -2613,11 +2613,11 @@ bool Staff::UpdateFixingLeaveByEntranceExit(bool firstRun, const Ride* ride) if (!firstRun) { auto exitPosition = ride_get_exit_location(ride, CurrentRideStation).ToCoordsXY(); - if (exitPosition.isNull()) + if (exitPosition.IsNull()) { exitPosition = ride_get_entrance_location(ride, CurrentRideStation).ToCoordsXY(); - if (exitPosition.isNull()) + if (exitPosition.IsNull()) { SetState(PeepState::Falling); return false; @@ -2634,7 +2634,7 @@ bool Staff::UpdateFixingLeaveByEntranceExit(bool firstRun, const Ride* ride) } int16_t xy_distance; - if (auto loc = UpdateAction(xy_distance)) + if (auto loc = UpdateAction(xy_distance); loc.has_value()) { uint16_t stationHeight = ride->stations[CurrentRideStation].GetBaseZ(); @@ -2643,7 +2643,7 @@ bool Staff::UpdateFixingLeaveByEntranceExit(bool firstRun, const Ride* ride) stationHeight += ride->GetRideTypeDescriptor().Heights.PlatformHeight; } - MoveTo({ *loc, stationHeight }); + MoveTo({ loc.value(), stationHeight }); return false; } SetState(PeepState::Falling); diff --git a/src/openrct2/platform/Crash.cpp b/src/openrct2/platform/Crash.cpp index 2fc168765a..adc637b91d 100644 --- a/src/openrct2/platform/Crash.cpp +++ b/src/openrct2/platform/Crash.cpp @@ -85,9 +85,9 @@ static bool UploadMinidump(const std::map& files, in } auto assertMsg = Guard::GetLastAssertMessage(); - if (assertMsg) + if (assertMsg.has_value()) { - parameters[L"assert_failure"] = String::ToWideChar(*assertMsg); + parameters[L"assert_failure"] = String::ToWideChar(assertMsg.value()); } int timeout = 10000; diff --git a/src/openrct2/rct1/RCT1.h b/src/openrct2/rct1/RCT1.h index 1340345651..87faeba3cb 100644 --- a/src/openrct2/rct1/RCT1.h +++ b/src/openrct2/rct1/RCT1.h @@ -34,6 +34,98 @@ namespace RCT1 constexpr const uint32_t RCT1_NUM_TERRAIN_SURFACES = 16; constexpr const uint32_t RCT1_NUM_TERRAIN_EDGES = 15; + enum class RideType : uint8_t + { + WoodenRollerCoaster = 0, + StandUpSteelRollerCoaster, + SuspendedRollerCoaster, + InvertedRollerCoaster, + SteelMiniRollerCoaster, + MiniatureRailway, + Monorail, + SuspendedSingleRailRollerCoaster, + BoatHire, + WoodenCrazyRodentRollerCoaster, + SingleRailRollerCoaster, + CarRide, + LaunchedFreefall, + BobsledRollerCoaster, + ObservationTower, + SteelRollerCoaster, + WaterSlide, + MineTrainRollerCoaster, + Chairlift, + SteelCorkscrewRollerCoaster, + HedgeMaze, + SpiralSlide, + GoKarts, + LogFlume, + RiverRapids, + Dodgems, + SwingingShip, + SwingingInverterShip, + IceCreamStall, + ChipsStall, + DrinkStall, + CandyflossStall, + BurgerBar, + MerryGoRound, + BalloonStall, + InformationKiosk, + Toilets, + FerrisWheel, + MotionSimulator, + _3DCinema, + TopSpin, + SpaceRings, + ReverseFreefallRollerCoaster, + SouvenirStall, + VerticalRollerCoaster, + PizzaStall, + Twist, + HauntedHouse, + PopcornStall, + Circus, + GhostTrain, + SteelTwisterRollerCoaster, + WoodenTwisterRollerCoaster, + WoodenSideFrictionRollerCoaster, + SteelWildMouseRollerCoaster, + HotDogStall, + ExoticSeaFoodStall, + HatStall, + ToffeeAppleStall, + VirginiaReel, + RiverRide, + CycleMonorail, + FlyingRollerCoaster, + SuspendedMonorail, + _40, + WoodenReverseRollerCoaster, + HeartlineTwisterRollerCoaster, + MiniatureGolf, + _44, + RotoDrop, + FlyingSaucers, + CrookedHouse, + CycleRailway, + SuspendedLoopingRollerCoaster, + WaterCoaster, + AirPoweredVerticalCoaster, + InvertedWildMouseCoaster, + JetSkis, + TShirtStall, + RaftRide, + DoughnutShop, + Enterprise, + CoffeeShop, + FriedChickenStall, + LemonadeStall, + + Count, + Null = 255, + }; + #pragma pack(push, 1) struct Entrance { @@ -50,7 +142,7 @@ namespace RCT1 */ struct Ride { - uint8_t type; // 0x000 + RideType type; // 0x000 uint8_t vehicle_type; // 0x001 uint16_t lifecycle_flags; // 0x002 uint8_t operating_mode; // 0x004 @@ -720,7 +812,7 @@ namespace RCT1 */ struct TD4 { - uint8_t type; // 0x00 + RideType type; // 0x00 uint8_t vehicle_type; uint32_t flags; // 0x02 uint8_t mode; // 0x06 @@ -779,98 +871,6 @@ namespace RCT1 assert_struct_size(TD4AA, 0xC4); #pragma pack(pop) - enum - { - RCT1_RIDE_TYPE_NULL = 255, - RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER = 0, - RCT1_RIDE_TYPE_STAND_UP_STEEL_ROLLER_COASTER, - RCT1_RIDE_TYPE_SUSPENDED_ROLLER_COASTER, - RCT1_RIDE_TYPE_INVERTED_ROLLER_COASTER, - RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER, - RCT1_RIDE_TYPE_MINIATURE_RAILWAY, - RCT1_RIDE_TYPE_MONORAIL, - RCT1_RIDE_TYPE_SUSPENDED_SINGLE_RAIL_ROLLER_COASTER, - RCT1_RIDE_TYPE_BOAT_HIRE, - RCT1_RIDE_TYPE_WOODEN_CRAZY_RODENT_ROLLER_COASTER, - RCT1_RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER, - RCT1_RIDE_TYPE_CAR_RIDE, - RCT1_RIDE_TYPE_LAUNCHED_FREEFALL, - RCT1_RIDE_TYPE_BOBSLED_ROLLER_COASTER, - RCT1_RIDE_TYPE_OBSERVATION_TOWER, - RCT1_RIDE_TYPE_STEEL_ROLLER_COASTER, - RCT1_RIDE_TYPE_WATER_SLIDE, - RCT1_RIDE_TYPE_MINE_TRAIN_ROLLER_COASTER, - RCT1_RIDE_TYPE_CHAIRLIFT, - RCT1_RIDE_TYPE_STEEL_CORKSCREW_ROLLER_COASTER, - RCT1_RIDE_TYPE_HEDGE_MAZE, - RCT1_RIDE_TYPE_SPIRAL_SLIDE, - RCT1_RIDE_TYPE_GO_KARTS, - RCT1_RIDE_TYPE_LOG_FLUME, - RCT1_RIDE_TYPE_RIVER_RAPIDS, - RCT1_RIDE_TYPE_DODGEMS, - RCT1_RIDE_TYPE_SWINGING_SHIP, - RCT1_RIDE_TYPE_SWINGING_INVERTER_SHIP, - RCT1_RIDE_TYPE_ICE_CREAM_STALL, - RCT1_RIDE_TYPE_CHIPS_STALL, - RCT1_RIDE_TYPE_DRINK_STALL, - RCT1_RIDE_TYPE_CANDYFLOSS_STALL, - RCT1_RIDE_TYPE_BURGER_BAR, - RCT1_RIDE_TYPE_MERRY_GO_ROUND, - RCT1_RIDE_TYPE_BALLOON_STALL, - RCT1_RIDE_TYPE_INFORMATION_KIOSK, - RCT1_RIDE_TYPE_TOILETS, - RCT1_RIDE_TYPE_FERRIS_WHEEL, - RCT1_RIDE_TYPE_MOTION_SIMULATOR, - RCT1_RIDE_TYPE_3D_CINEMA, - RCT1_RIDE_TYPE_TOP_SPIN, - RCT1_RIDE_TYPE_SPACE_RINGS, - RCT1_RIDE_TYPE_REVERSE_FREEFALL_ROLLER_COASTER, - RCT1_RIDE_TYPE_SOUVENIR_STALL, - RCT1_RIDE_TYPE_VERTICAL_ROLLER_COASTER, - RCT1_RIDE_TYPE_PIZZA_STALL, - RCT1_RIDE_TYPE_TWIST, - RCT1_RIDE_TYPE_HAUNTED_HOUSE, - RCT1_RIDE_TYPE_POPCORN_STALL, - RCT1_RIDE_TYPE_CIRCUS, - RCT1_RIDE_TYPE_GHOST_TRAIN, - RCT1_RIDE_TYPE_STEEL_TWISTER_ROLLER_COASTER, - RCT1_RIDE_TYPE_WOODEN_TWISTER_ROLLER_COASTER, - RCT1_RIDE_TYPE_WOODEN_SIDE_FRICTION_ROLLER_COASTER, - RCT1_RIDE_TYPE_STEEL_WILD_MOUSE_ROLLER_COASTER, - RCT1_RIDE_TYPE_HOT_DOG_STALL, - RCT1_RIDE_TYPE_EXOTIC_SEA_FOOD_STALL, - RCT1_RIDE_TYPE_HAT_STALL, - RCT1_RIDE_TYPE_TOFFEE_APPLE_STALL, - RCT1_RIDE_TYPE_VIRGINIA_REEL, - RCT1_RIDE_TYPE_RIVER_RIDE, - RCT1_RIDE_TYPE_CYCLE_MONORAIL, - RCT1_RIDE_TYPE_FLYING_ROLLER_COASTER, - RCT1_RIDE_TYPE_SUSPENDED_MONORAIL, - RCT1_RIDE_TYPE_40, - RCT1_RIDE_TYPE_WOODEN_REVERSER_ROLLER_COASTER, - RCT1_RIDE_TYPE_HEARTLINE_TWISTER_ROLLER_COASTER, - RCT1_RIDE_TYPE_MINIATURE_GOLF, - RCT1_RIDE_TYPE_44, - RCT1_RIDE_TYPE_ROTO_DROP, - RCT1_RIDE_TYPE_FLYING_SAUCERS, - RCT1_RIDE_TYPE_CROOKED_HOUSE, - RCT1_RIDE_TYPE_CYCLE_RAILWAY, - RCT1_RIDE_TYPE_SUSPENDED_LOOPING_ROLLER_COASTER, - RCT1_RIDE_TYPE_WATER_COASTER, - RCT1_RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER, - RCT1_RIDE_TYPE_INVERTED_WILD_MOUSE_COASTER, - RCT1_RIDE_TYPE_JET_SKIS, - RCT1_RIDE_TYPE_T_SHIRT_STALL, - RCT1_RIDE_TYPE_RAFT_RIDE, - RCT1_RIDE_TYPE_DOUGHNUT_SHOP, - RCT1_RIDE_TYPE_ENTERPRISE, - RCT1_RIDE_TYPE_COFFEE_SHOP, - RCT1_RIDE_TYPE_FRIED_CHICKEN_STALL, - RCT1_RIDE_TYPE_LEMONADE_STALL, - - RCT1_RIDE_TYPE_COUNT - }; - enum { RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN = 0, diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 4dea0e59fa..a41285d82b 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -139,7 +139,7 @@ namespace RCT1 EntryList _footpathRailingsEntries; // Lookup tables for converting from RCT1 hard coded types to the new dynamic object entries - ObjectEntryIndex _rideTypeToRideEntryMap[RCT1_RIDE_TYPE_COUNT]{}; + ObjectEntryIndex _rideTypeToRideEntryMap[EnumValue(RideType::Count)]{}; ObjectEntryIndex _vehicleTypeToRideEntryMap[RCT1_VEHICLE_TYPE_COUNT]{}; ObjectEntryIndex _smallSceneryTypeToEntryMap[256]{}; ObjectEntryIndex _largeSceneryTypeToEntryMap[256]{}; @@ -154,7 +154,7 @@ namespace RCT1 // Research std::bitset _researchRideEntryUsed{}; - std::bitset _researchRideTypeUsed{}; + std::bitset _researchRideTypeUsed{}; // Scenario repository - used for determining scenario name IScenarioRepository* _scenarioRepository = GetScenarioRepository(); @@ -462,7 +462,7 @@ namespace RCT1 { size_t researchListCount; const ResearchItem* researchList = GetResearchList(&researchListCount); - std::bitset rideTypeInResearch = GetRideTypesPresentInResearchList( + std::bitset rideTypeInResearch = GetRideTypesPresentInResearchList( researchList, researchListCount); for (size_t i = 0; i < researchListCount; i++) { @@ -487,14 +487,14 @@ namespace RCT1 AddEntriesForSceneryTheme(researchItem->item); break; case RCT1_RESEARCH_TYPE_RIDE: - AddEntryForRideType(researchItem->item); + AddEntryForRideType(static_cast(researchItem->item)); break; case RCT1_RESEARCH_TYPE_VEHICLE: // For some bizarre reason, RCT1 research lists contain vehicles that aren't actually researched. // Extra bizarrely, this does not seem to apply to Loopy Landscapes saves/scenarios. if (rideTypeInResearch[researchItem->related_ride] || _gameVersion == FILE_VERSION_RCT1_LL) { - AddEntryForVehicleType(researchItem->related_ride, researchItem->item); + AddEntryForVehicleType(static_cast(researchItem->related_ride), researchItem->item); } break; } @@ -568,7 +568,7 @@ namespace RCT1 for (size_t i = 0; i < std::size(_s4.rides); i++) { auto ride = &_s4.rides[i]; - if (ride->type != RCT1_RIDE_TYPE_NULL) + if (ride->type != RideType::Null) { if (RCT1::RideTypeUsesVehicles(ride->type)) AddEntryForVehicleType(ride->type, ride->vehicle_type); @@ -638,23 +638,25 @@ namespace RCT1 _waterEntry.GetOrAddEntry(entryName); } - void AddEntryForRideType(uint8_t rideType) + void AddEntryForRideType(RideType rideType) { - assert(rideType < std::size(_rideTypeToRideEntryMap)); - if (_rideTypeToRideEntryMap[rideType] == OBJECT_ENTRY_INDEX_NULL) + Guard::Assert(EnumValue(rideType) < std::size(_rideTypeToRideEntryMap)); + + if (_rideTypeToRideEntryMap[EnumValue(rideType)] == OBJECT_ENTRY_INDEX_NULL) { auto entryName = RCT1::GetRideTypeObject(rideType); if (!entryName.empty()) { auto entryIndex = _rideEntries.GetOrAddEntry(entryName); - _rideTypeToRideEntryMap[rideType] = entryIndex; + _rideTypeToRideEntryMap[EnumValue(rideType)] = entryIndex; } } } - void AddEntryForVehicleType(uint8_t rideType, uint8_t vehicleType) + void AddEntryForVehicleType(RideType rideType, uint8_t vehicleType) { - assert(vehicleType < std::size(_vehicleTypeToRideEntryMap)); + Guard::Assert(EnumValue(rideType) < std::size(_rideTypeToRideEntryMap)); + if (_vehicleTypeToRideEntryMap[vehicleType] == OBJECT_ENTRY_INDEX_NULL) { auto entryName = RCT1::GetVehicleObject(vehicleType); @@ -663,7 +665,7 @@ namespace RCT1 auto entryIndex = _rideEntries.GetOrAddEntry(entryName); _vehicleTypeToRideEntryMap[vehicleType] = entryIndex; - if (rideType != RIDE_TYPE_NULL) + if (rideType != RideType::Null) AddEntryForRideType(rideType); } } @@ -808,9 +810,10 @@ namespace RCT1 { for (int32_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++) { - if (_s4.rides[i].type != RIDE_TYPE_NULL) + if (_s4.rides[i].type != RideType::Null) { - ImportRide(GetOrAllocateRide(i), &_s4.rides[i], i); + const auto rideId = static_cast(i); + ImportRide(GetOrAllocateRide(rideId), &_s4.rides[i], rideId); } } } @@ -821,7 +824,7 @@ namespace RCT1 dst->id = rideIndex; // This is a peculiarity of this exact version number, which only Heide-Park seems to use. - if (_s4.game_version == 110018 && src->type == RCT1_RIDE_TYPE_INVERTED_ROLLER_COASTER) + if (_s4.game_version == 110018 && src->type == RideType::InvertedRollerCoaster) { dst->type = RIDE_TYPE_COMPACT_INVERTED_COASTER; } @@ -836,7 +839,7 @@ namespace RCT1 } else { - dst->subtype = _rideTypeToRideEntryMap[src->type]; + dst->subtype = _rideTypeToRideEntryMap[EnumValue(src->type)]; } rct_ride_entry* rideEntry = get_ride_entry(dst->subtype); @@ -867,9 +870,9 @@ namespace RCT1 } // Station - if (src->overall_view.isNull()) + if (src->overall_view.IsNull()) { - dst->overall_view.setNull(); + dst->overall_view.SetNull(); } else { @@ -878,9 +881,9 @@ namespace RCT1 for (int32_t i = 0; i < RCT12_MAX_STATIONS_PER_RIDE; i++) { - if (src->station_starts[i].isNull()) + if (src->station_starts[i].IsNull()) { - dst->stations[i].Start.setNull(); + dst->stations[i].Start.SetNull(); } else { @@ -894,13 +897,13 @@ namespace RCT1 dst->stations[i].TrainAtStation = src->station_depart[i]; // Direction is fixed later. - if (src->entrance[i].isNull()) + if (src->entrance[i].IsNull()) ride_clear_entrance_location(dst, i); else ride_set_entrance_location( dst, i, { src->entrance[i].x, src->entrance[i].y, src->station_height[i] / 2, 0 }); - if (src->exit[i].isNull()) + if (src->exit[i].IsNull()) ride_clear_exit_location(dst, i); else ride_set_exit_location(dst, i, { src->exit[i].x, src->exit[i].y, src->station_height[i] / 2, 0 }); @@ -915,7 +918,7 @@ namespace RCT1 // All other values take 0 as their default. Since they're already memset to that, no need to do it again. for (int32_t i = RCT12_MAX_STATIONS_PER_RIDE; i < MAX_STATIONS; i++) { - dst->stations[i].Start.setNull(); + dst->stations[i].Start.SetNull(); dst->stations[i].TrainAtStation = RideStation::NO_TRAIN; ride_clear_entrance_location(dst, i); ride_clear_exit_location(dst, i); @@ -962,14 +965,14 @@ namespace RCT1 { // Original RCT had no music settings, take default style auto style = GetStyleFromMusicIdentifier(GetRideTypeDescriptor(dst->type).DefaultMusic); - if (style) + if (style.has_value()) { - dst->music = *style; + dst->music = style.value(); } // Only merry-go-round and dodgems had music and used // the same flag as synchronise stations for the option to enable it - if (src->type == RCT1_RIDE_TYPE_MERRY_GO_ROUND || src->type == RCT1_RIDE_TYPE_DODGEMS) + if (src->type == RideType::MerryGoRound || src->type == RideType::Dodgems) { if (src->depart_flags & RCT1_RIDE_DEPART_PLAY_MUSIC) { @@ -1045,9 +1048,9 @@ namespace RCT1 src->chairlift_bullwheel_z[i] / 2 }; } - if (src->cur_test_track_location.isNull()) + if (src->cur_test_track_location.IsNull()) { - dst->CurTestTrackLocation.setNull(); + dst->CurTestTrackLocation.SetNull(); } else { @@ -1101,11 +1104,11 @@ namespace RCT1 dst->track_colour[0].supports = RCT1::GetColour(src->track_support_colour); // Balloons were always blue in the original RCT. - if (src->type == RCT1_RIDE_TYPE_BALLOON_STALL) + if (src->type == RideType::BalloonStall) { dst->track_colour[0].main = COLOUR_LIGHT_BLUE; } - else if (src->type == RCT1_RIDE_TYPE_RIVER_RAPIDS) + else if (src->type == RideType::RiverRapids) { dst->track_colour[0].main = COLOUR_WHITE; } @@ -1494,7 +1497,24 @@ namespace RCT1 ObjectList GetRequiredObjects() { - ObjectList result; + AppendRequiredObjects(entries, objectType, entryList.GetEntries()); + } + + void AppendRequiredObjects( + std::vector& entries, ObjectType objectType, const std::vector& objectNames) + { + for (const auto objectName : objectNames) + { + rct_object_entry entry{}; + entry.flags = ((static_cast(ObjectSourceGame::RCT2) << 4) & 0xF0) | (EnumValue(objectType) & 0x0F); + entry.SetName(objectName); + entries.push_back(entry); + } + } + + std::vector GetRequiredObjects() + { + std::vector result; AppendRequiredObjects(result, ObjectType::Ride, _rideEntries); AppendRequiredObjects(result, ObjectType::SmallScenery, _smallSceneryEntries); AppendRequiredObjects(result, ObjectType::LargeScenery, _largeSceneryEntries); @@ -1517,11 +1537,6 @@ namespace RCT1 })); AppendRequiredObjects(result, ObjectType::ParkEntrance, std::vector({ "rct2.park_entrance.pkent1" })); AppendRequiredObjects(result, ObjectType::Water, _waterEntry); - AppendRequiredObjects(result, ObjectType::TerrainSurface, _terrainSurfaceEntries); - AppendRequiredObjects(result, ObjectType::TerrainEdge, _terrainEdgeEntries); - AppendRequiredObjects(result, ObjectType::FootpathSurface, _footpathSurfaceEntries); - AppendRequiredObjects(result, ObjectType::FootpathRailings, _footpathRailingsEntries); - RCT12AddDefaultObjects(result); return result; } @@ -1636,7 +1651,8 @@ namespace RCT1 dst2->SetIsBroken(false); dst2->SetIsBlockedByVehicle(false); - dst2->SetSurfaceEntryIndex(entryIndex); + dst2->SetLegacyPathEntryIndex(entryIndex); + dst2->SetShouldDrawPathOverSupports(true); if (RCT1::PathIsQueue(pathType)) { dst2->SetIsQueue(true); @@ -1648,7 +1664,7 @@ namespace RCT1 railingsType = src2->GetRCT1SupportType(); } auto railingsEntryIndex = _footpathRailingsTypeToEntryMap[railingsType]; - dst2->SetRailingEntryIndex(railingsEntryIndex); + dst2->SetRailingsEntryIndex(railingsEntryIndex); // Additions ObjectEntryIndex additionType = dst2->GetAddition(); @@ -1893,8 +1909,7 @@ namespace RCT1 } bool researched = true; - std::bitset rideTypeInResearch = GetRideTypesPresentInResearchList( - researchList, researchListCount); + auto rideTypeInResearch = GetRideTypesPresentInResearchList(researchList, researchListCount); std::vector vehiclesWithMissingRideTypes; for (size_t i = 0; i < researchListCount; i++) { @@ -1928,10 +1943,10 @@ namespace RCT1 } case RCT1_RESEARCH_TYPE_RIDE: { - uint8_t rct1RideType = researchItem.item; - _researchRideTypeUsed[rct1RideType] = true; + const auto rct1RideType = static_cast(researchItem.item); + _researchRideTypeUsed[EnumValue(rct1RideType)] = true; - auto ownRideEntryIndex = _rideTypeToRideEntryMap[rct1RideType]; + auto ownRideEntryIndex = _rideTypeToRideEntryMap[EnumValue(rct1RideType)]; Guard::Assert( ownRideEntryIndex != OBJECT_ENTRY_INDEX_NULL, "ownRideEntryIndex was OBJECT_ENTRY_INDEX_NULL"); @@ -1955,7 +1970,7 @@ namespace RCT1 } if (researchItem2.type == RCT1_RESEARCH_TYPE_VEHICLE - && researchItem2.related_ride == rct1RideType) + && static_cast(researchItem2.related_ride) == rct1RideType) { auto rideEntryIndex2 = _vehicleTypeToRideEntryMap[researchItem2.item]; bool isOwnType = (ownRideEntryIndex == rideEntryIndex2); @@ -2073,10 +2088,10 @@ namespace RCT1 } } - static std::bitset GetRideTypesPresentInResearchList( + static std::bitset GetRideTypesPresentInResearchList( const RCT1::ResearchItem* researchList, size_t researchListCount) { - std::bitset ret = {}; + std::bitset ret = {}; for (size_t i = 0; i < researchListCount; i++) { @@ -2140,9 +2155,16 @@ namespace RCT1 // Park rating gParkRating = _s4.park_rating; - for (size_t i = 0; i < 32; i++) + + auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); + park.ResetHistories(); + std::copy(std::begin(_s4.park_rating_history), std::end(_s4.park_rating_history), gParkRatingHistory); + for (size_t i = 0; i < std::size(_s4.guests_in_park_history); i++) { - gParkRatingHistory[i] = _s4.park_rating_history[i]; + if (_s4.guests_in_park_history[i] != RCT12ParkHistoryUndefined) + { + gGuestsInParkHistory[i] = _s4.guests_in_park_history[i] * RCT12GuestsInParkHistoryFactor; + } } // Awards @@ -2526,10 +2548,12 @@ namespace RCT1 { if (_s4.scenario_slot_index == SC_URBAN_PARK && _isScenario) { + const auto merryGoRoundId = static_cast(0); + // First, make the queuing peep exit for (auto peep : EntityList()) { - if (peep->State == PeepState::QueuingFront && peep->CurrentRide == 0) + if (peep->State == PeepState::QueuingFront && peep->CurrentRide == merryGoRoundId) { peep->RemoveFromQueue(); peep->SetState(PeepState::Falling); @@ -2538,7 +2562,7 @@ namespace RCT1 } // Now, swap the entrance and exit. - auto ride = get_ride(0); + auto ride = get_ride(merryGoRoundId); if (ride != nullptr) { auto entranceCoords = ride->stations[0].Exit; @@ -2634,7 +2658,7 @@ namespace RCT1 if (researchList[i].type == RCT1_RESEARCH_TYPE_RIDE) { - return RCT1::GetRideType(researchList[i].item, 0); + return RCT1::GetRideType(static_cast(researchList[i].item), 0); } } @@ -2710,13 +2734,13 @@ namespace RCT1 { auto* dst = CreateEntityAt<::Vehicle>(srcBase.sprite_index); auto* src = static_cast(&srcBase); - const auto* ride = get_ride(src->ride); + const auto* ride = get_ride(static_cast(src->ride)); if (ride == nullptr) return; uint8_t vehicleEntryIndex = RCT1::GetVehicleSubEntryIndex(src->vehicle_type); - dst->ride = src->ride; + dst->ride = static_cast(src->ride); dst->ride_subtype = RCTEntryIndexToOpenRCT2EntryIndex(ride->subtype); dst->vehicle_type = vehicleEntryIndex; @@ -2792,9 +2816,9 @@ namespace RCT1 dst->TrackSubposition = VehicleTrackSubposition{ src->TrackSubposition }; dst->TrackLocation = { src->track_x, src->track_y, src->track_z }; dst->current_station = src->current_station; - if (src->boat_location.isNull() || ride->mode != RideMode::BoatHire || statusSrc != ::Vehicle::Status::TravellingBoat) + if (src->boat_location.IsNull() || ride->mode != RideMode::BoatHire || statusSrc != ::Vehicle::Status::TravellingBoat) { - dst->BoatLocation.setNull(); + dst->BoatLocation.SetNull(); dst->SetTrackDirection(src->GetTrackDirection()); dst->SetTrackType(RCT1TrackTypeToOpenRCT2(src->GetTrackType(), ride->type)); } diff --git a/src/openrct2/rct1/T4Importer.cpp b/src/openrct2/rct1/T4Importer.cpp index be246fd497..a98a070842 100644 --- a/src/openrct2/rct1/T4Importer.cpp +++ b/src/openrct2/rct1/T4Importer.cpp @@ -122,15 +122,14 @@ namespace RCT1 td->track_support_colour[i] = RCT1::GetColour(td4.track_support_colour_v0); // Mazes were only hedges - switch (td4.type) + if (td4.type == RideType::HedgeMaze) { - case RCT1_RIDE_TYPE_HEDGE_MAZE: - td->track_support_colour[i] = MAZE_WALL_TYPE_HEDGE; - break; - case RCT1_RIDE_TYPE_RIVER_RAPIDS: - td->track_spine_colour[i] = COLOUR_WHITE; - td->track_rail_colour[i] = COLOUR_WHITE; - break; + td->track_support_colour[i] = MAZE_WALL_TYPE_HEDGE; + } + else if (td4.type == RideType::RiverRapids) + { + td->track_spine_colour[i] = COLOUR_WHITE; + td->track_rail_colour[i] = COLOUR_WHITE; } } td->flags2 = 0; @@ -150,7 +149,7 @@ namespace RCT1 // Convert RCT1 vehicle type to RCT2 vehicle type. Initialise with a string consisting of 8 spaces. std::string_view vehicleObject; - if (td4Base.type == RIDE_TYPE_MAZE) + if (td4Base.type == RideType::HedgeMaze) { vehicleObject = RCT1::GetRideTypeObject(td4Base.type); } diff --git a/src/openrct2/rct1/Tables.cpp b/src/openrct2/rct1/Tables.cpp index 5922210c9a..90912a38da 100644 --- a/src/openrct2/rct1/Tables.cpp +++ b/src/openrct2/rct1/Tables.cpp @@ -163,11 +163,11 @@ namespace RCT1 return terrainEdge < std::size(map) ? map[terrainEdge] : map[0]; } - uint8_t GetRideType(uint8_t rideType, uint8_t vehicleType) + uint8_t GetRideType(RideType rideType, uint8_t vehicleType) { - if (rideType == RCT1_RIDE_TYPE_STEEL_TWISTER_ROLLER_COASTER && vehicleType == RCT1_VEHICLE_TYPE_NON_LOOPING_STEEL_TWISTER_ROLLER_COASTER_TRAIN) + if (rideType == RideType::SteelTwisterRollerCoaster && vehicleType == RCT1_VEHICLE_TYPE_NON_LOOPING_STEEL_TWISTER_ROLLER_COASTER_TRAIN) return RIDE_TYPE_HYPER_TWISTER; - if (rideType == RCT1_RIDE_TYPE_STEEL_CORKSCREW_ROLLER_COASTER && vehicleType == RCT1_VEHICLE_TYPE_HYPERCOASTER_TRAIN) + if (rideType == RideType::SteelCorkscrewRollerCoaster && vehicleType == RCT1_VEHICLE_TYPE_HYPERCOASTER_TRAIN) return RIDE_TYPE_HYPERCOASTER; static uint8_t map[] = @@ -259,8 +259,10 @@ namespace RCT1 RIDE_TYPE_DRINK_STALL, // RCT1_RIDE_TYPE_LEMONADE_STALL }; - Guard::ArgumentInRange(rideType, 0, std::size(map), "Unsupported RCT1 ride type."); - return map[rideType]; + const auto index = EnumValue(rideType); + Guard::ArgumentInRange(index, 0, std::size(map), "Unsupported RCT1 ride type."); + + return map[index]; } VehicleColourSchemeCopyDescriptor GetColourSchemeCopyDescriptor(uint8_t vehicleType) @@ -362,33 +364,33 @@ namespace RCT1 return map[vehicleType]; } - bool RideTypeUsesVehicles(uint8_t rideType) + bool RideTypeUsesVehicles(RideType 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_CHIPS_STALL: - case RCT1_RIDE_TYPE_DRINK_STALL: - case RCT1_RIDE_TYPE_CANDYFLOSS_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_TOFFEE_APPLE_STALL: - 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: + case RideType::HedgeMaze: + case RideType::SpiralSlide: + case RideType::IceCreamStall: + case RideType::ChipsStall: + case RideType::DrinkStall: + case RideType::CandyflossStall: + case RideType::BurgerBar: + case RideType::BalloonStall: + case RideType::InformationKiosk: + case RideType::Toilets: + case RideType::SouvenirStall: + case RideType::PizzaStall: + case RideType::PopcornStall: + case RideType::HotDogStall: + case RideType::ExoticSeaFoodStall: + case RideType::HatStall: + case RideType::ToffeeAppleStall: + case RideType::_40: + case RideType::_44: + case RideType::TShirtStall: + case RideType::DoughnutShop: + case RideType::CoffeeShop: + case RideType::FriedChickenStall: + case RideType::LemonadeStall: return false; default: return true; @@ -684,7 +686,7 @@ namespace RCT1 return map[vehicleSubEntry]; } - std::string_view GetRideTypeObject(uint8_t rideType) + std::string_view GetRideTypeObject(RideType rideType) { static constexpr const char * map[] = { @@ -775,8 +777,10 @@ namespace RCT1 "rct2.ride.lemst", // RCT1_RIDE_TYPE_LEMONADE_STALL }; - Guard::ArgumentInRange(rideType, 0, std::size(map), "Unsupported RCT1 ride type."); - return map[rideType]; + const auto index = EnumValue(rideType); + Guard::ArgumentInRange(index, 0, std::size(map), "Unsupported RCT1 ride type."); + + return map[index]; } std::string_view GetVehicleObject(uint8_t vehicleType) @@ -1249,10 +1253,10 @@ namespace RCT1 "rct1aa.footpath_surface.queue_yellow", // RCT1_FOOTPATH_TYPE_QUEUE_YELLOW "rct1aa.footpath_surface.queue_green", // RCT1_FOOTPATH_TYPE_QUEUE_GREEN - "rct1.footpath_surface.tarmac", // RCT1_FOOTPATH_TYPE_TARMAC_GRAY - "rct1aa.footpath_surface.tarmac_red", // RCT1_FOOTPATH_TYPE_TARMAC_RED - "rct1aa.footpath_surface.tarmac_brown", // RCT1_FOOTPATH_TYPE_TARMAC_BROWN - "rct1aa.footpath_surface.tarmac_green", // RCT1_FOOTPATH_TYPE_TARMAC_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 "rct1.footpath_surface.dirt", // RCT1_FOOTPATH_TYPE_DIRT_RED "rct1aa.footpath_surface.ash", // RCT1_FOOTPATH_TYPE_DIRT_BLACK diff --git a/src/openrct2/rct1/Tables.h b/src/openrct2/rct1/Tables.h index 005fb7d73b..b9cdeac19a 100644 --- a/src/openrct2/rct1/Tables.h +++ b/src/openrct2/rct1/Tables.h @@ -21,17 +21,19 @@ namespace RCT1 int8_t colour1, colour2, colour3; }; + enum class RideType : uint8_t; + colour_t GetColour(colour_t colour); PeepSpriteType GetPeepSpriteType(uint8_t rct1SpriteType); - uint8_t GetRideType(uint8_t rideType, uint8_t vehicleType); + uint8_t GetRideType(RideType rideType, uint8_t vehicleType); VehicleColourSchemeCopyDescriptor GetColourSchemeCopyDescriptor(uint8_t vehicleType); - bool RideTypeUsesVehicles(uint8_t rideType); + bool RideTypeUsesVehicles(RideType rideType); bool PathIsQueue(uint8_t pathType); uint8_t NormalisePathAddition(uint8_t pathAdditionType); uint8_t GetVehicleSubEntryIndex(uint8_t vehicleSubEntry); - std::string_view GetRideTypeObject(uint8_t rideType); + std::string_view GetRideTypeObject(RideType rideType); std::string_view GetVehicleObject(uint8_t vehicleType); std::string_view GetSmallSceneryObject(uint8_t smallSceneryType); std::string_view GetLargeSceneryObject(uint8_t largeSceneryType); diff --git a/src/openrct2/rct12/RCT12.cpp b/src/openrct2/rct12/RCT12.cpp index 445f3444e1..b46939548d 100644 --- a/src/openrct2/rct12/RCT12.cpp +++ b/src/openrct2/rct12/RCT12.cpp @@ -1047,7 +1047,7 @@ ride_id_t RCT12RideIdToOpenRCT2RideId(const RCT12RideId rideId) if (rideId == RCT12_RIDE_ID_NULL) return RIDE_ID_NULL; - return rideId; + return static_cast(rideId); } RCT12RideId OpenRCT2RideIdToRCT12RideId(const ride_id_t rideId) @@ -1055,7 +1055,7 @@ RCT12RideId OpenRCT2RideIdToRCT12RideId(const ride_id_t rideId) if (rideId == RIDE_ID_NULL) return RCT12_RIDE_ID_NULL; - return rideId; + return static_cast(rideId); } static bool RCT12IsFormatChar(codepoint_t c) @@ -1411,7 +1411,7 @@ std::optional GetStyleFromMusicIdentifier(std::string_view identifier) { return std::distance(std::begin(_musicStyles), it); } - return {}; + return std::nullopt; } void SetDefaultRCT2TerrainObjects(ObjectList& objectList) diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 1a9d730b5d..c377e03556 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -92,6 +92,9 @@ constexpr const uint16_t RCT12VehicleTrackTypeMask = 0b1111111111111100; constexpr const uint8_t RCT12PeepThoughtItemNone = std::numeric_limits::max(); +constexpr const uint8_t RCT12GuestsInParkHistoryFactor = 20; +constexpr const uint8_t RCT12ParkHistoryUndefined = std::numeric_limits::max(); + enum class RCT12TrackDesignVersion : uint8_t { TD4, @@ -198,12 +201,12 @@ struct RCT12xy8 uint16_t xy; }; - bool isNull() const + bool IsNull() const { return xy == RCT12_XY8_UNDEFINED; } - void setNull() + void SetNull() { xy = RCT12_XY8_UNDEFINED; } @@ -968,7 +971,7 @@ template std::vector RCT12GetRidesBeenOn(T* srcPeep) { if (srcPeep->rides_been_on[i / 8] & (1 << (i % 8))) { - ridesBeenOn.push_back(i); + ridesBeenOn.push_back(static_cast(i)); } } return ridesBeenOn; diff --git a/src/openrct2/rct12/SawyerChunkReader.cpp b/src/openrct2/rct12/SawyerChunkReader.cpp index 3ce28fadff..dee3fbfa20 100644 --- a/src/openrct2/rct12/SawyerChunkReader.cpp +++ b/src/openrct2/rct12/SawyerChunkReader.cpp @@ -10,6 +10,7 @@ #include "SawyerChunkReader.h" #include "../core/IStream.hpp" +#include "../core/Numerics.hpp" // malloc is very slow for large allocations in MSVC debug builds as it allocates // memory on a special debug heap and then initialises all the memory to 0xCC. @@ -295,7 +296,7 @@ size_t SawyerChunkReader::DecodeChunkRotate(void* dst, size_t dstCapacity, const uint8_t code = 1; for (size_t i = 0; i < srcLength; i++) { - dst8[i] = ror8(src8[i], code); + dst8[i] = Numerics::ror8(src8[i], code); code = (code + 2) % 8; } return srcLength; diff --git a/src/openrct2/rct12/SawyerChunkWriter.cpp b/src/openrct2/rct12/SawyerChunkWriter.cpp index 83a7dc944c..938a1176b3 100644 --- a/src/openrct2/rct12/SawyerChunkWriter.cpp +++ b/src/openrct2/rct12/SawyerChunkWriter.cpp @@ -10,6 +10,7 @@ #include "SawyerChunkWriter.h" #include "../core/IStream.hpp" +#include "../core/Numerics.hpp" #include "../util/SawyerCoding.h" // Maximum buffer size to store compressed data, maximum of 16 MiB @@ -99,7 +100,7 @@ void SawyerChunkWriter::WriteChunkTrack(const void* src, size_t length) { uint8_t newByte = ((checksum & 0xFF) + data[i]) & 0xFF; checksum = (checksum & 0xFFFFFF00) + newByte; - checksum = rol32(checksum, 3); + checksum = Numerics::rol32(checksum, 3); } checksum -= 0x1D4C1; diff --git a/src/openrct2/rct12/SawyerEncoding.cpp b/src/openrct2/rct12/SawyerEncoding.cpp index 0172d68d5b..758b6cb226 100644 --- a/src/openrct2/rct12/SawyerEncoding.cpp +++ b/src/openrct2/rct12/SawyerEncoding.cpp @@ -10,6 +10,7 @@ #include "SawyerEncoding.h" #include "../core/IStream.hpp" +#include "../core/Numerics.hpp" #include "RCT12.h" #include @@ -80,7 +81,7 @@ namespace SawyerEncoding { uint8_t newByte = ((checksum & 0xFF) + *data) & 0xFF; checksum = (checksum & 0xFFFFFF00) + newByte; - checksum = rol32(checksum, 3); + checksum = Numerics::rol32(checksum, 3); } uint32_t fileChecksum = stream->ReadValue(); diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index 24e1346ff0..1cb8938991 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -837,7 +837,24 @@ struct rct_s6_data // packed objects // SC6[3] - rct_object_entry objects[RCT2_OBJECT_ENTRY_COUNT]; + union + { + rct_object_entry Objects[RCT2_OBJECT_ENTRY_COUNT]; + struct + { + rct_object_entry RideObjects[RCT12_MAX_RIDE_OBJECTS]; + rct_object_entry SceneryObjects[RCT2_MAX_SMALL_SCENERY_OBJECTS]; + rct_object_entry LargeSceneryObjects[RCT2_MAX_LARGE_SCENERY_OBJECTS]; + rct_object_entry WallSceneryObjects[RCT2_MAX_WALL_SCENERY_OBJECTS]; + rct_object_entry BannerObjects[RCT2_MAX_BANNER_OBJECTS]; + rct_object_entry PathObjects[RCT2_MAX_PATH_OBJECTS]; + rct_object_entry PathAdditionObjects[RCT2_MAX_PATH_ADDITION_OBJECTS]; + rct_object_entry SceneryGroupObjects[RCT2_MAX_SCENERY_GROUP_OBJECTS]; + rct_object_entry ParkEntranceObjects[RCT2_MAX_PARK_ENTRANCE_OBJECTS]; + rct_object_entry WaterObjects[RCT2_MAX_WATER_OBJECTS]; + rct_object_entry ScenarioTextObjects[RCT2_MAX_SCENARIO_TEXT_OBJECTS]; + }; + }; // SC6[4] uint16_t elapsed_months; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 9728faa3a3..7a963d6b48 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -18,6 +18,7 @@ #include "../core/Console.hpp" #include "../core/FileStream.h" #include "../core/IStream.hpp" +#include "../core/Numerics.hpp" #include "../core/Path.hpp" #include "../core/Random.hpp" #include "../core/String.hpp" @@ -71,6 +72,8 @@ #include +#define DECRYPT_MONEY(money) (static_cast(Numerics::rol32((money) ^ 0xF4EC9621, 13))) + /** * Class to import RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6). */ @@ -173,9 +176,10 @@ public: _isSV7 = _stricmp(extension, ".sv7") == 0; } + chunkReader.ReadChunk(&_s6.Objects, sizeof(_s6.Objects)); + if (isScenario) { - chunkReader.ReadChunk(&_s6.objects, sizeof(_s6.objects)); chunkReader.ReadChunk(&_s6.elapsed_months, 16); chunkReader.ReadChunk(&_s6.tile_elements, sizeof(_s6.tile_elements)); chunkReader.ReadChunk(&_s6.next_free_tile_element_pointer_index, 2560076); @@ -189,7 +193,6 @@ public: } else { - chunkReader.ReadChunk(&_s6.objects, sizeof(_s6.objects)); chunkReader.ReadChunk(&_s6.elapsed_months, 16); chunkReader.ReadChunk(&_s6.tile_elements, sizeof(_s6.tile_elements)); chunkReader.ReadChunk(&_s6.next_free_tile_element_pointer_index, 3048816); @@ -270,14 +273,14 @@ public: gParkRating = _s6.park_rating; - std::memcpy(gParkRatingHistory, _s6.park_rating_history, sizeof(_s6.park_rating_history)); - - std::fill(std::begin(gGuestsInParkHistory), std::end(gGuestsInParkHistory), std::numeric_limits::max()); + auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); + park.ResetHistories(); + std::copy(std::begin(_s6.park_rating_history), std::end(_s6.park_rating_history), gParkRatingHistory); for (size_t i = 0; i < std::size(_s6.guests_in_park_history); i++) { - if (_s6.guests_in_park_history[i] != std::numeric_limits::max()) + if (_s6.guests_in_park_history[i] != RCT12ParkHistoryUndefined) { - gGuestsInParkHistory[i] = _s6.guests_in_park_history[i] * 20; + gGuestsInParkHistory[i] = _s6.guests_in_park_history[i] * RCT12GuestsInParkHistoryFactor; } } @@ -468,7 +471,6 @@ public: map_count_remaining_land_rights(); determine_ride_entrance_and_exit_locations(); - auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); park.Name = GetUserString(_s6.park_name); FixLandOwnership(); @@ -530,8 +532,9 @@ public: auto src = &_s6.rides[index]; if (src->type != RIDE_TYPE_NULL) { - auto dst = GetOrAllocateRide(index); - ImportRide(dst, src, index); + const auto rideId = static_cast(index); + auto dst = GetOrAllocateRide(rideId); + ImportRide(dst, src, rideId); } } } @@ -582,9 +585,9 @@ public: dst->default_name_number = src->name_arguments_number; } - if (src->overall_view.isNull()) + if (src->overall_view.IsNull()) { - dst->overall_view.setNull(); + dst->overall_view.SetNull(); } else { @@ -594,9 +597,9 @@ public: for (int32_t i = 0; i < RCT12_MAX_STATIONS_PER_RIDE; i++) { - if (src->station_starts[i].isNull()) + if (src->station_starts[i].IsNull()) { - dst->stations[i].Start.setNull(); + dst->stations[i].Start.SetNull(); } else { @@ -609,12 +612,12 @@ public: dst->stations[i].TrainAtStation = src->train_at_station[i]; // Direction is fixed later. - if (src->entrances[i].isNull()) + if (src->entrances[i].IsNull()) ride_clear_entrance_location(dst, i); else ride_set_entrance_location(dst, i, { src->entrances[i].x, src->entrances[i].y, src->station_heights[i], 0 }); - if (src->exits[i].isNull()) + if (src->exits[i].IsNull()) ride_clear_exit_location(dst, i); else ride_set_exit_location(dst, i, { src->exits[i].x, src->exits[i].y, src->station_heights[i], 0 }); @@ -631,7 +634,7 @@ public: // All other values take 0 as their default. Since they're already memset to that, no need to do it again. for (int32_t i = RCT12_MAX_STATIONS_PER_RIDE; i < MAX_STATIONS; i++) { - dst->stations[i].Start.setNull(); + dst->stations[i].Start.SetNull(); dst->stations[i].TrainAtStation = RideStation::NO_TRAIN; ride_clear_entrance_location(dst, i); ride_clear_exit_location(dst, i); @@ -683,9 +686,9 @@ public: // pad_106[0x2]; dst->testing_flags = src->testing_flags; - if (src->cur_test_track_location.isNull()) + if (src->cur_test_track_location.IsNull()) { - dst->CurTestTrackLocation.setNull(); + dst->CurTestTrackLocation.SetNull(); } else { @@ -873,7 +876,8 @@ public: { if (src.ride_index != RCT12_RIDE_ID_NULL) { - auto ride = get_ride(src.ride_index); + const auto rideId = static_cast(src.ride_index); + auto ride = get_ride(rideId); if (ride != nullptr) { ride->measurement = std::make_unique(); @@ -1010,7 +1014,7 @@ public: { if (sprite.unknown.sprite_identifier == RCT12SpriteIdentifier::Peep) { - if (sprite.peep.current_ride == rideIndex + if (sprite.peep.current_ride == static_cast(rideIndex) && (static_cast(sprite.peep.state) == PeepState::OnRide || static_cast(sprite.peep.state) == PeepState::EnteringRide)) { @@ -1136,13 +1140,13 @@ public: if (surfaceEntry == OBJECT_ENTRY_INDEX_NULL) { // Legacy footpath object - dst2->SetPathEntryIndex(pathEntryIndex); + dst2->SetLegacyPathEntryIndex(pathEntryIndex); } else { // Surface / railing dst2->SetSurfaceEntryIndex(surfaceEntry); - dst2->SetRailingEntryIndex(_pathToRailingMap[pathEntryIndex]); + dst2->SetRailingsEntryIndex(_pathToRailingMap[pathEntryIndex]); } dst2->SetQueueBannerDirection(src2->GetQueueBannerDirection()); @@ -1242,7 +1246,7 @@ public: if (surfaceEntry == OBJECT_ENTRY_INDEX_NULL) { // Legacy footpath object - dst2->SetPathEntryIndex(pathEntryIndex); + dst2->SetLegacyPathEntryIndex(pathEntryIndex); } else { @@ -1440,7 +1444,7 @@ public: dst->PeepFlags = src->peep_flags; if (isNullLocation(src->pathfind_goal)) { - dst->PathfindGoal.setNull(); + dst->PathfindGoal.SetNull(); dst->PathfindGoal.direction = INVALID_DIRECTION; } else @@ -1452,7 +1456,7 @@ public: { if (isNullLocation(src->pathfind_history[i])) { - dst->PathfindHistory[i].setNull(); + dst->PathfindHistory[i].SetNull(); dst->PathfindHistory[i].direction = INVALID_DIRECTION; } else @@ -1556,6 +1560,7 @@ public: return justText.data(); } +<<<<<<< HEAD ObjectList GetRequiredObjects() { std::fill(std::begin(_pathToSurfaceMap), std::end(_pathToSurfaceMap), OBJECT_ENTRY_INDEX_NULL); @@ -1651,6 +1656,59 @@ public: } } return area; +======= + template + static void AddRequiredObjects(std::vector& required, const T& list) + { + rct_object_entry nullEntry = {}; + std::memset(&nullEntry, 0xFF, sizeof(nullEntry)); + + for (const auto& entry : list) + { + required.push_back(entry); + } + + // NOTE: The segment of this object type needs to be filled to the internal limit + // the object manager currently expects this. + for (size_t i = std::size(list); i < TInternalLimit; i++) + { + required.push_back(nullEntry); + } + } + + ObjectList GetRequiredObjects() + { + std::vector result; + + AddRequiredObjects(result, _s6.RideObjects); + AddRequiredObjects(result, _s6.SceneryObjects); + AddRequiredObjects(result, _s6.LargeSceneryObjects); + AddRequiredObjects(result, _s6.WallSceneryObjects); + AddRequiredObjects(result, _s6.BannerObjects); + AddRequiredObjects(result, _s6.PathObjects); + AddRequiredObjects(result, _s6.PathAdditionObjects); + AddRequiredObjects(result, _s6.SceneryGroupObjects); + AddRequiredObjects(result, _s6.ParkEntranceObjects); + AddRequiredObjects(result, _s6.WaterObjects); + AddRequiredObjects(result, _s6.ScenarioTextObjects); + + ObjectList objectList; + for (size_t i = 0; i < result.size(); i++) + { + ObjectType objectType; + ObjectEntryIndex entryIndex; + get_type_entry_index(i, &objectType, &entryIndex); + + auto desc = ObjectEntryDescriptor(result[i]); + if (desc.HasValue()) + { + assert(desc.GetType() == objectType); + objectList.SetObject(entryIndex, desc); + } + } + + return objectList; +>>>>>>> upstream/develop } }; @@ -1667,15 +1725,15 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc dst->remaining_distance = src->remaining_distance; dst->velocity = src->velocity; dst->acceleration = src->acceleration; - dst->ride = src->ride; + dst->ride = static_cast(src->ride); dst->vehicle_type = src->vehicle_type; dst->colours = src->colours; dst->track_progress = src->track_progress; dst->TrackLocation = { src->track_x, src->track_y, src->track_z }; - if (src->boat_location.isNull() || static_cast(ride.mode) != RideMode::BoatHire + if (src->boat_location.IsNull() || static_cast(ride.mode) != RideMode::BoatHire || src->status != static_cast(Vehicle::Status::TravellingBoat)) { - dst->BoatLocation.setNull(); + dst->BoatLocation.SetNull(); dst->SetTrackDirection(src->GetTrackDirection()); dst->SetTrackType(src->GetTrackType()); // RotationControlToggle and Booster are saved as the same track piece ID diff --git a/src/openrct2/rct2/SeaDecrypt.cpp b/src/openrct2/rct2/SeaDecrypt.cpp index 0d7e1bb837..5ca8c7f4de 100644 --- a/src/openrct2/rct2/SeaDecrypt.cpp +++ b/src/openrct2/rct2/SeaDecrypt.cpp @@ -9,6 +9,7 @@ #include "../common.h" #include "../core/File.h" +#include "../core/Numerics.hpp" #include "../core/Path.hpp" #include "RCT2.h" @@ -53,8 +54,8 @@ static std::vector CreateMask(const EncryptionKey& key) { uint32_t s0 = seed0; uint32_t s1 = seed1 ^ 0xF7654321; - seed0 = rol32(s1, 25) + s0; - seed1 = rol32(s0, 29); + seed0 = Numerics::rol32(s1, 25) + s0; + seed1 = Numerics::rol32(s0, 29); result[i + 0] = (s0 >> 3) & 0xFF; result[i + 1] = (s0 >> 11) & 0xFF; result[i + 2] = (s0 >> 19) & 0xFF; diff --git a/src/openrct2/ride/CableLift.cpp b/src/openrct2/ride/CableLift.cpp index 92d9bc43a2..a42310440b 100644 --- a/src/openrct2/ride/CableLift.cpp +++ b/src/openrct2/ride/CableLift.cpp @@ -77,7 +77,7 @@ Vehicle* cable_lift_segment_create( current->SetState(Vehicle::Status::MovingToEndOfStation, 0); current->num_peeps = 0; current->next_free_seat = 0; - current->BoatLocation.setNull(); + current->BoatLocation.SetNull(); current->IsCrashedVehicle = false; return current; } diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 508d2a739f..1df711ad11 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -24,6 +24,7 @@ #include "../config/Config.h" #include "../core/FixedVector.h" #include "../core/Guard.hpp" +#include "../core/Numerics.hpp" #include "../interface/Window.h" #include "../localisation/Date.h" #include "../localisation/Localisation.h" @@ -147,21 +148,23 @@ ride_id_t GetNextFreeRideId() Ride* GetOrAllocateRide(ride_id_t index) { - if (_rides.size() <= index) + const auto idx = static_cast(index); + if (_rides.size() <= idx) { - _rides.resize(index + 1); + _rides.resize(idx + 1); } - auto result = &_rides[index]; + auto result = &_rides[idx]; result->id = index; return result; } Ride* get_ride(ride_id_t index) { - if (index < _rides.size()) + const auto idx = static_cast(index); + if (idx < _rides.size()) { - auto& ride = _rides[index]; + auto& ride = _rides[idx]; if (ride.type != RIDE_TYPE_NULL) { assert(ride.id == index); @@ -251,7 +254,7 @@ int32_t Ride::GetTotalQueueLength() const { int32_t i, queueLength = 0; for (i = 0; i < MAX_STATIONS; i++) - if (!ride_get_entrance_location(this, i).isNull()) + if (!ride_get_entrance_location(this, i).IsNull()) queueLength += stations[i].QueueLength; return queueLength; } @@ -260,7 +263,7 @@ int32_t Ride::GetMaxQueueTime() const { uint8_t i, queueTime = 0; for (i = 0; i < MAX_STATIONS; i++) - if (!ride_get_entrance_location(this, i).isNull()) + if (!ride_get_entrance_location(this, i).IsNull()) queueTime = std::max(queueTime, stations[i].QueueTime); return static_cast(queueTime); } @@ -1170,7 +1173,7 @@ void Ride::UpdateSpiralSlide() // Invalidate something related to station start for (int32_t i = 0; i < MAX_STATIONS; i++) { - if (stations[i].Start.isNull()) + if (stations[i].Start.IsNull()) continue; auto startLoc = stations[i].Start; @@ -1508,7 +1511,7 @@ void ride_breakdown_add_news_item(Ride* ride) { Formatter ft; ride->FormatNameTo(ft); - News::AddItemToQueue(News::ItemType::Ride, STR_RIDE_IS_BROKEN_DOWN, ride->id, ft); + News::AddItemToQueue(News::ItemType::Ride, STR_RIDE_IS_BROKEN_DOWN, EnumValue(ride->id), ft); } } @@ -1535,7 +1538,7 @@ static void ride_breakdown_status_update(Ride* ride) { Formatter ft; ride->FormatNameTo(ft); - News::AddItemToQueue(News::ItemType::Ride, STR_RIDE_IS_STILL_NOT_FIXED, ride->id, ft); + News::AddItemToQueue(News::ItemType::Ride, STR_RIDE_IS_STILL_NOT_FIXED, EnumValue(ride->id), ft); } } } @@ -1652,10 +1655,10 @@ Staff* ride_find_closest_mechanic(Ride* ride, int32_t forInspection) // Get either exit position or entrance position if there is no exit auto stationIndex = ride->inspection_station; TileCoordsXYZD location = ride_get_exit_location(ride, stationIndex); - if (location.isNull()) + if (location.IsNull()) { location = ride_get_entrance_location(ride, stationIndex); - if (location.isNull()) + if (location.IsNull()) return nullptr; } @@ -2160,7 +2163,7 @@ void ride_check_all_reachable() */ static bool ride_entrance_exit_is_reachable(const TileCoordsXYZD& coordinates) { - if (coordinates.isNull()) + if (coordinates.IsNull()) return true; TileCoordsXYZ loc{ coordinates.x, coordinates.y, coordinates.z }; @@ -2177,28 +2180,28 @@ static void ride_entrance_exit_connected(Ride* ride) auto entrance = ride_get_entrance_location(ride, i); auto exit = ride_get_exit_location(ride, i); - if (station_start.isNull()) + if (station_start.IsNull()) continue; - if (!entrance.isNull() && !ride_entrance_exit_is_reachable(entrance)) + if (!entrance.IsNull() && !ride_entrance_exit_is_reachable(entrance)) { // name of ride is parameter of the format string Formatter ft; ride->FormatNameTo(ft); if (gConfigNotifications.ride_warnings) { - News::AddItemToQueue(News::ItemType::Ride, STR_ENTRANCE_NOT_CONNECTED, ride->id, ft); + News::AddItemToQueue(News::ItemType::Ride, STR_ENTRANCE_NOT_CONNECTED, EnumValue(ride->id), ft); } ride->connected_message_throttle = 3; } - if (!exit.isNull() && !ride_entrance_exit_is_reachable(exit)) + if (!exit.IsNull() && !ride_entrance_exit_is_reachable(exit)) { // name of ride is parameter of the format string Formatter ft; ride->FormatNameTo(ft); if (gConfigNotifications.ride_warnings) { - News::AddItemToQueue(News::ItemType::Ride, STR_EXIT_NOT_CONNECTED, ride->id, ft); + News::AddItemToQueue(News::ItemType::Ride, STR_EXIT_NOT_CONNECTED, EnumValue(ride->id), ft); } ride->connected_message_throttle = 3; } @@ -2208,7 +2211,7 @@ static void ride_entrance_exit_connected(Ride* ride) static void ride_shop_connected(Ride* ride) { auto shopLoc = TileCoordsXY(ride->stations[0].Start); - if (shopLoc.isNull()) + if (shopLoc.IsNull()) return; TrackElement* trackElement = nullptr; @@ -2237,7 +2240,7 @@ static void ride_shop_connected(Ride* ride) const auto& ted = GetTrackElementDescriptor(track_type); uint8_t entrance_directions = ted.SequenceProperties[0] & 0xF; uint8_t tile_direction = trackElement->GetDirection(); - entrance_directions = rol4(entrance_directions, tile_direction); + entrance_directions = Numerics::rol4(entrance_directions, tile_direction); // Now each bit in entrance_directions stands for an entrance direction to check if (entrance_directions == 0) @@ -2267,7 +2270,7 @@ static void ride_shop_connected(Ride* ride) { Formatter ft; ride->FormatNameTo(ft); - News::AddItemToQueue(News::ItemType::Ride, STR_ENTRANCE_NOT_CONNECTED, ride->id, ft); + News::AddItemToQueue(News::ItemType::Ride, STR_ENTRANCE_NOT_CONNECTED, EnumValue(ride->id), ft); } ride->connected_message_throttle = 3; @@ -2317,7 +2320,7 @@ static void ride_station_set_map_tooltip(TileElement* tileElement) { auto stationIndex = tileElement->AsTrack()->GetStationIndex(); for (int32_t i = stationIndex; i >= 0; i--) - if (ride->stations[i].Start.isNull()) + if (ride->stations[i].Start.IsNull()) stationIndex--; auto ft = Formatter(); @@ -2342,14 +2345,14 @@ static void ride_entrance_set_map_tooltip(TileElement* tileElement) // Get the station auto stationIndex = tileElement->AsEntrance()->GetStationIndex(); for (int32_t i = stationIndex; i >= 0; i--) - if (ride->stations[i].Start.isNull()) + if (ride->stations[i].Start.IsNull()) stationIndex--; if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_ENTRANCE) { // Get the queue length int32_t queueLength = 0; - if (!ride_get_entrance_location(ride, stationIndex).isNull()) + if (!ride_get_entrance_location(ride, stationIndex).IsNull()) queueLength = ride->stations[stationIndex].QueueLength; auto ft = Formatter(); @@ -2383,7 +2386,7 @@ static void ride_entrance_set_map_tooltip(TileElement* tileElement) // Get the station stationIndex = tileElement->AsEntrance()->GetStationIndex(); for (int32_t i = stationIndex; i >= 0; i--) - if (ride->stations[i].Start.isNull()) + if (ride->stations[i].Start.IsNull()) stationIndex--; auto ft = Formatter(); @@ -2435,7 +2438,7 @@ static StationIndex ride_mode_check_valid_station_numbers(Ride* ride) uint16_t numStations = 0; for (StationIndex stationIndex = 0; stationIndex < MAX_STATIONS; ++stationIndex) { - if (!ride->stations[stationIndex].Start.isNull()) + if (!ride->stations[stationIndex].Start.IsNull()) { numStations++; } @@ -2515,22 +2518,22 @@ static int32_t ride_check_for_entrance_exit(ride_id_t rideIndex) uint8_t exit = 0; for (int32_t i = 0; i < MAX_STATIONS; i++) { - if (ride->stations[i].Start.isNull()) + if (ride->stations[i].Start.IsNull()) continue; - if (!ride_get_entrance_location(ride, i).isNull()) + if (!ride_get_entrance_location(ride, i).IsNull()) { entrance = 1; } - if (!ride_get_exit_location(ride, i).isNull()) + if (!ride_get_exit_location(ride, i).IsNull()) { exit = 1; } // If station start and no entrance/exit // Sets same error message as no entrance - if (ride_get_exit_location(ride, i).isNull() && ride_get_entrance_location(ride, i).isNull()) + if (ride_get_exit_location(ride, i).IsNull() && ride_get_entrance_location(ride, i).IsNull()) { entrance = 0; break; @@ -2561,7 +2564,7 @@ void Ride::ChainQueues() const for (int32_t i = 0; i < MAX_STATIONS; i++) { auto location = ride_get_entrance_location(this, i); - if (location.isNull()) + if (location.IsNull()) continue; auto mapLocation = location.ToCoordsXYZ(); @@ -2868,9 +2871,10 @@ static void ride_set_boat_hire_return_point(Ride* ride, CoordsXYE* startElement) auto trackCoords = CoordsXYZ{ trackBeginEnd.begin_x, trackBeginEnd.begin_y, trackBeginEnd.begin_z }; int32_t direction = trackBeginEnd.begin_direction; trackType = trackBeginEnd.begin_element->AsTrack()->GetTrackType(); - auto newCoords = sub_6C683D({ trackCoords, static_cast(direction) }, trackType, 0, &returnPos.element, 0); - returnPos = newCoords == std::nullopt ? CoordsXYE{ trackCoords, returnPos.element } - : CoordsXYE{ *newCoords, returnPos.element }; + auto newCoords = GetTrackElementOriginAndApplyChanges( + { trackCoords, static_cast(direction) }, trackType, 0, &returnPos.element, 0); + returnPos = newCoords.has_value() ? CoordsXYE{ newCoords.value(), returnPos.element } + : CoordsXYE{ trackCoords, returnPos.element }; }; trackType = returnPos.element->AsTrack()->GetTrackType(); @@ -2896,19 +2900,19 @@ static void ride_set_maze_entrance_exit_points(Ride* ride) const auto entrance = ride_get_entrance_location(ride, i); const auto exit = ride_get_exit_location(ride, i); - if (!entrance.isNull()) + if (!entrance.IsNull()) { *position++ = entrance; } - if (!exit.isNull()) + if (!exit.IsNull()) { *position++ = exit; } } - (*position++).setNull(); + (*position++).SetNull(); // Enumerate entrance and exit positions - for (position = positions; !(*position).isNull(); position++) + for (position = positions; !(*position).IsNull(); position++) { auto entranceExitMapPos = position->ToCoordsXYZ(); @@ -3045,7 +3049,7 @@ static Vehicle* vehicle_create_car( vehicle->vehicle_type = vehicleEntryIndex; vehicle->SubType = carIndex == 0 ? Vehicle::Type::Head : Vehicle::Type::Tail; - vehicle->var_44 = ror32(vehicleEntry->spacing, 10) & 0xFFFF; + vehicle->var_44 = Numerics::ror32(vehicleEntry->spacing, 10) & 0xFFFF; auto edx = vehicleEntry->spacing >> 1; *remainingDistance -= edx; vehicle->remaining_distance = *remainingDistance; @@ -3215,7 +3219,7 @@ static Vehicle* vehicle_create_car( // loc_6DDD5E: vehicle->num_peeps = 0; vehicle->next_free_seat = 0; - vehicle->BoatLocation.setNull(); + vehicle->BoatLocation.SetNull(); vehicle->IsCrashedVehicle = false; return vehicle; } @@ -3529,7 +3533,7 @@ static bool ride_initialise_cable_lift_track(Ride* ride, bool isApplying) for (StationIndex stationIndex = 0; stationIndex < MAX_STATIONS; stationIndex++) { location = ride->stations[stationIndex].GetStart(); - if (!location.isNull()) + if (!location.IsNull()) break; if (stationIndex == (MAX_STATIONS - 1)) { @@ -3615,7 +3619,7 @@ static bool ride_initialise_cable_lift_track(Ride* ride, bool isApplying) auto tmpLoc = CoordsXYZ{ it.current, tileElement->GetBaseZ() }; auto direction = tileElement->GetDirection(); trackType = tileElement->AsTrack()->GetTrackType(); - sub_6C683D({ tmpLoc, direction }, trackType, 0, &tileElement, flags); + GetTrackElementOriginAndApplyChanges({ tmpLoc, direction }, trackType, 0, &tileElement, flags); } } return true; @@ -3668,9 +3672,9 @@ static bool ride_create_cable_lift(ride_id_t rideIndex, bool isApplying) uint32_t ebx = 0; for (int32_t i = 0; i < 5; i++) { - uint32_t edx = ror32(0x15478, 10); + uint32_t edx = Numerics::ror32(0x15478, 10); uint16_t var_44 = edx & 0xFFFF; - edx = rol32(edx, 10) >> 1; + edx = Numerics::rol32(edx, 10) >> 1; ebx -= edx; int32_t remaining_distance = ebx; ebx -= edx; @@ -3713,16 +3717,16 @@ void Ride::ConstructMissingEntranceOrExit() const int32_t i; for (i = 0; i < MAX_STATIONS; i++) { - if (stations[i].Start.isNull()) + if (stations[i].Start.IsNull()) continue; - if (ride_get_entrance_location(this, i).isNull()) + if (ride_get_entrance_location(this, i).IsNull()) { entranceOrExit = WC_RIDE_CONSTRUCTION__WIDX_ENTRANCE; break; } - if (ride_get_exit_location(this, i).isNull()) + if (ride_get_exit_location(this, i).IsNull()) { entranceOrExit = WC_RIDE_CONSTRUCTION__WIDX_EXIT; break; @@ -3799,13 +3803,13 @@ bool Ride::Test(RideStatus newStatus, bool isApplying) if (type == RIDE_TYPE_NULL) { - log_warning("Invalid ride type for ride %u", id); + log_warning("Invalid ride type for ride %u", EnumValue(id)); return false; } if (newStatus != RideStatus::Simulating) { - window_close_by_number(WC_RIDE_CONSTRUCTION, id); + window_close_by_number(WC_RIDE_CONSTRUCTION, EnumValue(id)); } StationIndex stationIndex = ride_mode_check_station_present(this); @@ -3932,9 +3936,11 @@ bool Ride::Open(bool isApplying) // to set the track to its final state and clean up ghosts. // We can't just call close as it would cause a stack overflow during shop creation // with auto open on. - if (WC_RIDE_CONSTRUCTION == gCurrentToolWidget.window_classification && id == gCurrentToolWidget.window_number + if (WC_RIDE_CONSTRUCTION == gCurrentToolWidget.window_classification && EnumValue(id) == gCurrentToolWidget.window_number && (input_test_flag(INPUT_FLAG_TOOL_ACTIVE))) - window_close_by_number(WC_RIDE_CONSTRUCTION, id); + { + window_close_by_number(WC_RIDE_CONSTRUCTION, EnumValue(id)); + } StationIndex stationIndex = ride_mode_check_station_present(this); if (stationIndex == STATION_INDEX_NULL) @@ -4641,7 +4647,7 @@ void invalidate_test_results(Ride* ride) } } } - window_invalidate_by_number(WC_RIDE, ride->id); + window_invalidate_by_number(WC_RIDE, static_cast(ride->id)); } /** @@ -4852,9 +4858,9 @@ static std::optional ride_get_smallest_station_length(Ride* ride) std::optional result; for (const auto& station : ride->stations) { - if (!station.Start.isNull()) + if (!station.Start.IsNull()) { - if (!result.has_value() || station.Length < *result) + if (!result.has_value() || station.Length < result.value()) { result = station.Length; } @@ -4877,7 +4883,7 @@ static int32_t ride_get_track_length(Ride* ride) for (int32_t i = 0; i < MAX_STATIONS && !foundTrack; i++) { trackStart = ride->stations[i].GetStart(); - if (trackStart.isNull()) + if (trackStart.IsNull()) continue; tileElement = map_get_first_element_at(trackStart); @@ -4967,7 +4973,7 @@ void Ride::UpdateMaxVehicles() if (!stationNumTiles.has_value()) return; - auto stationLength = (*stationNumTiles * 0x44180) - 0x16B2A; + auto stationLength = (stationNumTiles.value() * 0x44180) - 0x16B2A; int32_t maxMass = GetRideTypeDescriptor().MaxMass << 8; int32_t maxCarsPerTrain = 1; for (int32_t numCars = rideEntry->max_cars_in_train; numCars > 0; numCars--) @@ -5089,7 +5095,7 @@ void Ride::UpdateMaxVehicles() { num_cars_per_train = numCarsPerTrain; num_vehicles = numVehicles; - window_invalidate_by_number(WC_RIDE, id); + window_invalidate_by_number(WC_RIDE, EnumValue(id)); } } @@ -5158,7 +5164,7 @@ void Ride::Crash(uint8_t vehicleIndex) { Formatter ft; FormatNameTo(ft); - News::AddItemToQueue(News::ItemType::Ride, STR_RIDE_HAS_CRASHED, id, ft); + News::AddItemToQueue(News::ItemType::Ride, STR_RIDE_HAS_CRASHED, EnumValue(id), ft); } } @@ -5338,7 +5344,7 @@ bool ride_has_adjacent_station(Ride* ride) for (StationIndex stationNum = 0; stationNum < MAX_STATIONS; stationNum++) { auto stationStart = ride->stations[stationNum].GetStart(); - if (!stationStart.isNull()) + if (!stationStart.IsNull()) { /* Get the map element for the station start. */ TileElement* stationElement = get_station_platform({ stationStart, stationStart.z + 0 }); @@ -5513,7 +5519,7 @@ void determine_ride_entrance_and_exit_locations() bool fixExit = false; // Skip if the station has no entrance - if (!entranceLoc.isNull()) + if (!entranceLoc.IsNull()) { const EntranceElement* entranceElement = map_get_ride_entrance_element_at(entranceLoc.ToCoordsXYZD(), false); @@ -5528,7 +5534,7 @@ void determine_ride_entrance_and_exit_locations() } } - if (!exitLoc.isNull()) + if (!exitLoc.IsNull()) { const EntranceElement* entranceElement = map_get_ride_exit_element_at(exitLoc.ToCoordsXYZD(), false); diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index b7365b1130..adbed46eb8 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -425,6 +425,7 @@ public: bool SupportsStatus(RideStatus s) const; void StopGuestsQueuing(); + void ValidateStations(); bool Open(bool isApplying); bool Test(RideStatus newStatus, bool isApplying); @@ -1149,7 +1150,7 @@ void ride_breakdown_add_news_item(Ride* ride); Staff* ride_find_closest_mechanic(Ride* ride, int32_t forInspection); int32_t ride_initialise_construction_window(Ride* ride); void ride_construction_invalidate_current_track(); -std::optional sub_6C683D( +std::optional GetTrackElementOriginAndApplyChanges( const CoordsXYZD& location, track_type_t type, uint16_t extra_params, TileElement** output_element, uint16_t flags); void ride_set_map_tooltip(TileElement* tileElement); void ride_prepare_breakdown(Ride* ride, int32_t breakdownReason); @@ -1220,9 +1221,7 @@ enum class RideSetSetting : uint8_t; money32 set_operating_setting(ride_id_t rideId, RideSetSetting setting, uint8_t value); money32 set_operating_setting_nested(ride_id_t rideId, RideSetSetting setting, uint8_t value, uint8_t flags); -void sub_6CB945(Ride* ride); - -void sub_6C94D8(); +void UpdateGhostTrackAndArrow(); void ride_reset_all_names(); diff --git a/src/openrct2/ride/RideConstruction.cpp b/src/openrct2/ride/RideConstruction.cpp index de5f99dfd3..b48053cc75 100644 --- a/src/openrct2/ride/RideConstruction.cpp +++ b/src/openrct2/ride/RideConstruction.cpp @@ -122,7 +122,7 @@ static rct_window* ride_create_or_find_construction_window(ride_id_t rideIndex) { auto windowManager = GetContext()->GetUiContext()->GetWindowManager(); auto intent = Intent(INTENT_ACTION_RIDE_CONSTRUCTION_FOCUS); - intent.putExtra(INTENT_EXTRA_RIDE_ID, rideIndex); + intent.putExtra(INTENT_EXTRA_RIDE_ID, EnumValue(rideIndex)); windowManager->BroadcastIntent(intent); return window_find_by_class(WC_RIDE_CONSTRUCTION); } @@ -239,7 +239,7 @@ void ride_clear_for_construction(Ride* ride) ride->RemoveVehicles(); ride_clear_blocked_tiles(ride); - auto w = window_find_by_number(WC_RIDE, ride->id); + auto w = window_find_by_number(WC_RIDE, EnumValue(ride->id)); if (w != nullptr) window_event_resize_call(w); } @@ -258,7 +258,7 @@ void ride_remove_peeps(Ride* ride) if (stationIndex != STATION_INDEX_NULL) { auto location = ride_get_exit_location(ride, stationIndex).ToCoordsXYZD(); - if (!location.isNull()) + if (!location.IsNull()) { auto direction = direction_reverse(location.direction); exitPosition = location; @@ -379,7 +379,7 @@ void ride_clear_blocked_tiles(Ride* ride) * di : output_element * bp : flags */ -std::optional sub_6C683D( +std::optional GetTrackElementOriginAndApplyChanges( const CoordsXYZD& location, track_type_t type, uint16_t extra_params, TileElement** output_element, uint16_t flags) { // Find the relevant track piece, prefer sequence 0 (this ensures correct behaviour for diagonal track pieces) @@ -549,7 +549,7 @@ void ride_construction_invalidate_current_track() switch (_rideConstructionState) { case RideConstructionState::Selected: - sub_6C683D( + GetTrackElementOriginAndApplyChanges( { _currentTrackBegin, static_cast(_currentTrackPieceDirection & 3) }, _currentTrackPieceType, 0, nullptr, TRACK_ELEMENT_SET_HIGHLIGHT_FALSE); break; @@ -661,8 +661,8 @@ void ride_construction_set_default_next_piece() ted = &GetTrackElementDescriptor(trackType); curve = ted->CurveChain.next; - bank = TrackDefinitions[trackType].bank_end; - slope = TrackDefinitions[trackType].vangle_end; + bank = ted->Definition.bank_end; + slope = ted->Definition.vangle_end; // Set track curve _currentTrackCurve = curve; @@ -707,8 +707,8 @@ void ride_construction_set_default_next_piece() ted = &GetTrackElementDescriptor(trackType); curve = ted->CurveChain.previous; - bank = TrackDefinitions[trackType].bank_start; - slope = TrackDefinitions[trackType].vangle_start; + bank = ted->Definition.bank_start; + slope = ted->Definition.vangle_start; // Set track curve _currentTrackCurve = curve; @@ -750,8 +750,9 @@ void ride_select_next_section() int32_t direction = _currentTrackPieceDirection; int32_t type = _currentTrackPieceType; TileElement* tileElement; - auto newCoords = sub_6C683D({ _currentTrackBegin, static_cast(direction & 3) }, type, 0, &tileElement, 0); - if (newCoords == std::nullopt) + auto newCoords = GetTrackElementOriginAndApplyChanges( + { _currentTrackBegin, static_cast(direction & 3) }, type, 0, &tileElement, 0); + if (!newCoords.has_value()) { _rideConstructionState = RideConstructionState::State0; window_ride_construction_update_active_elements(); @@ -816,7 +817,8 @@ void ride_select_previous_section() int32_t direction = _currentTrackPieceDirection; int32_t type = _currentTrackPieceType; TileElement* tileElement; - auto newCoords = sub_6C683D({ _currentTrackBegin, static_cast(direction & 3) }, type, 0, &tileElement, 0); + auto newCoords = GetTrackElementOriginAndApplyChanges( + { _currentTrackBegin, static_cast(direction & 3) }, type, 0, &tileElement, 0); if (newCoords == std::nullopt) { _rideConstructionState = RideConstructionState::State0; @@ -1034,13 +1036,13 @@ bool ride_modify(CoordsXYE* input) auto tileCoords = CoordsXYZ{ tileElement, tileElement.element->GetBaseZ() }; auto direction = tileElement.element->GetDirection(); auto type = tileElement.element->AsTrack()->GetTrackType(); - auto newCoords = sub_6C683D({ tileCoords, direction }, type, 0, nullptr, 0); - if (newCoords == std::nullopt) + auto newCoords = GetTrackElementOriginAndApplyChanges({ tileCoords, direction }, type, 0, nullptr, 0); + if (!newCoords.has_value()) return false; _currentRideIndex = rideIndex; _rideConstructionState = RideConstructionState::Selected; - _currentTrackBegin = *newCoords; + _currentTrackBegin = newCoords.value(); _currentTrackPieceDirection = direction; _currentTrackPieceType = type; _currentTrackSelectionFlags = 0; @@ -1200,42 +1202,41 @@ money32 set_operating_setting_nested(ride_id_t rideId, RideSetSetting setting, u return res->Error == GameActions::Status::Ok ? 0 : MONEY32_UNDEFINED; } -static int32_t loc_6CD18E( - int16_t mapX, int16_t mapY, int16_t entranceMinX, int16_t entranceMinY, int16_t entranceMaxX, int16_t entranceMaxY) +// Finds the direction a ride entrance should face for an NxN station. +// Direction is valid if queryLocation is directly adjacent to this station. +static Direction GetRideEntranceDirection(const CoordsXY& queryLocation, CoordsXY entranceMin, CoordsXY entranceMax) { - int32_t direction = 0; - if (mapX == entranceMinX) + entranceMin -= CoordsXY(32, 32); + entranceMax += CoordsXY(32, 32); + if (queryLocation.x == entranceMin.x) { - if (mapY > entranceMinY && mapY < entranceMaxY) + if (queryLocation.y > entranceMin.y && queryLocation.y < entranceMax.y) { - return direction; + return 0; } } - direction = 1; - if (mapY == entranceMaxY) + if (queryLocation.y == entranceMax.y) { - if (mapX > entranceMinX && mapX < entranceMaxX) + if (queryLocation.x > entranceMin.x && queryLocation.x < entranceMax.x) { - return direction; + return 1; } } - direction = 2; - if (mapX == entranceMaxX) + if (queryLocation.x == entranceMax.x) { - if (mapY > entranceMinY && mapY < entranceMaxY) + if (queryLocation.y > entranceMin.y && queryLocation.y < entranceMax.y) { - return direction; + return 2; } } - direction = 3; - if (mapY == entranceMinY) + if (queryLocation.y == entranceMin.y) { - if (mapX > entranceMinX && mapX < entranceMaxX) + if (queryLocation.x > entranceMin.x && queryLocation.x < entranceMax.x) { - return direction; + return 3; } } - return -1; + return INVALID_DIRECTION; } /** @@ -1245,8 +1246,8 @@ static int32_t loc_6CD18E( CoordsXYZD ride_get_entrance_or_exit_position_from_screen_position(const ScreenCoordsXY& screenCoords) { CoordsXYZD entranceExitCoords{}; - gRideEntranceExitPlaceDirection = INVALID_DIRECTION; + // determine if the mouse is hovering over a station - that's the station to add the entrance to auto info = get_map_coordinates_from_pos(screenCoords, EnumsToFlags(ViewportInteractionItem::Ride)); if (info.SpriteType != ViewportInteractionItem::None) { @@ -1273,57 +1274,60 @@ CoordsXYZD ride_get_entrance_or_exit_position_from_screen_position(const ScreenC auto ride = get_ride(gRideEntranceExitPlaceRideIndex); if (ride == nullptr) { - entranceExitCoords.setNull(); + entranceExitCoords.SetNull(); return entranceExitCoords; } auto stationBaseZ = ride->stations[gRideEntranceExitPlaceStationIndex].GetBaseZ(); - auto coords = screen_get_map_xy_with_z(screenCoords, stationBaseZ); - if (!coords) + auto coordsAtHeight = screen_get_map_xy_with_z(screenCoords, stationBaseZ); + if (!coordsAtHeight.has_value()) { - entranceExitCoords.setNull(); + entranceExitCoords.SetNull(); return entranceExitCoords; } - auto word_F4418C = coords->x; - auto word_F4418E = coords->y; - - entranceExitCoords = { coords->ToTileStart(), stationBaseZ, INVALID_DIRECTION }; + entranceExitCoords = { coordsAtHeight->ToTileStart(), stationBaseZ, INVALID_DIRECTION }; if (ride->type == RIDE_TYPE_NULL) { - entranceExitCoords.setNull(); + entranceExitCoords.SetNull(); return entranceExitCoords; } auto stationStart = ride->stations[gRideEntranceExitPlaceStationIndex].Start; - if (stationStart.isNull()) + if (stationStart.IsNull()) { - entranceExitCoords.setNull(); + entranceExitCoords.SetNull(); return entranceExitCoords; } + // flat rides if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_SINGLE_PIECE_STATION)) { - auto mapX = (word_F4418C & 0x1F) - 16; - auto mapY = (word_F4418E & 0x1F) - 16; + // find the quadrant the mouse is hovering over - that's the direction to start searching for a station TileElement + Direction startDirection = 0; + auto mapX = (coordsAtHeight->x & 0x1F) - 16; + auto mapY = (coordsAtHeight->y & 0x1F) - 16; if (std::abs(mapX) < std::abs(mapY)) { - entranceExitCoords.direction = mapY < 0 ? 3 : 1; + startDirection = mapY < 0 ? 3 : 1; } else { - entranceExitCoords.direction = mapX < 0 ? 0 : 2; + startDirection = mapX < 0 ? 0 : 2; } - - for (int32_t i = 0; i < MAX_STATIONS; i++) + // check all 4 directions, starting with the mouse's quadrant + for (uint8_t directionIncrement = 0; directionIncrement < 4; directionIncrement++) { - mapX = entranceExitCoords.x + CoordsDirectionDelta[entranceExitCoords.direction].x; - mapY = entranceExitCoords.y + CoordsDirectionDelta[entranceExitCoords.direction].y; - if (map_is_location_valid({ mapX, mapY })) + entranceExitCoords.direction = (startDirection + directionIncrement) & 3; + // search for TrackElement one tile over, shifted in the search direction + auto nextLocation = entranceExitCoords; + nextLocation += CoordsDirectionDelta[entranceExitCoords.direction]; + if (map_is_location_valid(nextLocation)) { - auto tileElement = map_get_first_element_at({ mapX, mapY }); + // iterate over every element in the tile until we find what we want + auto tileElement = map_get_first_element_at(nextLocation); if (tileElement == nullptr) continue; do @@ -1336,53 +1340,56 @@ CoordsXYZD ride_get_entrance_or_exit_position_from_screen_position(const ScreenC continue; if (tileElement->AsTrack()->GetTrackType() == TrackElemType::Maze) { + // if it's a maze, it can place the entrance and exit immediately entranceExitCoords.direction = direction_reverse(entranceExitCoords.direction); gRideEntranceExitPlaceDirection = entranceExitCoords.direction; return entranceExitCoords; } if (tileElement->AsTrack()->GetStationIndex() != gRideEntranceExitPlaceStationIndex) continue; + // if it's not a maze, the sequence properties for the TrackElement must be found to determine if an + // entrance can be placed on that side - int32_t eax = (entranceExitCoords.direction + 2 - tileElement->GetDirection()) - & TILE_ELEMENT_DIRECTION_MASK; + // get the ride entrance's side relative to the TrackElement + Direction direction = (direction_reverse(entranceExitCoords.direction) - tileElement->GetDirection()) & 3; const auto& ted = GetTrackElementDescriptor(tileElement->AsTrack()->GetTrackType()); - if (ted.SequenceProperties[tileElement->AsTrack()->GetSequenceIndex()] & (1 << eax)) + if (ted.SequenceProperties[tileElement->AsTrack()->GetSequenceIndex()] & (1 << direction)) { + // if that side of the TrackElement supports stations, the ride entrance is valid and faces away from + // the station entranceExitCoords.direction = direction_reverse(entranceExitCoords.direction); gRideEntranceExitPlaceDirection = entranceExitCoords.direction; return entranceExitCoords; } } while (!(tileElement++)->IsLastForTile()); } - entranceExitCoords.direction = (entranceExitCoords.direction + 1) & 3; } gRideEntranceExitPlaceDirection = INVALID_DIRECTION; } + // tracked rides excluding tower rides else { - auto mapX = stationStart.x; - auto mapY = stationStart.y; - auto entranceMinX = mapX; - auto entranceMinY = mapY; - auto entranceMaxX = mapX; - auto entranceMaxY = mapY; + // create a 2-point rectangle. The rectangle will have a width or height of 0 depending on station direction + CoordsXY entranceMin = { stationStart }; + CoordsXY entranceMax = { stationStart }; + // get the beginning of the station TrackElement auto tileElement = ride_get_station_start_track_element(ride, gRideEntranceExitPlaceStationIndex); if (tileElement == nullptr) { - entranceExitCoords.setNull(); + entranceExitCoords.SetNull(); return entranceExitCoords; } - entranceExitCoords.direction = tileElement->GetDirection(); - auto stationDirection = entranceExitCoords.direction; + auto stationDirection = tileElement->GetDirection(); + entranceExitCoords.direction = stationDirection; + auto next = entranceMax; + // find additional station TrackElements and extend the line of valid entrance locations while (true) { - entranceMaxX = mapX; - entranceMaxY = mapY; - mapX -= CoordsDirectionDelta[entranceExitCoords.direction].x; - mapY -= CoordsDirectionDelta[entranceExitCoords.direction].y; - tileElement = map_get_first_element_at({ mapX, mapY }); + entranceMax = next; + next -= CoordsDirectionDelta[stationDirection]; + tileElement = map_get_first_element_at(next); if (tileElement == nullptr) break; bool goToNextTile = false; @@ -1405,25 +1412,16 @@ CoordsXYZD ride_get_entrance_or_exit_position_from_screen_position(const ScreenC if (!goToNextTile) break; } + // swap variables for valid ranges + if (entranceMin.x > entranceMax.x) + std::swap(entranceMin.x, entranceMax.x); + if (entranceMin.y > entranceMax.y) + std::swap(entranceMin.y, entranceMax.y); - mapX = entranceMinX; - if (mapX > entranceMaxX) - { - entranceMinX = entranceMaxX; - entranceMaxX = mapX; - } + // get the station direction from its position + auto direction = GetRideEntranceDirection(entranceExitCoords, entranceMin, entranceMax); - mapY = entranceMinY; - if (mapY > entranceMaxY) - { - entranceMinY = entranceMaxY; - entranceMaxY = mapY; - } - - auto direction = loc_6CD18E( - entranceExitCoords.x, entranceExitCoords.y, entranceMinX - 32, entranceMinY - 32, entranceMaxX + 32, - entranceMaxY + 32); - if (direction != -1 && direction != stationDirection && direction != direction_reverse(stationDirection)) + if (direction != INVALID_DIRECTION && direction != stationDirection && direction != direction_reverse(stationDirection)) { entranceExitCoords.direction = direction; gRideEntranceExitPlaceDirection = entranceExitCoords.direction; @@ -1437,23 +1435,25 @@ CoordsXYZD ride_get_entrance_or_exit_position_from_screen_position(const ScreenC * * rct2: 0x006CB945 */ -void sub_6CB945(Ride* ride) +void Ride::ValidateStations() { const TrackElementDescriptor* ted; - if (ride->type != RIDE_TYPE_MAZE) + if (type != RIDE_TYPE_MAZE) { + // find the stations of the ride to begin stepping over track elements from for (StationIndex stationId = 0; stationId < MAX_STATIONS; ++stationId) { - if (ride->stations[stationId].Start.isNull()) + if (stations[stationId].Start.IsNull()) continue; - CoordsXYZ location = ride->stations[stationId].GetStart(); + CoordsXYZ location = stations[stationId].GetStart(); uint8_t direction = INVALID_DIRECTION; bool specialTrack = false; TileElement* tileElement = nullptr; while (true) { + // search backwards for the previous station TrackElement (only if the first station TrackElement is found) if (direction != INVALID_DIRECTION) { location.x -= CoordsDirectionDelta[direction].x; @@ -1463,6 +1463,7 @@ void sub_6CB945(Ride* ride) if (tileElement == nullptr) break; + // find the target TrackElement on the tile it's supposed to appear on bool trackFound = false; do { @@ -1470,12 +1471,13 @@ void sub_6CB945(Ride* ride) continue; if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) continue; - if (tileElement->AsTrack()->GetRideIndex() != ride->id) + if (tileElement->AsTrack()->GetRideIndex() != id) continue; if (tileElement->AsTrack()->GetSequenceIndex() != 0) continue; ted = &GetTrackElementDescriptor(tileElement->AsTrack()->GetTrackType()); + // keep searching for a station piece (coaster station, tower ride base, shops, and flat ride base) if (!(ted->SequenceProperties[0] & TRACK_SEQUENCE_FLAG_ORIGIN)) continue; @@ -1487,22 +1489,26 @@ void sub_6CB945(Ride* ride) { break; } - + // update the StationIndex, get the TrackElement's rotation tileElement->AsTrack()->SetStationIndex(stationId); direction = tileElement->GetDirection(); - if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_SINGLE_PIECE_STATION)) + // In the future this could look at the TED and see if the station has a sequence longer than 1 + // tower ride, flat ride, shop + if (GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_SINGLE_PIECE_STATION)) { + // if the track has multiple sequences, stop looking for the next one. specialTrack = true; break; } } + // if the track piece is not a tower ride, flat ride, or shop, continue to the next StationIndex if (!specialTrack) { continue; } - + // update all the blocks with StationIndex ted = &GetTrackElementDescriptor(tileElement->AsTrack()->GetTrackType()); const rct_preview_track* trackBlock = ted->Block; while ((++trackBlock)->index != 0xFF) @@ -1513,6 +1519,7 @@ void sub_6CB945(Ride* ride) tileElement = map_get_first_element_at(blockLocation); if (tileElement == nullptr) break; + // find the target TrackElement on the tile it's supposed to appear on do { if (blockLocation.z != tileElement->GetBaseZ()) @@ -1530,6 +1537,7 @@ void sub_6CB945(Ride* ride) if (!trackFound) { + // Critical error! Stop trying to find the next sequence to set StationIndex. break; } @@ -1537,22 +1545,22 @@ void sub_6CB945(Ride* ride) } } } - + // determine what entrances and exits exist FixedVector locations; for (StationIndex stationId = 0; stationId < MAX_STATIONS; ++stationId) { - auto entrance = ride_get_entrance_location(ride, stationId); - if (!entrance.isNull()) + auto entrance = ride_get_entrance_location(this, stationId); + if (!entrance.IsNull()) { locations.push_back(entrance); - ride_clear_entrance_location(ride, stationId); + ride_clear_entrance_location(this, stationId); } - auto exit = ride_get_exit_location(ride, stationId); - if (!exit.isNull()) + auto exit = ride_get_exit_location(this, stationId); + if (!exit.IsNull()) { locations.push_back(exit); - ride_clear_exit_location(ride, stationId); + ride_clear_exit_location(this, stationId); } } @@ -1560,7 +1568,8 @@ void sub_6CB945(Ride* ride) for (const TileCoordsXYZD& locationCoords : locations) { auto locationList = ++locationListIter; - + // determine if there's another ride entrance at this location later in the array + // if there is, skip it. The last ride entrance in the array at the location is not skipped bool duplicateLocation = false; while (locationList != locations.cend()) { @@ -1575,9 +1584,10 @@ void sub_6CB945(Ride* ride) if (duplicateLocation) { + // if it's a duplicate continue to the next ride entrance continue; } - + // if it's not a duplicate location CoordsXY location = locationCoords.ToCoordsXY(); TileElement* tileElement = map_get_first_element_at(location); @@ -1589,15 +1599,18 @@ void sub_6CB945(Ride* ride) continue; if (tileElement->base_height != locationCoords.z) continue; - if (tileElement->AsEntrance()->GetRideIndex() != ride->id) + if (tileElement->AsEntrance()->GetRideIndex() != id) continue; + // if it's a park entrance continue to the next tile element if (tileElement->AsEntrance()->GetEntranceType() > ENTRANCE_TYPE_RIDE_EXIT) continue; + // find the station that's connected to this ride entrance CoordsXY nextLocation = location; nextLocation.x += CoordsDirectionDelta[tileElement->GetDirection()].x; nextLocation.y += CoordsDirectionDelta[tileElement->GetDirection()].y; + // if there's no connected station, remove the ride entrance (see below) bool shouldRemove = true; TileElement* trackElement = map_get_first_element_at(nextLocation); if (trackElement == nullptr) @@ -1606,7 +1619,7 @@ void sub_6CB945(Ride* ride) { if (trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK) continue; - if (trackElement->AsTrack()->GetRideIndex() != ride->id) + if (trackElement->AsTrack()->GetRideIndex() != id) continue; if (trackElement->base_height != tileElement->base_height) continue; @@ -1614,41 +1627,45 @@ void sub_6CB945(Ride* ride) auto trackType = trackElement->AsTrack()->GetTrackType(); uint8_t trackSequence = trackElement->AsTrack()->GetSequenceIndex(); + // determine where the ride entrance is relative to the station track Direction direction = (tileElement->GetDirection() - direction_reverse(trackElement->GetDirection())) & 3; + // if the ride entrance is not on a valid side, remove it ted = &GetTrackElementDescriptor(trackType); if (!(ted->SequenceProperties[trackSequence] & (1 << direction))) { continue; } - + // get the StationIndex for the station StationIndex stationId = 0; if (trackType != TrackElemType::Maze) { stationId = trackElement->AsTrack()->GetStationIndex(); } - if (tileElement->AsEntrance()->GetEntranceType() == ENTRANCE_TYPE_RIDE_EXIT) { - if (!ride_get_exit_location(ride, stationId).isNull()) + // if the location is already set for this station, big problem! + if (!ride_get_exit_location(this, stationId).IsNull()) break; - - CoordsXYZD loc = { location, ride->stations[stationId].GetBaseZ(), tileElement->GetDirection() }; - ride_set_exit_location(ride, stationId, TileCoordsXYZD{ loc }); + // set the station's exit location to this one + CoordsXYZD loc = { location, stations[stationId].GetBaseZ(), tileElement->GetDirection() }; + ride_set_exit_location(this, stationId, TileCoordsXYZD{ loc }); } else { - if (!ride_get_entrance_location(ride, stationId).isNull()) + // if the location is already set for this station, big problem! + if (!ride_get_entrance_location(this, stationId).IsNull()) break; - - CoordsXYZD loc = { location, ride->stations[stationId].GetBaseZ(), tileElement->GetDirection() }; - ride_set_entrance_location(ride, stationId, TileCoordsXYZD{ loc }); + // set the station's entrance location to this one + CoordsXYZD loc = { location, stations[stationId].GetBaseZ(), tileElement->GetDirection() }; + ride_set_entrance_location(this, stationId, TileCoordsXYZD{ loc }); } - + // set the entrance's StationIndex as this station tileElement->AsEntrance()->SetStationIndex(stationId); shouldRemove = false; } while (!(trackElement++)->IsLastForTile()); + // remove the ride entrance and clean up if necessary if (shouldRemove) { footpath_queue_chain_reset(); @@ -1721,16 +1738,16 @@ bool ride_are_all_possible_entrances_and_exits_built(Ride* ride) for (int32_t i = 0; i < MAX_STATIONS; i++) { - if (ride->stations[i].Start.isNull()) + if (ride->stations[i].Start.IsNull()) { continue; } - if (ride_get_entrance_location(ride, i).isNull()) + if (ride_get_entrance_location(ride, i).IsNull()) { gGameCommandErrorText = STR_ENTRANCE_NOT_YET_BUILT; return false; } - if (ride_get_exit_location(ride, i).isNull()) + if (ride_get_exit_location(ride, i).IsNull()) { gGameCommandErrorText = STR_EXIT_NOT_YET_BUILT; return false; diff --git a/src/openrct2/ride/RideRatings.cpp b/src/openrct2/ride/RideRatings.cpp index b099ab2a86..5517784300 100644 --- a/src/openrct2/ride/RideRatings.cpp +++ b/src/openrct2/ride/RideRatings.cpp @@ -159,10 +159,10 @@ static void ride_ratings_update_state_0(RideRatingUpdateState& state) { ride_id_t currentRide = state.CurrentRide; - currentRide++; - if (currentRide >= MAX_RIDES) + currentRide = static_cast(EnumValue(currentRide) + 1); + if (currentRide >= static_cast(MAX_RIDES)) { - currentRide = 0; + currentRide = {}; } auto ride = get_ride(currentRide); @@ -237,7 +237,7 @@ static void ride_ratings_update_state_2(RideRatingUpdateState& state) { int32_t entranceIndex = tileElement->AsTrack()->GetStationIndex(); state.StationFlags &= ~RIDE_RATING_STATION_FLAG_NO_ENTRANCE; - if (ride_get_entrance_location(ride, entranceIndex).isNull()) + if (ride_get_entrance_location(ride, entranceIndex).IsNull()) { state.StationFlags |= RIDE_RATING_STATION_FLAG_NO_ENTRANCE; } @@ -285,7 +285,7 @@ static void ride_ratings_update_state_3(RideRatingUpdateState& state) ride_ratings_calculate(state, ride); ride_ratings_calculate_value(ride); - window_invalidate_by_number(WC_RIDE, state.CurrentRide); + window_invalidate_by_number(WC_RIDE, EnumValue(state.CurrentRide)); state.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; } @@ -386,10 +386,10 @@ static void ride_ratings_begin_proximity_loop(RideRatingUpdateState& state) for (int32_t i = 0; i < MAX_STATIONS; i++) { - if (!ride->stations[i].Start.isNull()) + if (!ride->stations[i].Start.IsNull()) { state.StationFlags &= ~RIDE_RATING_STATION_FLAG_NO_ENTRANCE; - if (ride_get_entrance_location(ride, i).isNull()) + if (ride_get_entrance_location(ride, i).IsNull()) { state.StationFlags |= RIDE_RATING_STATION_FLAG_NO_ENTRANCE; } @@ -591,7 +591,7 @@ static void ride_ratings_score_close_proximity(RideRatingUpdateState& state, Til break; case TILE_ELEMENT_TYPE_PATH: // Bonus for normal path - if (tileElement->AsPath()->GetSurfaceEntryIndex() != 0) + if (tileElement->AsPath()->GetLegacyPathEntryIndex() != 0) { if (tileElement->GetClearanceZ() == inputTileElement->GetBaseZ()) { @@ -753,7 +753,7 @@ static void ride_ratings_calculate(RideRatingUpdateState& state, Ride* ride) // Create event args object auto obj = DukObject(ctx); - obj.Set("rideId", ride->id); + obj.Set("rideId", EnumValue(ride->id)); obj.Set("excitement", originalExcitement); obj.Set("intensity", originalIntensity); obj.Set("nausea", originalNausea); diff --git a/src/openrct2/ride/RideTypes.h b/src/openrct2/ride/RideTypes.h index 2a1567ad4b..7d8b11b344 100644 --- a/src/openrct2/ride/RideTypes.h +++ b/src/openrct2/ride/RideTypes.h @@ -13,11 +13,12 @@ #include #include +#include -using ride_id_t = uint16_t; +enum class ride_id_t : uint16_t; struct Ride; -constexpr const ride_id_t RIDE_ID_NULL = std::numeric_limits::max(); +constexpr const ride_id_t RIDE_ID_NULL = static_cast(std::numeric_limits>::max()); /** * Couples a ride type and subtype together. diff --git a/src/openrct2/ride/Station.cpp b/src/openrct2/ride/Station.cpp index f62414cb19..ec38c94a0e 100644 --- a/src/openrct2/ride/Station.cpp +++ b/src/openrct2/ride/Station.cpp @@ -29,7 +29,7 @@ static void ride_invalidate_station_start(Ride* ride, StationIndex stationIndex, */ void ride_update_station(Ride* ride, StationIndex stationIndex) { - if (ride->stations[stationIndex].Start.isNull()) + if (ride->stations[stationIndex].Start.IsNull()) return; switch (ride->mode) @@ -367,7 +367,7 @@ StationIndex ride_get_first_valid_station_exit(Ride* ride) { for (StationIndex i = 0; i < MAX_STATIONS; i++) { - if (!ride->stations[i].Exit.isNull()) + if (!ride->stations[i].Exit.IsNull()) { return i; } @@ -379,7 +379,7 @@ StationIndex ride_get_first_valid_station_start(const Ride* ride) { for (StationIndex i = 0; i < MAX_STATIONS; i++) { - if (!ride->stations[i].Start.isNull()) + if (!ride->stations[i].Start.IsNull()) { return i; } @@ -391,7 +391,7 @@ StationIndex ride_get_first_empty_station_start(const Ride* ride) { for (StationIndex i = 0; i < MAX_STATIONS; i++) { - if (ride->stations[i].Start.isNull()) + if (ride->stations[i].Start.IsNull()) { return i; } @@ -411,12 +411,12 @@ TileCoordsXYZD ride_get_exit_location(const Ride* ride, const StationIndex stati void ride_clear_entrance_location(Ride* ride, const StationIndex stationIndex) { - ride->stations[stationIndex].Entrance.setNull(); + ride->stations[stationIndex].Entrance.SetNull(); } void ride_clear_exit_location(Ride* ride, const StationIndex stationIndex) { - ride->stations[stationIndex].Exit.setNull(); + ride->stations[stationIndex].Exit.SetNull(); } void ride_set_entrance_location(Ride* ride, const StationIndex stationIndex, const TileCoordsXYZD& location) diff --git a/src/openrct2/ride/Track.cpp b/src/openrct2/ride/Track.cpp index 73fa7f8946..e27ee73ed0 100644 --- a/src/openrct2/ride/Track.cpp +++ b/src/openrct2/ride/Track.cpp @@ -34,289 +34,18 @@ #include "TrackData.h" #include "TrackDesign.h" -/** rct2: 0x00997C9D */ -// clang-format off -const rct_trackdefinition TrackDefinitions[TrackElemType::Count] = -{ - // TYPE VANGLE END VANGLE START BANK END BANK START PREVIEW Z OFFSET - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT - { TRACK_STATION_END, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_END_STATION - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BEGIN_STATION - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MIDDLE_STATION - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_5_TILES - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_BANKED_LEFT_QUARTER_TURN_5_TILES - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_BANKED_RIGHT_QUARTER_TURN_5_TILES - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_DOWN - { TRACK_S_BEND, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_S_BEND_LEFT - { TRACK_S_BEND, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_S_BEND_RIGHT - { TRACK_VERTICAL_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, -48 }, // ELEM_LEFT_VERTICAL_LOOP - { TRACK_VERTICAL_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, -48 }, // ELEM_RIGHT_VERTICAL_LOOP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_BANK - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE - { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_TWIST_DOWN_TO_UP - { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_TWIST_DOWN_TO_UP - { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_LEFT_TWIST_UP_TO_DOWN - { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_RIGHT_TWIST_UP_TO_DOWN - { TRACK_HALF_LOOP, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 64 }, // ELEM_HALF_LOOP_UP - { TRACK_HALF_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -64 }, // ELEM_HALF_LOOP_DOWN - { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_CORKSCREW_UP - { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_CORKSCREW_UP - { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -32 }, // ELEM_LEFT_CORKSCREW_DOWN - { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -32 }, // ELEM_RIGHT_CORKSCREW_DOWN - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_TO_FLAT - { TRACK_TOWER_BASE, TRACK_VANGLE_TOWER, TRACK_VANGLE_TOWER, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_TOWER_BASE - { TRACK_TOWER_BASE, TRACK_VANGLE_TOWER, TRACK_VANGLE_TOWER, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_TOWER_SECTION - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_COVERED - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_COVERED - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_COVERED - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_25_DEG_UP_COVERED - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_60_DEG_UP_COVERED - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_25_DEG_UP_COVERED - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_FLAT_COVERED - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_25_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_FLAT_COVERED - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_COVERED - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_COVERED - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_S_BEND_LEFT_COVERED - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_S_BEND_RIGHT_COVERED - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_COVERED - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_COVERED - { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL - { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL - { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_SMALL - { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_SMALL - { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_LARGE - { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_LARGE - { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_LARGE - { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_LARGE - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_DOWN - { TRACK_BRAKES, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BRAKES - { TRACK_BOOSTER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BOOSTER - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP - { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_UP - { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_UP - { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_DOWN - { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_DOWN - { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_HELIX_LARGE_UP - { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_UP - { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_HELIX_LARGE_DOWN - { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_DOWN - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_25_DEG_UP_LEFT_BANKED - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_25_DEG_UP_RIGHT_BANKED - { TRACK_WATERFALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_WATERFALL - { TRACK_RAPIDS, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RAPIDS - { TRACK_ON_RIDE_PHOTO, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_ON_RIDE_PHOTO - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_25_DEG_DOWN_LEFT_BANKED - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_25_DEG_DOWN_RIGHT_BANKED - { TRACK_WATER_SPLASH, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_WATER_SPLASH - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_60_DEG_UP_LONG_BASE - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE - { TRACK_WHIRLPOOL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_WHIRLPOOL - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_60_DEG_DOWN_LONG_BASE - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE_122 - { TRACK_LIFT_HILL_CABLE, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_CABLE_LIFT_HILL - { TRACK_REVERSE_FREEFALL, TRACK_VANGLE_REVERSE_FREEFALL, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_REVERSE_FREEFALL_SLOPE - { TRACK_REVERSE_FREEFALL, TRACK_VANGLE_REVERSE_FREEFALL, TRACK_VANGLE_REVERSE_FREEFALL, TRACK_BANK_NONE,TRACK_BANK_NONE, 0 }, // ELEM_REVERSE_FREEFALL_VERTICAL - { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_90_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_DOWN_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_UP_TO_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_TO_90_DEG_DOWN - { TRACK_BRAKE_FOR_DROP, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BRAKE_FOR_DROP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_EIGHTH_TO_DIAG - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_EIGHTH_TO_DIAG - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_EIGHTH_TO_ORTHOGONAL - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_EIGHTH_TO_ORTHOGONAL - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_EIGHTH_BANK_TO_DIAG - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_EIGHTH_BANK_TO_DIAG - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_EIGHTH_BANK_TO_ORTHOGONAL - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_EIGHTH_BANK_TO_ORTHOGONAL - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP_TO_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_UP_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_DOWN_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_60_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_DOWN_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_DIAG_LEFT_BANK_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_DIAG_RIGHT_BANK_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP_TO_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN_TO_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_DIAG_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_DIAG_RIGHT_BANK - { TRACK_LOG_FLUME_REVERSER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LOG_FLUME_REVERSER - { TRACK_SPINNING_TUNNEL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_SPINNING_TUNNEL - { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN - { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN - { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP - { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK_TO_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK_TO_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_LEFT_BANK - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_RIGHT_BANK - { TRACK_POWERED_LIFT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_POWERED_LIFT - {TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 64 }, // ELEM_LEFT_LARGE_HALF_LOOP_UP - {TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 64 }, // ELEM_RIGHT_LARGE_HALF_LOOP_UP - {TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -64 }, // ELEM_RIGHT_LARGE_HALF_LOOP_DOWN - {TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -64 }, // ELEM_LEFT_LARGE_HALF_LOOP_DOWN - {TRACK_INLINE_TWIST_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_FLYER_TWIST_UP - {TRACK_INLINE_TWIST_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_FLYER_TWIST_UP - {TRACK_INLINE_TWIST_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_FLYER_TWIST_DOWN - {TRACK_INLINE_TWIST_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_FLYER_TWIST_DOWN - {TRACK_HALF_LOOP_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 64 }, // ELEM_FLYER_HALF_LOOP_UP - {TRACK_HALF_LOOP_INVERTED, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, -64 }, // ELEM_FLYER_HALF_LOOP_DOWN - {TRACK_CORKSCREW_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_FLYER_CORKSCREW_UP - {TRACK_CORKSCREW_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_FLYER_CORKSCREW_UP - {TRACK_CORKSCREW_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, -32 }, // ELEM_LEFT_FLYER_CORKSCREW_DOWN - {TRACK_CORKSCREW_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, -32 }, // ELEM_RIGHT_FLYER_CORKSCREW_DOWN - {TRACK_HEARTLINE_TRANSFER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_HEARTLINE_TRANSFER_UP - {TRACK_HEARTLINE_TRANSFER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_HEARTLINE_TRANSFER_DOWN - {TRACK_HEARTLINE_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_HEARTLINE_ROLL - {TRACK_HEARTLINE_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_HEARTLINE_ROLL - {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_A - {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_B - {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_C - {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_D - {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_E - {TRACK_QUARTER_LOOP_INVERTED, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_MULTIDIM_INVERTED_FLAT_TO_90_DEG_QUARTER_LOOP_DOWN - {TRACK_QUARTER_LOOP, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_90, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_TO_INVERTED_FLAT_QUARTER_LOOP_UP - {TRACK_QUARTER_LOOP, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_INVERTED_FLAT_TO_90_DEG_QUARTER_LOOP_DOWN - { TRACK_LIFT_HILL_CURVED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_CURVED_LIFT_HILL - { TRACK_LIFT_HILL_CURVED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_CURVED_LIFT_HILL - { TRACK_REVERSER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_REVERSER - { TRACK_REVERSER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_REVERSER - { TRACK_SLOPE_TO_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_AIR_THRUST_TOP_CAP - { TRACK_SLOPE_TO_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_AIR_THRUST_VERTICAL_DOWN - { TRACK_SLOPE_TO_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_AIR_THRUST_VERTICAL_DOWN_TO_LEVEL - { TRACK_BLOCK_BRAKES, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BLOCK_BRAKES - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_QUARTER_TURN_3_TILE_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_QUARTER_TURN_3_TILE_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_QUARTER_TURN_3_TILE_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_QUARTER_TURN_3_TILE_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_QUARTER_TURN_5_TILE_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_QUARTER_TURN_5_TILE_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_QUARTER_TURN_5_TILE_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_QUARTER_TURN_5_TILE_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_LEFT_BANKED_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_RIGHT_BANKED_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_UP_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_UP_TO_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_LEFT_BANKED_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_RIGHT_BANKED_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_DOWN_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_DOWN_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_FLAT_TO_LEFT_BANKED_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_FLAT_TO_RIGHT_BANKED_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_UP_TO_LEFT_BANKED_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_UP_TO_RIGHT_BANKED_FLAT - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_FLAT_TO_LEFT_BANKED_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_FLAT_TO_RIGHT_BANKED_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_DOWN_TO_LEFT_BANKED_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_DOWN_TO_RIGHT_BANKED_FLAT - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_LEFT_BANKED_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_RIGHT_BANKED_25_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_LEFT_BANKED_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_RIGHT_BANKED_25_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_DOWN_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_DOWN_TO_FLAT - { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_90_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_90_DEG_UP - { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_90_DEG_DOWN - { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_90_DEG_DOWN - { TRACK_QUARTER_LOOP_UNINVERTED,TRACK_SLOPE_NONE, TRACK_SLOPE_UP_90, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_MULTIDIM_90_DEG_UP_TO_INVERTED_FLAT_QUARTER_LOOP - { TRACK_QUARTER_LOOP_UNINVERTED,TRACK_SLOPE_DOWN_90, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_MULTIDIM_FLAT_TO_90_DEG_DOWN_QUARTER_LOOP - { TRACK_QUARTER_LOOP_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_90, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // 255 - { TRACK_ROTATION_CONTROL_TOGGLE,TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_ROTATION_CONTROL_TOGGLE - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x4A - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack2x2 - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack4x4 - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack2x4 - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x5 - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x1A - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x4B - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x1B - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, -40 }, // TrackElemType::FlatTrack1x4C - { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack3x3 -}; -// clang-format on +using namespace OpenRCT2::TrackMetaData; PitchAndRoll TrackPitchAndRollStart(track_type_t trackType) { - return { TrackDefinitions[trackType].vangle_start, TrackDefinitions[trackType].bank_start }; + const auto& ted = GetTrackElementDescriptor(trackType); + return { ted.Definition.vangle_start, ted.Definition.bank_start }; } PitchAndRoll TrackPitchAndRollEnd(track_type_t trackType) { - return { TrackDefinitions[trackType].vangle_end, TrackDefinitions[trackType].bank_end }; + const auto& ted = GetTrackElementDescriptor(trackType); + return { ted.Definition.vangle_end, ted.Definition.bank_end }; } /** @@ -327,13 +56,15 @@ int32_t track_is_connected_by_shape(TileElement* a, TileElement* b) int32_t trackType, aBank, aAngle, bBank, bAngle; trackType = a->AsTrack()->GetTrackType(); - aBank = TrackDefinitions[trackType].bank_end; - aAngle = TrackDefinitions[trackType].vangle_end; + const auto* ted = &GetTrackElementDescriptor(trackType); + aBank = ted->Definition.bank_end; + aAngle = ted->Definition.vangle_end; aBank = track_get_actual_bank(a, aBank); trackType = b->AsTrack()->GetTrackType(); - bBank = TrackDefinitions[trackType].bank_start; - bAngle = TrackDefinitions[trackType].vangle_start; + ted = &GetTrackElementDescriptor(trackType); + bBank = ted->Definition.bank_start; + bAngle = ted->Definition.vangle_start; bBank = track_get_actual_bank(b, bBank); return aBank == bBank && aAngle == bAngle; @@ -369,7 +100,7 @@ static void ride_remove_station(Ride* ride, const CoordsXYZ& location) auto stationStart = ride->stations[i].GetStart(); if (stationStart == location) { - ride->stations[i].Start.setNull(); + ride->stations[i].Start.SetNull(); ride->num_stations--; break; } @@ -873,7 +604,8 @@ roll_type_t track_get_actual_bank_2(int32_t rideType, bool isInverted, roll_type roll_type_t track_get_actual_bank_3(bool useInvertedSprites, TileElement* tileElement) { auto trackType = tileElement->AsTrack()->GetTrackType(); - auto bankStart = TrackDefinitions[trackType].bank_start; + const auto& ted = GetTrackElementDescriptor(trackType); + auto bankStart = ted.Definition.bank_start; auto ride = get_ride(tileElement->AsTrack()->GetRideIndex()); if (ride == nullptr) return bankStart; diff --git a/src/openrct2/ride/Track.h b/src/openrct2/ride/Track.h index ac21d47da3..4c65c732f9 100644 --- a/src/openrct2/ride/Track.h +++ b/src/openrct2/ride/Track.h @@ -526,10 +526,10 @@ namespace TrackElemType enum { - TRACK_SEQUENCE_FLAG_DIRECTION_0 = (1 << 0), - TRACK_SEQUENCE_FLAG_DIRECTION_1 = (1 << 1), - TRACK_SEQUENCE_FLAG_DIRECTION_2 = (1 << 2), - TRACK_SEQUENCE_FLAG_DIRECTION_3 = (1 << 3), + TRACK_SEQUENCE_FLAG_DIRECTION_0 = (1 << 0), // Ride Entrances and path connect to front + TRACK_SEQUENCE_FLAG_DIRECTION_1 = (1 << 1), // connect to right + TRACK_SEQUENCE_FLAG_DIRECTION_2 = (1 << 2), // connect to back + TRACK_SEQUENCE_FLAG_DIRECTION_3 = (1 << 3), // connect to left TRACK_SEQUENCE_FLAG_ORIGIN = (1 << 4), // 0x10 TRACK_SEQUENCE_FLAG_CONNECTS_TO_PATH = (1 << 5), // 0x20 TRACK_SEQUENCE_FLAG_DISALLOW_DOORS = (1 << 6), // 0x40 @@ -553,8 +553,6 @@ struct track_circuit_iterator bool looped; }; -extern const rct_trackdefinition TrackDefinitions[TrackElemType::Count]; - PitchAndRoll TrackPitchAndRollStart(track_type_t trackType); PitchAndRoll TrackPitchAndRollEnd(track_type_t trackType); diff --git a/src/openrct2/ride/TrackData.cpp b/src/openrct2/ride/TrackData.cpp index f30a130642..100dc1a637 100644 --- a/src/openrct2/ride/TrackData.cpp +++ b/src/openrct2/ride/TrackData.cpp @@ -5129,6 +5129,304 @@ static constexpr uint16_t TrackFlags[TrackElemType::Count] = { }; // clang-format on +/** rct2: 0x00997C9D */ +// clang-format off +static constexpr rct_trackdefinition TrackDefinitions[TrackElemType::Count] = +{ + // TYPE VANGLE END VANGLE START BANK END BANK START PREVIEW Z OFFSET + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT + { TRACK_STATION_END, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_END_STATION + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BEGIN_STATION + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MIDDLE_STATION + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_5_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_BANKED_LEFT_QUARTER_TURN_5_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_BANKED_RIGHT_QUARTER_TURN_5_TILES + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_DOWN + { TRACK_S_BEND, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_S_BEND_LEFT + { TRACK_S_BEND, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_S_BEND_RIGHT + { TRACK_VERTICAL_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, -48 }, // ELEM_LEFT_VERTICAL_LOOP + { TRACK_VERTICAL_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, -48 }, // ELEM_RIGHT_VERTICAL_LOOP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_BANK + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE + { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_TWIST_DOWN_TO_UP + { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_TWIST_DOWN_TO_UP + { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_LEFT_TWIST_UP_TO_DOWN + { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_RIGHT_TWIST_UP_TO_DOWN + { TRACK_HALF_LOOP, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 64 }, // ELEM_HALF_LOOP_UP + { TRACK_HALF_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -64 }, // ELEM_HALF_LOOP_DOWN + { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_CORKSCREW_UP + { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_CORKSCREW_UP + { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -32 }, // ELEM_LEFT_CORKSCREW_DOWN + { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -32 }, // ELEM_RIGHT_CORKSCREW_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_TO_FLAT + { TRACK_TOWER_BASE, TRACK_VANGLE_TOWER, TRACK_VANGLE_TOWER, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_TOWER_BASE + { TRACK_TOWER_BASE, TRACK_VANGLE_TOWER, TRACK_VANGLE_TOWER, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_TOWER_SECTION + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_25_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_60_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_25_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_FLAT_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_25_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_FLAT_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_S_BEND_LEFT_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_S_BEND_RIGHT_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_COVERED + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_SMALL + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_SMALL + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_LARGE + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_LARGE + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_LARGE + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_LARGE + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_DOWN + { TRACK_BRAKES, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BRAKES + { TRACK_BOOSTER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BOOSTER + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP + { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_UP + { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_UP + { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_DOWN + { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_DOWN + { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_HELIX_LARGE_UP + { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_UP + { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_HELIX_LARGE_DOWN + { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_25_DEG_UP_LEFT_BANKED + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_25_DEG_UP_RIGHT_BANKED + { TRACK_WATERFALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_WATERFALL + { TRACK_RAPIDS, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RAPIDS + { TRACK_ON_RIDE_PHOTO, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_ON_RIDE_PHOTO + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_25_DEG_DOWN_LEFT_BANKED + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_25_DEG_DOWN_RIGHT_BANKED + { TRACK_WATER_SPLASH, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_WATER_SPLASH + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_60_DEG_UP_LONG_BASE + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE + { TRACK_WHIRLPOOL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_WHIRLPOOL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_60_DEG_DOWN_LONG_BASE + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE_122 + { TRACK_LIFT_HILL_CABLE, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_CABLE_LIFT_HILL + { TRACK_REVERSE_FREEFALL, TRACK_VANGLE_REVERSE_FREEFALL, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_REVERSE_FREEFALL_SLOPE + { TRACK_REVERSE_FREEFALL, TRACK_VANGLE_REVERSE_FREEFALL, TRACK_VANGLE_REVERSE_FREEFALL, TRACK_BANK_NONE,TRACK_BANK_NONE, 0 }, // ELEM_REVERSE_FREEFALL_VERTICAL + { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_UP_TO_90_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_DOWN_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_UP_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_60_DEG_DOWN_TO_90_DEG_DOWN + { TRACK_BRAKE_FOR_DROP, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BRAKE_FOR_DROP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_EIGHTH_TO_DIAG + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_EIGHTH_TO_DIAG + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_EIGHTH_TO_ORTHOGONAL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_EIGHTH_TO_ORTHOGONAL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_EIGHTH_BANK_TO_DIAG + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_EIGHTH_BANK_TO_DIAG + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_EIGHTH_BANK_TO_ORTHOGONAL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_EIGHTH_BANK_TO_ORTHOGONAL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_UP_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_DOWN_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_60_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_FLAT_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_DIAG_LEFT_BANK_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_DIAG_RIGHT_BANK_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_UP_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_DIAG_25_DEG_DOWN_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_DIAG_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_DIAG_RIGHT_BANK + { TRACK_LOG_FLUME_REVERSER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LOG_FLUME_REVERSER + { TRACK_SPINNING_TUNNEL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_SPINNING_TUNNEL + { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN + { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN + { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP + { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANK_TO_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANK_TO_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_RIGHT_BANK + { TRACK_POWERED_LIFT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_POWERED_LIFT + {TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 64 }, // ELEM_LEFT_LARGE_HALF_LOOP_UP + {TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 64 }, // ELEM_RIGHT_LARGE_HALF_LOOP_UP + {TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -64 }, // ELEM_RIGHT_LARGE_HALF_LOOP_DOWN + {TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, -64 }, // ELEM_LEFT_LARGE_HALF_LOOP_DOWN + {TRACK_INLINE_TWIST_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_FLYER_TWIST_UP + {TRACK_INLINE_TWIST_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_FLYER_TWIST_UP + {TRACK_INLINE_TWIST_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_FLYER_TWIST_DOWN + {TRACK_INLINE_TWIST_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_FLYER_TWIST_DOWN + {TRACK_HALF_LOOP_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 64 }, // ELEM_FLYER_HALF_LOOP_UP + {TRACK_HALF_LOOP_INVERTED, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, -64 }, // ELEM_FLYER_HALF_LOOP_DOWN + {TRACK_CORKSCREW_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_FLYER_CORKSCREW_UP + {TRACK_CORKSCREW_UNINVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_FLYER_CORKSCREW_UP + {TRACK_CORKSCREW_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, -32 }, // ELEM_LEFT_FLYER_CORKSCREW_DOWN + {TRACK_CORKSCREW_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, -32 }, // ELEM_RIGHT_FLYER_CORKSCREW_DOWN + {TRACK_HEARTLINE_TRANSFER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_HEARTLINE_TRANSFER_UP + {TRACK_HEARTLINE_TRANSFER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_HEARTLINE_TRANSFER_DOWN + {TRACK_HEARTLINE_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_HEARTLINE_ROLL + {TRACK_HEARTLINE_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_HEARTLINE_ROLL + {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_A + {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_B + {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_C + {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_D + {TRACK_MINI_GOLF_HOLE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_MINI_GOLF_HOLE_E + {TRACK_QUARTER_LOOP_INVERTED, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_MULTIDIM_INVERTED_FLAT_TO_90_DEG_QUARTER_LOOP_DOWN + {TRACK_QUARTER_LOOP, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_90, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_90_DEG_TO_INVERTED_FLAT_QUARTER_LOOP_UP + {TRACK_QUARTER_LOOP, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, 0 }, // ELEM_INVERTED_FLAT_TO_90_DEG_QUARTER_LOOP_DOWN + { TRACK_LIFT_HILL_CURVED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_CURVED_LIFT_HILL + { TRACK_LIFT_HILL_CURVED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_CURVED_LIFT_HILL + { TRACK_REVERSER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_REVERSER + { TRACK_REVERSER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_REVERSER + { TRACK_SLOPE_TO_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_AIR_THRUST_TOP_CAP + { TRACK_SLOPE_TO_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_AIR_THRUST_VERTICAL_DOWN + { TRACK_SLOPE_TO_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_AIR_THRUST_VERTICAL_DOWN_TO_LEVEL + { TRACK_BLOCK_BRAKES, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_BLOCK_BRAKES + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_QUARTER_TURN_3_TILE_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_QUARTER_TURN_3_TILE_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_QUARTER_TURN_3_TILE_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_QUARTER_TURN_3_TILE_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_QUARTER_TURN_5_TILE_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_QUARTER_TURN_5_TILE_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_QUARTER_TURN_5_TILE_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_QUARTER_TURN_5_TILE_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_LEFT_BANKED_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_UP_TO_RIGHT_BANKED_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_UP_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_UP_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_LEFT_BANKED_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_25_DEG_DOWN_TO_RIGHT_BANKED_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_DOWN_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_DOWN_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_FLAT_TO_LEFT_BANKED_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_FLAT_TO_RIGHT_BANKED_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_UP_TO_LEFT_BANKED_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_UP_TO_RIGHT_BANKED_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_FLAT_TO_LEFT_BANKED_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_FLAT_TO_RIGHT_BANKED_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_DOWN_TO_LEFT_BANKED_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_DOWN_TO_RIGHT_BANKED_FLAT + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_LEFT_BANKED_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_RIGHT_BANKED_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_LEFT_BANKED_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, 0 }, // ELEM_FLAT_TO_RIGHT_BANKED_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_LEFT, 0 }, // ELEM_LEFT_BANKED_25_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_RIGHT, 0 }, // ELEM_RIGHT_BANKED_25_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_90_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_90_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_90_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_90_DEG_DOWN + { TRACK_QUARTER_LOOP_UNINVERTED,TRACK_SLOPE_NONE, TRACK_SLOPE_UP_90, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_MULTIDIM_90_DEG_UP_TO_INVERTED_FLAT_QUARTER_LOOP + { TRACK_QUARTER_LOOP_UNINVERTED,TRACK_SLOPE_DOWN_90, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // ELEM_MULTIDIM_FLAT_TO_90_DEG_DOWN_QUARTER_LOOP + { TRACK_QUARTER_LOOP_INVERTED, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_90, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, 0 }, // 255 + { TRACK_ROTATION_CONTROL_TOGGLE,TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // ELEM_ROTATION_CONTROL_TOGGLE + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x4A + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack2x2 + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack4x4 + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack2x4 + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x5 + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x1A + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x4B + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack1x1B + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, -40 }, // TrackElemType::FlatTrack1x4C + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, 0 }, // TrackElemType::FlatTrack3x3 +}; +// clang-format on + +constexpr static uint8_t TrackTypeToSpinFunction[TrackElemType::Count] = { + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, LR_SPIN, + RL_SPIN, NO_SPIN, NO_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, L5_SPIN, R5_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, LR_SPIN, RL_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, + L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, L5_SPIN, R5_SPIN, L5_SPIN, R5_SPIN, NO_SPIN, RC_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, + L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, SP_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, R5_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, L9_SPIN, R9_SPIN, L9_SPIN, R9_SPIN, L9_SPIN, R9_SPIN, L9_SPIN, R9_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, L7_SPIN, R7_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, + L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, + NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN +}; + namespace OpenRCT2 { namespace TrackMetaData @@ -5151,6 +5449,8 @@ namespace OpenRCT2 desc.MirrorElement = TrackElementMirrorMap[i]; desc.PieceLength = TrackPieceLengths[i]; desc.Price = TrackPricing[i]; + desc.Definition = TrackDefinitions[i]; + desc.SpinFunction = TrackTypeToSpinFunction[i]; for (uint8_t j = 0; j < MaxSequencesPerPiece; j++) { diff --git a/src/openrct2/ride/TrackData.h b/src/openrct2/ride/TrackData.h index 4cd3705355..1d8b3c4199 100644 --- a/src/openrct2/ride/TrackData.h +++ b/src/openrct2/ride/TrackData.h @@ -34,6 +34,23 @@ struct track_descriptor uint8_t track_element; }; +enum +{ + NO_SPIN, + L8_SPIN, + R8_SPIN, + LR_SPIN, + RL_SPIN, + L7_SPIN, + R7_SPIN, + L5_SPIN, + R5_SPIN, + RC_SPIN, // Rotation Control Spin + SP_SPIN, // Special rapids Spin + L9_SPIN, + R9_SPIN +}; + extern const track_descriptor gTrackDescriptors[142]; struct dodgems_track_size @@ -70,6 +87,9 @@ struct TrackElementDescriptor std::array SequenceElementAllowedWallEdges; std::array SequenceProperties; + + rct_trackdefinition Definition; + uint8_t SpinFunction; }; namespace OpenRCT2 diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 48ac02c8db..c09b82754b 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -33,12 +33,14 @@ #include "../audio/audio.h" #include "../core/DataSerialiser.h" #include "../core/File.h" +#include "../core/Numerics.hpp" #include "../core/String.hpp" #include "../drawing/X8DrawingEngine.h" #include "../localisation/Localisation.h" #include "../localisation/StringIds.h" #include "../management/Finance.h" #include "../network/network.h" +#include "../object/FootpathObject.h" #include "../object/FootpathSurfaceObject.h" #include "../object/ObjectList.h" #include "../object/ObjectManager.h" @@ -57,6 +59,7 @@ #include "RideData.h" #include "Track.h" #include "TrackData.h" +#include "TrackDesign.h" #include "TrackDesignRepository.h" #include "Vehicle.h" @@ -181,9 +184,10 @@ rct_string_id TrackDesign::CreateTrackDesignTrack(const Ride& ride) auto trackType = trackElement.element->AsTrack()->GetTrackType(); uint8_t direction = trackElement.element->GetDirection(); _saveDirection = direction; - auto newCoords = sub_6C683D({ trackElement, z, direction }, trackType, 0, &trackElement.element, 0); + auto newCoords = GetTrackElementOriginAndApplyChanges( + { trackElement, z, direction }, trackType, 0, &trackElement.element, 0); - if (newCoords == std::nullopt) + if (!newCoords.has_value()) { return STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; } @@ -237,9 +241,10 @@ rct_string_id TrackDesign::CreateTrackDesignTrack(const Ride& ride) z = trackElement.element->GetBaseZ(); direction = trackElement.element->GetDirection(); trackType = trackElement.element->AsTrack()->GetTrackType(); - newCoords = sub_6C683D({ trackElement, z, direction }, trackType, 0, &trackElement.element, 0); + newCoords = GetTrackElementOriginAndApplyChanges( + { trackElement, z, direction }, trackType, 0, &trackElement.element, 0); - if (newCoords == std::nullopt) + if (!newCoords.has_value()) { break; } @@ -270,7 +275,7 @@ rct_string_id TrackDesign::CreateTrackDesignTrack(const Ride& ride) location = ride_get_exit_location(&ride, station_index); } - if (location.isNull()) + if (location.IsNull()) { continue; } @@ -324,7 +329,7 @@ rct_string_id TrackDesign::CreateTrackDesignTrack(const Ride& ride) } } - place_virtual_track(this, PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(0), { 4096, 4096, 0 }); + place_virtual_track(this, PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(PreviewRideId), { 4096, 4096, 0 }); // Resave global vars for scenery reasons. _trackPreviewOrigin = startPos; @@ -384,7 +389,7 @@ rct_string_id TrackDesign::CreateTrackDesignMaze(const Ride& ride) } auto location = ride_get_entrance_location(&ride, 0); - if (location.isNull()) + if (location.IsNull()) { return STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; } @@ -413,7 +418,7 @@ rct_string_id TrackDesign::CreateTrackDesignMaze(const Ride& ride) maze_elements.push_back(mazeEntrance); location = ride_get_exit_location(&ride, 0); - if (location.isNull()) + if (location.IsNull()) { return STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; } @@ -443,7 +448,7 @@ rct_string_id TrackDesign::CreateTrackDesignMaze(const Ride& ride) // Save global vars as they are still used by scenery???? int32_t startZ = _trackPreviewOrigin.z; - place_virtual_track(this, PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(0), { 4096, 4096, 0 }); + place_virtual_track(this, PTD_OPERATION_DRAW_OUTLINES, true, GetOrAllocateRide(PreviewRideId), { 4096, 4096, 0 }); _trackPreviewOrigin = { startLoc.x, startLoc.y, startZ }; gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT; @@ -1219,7 +1224,8 @@ static std::optional TrackDesignPlaceSceneryElement( z = (scenery.z * COORDS_Z_STEP + originZ) / COORDS_Z_STEP; if (mode == 0) { - auto isQueue = (scenery.flags & (1 << 7)) != 0; + auto isQueue = scenery.IsQueue(); + uint8_t bh = ((scenery.flags & 0xF) << rotation); flags = bh >> 4; bh = (bh | flags) & 0xF; @@ -1480,7 +1486,7 @@ static std::optional track_design_place_maze(TrackDesign* td6, const Co } break; default: - maze_entry = rol16(maze_element.maze_entry, rotation * 4); + maze_entry = Numerics::rol16(maze_element.maze_entry, rotation * 4); if (_trackDesignPlaceOperation == PTD_OPERATION_PLACE_TRACK_PREVIEW) { @@ -1833,7 +1839,7 @@ static std::optional track_design_place_ride(TrackDesign* td6, const Co if (_trackDesignPlaceOperation == PTD_OPERATION_REMOVE_GHOST) { - sub_6CB945(ride); + ride->ValidateStations(); ride->Delete(); } return totalCost; @@ -1994,7 +2000,8 @@ static bool track_design_place_preview(TrackDesign* td6, money32* cost, Ride** o int32_t mapSize = gMapSize << 4; _currentTrackPieceDirection = 0; - int32_t z = place_virtual_track(td6, PTD_OPERATION_GET_PLACE_Z, true, GetOrAllocateRide(0), { mapSize, mapSize, 16 }); + int32_t z = place_virtual_track( + td6, PTD_OPERATION_GET_PLACE_Z, true, GetOrAllocateRide(PreviewRideId), { mapSize, mapSize, 16 }); if (_trackDesignPlaceStateHasScenery) { diff --git a/src/openrct2/ride/TrackDesign.h b/src/openrct2/ride/TrackDesign.h index 6ef6ceadf0..c28bf26bb1 100644 --- a/src/openrct2/ride/TrackDesign.h +++ b/src/openrct2/ride/TrackDesign.h @@ -195,6 +195,8 @@ enum MAZE_ELEMENT_TYPE_EXIT = (1 << 7) }; +static constexpr ride_id_t PreviewRideId = static_cast(0); + extern bool gTrackDesignSceneryToggle; extern bool _trackDesignDrawingPreview; diff --git a/src/openrct2/ride/TrackDesignSave.cpp b/src/openrct2/ride/TrackDesignSave.cpp index ee06bd6731..7910276105 100644 --- a/src/openrct2/ride/TrackDesignSave.cpp +++ b/src/openrct2/ride/TrackDesignSave.cpp @@ -283,7 +283,7 @@ static TrackDesignAddStatus track_design_save_add_large_scenery(const CoordsXY& auto sceneryOrigin = map_large_scenery_get_origin( { loc.x, loc.y, z << 3, static_cast(direction) }, sequence, nullptr); - if (!sceneryOrigin) + if (!sceneryOrigin.has_value()) { return TrackDesignAddStatus::Success(); } diff --git a/src/openrct2/ride/TrackPaint.cpp b/src/openrct2/ride/TrackPaint.cpp index d197375027..39645719be 100644 --- a/src/openrct2/ride/TrackPaint.cpp +++ b/src/openrct2/ride/TrackPaint.cpp @@ -120,6 +120,20 @@ const uint32_t floorSpritesCork[] = { SPR_FLOOR_CORK }; +const uint32_t floorSpritesMetal[] = { + SPR_FLOOR_METAL, + SPR_FLOOR_METAL, + SPR_FLOOR_METAL, + SPR_FLOOR_METAL +}; + +const uint32_t floorSpritesMetalB[] = { + SPR_FLOOR_METAL_B, + SPR_FLOOR_METAL_B, + SPR_FLOOR_METAL_B, + SPR_FLOOR_METAL_B +}; + const uint32_t fenceSpritesRope[] = { SPR_FENCE_ROPE_NE, SPR_FENCE_ROPE_SE, @@ -127,6 +141,14 @@ const uint32_t fenceSpritesRope[] = { SPR_FENCE_ROPE_NW }; +const uint32_t fenceSpritesMetal[] = { + SPR_FENCE_METAL_NE, + SPR_FENCE_METAL_SE, + SPR_FENCE_METAL_SW, + SPR_FENCE_METAL_NW +}; + + const uint32_t fenceSpritesMetalB[] = { SPR_FENCE_METAL_B_NE, SPR_FENCE_METAL_B_SE, diff --git a/src/openrct2/ride/TrackPaint.h b/src/openrct2/ride/TrackPaint.h index 5f7139116e..6c28ff0e73 100644 --- a/src/openrct2/ride/TrackPaint.h +++ b/src/openrct2/ride/TrackPaint.h @@ -240,8 +240,11 @@ enum }; extern const uint32_t floorSpritesCork[]; +extern const uint32_t floorSpritesMetal[]; +extern const uint32_t floorSpritesMetalB[]; extern const uint32_t fenceSpritesRope[]; +extern const uint32_t fenceSpritesMetal[]; extern const uint32_t fenceSpritesMetalB[]; extern const uint32_t trackSpritesSubmarineRideMiniHelicoptersQuarterTurn3Tiles[4][3]; diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index daa3e934d5..9551f0847f 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -1600,14 +1600,14 @@ void Vehicle::UpdateMeasurements() curRide->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; curRide->lifecycle_flags &= ~RIDE_LIFECYCLE_TEST_IN_PROGRESS; ClearUpdateFlag(VEHICLE_UPDATE_FLAG_TESTING); - window_invalidate_by_number(WC_RIDE, ride); + window_invalidate_by_number(WC_RIDE, EnumValue(ride)); return; } if (curRide->current_test_station == STATION_INDEX_NULL) return; - if (!ride_get_entrance_location(curRide, curRide->current_test_station).isNull()) + if (!ride_get_entrance_location(curRide, curRide->current_test_station).IsNull()) { uint8_t test_segment = curRide->current_test_segment; @@ -1666,7 +1666,7 @@ void Vehicle::UpdateMeasurements() { curRide->CurTestTrackLocation = curTrackLoc; - if (ride_get_entrance_location(curRide, curRide->current_test_station).isNull()) + if (ride_get_entrance_location(curRide, curRide->current_test_station).IsNull()) return; auto trackElemType = GetTrackType(); @@ -1882,7 +1882,7 @@ void Vehicle::UpdateMeasurements() } } - if (ride_get_entrance_location(curRide, curRide->current_test_station).isNull()) + if (ride_get_entrance_location(curRide, curRide->current_test_station).IsNull()) return; if (x == LOCATION_NULL) @@ -2332,7 +2332,7 @@ void Vehicle::UpdateWaitingForPassengers() if (!OpenRestraints()) return; - if (ride_get_entrance_location(curRide, current_station).isNull()) + if (ride_get_entrance_location(curRide, current_station).IsNull()) { curRide->stations[current_station].TrainAtStation = RideStation::NO_TRAIN; sub_state = 2; @@ -2340,7 +2340,7 @@ void Vehicle::UpdateWaitingForPassengers() } auto trainIndex = ride_get_train_index_from_vehicle(curRide, sprite_index); - if (!trainIndex) + if (!trainIndex.has_value()) { return; } @@ -2348,7 +2348,7 @@ void Vehicle::UpdateWaitingForPassengers() if (curRide->stations[current_station].TrainAtStation != RideStation::NO_TRAIN) return; - curRide->stations[current_station].TrainAtStation = *trainIndex; + curRide->stations[current_station].TrainAtStation = trainIndex.value(); sub_state = 1; time_waiting = 0; @@ -2568,7 +2568,7 @@ void Vehicle::UpdateWaitingToDepart() } else { - if (!ride_get_exit_location(curRide, current_station).isNull()) + if (!ride_get_exit_location(curRide, current_station).IsNull()) { SetState(Vehicle::Status::UnloadingPassengers); return; @@ -2582,7 +2582,7 @@ void Vehicle::UpdateWaitingToDepart() { if (trainCar->num_peeps != 0) { - if (!ride_get_exit_location(curRide, current_station).isNull()) + if (!ride_get_exit_location(curRide, current_station).IsNull()) { SetState(Vehicle::Status::UnloadingPassengers); return; @@ -3114,7 +3114,7 @@ static void test_finish(Ride& ride) totalTime = std::max(totalTime, 1u); ride.average_speed = ride.average_speed / totalTime; - window_invalidate_by_number(WC_RIDE, ride.id); + window_invalidate_by_number(WC_RIDE, EnumValue(ride.id)); } void Vehicle::UpdateTestFinish() @@ -3144,7 +3144,7 @@ static void test_reset(Ride& ride, StationIndex curStation) ride.previous_vertical_g = 0; ride.previous_lateral_g = 0; ride.testing_flags = 0; - ride.CurTestTrackLocation.setNull(); + ride.CurTestTrackLocation.SetNull(); ride.turn_count_default = 0; ride.turn_count_banked = 0; ride.turn_count_sloped = 0; @@ -3164,7 +3164,7 @@ static void test_reset(Ride& ride, StationIndex curStation) } ride.total_air_time = 0; ride.current_test_station = curStation; - window_invalidate_by_number(WC_RIDE, ride.id); + window_invalidate_by_number(WC_RIDE, EnumValue(ride.id)); } void Vehicle::TestReset() @@ -3570,7 +3570,7 @@ void Vehicle::CheckIfMissing() curRide->FormatNameTo(ft); ft.Add(GetRideComponentName(GetRideTypeDescriptor(curRide->type).NameConvention.station).singular); - News::AddItemToQueue(News::ItemType::Ride, STR_NEWS_VEHICLE_HAS_STALLED, ride, ft); + News::AddItemToQueue(News::ItemType::Ride, STR_NEWS_VEHICLE_HAS_STALLED, EnumValue(ride), ft); } } @@ -3607,12 +3607,12 @@ void Vehicle::UpdateCollisionSetup() { auto frontVehicle = GetHead(); auto trainIndex = ride_get_train_index_from_vehicle(curRide, frontVehicle->sprite_index); - if (!trainIndex) + if (!trainIndex.has_value()) { return; } - curRide->Crash(*trainIndex); + curRide->Crash(trainIndex.value()); if (curRide->status != RideStatus::Closed) { @@ -4200,7 +4200,7 @@ void Vehicle::UpdateUnloadingPassengers() } else { - if (ride_get_exit_location(curRide, current_station).isNull()) + if (ride_get_exit_location(curRide, current_station).IsNull()) { if (sub_state != 1) return; @@ -4388,7 +4388,7 @@ void Vehicle::TryReconnectBoatToTrack(const CoordsXY& currentBoatLocation, const { SetTrackType(trackElement->GetTrackType()); SetTrackDirection(curRide->boat_hire_return_direction); - BoatLocation.setNull(); + BoatLocation.SetNull(); } track_progress = 0; @@ -5305,7 +5305,8 @@ static void ride_train_crash(Ride* ride, uint16_t numFatalities) { ride->FormatNameTo(ft); News::AddItemToQueue( - News::ItemType::Ride, numFatalities == 1 ? STR_X_PERSON_DIED_ON_X : STR_X_PEOPLE_DIED_ON_X, ride->id, ft); + News::ItemType::Ride, numFatalities == 1 ? STR_X_PERSON_DIED_ON_X : STR_X_PEOPLE_DIED_ON_X, EnumValue(ride->id), + ft); } if (gParkRatingCasualtyPenalty < 500) @@ -5381,12 +5382,12 @@ void Vehicle::CrashOnLand() { auto frontVehicle = GetHead(); auto trainIndex = ride_get_train_index_from_vehicle(curRide, frontVehicle->sprite_index); - if (!trainIndex) + if (!trainIndex.has_value()) { return; } - curRide->Crash(*trainIndex); + curRide->Crash(trainIndex.value()); if (curRide->status != RideStatus::Closed) { @@ -5447,12 +5448,12 @@ void Vehicle::CrashOnWater() { auto frontVehicle = GetHead(); auto trainIndex = ride_get_train_index_from_vehicle(curRide, frontVehicle->sprite_index); - if (!trainIndex) + if (!trainIndex.has_value()) { return; } - curRide->Crash(*trainIndex); + curRide->Crash(trainIndex.value()); if (curRide->status != RideStatus::Closed) { @@ -7124,50 +7125,6 @@ void Vehicle::UpdateSwingingCar() } } -#pragma region TrackTypeToSpinFunction - -enum -{ - NO_SPIN, - L8_SPIN, - R8_SPIN, - LR_SPIN, - RL_SPIN, - L7_SPIN, - R7_SPIN, - L5_SPIN, - R5_SPIN, - RC_SPIN, // Rotation Control Spin - SP_SPIN, // Special rapids Spin - L9_SPIN, - R9_SPIN -}; - -static const uint8_t TrackTypeToSpinFunction[TrackElemType::Count] = { - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, LR_SPIN, - RL_SPIN, NO_SPIN, NO_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, L5_SPIN, R5_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, LR_SPIN, RL_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, - L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, L5_SPIN, R5_SPIN, L5_SPIN, R5_SPIN, NO_SPIN, RC_SPIN, NO_SPIN, L8_SPIN, R8_SPIN, - L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, SP_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, R5_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, L9_SPIN, R9_SPIN, L9_SPIN, R9_SPIN, L9_SPIN, R9_SPIN, L9_SPIN, R9_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, L7_SPIN, R7_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, L7_SPIN, R7_SPIN, L7_SPIN, R7_SPIN, - L8_SPIN, R8_SPIN, L8_SPIN, R8_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, - NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN, NO_SPIN -}; - -#pragma endregion - /** * * rct2: 0x006D661F @@ -7192,7 +7149,9 @@ void Vehicle::UpdateSpinningCar() // An L spin adds to the spin speed, R does the opposite // The number indicates how much right shift of the velocity will become spin // The bigger the number the less change in spin. - switch (TrackTypeToSpinFunction[trackType]) + + const auto& ted = GetTrackElementDescriptor(trackType); + switch (ted.SpinFunction) { case RC_SPIN: // On a rotation control track element @@ -7601,7 +7560,8 @@ void Vehicle::UpdateLandscapeDoor() const static PitchAndRoll PitchAndRollStart(bool useInvertedSprites, TileElement* tileElement) { auto trackType = tileElement->AsTrack()->GetTrackType(); - return PitchAndRoll{ TrackDefinitions[trackType].vangle_start, track_get_actual_bank_3(useInvertedSprites, tileElement) }; + const auto& ted = GetTrackElementDescriptor(trackType); + return PitchAndRoll{ ted.Definition.vangle_start, track_get_actual_bank_3(useInvertedSprites, tileElement) }; } void Vehicle::UpdateGoKartAttemptSwitchLanes() @@ -8475,8 +8435,8 @@ loc_6DAEB9: static PitchAndRoll PitchAndRollEnd(Ride* curRide, bool useInvertedSprites, uint16_t trackType, TileElement* tileElement) { bool isInverted = useInvertedSprites ^ tileElement->AsTrack()->IsInverted(); - return { TrackDefinitions[trackType].vangle_end, - track_get_actual_bank_2(curRide->type, isInverted, TrackDefinitions[trackType].bank_end) }; + const auto& ted = GetTrackElementDescriptor(trackType); + return { ted.Definition.vangle_end, track_get_actual_bank_2(curRide->type, isInverted, ted.Definition.bank_end) }; } /** diff --git a/src/openrct2/ride/Vehicle.h b/src/openrct2/ride/Vehicle.h index bc04b53ddf..2146af930d 100644 --- a/src/openrct2/ride/Vehicle.h +++ b/src/openrct2/ride/Vehicle.h @@ -63,7 +63,7 @@ struct Vehicle : EntityBase Tail, }; - enum class Status + enum class Status : uint8_t { MovingToEndOfStation, WaitingForPassengers, diff --git a/src/openrct2/ride/gentle/Dodgems.cpp b/src/openrct2/ride/gentle/Dodgems.cpp index c960e9caf2..fc2a81f38b 100644 --- a/src/openrct2/ride/gentle/Dodgems.cpp +++ b/src/openrct2/ride/gentle/Dodgems.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../../interface/Viewport.h" +#include "../../object/StationObject.h" #include "../../paint/Paint.h" #include "../../paint/Supports.h" #include "../../util/Util.h" @@ -47,45 +48,52 @@ static void paint_dodgems( wooden_a_supports_paint_setup(session, direction & 1, 0, height, session->TrackColours[SCHEME_MISC]); - uint32_t imageId = SPR_DODGEMS_FLOOR | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 30, 30, 1 }, { 1, 1, height }); - + StationObject* stationObject = nullptr; if (ride != nullptr) - { - track_paint_util_paint_fences( - session, edges, session->MapPosition, trackElement, ride, session->TrackColours[SCHEME_SUPPORTS], height, - dodgems_fence_sprites, session->CurrentRotation); - } + stationObject = ride_get_station_object(ride); - switch (direction) + if (stationObject != nullptr && !(stationObject->Flags & STATION_OBJECT_FLAGS::NO_PLATFORMS)) { - case 2: - trackSequence = 15 - trackSequence; - [[fallthrough]]; - case 0: - if ((trackSequence / 4) & 1) - { - paint_dodgems_roof(session, height + 30, 0); - } - else - { - paint_dodgems_roof(session, height + 30, 2); - } - break; + uint32_t imageId = SPR_DODGEMS_FLOOR | session->TrackColours[SCHEME_SUPPORTS]; + PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 30, 30, 1 }, { 1, 1, height }); - case 3: - trackSequence = 15 - trackSequence; - [[fallthrough]]; - case 1: - if ((trackSequence / 4) & 1) - { - paint_dodgems_roof(session, height + 30, 1); - } - else - { - paint_dodgems_roof(session, height + 30, 3); - } - break; + if (ride != nullptr) + { + track_paint_util_paint_fences( + session, edges, session->MapPosition, trackElement, ride, session->TrackColours[SCHEME_SUPPORTS], height, + dodgems_fence_sprites, session->CurrentRotation); + } + + switch (direction) + { + case 2: + trackSequence = 15 - trackSequence; + [[fallthrough]]; + case 0: + if ((trackSequence / 4) & 1) + { + paint_dodgems_roof(session, height + 30, 0); + } + else + { + paint_dodgems_roof(session, height + 30, 2); + } + break; + + case 3: + trackSequence = 15 - trackSequence; + [[fallthrough]]; + case 1: + if ((trackSequence / 4) & 1) + { + paint_dodgems_roof(session, height + 30, 1); + } + else + { + paint_dodgems_roof(session, height + 30, 3); + } + break; + } } paint_util_set_segment_support_height(session, SEGMENTS_ALL, height + 36, 0x20); diff --git a/src/openrct2/ride/gentle/FlyingSaucers.cpp b/src/openrct2/ride/gentle/FlyingSaucers.cpp index bb974de89b..f19348b83b 100644 --- a/src/openrct2/ride/gentle/FlyingSaucers.cpp +++ b/src/openrct2/ride/gentle/FlyingSaucers.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../../interface/Viewport.h" +#include "../../object/StationObject.h" #include "../../paint/Paint.h" #include "../../paint/Supports.h" #include "../Track.h" @@ -42,8 +43,15 @@ static void paint_flying_saucers( wooden_a_supports_paint_setup(session, direction & 1, 0, height, session->TrackColours[SCHEME_MISC]); - uint32_t imageId = SPR_FLYING_SAUCERS_FLOOR | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 30, 30, 1 }, { 1, 1, height }); + StationObject* stationObject = nullptr; + if (ride != nullptr) + stationObject = ride_get_station_object(ride); + + if (stationObject != nullptr && !(stationObject->Flags & STATION_OBJECT_FLAGS::NO_PLATFORMS)) + { + uint32_t imageId = SPR_FLYING_SAUCERS_FLOOR | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 30, 30, 1 }, { 1, 1, height }); + } if (ride != nullptr) { diff --git a/src/openrct2/ride/gentle/Maze.cpp b/src/openrct2/ride/gentle/Maze.cpp index 51d75f9d5d..b46e1e4268 100644 --- a/src/openrct2/ride/gentle/Maze.cpp +++ b/src/openrct2/ride/gentle/Maze.cpp @@ -7,6 +7,7 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../../core/Numerics.hpp" #include "../../interface/Viewport.h" #include "../../paint/Paint.h" #include "../../paint/Supports.h" @@ -49,7 +50,7 @@ static void maze_paint_setup( const TrackElement& trackElement) { uint16_t maze_entry = trackElement.GetMazeEntry(); - maze_entry = rol16(maze_entry, direction * 4); + maze_entry = Numerics::rol16(maze_entry, direction * 4); uint32_t rotation = session->CurrentRotation; // draw ground diff --git a/src/openrct2/ride/gentle/ObservationTower.cpp b/src/openrct2/ride/gentle/ObservationTower.cpp index ac23f41455..375d460b17 100644 --- a/src/openrct2/ride/gentle/ObservationTower.cpp +++ b/src/openrct2/ride/gentle/ObservationTower.cpp @@ -94,8 +94,12 @@ static void paint_observation_tower_base( wooden_a_supports_paint_setup(session, (direction & 1), 0, height, session->TrackColours[SCHEME_MISC]); - uint32_t imageId = SPR_FLOOR_METAL_B | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }, { 0, 0, height }); + StationObject* stationObject = nullptr; + if (ride != nullptr) + stationObject = ride_get_station_object(ride); + + track_paint_util_paint_floor( + session, edges, session->TrackColours[SCHEME_SUPPORTS], height, floorSpritesMetalB, stationObject); if (ride != nullptr) { @@ -106,7 +110,7 @@ static void paint_observation_tower_base( if (trackSequence == 0) { - imageId = SPR_OBSERVATION_TOWER_SEGMENT_BASE | session->TrackColours[SCHEME_TRACK]; + uint32_t imageId = SPR_OBSERVATION_TOWER_SEGMENT_BASE | session->TrackColours[SCHEME_TRACK]; PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 2, 2, 27 }, { 8, 8, height + 3 }); imageId = SPR_OBSERVATION_TOWER_SEGMENT | session->TrackColours[SCHEME_TRACK]; diff --git a/src/openrct2/ride/gentle/SpiralSlide.cpp b/src/openrct2/ride/gentle/SpiralSlide.cpp index 8e895952f9..6e98da0ee9 100644 --- a/src/openrct2/ride/gentle/SpiralSlide.cpp +++ b/src/openrct2/ride/gentle/SpiralSlide.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../../interface/Viewport.h" +#include "../../object/StationObject.h" #include "../../paint/Paint.h" #include "../../paint/Supports.h" #include "../Track.h" @@ -201,8 +202,16 @@ static void paint_spiral_slide( wooden_a_supports_paint_setup(session, direction & 1, 0, height, session->TrackColours[SCHEME_MISC]); // Base - uint32_t imageId = ((direction & 1) ? SPIRAL_SLIDE_BASE_B : SPIRAL_SLIDE_BASE_A) | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }, { 0, 0, height }); + StationObject* stationObject = nullptr; + if (ride != nullptr) + stationObject = ride_get_station_object(ride); + + if (stationObject != nullptr && !(stationObject->Flags & STATION_OBJECT_FLAGS::NO_PLATFORMS)) + { + uint32_t imageId = ((direction & 1) ? SPIRAL_SLIDE_BASE_B : SPIRAL_SLIDE_BASE_A) + | session->TrackColours[SCHEME_SUPPORTS]; + PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }, { 0, 0, height }); + } if (ride != nullptr) { diff --git a/src/openrct2/ride/thrill/LaunchedFreefall.cpp b/src/openrct2/ride/thrill/LaunchedFreefall.cpp index 9309b5262e..d9dd4c7ae3 100644 --- a/src/openrct2/ride/thrill/LaunchedFreefall.cpp +++ b/src/openrct2/ride/thrill/LaunchedFreefall.cpp @@ -24,9 +24,6 @@ enum SPR_LAUNCHED_FREEFALL_TOWER_SEGMENT_TOP = 14566, }; -static constexpr const uint32_t launched_freefall_fence_sprites[] = { SPR_FENCE_METAL_NE, SPR_FENCE_METAL_SE, - SPR_FENCE_METAL_SW, SPR_FENCE_METAL_NW }; - /** * * rct2: 0x006D5FAB @@ -96,19 +93,23 @@ static void paint_launched_freefall_base( wooden_a_supports_paint_setup(session, (direction & 1), 0, height, session->TrackColours[SCHEME_MISC]); - uint32_t imageId = SPR_FLOOR_METAL | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }, { 0, 0, height }); + StationObject* stationObject = nullptr; + if (ride != nullptr) + stationObject = ride_get_station_object(ride); + + track_paint_util_paint_floor( + session, edges, session->TrackColours[SCHEME_SUPPORTS], height, floorSpritesMetal, stationObject); if (ride != nullptr) { track_paint_util_paint_fences( session, edges, session->MapPosition, trackElement, ride, session->TrackColours[SCHEME_TRACK], height, - launched_freefall_fence_sprites, session->CurrentRotation); + fenceSpritesMetal, session->CurrentRotation); } if (trackSequence == 0) { - imageId = SPR_LAUNCHED_FREEFALL_TOWER_BASE | session->TrackColours[SCHEME_TRACK]; + uint32_t imageId = SPR_LAUNCHED_FREEFALL_TOWER_BASE | session->TrackColours[SCHEME_TRACK]; PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 2, 2, 27 }, { 8, 8, height + 3 }); height += 32; diff --git a/src/openrct2/ride/thrill/MagicCarpet.cpp b/src/openrct2/ride/thrill/MagicCarpet.cpp index 44d609520f..36b1e2fc6e 100644 --- a/src/openrct2/ride/thrill/MagicCarpet.cpp +++ b/src/openrct2/ride/thrill/MagicCarpet.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../../interface/Viewport.h" +#include "../../object/StationObject.h" #include "../../paint/Paint.h" #include "../../paint/Supports.h" #include "../../world/Entity.h" @@ -237,9 +238,15 @@ static void paint_magic_carpet( metal_a_supports_paint_setup( session, METAL_SUPPORTS_TUBES, 8, 0, height, session->TrackColours[SCHEME_SUPPORTS]); } + StationObject* stationObject = nullptr; + if (ride != nullptr) + stationObject = ride_get_station_object(ride); - uint32_t imageId = SPR_STATION_BASE_D | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }); + if (stationObject != nullptr && !(stationObject->Flags & STATION_OBJECT_FLAGS::NO_PLATFORMS)) + { + uint32_t imageId = SPR_STATION_BASE_D | session->TrackColours[SCHEME_SUPPORTS]; + PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }); + } break; } diff --git a/src/openrct2/ride/thrill/RotoDrop.cpp b/src/openrct2/ride/thrill/RotoDrop.cpp index 0ff5bf1f9f..e2a7f15dd3 100644 --- a/src/openrct2/ride/thrill/RotoDrop.cpp +++ b/src/openrct2/ride/thrill/RotoDrop.cpp @@ -106,8 +106,12 @@ static void paint_roto_drop_base( wooden_a_supports_paint_setup(session, (direction & 1), 0, height, session->TrackColours[SCHEME_MISC]); - uint32_t imageId = SPR_FLOOR_METAL_B | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }, { 0, 0, height }); + StationObject* stationObject = nullptr; + if (ride != nullptr) + stationObject = ride_get_station_object(ride); + + track_paint_util_paint_floor( + session, edges, session->TrackColours[SCHEME_SUPPORTS], height, floorSpritesMetalB, stationObject); if (ride != nullptr) { @@ -118,7 +122,7 @@ static void paint_roto_drop_base( if (trackSequence == 0) { - imageId = (direction & 1 ? SPR_ROTO_DROP_TOWER_BASE_90_DEG : SPR_ROTO_DROP_TOWER_BASE) + uint32_t imageId = (direction & 1 ? SPR_ROTO_DROP_TOWER_BASE_90_DEG : SPR_ROTO_DROP_TOWER_BASE) | session->TrackColours[SCHEME_TRACK]; PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 2, 2, 27 }, { 8, 8, height + 3 }); diff --git a/src/openrct2/ride/thrill/SwingingInverterShip.cpp b/src/openrct2/ride/thrill/SwingingInverterShip.cpp index 4972e34039..faca18d95b 100644 --- a/src/openrct2/ride/thrill/SwingingInverterShip.cpp +++ b/src/openrct2/ride/thrill/SwingingInverterShip.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../../interface/Viewport.h" +#include "../../object/StationObject.h" #include "../../paint/Paint.h" #include "../../paint/Supports.h" #include "../../world/Entity.h" @@ -129,6 +130,10 @@ static void paint_swinging_inverter_ship( uint8_t relativeTrackSequence = track_map_1x4[direction][trackSequence]; uint32_t imageId; + StationObject* stationObject = nullptr; + if (ride != nullptr) + stationObject = ride_get_station_object(ride); + if (relativeTrackSequence != 1 && relativeTrackSequence != 3) { if (direction & 1) @@ -142,27 +147,30 @@ static void paint_swinging_inverter_ship( metal_a_supports_paint_setup(session, METAL_SUPPORTS_TUBES, 8, 0, height, session->TrackColours[SCHEME_SUPPORTS]); } - imageId = SPR_STATION_BASE_D | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }); - - switch (direction) + if (stationObject != nullptr && !(stationObject->Flags & STATION_OBJECT_FLAGS::NO_PLATFORMS)) { - case 0: - imageId = SPR_STATION_PLATFORM_SW_NE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 0, 24, height + 9 }, { 32, 8, 1 }); - break; - case 1: - imageId = SPR_STATION_PLATFORM_NW_SE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 24, 0, height + 9 }, { 8, 32, 1 }); - break; - case 2: - imageId = SPR_STATION_PLATFORM_SW_NE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsChild(session, imageId, 0, 0, 32, 8, 1, height + 9, -2, 0, height); - break; - case 3: - imageId = SPR_STATION_PLATFORM_NW_SE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsChild(session, imageId, 0, 0, 8, 32, 1, height + 9, 0, -2, height); - break; + imageId = SPR_STATION_BASE_D | session->TrackColours[SCHEME_SUPPORTS]; + PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }); + + switch (direction) + { + case 0: + imageId = SPR_STATION_PLATFORM_SW_NE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 0, 24, height + 9 }, { 32, 8, 1 }); + break; + case 1: + imageId = SPR_STATION_PLATFORM_NW_SE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 24, 0, height + 9 }, { 8, 32, 1 }); + break; + case 2: + imageId = SPR_STATION_PLATFORM_SW_NE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsChild(session, imageId, 0, 0, 32, 8, 1, height + 9, -2, 0, height); + break; + case 3: + imageId = SPR_STATION_PLATFORM_NW_SE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsChild(session, imageId, 0, 0, 8, 32, 1, height + 9, 0, -2, height); + break; + } } } diff --git a/src/openrct2/ride/thrill/SwingingShip.cpp b/src/openrct2/ride/thrill/SwingingShip.cpp index 2ee85c3713..a923b133b7 100644 --- a/src/openrct2/ride/thrill/SwingingShip.cpp +++ b/src/openrct2/ride/thrill/SwingingShip.cpp @@ -8,6 +8,7 @@ *****************************************************************************/ #include "../../interface/Viewport.h" +#include "../../object/StationObject.h" #include "../../paint/Paint.h" #include "../../paint/Supports.h" #include "../../world/Entity.h" @@ -184,6 +185,10 @@ static void paint_swinging_ship( uint32_t imageId; bool hasFence; + StationObject* stationObject = nullptr; + if (ride != nullptr) + stationObject = ride_get_station_object(ride); + if (relativeTrackSequence == 1 || relativeTrackSequence == 4) { wooden_a_supports_paint_setup(session, direction & 1, 0, height, session->TrackColours[SCHEME_SUPPORTS]); @@ -193,111 +198,123 @@ static void paint_swinging_ship( metal_a_supports_paint_setup(session, METAL_SUPPORTS_TUBES, 6, 0, height, session->TrackColours[SCHEME_SUPPORTS]); metal_a_supports_paint_setup(session, METAL_SUPPORTS_TUBES, 7, 0, height, session->TrackColours[SCHEME_SUPPORTS]); - imageId = SPR_STATION_BASE_A_NW_SE | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }); + if (stationObject != nullptr && !(stationObject->Flags & STATION_OBJECT_FLAGS::NO_PLATFORMS)) + { + imageId = SPR_STATION_BASE_A_NW_SE | session->TrackColours[SCHEME_SUPPORTS]; + PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }); + } } else { metal_a_supports_paint_setup(session, METAL_SUPPORTS_TUBES, 5, 0, height, session->TrackColours[SCHEME_SUPPORTS]); metal_a_supports_paint_setup(session, METAL_SUPPORTS_TUBES, 8, 0, height, session->TrackColours[SCHEME_SUPPORTS]); - imageId = SPR_STATION_BASE_A_SW_NE | session->TrackColours[SCHEME_SUPPORTS]; - PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }); + if (stationObject != nullptr && !(stationObject->Flags & STATION_OBJECT_FLAGS::NO_PLATFORMS)) + { + imageId = SPR_STATION_BASE_A_SW_NE | session->TrackColours[SCHEME_SUPPORTS]; + PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 32, 32, 1 }); + } } paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0); - if (direction & 1) + if (stationObject != nullptr && !(stationObject->Flags & STATION_OBJECT_FLAGS::NO_PLATFORMS)) { - if (relativeTrackSequence != 1 && relativeTrackSequence != 4) + if (direction & 1) { - hasFence = track_paint_util_has_fence(EDGE_NE, session->MapPosition, trackElement, ride, session->CurrentRotation); - if (relativeTrackSequence == 2) + if (relativeTrackSequence != 1 && relativeTrackSequence != 4) { - imageId = (hasFence ? SPR_STATION_PLATFORM_BEGIN_FENCED_NW_SE : SPR_STATION_PLATFORM_BEGIN_NW_SE) - | session->TrackColours[SCHEME_TRACK]; - } - else - { - imageId = (hasFence ? SPR_STATION_PLATFORM_FENCED_NW_SE : SPR_STATION_PLATFORM_NW_SE) - | session->TrackColours[SCHEME_TRACK]; - } - PaintAddImageAsChild(session, imageId, 0, 0, 8, 32, 1, height + 9, 0, -2, height + 9); - - imageId = (relativeTrackSequence == 2 ? SPR_STATION_PLATFORM_BEGIN_NW_SE : SPR_STATION_PLATFORM_NW_SE) - | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 24, 0, height + 9 }, { 8, 32, 1 }); - - hasFence = track_paint_util_has_fence(EDGE_SW, session->MapPosition, trackElement, ride, session->CurrentRotation); - if (relativeTrackSequence == 3) - { - if (hasFence) + hasFence = track_paint_util_has_fence( + EDGE_NE, session->MapPosition, trackElement, ride, session->CurrentRotation); + if (relativeTrackSequence == 2) { - imageId = SPR_STATION_BEGIN_ANGLE_FENCE_NW_SE | session->TrackColours[SCHEME_TRACK]; + imageId = (hasFence ? SPR_STATION_PLATFORM_BEGIN_FENCED_NW_SE : SPR_STATION_PLATFORM_BEGIN_NW_SE) + | session->TrackColours[SCHEME_TRACK]; + } + else + { + imageId = (hasFence ? SPR_STATION_PLATFORM_FENCED_NW_SE : SPR_STATION_PLATFORM_NW_SE) + | session->TrackColours[SCHEME_TRACK]; + } + PaintAddImageAsChild(session, imageId, 0, 0, 8, 32, 1, height + 9, 0, -2, height + 9); + + imageId = (relativeTrackSequence == 2 ? SPR_STATION_PLATFORM_BEGIN_NW_SE : SPR_STATION_PLATFORM_NW_SE) + | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 24, 0, height + 9 }, { 8, 32, 1 }); + + hasFence = track_paint_util_has_fence( + EDGE_SW, session->MapPosition, trackElement, ride, session->CurrentRotation); + if (relativeTrackSequence == 3) + { + if (hasFence) + { + imageId = SPR_STATION_BEGIN_ANGLE_FENCE_NW_SE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 31, 0, height + 11 }, { 1, 32, 7 }); + } + else + { + imageId = SPR_STATION_FENCE_SMALL_SW_NE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 23, 31, height + 11 }, { 8, 1, 7 }); + } + + imageId = SPR_STATION_FENCE_SMALL_SW_NE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 0, 31, height + 11 }, { 8, 1, 7 }); + } + else if (hasFence) + { + imageId = SPR_STATION_FENCE_NW_SE | session->TrackColours[SCHEME_TRACK]; PaintAddImageAsParent(session, imageId, { 31, 0, height + 11 }, { 1, 32, 7 }); } - else - { - imageId = SPR_STATION_FENCE_SMALL_SW_NE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 23, 31, height + 11 }, { 8, 1, 7 }); - } - - imageId = SPR_STATION_FENCE_SMALL_SW_NE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 0, 31, height + 11 }, { 8, 1, 7 }); - } - else if (hasFence) - { - imageId = SPR_STATION_FENCE_NW_SE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 31, 0, height + 11 }, { 1, 32, 7 }); } } - } - else - { - if (relativeTrackSequence != 1 && relativeTrackSequence != 4) + else { - hasFence = track_paint_util_has_fence(EDGE_NW, session->MapPosition, trackElement, ride, session->CurrentRotation); - if (relativeTrackSequence == 2) + if (relativeTrackSequence != 1 && relativeTrackSequence != 4) { - imageId = (hasFence ? SPR_STATION_PLATFORM_BEGIN_FENCED_SW_NE : SPR_STATION_PLATFORM_BEGIN_SW_NE) - | session->TrackColours[SCHEME_TRACK]; - } - else - { - imageId = (hasFence ? SPR_STATION_PLATFORM_FENCED_SW_NE : SPR_STATION_PLATFORM_SW_NE) - | session->TrackColours[SCHEME_TRACK]; - } - PaintAddImageAsChild(session, imageId, 0, 0, 32, 8, 1, height + 9, -2, 0, height + 9); - - imageId = (relativeTrackSequence == 2 ? SPR_STATION_PLATFORM_BEGIN_SW_NE : SPR_STATION_PLATFORM_SW_NE) - | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 0, 24, height + 9 }, { 32, 8, 1 }); - - hasFence = track_paint_util_has_fence(EDGE_SE, session->MapPosition, trackElement, ride, session->CurrentRotation); - if (relativeTrackSequence == 3) - { - if (hasFence) + hasFence = track_paint_util_has_fence( + EDGE_NW, session->MapPosition, trackElement, ride, session->CurrentRotation); + if (relativeTrackSequence == 2) { - imageId = SPR_STATION_BEGIN_ANGLE_FENCE_SW_NE | session->TrackColours[SCHEME_TRACK]; + imageId = (hasFence ? SPR_STATION_PLATFORM_BEGIN_FENCED_SW_NE : SPR_STATION_PLATFORM_BEGIN_SW_NE) + | session->TrackColours[SCHEME_TRACK]; + } + else + { + imageId = (hasFence ? SPR_STATION_PLATFORM_FENCED_SW_NE : SPR_STATION_PLATFORM_SW_NE) + | session->TrackColours[SCHEME_TRACK]; + } + PaintAddImageAsChild(session, imageId, 0, 0, 32, 8, 1, height + 9, -2, 0, height + 9); + + imageId = (relativeTrackSequence == 2 ? SPR_STATION_PLATFORM_BEGIN_SW_NE : SPR_STATION_PLATFORM_SW_NE) + | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 0, 24, height + 9 }, { 32, 8, 1 }); + + hasFence = track_paint_util_has_fence( + EDGE_SE, session->MapPosition, trackElement, ride, session->CurrentRotation); + if (relativeTrackSequence == 3) + { + if (hasFence) + { + imageId = SPR_STATION_BEGIN_ANGLE_FENCE_SW_NE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 0, 31, height + 11 }, { 32, 1, 7 }); + } + else + { + imageId = SPR_STATION_FENCE_SMALL_NW_SE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 31, 23, height + 11 }, { 1, 8, 7 }); + } + + imageId = SPR_STATION_FENCE_SMALL_NW_SE | session->TrackColours[SCHEME_TRACK]; + PaintAddImageAsParent(session, imageId, { 31, 0, height + 11 }, { 1, 8, 7 }); + } + else if (hasFence) + { + imageId = SPR_STATION_FENCE_SW_NE | session->TrackColours[SCHEME_TRACK]; PaintAddImageAsParent(session, imageId, { 0, 31, height + 11 }, { 32, 1, 7 }); } - else - { - imageId = SPR_STATION_FENCE_SMALL_NW_SE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 31, 23, height + 11 }, { 1, 8, 7 }); - } - - imageId = SPR_STATION_FENCE_SMALL_NW_SE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 31, 0, height + 11 }, { 1, 8, 7 }); - } - else if (hasFence) - { - imageId = SPR_STATION_FENCE_SW_NE | session->TrackColours[SCHEME_TRACK]; - PaintAddImageAsParent(session, imageId, { 0, 31, height + 11 }, { 32, 1, 7 }); } } } - switch (relativeTrackSequence) { case 1: diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp index 0818daadec..436ba884a7 100644 --- a/src/openrct2/scenario/ScenarioRepository.cpp +++ b/src/openrct2/scenario/ScenarioRepository.cpp @@ -19,6 +19,7 @@ #include "../core/FileIndex.hpp" #include "../core/FileStream.h" #include "../core/MemoryStream.h" +#include "../core/Numerics.hpp" #include "../core/Path.hpp" #include "../core/String.hpp" #include "../localisation/Language.h" @@ -547,7 +548,7 @@ private: // Rotate each byte of mp.dat left by 4 bits to convert for (size_t i = 0; i < mpdat.size(); i++) { - mpdat[i] = rol8(mpdat[i], 4); + mpdat[i] = Numerics::rol8(mpdat[i], 4); } File::WriteAllBytes(dstPath, mpdat.data(), mpdat.size()); diff --git a/src/openrct2/scripting/Duktape.hpp b/src/openrct2/scripting/Duktape.hpp index 37e69cc77c..51d77a2f1a 100644 --- a/src/openrct2/scripting/Duktape.hpp +++ b/src/openrct2/scripting/Duktape.hpp @@ -341,7 +341,7 @@ namespace OpenRCT2::Scripting template<> inline DukValue ToDuk(duk_context* ctx, const CoordsXYZ& value) { - if (value.isNull()) + if (value.IsNull()) { return ToDuk(ctx, nullptr); } @@ -366,14 +366,14 @@ namespace OpenRCT2::Scripting } else { - result.setNull(); + result.SetNull(); } return result; } template<> inline DukValue ToDuk(duk_context* ctx, const CoordsXYZD& value) { - if (value.isNull()) + if (value.IsNull()) { return ToDuk(ctx, nullptr); } @@ -408,7 +408,7 @@ namespace OpenRCT2::Scripting } else { - result.setNull(); + result.SetNull(); } return result; } diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index caf284513b..3f5cf95324 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -878,7 +878,7 @@ DukValue ScriptEngine::GameActionResultToDuk(const GameAction& action, const std { obj.Set("cost", result->Cost); } - if (!result->Position.isNull()) + if (!result->Position.IsNull()) { obj.Set("position", ToDuk(_context, result->Position)); } @@ -893,7 +893,7 @@ DukValue ScriptEngine::GameActionResultToDuk(const GameAction& action, const std auto& rideCreateResult = static_cast(*result.get()); if (rideCreateResult.rideIndex != RIDE_ID_NULL) { - obj.Set("ride", rideCreateResult.rideIndex); + obj.Set("ride", EnumValue(rideCreateResult.rideIndex)); } } else if (action.GetType() == GameCommand::HireNewStaffMember) diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index 404e7daffd..1e0c0db23b 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -46,7 +46,7 @@ namespace OpenRCT2 namespace OpenRCT2::Scripting { - static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 36; + static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 37; // Versions marking breaking changes. static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33; diff --git a/src/openrct2/scripting/bindings/entity/ScVehicle.cpp b/src/openrct2/scripting/bindings/entity/ScVehicle.cpp index 90389d7157..2f4be2efcb 100644 --- a/src/openrct2/scripting/bindings/entity/ScVehicle.cpp +++ b/src/openrct2/scripting/bindings/entity/ScVehicle.cpp @@ -135,18 +135,18 @@ namespace OpenRCT2::Scripting } } - ride_id_t ScVehicle::ride_get() const + int32_t ScVehicle::ride_get() const { auto vehicle = GetVehicle(); - return vehicle != nullptr ? vehicle->ride : 0; + return EnumValue(vehicle != nullptr ? vehicle->ride : RIDE_ID_NULL); } - void ScVehicle::ride_set(ride_id_t value) + void ScVehicle::ride_set(int32_t value) { ThrowIfGameStateNotMutable(); auto vehicle = GetVehicle(); if (vehicle != nullptr) { - vehicle->ride = value; + vehicle->ride = static_cast(value); } } diff --git a/src/openrct2/scripting/bindings/entity/ScVehicle.hpp b/src/openrct2/scripting/bindings/entity/ScVehicle.hpp index 57d29c6194..c98cd5b3dc 100644 --- a/src/openrct2/scripting/bindings/entity/ScVehicle.hpp +++ b/src/openrct2/scripting/bindings/entity/ScVehicle.hpp @@ -35,8 +35,8 @@ namespace OpenRCT2::Scripting uint8_t spriteType_get() const; void spriteType_set(uint8_t value); - ride_id_t ride_get() const; - void ride_set(ride_id_t value); + int32_t ride_get() const; + void ride_set(int32_t value); uint8_t numSeats_get() const; void numSeats_set(uint8_t value); diff --git a/src/openrct2/scripting/bindings/object/ScObject.hpp b/src/openrct2/scripting/bindings/object/ScObject.hpp index 763aa2d5cc..19f1b09399 100644 --- a/src/openrct2/scripting/bindings/object/ScObject.hpp +++ b/src/openrct2/scripting/bindings/object/ScObject.hpp @@ -60,23 +60,25 @@ namespace OpenRCT2::Scripting static std::string_view ObjectTypeToString(uint8_t type) { - static const char* Types[] = { "ride", - "small_scenery", - "large_scenery", - "wall", - "banner", - "footpath", - "footpath_addition", - "scenery_group", - "park_entrance", - "water", - "stex", - "terrain_surface", - "terrain_edge", - "station", - "music", - "footpath_surface", - "footpath_railings" }; + static constexpr std::string_view Types[] = { + "ride", + "small_scenery", + "large_scenery", + "wall", + "banner", + "footpath", + "footpath_addition", + "scenery_group", + "park_entrance", + "water", + "stex", + "terrain_surface", + "terrain_edge", + "station", + "music", + "footpath_surface", + "footpath_railings", + }; if (type >= std::size(Types)) return "unknown"; return Types[type]; diff --git a/src/openrct2/scripting/bindings/ride/ScRide.cpp b/src/openrct2/scripting/bindings/ride/ScRide.cpp index 34905f358c..6bdd07b4f7 100644 --- a/src/openrct2/scripting/bindings/ride/ScRide.cpp +++ b/src/openrct2/scripting/bindings/ride/ScRide.cpp @@ -27,7 +27,7 @@ namespace OpenRCT2::Scripting int32_t ScRide::id_get() const { - return _rideId; + return EnumValue(_rideId); } std::shared_ptr ScRide::object_get() diff --git a/src/openrct2/scripting/bindings/world/ScTileElement.cpp b/src/openrct2/scripting/bindings/world/ScTileElement.cpp index 4b130b782c..500a197618 100644 --- a/src/openrct2/scripting/bindings/world/ScTileElement.cpp +++ b/src/openrct2/scripting/bindings/world/ScTileElement.cpp @@ -427,7 +427,7 @@ namespace OpenRCT2::Scripting { auto el = _element->AsPath(); if (el->IsQueue() && el->GetRideIndex() != RIDE_ID_NULL) - duk_push_int(ctx, el->GetRideIndex()); + duk_push_int(ctx, EnumValue(el->GetRideIndex())); else duk_push_null(ctx); break; @@ -435,13 +435,13 @@ namespace OpenRCT2::Scripting case TILE_ELEMENT_TYPE_TRACK: { auto el = _element->AsTrack(); - duk_push_int(ctx, el->GetRideIndex()); + duk_push_int(ctx, EnumValue(el->GetRideIndex())); break; } case TILE_ELEMENT_TYPE_ENTRANCE: { auto el = _element->AsEntrance(); - duk_push_int(ctx, el->GetRideIndex()); + duk_push_int(ctx, EnumValue(el->GetRideIndex())); break; } default: @@ -452,7 +452,7 @@ namespace OpenRCT2::Scripting } return DukValue::take_from_stack(ctx); } - void ScTileElement::ride_set(ride_id_t value) + void ScTileElement::ride_set(int32_t value) { ThrowIfGameStateNotMutable(); switch (_element->GetType()) @@ -462,7 +462,7 @@ namespace OpenRCT2::Scripting auto el = _element->AsPath(); if (!el->HasAddition()) { - el->SetRideIndex(value); + el->SetRideIndex(static_cast(value)); Invalidate(); } break; @@ -470,14 +470,14 @@ namespace OpenRCT2::Scripting case TILE_ELEMENT_TYPE_TRACK: { auto el = _element->AsTrack(); - el->SetRideIndex(value); + el->SetRideIndex(static_cast(value)); Invalidate(); break; } case TILE_ELEMENT_TYPE_ENTRANCE: { auto el = _element->AsEntrance(); - el->SetRideIndex(value); + el->SetRideIndex(static_cast(value)); Invalidate(); break; } @@ -709,7 +709,7 @@ namespace OpenRCT2::Scripting case TILE_ELEMENT_TYPE_PATH: { auto el = _element->AsPath(); - duk_push_int(ctx, el->GetPathEntryIndex()); + duk_push_int(ctx, el->GetLegacyPathEntryIndex()); break; } case TILE_ELEMENT_TYPE_SMALL_SCENERY: @@ -755,7 +755,7 @@ namespace OpenRCT2::Scripting case TILE_ELEMENT_TYPE_PATH: { auto el = _element->AsPath(); - el->SetPathEntryIndex(index); + el->SetLegacyPathEntryIndex(index); Invalidate(); break; } @@ -1401,7 +1401,7 @@ namespace OpenRCT2::Scripting auto el = _element->AsEntrance(); if (el != nullptr) { - auto index = el->GetPathEntryIndex(); + auto index = el->GetLegacyPathEntryIndex(); if (index != OBJECT_ENTRY_INDEX_NULL) { duk_push_int(ctx, index); @@ -1423,7 +1423,7 @@ namespace OpenRCT2::Scripting auto el = _element->AsEntrance(); if (el != nullptr) { - el->SetPathEntryIndex(FromDuk(value)); + el->SetLegacyPathEntryIndex(FromDuk(value)); Invalidate(); } } diff --git a/src/openrct2/scripting/bindings/world/ScTileElement.hpp b/src/openrct2/scripting/bindings/world/ScTileElement.hpp index e069e037e4..feca670d5c 100644 --- a/src/openrct2/scripting/bindings/world/ScTileElement.hpp +++ b/src/openrct2/scripting/bindings/world/ScTileElement.hpp @@ -85,7 +85,7 @@ namespace OpenRCT2::Scripting void sequence_set(uint8_t value); DukValue ride_get() const; - void ride_set(ride_id_t value); + void ride_set(int32_t value); DukValue station_get() const; void station_set(uint8_t value); diff --git a/src/openrct2/util/SawyerCoding.cpp b/src/openrct2/util/SawyerCoding.cpp index b8c2fb586d..2c03a10910 100644 --- a/src/openrct2/util/SawyerCoding.cpp +++ b/src/openrct2/util/SawyerCoding.cpp @@ -9,6 +9,7 @@ #include "SawyerCoding.h" +#include "../core/Numerics.hpp" #include "../platform/platform.h" #include "../scenario/Scenario.h" #include "Util.h" @@ -113,10 +114,10 @@ size_t sawyercoding_decode_sc4(const uint8_t* src, uint8_t* dst, size_t length, for (size_t i = 0x60018; i <= std::min(decodedLength - 1, static_cast(0x1F8350)); i += 4) { - dst[i + 1] = ror8(dst[i + 1], 3); + dst[i + 1] = Numerics::ror8(dst[i + 1], 3); uint32_t* code = reinterpret_cast(&dst[i]); - *code = rol32(*code, 9); + *code = Numerics::rol32(*code, 9); } return decodedLength; @@ -148,7 +149,7 @@ size_t sawyercoding_encode_td6(const uint8_t* src, uint8_t* dst, size_t length) { uint8_t new_byte = ((checksum & 0xFF) + dst[i]) & 0xFF; checksum = (checksum & 0xFFFFFF00) + new_byte; - checksum = rol32(checksum, 3); + checksum = Numerics::rol32(checksum, 3); } checksum -= 0x1D4C1; @@ -167,7 +168,7 @@ int32_t sawyercoding_validate_track_checksum(const uint8_t* src, size_t length) { uint8_t new_byte = ((checksum & 0xFF) + src[i]) & 0xFF; checksum = (checksum & 0xFFFFFF00) + new_byte; - checksum = rol32(checksum, 3); + checksum = Numerics::rol32(checksum, 3); } if (checksum - 0x1D4C1 == file_checksum) @@ -383,7 +384,7 @@ static void encode_chunk_rotate(uint8_t* buffer, size_t length) uint8_t code = 1; for (i = 0; i < length; i++) { - buffer[i] = rol8(buffer[i], code); + buffer[i] = Numerics::rol8(buffer[i], code); code = (code + 2) % 8; } } @@ -401,7 +402,7 @@ int32_t sawyercoding_detect_file_type(const uint8_t* src, size_t length) for (i = 0; i < length - 4; i++) { actualChecksum = (actualChecksum & 0xFFFFFF00) | (((actualChecksum & 0xFF) + static_cast(src[i])) & 0xFF); - actualChecksum = rol32(actualChecksum, 3); + actualChecksum = Numerics::rol32(actualChecksum, 3); } return sawyercoding_detect_rct1_version(checksum - actualChecksum); diff --git a/src/openrct2/windows/_legacy.cpp b/src/openrct2/windows/_legacy.cpp index 2fb047ac62..12a005b4c5 100644 --- a/src/openrct2/windows/_legacy.cpp +++ b/src/openrct2/windows/_legacy.cpp @@ -311,7 +311,8 @@ bool window_ride_construction_update_state( if (alternativeType != TrackElemType::None && (availablePieces & (1ULL << trackType))) { trackType = alternativeType; - liftHillAndInvertedState &= ~CONSTRUCTION_LIFT_HILL_SELECTED; + if (!gCheatsEnableChainLiftOnAllTrack) + liftHillAndInvertedState &= ~CONSTRUCTION_LIFT_HILL_SELECTED; } } diff --git a/src/openrct2/world/Banner.cpp b/src/openrct2/world/Banner.cpp index 1d276df688..10d704a732 100644 --- a/src/openrct2/world/Banner.cpp +++ b/src/openrct2/world/Banner.cpp @@ -221,7 +221,7 @@ ride_id_t banner_get_closest_ride_index(const CoordsXYZ& mapPos) continue; auto rideCoords = ride.overall_view; - if (rideCoords.isNull()) + if (rideCoords.IsNull()) continue; int32_t distance = abs(mapPos.x - rideCoords.x) + abs(mapPos.y - rideCoords.y); diff --git a/src/openrct2/world/Entrance.cpp b/src/openrct2/world/Entrance.cpp index c8452de96d..38721d42b9 100644 --- a/src/openrct2/world/Entrance.cpp +++ b/src/openrct2/world/Entrance.cpp @@ -275,35 +275,40 @@ void EntranceElement::SetSequenceIndex(uint8_t newSequenceIndex) SequenceIndex |= (newSequenceIndex & 0xF); } -FootpathObject* EntranceElement::GetPathEntry() const +bool EntranceElement::HasLegacyPathEntry() const { - auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); - return static_cast(objMgr.GetLoadedObject(ObjectType::Paths, GetPathEntryIndex())); + return (flags2 & ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY) != 0; } -ObjectEntryIndex EntranceElement::GetPathEntryIndex() const +ObjectEntryIndex EntranceElement::GetLegacyPathEntryIndex() const { - if (flags2 & ENTRANCE_ELEMENT_FLAGS2_PATH_ENTRY) + if (HasLegacyPathEntry()) return PathType; else return OBJECT_ENTRY_INDEX_NULL; } -void EntranceElement::SetPathEntryIndex(ObjectEntryIndex newIndex) +const FootpathObject* EntranceElement::GetLegacyPathEntry() const { - PathType = newIndex; - flags2 |= ENTRANCE_ELEMENT_FLAGS2_PATH_ENTRY; + auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); + return static_cast(objMgr.GetLoadedObject(ObjectType::Paths, GetLegacyPathEntryIndex())); +} + +void EntranceElement::SetLegacyPathEntryIndex(ObjectEntryIndex newPathType) +{ + PathType = newPathType; + flags2 |= ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY; } ObjectEntryIndex EntranceElement::GetSurfaceEntryIndex() const { - if (flags2 & ENTRANCE_ELEMENT_FLAGS2_PATH_ENTRY) + if (HasLegacyPathEntry()) return OBJECT_ENTRY_INDEX_NULL; else return PathType; } -FootpathSurfaceObject* EntranceElement::GetSurfaceEntry() const +const FootpathSurfaceObject* EntranceElement::GetSurfaceEntry() const { auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); return static_cast(objMgr.GetLoadedObject(ObjectType::FootpathSurface, GetSurfaceEntryIndex())); @@ -312,5 +317,23 @@ FootpathSurfaceObject* EntranceElement::GetSurfaceEntry() const void EntranceElement::SetSurfaceEntryIndex(ObjectEntryIndex newIndex) { PathType = newIndex; - flags2 &= ~ENTRANCE_ELEMENT_FLAGS2_PATH_ENTRY; + flags2 &= ~ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY; +} + +const PathSurfaceDescriptor* EntranceElement::GetPathSurfaceDescriptor() const +{ + if (HasLegacyPathEntry()) + { + const auto* legacyPathEntry = GetLegacyPathEntry(); + if (legacyPathEntry == nullptr) + return nullptr; + + return &legacyPathEntry->GetPathSurfaceDescriptor(); + } + + const auto* surfaceEntry = GetSurfaceEntry(); + if (surfaceEntry == nullptr) + return nullptr; + + return &surfaceEntry->GetDescriptor(); } diff --git a/src/openrct2/world/Entrance.h b/src/openrct2/world/Entrance.h index 76b802da76..2874541a71 100644 --- a/src/openrct2/world/Entrance.h +++ b/src/openrct2/world/Entrance.h @@ -30,7 +30,7 @@ struct TileElement; enum { - ENTRANCE_ELEMENT_FLAGS2_PATH_ENTRY = (1 << 0), + ENTRANCE_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY = (1 << 0), }; constexpr const uint8_t ParkEntranceHeight = 12 * COORDS_Z_STEP; diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 4290b59ebf..a2bef0f98d 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -251,7 +251,7 @@ CoordsXY footpath_get_coordinates_from_pos(const ScreenCoordsXY& screenCoords, i if (window == nullptr || window->viewport == nullptr) { CoordsXY position{}; - position.setNull(); + position.SetNull(); return position; } auto viewport = window->viewport; @@ -264,7 +264,7 @@ CoordsXY footpath_get_coordinates_from_pos(const ScreenCoordsXY& screenCoords, i if (info.SpriteType == ViewportInteractionItem::None) { auto position = info.Loc; - position.setNull(); + position.SetNull(); return position; } } @@ -349,7 +349,7 @@ CoordsXY footpath_bridge_get_info_from_pos(const ScreenCoordsXY& screenCoords, i if (window == nullptr || window->viewport == nullptr) { CoordsXY ret{}; - ret.setNull(); + ret.SetNull(); return ret; } auto viewport = window->viewport; @@ -1226,7 +1226,7 @@ void footpath_update_queue_chains() for (int32_t i = 0; i < MAX_STATIONS; i++) { TileCoordsXYZD location = ride_get_entrance_location(ride, i); - if (location.isNull()) + if (location.IsNull()) continue; TileElement* tileElement = map_get_first_element_at(location.ToCoordsXY()); @@ -1649,13 +1649,7 @@ void PathElement::SetAdditionIsGhost(bool isGhost) Flags2 |= FOOTPATH_ELEMENT_FLAGS2_ADDITION_IS_GHOST; } -FootpathObject* PathElement::GetPathEntry() const -{ - auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); - return static_cast(objMgr.GetLoadedObject(ObjectType::Paths, GetPathEntryIndex())); -} - -ObjectEntryIndex PathElement::GetPathEntryIndex() const +ObjectEntryIndex PathElement::GetLegacyPathEntryIndex() const { if (Flags2 & FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY) return SurfaceIndex; @@ -1663,7 +1657,12 @@ ObjectEntryIndex PathElement::GetPathEntryIndex() const return OBJECT_ENTRY_INDEX_NULL; } -void PathElement::SetPathEntryIndex(ObjectEntryIndex newIndex) +const FootpathObject* PathElement::GetLegacyPathEntry() const +{ + return GetLegacyFootpathEntry(GetLegacyPathEntryIndex()); +} + +void PathElement::SetLegacyPathEntryIndex(ObjectEntryIndex newIndex) { SurfaceIndex = newIndex; RailingsIndex = OBJECT_ENTRY_INDEX_NULL; @@ -1675,6 +1674,45 @@ bool PathElement::HasLegacyPathEntry() const return (Flags2 & FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY) != 0; } +const PathSurfaceDescriptor* PathElement::GetSurfaceDescriptor() const +{ + if (HasLegacyPathEntry()) + { + const auto* legacyPathEntry = GetLegacyPathEntry(); + if (legacyPathEntry == nullptr) + return nullptr; + + if (IsQueue()) + return &legacyPathEntry->GetQueueSurfaceDescriptor(); + + return &legacyPathEntry->GetPathSurfaceDescriptor(); + } + + const auto* surfaceEntry = GetSurfaceEntry(); + if (surfaceEntry == nullptr) + return nullptr; + + return &surfaceEntry->GetDescriptor(); +} + +const PathRailingsDescriptor* PathElement::GetRailingsDescriptor() const +{ + if (HasLegacyPathEntry()) + { + const auto* legacyPathEntry = GetLegacyPathEntry(); + if (legacyPathEntry == nullptr) + return nullptr; + + return &legacyPathEntry->GetPathRailingsDescriptor(); + } + + const auto* railingsEntry = GetRailingsEntry(); + if (railingsEntry == nullptr) + return nullptr; + + return &railingsEntry->GetDescriptor(); +} + ObjectEntryIndex PathElement::GetSurfaceEntryIndex() const { if (Flags2 & FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY) @@ -1683,39 +1721,33 @@ ObjectEntryIndex PathElement::GetSurfaceEntryIndex() const return SurfaceIndex; } -ObjectEntryIndex PathElement::GetRailingEntryIndex() const -{ - if (Flags2 & FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY) - return OBJECT_ENTRY_INDEX_NULL; - else - return RailingsIndex; -} - -FootpathSurfaceObject* PathElement::GetSurfaceEntry() const +const FootpathSurfaceObject* PathElement::GetSurfaceEntry() const { auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); return static_cast(objMgr.GetLoadedObject(ObjectType::FootpathSurface, GetSurfaceEntryIndex())); } -FootpathRailingsObject* PathElement::GetRailingEntry() const -{ - auto entryIndex = GetRailingEntryIndex(); - if (entryIndex == OBJECT_ENTRY_INDEX_NULL) - { - return nullptr; - } - - auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); - return static_cast(objMgr.GetLoadedObject(ObjectType::FootpathRailings, entryIndex)); -} - void PathElement::SetSurfaceEntryIndex(ObjectEntryIndex newIndex) { SurfaceIndex = newIndex; Flags2 &= ~FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY; } -void PathElement::SetRailingEntryIndex(ObjectEntryIndex newEntryIndex) +ObjectEntryIndex PathElement::GetRailingsEntryIndex() const +{ + if (Flags2 & FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY) + return OBJECT_ENTRY_INDEX_NULL; + else + return RailingsIndex; +} + +const FootpathRailingsObject* PathElement::GetRailingsEntry() const +{ + auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); + return static_cast(objMgr.GetLoadedObject(ObjectType::FootpathRailings, GetRailingsEntryIndex())); +} + +void PathElement::SetRailingsEntryIndex(ObjectEntryIndex newEntryIndex) { RailingsIndex = newEntryIndex; Flags2 &= ~FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY; @@ -1732,6 +1764,17 @@ void PathElement::SetQueueBannerDirection(uint8_t direction) type |= (direction << 6); } +bool PathElement::ShouldDrawPathOverSupports() const +{ + // TODO: make this an actual decision of the tile element. + return (GetRailingsDescriptor()->Flags & RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS); +} + +void PathElement::SetShouldDrawPathOverSupports(bool on) +{ + log_verbose("Setting 'draw path over supports' to %d", static_cast(on)); +} + /** * * rct2: 0x006A8B12 @@ -2283,7 +2326,18 @@ void footpath_remove_edges_at(const CoordsXY& footpathPos, TileElement* tileElem tileElement->AsPath()->SetEdgesAndCorners(0); } -FootpathSurfaceObject* get_path_surface_entry(ObjectEntryIndex entryIndex) +const FootpathObject* GetLegacyFootpathEntry(ObjectEntryIndex entryIndex) +{ + auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); + auto obj = objMgr.GetLoadedObject(ObjectType::Paths, entryIndex); + if (obj == nullptr) + return nullptr; + + const FootpathObject* footpathObject = (static_cast(obj)); + return footpathObject; +} + +const FootpathSurfaceObject* GetPathSurfaceEntry(ObjectEntryIndex entryIndex) { auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); auto obj = objMgr.GetLoadedObject(ObjectType::FootpathSurface, entryIndex); @@ -2293,7 +2347,7 @@ FootpathSurfaceObject* get_path_surface_entry(ObjectEntryIndex entryIndex) return static_cast(obj); } -FootpathRailingsObject* get_path_railings_entry(ObjectEntryIndex entryIndex) +const FootpathRailingsObject* GetPathRailingsEntry(ObjectEntryIndex entryIndex) { auto& objMgr = OpenRCT2::GetContext()->GetObjectManager(); auto obj = objMgr.GetLoadedObject(ObjectType::FootpathRailings, entryIndex); diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index 9ec4c30e43..e1bacbbf55 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -13,6 +13,7 @@ #include "../interface/Viewport.h" #include "../object/Object.h" +class FootpathObject; class FootpathSurfaceObject; class FootpathRailingsObject; @@ -35,6 +36,13 @@ enum class RailingEntrySupportType : uint8_t Count }; +enum +{ + FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR = (1 << 2), + FOOTPATH_ENTRY_FLAG_IS_QUEUE = (1 << 3), + FOOTPATH_ENTRY_FLAG_NO_SLOPE_RAILINGS = (1 << 4), +}; + #pragma pack(push, 1) struct rct_footpath_entry { @@ -55,6 +63,12 @@ struct rct_footpath_entry } constexpr uint32_t GetQueuePreviewImage() const { + // Editor-only paths usually lack queue images. In this case, use the main path image. + if (flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR) + { + return GetPreviewImage(); + } + return image + 72; } constexpr uint32_t GetRailingsImage() const @@ -65,23 +79,50 @@ struct rct_footpath_entry assert_struct_size(rct_footpath_entry, 13); #pragma pack(pop) -struct PathSurfaceEntry +struct PathSurfaceDescriptor { - rct_string_id string_idx; - uint32_t image; - uint32_t preview; - uint8_t flags; + rct_string_id Name; + uint32_t Image; + uint32_t PreviewImage; + uint8_t Flags; + + inline constexpr bool IsEditorOnly() const + { + return Flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR; + } }; -struct PathRailingsEntry +struct PathRailingsDescriptor { - rct_string_id string_idx; - uint32_t preview; - uint32_t bridge_image; - uint32_t railings_image; - RailingEntrySupportType support_type; - uint8_t flags; - uint8_t scrolling_mode; + rct_string_id Name; + uint32_t PreviewImage; + uint32_t BridgeImage; + uint32_t RailingsImage; + RailingEntrySupportType SupportType; + colour_t SupportColour; + uint8_t Flags; + uint8_t ScrollingMode; +}; + +using PathConstructFlags = uint8_t; +namespace PathConstructFlag +{ + constexpr PathConstructFlags IsQueue = 1 << 0; + constexpr PathConstructFlags IsLegacyPathObject = 1 << 1; +} // namespace PathConstructFlag + +struct FootpathSelection +{ + ObjectEntryIndex LegacyPath = OBJECT_ENTRY_INDEX_NULL; + ObjectEntryIndex NormalSurface = OBJECT_ENTRY_INDEX_NULL; + ObjectEntryIndex QueueSurface = OBJECT_ENTRY_INDEX_NULL; + ObjectEntryIndex Railings = OBJECT_ENTRY_INDEX_NULL; + bool IsQueueSelected{}; + + ObjectEntryIndex GetSelectedSurface() const + { + return IsQueueSelected ? QueueSurface : NormalSurface; + } }; using PathConstructFlags = uint8_t; @@ -150,13 +191,6 @@ enum FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY = (1 << 5), }; -enum -{ - FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR = (1 << 2), - FOOTPATH_ENTRY_FLAG_IS_QUEUE = (1 << 3), - FOOTPATH_ENTRY_FLAG_NO_SLOPE_RAILINGS = (1 << 4), -}; - enum { RAILING_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE = (1 << 0), @@ -238,8 +272,9 @@ bool footpath_is_blocked_by_vehicle(const TileCoordsXYZ& position); int32_t footpath_is_connected_to_map_edge(const CoordsXYZ& footpathPos, int32_t direction, int32_t flags); void footpath_remove_edges_at(const CoordsXY& footpathPos, TileElement* tileElement); -FootpathSurfaceObject* get_path_surface_entry(ObjectEntryIndex entryIndex); -FootpathRailingsObject* get_path_railings_entry(ObjectEntryIndex entryIndex); +const FootpathObject* GetLegacyFootpathEntry(ObjectEntryIndex entryIndex); +const FootpathSurfaceObject* GetPathSurfaceEntry(ObjectEntryIndex entryIndex); +const FootpathRailingsObject* GetPathRailingsEntry(ObjectEntryIndex entryIndex); void footpath_queue_chain_reset(); void footpath_queue_chain_push(ride_id_t rideIndex); diff --git a/src/openrct2/world/Location.hpp b/src/openrct2/world/Location.hpp index c9f90a921b..55855570fc 100644 --- a/src/openrct2/world/Location.hpp +++ b/src/openrct2/world/Location.hpp @@ -215,12 +215,12 @@ struct CoordsXY return { floor2(x, COORDS_XY_STEP), floor2(y, COORDS_XY_STEP) }; } - constexpr bool isNull() const + constexpr bool IsNull() const { return x == COORDS_NULL; }; - constexpr void setNull() + constexpr void SetNull() { x = COORDS_NULL; y = 0; @@ -269,9 +269,9 @@ struct CoordsXYZ : public CoordsXY return ToTileStart() + CoordsXYZ{ COORDS_XY_HALF_TILE, COORDS_XY_HALF_TILE, 0 }; } - constexpr void setNull() + constexpr void SetNull() { - CoordsXY::setNull(); + CoordsXY::SetNull(); z = 0; } }; @@ -343,10 +343,10 @@ struct TileCoordsXY constexpr CoordsXY ToCoordsXY() const { - if (isNull()) + if (IsNull()) { CoordsXY ret{}; - ret.setNull(); + ret.SetNull(); return ret; } @@ -390,12 +390,12 @@ struct TileCoordsXY return !(*this == other); } - constexpr bool isNull() const + constexpr bool IsNull() const { return x == COORDS_NULL; }; - constexpr void setNull() + constexpr void SetNull() { x = COORDS_NULL; y = 0; @@ -457,18 +457,18 @@ struct TileCoordsXYZ : public TileCoordsXY constexpr CoordsXYZ ToCoordsXYZ() const { - if (isNull()) + if (IsNull()) { CoordsXYZ ret{}; - ret.setNull(); + ret.SetNull(); return ret; } return { x * COORDS_XY_STEP, y * COORDS_XY_STEP, z * COORDS_Z_STEP }; } - constexpr void setNull() + constexpr void SetNull() { - TileCoordsXY::setNull(); + TileCoordsXY::SetNull(); z = 0; } }; @@ -667,18 +667,18 @@ struct TileCoordsXYZD : public TileCoordsXYZ constexpr CoordsXYZD ToCoordsXYZD() const { - if (isNull()) + if (IsNull()) { CoordsXYZD ret{}; - ret.setNull(); + ret.SetNull(); return ret; } return { x * COORDS_XY_STEP, y * COORDS_XY_STEP, z * COORDS_Z_STEP, direction }; } - constexpr void setNull() + constexpr void SetNull() { - TileCoordsXYZ::setNull(); + TileCoordsXYZ::SetNull(); direction = INVALID_DIRECTION; } }; diff --git a/src/openrct2/world/MoneyEffect.cpp b/src/openrct2/world/MoneyEffect.cpp index e001459036..9bfe2b68c7 100644 --- a/src/openrct2/world/MoneyEffect.cpp +++ b/src/openrct2/world/MoneyEffect.cpp @@ -66,7 +66,7 @@ void MoneyEffect::CreateAt(money64 value, const CoordsXYZ& effectPos, bool verti void MoneyEffect::Create(money64 value, const CoordsXYZ& loc) { auto offsetLoc = loc; - if (loc.isNull()) + if (loc.IsNull()) { // If game actions return no valid location of the action we can not use the screen // coordinates as every client will have different ones. @@ -83,10 +83,10 @@ void MoneyEffect::Create(money64 value, const CoordsXYZ& loc) rct_viewport* mainViewport = window_get_viewport(mainWindow); auto mapPositionXY = screen_get_map_xy( { mainViewport->pos.x + (mainViewport->width / 2), mainViewport->pos.y + (mainViewport->height / 2) }, nullptr); - if (!mapPositionXY) + if (!mapPositionXY.has_value()) return; - offsetLoc = { *mapPositionXY, tile_element_height(*mapPositionXY) }; + offsetLoc = { mapPositionXY.value(), tile_element_height(*mapPositionXY) }; } offsetLoc.z += 10; CreateAt(-value, offsetLoc, false); diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index 58710151ec..f5063d00d8 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -743,8 +743,8 @@ template static void HistoryPushRecord(T history[TSize void Park::ResetHistories() { - std::fill(std::begin(gParkRatingHistory), std::end(gParkRatingHistory), std::numeric_limits::max()); - std::fill(std::begin(gGuestsInParkHistory), std::end(gGuestsInParkHistory), std::numeric_limits::max()); + std::fill(std::begin(gParkRatingHistory), std::end(gParkRatingHistory), ParkRatingHistoryUndefined); + std::fill(std::begin(gGuestsInParkHistory), std::end(gGuestsInParkHistory), GuestsInParkHistoryUndefined); } void Park::UpdateHistories() diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index 1b559009cf..7f27f77076 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -13,11 +13,11 @@ #include "../ride/Ride.h" #include "Map.h" -#define DECRYPT_MONEY(money) (static_cast(rol32((money) ^ 0xF4EC9621, 13))) -#define ENCRYPT_MONEY(money) (static_cast(ror32((money), 13) ^ 0xF4EC9621)) - #define MAX_ENTRANCE_FEE MONEY(200, 00) +constexpr const uint8_t ParkRatingHistoryUndefined = std::numeric_limits::max(); +constexpr const uint32_t GuestsInParkHistoryUndefined = std::numeric_limits::max(); + enum : uint32_t { PARK_FLAGS_PARK_OPEN = (1 << 0), diff --git a/src/openrct2/world/TileElement.h b/src/openrct2/world/TileElement.h index 064e49d437..43fee6930a 100644 --- a/src/openrct2/world/TileElement.h +++ b/src/openrct2/world/TileElement.h @@ -263,29 +263,32 @@ private: ObjectEntryIndex SurfaceIndex; // 5 ObjectEntryIndex RailingsIndex; // 7 uint8_t Additions; // 9 (0 means no addition) - uint8_t EdgesAndCorners; // 11 (edges in lower 4 bits, corners in upper 4) - uint8_t Flags2; // 12 - uint8_t SlopeDirection; // 13 + uint8_t EdgesAndCorners; // 10 (edges in lower 4 bits, corners in upper 4) + uint8_t Flags2; // 11 + uint8_t SlopeDirection; // 12 union { - uint8_t AdditionStatus; // 14, only used for litter bins - ride_id_t rideIndex; // 14 + uint8_t AdditionStatus; // 13, only used for litter bins + ride_id_t rideIndex; // 13 }; ::StationIndex StationIndex; // 15 public: - FootpathObject* GetPathEntry() const; - ObjectEntryIndex GetPathEntryIndex() const; - void SetPathEntryIndex(ObjectEntryIndex newIndex); + ObjectEntryIndex GetLegacyPathEntryIndex() const; + const FootpathObject* GetLegacyPathEntry() const; + void SetLegacyPathEntryIndex(ObjectEntryIndex newIndex); bool HasLegacyPathEntry() const; ObjectEntryIndex GetSurfaceEntryIndex() const; - FootpathSurfaceObject* GetSurfaceEntry() const; + const FootpathSurfaceObject* GetSurfaceEntry() const; void SetSurfaceEntryIndex(ObjectEntryIndex newIndex); - ObjectEntryIndex GetRailingEntryIndex() const; - FootpathRailingsObject* GetRailingEntry() const; - void SetRailingEntryIndex(ObjectEntryIndex newIndex); + ObjectEntryIndex GetRailingsEntryIndex() const; + const FootpathRailingsObject* GetRailingsEntry() const; + void SetRailingsEntryIndex(ObjectEntryIndex newIndex); + + const PathSurfaceDescriptor* GetSurfaceDescriptor() const; + const PathRailingsDescriptor* GetRailingsDescriptor() const; uint8_t GetQueueBannerDirection() const; void SetQueueBannerDirection(uint8_t direction); @@ -335,6 +338,9 @@ public: uint8_t GetAdditionStatus() const; void SetAdditionStatus(uint8_t newStatus); + bool ShouldDrawPathOverSupports() const; + void SetShouldDrawPathOverSupports(bool on); + bool IsLevelCrossing(const CoordsXY& coords) const; }; assert_struct_size(PathElement, 16); @@ -569,7 +575,7 @@ private: uint8_t flags2; // C #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" - uint8_t pad_0C[3]; + uint8_t pad_0D[3]; #pragma clang diagnostic pop public: @@ -585,14 +591,18 @@ public: uint8_t GetSequenceIndex() const; void SetSequenceIndex(uint8_t newSequenceIndex); - FootpathObject* GetPathEntry() const; - ObjectEntryIndex GetPathEntryIndex() const; - void SetPathEntryIndex(ObjectEntryIndex newIndex); + bool HasLegacyPathEntry() const; + + ObjectEntryIndex GetLegacyPathEntryIndex() const; + const FootpathObject* GetLegacyPathEntry() const; + void SetLegacyPathEntryIndex(ObjectEntryIndex newPathType); ObjectEntryIndex GetSurfaceEntryIndex() const; - FootpathSurfaceObject* GetSurfaceEntry() const; + const FootpathSurfaceObject* GetSurfaceEntry() const; void SetSurfaceEntryIndex(ObjectEntryIndex newIndex); + const PathSurfaceDescriptor* GetPathSurfaceDescriptor() const; + int32_t GetDirections() const; }; assert_struct_size(EntranceElement, 16); diff --git a/test/testpaint/Compat.cpp b/test/testpaint/Compat.cpp index 2d90873a28..117a0f0716 100644 --- a/test/testpaint/Compat.cpp +++ b/test/testpaint/Compat.cpp @@ -9,6 +9,7 @@ #include "Addresses.h" +#include #include #include #include @@ -72,18 +73,25 @@ uint8_t get_current_rotation() } int object_entry_group_counts[] = { - 128, // rides - 252, // small scenery - 128, // large scenery - 128, // walls - 32, // banners - 16, // paths - 15, // path bits - 19, // scenery sets - 1, // park entrance - 1, // water - 1 // scenario text + 128, // ObjectType::Ride + 252, // ObjectType::SmallScenery + 128, // ObjectType::LargeScenery + 128, // ObjectType::Walls + 32, // ObjectType::Banners + 16, // ObjectType::Paths + 15, // ObjectType::PathBits + 19, // ObjectType::SceneryGroup + 1, // ObjectType::ParkEntrance + 1, // ObjectType::Water + 1, // ObjectType::ScenarioText + 0, // ObjectType::TerrainSurface + 0, // ObjectType::TerrainEdge + 0, // ObjectType::Station + 0, // ObjectType::Music + 0, // ObjectType::FootpathSurface + 0, // ObjectType::FootpathRailings }; +static_assert(std::size(object_entry_group_counts) == EnumValue(ObjectType::Count)); GeneralConfiguration gConfigGeneral; uint16_t gMapSelectFlags; diff --git a/test/tests/Pathfinding.cpp b/test/tests/Pathfinding.cpp index df55e74b3e..c34ea49c8f 100644 --- a/test/tests/Pathfinding.cpp +++ b/test/tests/Pathfinding.cpp @@ -64,7 +64,7 @@ protected: return nullptr; } - static bool FindPath(TileCoordsXYZ* pos, const TileCoordsXYZ& goal, int expectedSteps, int targetRideID) + static bool FindPath(TileCoordsXYZ* pos, const TileCoordsXYZ& goal, int expectedSteps, ride_id_t targetRideID) { // Our start position is in tile coordinates, but we need to give the peep spawn // position in actual world coords (32 units per tile X/Y, 8 per Z level).