diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index 75f6ed031d..b310363d6a 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -18,6 +18,7 @@ #include "ParkImporter.h" #include "actions/LandBuyRightsAction.h" #include "actions/LandSetRightsAction.h" +#include "actions/ResultWithMessage.h" #include "audio/audio.h" #include "core/Path.hpp" #include "entity/EntityList.h" @@ -513,7 +514,7 @@ namespace Editor * * rct2: 0x0066FEAC */ - std::pair CheckPark() + ResultWithMessage CheckPark() { int32_t parkSize = park_calculate_size(); if (parkSize == 0) diff --git a/src/openrct2/Editor.h b/src/openrct2/Editor.h index 17985ad6cc..90b32d3d85 100644 --- a/src/openrct2/Editor.h +++ b/src/openrct2/Editor.h @@ -12,6 +12,8 @@ #include "common.h" #include "object/Object.h" +struct ResultWithMessage; + namespace Editor { void Load(); @@ -20,7 +22,7 @@ namespace Editor void LoadTrackManager(); bool LoadLandscape(const utf8* path); - std::pair CheckPark(); + ResultWithMessage CheckPark(); std::pair CheckObjectSelection(); void OpenWindowsForCurrentStep(); diff --git a/src/openrct2/actions/ResultWithMessage.h b/src/openrct2/actions/ResultWithMessage.h new file mode 100644 index 0000000000..eb1b38bd31 --- /dev/null +++ b/src/openrct2/actions/ResultWithMessage.h @@ -0,0 +1,19 @@ +/***************************************************************************** + * Copyright (c) 2014-2022 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 "../localisation/StringIds.h" + +struct ResultWithMessage +{ + bool Successful{}; + rct_string_id Message = STR_NONE; +}; diff --git a/src/openrct2/actions/RideSetStatusAction.cpp b/src/openrct2/actions/RideSetStatusAction.cpp index ce0c49515e..f37e77b66d 100644 --- a/src/openrct2/actions/RideSetStatusAction.cpp +++ b/src/openrct2/actions/RideSetStatusAction.cpp @@ -93,19 +93,21 @@ GameActions::Result RideSetStatusAction::Query() const if (_status == RideStatus::Testing || _status == RideStatus::Simulating) { - if (!ride->Test(_status, false)) + const auto modeSwitchResult = ride->Test(_status, false); + if (!modeSwitchResult.Successful) { res.Error = GameActions::Status::Unknown; - res.ErrorMessage = gGameCommandErrorText; + res.ErrorMessage = modeSwitchResult.Message; return res; } } else if (_status == RideStatus::Open) { - if (!ride->Open(false)) + const auto modeSwitchResult = ride->Open(false); + if (!modeSwitchResult.Successful) { res.Error = GameActions::Status::Unknown; - res.ErrorMessage = gGameCommandErrorText; + res.ErrorMessage = modeSwitchResult.Message; return res; } } @@ -164,10 +166,11 @@ GameActions::Result RideSetStatusAction::Execute() const ride_clear_for_construction(ride); ride->RemovePeeps(); - if (!ride->Test(_status, true)) + const auto modeSwitchResult = ride->Test(_status, true); + if (!modeSwitchResult.Successful) { res.Error = GameActions::Status::Unknown; - res.ErrorMessage = gGameCommandErrorText; + res.ErrorMessage = modeSwitchResult.Message; return res; } @@ -205,18 +208,23 @@ GameActions::Result RideSetStatusAction::Execute() const if (_status == RideStatus::Testing) { - if (!ride->Test(_status, true)) + const auto modeSwitchResult = ride->Test(_status, true); + if (!modeSwitchResult.Successful) { res.Error = GameActions::Status::Unknown; - res.ErrorMessage = gGameCommandErrorText; + res.ErrorMessage = modeSwitchResult.Message; return res; } } - else if (!ride->Open(true)) + else { - res.Error = GameActions::Status::Unknown; - res.ErrorMessage = gGameCommandErrorText; - return res; + const auto modeSwitchResult = ride->Open(true); + if (!modeSwitchResult.Successful) + { + res.Error = GameActions::Status::Unknown; + res.ErrorMessage = modeSwitchResult.Message; + return res; + } } ride->race_winner = EntityId::GetNull(); diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 4b3cbcb56f..a17b96d626 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -106,6 +106,7 @@ + @@ -995,4 +996,4 @@ - \ No newline at end of file + diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 574b40c9e9..12e71aabd0 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -15,6 +15,7 @@ #include "../Game.h" #include "../Input.h" #include "../OpenRCT2.h" +#include "../actions/ResultWithMessage.h" #include "../actions/RideSetSettingAction.h" #include "../actions/RideSetStatusAction.h" #include "../actions/RideSetVehicleAction.h" @@ -94,6 +95,12 @@ static constexpr const int32_t RideInspectionInterval[] = { static std::vector _rides; +struct StationIndexWithMessage +{ + ::StationIndex StationIndex; + rct_string_id Message = STR_NONE; +}; + // Static function declarations Staff* find_closest_mechanic(const CoordsXY& entrancePosition, int32_t forInspection); static void ride_breakdown_status_update(Ride* ride); @@ -2506,7 +2513,7 @@ void ride_set_map_tooltip(TileElement* tileElement) * * rct2: 0x006B4CC1 */ -static StationIndex ride_mode_check_valid_station_numbers(Ride* ride) +static ResultWithMessage ride_mode_check_valid_station_numbers(Ride* ride) { uint16_t numStations = 0; for (const auto& station : ride->GetStations()) @@ -2524,14 +2531,12 @@ static StationIndex ride_mode_check_valid_station_numbers(Ride* ride) case RideMode::PoweredLaunch: case RideMode::LimPoweredLaunch: if (numStations <= 1) - return StationIndex::FromUnderlying(1); - gGameCommandErrorText = STR_UNABLE_TO_OPERATE_WITH_MORE_THAN_ONE_STATION_IN_THIS_MODE; - return StationIndex::FromUnderlying(0); + return { true }; + return { false, STR_UNABLE_TO_OPERATE_WITH_MORE_THAN_ONE_STATION_IN_THIS_MODE }; case RideMode::Shuttle: if (numStations >= 2) - return StationIndex::FromUnderlying(1); - gGameCommandErrorText = STR_UNABLE_TO_OPERATE_WITH_LESS_THAN_TWO_STATIONS_IN_THIS_MODE; - return StationIndex::FromUnderlying(0); + return { true }; + return { false, STR_UNABLE_TO_OPERATE_WITH_LESS_THAN_TWO_STATIONS_IN_THIS_MODE }; default: { // This is workaround for multiple compilation errors of type "enumeration value ‘RIDE_MODE_*' not handled @@ -2542,50 +2547,47 @@ static StationIndex ride_mode_check_valid_station_numbers(Ride* ride) if (ride->type == RIDE_TYPE_GO_KARTS || ride->type == RIDE_TYPE_MINI_GOLF) { if (numStations <= 1) - return StationIndex::FromUnderlying(1); - gGameCommandErrorText = STR_UNABLE_TO_OPERATE_WITH_MORE_THAN_ONE_STATION_IN_THIS_MODE; - return StationIndex::FromUnderlying(0); + return { true }; + return { false, STR_UNABLE_TO_OPERATE_WITH_MORE_THAN_ONE_STATION_IN_THIS_MODE }; } - return StationIndex::FromUnderlying(1); + return { true }; } /** * returns stationIndex of first station on success * STATION_INDEX_NULL on failure. */ -static StationIndex ride_mode_check_station_present(Ride* ride) +static StationIndexWithMessage ride_mode_check_station_present(Ride* ride) { auto stationIndex = ride_get_first_valid_station_start(ride); if (stationIndex.IsNull()) { - gGameCommandErrorText = STR_NOT_YET_CONSTRUCTED; if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_NO_TRACK)) - return StationIndex::GetNull(); + return { StationIndex::GetNull(), STR_NOT_YET_CONSTRUCTED }; if (ride->type == RIDE_TYPE_MAZE) - return StationIndex::GetNull(); + return { StationIndex::GetNull(), STR_NOT_YET_CONSTRUCTED }; - gGameCommandErrorText = STR_REQUIRES_A_STATION_PLATFORM; - return StationIndex::GetNull(); + return { StationIndex::GetNull(), STR_REQUIRES_A_STATION_PLATFORM }; } - return stationIndex; + return { stationIndex }; } /** * * rct2: 0x006B5872 */ -static int32_t ride_check_for_entrance_exit(RideId rideIndex) +static ResultWithMessage ride_check_for_entrance_exit(RideId rideIndex) { auto ride = get_ride(rideIndex); if (ride == nullptr) - return 0; + return { false }; if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_IS_SHOP)) - return 1; + return { true }; uint8_t entrance = 0; uint8_t exit = 0; @@ -2615,17 +2617,15 @@ static int32_t ride_check_for_entrance_exit(RideId rideIndex) if (entrance == 0) { - gGameCommandErrorText = STR_ENTRANCE_NOT_YET_BUILT; - return 0; + return { false, STR_ENTRANCE_NOT_YET_BUILT }; } if (exit == 0) { - gGameCommandErrorText = STR_EXIT_NOT_YET_BUILT; - return 0; + return { false, STR_EXIT_NOT_YET_BUILT }; } - return 1; + return { true }; } /** @@ -2665,7 +2665,7 @@ void Ride::ChainQueues() const * * rct2: 0x006D3319 */ -static int32_t ride_check_block_brakes(CoordsXYE* input, CoordsXYE* output) +static ResultWithMessage ride_check_block_brakes(CoordsXYE* input, CoordsXYE* output) { RideId rideIndex = input->element->AsTrack()->GetRideIndex(); rct_window* w = window_find_by_class(WC_RIDE_CONSTRUCTION); @@ -2681,34 +2681,30 @@ static int32_t ride_check_block_brakes(CoordsXYE* input, CoordsXYE* output) auto type = it.last.element->AsTrack()->GetTrackType(); if (type == TrackElemType::EndStation) { - gGameCommandErrorText = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION; *output = it.current; - return 0; + return { false, STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION }; } if (type == TrackElemType::BlockBrakes) { - gGameCommandErrorText = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_EACH_OTHER; *output = it.current; - return 0; + return { false, STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_EACH_OTHER }; } if (it.last.element->AsTrack()->HasChain() && type != TrackElemType::LeftCurvedLiftHill && type != TrackElemType::RightCurvedLiftHill) { - gGameCommandErrorText = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_THE_TOP_OF_THIS_LIFT_HILL; *output = it.current; - return 0; + return { false, STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_THE_TOP_OF_THIS_LIFT_HILL }; } } } if (!it.looped) { // Not sure why this is the case... - gGameCommandErrorText = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION; *output = it.last; - return 0; + return { false, STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION }; } - return 1; + return { true }; } /** @@ -3456,25 +3452,24 @@ static void ride_create_vehicles_find_first_block(Ride* ride, CoordsXYE* outXYEl * Create and place the rides vehicles * rct2: 0x006DD84C */ -bool Ride::CreateVehicles(const CoordsXYE& element, bool isApplying) +ResultWithMessage Ride::CreateVehicles(const CoordsXYE& element, bool isApplying) { UpdateMaxVehicles(); if (subtype == OBJECT_ENTRY_INDEX_NULL) { - return true; + return { true }; } // Check if there are enough free sprite slots for all the vehicles int32_t totalCars = num_vehicles * num_cars_per_train; if (totalCars > count_free_misc_sprite_slots()) { - gGameCommandErrorText = STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES; - return false; + return { false, STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES }; } if (!isApplying) { - return true; + return { true }; } auto* trackElement = element.element->AsTrack(); @@ -3496,8 +3491,7 @@ bool Ride::CreateVehicles(const CoordsXYE& element, bool isApplying) // This flag is needed for Ride::RemoveVehicles() lifecycle_flags |= RIDE_LIFECYCLE_ON_TRACK; RemoveVehicles(); - gGameCommandErrorText = STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES; - return false; + return { false, STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES }; } // return true; @@ -3540,7 +3534,7 @@ bool Ride::CreateVehicles(const CoordsXYE& element, bool isApplying) } } ride_update_vehicle_colours(this); - return true; + return { true }; } /** @@ -3603,7 +3597,7 @@ void Ride::MoveTrainsToBlockBrakes(TrackElement* firstBlock) * appropriate track. * rct2: 0x006D31A6 */ -static bool ride_initialise_cable_lift_track(Ride* ride, bool isApplying) +static ResultWithMessage ride_initialise_cable_lift_track(Ride* ride, bool isApplying) { CoordsXYZ location; location.SetNull(); @@ -3616,14 +3610,13 @@ static bool ride_initialise_cable_lift_track(Ride* ride, bool isApplying) if (location.IsNull()) { - gGameCommandErrorText = STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION; - return false; + return { false, STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION }; } bool success = false; TileElement* tileElement = map_get_first_element_at(location); if (tileElement == nullptr) - return success; + return { false }; do { if (tileElement->GetType() != TileElementType::Track) @@ -3641,7 +3634,7 @@ static bool ride_initialise_cable_lift_track(Ride* ride, bool isApplying) } while (!(tileElement++)->IsLastForTile()); if (!success) - return false; + return { false }; enum { @@ -3687,8 +3680,7 @@ static bool ride_initialise_cable_lift_track(Ride* ride, bool isApplying) state = STATE_REST_OF_TRACK; break; default: - gGameCommandErrorText = STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION; - return false; + return { false, STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION }; } break; } @@ -3700,45 +3692,43 @@ static bool ride_initialise_cable_lift_track(Ride* ride, bool isApplying) GetTrackElementOriginAndApplyChanges({ tmpLoc, direction }, trackType, 0, &tileElement, flags); } } - return true; + return { true }; } /** * * rct2: 0x006DF4D4 */ -static bool ride_create_cable_lift(RideId rideIndex, bool isApplying) +static ResultWithMessage ride_create_cable_lift(RideId rideIndex, bool isApplying) { auto ride = get_ride(rideIndex); if (ride == nullptr) - return false; + return { false }; if (ride->mode != RideMode::ContinuousCircuitBlockSectioned && ride->mode != RideMode::ContinuousCircuit) { - gGameCommandErrorText = STR_CABLE_LIFT_UNABLE_TO_WORK_IN_THIS_OPERATING_MODE; - return false; + return { false, STR_CABLE_LIFT_UNABLE_TO_WORK_IN_THIS_OPERATING_MODE }; } if (ride->num_circuits > 1) { - gGameCommandErrorText = STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL; - return false; + return { false, STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL }; } if (count_free_misc_sprite_slots() <= 5) { - gGameCommandErrorText = STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES; - return false; + return { false, STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES }; } - if (!ride_initialise_cable_lift_track(ride, isApplying)) + auto cableLiftInitialiseResult = ride_initialise_cable_lift_track(ride, isApplying); + if (!cableLiftInitialiseResult.Successful) { - return false; + return { false, cableLiftInitialiseResult.Message }; } if (!isApplying) { - return true; + return { true }; } auto cableLiftLoc = ride->CableLiftLoc; @@ -3777,7 +3767,7 @@ static bool ride_create_cable_lift(RideId rideIndex, bool isApplying) ride->lifecycle_flags |= RIDE_LIFECYCLE_CABLE_LIFT; head->CableLiftUpdateTrackMotion(); - return true; + return { true }; } /** @@ -3879,14 +3869,14 @@ TrackElement* Ride::GetOriginElement(StationIndex stationIndex) const return nullptr; } -bool Ride::Test(RideStatus newStatus, bool isApplying) +ResultWithMessage Ride::Test(RideStatus newStatus, bool isApplying) { CoordsXYE trackElement, problematicTrackElement = {}; if (type == RIDE_TYPE_NULL) { log_warning("Invalid ride type for ride %u", id.ToUnderlying()); - return false; + return { false }; } if (newStatus != RideStatus::Simulating) @@ -3894,17 +3884,23 @@ bool Ride::Test(RideStatus newStatus, bool isApplying) window_close_by_number(WC_RIDE_CONSTRUCTION, id.ToUnderlying()); } - StationIndex stationIndex = ride_mode_check_station_present(this); + auto stationIndexCheck = ride_mode_check_station_present(this); + auto stationIndex = stationIndexCheck.StationIndex; if (stationIndex.IsNull()) - return false; + return { false, stationIndexCheck.Message }; - if (!ride_mode_check_valid_station_numbers(this).ToUnderlying()) - return false; + auto stationNumbersCheck = ride_mode_check_valid_station_numbers(this); + if (!stationNumbersCheck.Successful) + return { false, stationNumbersCheck.Message }; - if (newStatus != RideStatus::Simulating && !ride_check_for_entrance_exit(id)) + if (newStatus != RideStatus::Simulating) { - ConstructMissingEntranceOrExit(); - return false; + auto entranceExitCheck = ride_check_for_entrance_exit(id); + if (!entranceExitCheck.Successful) + { + ConstructMissingEntranceOrExit(); + return { false, entranceExitCheck.Message }; + } } // z = ride->stations[i].GetBaseZ(); @@ -3916,7 +3912,7 @@ bool Ride::Test(RideStatus newStatus, bool isApplying) { // Maze is strange, station start is 0... investigation required if (type != RIDE_TYPE_MAZE) - return false; + return { false }; } if (mode == RideMode::ContinuousCircuit || IsBlockSectioned()) @@ -3924,18 +3920,18 @@ bool Ride::Test(RideStatus newStatus, bool isApplying) if (ride_find_track_gap(this, &trackElement, &problematicTrackElement) && (newStatus != RideStatus::Simulating || IsBlockSectioned())) { - gGameCommandErrorText = STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT; ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT }; } } if (IsBlockSectioned()) { - if (!ride_check_block_brakes(&trackElement, &problematicTrackElement)) + auto blockBrakeCheck = ride_check_block_brakes(&trackElement, &problematicTrackElement); + if (!blockBrakeCheck.Successful) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, blockBrakeCheck.Message }; } } @@ -3944,20 +3940,18 @@ bool Ride::Test(RideStatus newStatus, bool isApplying) rct_ride_entry* rideType = get_ride_entry(subtype); if (rideType->flags & RIDE_ENTRY_FLAG_NO_INVERSIONS) { - gGameCommandErrorText = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; if (ride_check_track_contains_inversions(&trackElement, &problematicTrackElement)) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN }; } } if (rideType->flags & RIDE_ENTRY_FLAG_NO_BANKED_TRACK) { - gGameCommandErrorText = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; if (ride_check_track_contains_banked(&trackElement, &problematicTrackElement)) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN }; } } } @@ -3966,22 +3960,19 @@ bool Ride::Test(RideStatus newStatus, bool isApplying) { if (!ride_find_track_gap(this, &trackElement, &problematicTrackElement)) { - gGameCommandErrorText = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; - return false; + return { false, STR_RIDE_MUST_START_AND_END_WITH_STATIONS }; } - gGameCommandErrorText = STR_STATION_NOT_LONG_ENOUGH; if (!ride_check_station_length(&trackElement, &problematicTrackElement)) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_STATION_NOT_LONG_ENOUGH }; } - gGameCommandErrorText = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; if (!ride_check_start_and_end_is_station(&trackElement)) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_RIDE_MUST_START_AND_END_WITH_STATIONS }; } } @@ -3991,26 +3982,28 @@ bool Ride::Test(RideStatus newStatus, bool isApplying) const auto& rtd = GetRideTypeDescriptor(); if (!rtd.HasFlag(RIDE_TYPE_FLAG_NO_VEHICLES) && !(lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) { - if (!CreateVehicles(trackElement, isApplying)) + const auto createVehicleResult = CreateVehicles(trackElement, isApplying); + if (!createVehicleResult.Successful) { - return false; + return { false, createVehicleResult.Message }; } } if (rtd.HasFlag(RIDE_TYPE_FLAG_ALLOW_CABLE_LIFT_HILL) && (lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED) && !(lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT)) { - if (!ride_create_cable_lift(id, isApplying)) - return false; + const auto createCableLiftResult = ride_create_cable_lift(id, isApplying); + if (!createCableLiftResult.Successful) + return { false, createCableLiftResult.Message }; } - return true; + return { true }; } /** * * rct2: 0x006B4EEA */ -bool Ride::Open(bool isApplying) +ResultWithMessage Ride::Open(bool isApplying) { CoordsXYE trackElement, problematicTrackElement = {}; @@ -4024,17 +4017,20 @@ bool Ride::Open(bool isApplying) window_close_by_number(WC_RIDE_CONSTRUCTION, id.ToUnderlying()); } - StationIndex stationIndex = ride_mode_check_station_present(this); + auto stationIndexCheck = ride_mode_check_station_present(this); + auto stationIndex = stationIndexCheck.StationIndex; if (stationIndex.IsNull()) - return false; + return { false, stationIndexCheck.Message }; - if (!ride_mode_check_valid_station_numbers(this).ToUnderlying()) - return false; + auto stationNumbersCheck = ride_mode_check_valid_station_numbers(this); + if (!stationNumbersCheck.Successful) + return { false, stationNumbersCheck.Message }; - if (!ride_check_for_entrance_exit(id)) + auto entranceExitCheck = ride_check_for_entrance_exit(id); + if (!entranceExitCheck.Successful) { ConstructMissingEntranceOrExit(); - return false; + return { false, entranceExitCheck.Message }; } if (isApplying) @@ -4052,25 +4048,25 @@ bool Ride::Open(bool isApplying) { // Maze is strange, station start is 0... investigation required if (type != RIDE_TYPE_MAZE) - return false; + return { false }; } if (mode == RideMode::Race || mode == RideMode::ContinuousCircuit || IsBlockSectioned()) { if (ride_find_track_gap(this, &trackElement, &problematicTrackElement)) { - gGameCommandErrorText = STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT; ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT }; } } if (IsBlockSectioned()) { - if (!ride_check_block_brakes(&trackElement, &problematicTrackElement)) + auto blockBrakeCheck = ride_check_block_brakes(&trackElement, &problematicTrackElement); + if (!blockBrakeCheck.Successful) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, blockBrakeCheck.Message }; } } @@ -4079,20 +4075,18 @@ bool Ride::Open(bool isApplying) rct_ride_entry* rideEntry = get_ride_entry(subtype); if (rideEntry->flags & RIDE_ENTRY_FLAG_NO_INVERSIONS) { - gGameCommandErrorText = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; if (ride_check_track_contains_inversions(&trackElement, &problematicTrackElement)) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN }; } } if (rideEntry->flags & RIDE_ENTRY_FLAG_NO_BANKED_TRACK) { - gGameCommandErrorText = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; if (ride_check_track_contains_banked(&trackElement, &problematicTrackElement)) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN }; } } } @@ -4101,22 +4095,19 @@ bool Ride::Open(bool isApplying) { if (!ride_find_track_gap(this, &trackElement, &problematicTrackElement)) { - gGameCommandErrorText = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; - return false; + return { false, STR_RIDE_MUST_START_AND_END_WITH_STATIONS }; } - gGameCommandErrorText = STR_STATION_NOT_LONG_ENOUGH; if (!ride_check_station_length(&trackElement, &problematicTrackElement)) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_STATION_NOT_LONG_ENOUGH }; } - gGameCommandErrorText = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; if (!ride_check_start_and_end_is_station(&trackElement)) { ride_scroll_to_track_error(&problematicTrackElement); - return false; + return { false, STR_RIDE_MUST_START_AND_END_WITH_STATIONS }; } } @@ -4125,20 +4116,22 @@ bool Ride::Open(bool isApplying) if (!GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_NO_VEHICLES) && !(lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) { - if (!CreateVehicles(trackElement, isApplying)) + const auto createVehicleResult = CreateVehicles(trackElement, isApplying); + if (!createVehicleResult.Successful) { - return false; + return { false, createVehicleResult.Message }; } } if ((GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_ALLOW_CABLE_LIFT_HILL)) && (lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED) && !(lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT)) { - if (!ride_create_cable_lift(id, isApplying)) - return false; + const auto createCableLiftResult = ride_create_cable_lift(id, isApplying); + if (!createCableLiftResult.Successful) + return { false, createCableLiftResult.Message }; } - return true; + return { true }; } /** diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index bbb2cf47a3..68e7a296d1 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -10,6 +10,7 @@ #pragma once #include "../Limits.h" +#include "../actions/ResultWithMessage.h" #include "../common.h" #include "../object/MusicObject.h" #include "../rct2/DATLimits.h" @@ -33,6 +34,7 @@ struct Guest; struct Staff; struct Vehicle; struct rct_ride_entry; +struct ResultWithMessage; #define RIDE_TYPE_NULL 255 #define RIDE_ADJACENCY_CHECK_DISTANCE 5 @@ -296,7 +298,7 @@ private: void UpdateChairlift(); void UpdateSpiralSlide(); void UpdateQueueLength(StationIndex stationIndex); - bool CreateVehicles(const CoordsXYE& element, bool isApplying); + ResultWithMessage CreateVehicles(const CoordsXYE& element, bool isApplying); void MoveTrainsToBlockBrakes(TrackElement* firstBlock); money64 CalculateIncomePerHour() const; void ChainQueues() const; @@ -332,8 +334,8 @@ public: void StopGuestsQueuing(); void ValidateStations(); - bool Open(bool isApplying); - bool Test(RideStatus newStatus, bool isApplying); + ResultWithMessage Open(bool isApplying); + ResultWithMessage Test(RideStatus newStatus, bool isApplying); RideMode GetDefaultMode() const;