diff --git a/src/openrct2/GameStateSnapshots.cpp b/src/openrct2/GameStateSnapshots.cpp index 6f0bbcad1f..2bfb86510f 100644 --- a/src/openrct2/GameStateSnapshots.cpp +++ b/src/openrct2/GameStateSnapshots.cpp @@ -455,6 +455,7 @@ struct GameStateSnapshots final : public IGameStateSnapshots COMPARE_FIELD(Vehicle, target_seat_rotation); COMPARE_FIELD(Vehicle, BoatLocation.x); COMPARE_FIELD(Vehicle, BoatLocation.y); + COMPARE_FIELD(Vehicle, BlockBrakeSpeed); } void CompareSpriteDataLitter(const Litter& spriteBase, const Litter& spriteCmp, GameStateSpriteChange& changeData) const diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index 3faf02e2cb..e9965f5be8 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -7381,6 +7381,60 @@ void Vehicle::Sub6DBF3E() } } +/** + * Determine whether to use block brake speed or brake speed. If block brake is closed or no block brake present, use the + * brake's speed; if block brake is open, use maximum of brake speed or block brake speed. + */ +uint8_t Vehicle::ChooseBrakeSpeed() const +{ + if (GetTrackType() != TrackElemType::Brakes) + return brake_speed; + auto trackElement = MapGetTrackElementAtOfTypeSeq(TrackLocation, GetTrackType(), 0); + if (trackElement != nullptr) + { + if (trackElement->AsTrack()->IsBrakeClosed()) + return brake_speed; + else + return std::max(brake_speed, BlockBrakeSpeed); + } + return brake_speed; +} + +/** + * Populate the vehicle's brake_speed and BlockBrakeSpeed values. + */ +void Vehicle::PopulateBrakeSpeed(const CoordsXYZ& vehicleTrackLocation, TrackElement& brake) +{ + auto trackSpeed = brake.GetBrakeBoosterSpeed(); + brake_speed = trackSpeed; + if (brake.GetTrackType() != TrackElemType::Brakes) + { + BlockBrakeSpeed = trackSpeed; + return; + } + // As soon as feasible, encode block brake speed into track element so the lookforward can be skipped here. + + CoordsXYE output = CoordsXYE(vehicleTrackLocation.x, vehicleTrackLocation.y, reinterpret_cast(&brake)); + int32_t outputZ = vehicleTrackLocation.z; + uint16_t timeoutCount = 256; + do + { + if (output.element->AsTrack()->GetTrackType() == TrackElemType::BlockBrakes) + { + BlockBrakeSpeed = output.element->AsTrack()->GetBrakeBoosterSpeed(); + return; + } + if (output.element->AsTrack()->GetTrackType() != TrackElemType::Brakes) + { + break; + } + timeoutCount--; + } while (TrackBlockGetNext(&output, &output, &outputZ, nullptr) && timeoutCount); + + // If block brake is not found, use the track's speed + BlockBrakeSpeed = trackSpeed; +} + /** * * rct2: 0x006DB08C @@ -7550,7 +7604,7 @@ bool Vehicle::UpdateTrackMotionForwardsGetNewTrack(uint16_t trackType, const Rid } SetTrackDirection(location.direction); SetTrackType(trackType); - brake_speed = tileElement->AsTrack()->GetBrakeBoosterSpeed(); + PopulateBrakeSpeed(TrackLocation, *tileElement->AsTrack()); if (trackType == TrackElemType::OnRidePhoto) { trigger_on_ride_photo(TrackLocation, tileElement); @@ -7597,8 +7651,9 @@ Loc6DAEB9: && curRide.breakdown_reason_pending == BREAKDOWN_BRAKES_FAILURE; if (!hasBrakesFailure || curRide.mechanic_status == RIDE_MECHANIC_STATUS_HAS_FIXED_STATION_BRAKES) { - auto brakeSpeed = brake_speed << 16; - if (brakeSpeed < _vehicleVelocityF64E08) + auto brakeSpeed = ChooseBrakeSpeed(); + + if ((brakeSpeed << 16) < _vehicleVelocityF64E08) { acceleration = -_vehicleVelocityF64E08 * 16; } @@ -7955,7 +8010,7 @@ bool Vehicle::UpdateTrackMotionBackwardsGetNewTrack(uint16_t trackType, const Ri direction &= 3; SetTrackType(trackType); SetTrackDirection(direction); - brake_speed = tileElement->AsTrack()->GetBrakeBoosterSpeed(); + PopulateBrakeSpeed(TrackLocation, *tileElement->AsTrack()); // There are two bytes before the move info list uint16_t trackTotalProgress = GetTrackProgress(); @@ -7986,7 +8041,9 @@ bool Vehicle::UpdateTrackMotionBackwards(const CarEntry* carEntry, const Ride& c if (trackType == TrackElemType::Brakes) { - if (-(brake_speed << 16) > _vehicleVelocityF64E08) + auto brakeSpeed = ChooseBrakeSpeed(); + + if (-(brakeSpeed << 16) > _vehicleVelocityF64E08) { acceleration = _vehicleVelocityF64E08 * -16; } @@ -9408,4 +9465,5 @@ void Vehicle::Serialise(DataSerialiser& stream) stream << seat_rotation; stream << target_seat_rotation; stream << BoatLocation; + stream << BlockBrakeSpeed; } diff --git a/src/openrct2/ride/Vehicle.h b/src/openrct2/ride/Vehicle.h index 55fc833ecf..a3f98f6ac1 100644 --- a/src/openrct2/ride/Vehicle.h +++ b/src/openrct2/ride/Vehicle.h @@ -210,6 +210,7 @@ struct Vehicle : EntityBase uint8_t seat_rotation; uint8_t target_seat_rotation; CoordsXY BoatLocation; + uint8_t BlockBrakeSpeed; constexpr bool IsHead() const { @@ -377,6 +378,8 @@ private: void UpdateLandscapeDoor() const; void UpdateLandscapeDoorBackwards() const; int32_t CalculateRiderBraking() const; + uint8_t ChooseBrakeSpeed() const; + void PopulateBrakeSpeed(const CoordsXYZ& vehicleTrackLocation, TrackElement& brake); void Loc6DCE02(const Ride& curRide); };