diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 45760dcd97..c204a4edbc 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,6 +1,7 @@ 0.4.26 (in development) ------------------------------------------------------------------------ - Feature: [#24949] Add an option to the command line screenshot function to draw debug bounding boxes. +- Improved: [#18714] Rides using block-sectioned operating modes can now enter simulating mode without having to complete the circuit first. - Improved: [#24734] Save files now use Zstd compression for faster saving and smaller files. - Improved: [#24890] The ride list is now searchable. - Improved: [#24893] The ride list now has headers, and can be sorted in both directions. diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index aab577a8b2..d3d9d838fd 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -49,7 +49,7 @@ using namespace OpenRCT2; // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -constexpr uint8_t kNetworkStreamVersion = 3; +constexpr uint8_t kNetworkStreamVersion = 4; const std::string kNetworkStreamID = std::string(kOpenRCT2Version) + "-" + std::to_string(kNetworkStreamVersion); diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 65d471d0a4..49c97c9ef7 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -2703,7 +2703,7 @@ void Ride::chainQueues() const * * rct2: 0x006D3319 */ -static ResultWithMessage RideCheckBlockBrakes(const CoordsXYE& input, CoordsXYE* output) +static ResultWithMessage RideCheckBlockBrakes(const CoordsXYE& input, CoordsXYE* output, bool shouldCheckCompleteCircuit) { if (input.element == nullptr || input.element->GetType() != TileElementType::Track) return { false }; @@ -2740,7 +2740,7 @@ static ResultWithMessage RideCheckBlockBrakes(const CoordsXYE& input, CoordsXYE* } } } - if (!it.looped) + if (!it.looped && shouldCheckCompleteCircuit) { // Not sure why this is the case... *output = it.last; @@ -3459,14 +3459,14 @@ static TrainReference VehicleCreateTrain( return train; } -static bool VehicleCreateTrains(Ride& ride, const CoordsXYZ& trainsPos, TrackElement* trackElement) +static bool VehicleCreateTrains(Ride& ride, const CoordsXYZ& trainsPos, TrackElement* trackElement, int16_t numberOfTrains) { TrainReference firstTrain = {}; TrainReference lastTrain = {}; int32_t remainingDistance = 0; bool allTrainsCreated = true; - for (int32_t vehicleIndex = 0; vehicleIndex < ride.numTrains; vehicleIndex++) + for (int32_t vehicleIndex = 0; vehicleIndex < numberOfTrains; vehicleIndex++) { if (ride.isBlockSectioned()) { @@ -3586,7 +3586,7 @@ static void RidecreateVehiclesFindFirstBlock(const Ride& ride, CoordsXYE* outXYE * Create and place the rides vehicles * rct2: 0x006DD84C */ -ResultWithMessage Ride::createVehicles(const CoordsXYE& element, bool isApplying) +ResultWithMessage Ride::createVehicles(const CoordsXYE& element, bool isApplying, bool isSimulating) { updateMaxVehicles(); if (subtype == kObjectEntryIndexNull) @@ -3595,7 +3595,12 @@ ResultWithMessage Ride::createVehicles(const CoordsXYE& element, bool isApplying } // Check if there are enough free sprite slots for all the vehicles - int32_t totalCars = numTrains * numCarsPerTrain; + int32_t numberOfTrains = numTrains; + if (isBlockSectioned() && isSimulating) + { + numberOfTrains = 1; + } + int32_t totalCars = numberOfTrains * numCarsPerTrain; if (totalCars > count_free_misc_sprite_slots()) { return { false, STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES }; @@ -3620,7 +3625,7 @@ ResultWithMessage Ride::createVehicles(const CoordsXYE& element, bool isApplying vehiclePos.z = trackElement->GetBaseZ(); } - if (!VehicleCreateTrains(*this, vehiclePos, trackElement)) + if (!VehicleCreateTrains(*this, vehiclePos, trackElement, numberOfTrains)) { // This flag is needed for Ride::removeVehicles() lifecycleFlags |= RIDE_LIFECYCLE_ON_TRACK; @@ -3640,7 +3645,7 @@ ResultWithMessage Ride::createVehicles(const CoordsXYE& element, bool isApplying // if (type != RIDE_TYPE_SPACE_RINGS && !getRideTypeDescriptor().HasFlag(RtdFlag::vehicleIsIntegral)) { - if (isBlockSectioned()) + if (isBlockSectioned() && !isSimulating) { CoordsXYE firstBlock{}; RidecreateVehiclesFindFirstBlock(*this, &firstBlock); @@ -4068,18 +4073,18 @@ ResultWithMessage Ride::test(bool isApplying) return message; } - message = changeStatusCheckTrackValidity(trackElement); + message = changeStatusCheckTrackValidity(trackElement, false); if (!message.Successful) { return message; } - return changeStatusCreateVehicles(isApplying, trackElement); + return changeStatusCreateVehicles(isApplying, trackElement, false); } ResultWithMessage Ride::simulate(bool isApplying) { - CoordsXYE trackElement, problematicTrackElement = {}; + CoordsXYE trackElement = {}; if (type == kRideTypeNull) { LOG_WARNING("Invalid ride type for ride %u", id.ToUnderlying()); @@ -4099,19 +4104,13 @@ ResultWithMessage Ride::simulate(bool isApplying) return message; } - if (isBlockSectioned() && findTrackGap(trackElement, &problematicTrackElement)) - { - RideScrollToTrackError(problematicTrackElement); - return { false, STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT }; - } - - message = changeStatusCheckTrackValidity(trackElement); + message = changeStatusCheckTrackValidity(trackElement, true); if (!message.Successful) { return message; } - return changeStatusCreateVehicles(isApplying, trackElement); + return changeStatusCreateVehicles(isApplying, trackElement, true); } /** @@ -4163,13 +4162,13 @@ ResultWithMessage Ride::open(bool isApplying) return message; } - message = changeStatusCheckTrackValidity(trackElement); + message = changeStatusCheckTrackValidity(trackElement, false); if (!message.Successful) { return message; } - return changeStatusCreateVehicles(isApplying, trackElement); + return changeStatusCreateVehicles(isApplying, trackElement, false); } /** @@ -5941,13 +5940,13 @@ ResultWithMessage Ride::changeStatusCheckCompleteCircuit(const CoordsXYE& trackE return { true }; } -ResultWithMessage Ride::changeStatusCheckTrackValidity(const CoordsXYE& trackElement) +ResultWithMessage Ride::changeStatusCheckTrackValidity(const CoordsXYE& trackElement, bool isSimulating) { CoordsXYE problematicTrackElement = {}; if (isBlockSectioned()) { - auto blockBrakeCheck = RideCheckBlockBrakes(trackElement, &problematicTrackElement); + auto blockBrakeCheck = RideCheckBlockBrakes(trackElement, &problematicTrackElement, !isSimulating); if (!blockBrakeCheck.Successful) { RideScrollToTrackError(problematicTrackElement); @@ -6003,7 +6002,7 @@ ResultWithMessage Ride::changeStatusCheckTrackValidity(const CoordsXYE& trackEle return { true }; } -ResultWithMessage Ride::changeStatusCreateVehicles(bool isApplying, const CoordsXYE& trackElement) +ResultWithMessage Ride::changeStatusCreateVehicles(bool isApplying, const CoordsXYE& trackElement, bool isSimulating) { if (isApplying) RideSetStartFinishPoints(id, trackElement); @@ -6011,7 +6010,7 @@ ResultWithMessage Ride::changeStatusCreateVehicles(bool isApplying, const Coords const auto& rtd = getRideTypeDescriptor(); if (!rtd.HasFlag(RtdFlag::noVehicles) && !(lifecycleFlags & RIDE_LIFECYCLE_ON_TRACK)) { - const auto createVehicleResult = createVehicles(trackElement, isApplying); + const auto createVehicleResult = createVehicles(trackElement, isApplying, isSimulating); if (!createVehicleResult.Successful) { return { false, createVehicleResult.Message }; diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index 608a44fa7e..467f12705e 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -331,7 +331,7 @@ public: private: void update(); void updateQueueLength(StationIndex stationIndex); - ResultWithMessage createVehicles(const CoordsXYE& element, bool isApplying); + ResultWithMessage createVehicles(const CoordsXYE& element, bool isApplying, bool isSimulating); void moveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, OpenRCT2::TrackElement& firstBlock); money64 calculateIncomePerHour() const; void chainQueues() const; @@ -340,8 +340,8 @@ private: ResultWithMessage changeStatusDoStationChecks(StationIndex& stationIndex); ResultWithMessage changeStatusGetStartElement(StationIndex stationIndex, CoordsXYE& trackElement); ResultWithMessage changeStatusCheckCompleteCircuit(const CoordsXYE& trackElement); - ResultWithMessage changeStatusCheckTrackValidity(const CoordsXYE& trackElement); - ResultWithMessage changeStatusCreateVehicles(bool isApplying, const CoordsXYE& trackElement); + ResultWithMessage changeStatusCheckTrackValidity(const CoordsXYE& trackElement, bool isSimulating); + ResultWithMessage changeStatusCreateVehicles(bool isApplying, const CoordsXYE& trackElement, bool isSimulating); public: bool canBreakDown() const;