1
0
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:
Michael Steenbeek
2024-12-23 20:39:28 +01:00
committed by GitHub
5 changed files with 87 additions and 1 deletions

View File

@@ -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 isnt 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.

View File

@@ -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);

View File

@@ -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);
}
}
/**

View File

@@ -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());

View File

@@ -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);