mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-24 23:34:37 +01:00
Merge pull request #15623 from Gymnasiast/fix/14482
Fix #14482: Rides with Crooked House hack sometimes misbehave
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
- Fix: [#13465] Creating a scenario based on a won save game results in a scenario that’s instantly won.
|
||||
- Fix: [#13912] “Dome park” no longer renders dome correctly.
|
||||
- Fix: [#14316] Closing the Track Designs Manager window causes broken state.
|
||||
- Fix: [#14482, #15258] Rides with invisibility hacks sometimes behave incorrectly.
|
||||
- Fix: [#14649] ImageImporter incorrectly remaps colours outside the RCT2 palette.
|
||||
- Fix: [#14667] “Extreme Hawaiian Island” has unpurchaseable land tiles (original bug).
|
||||
- Fix: [#14741] Crash when exiting OpenRCT2 on macOS.
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
// This string specifies which version of network stream current build uses.
|
||||
// It is used for making sure only compatible builds get connected, even within
|
||||
// single OpenRCT2 version.
|
||||
#define NETWORK_STREAM_VERSION "14"
|
||||
#define NETWORK_STREAM_VERSION "15"
|
||||
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
|
||||
|
||||
static Peep* _pickup_peep = nullptr;
|
||||
|
||||
@@ -140,9 +140,9 @@ bool RCT2TrackTypeIsBooster(uint8_t rideType, uint16_t trackType)
|
||||
&& trackType == TrackElemType::Booster;
|
||||
}
|
||||
|
||||
track_type_t RCT2TrackTypeToOpenRCT2(RCT12TrackType origTrackType, uint8_t rideType)
|
||||
track_type_t RCT2TrackTypeToOpenRCT2(RCT12TrackType origTrackType, uint8_t rideType, bool convertFlat)
|
||||
{
|
||||
if (GetRideTypeDescriptor(rideType).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE))
|
||||
if (convertFlat && GetRideTypeDescriptor(rideType).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE))
|
||||
return RCT12FlatTrackTypeToOpenRCT2(origTrackType);
|
||||
if (origTrackType == TrackElemType::RotationControlToggleAlias && !RCT2TrackTypeIsBooster(rideType, origTrackType))
|
||||
return TrackElemType::RotationControlToggle;
|
||||
|
||||
@@ -1069,7 +1069,7 @@ ObjectEntryIndex RCT2RideTypeToOpenRCT2RideType(uint8_t rct2RideType, const rct_
|
||||
bool RCT2TrackTypeIsBooster(uint8_t rideType, uint16_t trackType);
|
||||
bool RCT2RideTypeNeedsConversion(uint8_t rct2RideType);
|
||||
uint8_t OpenRCT2RideTypeToRCT2RideType(ObjectEntryIndex openrct2Type);
|
||||
track_type_t RCT2TrackTypeToOpenRCT2(RCT12TrackType origTrackType, uint8_t rideType);
|
||||
track_type_t RCT2TrackTypeToOpenRCT2(RCT12TrackType origTrackType, uint8_t rideType, bool convertFlat);
|
||||
RCT12TrackType OpenRCT2TrackTypeToRCT2(track_type_t origTrackType);
|
||||
|
||||
/**
|
||||
|
||||
@@ -86,6 +86,7 @@ private:
|
||||
rct_s6_data _s6{};
|
||||
uint8_t _gameVersion = 0;
|
||||
bool _isSV7 = false;
|
||||
std::bitset<RCT12_MAX_RIDES_IN_PARK> _isFlatRide{};
|
||||
|
||||
public:
|
||||
S6Importer(IObjectRepository& objectRepository)
|
||||
@@ -234,6 +235,7 @@ public:
|
||||
|
||||
scenario_rand_seed(_s6.scenario_srand_0, _s6.scenario_srand_1);
|
||||
|
||||
DetermineFlatRideStatus();
|
||||
ImportTileElements();
|
||||
ImportEntities();
|
||||
|
||||
@@ -544,6 +546,46 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This code is needed to detect hacks where a tracked ride has been made invisible
|
||||
* by setting its ride type to a flat ride.
|
||||
*
|
||||
* The function should classify rides as follows:
|
||||
* 1. If the ride type is tracked and its vehicles also belong on tracks, it should be classified as tracked.
|
||||
* 2. If the ride type is a flat ride, but its vehicles belong on tracks,
|
||||
* it should be classified as tracked (Crooked House mod).
|
||||
* 3. If the ride type is tracked and its vehicles belong to a flat ride, it should be classified as tracked.
|
||||
* 4. If the ride type is a flat ride and its vehicles also belong to a flat ride, it should be classified as a flat ride.
|
||||
*/
|
||||
void DetermineFlatRideStatus()
|
||||
{
|
||||
for (uint8_t index = 0; index < RCT12_MAX_RIDES_IN_PARK; index++)
|
||||
{
|
||||
auto src = &_s6.rides[index];
|
||||
if (src->type == RIDE_TYPE_NULL)
|
||||
continue;
|
||||
|
||||
auto subtype = RCTEntryIndexToOpenRCT2EntryIndex(src->subtype);
|
||||
auto* rideEntry = get_ride_entry(subtype);
|
||||
// If the ride is tracked, we don’t need to check the vehicle any more.
|
||||
if (!GetRideTypeDescriptor(src->type).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE))
|
||||
{
|
||||
_isFlatRide[index] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have established the ride type is a flat ride, which means the vehicle now determines whether it is a
|
||||
// true flat ride (scenario 4) or a tracked ride with an invisibility hack (scenario 2).
|
||||
ObjectEntryIndex originalRideType = src->type;
|
||||
if (rideEntry != nullptr)
|
||||
{
|
||||
originalRideType = ride_entry_get_first_non_null_ride_type(rideEntry);
|
||||
}
|
||||
const auto isFlatRide = GetRideTypeDescriptor(originalRideType).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE);
|
||||
_isFlatRide.set(static_cast<size_t>(index), isFlatRide);
|
||||
}
|
||||
}
|
||||
|
||||
void ImportRide(Ride* dst, const rct2_ride* src, const ride_id_t rideIndex)
|
||||
{
|
||||
*dst = {};
|
||||
@@ -860,7 +902,8 @@ public:
|
||||
dst.CurrentRide = RCT12RideIdToOpenRCT2RideId(src.current_ride);
|
||||
dst.State = src.state;
|
||||
if (src.current_ride < RCT12_MAX_RIDES_IN_PARK && _s6.rides[src.current_ride].type < std::size(RideTypeDescriptors))
|
||||
dst.ProximityTrackType = RCT2TrackTypeToOpenRCT2(src.proximity_track_type, _s6.rides[src.current_ride].type);
|
||||
dst.ProximityTrackType = RCT2TrackTypeToOpenRCT2(
|
||||
src.proximity_track_type, _s6.rides[src.current_ride].type, _isFlatRide[src.current_ride]);
|
||||
else
|
||||
dst.ProximityTrackType = 0xFF;
|
||||
dst.ProximityBaseHeight = src.proximity_base_height;
|
||||
@@ -1203,7 +1246,7 @@ public:
|
||||
auto rideType = _s6.rides[src2->GetRideIndex()].type;
|
||||
track_type_t trackType = static_cast<track_type_t>(src2->GetTrackType());
|
||||
|
||||
dst2->SetTrackType(RCT2TrackTypeToOpenRCT2(trackType, rideType));
|
||||
dst2->SetTrackType(RCT2TrackTypeToOpenRCT2(trackType, rideType, _isFlatRide[src2->GetRideIndex()]));
|
||||
dst2->SetRideType(rideType);
|
||||
dst2->SetSequenceIndex(src2->GetSequenceIndex());
|
||||
dst2->SetRideIndex(RCT12RideIdToOpenRCT2RideId(src2->GetRideIndex()));
|
||||
@@ -1648,7 +1691,7 @@ template<> void S6Importer::ImportEntity<Vehicle>(const RCT12SpriteBase& baseSrc
|
||||
dst->SetTrackType(src->GetTrackType());
|
||||
// RotationControlToggle and Booster are saved as the same track piece ID
|
||||
// Which one the vehicle is using must be determined
|
||||
if (GetRideTypeDescriptor(ride.type).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE))
|
||||
if (_isFlatRide[src->ride])
|
||||
{
|
||||
dst->SetTrackType(RCT12FlatTrackTypeToOpenRCT2(src->GetTrackType()));
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ public:
|
||||
_stream.Read(&t6TrackElement, sizeof(rct_td46_track_element));
|
||||
TrackDesignTrackElement trackElement{};
|
||||
|
||||
track_type_t trackType = RCT2TrackTypeToOpenRCT2(t6TrackElement.type, td->type);
|
||||
track_type_t trackType = RCT2TrackTypeToOpenRCT2(t6TrackElement.type, td->type, true);
|
||||
if (trackType == TrackElemType::InvertedUp90ToFlatQuarterLoopAlias)
|
||||
{
|
||||
trackType = TrackElemType::MultiDimInvertedUp90ToFlatQuarterLoop;
|
||||
|
||||
Reference in New Issue
Block a user