From b6667b5b9896fbbb2a144ad6e8c815e9cd05a6b2 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 17 May 2021 22:38:12 +0100 Subject: [PATCH] Update import of guests and peep thoughts Also fix banner import from S4/S6 --- src/openrct2-ui/windows/Guest.cpp | 2 +- src/openrct2/ParkFile.cpp | 605 +++++++++++--------- src/openrct2/actions/RideDemolishAction.cpp | 5 +- src/openrct2/core/DataSerialiserTraits.h | 4 +- src/openrct2/peep/Guest.cpp | 72 +-- src/openrct2/peep/Peep.cpp | 12 +- src/openrct2/peep/Peep.h | 19 +- src/openrct2/rct1/S4Importer.cpp | 12 +- src/openrct2/rct2/S6Importer.cpp | 12 +- src/openrct2/world/Banner.cpp | 1 + 10 files changed, 438 insertions(+), 306 deletions(-) diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index 80073e0fd3..370f9a813a 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -1097,7 +1097,7 @@ void window_guest_overview_update(rct_window* w) int32_t random = util_rand() & 0xFFFF; if (random <= 0x2AAA) { - peep->InsertNewThought(PeepThoughtType::Watched, PEEP_THOUGHT_ITEM_NONE); + peep->InsertNewThought(PeepThoughtType::Watched); } } } diff --git a/src/openrct2/ParkFile.cpp b/src/openrct2/ParkFile.cpp index 8f2c8183b0..798195b753 100644 --- a/src/openrct2/ParkFile.cpp +++ b/src/openrct2/ParkFile.cpp @@ -58,10 +58,10 @@ namespace OpenRCT2 constexpr uint32_t PARK_FILE_MAGIC = 0x4B524150; // PARK // Current version that is saved. - constexpr uint32_t PARK_FILE_CURRENT_VERSION = 0x1; + constexpr uint32_t PARK_FILE_CURRENT_VERSION = 0x2; // The minimum version that is forwards compatible with the current version. - constexpr uint32_t PARK_FILE_MIN_VERSION = 0x1; + constexpr uint32_t PARK_FILE_MIN_VERSION = 0x2; namespace ParkFileChunkType { @@ -1178,7 +1178,7 @@ namespace OpenRCT2 } } - template static void ReadWriteEntity(OrcaStream::ChunkStream& cs, T& entity); + template static void ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, T& entity); static void ReadWriteEntityCommon(OrcaStream::ChunkStream& cs, SpriteBase& entity) { @@ -1192,8 +1192,10 @@ namespace OpenRCT2 cs.ReadWrite(entity.sprite_direction); } - static void ReadWritePeep(OrcaStream::ChunkStream& cs, Peep& entity) + static void ReadWritePeep(OrcaStream& os, OrcaStream::ChunkStream& cs, Peep& entity) { + auto version = os.GetHeader().TargetVersion; + ReadWriteEntityCommon(cs, entity); auto guest = entity.As(); @@ -1207,27 +1209,38 @@ namespace OpenRCT2 { cs.Write(static_cast(entity.Name)); } + cs.ReadWrite(entity.NextLoc); cs.ReadWrite(entity.NextFlags); - if (guest != nullptr) + + if (version <= 1) { - cs.ReadWrite(guest->OutsideOfPark); - } - else - { - cs.Ignore(); + if (guest != nullptr) + { + cs.ReadWrite(guest->OutsideOfPark); + } + else + { + cs.Ignore(); + } } + cs.ReadWrite(entity.State); cs.ReadWrite(entity.SubState); cs.ReadWrite(entity.SpriteType); - if (guest != nullptr) + + if (version <= 1) { - cs.ReadWrite(guest->GuestNumRides); - } - else - { - cs.Ignore(); + if (guest != nullptr) + { + cs.ReadWrite(guest->GuestNumRides); + } + else + { + cs.Ignore(); + } } + cs.ReadWrite(entity.TshirtColour); cs.ReadWrite(entity.TrousersColour); cs.ReadWrite(entity.DestinationX); @@ -1236,104 +1249,97 @@ namespace OpenRCT2 cs.ReadWrite(entity.Var37); cs.ReadWrite(entity.Energy); cs.ReadWrite(entity.EnergyTarget); - if (guest != nullptr) - { - cs.ReadWrite(guest->Happiness); - cs.ReadWrite(guest->HappinessTarget); - cs.ReadWrite(guest->Nausea); - cs.ReadWrite(guest->NauseaTarget); - cs.ReadWrite(guest->Hunger); - cs.ReadWrite(guest->Thirst); - cs.ReadWrite(guest->Toilet); - } - else - { - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - } - cs.ReadWrite(entity.Mass); - if (guest != nullptr) - { - cs.ReadWrite(guest->TimeToConsume); - } - else - { - uint8_t temp{}; - cs.ReadWrite(temp); - } - if (guest != nullptr) + if (version <= 1) { - if (cs.GetMode() == OrcaStream::Mode::READING) + if (guest != nullptr) { - guest->Intensity = IntensityRange(cs.Read()); + cs.ReadWrite(guest->Happiness); + cs.ReadWrite(guest->HappinessTarget); + cs.ReadWrite(guest->Nausea); + cs.ReadWrite(guest->NauseaTarget); + cs.ReadWrite(guest->Hunger); + cs.ReadWrite(guest->Thirst); + cs.ReadWrite(guest->Toilet); } else { - cs.Write(static_cast(guest->Intensity)); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); } } - else + + cs.ReadWrite(entity.Mass); + + if (version <= 1) { - cs.Ignore(); + if (guest != nullptr) + { + cs.ReadWrite(guest->TimeToConsume); + } + else + { + uint8_t temp{}; + cs.ReadWrite(temp); + } } - if (guest != nullptr) + if (version <= 1) { - cs.ReadWrite(guest->NauseaTolerance); - } - else - { - cs.Ignore(); + if (guest != nullptr) + { + if (cs.GetMode() == OrcaStream::Mode::READING) + { + guest->Intensity = IntensityRange(cs.Read()); + } + else + { + cs.Write(static_cast(guest->Intensity)); + } + cs.ReadWrite(guest->NauseaTolerance); + } + else + { + cs.Ignore(); + cs.Ignore(); + } } cs.ReadWrite(entity.WindowInvalidateFlags); - if (guest != nullptr) + if (version <= 1) { - cs.ReadWrite(guest->PaidOnDrink); - } - else - { - cs.Ignore(); - } + if (guest != nullptr) + { + cs.ReadWrite(guest->PaidOnDrink); + cs.ReadWriteArray(guest->RideTypesBeenOn, [&cs](uint8_t& rideType) { + cs.ReadWrite(rideType); + return true; + }); + cs.ReadWrite(guest->ItemFlags); + cs.ReadWrite(guest->Photo2RideRef); + cs.ReadWrite(guest->Photo3RideRef); + cs.ReadWrite(guest->Photo4RideRef); + } + else + { + cs.Ignore(); - if (guest != nullptr) - { - cs.ReadWriteArray(guest->RideTypesBeenOn, [&cs](uint8_t& rideType) { - cs.ReadWrite(rideType); - return true; - }); - } - else - { - std::vector temp; - cs.ReadWriteVector(temp, [&cs](uint8_t& rideType) { - cs.ReadWrite(rideType); - return true; - }); - } - - if (guest != nullptr) - { - cs.ReadWrite(guest->ItemFlags); - cs.ReadWrite(guest->Photo2RideRef); - cs.ReadWrite(guest->Photo3RideRef); - cs.ReadWrite(guest->Photo4RideRef); - } - else - { - uint64_t temp{}; - ride_id_t temp2{}; - cs.ReadWrite(temp); - cs.ReadWrite(temp2); - cs.ReadWrite(temp2); - cs.ReadWrite(temp2); + std::vector temp; + cs.ReadWriteVector(temp, [&cs](uint8_t& rideType) { + cs.ReadWrite(rideType); + return true; + }); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + } } cs.ReadWrite(entity.CurrentRide); @@ -1348,107 +1354,110 @@ namespace OpenRCT2 cs.ReadWrite(entity.ActionFrame); cs.ReadWrite(entity.StepProgress); - if (guest != nullptr) + if (version <= 1) { - cs.ReadWrite(guest->GuestNextInQueue); - } - else - { - cs.Ignore(); + if (guest != nullptr) + { + cs.ReadWrite(guest->GuestNextInQueue); + } + else + { + cs.Ignore(); + } } cs.ReadWrite(entity.PeepDirection); cs.ReadWrite(entity.InteractionRideIndex); - if (guest != nullptr) + if (version <= 1) { - cs.ReadWrite(guest->TimeInQueue); - } - else - { - cs.Ignore(); - } + if (guest != nullptr) + { + cs.ReadWrite(guest->TimeInQueue); + cs.ReadWriteArray(guest->RidesBeenOn, [&cs](ride_id_t& rideId) { + cs.ReadWrite(rideId); + return true; + }); + } + else + { + cs.Ignore(); - if (guest != nullptr) - { - cs.ReadWriteArray(guest->RidesBeenOn, [&cs](ride_id_t& rideId) { - cs.ReadWrite(rideId); - return true; - }); - } - else - { - std::vector ridesBeenOn; - cs.ReadWriteArray(guest->RidesBeenOn, [&cs](ride_id_t& rideId) { - cs.ReadWrite(rideId); - return true; - }); + std::vector ridesBeenOn; + cs.ReadWriteArray(guest->RidesBeenOn, [&cs](ride_id_t& rideId) { + cs.ReadWrite(rideId); + return true; + }); + } } cs.ReadWrite(entity.Id); - if (guest != nullptr) + if (version <= 1) { - cs.ReadWrite(guest->CashInPocket); - cs.ReadWrite(guest->CashSpent); - } - else - { - cs.Ignore(); - cs.Ignore(); - } + if (guest != nullptr) + { + cs.ReadWrite(guest->CashInPocket); + cs.ReadWrite(guest->CashSpent); + cs.ReadWrite(guest->ParkEntryTime); + cs.ReadWrite(guest->RejoinQueueTimeout); + cs.ReadWrite(guest->PreviousRide); + cs.ReadWrite(guest->PreviousRideTimeOut); + cs.ReadWriteArray(guest->Thoughts, [&cs](rct_peep_thought& thought) { + cs.ReadWrite(thought.type); - // Includes HireDate - if (guest != nullptr) - { - cs.ReadWrite(guest->ParkEntryTime); - cs.ReadWrite(guest->RejoinQueueTimeout); - cs.ReadWrite(guest->PreviousRide); - cs.ReadWrite(guest->PreviousRideTimeOut); - } - else - { - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - } + uint8_t item; + cs.ReadWrite(item); + if (item == 255) + { + thought.argument = std::numeric_limits::max(); + } + else + { + thought.argument = item; + } - if (guest != nullptr) - { - cs.ReadWriteArray(guest->Thoughts, [&cs](rct_peep_thought& thought) { - cs.ReadWrite(thought.type); - cs.ReadWrite(thought.item); - cs.ReadWrite(thought.freshness); - cs.ReadWrite(thought.fresh_timeout); - return true; - }); - } - else - { - std::vector temp; - cs.ReadWriteVector(temp, [&cs](rct_peep_thought& thought) { - cs.ReadWrite(thought.type); - cs.ReadWrite(thought.item); - cs.ReadWrite(thought.freshness); - cs.ReadWrite(thought.fresh_timeout); - return true; - }); + cs.ReadWrite(thought.freshness); + cs.ReadWrite(thought.fresh_timeout); + return true; + }); + } + else + { + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + + std::vector temp; + cs.ReadWriteVector(temp, [&cs](rct_peep_thought& thought) { + cs.ReadWrite(thought.type); + cs.ReadWrite(thought.item); + cs.ReadWrite(thought.freshness); + cs.ReadWrite(thought.fresh_timeout); + return true; + }); + } } cs.ReadWrite(entity.PathCheckOptimisation); - if (guest != nullptr) + if (version <= 1) { - cs.ReadWrite(guest->GuestHeadingToRideId); - cs.ReadWrite(guest->GuestIsLostCountdown); - cs.ReadWrite(guest->Photo1RideRef); - } - else - { - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); + if (guest != nullptr) + { + cs.ReadWrite(guest->GuestHeadingToRideId); + cs.ReadWrite(guest->GuestIsLostCountdown); + cs.ReadWrite(guest->Photo1RideRef); + } + else + { + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + } } cs.ReadWrite(entity.PeepFlags); @@ -1465,64 +1474,67 @@ namespace OpenRCT2 } cs.ReadWrite(entity.WalkingFrameNum); - if (guest != nullptr) + if (version <= 1) { - cs.ReadWrite(guest->LitterCount); - cs.ReadWrite(guest->GuestTimeOnRide); - cs.ReadWrite(guest->DisgustingCount); - cs.ReadWrite(guest->PaidToEnter); - cs.ReadWrite(guest->PaidOnRides); - cs.ReadWrite(guest->PaidOnFood); - cs.ReadWrite(guest->PaidOnSouvenirs); - cs.ReadWrite(guest->AmountOfFood); - cs.ReadWrite(guest->AmountOfDrinks); - cs.ReadWrite(guest->AmountOfSouvenirs); - cs.ReadWrite(guest->VandalismSeen); - cs.ReadWrite(guest->VoucherType); - cs.ReadWrite(guest->VoucherRideId); - cs.ReadWrite(guest->SurroundingsThoughtTimeout); - cs.ReadWrite(guest->Angriness); - cs.ReadWrite(guest->TimeLost); - cs.ReadWrite(guest->DaysInQueue); - cs.ReadWrite(guest->BalloonColour); - cs.ReadWrite(guest->UmbrellaColour); - cs.ReadWrite(guest->HatColour); - cs.ReadWrite(guest->FavouriteRide); - cs.ReadWrite(guest->FavouriteRideRating); - } - else - { - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); - cs.Ignore(); + if (guest != nullptr) + { + cs.ReadWrite(guest->LitterCount); + cs.ReadWrite(guest->GuestTimeOnRide); + cs.ReadWrite(guest->DisgustingCount); + cs.ReadWrite(guest->PaidToEnter); + cs.ReadWrite(guest->PaidOnRides); + cs.ReadWrite(guest->PaidOnFood); + cs.ReadWrite(guest->PaidOnSouvenirs); + cs.ReadWrite(guest->AmountOfFood); + cs.ReadWrite(guest->AmountOfDrinks); + cs.ReadWrite(guest->AmountOfSouvenirs); + cs.ReadWrite(guest->VandalismSeen); + cs.ReadWrite(guest->VoucherType); + cs.ReadWrite(guest->VoucherRideId); + cs.ReadWrite(guest->SurroundingsThoughtTimeout); + cs.ReadWrite(guest->Angriness); + cs.ReadWrite(guest->TimeLost); + cs.ReadWrite(guest->DaysInQueue); + cs.ReadWrite(guest->BalloonColour); + cs.ReadWrite(guest->UmbrellaColour); + cs.ReadWrite(guest->HatColour); + cs.ReadWrite(guest->FavouriteRide); + cs.ReadWrite(guest->FavouriteRideRating); + } + else + { + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + } } } - template void WriteEntitiesOfType(OrcaStream::ChunkStream& cs); - template void WriteEntitiesOfTypes(OrcaStream::ChunkStream& cs); + template void WriteEntitiesOfType(OrcaStream& os, OrcaStream::ChunkStream& cs); + template void WriteEntitiesOfTypes(OrcaStream& os, OrcaStream::ChunkStream& cs); - template void ReadEntitiesOfType(OrcaStream::ChunkStream& cs); + template void ReadEntitiesOfType(OrcaStream& os, OrcaStream::ChunkStream& cs); - template void ReadEntitiesOfTypes(OrcaStream::ChunkStream& cs); + template void ReadEntitiesOfTypes(OrcaStream& os, OrcaStream::ChunkStream& cs); void ReadWriteEntitiesChunk(OrcaStream& os); @@ -1558,7 +1570,7 @@ namespace OpenRCT2 } }; - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, Vehicle& entity) + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Vehicle& entity) { ReadWriteEntityCommon(cs, entity); cs.ReadWrite(entity.SubType); @@ -1629,9 +1641,82 @@ namespace OpenRCT2 cs.ReadWrite(entity.IsCrashedVehicle); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, Guest& entity) + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Guest& guest) { - ReadWritePeep(cs, entity); + ReadWritePeep(os, cs, guest); + + cs.ReadWrite(guest.GuestNumRides); + cs.ReadWrite(guest.GuestNextInQueue); + cs.ReadWrite(guest.ParkEntryTime); + cs.ReadWrite(guest.GuestHeadingToRideId); + cs.ReadWrite(guest.GuestIsLostCountdown); + cs.ReadWrite(guest.GuestTimeOnRide); + cs.ReadWrite(guest.PaidToEnter); + cs.ReadWrite(guest.PaidOnRides); + cs.ReadWrite(guest.PaidOnFood); + cs.ReadWrite(guest.PaidOnDrink); + cs.ReadWrite(guest.PaidOnSouvenirs); + cs.ReadWrite(guest.OutsideOfPark); + cs.ReadWrite(guest.Happiness); + cs.ReadWrite(guest.HappinessTarget); + cs.ReadWrite(guest.Nausea); + cs.ReadWrite(guest.NauseaTarget); + cs.ReadWrite(guest.Hunger); + cs.ReadWrite(guest.Thirst); + cs.ReadWrite(guest.Toilet); + cs.ReadWrite(guest.TimeToConsume); + if (cs.GetMode() == OrcaStream::Mode::READING) + { + guest.Intensity = IntensityRange(cs.Read()); + } + else + { + cs.Write(static_cast(guest.Intensity)); + } + cs.ReadWrite(guest.NauseaTolerance); + cs.ReadWriteArray(guest.RideTypesBeenOn, [&cs](uint8_t& rideType) { + cs.ReadWrite(rideType); + return rideType != RIDE_TYPE_NULL; + }); + cs.ReadWrite(guest.TimeInQueue); + cs.ReadWriteArray(guest.RidesBeenOn, [&cs](ride_id_t& rideId) { + cs.ReadWrite(rideId); + return rideId != RIDE_ID_NULL; + }); + cs.ReadWrite(guest.CashInPocket); + cs.ReadWrite(guest.CashSpent); + cs.ReadWrite(guest.Photo1RideRef); + cs.ReadWrite(guest.Photo2RideRef); + cs.ReadWrite(guest.Photo3RideRef); + cs.ReadWrite(guest.Photo4RideRef); + cs.ReadWrite(guest.RejoinQueueTimeout); + cs.ReadWrite(guest.PreviousRide); + cs.ReadWrite(guest.PreviousRideTimeOut); + cs.ReadWriteArray(guest.Thoughts, [&cs](rct_peep_thought& thought) { + cs.ReadWrite(thought.type); + cs.ReadWrite(thought.item); + cs.ReadWrite(thought.freshness); + cs.ReadWrite(thought.fresh_timeout); + return true; + }); + cs.ReadWrite(guest.LitterCount); + cs.ReadWrite(guest.DisgustingCount); + cs.ReadWrite(guest.AmountOfFood); + cs.ReadWrite(guest.AmountOfDrinks); + cs.ReadWrite(guest.AmountOfSouvenirs); + cs.ReadWrite(guest.VandalismSeen); + cs.ReadWrite(guest.VoucherType); + cs.ReadWrite(guest.VoucherRideId); + cs.ReadWrite(guest.SurroundingsThoughtTimeout); + cs.ReadWrite(guest.Angriness); + cs.ReadWrite(guest.TimeLost); + cs.ReadWrite(guest.DaysInQueue); + cs.ReadWrite(guest.BalloonColour); + cs.ReadWrite(guest.UmbrellaColour); + cs.ReadWrite(guest.HatColour); + cs.ReadWrite(guest.FavouriteRide); + cs.ReadWrite(guest.FavouriteRideRating); + cs.ReadWrite(guest.ItemFlags); } static std::vector GetPatrolArea(Staff& staff) @@ -1679,9 +1764,9 @@ namespace OpenRCT2 } } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, Staff& entity) + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Staff& entity) { - ReadWritePeep(cs, entity); + ReadWritePeep(os, cs, entity); std::vector patrolArea; if (cs.GetMode() == OrcaStream::Mode::WRITING) @@ -1695,13 +1780,14 @@ namespace OpenRCT2 } } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, SteamParticle& steamParticle) + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, SteamParticle& steamParticle) { ReadWriteEntityCommon(cs, steamParticle); cs.ReadWrite(steamParticle.time_to_move); cs.ReadWrite(steamParticle.frame); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, MoneyEffect& moneyEffect) + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, MoneyEffect& moneyEffect) { ReadWriteEntityCommon(cs, moneyEffect); cs.ReadWrite(moneyEffect.MoveDelay); @@ -1711,7 +1797,9 @@ namespace OpenRCT2 cs.ReadWrite(moneyEffect.OffsetX); cs.ReadWrite(moneyEffect.Wiggle); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, VehicleCrashParticle& vehicleCrashParticle) + + template<> + void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, VehicleCrashParticle& vehicleCrashParticle) { ReadWriteEntityCommon(cs, vehicleCrashParticle); cs.ReadWrite(vehicleCrashParticle.frame); @@ -1727,22 +1815,26 @@ namespace OpenRCT2 cs.ReadWrite(vehicleCrashParticle.acceleration_y); cs.ReadWrite(vehicleCrashParticle.acceleration_z); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, ExplosionCloud& entity) + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, ExplosionCloud& entity) { ReadWriteEntityCommon(cs, entity); cs.ReadWrite(entity.frame); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, CrashSplashParticle& entity) + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, CrashSplashParticle& entity) { ReadWriteEntityCommon(cs, entity); cs.ReadWrite(entity.frame); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, ExplosionFlare& entity) + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, ExplosionFlare& entity) { ReadWriteEntityCommon(cs, entity); cs.ReadWrite(entity.frame); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, JumpingFountain& fountain) + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, JumpingFountain& fountain) { ReadWriteEntityCommon(cs, fountain); cs.ReadWrite(fountain.NumTicksAlive); @@ -1753,7 +1845,8 @@ namespace OpenRCT2 cs.ReadWrite(fountain.TargetY); cs.ReadWrite(fountain.Iteration); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, Balloon& balloon) + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Balloon& balloon) { ReadWriteEntityCommon(cs, balloon); cs.ReadWrite(balloon.popped); @@ -1761,7 +1854,8 @@ namespace OpenRCT2 cs.ReadWrite(balloon.frame); cs.ReadWrite(balloon.colour); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, Duck& duck) + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Duck& duck) { ReadWriteEntityCommon(cs, duck); cs.ReadWrite(duck.frame); @@ -1770,13 +1864,14 @@ namespace OpenRCT2 cs.ReadWrite(duck.state); } - template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, Litter& entity) + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Litter& entity) { ReadWriteEntityCommon(cs, entity); cs.ReadWrite(entity.SubType); cs.ReadWrite(entity.creationTick); } - template void ParkFile::WriteEntitiesOfType(OrcaStream::ChunkStream& cs) + + template void ParkFile::WriteEntitiesOfType(OrcaStream& os, OrcaStream::ChunkStream& cs) { uint16_t count = GetEntityListCount(T::cEntityType); cs.Write(T::cEntityType); @@ -1784,16 +1879,16 @@ namespace OpenRCT2 for (auto* ent : EntityList()) { cs.Write(ent->sprite_index); - ReadWriteEntity(cs, *ent); + ReadWriteEntity(os, cs, *ent); } } - template void ParkFile::WriteEntitiesOfTypes(OrcaStream::ChunkStream& cs) + template void ParkFile::WriteEntitiesOfTypes(OrcaStream& os, OrcaStream::ChunkStream& cs) { - (WriteEntitiesOfType(cs), ...); + (WriteEntitiesOfType(os, cs), ...); } - template void ParkFile::ReadEntitiesOfType(OrcaStream::ChunkStream& cs) + template void ParkFile::ReadEntitiesOfType(OrcaStream& os, OrcaStream::ChunkStream& cs) { [[maybe_unused]] auto t = cs.Read(); assert(t == T::cEntityType); @@ -1809,18 +1904,18 @@ namespace OpenRCT2 // Unable to allocate entity ent = &placeholder; } - ReadWriteEntity(cs, *ent); + ReadWriteEntity(os, cs, *ent); } } - template void ParkFile::ReadEntitiesOfTypes(OrcaStream::ChunkStream& cs) + template void ParkFile::ReadEntitiesOfTypes(OrcaStream& os, OrcaStream::ChunkStream& cs) { - (ReadEntitiesOfType(cs), ...); + (ReadEntitiesOfType(os, cs), ...); } void ParkFile::ReadWriteEntitiesChunk(OrcaStream& os) { - os.ReadWriteChunk(ParkFileChunkType::ENTITIES, [this](OrcaStream::ChunkStream& cs) { + os.ReadWriteChunk(ParkFileChunkType::ENTITIES, [this, &os](OrcaStream::ChunkStream& cs) { if (cs.GetMode() == OrcaStream::Mode::READING) { reset_sprite_list(); @@ -1831,13 +1926,13 @@ namespace OpenRCT2 { ReadEntitiesOfTypes< Vehicle, Guest, Staff, Litter, SteamParticle, MoneyEffect, VehicleCrashParticle, ExplosionCloud, - CrashSplashParticle, ExplosionFlare, JumpingFountain, Balloon, Duck>(cs); + CrashSplashParticle, ExplosionFlare, JumpingFountain, Balloon, Duck>(os, cs); } else { WriteEntitiesOfTypes< Vehicle, Guest, Staff, Litter, SteamParticle, MoneyEffect, VehicleCrashParticle, ExplosionCloud, - CrashSplashParticle, ExplosionFlare, JumpingFountain, Balloon, Duck>(cs); + CrashSplashParticle, ExplosionFlare, JumpingFountain, Balloon, Duck>(os, cs); } }); } diff --git a/src/openrct2/actions/RideDemolishAction.cpp b/src/openrct2/actions/RideDemolishAction.cpp index 8a2d58d6d9..818ee3cd18 100644 --- a/src/openrct2/actions/RideDemolishAction.cpp +++ b/src/openrct2/actions/RideDemolishAction.cpp @@ -210,12 +210,13 @@ GameActions::Result::Ptr RideDemolishAction::DemolishRide(Ride* ride) const if (peep->Thoughts[i].type == PeepThoughtType::None) break; - if (peep->Thoughts[i].type != PeepThoughtType::None && peep->Thoughts[i].item == _rideIndex) + // TODO actually verify the thought is a ride specific thought... + if (peep->Thoughts[i].type != PeepThoughtType::None && peep->Thoughts[i].ride == static_cast(_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; + peep->Thoughts[PEEP_MAX_THOUGHTS - 1].argument = std::numeric_limits::max(); // Next iteration, check the new thought at this index i--; } diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index a5ce573800..48c5948ea6 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -865,8 +865,8 @@ template<> struct DataSerializerTraits_t { char msg[128] = {}; snprintf( - msg, sizeof(msg), "rct_peep_thought(type = %d, item = %d, freshness = %d, freshtimeout = %d)", - static_cast(val.type), val.item, val.freshness, val.fresh_timeout); + msg, sizeof(msg), "rct_peep_thought(type = %d, item = %u, freshness = %d, freshtimeout = %d)", + static_cast(val.type), val.argument, val.freshness, val.fresh_timeout); stream->Write(msg, strlen(msg)); } }; diff --git a/src/openrct2/peep/Guest.cpp b/src/openrct2/peep/Guest.cpp index 54fa56b2da..484524db13 100644 --- a/src/openrct2/peep/Guest.cpp +++ b/src/openrct2/peep/Guest.cpp @@ -881,7 +881,7 @@ void Guest::Tick128UpdateGuest(int32_t index) PeepThoughtType thought_type = crowded_thoughts[scenario_rand() & 0xF]; if (thought_type != PeepThoughtType::None) { - InsertNewThought(thought_type, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(thought_type); } } @@ -942,7 +942,7 @@ void Guest::Tick128UpdateGuest(int32_t index) if (thought_type != PeepThoughtType::None) { - InsertNewThought(thought_type, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(thought_type); HappinessTarget = std::min(PEEP_MAX_HAPPINESS, HappinessTarget + 45); } } @@ -957,7 +957,7 @@ void Guest::Tick128UpdateGuest(int32_t index) if (PeepFlags & PEEP_FLAGS_WOW) { - InsertNewThought(PeepThoughtType::Wow2, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::Wow2); } if (GuestTimeOnRide > 15) @@ -1062,7 +1062,7 @@ void Guest::Tick128UpdateGuest(int32_t index) { PeepThoughtType chosen_thought = possible_thoughts[scenario_rand() % num_thoughts]; - InsertNewThought(chosen_thought, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(chosen_thought); switch (chosen_thought) { @@ -1098,7 +1098,7 @@ void Guest::Tick128UpdateGuest(int32_t index) thought_type = PeepThoughtType::VerySick; peep_head_for_nearest_ride_type(this, RIDE_TYPE_FIRST_AID); } - InsertNewThought(thought_type, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(thought_type); } } @@ -1372,7 +1372,7 @@ void Guest::CheckIfLost() return; TimeLost = 230; } - InsertNewThought(PeepThoughtType::Lost, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::Lost); HappinessTarget = std::max(HappinessTarget - 30, 0); } @@ -1422,7 +1422,7 @@ void Guest::CheckCantFindExit() // Peeps who can't find the park exit will continue to get less happy until they find it. if (GuestIsLostCountdown == 1) { - InsertNewThought(PeepThoughtType::CantFindExit, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::CantFindExit); HappinessTarget = std::max(HappinessTarget - 30, 0); } @@ -1458,7 +1458,7 @@ bool Guest::DecideAndBuyItem(Ride* ride, ShopItem shopItem, money32 price) if (HasItem(shopItem)) { - InsertNewThought(PeepThoughtType::AlreadyGot, EnumValue(shopItem)); + InsertNewThought(PeepThoughtType::AlreadyGot, shopItem); return false; } @@ -1467,7 +1467,7 @@ bool Guest::DecideAndBuyItem(Ride* ride, ShopItem shopItem, money32 price) int32_t food = bitscanforward(GetFoodOrDrinkFlags()); if (food != -1) { - InsertNewThought(PeepThoughtType::HaventFinished, food); + InsertNewThought(PeepThoughtType::HaventFinished, static_cast(food)); return false; } else if (Nausea >= 145) @@ -1488,13 +1488,13 @@ bool Guest::DecideAndBuyItem(Ride* ride, ShopItem shopItem, money32 price) if (GetShopItemDescriptor(shopItem).IsFood() && (Hunger > 75)) { - InsertNewThought(PeepThoughtType::NotHungry, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::NotHungry); return false; } if (GetShopItemDescriptor(shopItem).IsDrink() && (Thirst > 75)) { - InsertNewThought(PeepThoughtType::NotThirsty, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::NotThirsty); return false; } @@ -1510,12 +1510,12 @@ bool Guest::DecideAndBuyItem(Ride* ride, ShopItem shopItem, money32 price) { if (CashInPocket == 0) { - InsertNewThought(PeepThoughtType::SpentMoney, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::SpentMoney); return false; } if (price > CashInPocket) { - InsertNewThought(PeepThoughtType::CantAffordItem, EnumValue(shopItem)); + InsertNewThought(PeepThoughtType::CantAffordItem, shopItem); return false; } } @@ -1986,7 +1986,7 @@ bool Guest::ShouldGoOnRide(Ride* ride, int32_t entranceNum, bool atQueue, bool t { if (CashInPocket <= 0) { - InsertNewThought(PeepThoughtType::SpentMoney, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::SpentMoney); } else { @@ -2230,7 +2230,7 @@ bool Guest::ShouldGoToShop(Ride* ride, bool peepAtShop) { if (CashInPocket <= 0) { - InsertNewThought(PeepThoughtType::SpentMoney, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::SpentMoney); } else { @@ -2572,7 +2572,7 @@ static bool peep_check_ride_price_at_entrance(Guest* peep, Ride* ride, money32 r if (peep->CashInPocket <= 0 && !(gParkFlags & PARK_FLAGS_NO_MONEY)) { - peep->InsertNewThought(PeepThoughtType::SpentMoney, PEEP_THOUGHT_ITEM_NONE); + peep->InsertNewThought(PeepThoughtType::SpentMoney); peep_update_ride_at_entrance_try_leave(peep); return false; } @@ -3058,7 +3058,7 @@ static void peep_leave_park(Guest* peep) peep->PeepFlags &= ~PEEP_FLAGS_PARK_ENTRANCE_CHOSEN; } - peep->InsertNewThought(PeepThoughtType::GoHome, PEEP_THOUGHT_ITEM_NONE); + peep->InsertNewThought(PeepThoughtType::GoHome); rct_window* w = window_find_by_number(WC_PEEP, peep->sprite_index); if (w != nullptr) @@ -5413,11 +5413,11 @@ void Guest::UpdateWalking() if (CurrentSeat & 1) { - InsertNewThought(PeepThoughtType::NewRide, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::NewRide); } if (CurrentRide == RIDE_ID_NULL) { - InsertNewThought(PeepThoughtType::Scenery, PEEP_THOUGHT_ITEM_NONE); + InsertNewThought(PeepThoughtType::Scenery); } } @@ -6769,7 +6769,7 @@ void peep_thought_set_format_args(const rct_peep_thought* thought, Formatter& ft PeepThoughtToActionFlag flags = PeepThoughtToActionMap[EnumValue(thought->type)].flags; if (flags & PEEP_THOUGHT_ACTION_FLAG_RIDE) { - auto ride = get_ride(thought->item); + auto ride = get_ride(thought->ride); if (ride != nullptr) { ride->FormatNameTo(ft); @@ -6781,22 +6781,30 @@ void peep_thought_set_format_args(const rct_peep_thought* thought, Formatter& ft } else if (flags & PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_SINGULAR) { - ft.Add(GetShopItemDescriptor(ShopItem(thought->item)).Naming.Singular); + ft.Add(GetShopItemDescriptor(thought->item).Naming.Singular); } else if (flags & PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE) { - ft.Add(GetShopItemDescriptor(ShopItem(thought->item)).Naming.Indefinite); + ft.Add(GetShopItemDescriptor(thought->item).Naming.Indefinite); } } -/** - * - * rct2: 0x699F5A - * al:thoughtType - * ah:thoughtArguments - * esi: peep - */ -void Guest::InsertNewThought(PeepThoughtType thoughtType, uint8_t thoughtArguments) +void Guest::InsertNewThought(PeepThoughtType thoughtType) +{ + InsertNewThought(thoughtType, std::numeric_limits::max()); +} + +void Guest::InsertNewThought(PeepThoughtType thoughtType, ride_id_t ride) +{ + InsertNewThought(thoughtType, static_cast(ride)); +} + +void Guest::InsertNewThought(PeepThoughtType thoughtType, ShopItem item) +{ + InsertNewThought(thoughtType, static_cast(item)); +} + +void Guest::InsertNewThought(PeepThoughtType thoughtType, uint32_t arg) { PeepActionType newAction = PeepThoughtToActionMap[EnumValue(thoughtType)].action; if (newAction != PeepActionType::Walking && IsActionInterruptable()) @@ -6814,7 +6822,7 @@ void Guest::InsertNewThought(PeepThoughtType thoughtType, uint8_t thoughtArgumen if (thought->type == PeepThoughtType::None) break; - if (thought->type == thoughtType && thought->item == thoughtArguments) + if (thought->type == thoughtType && thought->argument == arg) { // If the thought type has not changed then we need to move // it to the top of the thought list. This is done by first removing the @@ -6830,7 +6838,7 @@ void Guest::InsertNewThought(PeepThoughtType thoughtType, uint8_t thoughtArgumen memmove(&Thoughts[1], &Thoughts[0], sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - 1)); Thoughts[0].type = thoughtType; - Thoughts[0].item = thoughtArguments; + Thoughts[0].argument = arg; Thoughts[0].freshness = 0; Thoughts[0].fresh_timeout = 0; diff --git a/src/openrct2/peep/Peep.cpp b/src/openrct2/peep/Peep.cpp index 643abc21bf..3fe5986ed5 100644 --- a/src/openrct2/peep/Peep.cpp +++ b/src/openrct2/peep/Peep.cpp @@ -749,7 +749,7 @@ void Peep::UpdateFalling() { // Drop balloon if held peep_release_balloon(guest, height); - guest->InsertNewThought(PeepThoughtType::Drowning, PEEP_THOUGHT_ITEM_NONE); + guest->InsertNewThought(PeepThoughtType::Drowning); } Action = PeepActionType::Drowning; @@ -841,7 +841,7 @@ void Peep::UpdatePicked() auto* guest = As(); if (SubState == 13 && guest != nullptr) { - guest->InsertNewThought(PeepThoughtType::Help, PEEP_THOUGHT_ITEM_NONE); + guest->InsertNewThought(PeepThoughtType::Help); } } @@ -1932,7 +1932,7 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool { if ((scenario_rand() & 0xFFFF) <= 10922) { - guest->InsertNewThought(PeepThoughtType::Vandalism, PEEP_THOUGHT_ITEM_NONE); + guest->InsertNewThought(PeepThoughtType::Vandalism); guest->HappinessTarget = std::max(0, guest->HappinessTarget - 17); } vandalThoughtTimeout = 3; @@ -1977,7 +1977,7 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool if (crowded >= 10 && guest->State == PeepState::Walking && (scenario_rand() & 0xFFFF) <= 21845) { - guest->InsertNewThought(PeepThoughtType::Crowded, PEEP_THOUGHT_ITEM_NONE); + guest->InsertNewThought(PeepThoughtType::Crowded); guest->HappinessTarget = std::max(0, guest->HappinessTarget - 14); } @@ -2003,7 +2003,7 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool if (total_sick >= 3 && (scenario_rand() & 0xFFFF) <= 10922) { - guest->InsertNewThought(PeepThoughtType::PathDisgusting, PEEP_THOUGHT_ITEM_NONE); + guest->InsertNewThought(PeepThoughtType::PathDisgusting); guest->HappinessTarget = std::max(0, guest->HappinessTarget - 17); // Reset disgusting time guest->DisgustingCount |= 0xC0; @@ -2029,7 +2029,7 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool if (total_litter >= 3 && (scenario_rand() & 0xFFFF) <= 10922) { - guest->InsertNewThought(PeepThoughtType::BadLitter, PEEP_THOUGHT_ITEM_NONE); + guest->InsertNewThought(PeepThoughtType::BadLitter); guest->HappinessTarget = std::max(0, guest->HappinessTarget - 17); // Reset litter time guest->LitterCount |= 0xC0; diff --git a/src/openrct2/peep/Peep.h b/src/openrct2/peep/Peep.h index 7ad30abb96..f876e3b68c 100644 --- a/src/openrct2/peep/Peep.h +++ b/src/openrct2/peep/Peep.h @@ -25,7 +25,6 @@ #include #define PEEP_MAX_THOUGHTS 5 -#define PEEP_THOUGHT_ITEM_NONE 255 #define PEEP_HUNGER_WARNING_THRESHOLD 25 #define PEEP_THIRST_WARNING_THRESHOLD 25 @@ -488,10 +487,15 @@ enum PeepRideDecision struct rct_peep_thought { - PeepThoughtType type; // 0 - uint8_t item; // 1 - uint8_t freshness; // 2 larger is less fresh - uint8_t fresh_timeout; // 3 updates every tick + PeepThoughtType type; + union + { + uint32_t argument; + ride_id_t ride; + ShopItem item; + }; + uint8_t freshness; + uint8_t fresh_timeout; }; struct Guest; @@ -771,7 +775,10 @@ public: void HandleEasterEggName(); int32_t GetEasterEggNameId() const; void UpdateEasterEggInteractions(); - void InsertNewThought(PeepThoughtType thought_type, uint8_t thought_arguments); + void InsertNewThought(PeepThoughtType thoughtType); + void InsertNewThought(PeepThoughtType thoughtType, uint32_t arg); + void InsertNewThought(PeepThoughtType thoughtType, ride_id_t ride); + void InsertNewThought(PeepThoughtType thoughtType, ShopItem shopItem); static Guest* Generate(const CoordsXYZ& coords); bool UpdateQueuePosition(PeepActionType previous_action); void RemoveFromQueue(); diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index b027ab1af2..8d85ec22bf 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -2368,7 +2368,10 @@ private: void ImportBanner(Banner* dst, const RCT12Banner* src) { + auto id = dst->id; + *dst = {}; + dst->id = id; dst->type = RCTEntryIndexToOpenRCT2EntryIndex(src->type); dst->flags = 0; @@ -2865,7 +2868,14 @@ template<> void S4Importer::ImportEntity(const RCT12SpriteBase& srcBase) auto srcThought = &src->thoughts[i]; auto dstThought = &dst->Thoughts[i]; dstThought->type = static_cast(srcThought->type); - dstThought->item = srcThought->item; + if (srcThought->item == 255) + { + dstThought->argument = std::numeric_limits::max(); + } + else + { + dstThought->argument = srcThought->item; + } dstThought->freshness = srcThought->freshness; dstThought->fresh_timeout = srcThought->fresh_timeout; } diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 2f5619cbe2..a98686dbb6 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -882,7 +882,10 @@ public: void ImportBanner(Banner* dst, const RCT12Banner* src) { + auto id = dst->id; + *dst = {}; + dst->id = id; dst->type = RCTEntryIndexToOpenRCT2EntryIndex(src->type); dst->flags = src->flags; @@ -1741,7 +1744,14 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc) auto srcThought = &src->thoughts[i]; auto dstThought = &dst->Thoughts[i]; dstThought->type = static_cast(srcThought->type); - dstThought->item = srcThought->item; + if (srcThought->item == 255) + { + dstThought->argument = std::numeric_limits::max(); + } + else + { + dstThought->argument = srcThought->item; + } dstThought->freshness = srcThought->freshness; dstThought->fresh_timeout = srcThought->fresh_timeout; } diff --git a/src/openrct2/world/Banner.cpp b/src/openrct2/world/Banner.cpp index e2b5d8aa30..616628eab1 100644 --- a/src/openrct2/world/Banner.cpp +++ b/src/openrct2/world/Banner.cpp @@ -406,6 +406,7 @@ Banner* GetOrCreateBanner(BannerIndex id) { _banners.resize(id + 1); } + _banners[id].id = id; return &_banners[id]; } return nullptr;