diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 188134006b..729481c7b1 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -29,6 +29,7 @@ - Fix: [#24362] When upgrading from an older version on Windows, old versions of official objects are not always removed. - Fix: [#24366] Zero G Rolls have some incorrect vehicle yaw rotations. - Fix: [#24371] Fix divide by zero in the scenery window when there is no scenery. +- Fix: [#24378] Prevent ride and stall statistics from overflowing. - Fix: [#24388] Shortcut keys are not localised based on the user’s language settings. - Fix: [#24403] Park fences draw underneath and through opaque water. - Fix: [#24406] The network status window uses an undefined string for its title. diff --git a/src/openrct2/entity/Guest.cpp b/src/openrct2/entity/Guest.cpp index bcc8f16362..c77ffa5dcf 100644 --- a/src/openrct2/entity/Guest.cpp +++ b/src/openrct2/entity/Guest.cpp @@ -1744,10 +1744,10 @@ static bool GuestDecideAndBuyItem(Guest& guest, Ride& ride, const ShopItem shopI { guest.SpendMoney(*expend_type, price, expenditure); } - ride.totalProfit += (price - shopItemDescriptor.Cost); + ride.totalProfit = AddClamp(ride.totalProfit, price - shopItemDescriptor.Cost); ride.windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_INCOME; ride.curNumCustomers++; - ride.totalCustomers++; + ride.totalCustomers = AddClamp(ride.totalCustomers, 1u); ride.windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_CUSTOMER; return true; @@ -1836,7 +1836,7 @@ void Guest::OnExitRide(Ride& ride) } } - ride.totalCustomers++; + ride.totalCustomers = AddClamp(ride.totalCustomers, 1u); ride.windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_CUSTOMER; } @@ -3361,7 +3361,7 @@ static bool PeepShouldUseCashMachine(Guest& guest, RideId rideIndex) { ride->updateSatisfaction(guest.Happiness >> 6); ride->curNumCustomers++; - ride->totalCustomers++; + ride->totalCustomers = AddClamp(ride->totalCustomers, 1u); ride->windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_CUSTOMER; } return true; @@ -3433,7 +3433,7 @@ void Guest::UpdateBuying() UpdateCurrentAnimationType(); - ride->numPrimaryItemsSold++; + ride->numPrimaryItemsSold = AddClamp(ride->numPrimaryItemsSold, 1u); } } else @@ -3450,7 +3450,7 @@ void Guest::UpdateBuying() item_bought = GuestDecideAndBuyItem(*this, *ride, ride_type->shop_item[1], price); if (item_bought) { - ride->numSecondaryItemsSold++; + ride->numSecondaryItemsSold = AddClamp(ride->numSecondaryItemsSold, 1u); } } @@ -3461,7 +3461,7 @@ void Guest::UpdateBuying() item_bought = GuestDecideAndBuyItem(*this, *ride, ride_type->shop_item[0], price); if (item_bought) { - ride->numPrimaryItemsSold++; + ride->numPrimaryItemsSold = AddClamp(ride->numPrimaryItemsSold, 1u); } } } @@ -4470,7 +4470,7 @@ void Guest::UpdateRideInExit() ShopItem secondaryItem = ride->getRideTypeDescriptor().PhotoItem; if (GuestDecideAndBuyItem(*this, *ride, secondaryItem, ride->price[1])) { - ride->numSecondaryItemsSold++; + ride->numSecondaryItemsSold = AddClamp(ride->numSecondaryItemsSold, 1u); } } RideSubState = PeepRideSubState::LeaveExit; @@ -5203,7 +5203,7 @@ void Guest::UpdateRideShopLeave() auto ride = GetRide(CurrentRide); if (ride != nullptr) { - ride->totalCustomers++; + ride->totalCustomers = AddClamp(ride->totalCustomers, 1u); ride->windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_CUSTOMER; ride->updateSatisfaction(Happiness / 64); } @@ -6404,6 +6404,7 @@ static void GuestUpdateWalkingBreakScenery(Guest& guest) if (std::max(xDist, yDist) < 224) { innerPeep->StaffVandalsStopped = AddClamp(innerPeep->StaffVandalsStopped, 1u); + innerPeep->WindowInvalidateFlags |= PEEP_INVALIDATE_STAFF_STATS; return; } } diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index b20c04e14e..94d2a28a5d 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -50,6 +50,7 @@ #include "../ride/Station.h" #include "../ride/Track.h" #include "../ui/WindowManager.h" +#include "../util/Util.h" #include "../windows/Intent.h" #include "../world/Climate.h" #include "../world/ConstructionClearance.h" @@ -2274,7 +2275,7 @@ static bool PeepInteractWithShop(Peep* peep, const CoordsXYE& coords) auto cost = ride->price[0]; if (cost != 0 && !(getGameState().park.Flags & PARK_FLAGS_NO_MONEY)) { - ride->totalProfit += cost; + ride->totalProfit = AddClamp(ride->totalProfit, cost); ride->windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_INCOME; guest->SpendMoney(cost, ExpenditureType::ParkRideTickets); } diff --git a/src/openrct2/management/Finance.cpp b/src/openrct2/management/Finance.cpp index 00a098e115..877162fbf8 100644 --- a/src/openrct2/management/Finance.cpp +++ b/src/openrct2/management/Finance.cpp @@ -170,7 +170,7 @@ void FinancePayRideUpkeep() auto upkeep = ride.upkeepCost; if (upkeep != kMoney64Undefined) { - ride.totalProfit -= upkeep; + ride.totalProfit = AddClamp(ride.totalProfit, -upkeep); ride.windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_INCOME; FinancePayment(upkeep, ExpenditureType::RideRunningCosts); } diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 0e6a4f49f1..b89e1c1549 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -375,7 +375,7 @@ void RideUpdateFavouritedStat() auto ride = GetRide(peep->FavouriteRide); if (ride != nullptr) { - ride->guestsFavourite++; + ride->guestsFavourite = AddClamp(ride->guestsFavourite, 1u); ride->windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_CUSTOMER; } } @@ -1305,9 +1305,8 @@ static void RideInspectionUpdate(Ride& ride) if (gLegacyScene == LegacyScene::trackDesigner) return; - ride.lastInspection++; - if (ride.lastInspection == 0) - ride.lastInspection--; + ride.lastInspection = AddClamp(ride.lastInspection, 1); + ride.windowInvalidateFlags |= RIDE_INVALIDATE_RIDE_MAINTENANCE; int32_t inspectionIntervalMinutes = RideInspectionInterval[ride.inspectionInterval]; // An inspection interval of 0 minutes means the ride is set to never be inspected. diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index abf2ed9237..d2503250c7 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -274,9 +274,9 @@ struct Ride uint8_t downtimeHistory[OpenRCT2::Limits::kDowntimeHistorySize]{}; uint32_t numPrimaryItemsSold{}; uint32_t numSecondaryItemsSold{}; - uint8_t breakdownSoundModifier{}; // Used to oscillate the sound when ride breaks down. // 0 = no change, 255 = max change + uint8_t breakdownSoundModifier{}; uint8_t notFixedTimeout{}; uint8_t lastCrashType{}; uint8_t connectedMessageThrottle{};