mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-10 09:32:29 +01:00
Merge pull request #23459 from Gymnasiast/fix/1122
Fix #1122: Trains can spawn on cable lift hill
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
- Improved: [#23404] Folders are now paired with an icon in the load/save window.
|
||||
- Improved: [#23431] Opaque water and Corkscrew Roller Coaster boosters now show up if RCT1 isn’t linked.
|
||||
- Change: [#23413] The max number of park entrance objects has been raised to 255.
|
||||
- Fix: [#1122] Trains spawned on a cable lift hill will fall down and crash (original bug).
|
||||
- Fix: [#22742, #22793] In game console does not handle format tokens properly.
|
||||
- Fix: [#23286] Currency formatted incorrectly in the in game console.
|
||||
- Fix: [#23348] Console set commands don't print output properly.
|
||||
|
||||
@@ -50,7 +50,7 @@ using namespace OpenRCT2;
|
||||
// It is used for making sure only compatible builds get connected, even within
|
||||
// single OpenRCT2 version.
|
||||
|
||||
constexpr uint8_t kNetworkStreamVersion = 2;
|
||||
constexpr uint8_t kNetworkStreamVersion = 3;
|
||||
|
||||
const std::string kNetworkStreamID = std::string(OPENRCT2_VERSION) + "-" + std::to_string(kNetworkStreamVersion);
|
||||
|
||||
|
||||
@@ -3666,6 +3666,23 @@ ResultWithMessage Ride::CreateVehicles(const CoordsXYE& element, bool isApplying
|
||||
*/
|
||||
void Ride::MoveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, TrackElement& firstBlock)
|
||||
{
|
||||
// If the ride has a cable lift, we don't want to fetch the cable lift element and the block preceding it
|
||||
TrackElement* cableLiftTileElement = nullptr;
|
||||
TrackElement* cableLiftPreviousBlock = nullptr;
|
||||
if (lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED)
|
||||
{
|
||||
cableLiftTileElement = MapGetTrackElementAt(CableLiftLoc);
|
||||
if (cableLiftTileElement != nullptr)
|
||||
{
|
||||
cableLiftTileElement = MapGetTrackElementAt(CableLiftLoc);
|
||||
if (cableLiftTileElement != nullptr)
|
||||
{
|
||||
CoordsXYZ location = CableLiftLoc;
|
||||
cableLiftPreviousBlock = TrackGetPreviousBlock(location, reinterpret_cast<TileElement*>(cableLiftTileElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < NumTrains; i++)
|
||||
{
|
||||
auto train = GetEntity<Vehicle>(vehicles[i]);
|
||||
@@ -3695,6 +3712,14 @@ void Ride::MoveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, TrackEle
|
||||
break;
|
||||
}
|
||||
|
||||
// Setting the first block before the cable lift to the same state as the cable lift ensures that any train which
|
||||
// would be placed on the cable lift will instead stop on the block before it. As there can only be one cable lift
|
||||
// per ride and there must always be at least one block left free, there will be enough blocks remaining. This fixes
|
||||
// the bug in #1122.
|
||||
if (cableLiftTileElement != nullptr && cableLiftPreviousBlock != nullptr)
|
||||
{
|
||||
cableLiftPreviousBlock->SetBrakeClosed(cableLiftTileElement->IsBrakeClosed());
|
||||
}
|
||||
firstBlock.SetBrakeClosed(true);
|
||||
for (Vehicle* car = train; car != nullptr; car = GetEntity<Vehicle>(car->next_vehicle_on_train))
|
||||
{
|
||||
@@ -3722,6 +3747,12 @@ void Ride::MoveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, TrackEle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After all trains are in position, set the block preceding the cable lift to open.
|
||||
if (cableLiftPreviousBlock != nullptr)
|
||||
{
|
||||
cableLiftPreviousBlock->SetBrakeClosed(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -523,6 +523,58 @@ void TrackGetFront(const CoordsXYE& input, CoordsXYE* output)
|
||||
*output = lastTrack;
|
||||
}
|
||||
|
||||
TrackElement* TrackGetPreviousBlock(CoordsXYZ& location, TileElement* tileElement)
|
||||
{
|
||||
CoordsXYZ startLocation = location;
|
||||
TrackBeginEnd trackBeginEnd, slowTrackBeginEnd;
|
||||
TileElement slowTileElement = *tileElement;
|
||||
bool counter = true;
|
||||
CoordsXY slowLocation = location;
|
||||
do
|
||||
{
|
||||
if (!TrackBlockGetPrevious({ location, tileElement }, &trackBeginEnd))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (trackBeginEnd.begin_x == startLocation.x && trackBeginEnd.begin_y == startLocation.y
|
||||
&& tileElement == trackBeginEnd.begin_element)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
location.x = trackBeginEnd.end_x;
|
||||
location.y = trackBeginEnd.end_y;
|
||||
location.z = trackBeginEnd.begin_z;
|
||||
tileElement = trackBeginEnd.begin_element;
|
||||
|
||||
// #2081: prevent infinite loop
|
||||
counter = !counter;
|
||||
if (counter)
|
||||
{
|
||||
TrackBlockGetPrevious({ slowLocation, &slowTileElement }, &slowTrackBeginEnd);
|
||||
slowLocation.x = slowTrackBeginEnd.end_x;
|
||||
slowLocation.y = slowTrackBeginEnd.end_y;
|
||||
slowTileElement = *(slowTrackBeginEnd.begin_element);
|
||||
if (slowLocation == location && slowTileElement.GetBaseZ() == tileElement->GetBaseZ()
|
||||
&& slowTileElement.GetType() == tileElement->GetType()
|
||||
&& slowTileElement.GetDirection() == tileElement->GetDirection())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} while (!(trackBeginEnd.begin_element->AsTrack()->IsBlockStart()));
|
||||
|
||||
// Get the start of the track block instead of the end
|
||||
location = { trackBeginEnd.begin_x, trackBeginEnd.begin_y, trackBeginEnd.begin_z };
|
||||
auto trackOrigin = MapGetTrackElementAtOfTypeSeq(location, trackBeginEnd.begin_element->AsTrack()->GetTrackType(), 0);
|
||||
if (trackOrigin == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return trackOrigin->AsTrack();
|
||||
}
|
||||
|
||||
TrackRoll TrackGetActualBank(TileElement* tileElement, TrackRoll bank)
|
||||
{
|
||||
auto ride = GetRide(tileElement->AsTrack()->GetRideIndex());
|
||||
|
||||
@@ -702,6 +702,8 @@ bool TrackCircuitIteratorsMatch(const TrackCircuitIterator* firstIt, const Track
|
||||
void TrackGetBack(const CoordsXYE& input, CoordsXYE* output);
|
||||
void TrackGetFront(const CoordsXYE& input, CoordsXYE* output);
|
||||
|
||||
TrackElement* TrackGetPreviousBlock(CoordsXYZ& location, TileElement* tileElement);
|
||||
|
||||
bool TrackElementIsCovered(OpenRCT2::TrackElemType trackElementType);
|
||||
OpenRCT2::TrackElemType UncoverTrackElement(OpenRCT2::TrackElemType trackElementType);
|
||||
bool TrackTypeIsStation(OpenRCT2::TrackElemType trackType);
|
||||
|
||||
Reference in New Issue
Block a user