diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 0208bbd933..ba845825b4 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -9,6 +9,7 @@ - Feature: [#14731] Opaque water (like in RCT1). - Change: [#14496] [Plugin] Rename Object to LoadedObject to fix conflicts with Typescript's Object interface. - Change: [#14536] [Plugin] Rename ListView to ListViewWidget to make it consistent with names of other widgets. +- Change: [#14751] “No construction above tree height” limitation now allows placing high trees. - Fix: [#11829] Visual glitches and crashes when using RCT1 assets from mismatched or corrupt CSG1.DAT and CSG1i.DAT files. - Fix: [#13581] Opening the Options menu causes a noticeable drop in FPS. - Fix: [#13894] Block brakes do not animate. diff --git a/src/openrct2-ui/interface/ViewportInteraction.cpp b/src/openrct2-ui/interface/ViewportInteraction.cpp index 5ecd8b11d6..a554534f57 100644 --- a/src/openrct2-ui/interface/ViewportInteraction.cpp +++ b/src/openrct2-ui/interface/ViewportInteraction.cpp @@ -275,7 +275,7 @@ InteractionInfo ViewportInteractionGetItemRight(const ScreenCoordsXY& screenCoor return info; } ride = get_ride(vehicle->ride); - if (ride != nullptr && ride->status == RIDE_STATUS_CLOSED) + if (ride != nullptr && ride->status == RideStatus::Closed) { auto ft = Formatter(); ft.Add(STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); @@ -304,7 +304,7 @@ InteractionInfo ViewportInteractionGetItemRight(const ScreenCoordsXY& screenCoor return info; } - if (ride->status != RIDE_STATUS_CLOSED) + if (ride->status != RideStatus::Closed) return info; auto ft = Formatter(); diff --git a/src/openrct2-ui/windows/EditorBottomToolbar.cpp b/src/openrct2-ui/windows/EditorBottomToolbar.cpp index 5092053aae..7528a2bcff 100644 --- a/src/openrct2-ui/windows/EditorBottomToolbar.cpp +++ b/src/openrct2-ui/windows/EditorBottomToolbar.cpp @@ -176,14 +176,14 @@ static bool window_editor_bottom_toolbar_check_object_selection() { rct_window* w; - ObjectType missingObjectType = Editor::CheckObjectSelection(); + auto [missingObjectType, errorString] = Editor::CheckObjectSelection(); if (missingObjectType == ObjectType::None) { window_close_by_class(WC_EDITOR_OBJECT_SELECTION); return true; } - context_show_error(STR_INVALID_SELECTION_OF_OBJECTS, gGameCommandErrorText, {}); + context_show_error(STR_INVALID_SELECTION_OF_OBJECTS, errorString, {}); w = window_find_by_class(WC_EDITOR_OBJECT_SELECTION); if (w != nullptr) { @@ -219,7 +219,8 @@ void window_editor_bottom_toolbar_jump_forward_from_object_selection() */ void window_editor_bottom_toolbar_jump_forward_to_invention_list_set_up() { - if (Editor::CheckPark()) + auto [checksPassed, errorString] = Editor::CheckPark(); + if (checksPassed) { window_close_all(); context_open_window(WC_EDITOR_INVENTION_LIST); @@ -227,7 +228,7 @@ void window_editor_bottom_toolbar_jump_forward_to_invention_list_set_up() } else { - context_show_error(STR_CANT_ADVANCE_TO_NEXT_EDITOR_STAGE, gGameCommandErrorText, {}); + context_show_error(STR_CANT_ADVANCE_TO_NEXT_EDITOR_STAGE, errorString, {}); } gfx_invalidate_screen(); diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp index 496fb65980..9b5a9f1de2 100644 --- a/src/openrct2-ui/windows/MazeConstruction.cpp +++ b/src/openrct2-ui/windows/MazeConstruction.cpp @@ -292,7 +292,7 @@ static void window_maze_construction_mousedown(rct_window* w, rct_widgetindex wi static void window_maze_construction_update(rct_window* w) { auto ride = get_ride(_currentRideIndex); - if (ride == nullptr || ride->status != RIDE_STATUS_CLOSED) + if (ride == nullptr || ride->status != RideStatus::Closed) { window_close(w); return; diff --git a/src/openrct2-ui/windows/NewCampaign.cpp b/src/openrct2-ui/windows/NewCampaign.cpp index fc0b0a2ac6..cdd7d2e63b 100644 --- a/src/openrct2-ui/windows/NewCampaign.cpp +++ b/src/openrct2-ui/windows/NewCampaign.cpp @@ -126,7 +126,7 @@ public: RideList.clear(); for (const auto& curRide : GetRideManager()) { - if (curRide.status == RIDE_STATUS_OPEN) + if (curRide.status == RideStatus::Open) { if (!curRide.GetRideTypeDescriptor().HasFlag( RIDE_TYPE_FLAG_IS_SHOP | RIDE_TYPE_FLAG_SELLS_FOOD | RIDE_TYPE_FLAG_SELLS_DRINKS diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index d2fa1b1bd2..8798d50b2c 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -1758,21 +1758,21 @@ static void window_ride_main_mouseup(rct_window* w, rct_widgetindex widgetIndex) auto ride = get_ride(w->number); if (ride != nullptr) { - int32_t status; + RideStatus status; switch (widgetIndex) { default: case WIDX_CLOSE_LIGHT: - status = RIDE_STATUS_CLOSED; + status = RideStatus::Closed; break; case WIDX_SIMULATE_LIGHT: - status = RIDE_STATUS_SIMULATING; + status = RideStatus::Simulating; break; case WIDX_TEST_LIGHT: - status = RIDE_STATUS_TESTING; + status = RideStatus::Testing; break; case WIDX_OPEN_LIGHT: - status = RIDE_STATUS_OPEN; + status = RideStatus::Open; break; } ride_set_status(ride, status); @@ -1797,12 +1797,12 @@ static void window_ride_main_resize(rct_window* w) if (ride != nullptr) { #ifdef __SIMULATE_IN_RIDE_WINDOW__ - if (ride->SupportsStatus(RIDE_STATUS_SIMULATING)) + if (ride->SupportsStatus(RideStatus::Simulating)) { minHeight += 14; } #endif - if (ride->SupportsStatus(RIDE_STATUS_TESTING)) + if (ride->SupportsStatus(RideStatus::Testing)) { minHeight += 14; } @@ -1880,46 +1880,46 @@ static void window_ride_show_view_dropdown(rct_window* w, rct_widget* widget) Dropdown::SetChecked(w->viewport_focus_coordinates.var_480, true); } -static uint8_t window_ride_get_next_default_status(const Ride* ride) +static RideStatus window_ride_get_next_default_status(const Ride* ride) { switch (ride->status) { default: - case RIDE_STATUS_CLOSED: + case RideStatus::Closed: if ((ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) || (ride->lifecycle_flags & RIDE_LIFECYCLE_HAS_STALLED_VEHICLE)) { - return RIDE_STATUS_CLOSED; + return RideStatus::Closed; } - else if (ride->SupportsStatus(RIDE_STATUS_TESTING) && !(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + else if (ride->SupportsStatus(RideStatus::Testing) && !(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) { - return RIDE_STATUS_TESTING; + return RideStatus::Testing; } else { - return RIDE_STATUS_OPEN; + return RideStatus::Open; } - case RIDE_STATUS_SIMULATING: - return RIDE_STATUS_TESTING; - case RIDE_STATUS_TESTING: - return (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) ? RIDE_STATUS_OPEN : RIDE_STATUS_CLOSED; - case RIDE_STATUS_OPEN: - return RIDE_STATUS_CLOSED; + case RideStatus::Simulating: + return RideStatus::Testing; + case RideStatus::Testing: + return (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) ? RideStatus::Open : RideStatus::Closed; + case RideStatus::Open: + return RideStatus::Closed; } } struct RideStatusDropdownInfo { struct Ride* Ride{}; - uint8_t CurrentStatus{}; - uint8_t DefaultStatus{}; + RideStatus CurrentStatus{}; + RideStatus DefaultStatus{}; int32_t NumItems{}; int32_t CheckedIndex = -1; int32_t DefaultIndex = -1; }; -static void window_ride_set_dropdown(RideStatusDropdownInfo& info, uint8_t status, rct_string_id text) +static void window_ride_set_dropdown(RideStatusDropdownInfo& info, RideStatus status, rct_string_id text) { if (info.Ride->SupportsStatus(status)) { @@ -1947,12 +1947,12 @@ static void window_ride_show_open_dropdown(rct_window* w, rct_widget* widget) info.CurrentStatus = info.Ride->status; info.DefaultStatus = window_ride_get_next_default_status(info.Ride); - window_ride_set_dropdown(info, RIDE_STATUS_CLOSED, STR_CLOSE_RIDE); + window_ride_set_dropdown(info, RideStatus::Closed, STR_CLOSE_RIDE); #ifdef __SIMULATE_IN_RIDE_WINDOW__ - window_ride_set_dropdown(info, RIDE_STATUS_SIMULATING, STR_SIMULATE_RIDE); + window_ride_set_dropdown(info, RideStatus::Simulating, STR_SIMULATE_RIDE); #endif - window_ride_set_dropdown(info, RIDE_STATUS_TESTING, STR_TEST_RIDE); - window_ride_set_dropdown(info, RIDE_STATUS_OPEN, STR_OPEN_RIDE); + window_ride_set_dropdown(info, RideStatus::Testing, STR_TEST_RIDE); + window_ride_set_dropdown(info, RideStatus::Open, STR_OPEN_RIDE); WindowDropdownShowText( { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, info.NumItems); Dropdown::SetChecked(info.CheckedIndex, true); @@ -2196,7 +2196,7 @@ static void window_ride_main_dropdown(rct_window* w, rct_widgetindex widgetIndex auto ride = get_ride(w->number); if (ride != nullptr) { - auto status = RIDE_STATUS_CLOSED; + auto status = RideStatus::Closed; if (dropdownIndex < 0) { dropdownIndex = gDropdownHighlightedIndex; @@ -2206,16 +2206,16 @@ static void window_ride_main_dropdown(rct_window* w, rct_widgetindex widgetIndex switch (gDropdownItemsArgs[dropdownIndex]) { case STR_CLOSE_RIDE: - status = RIDE_STATUS_CLOSED; + status = RideStatus::Closed; break; case STR_SIMULATE_RIDE: - status = RIDE_STATUS_SIMULATING; + status = RideStatus::Simulating; break; case STR_TEST_RIDE: - status = RIDE_STATUS_TESTING; + status = RideStatus::Testing; break; case STR_OPEN_RIDE: - status = RIDE_STATUS_OPEN; + status = RideStatus::Open; break; } } @@ -2342,25 +2342,25 @@ static void window_ride_main_invalidate(rct_window* w) SPR_TESTING, SPR_G2_SIMULATE, }; - window_ride_main_widgets[WIDX_OPEN].image = spriteIds[ride->status]; + window_ride_main_widgets[WIDX_OPEN].image = spriteIds[EnumValue(ride->status)]; #ifdef __SIMULATE_IN_RIDE_WINDOW__ - window_ride_main_widgets[WIDX_CLOSE_LIGHT].image = SPR_G2_RCT1_CLOSE_BUTTON_0 + (ride->status == RIDE_STATUS_CLOSED) * 2 + window_ride_main_widgets[WIDX_CLOSE_LIGHT].image = SPR_G2_RCT1_CLOSE_BUTTON_0 + (ride->status == RideStatus::Closed) * 2 + WidgetIsPressed(w, WIDX_CLOSE_LIGHT); window_ride_main_widgets[WIDX_SIMULATE_LIGHT].image = SPR_G2_RCT1_SIMULATE_BUTTON_0 - + (ride->status == RIDE_STATUS_SIMULATING) * 2 + WidgetIsPressed(w, WIDX_SIMULATE_LIGHT); - window_ride_main_widgets[WIDX_TEST_LIGHT].image = SPR_G2_RCT1_TEST_BUTTON_0 + (ride->status == RIDE_STATUS_TESTING) * 2 + + (ride->status == RideStatus::Simulating) * 2 + WidgetIsPressed(w, WIDX_SIMULATE_LIGHT); + window_ride_main_widgets[WIDX_TEST_LIGHT].image = SPR_G2_RCT1_TEST_BUTTON_0 + (ride->status == RideStatus::Testing) * 2 + WidgetIsPressed(w, WIDX_TEST_LIGHT); #else - window_ride_main_widgets[WIDX_CLOSE_LIGHT].image = SPR_G2_RCT1_CLOSE_BUTTON_0 + (ride->status == RIDE_STATUS_CLOSED) * 2 + window_ride_main_widgets[WIDX_CLOSE_LIGHT].image = SPR_G2_RCT1_CLOSE_BUTTON_0 + (ride->status == RideStatus::Closed) * 2 + WidgetIsPressed(w, WIDX_CLOSE_LIGHT); - auto baseSprite = ride->status == RIDE_STATUS_SIMULATING ? SPR_G2_RCT1_SIMULATE_BUTTON_0 : SPR_G2_RCT1_TEST_BUTTON_0; + auto baseSprite = ride->status == RideStatus::Simulating ? SPR_G2_RCT1_SIMULATE_BUTTON_0 : SPR_G2_RCT1_TEST_BUTTON_0; window_ride_main_widgets[WIDX_TEST_LIGHT].image = baseSprite - + (ride->status == RIDE_STATUS_TESTING || ride->status == RIDE_STATUS_SIMULATING) * 2 + + (ride->status == RideStatus::Testing || ride->status == RideStatus::Simulating) * 2 + WidgetIsPressed(w, WIDX_TEST_LIGHT); #endif - window_ride_main_widgets[WIDX_OPEN_LIGHT].image = SPR_G2_RCT1_OPEN_BUTTON_0 + (ride->status == RIDE_STATUS_OPEN) * 2 + window_ride_main_widgets[WIDX_OPEN_LIGHT].image = SPR_G2_RCT1_OPEN_BUTTON_0 + (ride->status == RideStatus::Open) * 2 + WidgetIsPressed(w, WIDX_OPEN_LIGHT); window_ride_anchor_border_widgets(w); @@ -2403,10 +2403,10 @@ static void window_ride_main_invalidate(rct_window* w) window_ride_main_widgets[WIDX_CLOSE_LIGHT].type = WindowWidgetType::ImgBtn; window_ride_main_widgets[WIDX_SIMULATE_LIGHT].type = WindowWidgetType::Empty; #ifdef __SIMULATE_IN_RIDE_WINDOW__ - if (ride->SupportsStatus(RIDE_STATUS_SIMULATING)) + if (ride->SupportsStatus(RideStatus::Simulating)) window_ride_main_widgets[WIDX_SIMULATE_LIGHT].type = WindowWidgetType::ImgBtn; #endif - window_ride_main_widgets[WIDX_TEST_LIGHT].type = ride->SupportsStatus(RIDE_STATUS_TESTING) ? WindowWidgetType::ImgBtn + window_ride_main_widgets[WIDX_TEST_LIGHT].type = ride->SupportsStatus(RideStatus::Testing) ? WindowWidgetType::ImgBtn : WindowWidgetType::Empty; window_ride_main_widgets[WIDX_OPEN_LIGHT].type = WindowWidgetType::ImgBtn; @@ -2540,7 +2540,7 @@ static rct_string_id window_ride_get_status_station(rct_window* w, Formatter& ft } while (count >= 0); // Entrance / exit - if (ride->status == RIDE_STATUS_CLOSED) + if (ride->status == RideStatus::Closed) { if (ride_get_entrance_location(ride, static_cast(stationIndex)).isNull()) stringId = STR_NO_ENTRANCE; @@ -3921,7 +3921,7 @@ static void window_ride_maintenance_dropdown(rct_window* w, rct_widgetindex widg { context_show_error(STR_DEBUG_CANT_FORCE_BREAKDOWN, STR_DEBUG_RIDE_ALREADY_BROKEN, {}); } - else if (ride->status == RIDE_STATUS_CLOSED) + else if (ride->status == RideStatus::Closed) { context_show_error(STR_DEBUG_CANT_FORCE_BREAKDOWN, STR_DEBUG_RIDE_IS_CLOSED, {}); } diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 8abb0d5653..7cf2b5f06a 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -610,7 +610,7 @@ static void window_ride_construction_close(rct_window* w) if (!_autoOpeningShop) { _autoOpeningShop = true; - ride_set_status(ride, RIDE_STATUS_OPEN); + ride_set_status(ride, RideStatus::Open); _autoOpeningShop = false; } } @@ -669,7 +669,7 @@ static void window_ride_construction_mouseup(rct_window* w, rct_widgetindex widg auto ride = get_ride(_currentRideIndex); if (ride != nullptr) { - auto status = ride->status == RIDE_STATUS_SIMULATING ? RIDE_STATUS_CLOSED : RIDE_STATUS_SIMULATING; + auto status = ride->status == RideStatus::Simulating ? RideStatus::Closed : RideStatus::Simulating; ride_set_status(ride, status); } break; @@ -2036,7 +2036,7 @@ static void window_ride_construction_update(rct_window* w) // Close construction window if ride is not closed, // editing ride while open will cause many issues until properly handled - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + if (ride->status != RideStatus::Closed && ride->status != RideStatus::Simulating) { window_close(w); return; @@ -2269,10 +2269,10 @@ static void window_ride_construction_invalidate(rct_window* w) // Simulate button auto& simulateWidget = w->widgets[WIDX_SIMULATE]; simulateWidget.type = WindowWidgetType::Empty; - if (ride->SupportsStatus(RIDE_STATUS_SIMULATING)) + if (ride->SupportsStatus(RideStatus::Simulating)) { simulateWidget.type = WindowWidgetType::FlatBtn; - if (ride->status == RIDE_STATUS_SIMULATING) + if (ride->status == RideStatus::Simulating) { w->pressed_widgets |= (1ULL << WIDX_SIMULATE); } diff --git a/src/openrct2-ui/windows/RideList.cpp b/src/openrct2-ui/windows/RideList.cpp index 12a8d337bc..5ca445f2f6 100644 --- a/src/openrct2-ui/windows/RideList.cpp +++ b/src/openrct2-ui/windows/RideList.cpp @@ -517,10 +517,10 @@ static void window_ride_list_invalidate(rct_window* w) { auto c = static_cast(w->page); allClosed = std::none_of(rideManager.begin(), rideManager.end(), [c](const Ride& ride) { - return ride.GetClassification() == c && ride.status == RIDE_STATUS_OPEN; + return ride.GetClassification() == c && ride.status == RideStatus::Open; }); allOpen = std::none_of(rideManager.begin(), rideManager.end(), [c](const Ride& ride) { - return ride.GetClassification() == c && ride.status != RIDE_STATUS_OPEN; + return ride.GetClassification() == c && ride.status != RideStatus::Open; }); } @@ -797,7 +797,7 @@ void window_ride_list_refresh_list(rct_window* w) { auto ride = &ridec; if (ride->GetClassification() != static_cast(w->page) - || (ride->status == RIDE_STATUS_CLOSED && !ride_has_any_track_elements(ride))) + || (ride->status == RideStatus::Closed && !ride_has_any_track_elements(ride))) continue; if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_LIST) @@ -1021,9 +1021,9 @@ static void window_ride_list_close_all(rct_window* w) { for (auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_CLOSED && ride.GetClassification() == static_cast(w->page)) + if (ride.status != RideStatus::Closed && ride.GetClassification() == static_cast(w->page)) { - ride_set_status(&ride, RIDE_STATUS_CLOSED); + ride_set_status(&ride, RideStatus::Closed); } } } @@ -1032,9 +1032,9 @@ static void window_ride_list_open_all(rct_window* w) { for (auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_OPEN && ride.GetClassification() == static_cast(w->page)) + if (ride.status != RideStatus::Open && ride.GetClassification() == static_cast(w->page)) { - ride_set_status(&ride, RIDE_STATUS_OPEN); + ride_set_status(&ride, RideStatus::Open); } } } diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index f6a1159782..ea2b7e11f9 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -472,7 +472,7 @@ namespace Editor * * rct2: 0x006AB9B8 */ - ObjectType CheckObjectSelection() + std::pair CheckObjectSelection() { bool isTrackDesignerManager = gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER); @@ -480,62 +480,54 @@ namespace Editor { if (!editor_check_object_group_at_least_one_surface_selected(false)) { - gGameCommandErrorText = STR_AT_LEAST_ONE_FOOTPATH_NON_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED; - return ObjectType::FootpathSurface; + return { ObjectType::FootpathSurface, STR_AT_LEAST_ONE_FOOTPATH_NON_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED }; } if (!editor_check_object_group_at_least_one_surface_selected(true)) { - gGameCommandErrorText = STR_AT_LEAST_ONE_FOOTPATH_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED; - return ObjectType::FootpathSurface; + return { ObjectType::FootpathSurface, STR_AT_LEAST_ONE_FOOTPATH_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED }; } if (!editor_check_object_group_at_least_one_selected(ObjectType::FootpathRailings)) { - gGameCommandErrorText = STR_AT_LEAST_ONE_FOOTPATH_RAILING_OBJECT_MUST_BE_SELECTED; - return ObjectType::FootpathRailings; + return { ObjectType::FootpathRailings, STR_AT_LEAST_ONE_FOOTPATH_RAILING_OBJECT_MUST_BE_SELECTED }; } } if (!editor_check_object_group_at_least_one_selected(ObjectType::Ride)) { - gGameCommandErrorText = STR_AT_LEAST_ONE_RIDE_OBJECT_MUST_BE_SELECTED; - return ObjectType::Ride; + return { ObjectType::Ride, STR_AT_LEAST_ONE_RIDE_OBJECT_MUST_BE_SELECTED }; } if (!isTrackDesignerManager) { if (!editor_check_object_group_at_least_one_selected(ObjectType::ParkEntrance)) { - gGameCommandErrorText = STR_PARK_ENTRANCE_TYPE_MUST_BE_SELECTED; - return ObjectType::ParkEntrance; + return { ObjectType::ParkEntrance, STR_PARK_ENTRANCE_TYPE_MUST_BE_SELECTED }; } if (!editor_check_object_group_at_least_one_selected(ObjectType::Water)) { - gGameCommandErrorText = STR_WATER_TYPE_MUST_BE_SELECTED; - return ObjectType::Water; + return { ObjectType::Water, STR_WATER_TYPE_MUST_BE_SELECTED }; } } - return ObjectType::None; + return { ObjectType::None, STR_NONE }; } /** * * rct2: 0x0066FEAC */ - bool CheckPark() + std::pair CheckPark() { int32_t parkSize = park_calculate_size(); if (parkSize == 0) { - gGameCommandErrorText = STR_PARK_MUST_OWN_SOME_LAND; - return false; + return { false, STR_PARK_MUST_OWN_SOME_LAND }; } if (gParkEntrances.empty()) { - gGameCommandErrorText = STR_NO_PARK_ENTRANCES; - return false; + return { false, STR_NO_PARK_ENTRANCES }; } for (const auto& parkEntrance : gParkEntrances) @@ -545,12 +537,10 @@ namespace Editor switch (footpath_is_connected_to_map_edge(parkEntrance, direction, 0)) { case FOOTPATH_SEARCH_NOT_FOUND: - gGameCommandErrorText = STR_PARK_ENTRANCE_WRONG_DIRECTION_OR_NO_PATH; - return false; + return { false, STR_PARK_ENTRANCE_WRONG_DIRECTION_OR_NO_PATH }; case FOOTPATH_SEARCH_INCOMPLETE: case FOOTPATH_SEARCH_TOO_COMPLEX: - gGameCommandErrorText = STR_PARK_ENTRANCE_PATH_INCOMPLETE_OR_COMPLEX; - return false; + return { false, STR_PARK_ENTRANCE_PATH_INCOMPLETE_OR_COMPLEX }; case FOOTPATH_SEARCH_SUCCESS: // Run the search again and unown the path footpath_is_connected_to_map_edge(parkEntrance, direction, (1 << 5)); @@ -560,11 +550,10 @@ namespace Editor if (gPeepSpawns.empty()) { - gGameCommandErrorText = STR_PEEP_SPAWNS_NOT_SET; - return false; + return { false, STR_PEEP_SPAWNS_NOT_SET }; } - return true; + return { true, STR_NONE }; } uint8_t GetSelectedObjectFlags(ObjectType objectType, size_t index) diff --git a/src/openrct2/Editor.h b/src/openrct2/Editor.h index cdbc822be7..8a7499f2d8 100644 --- a/src/openrct2/Editor.h +++ b/src/openrct2/Editor.h @@ -21,8 +21,8 @@ namespace Editor void LoadTrackManager(); bool LoadLandscape(const utf8* path); - bool CheckPark(); - ObjectType CheckObjectSelection(); + std::pair CheckPark(); + std::pair CheckObjectSelection(); void OpenWindowsForCurrentStep(); diff --git a/src/openrct2/actions/FootpathPlaceAction.cpp b/src/openrct2/actions/FootpathPlaceAction.cpp index 59fd4c72a0..be5b708c99 100644 --- a/src/openrct2/actions/FootpathPlaceAction.cpp +++ b/src/openrct2/actions/FootpathPlaceAction.cpp @@ -355,14 +355,14 @@ GameActions::Result::Ptr FootpathPlaceAction::ElementInsertExecute(GameActions:: auto isQueue = _constructFlags & PathConstructFlag::IsQueue; uint8_t crossingMode = isQueue || (_slope != TILE_ELEMENT_SLOPE_FLAT) ? CREATE_CROSSING_MODE_NONE : CREATE_CROSSING_MODE_PATH_OVER_TRACK; - if (!entrancePath - && !map_can_construct_with_clear_at( - { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), - &res->Cost, crossingMode)) + auto canBuild = MapCanConstructWithClearAt( + { _loc, zLow, zHigh }, &map_place_non_scenery_clear_func, quarterTile, GAME_COMMAND_FLAG_APPLY | GetFlags(), + crossingMode); + if (!entrancePath && canBuild->Error != GameActions::Status::Ok) { - return MakeResult( - GameActions::Status::NoClearance, STR_CANT_BUILD_FOOTPATH_HERE, gGameCommandErrorText, gCommonFormatArgs); + return canBuild; } + res->Cost += canBuild->Cost; gFootpathGroundFlags = gMapGroundFlags; diff --git a/src/openrct2/actions/GameActionCompat.cpp b/src/openrct2/actions/GameActionCompat.cpp index 15c9cc46e2..9af73acc63 100644 --- a/src/openrct2/actions/GameActionCompat.cpp +++ b/src/openrct2/actions/GameActionCompat.cpp @@ -82,7 +82,7 @@ void ride_construct_new(RideSelection listItem) #pragma region RideSetStatusAction -void ride_set_status(Ride* ride, int32_t status) +void ride_set_status(Ride* ride, RideStatus status) { auto gameAction = RideSetStatusAction(ride->id, status); GameActions::Execute(&gameAction); diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.cpp b/src/openrct2/actions/LargeSceneryPlaceAction.cpp index eb44faec02..d3d3c5afc2 100644 --- a/src/openrct2/actions/LargeSceneryPlaceAction.cpp +++ b/src/openrct2/actions/LargeSceneryPlaceAction.cpp @@ -139,7 +139,7 @@ GameActions::Result::Ptr LargeSceneryPlaceAction::Query() const QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); if (!map_can_construct_with_clear_at( { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, - CREATE_CROSSING_MODE_NONE)) + CREATE_CROSSING_MODE_NONE, (sceneryEntry->flags & LARGE_SCENERY_FLAG_IS_TREE) != 0)) { return std::make_unique( GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); @@ -265,7 +265,7 @@ GameActions::Result::Ptr LargeSceneryPlaceAction::Execute() const QuarterTile quarterTile = QuarterTile{ static_cast(tile->flags >> 12), 0 }.Rotate(_loc.direction); if (!map_can_construct_with_clear_at( { curTile, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &supportsCost, - CREATE_CROSSING_MODE_NONE)) + CREATE_CROSSING_MODE_NONE, (sceneryEntry->flags & LARGE_SCENERY_FLAG_IS_TREE) != 0)) { DeleteBanner(banner->id); return MakeResult(GameActions::Status::NoClearance, gGameCommandErrorText, gCommonFormatArgs); diff --git a/src/openrct2/actions/RideCreateAction.cpp b/src/openrct2/actions/RideCreateAction.cpp index 68a94eb88a..4dcb4344b5 100644 --- a/src/openrct2/actions/RideCreateAction.cpp +++ b/src/openrct2/actions/RideCreateAction.cpp @@ -157,7 +157,7 @@ GameActions::Result::Ptr RideCreateAction::Execute() const vehicle = SPRITE_INDEX_NULL; } - ride->status = RIDE_STATUS_CLOSED; + ride->status = RideStatus::Closed; ride->lifecycle_flags = 0; ride->vehicle_change_timeout = 0; ride->num_stations = 0; diff --git a/src/openrct2/actions/RideDemolishAction.cpp b/src/openrct2/actions/RideDemolishAction.cpp index d2f5e5c811..f4d1911cba 100644 --- a/src/openrct2/actions/RideDemolishAction.cpp +++ b/src/openrct2/actions/RideDemolishAction.cpp @@ -74,7 +74,7 @@ GameActions::Result::Ptr RideDemolishAction::Query() const if (_modifyType == RIDE_MODIFY_RENEW) { - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + if (ride->status != RideStatus::Closed && ride->status != RideStatus::Simulating) { return std::make_unique( GameActions::Status::Disallowed, STR_CANT_REFURBISH_RIDE, STR_MUST_BE_CLOSED_FIRST); diff --git a/src/openrct2/actions/RideEntranceExitPlaceAction.cpp b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp index 991d263acc..5627295f31 100644 --- a/src/openrct2/actions/RideEntranceExitPlaceAction.cpp +++ b/src/openrct2/actions/RideEntranceExitPlaceAction.cpp @@ -68,7 +68,7 @@ GameActions::Result::Ptr RideEntranceExitPlaceAction::Query() const return MakeResult(GameActions::Status::InvalidParameters, errorTitle); } - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + if (ride->status != RideStatus::Closed && ride->status != RideStatus::Simulating) { return MakeResult(GameActions::Status::NotClosed, errorTitle, STR_MUST_BE_CLOSED_FIRST); } diff --git a/src/openrct2/actions/RideEntranceExitRemoveAction.cpp b/src/openrct2/actions/RideEntranceExitRemoveAction.cpp index 5ef2b553df..f4fac8cae3 100644 --- a/src/openrct2/actions/RideEntranceExitRemoveAction.cpp +++ b/src/openrct2/actions/RideEntranceExitRemoveAction.cpp @@ -78,7 +78,7 @@ GameActions::Result::Ptr RideEntranceExitRemoveAction::Query() const return std::make_unique(GameActions::Status::InvalidParameters, STR_NONE); } - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + if (ride->status != RideStatus::Closed && ride->status != RideStatus::Simulating) { return MakeResult(GameActions::Status::InvalidParameters, STR_MUST_BE_CLOSED_FIRST); } diff --git a/src/openrct2/actions/RideSetSettingAction.cpp b/src/openrct2/actions/RideSetSettingAction.cpp index 8c19249b86..fb7b8d506b 100644 --- a/src/openrct2/actions/RideSetSettingAction.cpp +++ b/src/openrct2/actions/RideSetSettingAction.cpp @@ -58,7 +58,7 @@ GameActions::Result::Ptr RideSetSettingAction::Query() const GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); } - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + if (ride->status != RideStatus::Closed && ride->status != RideStatus::Simulating) { return MakeResult(GameActions::Status::Disallowed, STR_CANT_CHANGE_OPERATING_MODE, STR_MUST_BE_CLOSED_FIRST); } diff --git a/src/openrct2/actions/RideSetStatusAction.cpp b/src/openrct2/actions/RideSetStatusAction.cpp index baeb92a9c9..2750d639f3 100644 --- a/src/openrct2/actions/RideSetStatusAction.cpp +++ b/src/openrct2/actions/RideSetStatusAction.cpp @@ -28,7 +28,7 @@ static rct_string_id _StatusErrorTitles[] = { STR_CANT_SIMULATE, }; -RideSetStatusAction::RideSetStatusAction(ride_id_t rideIndex, uint8_t status) +RideSetStatusAction::RideSetStatusAction(ride_id_t rideIndex, RideStatus status) : _rideIndex(rideIndex) , _status(status) { @@ -66,7 +66,7 @@ GameActions::Result::Ptr RideSetStatusAction::Query() const return res; } - if (_status >= RIDE_STATUS_COUNT) + if (_status >= RideStatus::Count) { log_warning("Invalid ride status %u for ride %u", uint32_t(_status), uint32_t(_rideIndex)); res->Error = GameActions::Status::InvalidParameters; @@ -75,21 +75,21 @@ GameActions::Result::Ptr RideSetStatusAction::Query() const return res; } - res->ErrorTitle = _StatusErrorTitles[_status]; + res->ErrorTitle = _StatusErrorTitles[EnumValue(_status)]; Formatter ft(res->ErrorMessageArgs.data()); ft.Increment(6); ride->FormatNameTo(ft); if (_status != ride->status) { - if (_status == RIDE_STATUS_SIMULATING && (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + if (_status == RideStatus::Simulating && (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { // Simulating will force clear the track, so make sure player can't cheat around a break down res->Error = GameActions::Status::Disallowed; res->ErrorMessage = STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING; return res; } - else if (_status == RIDE_STATUS_TESTING || _status == RIDE_STATUS_SIMULATING) + else if (_status == RideStatus::Testing || _status == RideStatus::Simulating) { if (!ride->Test(_status, false)) { @@ -98,7 +98,7 @@ GameActions::Result::Ptr RideSetStatusAction::Query() const return res; } } - else if (_status == RIDE_STATUS_OPEN) + else if (_status == RideStatus::Open) { if (!ride->Open(false)) { @@ -126,7 +126,7 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const return res; } - res->ErrorTitle = _StatusErrorTitles[_status]; + res->ErrorTitle = _StatusErrorTitles[static_cast(_status)]; Formatter ft(res->ErrorMessageArgs.data()); ft.Increment(6); @@ -139,8 +139,8 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const switch (_status) { - case RIDE_STATUS_CLOSED: - if (ride->status == _status || ride->status == RIDE_STATUS_SIMULATING) + case RideStatus::Closed: + if (ride->status == _status || ride->status == RideStatus::Simulating) { if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { @@ -150,13 +150,13 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const } } - ride->status = RIDE_STATUS_CLOSED; + ride->status = RideStatus::Closed; 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); break; - case RIDE_STATUS_SIMULATING: + case RideStatus::Simulating: { ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; ride_clear_for_construction(ride); @@ -179,15 +179,15 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const window_invalidate_by_number(WC_RIDE, _rideIndex); break; } - case RIDE_STATUS_TESTING: - case RIDE_STATUS_OPEN: + case RideStatus::Testing: + case RideStatus::Open: { if (ride->status == _status) { return res; } - if (ride->status == RIDE_STATUS_SIMULATING) + if (ride->status == RideStatus::Simulating) { ride_clear_for_construction(ride); ride_remove_peeps(ride); @@ -201,7 +201,7 @@ GameActions::Result::Ptr RideSetStatusAction::Execute() const window_close(constructionWindow); } - if (_status == RIDE_STATUS_TESTING) + if (_status == RideStatus::Testing) { if (!ride->Test(_status, true)) { diff --git a/src/openrct2/actions/RideSetStatusAction.h b/src/openrct2/actions/RideSetStatusAction.h index 35e4f9d030..fc97fb220e 100644 --- a/src/openrct2/actions/RideSetStatusAction.h +++ b/src/openrct2/actions/RideSetStatusAction.h @@ -15,11 +15,11 @@ DEFINE_GAME_ACTION(RideSetStatusAction, GameCommand::SetRideStatus, GameActions: { private: NetworkRideId_t _rideIndex{ RIDE_ID_NULL }; - uint8_t _status{ RIDE_STATUS_CLOSED }; + RideStatus _status{ RideStatus::Closed }; public: RideSetStatusAction() = default; - RideSetStatusAction(ride_id_t rideIndex, uint8_t status); + RideSetStatusAction(ride_id_t rideIndex, RideStatus status); void AcceptParameters(GameActionParameterVisitor & visitor) override; diff --git a/src/openrct2/actions/RideSetVehicleAction.cpp b/src/openrct2/actions/RideSetVehicleAction.cpp index 2663b1d86b..167d2cb0b2 100644 --- a/src/openrct2/actions/RideSetVehicleAction.cpp +++ b/src/openrct2/actions/RideSetVehicleAction.cpp @@ -77,7 +77,7 @@ GameActions::Result::Ptr RideSetVehicleAction::Query() const GameActions::Status::Broken, errTitle, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); } - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + if (ride->status != RideStatus::Closed && ride->status != RideStatus::Simulating) { return std::make_unique(GameActions::Status::NotClosed, errTitle, STR_MUST_BE_CLOSED_FIRST); } diff --git a/src/openrct2/actions/SmallSceneryPlaceAction.cpp b/src/openrct2/actions/SmallSceneryPlaceAction.cpp index df01106163..b5ab7b60a1 100644 --- a/src/openrct2/actions/SmallSceneryPlaceAction.cpp +++ b/src/openrct2/actions/SmallSceneryPlaceAction.cpp @@ -280,7 +280,7 @@ GameActions::Result::Ptr SmallSceneryPlaceAction::Query() const if (!map_can_construct_with_clear_at( { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags(), &clearCost, - CREATE_CROSSING_MODE_NONE)) + CREATE_CROSSING_MODE_NONE, scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_IS_TREE))) { return std::make_unique( GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); @@ -418,7 +418,7 @@ GameActions::Result::Ptr SmallSceneryPlaceAction::Execute() const if (!map_can_construct_with_clear_at( { _loc, zLow, zHigh }, &map_place_scenery_clear_func, quarterTile, GetFlags() | GAME_COMMAND_FLAG_APPLY, &clearCost, - CREATE_CROSSING_MODE_NONE)) + CREATE_CROSSING_MODE_NONE, scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_IS_TREE))) { return std::make_unique( GameActions::Status::Disallowed, gGameCommandErrorText, gCommonFormatArgs); diff --git a/src/openrct2/actions/TrackPlaceAction.cpp b/src/openrct2/actions/TrackPlaceAction.cpp index 09953a419e..7aa0bac0f6 100644 --- a/src/openrct2/actions/TrackPlaceAction.cpp +++ b/src/openrct2/actions/TrackPlaceAction.cpp @@ -614,7 +614,7 @@ GameActions::Result::Ptr TrackPlaceAction::Execute() const // If the placed tile is a station modify station properties. // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN - && !(ride->status == RIDE_STATUS_SIMULATING && GetFlags() & GAME_COMMAND_FLAG_GHOST)) + && !(ride->status == RideStatus::Simulating && GetFlags() & GAME_COMMAND_FLAG_GHOST)) { if (trackBlock->index == 0) { diff --git a/src/openrct2/actions/TrackRemoveAction.cpp b/src/openrct2/actions/TrackRemoveAction.cpp index c89cc2db92..0165bb721f 100644 --- a/src/openrct2/actions/TrackRemoveAction.cpp +++ b/src/openrct2/actions/TrackRemoveAction.cpp @@ -401,7 +401,7 @@ GameActions::Result::Ptr TrackRemoveAction::Execute() const // If the removed tile is a station modify station properties. // Don't do this if the ride is simulating and the tile is a ghost to prevent desyncs. if (entranceDirections & TRACK_SEQUENCE_FLAG_ORIGIN - && !(ride->status == RIDE_STATUS_SIMULATING && tileElement->Flags & TILE_ELEMENT_FLAG_GHOST) + && !(ride->status == RideStatus::Simulating && tileElement->Flags & TILE_ELEMENT_FLAG_GHOST) && (tileElement->AsTrack()->GetSequenceIndex() == 0)) { if (!track_remove_station_element({ mapLoc, _origin.direction }, rideIndex, GAME_COMMAND_FLAG_APPLY)) diff --git a/src/openrct2/management/Award.cpp b/src/openrct2/management/Award.cpp index 32b37fa512..f6cb615059 100644 --- a/src/openrct2/management/Award.cpp +++ b/src/openrct2/management/Award.cpp @@ -146,7 +146,7 @@ static bool award_is_deserved_best_rollercoasters([[maybe_unused]] int32_t activ continue; } - if (ride.status != RIDE_STATUS_OPEN || (ride.lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) + if (ride.status != RideStatus::Open || (ride.lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) { continue; } @@ -280,7 +280,7 @@ static bool award_is_deserved_best_food(int32_t activeAwardTypes) uint64_t shopTypes = 0; for (const auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_OPEN) + if (ride.status != RideStatus::Open) continue; if (!ride.GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_SELLS_FOOD)) continue; @@ -324,7 +324,7 @@ static bool award_is_deserved_worst_food(int32_t activeAwardTypes) uint64_t shopTypes = 0; for (const auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_OPEN) + if (ride.status != RideStatus::Open) continue; if (!ride.GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_SELLS_FOOD)) continue; @@ -363,7 +363,7 @@ static bool award_is_deserved_best_restrooms([[maybe_unused]] int32_t activeAwar // Count open restrooms const auto& rideManager = GetRideManager(); auto numRestrooms = static_cast(std::count_if(rideManager.begin(), rideManager.end(), [](const Ride& ride) { - return ride.type == RIDE_TYPE_TOILETS && ride.status == RIDE_STATUS_OPEN; + return ride.type == RIDE_TYPE_TOILETS && ride.status == RideStatus::Open; })); // At least 4 open restrooms @@ -426,7 +426,7 @@ static bool award_is_deserved_best_water_rides([[maybe_unused]] int32_t activeAw continue; } - if (ride.status != RIDE_STATUS_OPEN || (ride.lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) + if (ride.status != RideStatus::Open || (ride.lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) { continue; } @@ -457,7 +457,7 @@ static bool award_is_deserved_best_custom_designed_rides(int32_t activeAwardType continue; if (ride.excitement < RIDE_RATING(5, 50)) continue; - if (ride.status != RIDE_STATUS_OPEN || (ride.lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) + if (ride.status != RideStatus::Open || (ride.lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) continue; customDesignedRides++; @@ -529,7 +529,7 @@ static bool award_is_deserved_best_gentle_rides([[maybe_unused]] int32_t activeA continue; } - if (ride.status != RIDE_STATUS_OPEN || (ride.lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) + if (ride.status != RideStatus::Open || (ride.lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) { continue; } diff --git a/src/openrct2/management/Finance.cpp b/src/openrct2/management/Finance.cpp index 92e0a03566..dc78081c5d 100644 --- a/src/openrct2/management/Finance.cpp +++ b/src/openrct2/management/Finance.cpp @@ -164,7 +164,7 @@ void finance_pay_ride_upkeep() ride.Renew(); } - if (ride.status != RIDE_STATUS_CLOSED && !(gParkFlags & PARK_FLAGS_NO_MONEY)) + if (ride.status != RideStatus::Closed && !(gParkFlags & PARK_FLAGS_NO_MONEY)) { int16_t upkeep = ride.upkeep_cost; if (upkeep != -1) @@ -257,7 +257,7 @@ void finance_update_daily_profit() // Ride costs for (auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_CLOSED && ride.upkeep_cost != MONEY16_UNDEFINED) + if (ride.status != RideStatus::Closed && ride.upkeep_cost != MONEY16_UNDEFINED) { current_profit -= 2 * ride.upkeep_cost; } diff --git a/src/openrct2/object/LargeSceneryObject.cpp b/src/openrct2/object/LargeSceneryObject.cpp index 87da9feb8b..fa96ac5535 100644 --- a/src/openrct2/object/LargeSceneryObject.cpp +++ b/src/openrct2/object/LargeSceneryObject.cpp @@ -144,6 +144,7 @@ void LargeSceneryObject::ReadJson(IReadObjectContext* context, json_t& root) { "hasSecondaryColour", LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR }, { "isAnimated", LARGE_SCENERY_FLAG_ANIMATED }, { "isPhotogenic", LARGE_SCENERY_FLAG_PHOTOGENIC }, + { "isTree", LARGE_SCENERY_FLAG_IS_TREE }, }); // Tiles diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index 9f1b312d7e..55391dcc06 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -739,9 +739,9 @@ paint_struct* PaintAddImageAsParent( } paint_struct* PaintAddImageAsParent( - paint_session* session, uint32_t image_id, int8_t x_offset, int8_t y_offset, int16_t bound_box_length_x, - int16_t bound_box_length_y, int8_t bound_box_length_z, int16_t z_offset, int16_t bound_box_offset_x, - int16_t bound_box_offset_y, int16_t bound_box_offset_z) + paint_session* session, uint32_t image_id, int32_t x_offset, int32_t y_offset, int32_t bound_box_length_x, + int32_t bound_box_length_y, int32_t bound_box_length_z, int32_t z_offset, int32_t bound_box_offset_x, + int32_t bound_box_offset_y, int32_t bound_box_offset_z) { return PaintAddImageAsParent( session, image_id, { x_offset, y_offset, z_offset }, { bound_box_length_x, bound_box_length_y, bound_box_length_z }, diff --git a/src/openrct2/paint/tile_element/Paint.Entrance.cpp b/src/openrct2/paint/tile_element/Paint.Entrance.cpp index 17bfe5caf5..4b0f8c3b85 100644 --- a/src/openrct2/paint/tile_element/Paint.Entrance.cpp +++ b/src/openrct2/paint/tile_element/Paint.Entrance.cpp @@ -166,7 +166,7 @@ static void ride_entrance_exit_paint(paint_session* session, uint8_t direction, auto ft = Formatter(); ft.Add(STR_RIDE_ENTRANCE_NAME); - if (ride->status == RIDE_STATUS_OPEN && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + if (ride->status == RideStatus::Open && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { ride->FormatNameTo(ft); } diff --git a/src/openrct2/paint/tile_element/Paint.Path.cpp b/src/openrct2/paint/tile_element/Paint.Path.cpp index 13b3986c06..c4ef059a8b 100644 --- a/src/openrct2/paint/tile_element/Paint.Path.cpp +++ b/src/openrct2/paint/tile_element/Paint.Path.cpp @@ -457,7 +457,7 @@ static void sub_6A4101( auto ft = Formatter(); - if (ride->status == RIDE_STATUS_OPEN && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + if (ride->status == RideStatus::Open && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { ft.Add(STR_RIDE_ENTRANCE_NAME); ride->FormatNameTo(ft); diff --git a/src/openrct2/peep/Guest.cpp b/src/openrct2/peep/Guest.cpp index 946f176129..7f7f04c4c1 100644 --- a/src/openrct2/peep/Guest.cpp +++ b/src/openrct2/peep/Guest.cpp @@ -1902,7 +1902,7 @@ bool Guest::ShouldGoOnRide(Ride* ride, int32_t entranceNum, bool atQueue, bool t // Indicates whether a peep is physically at the ride, or is just thinking about going on the ride. bool peepAtRide = !thinking; - if (ride->status == RIDE_STATUS_OPEN && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + if (ride->status == RideStatus::Open && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { // Peeps that are leaving the park will refuse to go on any rides, with the exception of free transport rides. assert(ride->type < std::size(RideTypeDescriptors)); @@ -2918,7 +2918,7 @@ static PeepThoughtType peep_assess_surroundings(int16_t centre_x, int16_t centre ride = get_ride(tileElement->AsTrack()->GetRideIndex()); if (ride != nullptr) { - if (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC && ride->status != RIDE_STATUS_CLOSED + if (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC && ride->status != RideStatus::Closed && !(ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED))) { if (ride->type == RIDE_TYPE_MERRY_GO_ROUND) @@ -3282,7 +3282,7 @@ void Guest::UpdateBuying() return; auto ride = get_ride(CurrentRide); - if (ride == nullptr || ride->status != RIDE_STATUS_OPEN) + if (ride == nullptr || ride->status != RideStatus::Open) { SetState(PeepState::Falling); return; @@ -3432,7 +3432,7 @@ void Guest::UpdateRideAtEntrance() return; } - if (ride->status != RIDE_STATUS_OPEN || ride->vehicle_change_timeout != 0) + if (ride->status != RideStatus::Open || ride->vehicle_change_timeout != 0) { peep_update_ride_at_entrance_try_leave(this); return; @@ -3869,7 +3869,7 @@ void Guest::UpdateRideFreeVehicleCheck() if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_NO_VEHICLES)) { - if (ride->status != RIDE_STATUS_OPEN || ride->vehicle_change_timeout != 0 || (++RejoinQueueTimeout) == 0) + if (ride->status != RideStatus::Open || ride->vehicle_change_timeout != 0 || (++RejoinQueueTimeout) == 0) { peep_update_ride_no_free_vehicle_rejoin_queue(this, ride); return; @@ -3948,7 +3948,7 @@ void Guest::UpdateRideFreeVehicleCheck() { return; } - if (ride->status == RIDE_STATUS_OPEN && ++RejoinQueueTimeout != 0 + if (ride->status == RideStatus::Open && ++RejoinQueueTimeout != 0 && !currentTrain->HasUpdateFlag(VEHICLE_UPDATE_FLAG_TRAIN_READY_DEPART)) { return; @@ -4552,7 +4552,7 @@ void Guest::UpdateRideApproachSpiralSlide() else if (waypoint == 2) { bool lastRide = false; - if (ride->status != RIDE_STATUS_OPEN) + if (ride->status != RideStatus::Open) lastRide = true; else if (CurrentCar++ != 0) { @@ -5437,7 +5437,7 @@ void Guest::UpdateQueuing() return; } auto ride = get_ride(CurrentRide); - if (ride == nullptr || ride->status != RIDE_STATUS_OPEN) + if (ride == nullptr || ride->status != RideStatus::Open) { RemoveFromQueue(); SetState(PeepState::One); @@ -6188,7 +6188,7 @@ bool loc_690FD0(Peep* peep, ride_id_t* rideToView, uint8_t* rideSeatToView, Tile if (ride->excitement == RIDE_RATING_UNDEFINED) { *rideSeatToView = 1; - if (ride->status != RIDE_STATUS_OPEN) + if (ride->status != RideStatus::Open) { if (tileElement->GetClearanceZ() > peep->NextLoc.z + (8 * COORDS_Z_STEP)) { @@ -6201,7 +6201,7 @@ bool loc_690FD0(Peep* peep, ride_id_t* rideToView, uint8_t* rideSeatToView, Tile else { *rideSeatToView = 0; - if (ride->status == RIDE_STATUS_OPEN && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) + if (ride->status == RideStatus::Open && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { if (tileElement->GetClearanceZ() > peep->NextLoc.z + (8 * COORDS_Z_STEP)) { diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 3f76b06e05..ecd4a6845f 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -2166,7 +2166,7 @@ int32_t guest_path_finding(Guest* peep) // Peep is heading for a ride. ride_id_t rideIndex = peep->GuestHeadingToRideId; auto ride = get_ride(rideIndex); - if (ride == nullptr || ride->status != RIDE_STATUS_OPEN) + if (ride == nullptr || ride->status != RideStatus::Open) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) diff --git a/src/openrct2/peep/Peep.cpp b/src/openrct2/peep/Peep.cpp index d00b375317..2262fc0945 100644 --- a/src/openrct2/peep/Peep.cpp +++ b/src/openrct2/peep/Peep.cpp @@ -2198,7 +2198,7 @@ static bool peep_interact_with_shop(Peep* peep, const CoordsXYE& coords) guest->TimeLost = 0; - if (ride->status != RIDE_STATUS_OPEN) + if (ride->status != RideStatus::Open) { peep_return_to_centre_of_tile(guest); return true; diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 09733ee198..9e4c416910 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -848,7 +848,7 @@ private: dst->custom_name = GetUserString(src->name); } - dst->status = src->status; + dst->status = static_cast(src->status); // Flags dst->lifecycle_flags = src->lifecycle_flags; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index aa988a4416..34385eadeb 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -538,7 +538,7 @@ public: } // pad_046; - dst->status = src->status; + dst->status = static_cast(src->status); dst->default_name_number = src->name_arguments_number; if (is_user_string_id(src->name)) diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 6043a5ddb4..4aa94996ae 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -807,7 +807,7 @@ void Ride::FormatStatusTo(Formatter& ft) const { ft.Add(STR_BROKEN_DOWN); } - else if (status == RIDE_STATUS_CLOSED) + else if (status == RideStatus::Closed) { if (!GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_IS_SHOP)) { @@ -826,11 +826,11 @@ void Ride::FormatStatusTo(Formatter& ft) const ft.Add(STR_CLOSED); } } - else if (status == RIDE_STATUS_SIMULATING) + else if (status == RideStatus::Simulating) { ft.Add(STR_SIMULATING); } - else if (status == RIDE_STATUS_TESTING) + else if (status == RideStatus::Testing) { ft.Add(STR_TEST_RUN); } @@ -896,22 +896,24 @@ bool Ride::CanHaveMultipleCircuits() const return true; } -bool Ride::SupportsStatus(int32_t s) const +bool Ride::SupportsStatus(RideStatus s) const { const auto& rtd = GetRideTypeDescriptor(); switch (s) { - case RIDE_STATUS_CLOSED: - case RIDE_STATUS_OPEN: + case RideStatus::Closed: + case RideStatus::Open: return true; - case RIDE_STATUS_SIMULATING: + case RideStatus::Simulating: return (!rtd.HasFlag(RIDE_TYPE_FLAG_NO_TEST_MODE) && rtd.HasFlag(RIDE_TYPE_FLAG_HAS_TRACK)); - case RIDE_STATUS_TESTING: + case RideStatus::Testing: return !rtd.HasFlag(RIDE_TYPE_FLAG_NO_TEST_MODE); - default: + case RideStatus::Count: // Meaningless but necessary to satisfy -Wswitch return false; } + // Unreachable + return false; } #pragma region Initialisation functions @@ -959,7 +961,7 @@ static int32_t ride_check_if_construction_allowed(Ride* ride) return 0; } - if (ride->status != RIDE_STATUS_CLOSED && ride->status != RIDE_STATUS_SIMULATING) + if (ride->status != RideStatus::Closed && ride->status != RideStatus::Simulating) { ft.Increment(6); ride->FormatNameTo(ft); @@ -1840,9 +1842,9 @@ bool ride_modify(CoordsXYE* input) } // Stop the ride again to clear all vehicles and peeps (compatible with network games) - if (ride->status != RIDE_STATUS_SIMULATING) + if (ride->status != RideStatus::Simulating) { - ride_set_status(ride, RIDE_STATUS_CLOSED); + ride_set_status(ride, RideStatus::Closed); } // Check if element is a station entrance or exit @@ -2088,18 +2090,18 @@ void Ride::Update() ride_inspection_update(this); // If ride is simulating but crashed, reset the vehicles - if (status == RIDE_STATUS_SIMULATING && (lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) + if (status == RideStatus::Simulating && (lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) { if (mode == RideMode::ContinuousCircuitBlockSectioned || mode == RideMode::PoweredLaunchBlockSectioned) { // We require this to execute right away during the simulation, always ignore network and queue. - RideSetStatusAction gameAction = RideSetStatusAction(id, RIDE_STATUS_CLOSED); + RideSetStatusAction gameAction = RideSetStatusAction(id, RideStatus::Closed); GameActions::ExecuteNested(&gameAction); } else { // We require this to execute right away during the simulation, always ignore network and queue. - RideSetStatusAction gameAction = RideSetStatusAction(id, RIDE_STATUS_SIMULATING); + RideSetStatusAction gameAction = RideSetStatusAction(id, RideStatus::Simulating); GameActions::ExecuteNested(&gameAction); } } @@ -2359,7 +2361,7 @@ static void ride_breakdown_update(Ride* ride) if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) return; - if (ride->status == RIDE_STATUS_CLOSED || ride->status == RIDE_STATUS_SIMULATING) + if (ride->status == RideStatus::Closed || ride->status == RideStatus::Simulating) return; if (!ride->CanBreakDown()) @@ -2821,7 +2823,7 @@ static void ride_music_update(Ride* ride) return; } - if (ride->status != RIDE_STATUS_OPEN || !(ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC)) + if (ride->status != RideStatus::Open || !(ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC)) { ride->music_tune_id = 255; return; @@ -2985,7 +2987,7 @@ void ride_measurements_update() for (auto& ride : GetRideManager()) { auto measurement = ride.measurement.get(); - if (measurement != nullptr && (ride.lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) && ride.status != RIDE_STATUS_SIMULATING) + if (measurement != nullptr && (ride.lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) && ride.status != RideStatus::Simulating) { if (measurement->flags & RIDE_MEASUREMENT_FLAG_RUNNING) { @@ -3199,7 +3201,7 @@ void ride_check_all_reachable() { if (ride.connected_message_throttle != 0) ride.connected_message_throttle--; - if (ride.status != RIDE_STATUS_OPEN || ride.connected_message_throttle != 0) + if (ride.status != RideStatus::Open || ride.connected_message_throttle != 0) continue; if (ride.GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_IS_SHOP)) @@ -4835,7 +4837,7 @@ TrackElement* Ride::GetOriginElement(StationIndex stationIndex) const return nullptr; } -bool Ride::Test(int32_t newStatus, bool isApplying) +bool Ride::Test(RideStatus newStatus, bool isApplying) { CoordsXYE trackElement, problematicTrackElement = {}; @@ -4845,7 +4847,7 @@ bool Ride::Test(int32_t newStatus, bool isApplying) return false; } - if (newStatus != RIDE_STATUS_SIMULATING) + if (newStatus != RideStatus::Simulating) { window_close_by_number(WC_RIDE_CONSTRUCTION, id); } @@ -4857,7 +4859,7 @@ bool Ride::Test(int32_t newStatus, bool isApplying) if (!ride_mode_check_valid_station_numbers(this)) return false; - if (newStatus != RIDE_STATUS_SIMULATING && !ride_check_for_entrance_exit(id)) + if (newStatus != RideStatus::Simulating && !ride_check_for_entrance_exit(id)) { ConstructMissingEntranceOrExit(); return false; @@ -4878,7 +4880,7 @@ bool Ride::Test(int32_t newStatus, bool isApplying) if (mode == RideMode::ContinuousCircuit || IsBlockSectioned()) { if (ride_find_track_gap(this, &trackElement, &problematicTrackElement) - && (newStatus != RIDE_STATUS_SIMULATING || IsBlockSectioned())) + && (newStatus != RideStatus::Simulating || IsBlockSectioned())) { gGameCommandErrorText = STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT; ride_scroll_to_track_error(&problematicTrackElement); diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index fc70f81caa..ed918e32b9 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -202,6 +202,7 @@ namespace ShelteredSectionsBits struct TrackDesign; enum class RideMode : uint8_t; +enum class RideStatus : uint8_t; /** * Ride structure. @@ -220,7 +221,7 @@ struct Ride uint8_t colour_scheme_type; VehicleColour vehicle_colours[MAX_VEHICLES_PER_RIDE + 1]; // 0 = closed, 1 = open, 2 = test - uint8_t status; + RideStatus status; std::string custom_name; uint16_t default_name_number; CoordsXY overall_view; @@ -422,12 +423,12 @@ public: bool IsPoweredLaunched() const; bool IsBlockSectioned() const; bool CanHaveMultipleCircuits() const; - bool SupportsStatus(int32_t s) const; + bool SupportsStatus(RideStatus s) const; void StopGuestsQueuing(); bool Open(bool isApplying); - bool Test(int32_t newStatus, bool isApplying); + bool Test(RideStatus newStatus, bool isApplying); RideMode GetDefaultMode() const; @@ -666,13 +667,13 @@ enum RIDE_TYPE_COUNT }; -enum +enum class RideStatus : uint8_t { - RIDE_STATUS_CLOSED, - RIDE_STATUS_OPEN, - RIDE_STATUS_TESTING, - RIDE_STATUS_SIMULATING, - RIDE_STATUS_COUNT, + Closed, + Open, + Testing, + Simulating, + Count, }; enum class RideMode : uint8_t @@ -1153,7 +1154,7 @@ void ride_set_map_tooltip(TileElement* tileElement); void ride_prepare_breakdown(Ride* ride, int32_t breakdownReason); TileElement* ride_get_station_start_track_element(Ride* ride, StationIndex stationIndex); TileElement* ride_get_station_exit_element(const CoordsXYZ& elementPos); -void ride_set_status(Ride* ride, int32_t status); +void ride_set_status(Ride* ride, RideStatus status); void ride_set_name(Ride* ride, const char* name, uint32_t flags); int32_t ride_get_refund_price(const Ride* ride); int32_t ride_get_random_colour_preset_index(uint8_t ride_type); diff --git a/src/openrct2/ride/RideRatings.cpp b/src/openrct2/ride/RideRatings.cpp index b987d941be..e8fe13ac6c 100644 --- a/src/openrct2/ride/RideRatings.cpp +++ b/src/openrct2/ride/RideRatings.cpp @@ -100,7 +100,7 @@ static void ride_ratings_add(RatingTuple* rating, int32_t excitement, int32_t in */ void ride_ratings_update_ride(const Ride& ride) { - if (ride.status != RIDE_STATUS_CLOSED) + if (ride.status != RideStatus::Closed) { gRideRatingsCalcData.CurrentRide = ride.id; gRideRatingsCalcData.State = RIDE_RATINGS_STATE_INITIALISE; @@ -163,7 +163,7 @@ static void ride_ratings_update_state_0() } auto ride = get_ride(currentRide); - if (ride != nullptr && ride->status != RIDE_STATUS_CLOSED && !(ride->lifecycle_flags & RIDE_LIFECYCLE_FIXED_RATINGS)) + if (ride != nullptr && ride->status != RideStatus::Closed && !(ride->lifecycle_flags & RIDE_LIFECYCLE_FIXED_RATINGS)) { gRideRatingsCalcData.State = RIDE_RATINGS_STATE_INITIALISE; } @@ -196,7 +196,7 @@ static void ride_ratings_update_state_2() { const ride_id_t rideIndex = gRideRatingsCalcData.CurrentRide; auto ride = get_ride(rideIndex); - if (ride == nullptr || ride->status == RIDE_STATUS_CLOSED || ride->type >= RIDE_TYPE_COUNT) + if (ride == nullptr || ride->status == RideStatus::Closed || ride->type >= RIDE_TYPE_COUNT) { gRideRatingsCalcData.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; return; @@ -273,7 +273,7 @@ static void ride_ratings_update_state_2() static void ride_ratings_update_state_3() { auto ride = get_ride(gRideRatingsCalcData.CurrentRide); - if (ride == nullptr || ride->status == RIDE_STATUS_CLOSED) + if (ride == nullptr || ride->status == RideStatus::Closed) { gRideRatingsCalcData.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; return; @@ -303,7 +303,7 @@ static void ride_ratings_update_state_4() static void ride_ratings_update_state_5() { auto ride = get_ride(gRideRatingsCalcData.CurrentRide); - if (ride == nullptr || ride->status == RIDE_STATUS_CLOSED) + if (ride == nullptr || ride->status == RideStatus::Closed) { gRideRatingsCalcData.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; return; @@ -369,7 +369,7 @@ static void ride_ratings_update_state_5() static void ride_ratings_begin_proximity_loop() { auto ride = get_ride(gRideRatingsCalcData.CurrentRide); - if (ride == nullptr || ride->status == RIDE_STATUS_CLOSED) + if (ride == nullptr || ride->status == RideStatus::Closed) { gRideRatingsCalcData.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; return; @@ -853,7 +853,7 @@ static void ride_ratings_calculate_value(Ride* ride) // Other ride of same type penalty const auto& rideManager = GetRideManager(); auto otherRidesOfSameType = std::count_if(rideManager.begin(), rideManager.end(), [ride](const Ride& r) { - return r.status == RIDE_STATUS_OPEN && r.type == ride->type; + return r.status == RideStatus::Open && r.type == ride->type; }); if (otherRidesOfSameType > 1) value -= value / 4; diff --git a/src/openrct2/ride/Station.cpp b/src/openrct2/ride/Station.cpp index 570611d26a..f62414cb19 100644 --- a/src/openrct2/ride/Station.cpp +++ b/src/openrct2/ride/Station.cpp @@ -58,7 +58,7 @@ static void ride_update_station_blocksection(Ride* ride, StationIndex stationInd { TileElement* tileElement = ride_get_station_start_track_element(ride, stationIndex); - if ((ride->status == RIDE_STATUS_CLOSED && ride->num_riders == 0) + if ((ride->status == RideStatus::Closed && ride->num_riders == 0) || (tileElement != nullptr && tileElement->AsTrack()->BlockBrakeClosed())) { ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG; @@ -89,7 +89,7 @@ static void ride_update_station_dodgems(Ride* ride, StationIndex stationIndex) { // Change of station depart flag should really call invalidate_station_start // but since dodgems do not have station lights there is no point. - if (ride->status == RIDE_STATUS_CLOSED || (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED))) + if (ride->status == RideStatus::Closed || (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED))) { ride->stations[stationIndex].Depart &= ~STATION_DEPART_FLAG; return; @@ -148,7 +148,7 @@ static void ride_update_station_normal(Ride* ride, StationIndex stationIndex) { int32_t time = ride->stations[stationIndex].Depart & STATION_DEPART_MASK; if ((ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) - || (ride->status == RIDE_STATUS_CLOSED && ride->num_riders == 0)) + || (ride->status == RideStatus::Closed && ride->num_riders == 0)) { if (time != 0 && time != 127 && !(gCurrentTicks & 7)) time--; @@ -180,7 +180,7 @@ static void ride_update_station_normal(Ride* ride, StationIndex stationIndex) */ static void ride_update_station_race(Ride* ride, StationIndex stationIndex) { - if (ride->status == RIDE_STATUS_CLOSED || (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED))) + if (ride->status == RideStatus::Closed || (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED))) { if (ride->stations[stationIndex].Depart & STATION_DEPART_FLAG) { diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index 3ab0c5d5a4..a4c30557ed 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -2215,7 +2215,7 @@ void Vehicle::TrainReadyToDepart(uint8_t num_peeps_on_train, uint8_t num_used_se if (curRide == nullptr) return; - if (curRide->status == RIDE_STATUS_OPEN && !(curRide->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) + if (curRide->status == RideStatus::Open && !(curRide->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) && !HasUpdateFlag(VEHICLE_UPDATE_FLAG_TRAIN_READY_DEPART)) { return; @@ -2225,7 +2225,7 @@ void Vehicle::TrainReadyToDepart(uint8_t num_peeps_on_train, uint8_t num_used_se { // Original code did not check if the ride was a boat hire, causing empty boats to leave the platform when closing a // Boat Hire with passengers on it. - if (curRide->status != RIDE_STATUS_CLOSED || (curRide->num_riders != 0 && curRide->type != RIDE_TYPE_BOAT_HIRE)) + if (curRide->status != RideStatus::Closed || (curRide->num_riders != 0 && curRide->type != RIDE_TYPE_BOAT_HIRE)) { curRide->stations[current_station].TrainAtStation = RideStation::NO_TRAIN; sub_state = 2; @@ -2339,7 +2339,7 @@ void Vehicle::UpdateWaitingForPassengers() num_seats_on_train &= 0x7F; - if (curRide->SupportsStatus(RIDE_STATUS_TESTING)) + if (curRide->SupportsStatus(RideStatus::Testing)) { if (time_waiting < 20) { @@ -2518,7 +2518,7 @@ void Vehicle::UpdateWaitingToDepart() } bool skipCheck = false; - if (shouldBreak || curRide->status != RIDE_STATUS_OPEN) + if (shouldBreak || curRide->status != RideStatus::Open) { if (curRide->mode == RideMode::ForwardRotation || curRide->mode == RideMode::BackwardRotation) { @@ -2897,7 +2897,7 @@ static bool ride_station_can_depart_synchronised(const Ride& ride, StationIndex if (!(sv_ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { - if (sv_ride->status != RIDE_STATUS_CLOSED) + if (sv_ride->status != RideStatus::Closed) { if (sv_ride->IsBlockSectioned()) { @@ -3559,7 +3559,7 @@ void Vehicle::UpdateCollisionSetup() if (curRide == nullptr) return; - if (curRide->status == RIDE_STATUS_SIMULATING) + if (curRide->status == RideStatus::Simulating) { SimulateCrash(); return; @@ -3578,10 +3578,10 @@ void Vehicle::UpdateCollisionSetup() curRide->Crash(*trainIndex); - if (curRide->status != RIDE_STATUS_CLOSED) + if (curRide->status != RideStatus::Closed) { // We require this to execute right away during the simulation, always ignore network and queue. - auto gameAction = RideSetStatusAction(curRide->id, RIDE_STATUS_CLOSED); + auto gameAction = RideSetStatusAction(curRide->id, RideStatus::Closed); GameActions::ExecuteNested(&gameAction); } } @@ -3650,7 +3650,7 @@ static constexpr const CoordsXY stru_9A3AC4[] = { void Vehicle::UpdateCrashSetup() { auto curRide = GetRide(); - if (curRide != nullptr && curRide->status == RIDE_STATUS_SIMULATING) + if (curRide != nullptr && curRide->status == RideStatus::Simulating) { SimulateCrash(); return; @@ -4787,7 +4787,7 @@ void Vehicle::UpdateSwinging() current_time = -1; var_CE++; - if (curRide->status != RIDE_STATUS_CLOSED) + if (curRide->status != RideStatus::Closed) { // It takes 3 swings to get into full swing // ride->rotations already takes this into account @@ -4878,7 +4878,7 @@ void Vehicle::UpdateFerrisWheelRotating() if (subState == Pitch) { bool shouldStop = true; - if (curRide->status != RIDE_STATUS_CLOSED) + if (curRide->status != RideStatus::Closed) { if (var_CE < curRide->rotations) shouldStop = false; @@ -4991,7 +4991,7 @@ void Vehicle::UpdateRotating() if (_vehicleBreakdown != BREAKDOWN_CONTROL_FAILURE) { bool shouldStop = true; - if (curRide->status != RIDE_STATUS_CLOSED) + if (curRide->status != RideStatus::Closed) { sprite = var_CE + 1; if (curRide->type == RIDE_TYPE_ENTERPRISE) @@ -5322,7 +5322,7 @@ void Vehicle::CrashOnLand() if (curRide == nullptr) return; - if (curRide->status == RIDE_STATUS_SIMULATING) + if (curRide->status == RideStatus::Simulating) { SimulateCrash(); return; @@ -5340,10 +5340,10 @@ void Vehicle::CrashOnLand() curRide->Crash(*trainIndex); - if (curRide->status != RIDE_STATUS_CLOSED) + if (curRide->status != RideStatus::Closed) { // We require this to execute right away during the simulation, always ignore network and queue. - auto gameAction = RideSetStatusAction(curRide->id, RIDE_STATUS_CLOSED); + auto gameAction = RideSetStatusAction(curRide->id, RideStatus::Closed); GameActions::ExecuteNested(&gameAction); } } @@ -5384,7 +5384,7 @@ void Vehicle::CrashOnWater() if (curRide == nullptr) return; - if (curRide->status == RIDE_STATUS_SIMULATING) + if (curRide->status == RideStatus::Simulating) { SimulateCrash(); return; @@ -5402,10 +5402,10 @@ void Vehicle::CrashOnWater() curRide->Crash(*trainIndex); - if (curRide->status != RIDE_STATUS_CLOSED) + if (curRide->status != RideStatus::Closed) { // We require this to execute right away during the simulation, always ignore network and queue. - auto gameAction = RideSetStatusAction(curRide->id, RIDE_STATUS_CLOSED); + auto gameAction = RideSetStatusAction(curRide->id, RideStatus::Closed); GameActions::ExecuteNested(&gameAction); } } @@ -9902,7 +9902,7 @@ void Vehicle::SetState(Vehicle::Status vehicleStatus, uint8_t subState) bool Vehicle::IsGhost() const { auto r = GetRide(); - return r != nullptr && r->status == RIDE_STATUS_SIMULATING; + return r != nullptr && r->status == RideStatus::Simulating; } void Vehicle::EnableCollisionsForTrain() diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index a98919efc0..a65acba622 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -657,7 +657,7 @@ ObjectiveStatus Objective::Check10RollerCoasters() const std::bitset type_already_counted; for (const auto& ride : GetRideManager()) { - if (ride.status == RIDE_STATUS_OPEN && ride.excitement >= RIDE_RATING(6, 00) && ride.subtype != OBJECT_ENTRY_INDEX_NULL) + if (ride.status == RideStatus::Open && ride.excitement >= RIDE_RATING(6, 00) && ride.subtype != OBJECT_ENTRY_INDEX_NULL) { auto rideEntry = ride.GetRideEntry(); if (rideEntry != nullptr) @@ -757,7 +757,7 @@ ObjectiveStatus Objective::Check10RollerCoastersLength() const auto rcs = 0; for (const auto& ride : GetRideManager()) { - if (ride.status == RIDE_STATUS_OPEN && ride.excitement >= RIDE_RATING(7, 00) && ride.subtype != OBJECT_ENTRY_INDEX_NULL) + if (ride.status == RideStatus::Open && ride.excitement >= RIDE_RATING(7, 00) && ride.subtype != OBJECT_ENTRY_INDEX_NULL) { auto rideEntry = ride.GetRideEntry(); if (rideEntry != nullptr) @@ -788,7 +788,7 @@ ObjectiveStatus Objective::CheckFinish5RollerCoasters() const auto rcs = 0; for (const auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_CLOSED && ride.excitement >= MinimumExcitement) + if (ride.status != RideStatus::Closed && ride.excitement >= MinimumExcitement) { auto rideEntry = ride.GetRideEntry(); if (rideEntry != nullptr) diff --git a/src/openrct2/scripting/ScRide.hpp b/src/openrct2/scripting/ScRide.hpp index 6ce02577c4..e76b096b3d 100644 --- a/src/openrct2/scripting/ScRide.hpp +++ b/src/openrct2/scripting/ScRide.hpp @@ -251,14 +251,16 @@ namespace OpenRCT2::Scripting { switch (ride->status) { - case RIDE_STATUS_CLOSED: + case RideStatus::Closed: return "closed"; - case RIDE_STATUS_OPEN: + case RideStatus::Open: return "open"; - case RIDE_STATUS_TESTING: + case RideStatus::Testing: return "testing"; - case RIDE_STATUS_SIMULATING: + case RideStatus::Simulating: return "simulating"; + case RideStatus::Count: // Meaningless but necessary to satisfy -Wswitch + return "count"; } } return ""; diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 7e4352cee6..5375a9a6c6 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -116,6 +116,8 @@ static TilePointerIndex _tileIndex; static std::vector _tileElements; static TilePointerIndex _tileIndexStash; static std::vector _tileElementsStash; +static size_t _tileElementsInUse; +static size_t _tileElementsInUseStash; static int32_t _mapSizeStash; static int32_t _currentRotationStash; @@ -125,6 +127,7 @@ void StashMap() _tileElementsStash = std::move(_tileElements); _mapSizeStash = gMapSize; _currentRotationStash = gCurrentRotation; + _tileElementsInUseStash = _tileElementsInUse; } void UnstashMap() @@ -133,6 +136,7 @@ void UnstashMap() _tileElements = std::move(_tileElementsStash); gMapSize = _mapSizeStash; gCurrentRotation = _currentRotationStash; + _tileElementsInUse = _tileElementsInUseStash; } const std::vector& GetTileElements() @@ -144,6 +148,7 @@ void SetTileElements(std::vector&& tileElements) { _tileElements = std::move(tileElements); _tileIndex = TilePointerIndex(MAXIMUM_MAP_SIZE_TECHNICAL, _tileElements.data()); + _tileElementsInUse = _tileElements.size(); } static TileElement GetDefaultSurfaceElement() @@ -234,27 +239,39 @@ void ReorganiseTileElements() ReorganiseTileElements(_tileElements.size()); } -static bool map_check_free_elements_and_reorganise(size_t numElements) +static bool map_check_free_elements_and_reorganise(size_t numElementsOnTile, size_t numNewElements) { + // Check hard cap on num in use tiles (this would be the size of _tileElements immediately after a reorg) + if (_tileElementsInUse + numNewElements > MAX_TILE_ELEMENTS) + { + gGameCommandErrorText = STR_ERR_LANDSCAPE_DATA_AREA_FULL; + return false; + } + + auto totalElementsRequired = numElementsOnTile + numNewElements; auto freeElements = _tileElements.capacity() - _tileElements.size(); - if (freeElements >= numElements) + if (freeElements >= totalElementsRequired) { return true; } else { - auto newCapacity = std::min(MAX_TILE_ELEMENTS, _tileElements.capacity() * 2); - if (newCapacity - _tileElements.size() < numElements) + // if space issue is due to fragmentation then Reorg Tiles without increasing capacity + if (_tileElements.size() > totalElementsRequired + _tileElementsInUse) { - // Limit reached - gGameCommandErrorText = STR_ERR_LANDSCAPE_DATA_AREA_FULL; - return false; - } - else - { - ReorganiseTileElements(newCapacity); - return true; + ReorganiseTileElements(); + // This check is not expected to fail + freeElements = _tileElements.capacity() - _tileElements.size(); + if (freeElements >= totalElementsRequired) + { + return true; + } } + + // Capacity must increase to handle the space (Note capacity can go above MAX_TILE_ELEMENTS) + auto newCapacity = _tileElements.capacity() * 2; + ReorganiseTileElements(newCapacity); + return true; } } @@ -263,7 +280,7 @@ static size_t CountElementsOnTile(const CoordsXY& loc); bool MapCheckCapacityAndReorganise(const CoordsXY& loc, size_t numElements) { auto numElementsOnTile = CountElementsOnTile(loc); - return map_check_free_elements_and_reorganise(numElementsOnTile + numElements); + return map_check_free_elements_and_reorganise(numElementsOnTile, numElements); } static void clear_elements_at(const CoordsXY& loc); @@ -1041,7 +1058,7 @@ void tile_element_remove(TileElement* tileElement) // Mark the latest element with the last element flag. (tileElement - 1)->SetLastForTile(true); tileElement->base_height = MAX_ELEMENT_HEIGHT; - + _tileElementsInUse--; if (tileElement == &_tileElements.back()) { _tileElements.pop_back(); @@ -1157,16 +1174,17 @@ static size_t CountElementsOnTile(const CoordsXY& loc) return count; } -static TileElement* AllocateTileElements(size_t count) +static TileElement* AllocateTileElements(size_t numElementsOnTile, size_t numNewElements) { - if (!map_check_free_elements_and_reorganise(count)) + if (!map_check_free_elements_and_reorganise(numElementsOnTile, numNewElements)) { log_error("Cannot insert new element"); return nullptr; } auto oldSize = _tileElements.size(); - _tileElements.resize(_tileElements.size() + count); + _tileElements.resize(_tileElements.size() + numElementsOnTile + numNewElements); + _tileElementsInUse += numNewElements; return &_tileElements[oldSize]; } @@ -1179,8 +1197,7 @@ TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants const auto& tileLoc = TileCoordsXYZ(loc); auto numElementsOnTileOld = CountElementsOnTile(loc); - auto numElementsOnTileNew = numElementsOnTileOld + 1; - auto* newTileElement = AllocateTileElements(numElementsOnTileNew); + auto* newTileElement = AllocateTileElements(numElementsOnTileOld, 1); auto* originalTileElement = _tileIndex.GetFirstElementAt(tileLoc); if (newTileElement == nullptr) { @@ -1328,7 +1345,7 @@ void map_obstruction_set_error_text(TileElement* tileElement, GameActions::Resul * bl = bl */ std::unique_ptr MapCanConstructWithClearAt( - const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, uint8_t crossingMode) + const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, uint8_t crossingMode, bool isTree) { int32_t northZ, eastZ, baseHeight, southZ, westZ, water_height; northZ = eastZ = baseHeight = southZ = westZ = water_height = 0; @@ -1380,7 +1397,7 @@ std::unique_ptr MapCanConstructWithClearAt( } } loc_68B9B7: - if (gParkFlags & PARK_FLAGS_FORBID_HIGH_CONSTRUCTION) + if (gParkFlags & PARK_FLAGS_FORBID_HIGH_CONSTRUCTION && !isTree) { auto heightFromGround = pos.clearanceZ - tileElement->GetBaseZ(); @@ -1507,9 +1524,9 @@ std::unique_ptr MapCanConstructWithClearAt( bool map_can_construct_with_clear_at( const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, money32* price, - uint8_t crossingMode) + uint8_t crossingMode, bool isTree) { - auto res = MapCanConstructWithClearAt(pos, clearFunc, quarterTile, flags, crossingMode); + auto res = MapCanConstructWithClearAt(pos, clearFunc, quarterTile, flags, crossingMode, isTree); if (auto message = res->ErrorMessage.AsStringId()) gGameCommandErrorText = *message; else diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 512b1732c7..f0c8607444 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -248,9 +248,10 @@ int32_t map_place_non_scenery_clear_func(TileElement** tile_element, const Coord int32_t map_place_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price); bool map_can_construct_with_clear_at( const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, money32* price, - uint8_t crossingMode); + uint8_t crossingMode, bool isTree = false); std::unique_ptr MapCanConstructWithClearAt( - const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, uint8_t crossingMode); + const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, uint8_t crossingMode, + bool isTree = false); std::unique_ptr MapCanConstructAt(const CoordsXYRangedZ& pos, QuarterTile bl); int32_t map_can_construct_at(const CoordsXYRangedZ& pos, QuarterTile bl); diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index f21c4a5b4e..58710151ec 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -525,7 +525,7 @@ money16 Park::CalculateTotalRideValueForMoney() const bool ridePricesUnlocked = park_ride_prices_unlocked() && !(gParkFlags & PARK_FLAGS_NO_MONEY); for (auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_OPEN) + if (ride.status != RideStatus::Open) continue; if (ride.lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue; @@ -556,7 +556,7 @@ uint32_t Park::CalculateSuggestedMaxGuests() const // TODO combine the two ride loops for (auto& ride : GetRideManager()) { - if (ride.status != RIDE_STATUS_OPEN) + if (ride.status != RideStatus::Open) continue; if (ride.lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue; diff --git a/src/openrct2/world/Scenery.h b/src/openrct2/world/Scenery.h index 45e8ecdf7b..7809f753cb 100644 --- a/src/openrct2/world/Scenery.h +++ b/src/openrct2/world/Scenery.h @@ -96,6 +96,7 @@ enum LARGE_SCENERY_FLAGS LARGE_SCENERY_FLAG_3D_TEXT = (1 << 2), // 0x4 LARGE_SCENERY_FLAG_ANIMATED = (1 << 3), // 0x8 LARGE_SCENERY_FLAG_PHOTOGENIC = (1 << 4), // 0x10 + LARGE_SCENERY_FLAG_IS_TREE = (1 << 5), // 0x20 }; enum WALL_SCENERY_FLAGS diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index 52ad88cbd2..a1baed3f35 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -316,7 +316,7 @@ namespace OpenRCT2::TileInspector GameActionResultPtr PasteElementAt(const CoordsXY& loc, TileElement element, bool isExecuting) { // Make sure there is enough space for the new element - if (!!MapCheckCapacityAndReorganise(loc)) + if (!MapCheckCapacityAndReorganise(loc)) { return std::make_unique(GameActions::Status::NoFreeElements, STR_NONE); } diff --git a/test/testpaint/Compat.cpp b/test/testpaint/Compat.cpp index d5c2d22557..2d90873a28 100644 --- a/test/testpaint/Compat.cpp +++ b/test/testpaint/Compat.cpp @@ -471,7 +471,7 @@ Ride* Vehicle::GetRide() const bool Vehicle::IsGhost() const { auto r = GetRide(); - return r != nullptr && r->status == RIDE_STATUS_SIMULATING; + return r != nullptr && r->status == RideStatus::Simulating; } uint8_t TileElementBase::GetOccupiedQuadrants() const diff --git a/test/tests/PlayTests.cpp b/test/tests/PlayTests.cpp index 2554f20395..55b5695373 100644 --- a/test/tests/PlayTests.cpp +++ b/test/tests/PlayTests.cpp @@ -107,7 +107,7 @@ TEST_F(PlayTests, SecondGuestInQueueShouldNotRideIfNoFunds) Ride& ferrisWheel = *it; // Open it for free - ride_set_status(&ferrisWheel, RIDE_STATUS_OPEN); + ride_set_status(&ferrisWheel, RideStatus::Open); execute(ferrisWheel.id, 0, true); // Ignore intensity to stimulate peeps to queue into ferris wheel @@ -167,7 +167,7 @@ TEST_F(PlayTests, CarRideWithOneCarOnlyAcceptsTwoGuests) Ride& carRide = *it; // Open it for free - ride_set_status(&carRide, RIDE_STATUS_OPEN); + ride_set_status(&carRide, RideStatus::Open); execute(carRide.id, 0, true); // Ignore intensity to stimulate peeps to queue into the ride