From d8da02e7dd217068e0299f9994eb2602bd4031ce Mon Sep 17 00:00:00 2001 From: matheusvb3 <98937378+matheusvb3@users.noreply.github.com> Date: Sat, 4 Oct 2025 19:52:26 -0300 Subject: [PATCH] Make peeps not stop on level crossings (#25089) * Check if actions can be performed safely * Add explanatory comment * Refactor Easter egg logic in Guest::UpdateWalking * Add changelog entry * Make the comment more explanatory * Update NetworkBase.cpp * Update changelog for v0.28 --- distribution/changelog.txt | 1 + src/openrct2/entity/Guest.cpp | 46 +++++++++++----------------- src/openrct2/entity/Peep.cpp | 11 ++++++- src/openrct2/entity/Peep.h | 1 + src/openrct2/entity/Staff.cpp | 2 +- src/openrct2/network/NetworkBase.cpp | 2 +- src/openrct2/world/MapAnimation.cpp | 2 +- 7 files changed, 33 insertions(+), 32 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 720e99e11c..f55b88530b 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,5 +1,6 @@ 0.4.28 (in development) ------------------------------------------------------------------------ +- Change: [#25089] Peep actions and animations that cause them to stop moving no longer trigger when they are on a level crossing. - Fix: [#25299] The Mine Train Coaster left large helix draws incorrect sprites at certain angles (original bug). 0.4.27 (2025-10-04) diff --git a/src/openrct2/entity/Guest.cpp b/src/openrct2/entity/Guest.cpp index 15f25db082..80783427d8 100644 --- a/src/openrct2/entity/Guest.cpp +++ b/src/openrct2/entity/Guest.cpp @@ -532,7 +532,7 @@ void Guest::GivePassingGuestPizza(Guest& passingPeep) int32_t otherPeepOppositeDirection = passingPeep.Orientation >> 3; if (peepDirection == otherPeepOppositeDirection) { - if (passingPeep.IsActionInterruptable()) + if (passingPeep.IsActionInterruptableSafely()) { passingPeep.Action = PeepActionType::Wave2; passingPeep.AnimationFrameNum = 0; @@ -547,7 +547,7 @@ void Guest::MakePassingGuestSick(Guest& passingPeep) if (passingPeep.State != PeepState::Walking) return; - if (passingPeep.IsActionInterruptable()) + if (passingPeep.IsActionInterruptableSafely()) { passingPeep.Action = PeepActionType::ThrowUp; passingPeep.AnimationFrameNum = 0; @@ -595,7 +595,7 @@ void Guest::UpdateEasterEggInteractions() { if ((ScenarioRand() & 0xFFFF) <= 1456) { - if (IsActionInterruptable()) + if (IsActionInterruptableSafely()) { Action = PeepActionType::Joy; AnimationFrameNum = 0; @@ -800,7 +800,7 @@ void Guest::UpdateMotivesIdle() { if ((ScenarioRand() & 0xFF) <= static_cast((Nausea - 128) / 2)) { - if (IsActionInterruptable()) + if (IsActionInterruptableSafely()) { Action = PeepActionType::ThrowUp; AnimationFrameNum = 0; @@ -2426,7 +2426,7 @@ void Guest::ChoseNotToGoOnRide(const Ride& ride, bool peepAtRide, bool updateLas void Guest::ReadMap() { - if (IsActionInterruptable() && !IsOnLevelCrossing()) + if (IsActionInterruptableSafely()) { Action = PeepActionType::ReadMap; AnimationFrameNum = 0; @@ -5473,32 +5473,22 @@ void Guest::UpdateWalking() const auto currentTicks = getGameState().currentTicks; - if (!IsOnLevelCrossing()) + if (IsActionInterruptableSafely()) { - if (PeepFlags & PEEP_FLAGS_WAVING && IsActionInterruptable() && (0xFFFF & ScenarioRand()) < 936) + PeepActionType NewAction = Action; + + if (PeepFlags & PEEP_FLAGS_WAVING && (0xFFFF & ScenarioRand()) < 936) + NewAction = PeepActionType::Wave2; + else if (PeepFlags & PEEP_FLAGS_PHOTO && (0xFFFF & ScenarioRand()) < 936) + NewAction = PeepActionType::TakePhoto; + else if (PeepFlags & PEEP_FLAGS_PAINTING && (0xFFFF & ScenarioRand()) < 936) + NewAction = PeepActionType::DrawPicture; + + if (NewAction != Action) { - Action = PeepActionType::Wave2; + Action = NewAction; AnimationFrameNum = 0; AnimationImageIdOffset = 0; - - UpdateCurrentAnimationType(); - } - - if (PeepFlags & PEEP_FLAGS_PHOTO && IsActionInterruptable() && (0xFFFF & ScenarioRand()) < 936) - { - Action = PeepActionType::TakePhoto; - AnimationFrameNum = 0; - AnimationImageIdOffset = 0; - - UpdateCurrentAnimationType(); - } - - if (PeepFlags & PEEP_FLAGS_PAINTING && IsActionInterruptable() && (0xFFFF & ScenarioRand()) < 936) - { - Action = PeepActionType::DrawPicture; - AnimationFrameNum = 0; - AnimationImageIdOffset = 0; - UpdateCurrentAnimationType(); } } @@ -7129,7 +7119,7 @@ void Guest::InsertNewThought(PeepThoughtType thought_type, RideId rideId) void Guest::InsertNewThought(PeepThoughtType thoughtType, uint16_t thoughtArguments) { PeepActionType newAction = PeepThoughtToActionMap[EnumValue(thoughtType)].action; - if (newAction != PeepActionType::Walking && IsActionInterruptable()) + if (newAction != PeepActionType::Walking && IsActionInterruptableSafely()) { Action = newAction; AnimationFrameNum = 0; diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index 7fe3308b7c..2063dd9cb8 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -1229,7 +1229,7 @@ void PeepApplause() GuestReleaseBalloon(peep, peep->z + 9); // Clap - if ((peep->State == PeepState::Walking || peep->State == PeepState::Queuing) && peep->IsActionInterruptable()) + if ((peep->State == PeepState::Walking || peep->State == PeepState::Queuing) && peep->IsActionInterruptableSafely()) { peep->Action = PeepActionType::Clap; peep->AnimationFrameNum = 0; @@ -1533,6 +1533,15 @@ bool Peep::IsActionInterruptable() const return IsActionIdle() || IsActionWalking(); } +/** + * Used to avoid peep action and animation triggers that cause them to stop moving and might put them at risk + * of getting run over at level crossings, such as guests reading the map and entertainers performing. + */ +bool Peep::IsActionInterruptableSafely() const +{ + return IsActionInterruptable() && !IsOnLevelCrossing(); +} + void PeepSetMapTooltip(Peep* peep) { auto ft = Formatter(); diff --git a/src/openrct2/entity/Peep.h b/src/openrct2/entity/Peep.h index f4689518a9..b6af2ff277 100644 --- a/src/openrct2/entity/Peep.h +++ b/src/openrct2/entity/Peep.h @@ -388,6 +388,7 @@ public: // Peep bool IsActionWalking() const; bool IsActionIdle() const; bool IsActionInterruptable() const; + bool IsActionInterruptableSafely() const; // Reset the peep's stored goal, which means they will forget any stored pathfinding history // on the next GuestPathfinding::ChooseDirection call. diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index 54b7f16e17..d45bfb45c3 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -924,7 +924,7 @@ void Staff::EntertainerUpdateNearbyPeeps() const */ bool Staff::DoEntertainerPathFinding() { - if (((ScenarioRand() & 0xFFFF) <= 0x4000) && IsActionInterruptable()) + if (((ScenarioRand() & 0xFFFF) <= 0x4000) && IsActionInterruptableSafely()) { Action = (ScenarioRand() & 1) ? PeepActionType::Wave2 : PeepActionType::Joy; AnimationFrameNum = 0; diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index afe97f0e2f..27b45a8232 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -47,7 +47,7 @@ // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -constexpr uint8_t kStreamVersion = 0; +constexpr uint8_t kStreamVersion = 1; const std::string kStreamID = std::string(kOpenRCT2Version) + "-" + std::to_string(kStreamVersion); diff --git a/src/openrct2/world/MapAnimation.cpp b/src/openrct2/world/MapAnimation.cpp index 82a05c515b..bc79e887ad 100644 --- a/src/openrct2/world/MapAnimation.cpp +++ b/src/openrct2/world/MapAnimation.cpp @@ -176,7 +176,7 @@ static std::optional UpdateSmallSceneryAnimation( auto quad = EntityTileList(CoordsXY{ loc.x, loc.y } - CoordsDirectionDelta[direction]); for (auto peep : quad) { - if (peep->State != PeepState::Walking || peep->z != baseZ || peep->Action < PeepActionType::Idle) + if (peep->State != PeepState::Walking || peep->z != baseZ || !peep->IsActionInterruptableSafely()) continue; peep->Action = PeepActionType::CheckTime; peep->AnimationFrameNum = 0;