mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-06 06:32:56 +01:00
Fix #15193: Crash when rides/stalls are demolished
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
- Fix: [#15148] Track Designs Manager delete confirmation window doesn't display properly.
|
||||
- Fix: [#15170] Plugin: incorrect label text alignment.
|
||||
- Fix: [#15184] Crash when hovering over water types in Object Selection.
|
||||
- Fix: [#15193] Crash when rides/stalls are demolished.
|
||||
- Improved: [#3417] Crash dumps are now placed in their own folder.
|
||||
- Change: [#8601] Revert ToonTower base block fix to re-enable support blocking.
|
||||
- Change: [#15174] [Plugin] Deprecate the type "peep" and add support to target a specific scripting api version.
|
||||
|
||||
@@ -136,89 +136,7 @@ GameActions::Result::Ptr RideDemolishAction::DemolishRide(Ride* ride) const
|
||||
|
||||
for (auto peep : EntityList<Guest>())
|
||||
{
|
||||
uint8_t ride_id_bit = _rideIndex % 8;
|
||||
uint8_t ride_id_offset = _rideIndex / 8;
|
||||
|
||||
// clear ride from potentially being in RidesBeenOn
|
||||
peep->RidesBeenOn[ride_id_offset] &= ~(1 << ride_id_bit);
|
||||
if (peep->State == PeepState::Watching)
|
||||
{
|
||||
if (peep->CurrentRide == _rideIndex)
|
||||
{
|
||||
peep->CurrentRide = RIDE_ID_NULL;
|
||||
if (peep->TimeToStand >= 50)
|
||||
{
|
||||
// make peep stop watching the ride
|
||||
peep->TimeToStand = 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove any free voucher for this ride from peep
|
||||
if (peep->HasItem(ShopItem::Voucher))
|
||||
{
|
||||
if (peep->VoucherType == VOUCHER_TYPE_RIDE_FREE && peep->VoucherRideId == _rideIndex)
|
||||
{
|
||||
peep->RemoveItem(ShopItem::Voucher);
|
||||
}
|
||||
}
|
||||
|
||||
// remove any photos of this ride from peep
|
||||
if (peep->HasItem(ShopItem::Photo))
|
||||
{
|
||||
if (peep->Photo1RideRef == _rideIndex)
|
||||
{
|
||||
peep->RemoveItem(ShopItem::Photo);
|
||||
}
|
||||
}
|
||||
if (peep->HasItem(ShopItem::Photo2))
|
||||
{
|
||||
if (peep->Photo2RideRef == _rideIndex)
|
||||
{
|
||||
peep->RemoveItem(ShopItem::Photo2);
|
||||
}
|
||||
}
|
||||
if (peep->HasItem(ShopItem::Photo3))
|
||||
{
|
||||
if (peep->Photo3RideRef == _rideIndex)
|
||||
{
|
||||
peep->RemoveItem(ShopItem::Photo3);
|
||||
}
|
||||
}
|
||||
if (peep->HasItem(ShopItem::Photo4))
|
||||
{
|
||||
if (peep->Photo4RideRef == _rideIndex)
|
||||
{
|
||||
peep->RemoveItem(ShopItem::Photo4);
|
||||
}
|
||||
}
|
||||
|
||||
if (peep->GuestHeadingToRideId == _rideIndex)
|
||||
{
|
||||
peep->GuestHeadingToRideId = RIDE_ID_NULL;
|
||||
}
|
||||
if (peep->FavouriteRide == _rideIndex)
|
||||
{
|
||||
peep->FavouriteRide = RIDE_ID_NULL;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < PEEP_MAX_THOUGHTS; i++)
|
||||
{
|
||||
// Don't touch items after the first NONE thought as they are not valid
|
||||
// fixes issues with clearing out bad thought data in multiplayer
|
||||
if (peep->Thoughts[i].type == PeepThoughtType::None)
|
||||
break;
|
||||
|
||||
if (peep->Thoughts[i].type != PeepThoughtType::None && peep->Thoughts[i].item == _rideIndex)
|
||||
{
|
||||
// Clear top thought, push others up
|
||||
memmove(&peep->Thoughts[i], &peep->Thoughts[i + 1], sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - i - 1));
|
||||
peep->Thoughts[PEEP_MAX_THOUGHTS - 1].type = PeepThoughtType::None;
|
||||
peep->Thoughts[PEEP_MAX_THOUGHTS - 1].item = PEEP_THOUGHT_ITEM_NONE;
|
||||
// Next iteration, check the new thought at this index
|
||||
i--;
|
||||
}
|
||||
}
|
||||
peep->RemoveRideFromMemory(_rideIndex);
|
||||
}
|
||||
|
||||
MarketingCancelCampaignsForRide(_rideIndex);
|
||||
|
||||
@@ -7356,3 +7356,112 @@ bool Guest::HasItem(ShopItem peepItem) const
|
||||
{
|
||||
return GetItemFlags() & EnumToFlag(peepItem);
|
||||
}
|
||||
|
||||
static bool IsThoughtShopItemRelated(const PeepThoughtType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PeepThoughtType::AlreadyGot:
|
||||
case PeepThoughtType::HaventFinished:
|
||||
case PeepThoughtType::CantAffordItem:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Guest::RemoveRideFromMemory(ride_id_t rideId)
|
||||
{
|
||||
uint8_t ride_id_bit = rideId % 8;
|
||||
uint8_t ride_id_offset = rideId / 8;
|
||||
|
||||
// clear ride from potentially being in RidesBeenOn
|
||||
RidesBeenOn[ride_id_offset] &= ~(1 << ride_id_bit);
|
||||
if (State == PeepState::Watching)
|
||||
{
|
||||
if (CurrentRide == rideId)
|
||||
{
|
||||
CurrentRide = RIDE_ID_NULL;
|
||||
if (TimeToStand >= 50)
|
||||
{
|
||||
// make peep stop watching the ride
|
||||
TimeToStand = 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove any free voucher for this ride from peep
|
||||
if (HasItem(ShopItem::Voucher))
|
||||
{
|
||||
if (VoucherType == VOUCHER_TYPE_RIDE_FREE && VoucherRideId == rideId)
|
||||
{
|
||||
RemoveItem(ShopItem::Voucher);
|
||||
}
|
||||
}
|
||||
|
||||
// remove any photos of this ride from peep
|
||||
if (HasItem(ShopItem::Photo))
|
||||
{
|
||||
if (Photo1RideRef == rideId)
|
||||
{
|
||||
RemoveItem(ShopItem::Photo);
|
||||
}
|
||||
}
|
||||
if (HasItem(ShopItem::Photo2))
|
||||
{
|
||||
if (Photo2RideRef == rideId)
|
||||
{
|
||||
RemoveItem(ShopItem::Photo2);
|
||||
}
|
||||
}
|
||||
if (HasItem(ShopItem::Photo3))
|
||||
{
|
||||
if (Photo3RideRef == rideId)
|
||||
{
|
||||
RemoveItem(ShopItem::Photo3);
|
||||
}
|
||||
}
|
||||
if (HasItem(ShopItem::Photo4))
|
||||
{
|
||||
if (Photo4RideRef == rideId)
|
||||
{
|
||||
RemoveItem(ShopItem::Photo4);
|
||||
}
|
||||
}
|
||||
|
||||
if (GuestHeadingToRideId == rideId)
|
||||
{
|
||||
GuestHeadingToRideId = RIDE_ID_NULL;
|
||||
}
|
||||
if (FavouriteRide == rideId)
|
||||
{
|
||||
FavouriteRide = RIDE_ID_NULL;
|
||||
}
|
||||
|
||||
// Erase all thoughts that contain the ride.
|
||||
for (auto it = std::begin(Thoughts); it != std::end(Thoughts);)
|
||||
{
|
||||
const auto& entry = *it;
|
||||
if (entry.type == PeepThoughtType::None)
|
||||
break;
|
||||
|
||||
// Ride ids and shop item ids might have the same value, look only for ride thoughts.
|
||||
if (IsThoughtShopItemRelated(entry.type) || entry.item != rideId)
|
||||
{
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto itNext = std::next(it); itNext != std::end(Thoughts))
|
||||
{
|
||||
// Overwrite this entry by shifting all entries that follow.
|
||||
std::rotate(it, itNext, std::end(Thoughts));
|
||||
}
|
||||
|
||||
// Last slot is now free.
|
||||
auto& lastEntry = Thoughts.back();
|
||||
lastEntry.type = PeepThoughtType::None;
|
||||
lastEntry.item = PEEP_THOUGHT_ITEM_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -784,6 +784,10 @@ public:
|
||||
bool HasItem(ShopItem peepItem) const;
|
||||
void Serialise(DataSerialiser& stream);
|
||||
|
||||
// Removes the ride from the guests memory, this includes
|
||||
// the history, thoughts, etc.
|
||||
void RemoveRideFromMemory(ride_id_t rideId);
|
||||
|
||||
private:
|
||||
void UpdateRide();
|
||||
void UpdateOnRide(){}; // TODO
|
||||
|
||||
Reference in New Issue
Block a user