diff --git a/src/openrct2/entity/Guest.cpp b/src/openrct2/entity/Guest.cpp index 5e633d77eb..ce85f6369b 100644 --- a/src/openrct2/entity/Guest.cpp +++ b/src/openrct2/entity/Guest.cpp @@ -5202,6 +5202,169 @@ void Guest::UpdateRideShopLeave() } } +/* From peep_update */ +static void GuestUpdateThoughts(Guest* peep) +{ + // Thoughts must always have a gap of at least + // 220 ticks in age between them. In order to + // allow this when a thought is new it enters + // a holding zone. Before it becomes fresh. + int32_t add_fresh = 1; + int32_t fresh_thought = -1; + for (int32_t i = 0; i < kPeepMaxThoughts; i++) + { + if (peep->Thoughts[i].type == PeepThoughtType::None) + break; + + if (peep->Thoughts[i].freshness == 1) + { + add_fresh = 0; + // If thought is fresh we wait 220 ticks + // before allowing a new thought to become fresh. + if (++peep->Thoughts[i].fresh_timeout >= 220) + { + peep->Thoughts[i].fresh_timeout = 0; + // Thought is no longer fresh + peep->Thoughts[i].freshness++; + add_fresh = 1; + } + } + else if (peep->Thoughts[i].freshness > 1) + { + if (++peep->Thoughts[i].fresh_timeout == 0) + { + // When thought is older than ~6900 ticks remove it + if (++peep->Thoughts[i].freshness >= 28) + { + peep->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_THOUGHTS; + + // Clear top thought, push others up + if (i < kPeepMaxThoughts - 2) + { + memmove(&peep->Thoughts[i], &peep->Thoughts[i + 1], sizeof(PeepThought) * (kPeepMaxThoughts - i - 1)); + } + peep->Thoughts[kPeepMaxThoughts - 1].type = PeepThoughtType::None; + } + } + } + else + { + fresh_thought = i; + } + } + // If there are no fresh thoughts + // a previously new thought can become + // fresh. + if (add_fresh && fresh_thought != -1) + { + peep->Thoughts[fresh_thought].freshness = 1; + peep->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_THOUGHTS; + } +} + +void Guest::Update() +{ + if (PeepFlags & PEEP_FLAGS_POSITION_FROZEN) + { + if (!(PeepFlags & PEEP_FLAGS_ANIMATION_FROZEN)) + { + // This is circumventing other logic, so only update every few ticks + if ((getGameState().currentTicks & 3) == 0) + { + if (IsActionWalking()) + UpdateWalkingAnimation(); + else + UpdateActionAnimation(); + Invalidate(); + } + } + return; + } + else if (PeepFlags & PEEP_FLAGS_ANIMATION_FROZEN) + { + // Animation is frozen while position is not. This allows a peep to walk + // around without its sprite being updated, which looks very glitchy. + // We'll just remove the flag and continue as normal, in this case. + PeepFlags &= ~PEEP_FLAGS_ANIMATION_FROZEN; + } + + auto* guest = As(); + if (guest != nullptr) + { + if (!guest->PreviousRide.IsNull()) + if (++guest->PreviousRideTimeOut >= 720) + guest->PreviousRide = RideId::GetNull(); + + GuestUpdateThoughts(guest); + } + + // Walking speed logic + uint32_t stepsToTake = Energy; + if (stepsToTake < 95 && State == PeepState::Queuing) + stepsToTake = 95; + if ((PeepFlags & PEEP_FLAGS_SLOW_WALK) && State != PeepState::Queuing) + stepsToTake /= 2; + if (IsActionWalking() && GetNextIsSloped()) + { + stepsToTake /= 2; + if (State == PeepState::Queuing) + stepsToTake += stepsToTake / 2; + } + // Ensure guests make it across a level crossing in time + constexpr auto minStepsForCrossing = 55; + if (stepsToTake < minStepsForCrossing && IsOnPathBlockedByVehicle()) + stepsToTake = minStepsForCrossing; + + uint32_t carryCheck = StepProgress + stepsToTake; + StepProgress = carryCheck; + if (carryCheck <= 255) + { + if (guest != nullptr) + { + guest->UpdateEasterEggInteractions(); + } + } + else + { + // Loc68FD2F + switch (State) + { + case PeepState::Falling: + UpdateFalling(); + break; + case PeepState::One: + Update1(); + break; + case PeepState::OnRide: + // No action + break; + case PeepState::Picked: + UpdatePicked(); + break; + default: + { + if (guest != nullptr) + { + guest->UpdateGuest(); + } + else + { + auto* staff = As(); + if (staff != nullptr) + { + staff->UpdateStaff(stepsToTake); + } + else + { + assert(false); + } + } + break; + } + } + } +} + void Guest::UpdateGuest() { switch (State) diff --git a/src/openrct2/entity/Guest.h b/src/openrct2/entity/Guest.h index 41c6b85a94..69faf913ef 100644 --- a/src/openrct2/entity/Guest.h +++ b/src/openrct2/entity/Guest.h @@ -320,6 +320,7 @@ public: uint8_t FavouriteRideRating; uint64_t ItemFlags; + void Update(); void UpdateGuest(); void Tick128UpdateGuest(uint32_t index); uint64_t GetFoodOrDrinkFlags() const; diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index 35e0539fa9..3db2b02654 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -928,173 +928,6 @@ void Peep::UpdatePicked() } } -/* From peep_update */ -static void GuestUpdateThoughts(Guest* peep) -{ - // Thoughts must always have a gap of at least - // 220 ticks in age between them. In order to - // allow this when a thought is new it enters - // a holding zone. Before it becomes fresh. - int32_t add_fresh = 1; - int32_t fresh_thought = -1; - for (int32_t i = 0; i < kPeepMaxThoughts; i++) - { - if (peep->Thoughts[i].type == PeepThoughtType::None) - break; - - if (peep->Thoughts[i].freshness == 1) - { - add_fresh = 0; - // If thought is fresh we wait 220 ticks - // before allowing a new thought to become fresh. - if (++peep->Thoughts[i].fresh_timeout >= 220) - { - peep->Thoughts[i].fresh_timeout = 0; - // Thought is no longer fresh - peep->Thoughts[i].freshness++; - add_fresh = 1; - } - } - else if (peep->Thoughts[i].freshness > 1) - { - if (++peep->Thoughts[i].fresh_timeout == 0) - { - // When thought is older than ~6900 ticks remove it - if (++peep->Thoughts[i].freshness >= 28) - { - peep->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_THOUGHTS; - - // Clear top thought, push others up - if (i < kPeepMaxThoughts - 2) - { - memmove(&peep->Thoughts[i], &peep->Thoughts[i + 1], sizeof(PeepThought) * (kPeepMaxThoughts - i - 1)); - } - peep->Thoughts[kPeepMaxThoughts - 1].type = PeepThoughtType::None; - } - } - } - else - { - fresh_thought = i; - } - } - // If there are no fresh thoughts - // a previously new thought can become - // fresh. - if (add_fresh && fresh_thought != -1) - { - peep->Thoughts[fresh_thought].freshness = 1; - peep->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_THOUGHTS; - } -} - -/** - * - * rct2: 0x0068FC1E - */ -void Peep::Update() -{ - if (PeepFlags & PEEP_FLAGS_POSITION_FROZEN) - { - if (!(PeepFlags & PEEP_FLAGS_ANIMATION_FROZEN)) - { - // This is circumventing other logic, so only update every few ticks - if ((getGameState().currentTicks & 3) == 0) - { - if (IsActionWalking()) - UpdateWalkingAnimation(); - else - UpdateActionAnimation(); - Invalidate(); - } - } - return; - } - else if (PeepFlags & PEEP_FLAGS_ANIMATION_FROZEN) - { - // Animation is frozen while position is not. This allows a peep to walk - // around without its sprite being updated, which looks very glitchy. - // We'll just remove the flag and continue as normal, in this case. - PeepFlags &= ~PEEP_FLAGS_ANIMATION_FROZEN; - } - - auto* guest = As(); - if (guest != nullptr) - { - if (!guest->PreviousRide.IsNull()) - if (++guest->PreviousRideTimeOut >= 720) - guest->PreviousRide = RideId::GetNull(); - - GuestUpdateThoughts(guest); - } - - // Walking speed logic - uint32_t stepsToTake = Energy; - if (stepsToTake < 95 && State == PeepState::Queuing) - stepsToTake = 95; - if ((PeepFlags & PEEP_FLAGS_SLOW_WALK) && State != PeepState::Queuing) - stepsToTake /= 2; - if (IsActionWalking() && GetNextIsSloped()) - { - stepsToTake /= 2; - if (State == PeepState::Queuing) - stepsToTake += stepsToTake / 2; - } - // Ensure guests make it across a level crossing in time - constexpr auto minStepsForCrossing = 55; - if (stepsToTake < minStepsForCrossing && IsOnPathBlockedByVehicle()) - stepsToTake = minStepsForCrossing; - - uint32_t carryCheck = StepProgress + stepsToTake; - StepProgress = carryCheck; - if (carryCheck <= 255) - { - if (guest != nullptr) - { - guest->UpdateEasterEggInteractions(); - } - } - else - { - // Loc68FD2F - switch (State) - { - case PeepState::Falling: - UpdateFalling(); - break; - case PeepState::One: - Update1(); - break; - case PeepState::OnRide: - // No action - break; - case PeepState::Picked: - UpdatePicked(); - break; - default: - { - if (guest != nullptr) - { - guest->UpdateGuest(); - } - else - { - auto* staff = As(); - if (staff != nullptr) - { - staff->UpdateStaff(stepsToTake); - } - else - { - assert(false); - } - } - break; - } - } - } -} - /** * * rct2: 0x0069BF41 diff --git a/src/openrct2/entity/Peep.h b/src/openrct2/entity/Peep.h index 8e207d3fa4..197592134d 100644 --- a/src/openrct2/entity/Peep.h +++ b/src/openrct2/entity/Peep.h @@ -356,7 +356,6 @@ struct Peep : EntityBase uint32_t PeepFlags; public: // Peep - void Update(); std::optional UpdateAction(int16_t& xy_distance); std::optional UpdateAction(); bool UpdateActionAnimation(); @@ -408,7 +407,7 @@ public: // Peep void SwitchNextAnimationType(); [[nodiscard]] PeepAnimationType GetAnimationType(); -private: +protected: void UpdateFalling(); void Update1(); void UpdatePicked(); diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index 9954d1ca99..b6933c6221 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -1680,6 +1680,104 @@ bool Staff::IsMechanic() const return AssignedStaffType == StaffType::Mechanic; } +void Staff::Update() +{ + if (PeepFlags & PEEP_FLAGS_POSITION_FROZEN) + { + if (!(PeepFlags & PEEP_FLAGS_ANIMATION_FROZEN)) + { + // This is circumventing other logic, so only update every few ticks + if ((getGameState().currentTicks & 3) == 0) + { + if (IsActionWalking()) + UpdateWalkingAnimation(); + else + UpdateActionAnimation(); + Invalidate(); + } + } + return; + } + else if (PeepFlags & PEEP_FLAGS_ANIMATION_FROZEN) + { + // Animation is frozen while position is not. This allows a peep to walk + // around without its sprite being updated, which looks very glitchy. + // We'll just remove the flag and continue as normal, in this case. + PeepFlags &= ~PEEP_FLAGS_ANIMATION_FROZEN; + } + + auto* guest = As(); + if (guest != nullptr) + { + } + + // Walking speed logic + uint32_t stepsToTake = Energy; + if (stepsToTake < 95 && State == PeepState::Queuing) + stepsToTake = 95; + if ((PeepFlags & PEEP_FLAGS_SLOW_WALK) && State != PeepState::Queuing) + stepsToTake /= 2; + if (IsActionWalking() && GetNextIsSloped()) + { + stepsToTake /= 2; + if (State == PeepState::Queuing) + stepsToTake += stepsToTake / 2; + } + // Ensure guests make it across a level crossing in time + constexpr auto minStepsForCrossing = 55; + if (stepsToTake < minStepsForCrossing && IsOnPathBlockedByVehicle()) + stepsToTake = minStepsForCrossing; + + uint32_t carryCheck = StepProgress + stepsToTake; + StepProgress = carryCheck; + if (carryCheck <= 255) + { + if (guest != nullptr) + { + guest->UpdateEasterEggInteractions(); + } + } + else + { + // Loc68FD2F + switch (State) + { + case PeepState::Falling: + UpdateFalling(); + break; + case PeepState::One: + Update1(); + break; + case PeepState::OnRide: + // No action + break; + case PeepState::Picked: + UpdatePicked(); + break; + default: + { + if (guest != nullptr) + { + guest->UpdateGuest(); + } + else + { + auto* staff = As(); + if (staff != nullptr) + { + staff->UpdateStaff(stepsToTake); + } + else + { + assert(false); + } + } + break; + } + } + } +} + void Staff::UpdateStaff(uint32_t stepsToTake) { switch (State) diff --git a/src/openrct2/entity/Staff.h b/src/openrct2/entity/Staff.h index bc1b7737bf..8e060c551d 100644 --- a/src/openrct2/entity/Staff.h +++ b/src/openrct2/entity/Staff.h @@ -59,6 +59,7 @@ public: }; uint32_t StaffBinsEmptied; + void Update(); void UpdateStaff(uint32_t stepsToTake); void Tick128UpdateStaff(); bool IsMechanic() const;