/***************************************************************************** * Copyright (c) 2014-2020 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ #include "RideSetVehicleAction.h" #include "../Cheats.h" #include "../Context.h" #include "../core/MemoryStream.h" #include "../drawing/Drawing.h" #include "../interface/Window.h" #include "../localisation/Localisation.h" #include "../localisation/StringIds.h" #include "../management/Research.h" #include "../object/ObjectManager.h" #include "../ride/Ride.h" #include "../ride/RideData.h" #include "../ui/UiContext.h" #include "../ui/WindowManager.h" #include "../util/Util.h" #include "../world/Park.h" constexpr static rct_string_id SetVehicleTypeErrorTitle[] = { STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL, STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL, STR_RIDE_SET_VEHICLE_TYPE_FAIL, }; RideSetVehicleAction::RideSetVehicleAction(ride_id_t rideIndex, RideSetVehicleType type, uint8_t value, uint8_t colour) : _rideIndex(rideIndex) , _type(type) , _value(value) , _colour(colour) { } void RideSetVehicleAction::AcceptParameters(GameActionParameterVisitor& visitor) { visitor.Visit("ride", _rideIndex); visitor.Visit("type", _type); visitor.Visit("value", _value); visitor.Visit("colour", _colour); } uint16_t RideSetVehicleAction::GetActionFlags() const { return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; } void RideSetVehicleAction::Serialise(DataSerialiser& stream) { GameAction::Serialise(stream); stream << DS_TAG(_rideIndex) << DS_TAG(_type) << DS_TAG(_value) << DS_TAG(_colour); } GameActions::Result::Ptr RideSetVehicleAction::Query() const { if (_type >= RideSetVehicleType::Count) { log_warning("Invalid type. type = %d", _type); } auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; auto ride = get_ride(_rideIndex); if (ride == nullptr) { log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) { return std::make_unique( GameActions::Status::Broken, errTitle, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING); } if (ride->status != RideStatus::Closed && ride->status != RideStatus::Simulating) { return std::make_unique(GameActions::Status::NotClosed, errTitle, STR_MUST_BE_CLOSED_FIRST); } switch (_type) { case RideSetVehicleType::NumTrains: case RideSetVehicleType::NumCarsPerTrain: break; case RideSetVehicleType::RideEntry: { if (!ride_is_vehicle_type_valid(ride)) { log_error("Invalid vehicle type. type = %d", _value); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } auto rideEntry = get_ride_entry(_value); if (rideEntry == nullptr) { log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } // Validate preset vehicle_colour_preset_list* presetList = rideEntry->vehicle_preset_list; if (_colour >= presetList->count && _colour != 255 && _colour != 0) { log_error("Unknown vehicle colour preset. colour = %d", _colour); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } break; } default: log_error("Unknown vehicle command. type = %d", _type); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } return std::make_unique(); } GameActions::Result::Ptr RideSetVehicleAction::Execute() const { auto errTitle = SetVehicleTypeErrorTitle[EnumValue(_type)]; auto ride = get_ride(_rideIndex); if (ride == nullptr) { log_warning("Invalid game command, ride_id = %u", uint32_t(_rideIndex)); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } switch (_type) { case RideSetVehicleType::NumTrains: ride_clear_for_construction(ride); ride_remove_peeps(ride); ride->vehicle_change_timeout = 100; ride->proposed_num_vehicles = _value; break; case RideSetVehicleType::NumCarsPerTrain: { ride_clear_for_construction(ride); ride_remove_peeps(ride); ride->vehicle_change_timeout = 100; invalidate_test_results(ride); auto rideEntry = get_ride_entry(ride->subtype); if (rideEntry == nullptr) { log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } auto clampValue = _value; if (!gCheatsDisableTrainLengthLimit) { clampValue = std::clamp(clampValue, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); } ride->proposed_num_cars_per_train = clampValue; break; } case RideSetVehicleType::RideEntry: { ride_clear_for_construction(ride); ride_remove_peeps(ride); ride->vehicle_change_timeout = 100; invalidate_test_results(ride); ride->subtype = _value; auto rideEntry = get_ride_entry(ride->subtype); if (rideEntry == nullptr) { log_warning("Invalid ride entry, ride->subtype = %d", ride->subtype); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } ride_set_vehicle_colours_to_random_preset(ride, _colour); if (!gCheatsDisableTrainLengthLimit) { ride->proposed_num_cars_per_train = std::clamp( ride->proposed_num_cars_per_train, rideEntry->min_cars_in_train, rideEntry->max_cars_in_train); } break; } default: log_error("Unknown vehicle command. type = %d", _type); return std::make_unique(GameActions::Status::InvalidParameters, errTitle); } ride->num_circuits = 1; ride->UpdateMaxVehicles(); auto res = std::make_unique(); if (!ride->overall_view.IsNull()) { auto location = ride->overall_view.ToTileCentre(); res->Position = { location, tile_element_height(res->Position) }; } auto intent = Intent(INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE); intent.putExtra(INTENT_EXTRA_RIDE_ID, EnumValue(_rideIndex)); context_broadcast_intent(&intent); gfx_invalidate_screen(); return res; } bool RideSetVehicleAction::ride_is_vehicle_type_valid(Ride* ride) const { bool selectionShouldBeExpanded; int32_t rideTypeIterator, rideTypeIteratorMax; if (gCheatsShowVehiclesFromOtherTrackTypes && !( ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE) || ride->type == RIDE_TYPE_MAZE || ride->type == RIDE_TYPE_MINI_GOLF)) { selectionShouldBeExpanded = true; rideTypeIterator = 0; rideTypeIteratorMax = RIDE_TYPE_COUNT - 1; } else { selectionShouldBeExpanded = false; rideTypeIterator = ride->type; rideTypeIteratorMax = ride->type; } for (; rideTypeIterator <= rideTypeIteratorMax; rideTypeIterator++) { if (selectionShouldBeExpanded) { if (GetRideTypeDescriptor(rideTypeIterator).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE)) continue; if (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF) continue; } auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator); for (auto rideEntryIndex : rideEntries) { if (rideEntryIndex == _value) { if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus) { return false; } return true; } } } return false; }