diff --git a/src/openrct2/GameStateSnapshots.cpp b/src/openrct2/GameStateSnapshots.cpp index 3f5bfec345..25c28f3356 100644 --- a/src/openrct2/GameStateSnapshots.cpp +++ b/src/openrct2/GameStateSnapshots.cpp @@ -525,7 +525,7 @@ struct GameStateSnapshots final : public IGameStateSnapshots COMPARE_FIELD(JumpingFountain, frame); COMPARE_FIELD(JumpingFountain, FountainType); COMPARE_FIELD(JumpingFountain, NumTicksAlive); - COMPARE_FIELD(JumpingFountain, FountainFlags); + COMPARE_FIELD(JumpingFountain, fountainFlags); COMPARE_FIELD(JumpingFountain, TargetX); COMPARE_FIELD(JumpingFountain, TargetY); COMPARE_FIELD(JumpingFountain, Iteration); diff --git a/src/openrct2/core/FlagHolder.hpp b/src/openrct2/core/FlagHolder.hpp index e41305563d..8b7a780ebc 100644 --- a/src/openrct2/core/FlagHolder.hpp +++ b/src/openrct2/core/FlagHolder.hpp @@ -19,7 +19,7 @@ struct FlagHolder FlagHolder() = default; template - FlagHolder(TTypes... types) + constexpr FlagHolder(TTypes... types) : holder(EnumsToFlags(types...)) { } @@ -85,4 +85,11 @@ struct FlagHolder { holder ^= EnumToFlag(flag); } + + constexpr FlagHolder operator|(const FlagHolder& other) const noexcept + { + FlagHolder res = *this; + res.holder |= other.holder; + return res; + } }; diff --git a/src/openrct2/entity/Fountain.cpp b/src/openrct2/entity/Fountain.cpp index ee92726905..ad110a1fdd 100644 --- a/src/openrct2/entity/Fountain.cpp +++ b/src/openrct2/entity/Fountain.cpp @@ -24,16 +24,16 @@ using namespace OpenRCT2; -enum class PATTERN +enum class Pattern { - CYCLIC_SQUARES, - CONTINUOUS_CHASERS, - BOUNCING_PAIRS, - SPROUTING_BLOOMS, - RACING_PAIRS, - SPLITTING_CHASERS, - DOPEY_JUMPERS, - FAST_RANDOM_CHASERS, + cyclicSquares, + continuousChasers, + bouncingPairs, + sproutingBlooms, + racingPairs, + splittingChasers, + dopeyJumpers, + fastRandomChasers, }; static constexpr std::array _fountainDirectionsNegative = { @@ -66,20 +66,20 @@ const uint8_t _fountainDirections[] = { }; // rct2: 0x0097F048 -const uint8_t _fountainDirectionFlags[] = { - 0, 0, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, 0, 0, +const FountainFlags _fountainDirectionFlags[] = { + {}, {}, FountainFlag::direction, FountainFlag::direction, FountainFlag::direction, FountainFlag::direction, {}, {}, }; // rct2: 0x0097F050 -const uint8_t _fountainPatternFlags[] = { - FOUNTAIN_FLAG::TERMINATE, // CYCLIC_SQUARES - FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::GOTO_EDGE, // CONTINUOUS_CHASERS - FOUNTAIN_FLAG::BOUNCE, // BOUNCING_PAIRS - FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::SPLIT, // SPROUTING_BLOOMS - FOUNTAIN_FLAG::GOTO_EDGE, // RACING_PAIRS - FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::GOTO_EDGE | FOUNTAIN_FLAG::SPLIT, // SPLITTING_CHASERS - 0, // DOPEY_JUMPERS - FOUNTAIN_FLAG::FAST, // FAST_RANDOM_CHASERS +const FountainFlags _fountainPatternFlags[] = { + { FountainFlag::terminate }, // cyclicSquares + { FountainFlag::fast, FountainFlag::goToEdge }, // continuousChasers + { FountainFlag::bounce }, // bouncingPairs + { FountainFlag::fast, FountainFlag::split }, // sproutingBlooms + { FountainFlag::goToEdge }, // racingPairs + { FountainFlag::fast, FountainFlag::goToEdge, FountainFlag::split }, // splittingChasers + {}, // dopeyJumpers + { FountainFlag::fast }, // fastRandomChasers }; template<> @@ -97,9 +97,9 @@ void JumpingFountain::StartAnimation(const JumpingFountainType newType, const Co // Change pattern approximately every 51 seconds uint32_t pattern = (currentTicks >> 11) & 7; - switch (static_cast(pattern)) + switch (static_cast(pattern)) { - case PATTERN::CYCLIC_SQUARES: + case Pattern::cyclicSquares: // 0, 1, 2, 3 for (int32_t i = 0; i < kNumOrthogonalDirections; i++) { @@ -108,7 +108,7 @@ void JumpingFountain::StartAnimation(const JumpingFountainType newType, const Co _fountainDirectionFlags[i] | _fountainPatternFlags[pattern], 0); } break; - case PATTERN::BOUNCING_PAIRS: + case Pattern::bouncingPairs: // random [0, 2 or 1, 3] randomIndex = ScenarioRand() & 1; for (int32_t i = randomIndex; i < kNumOrthogonalDirections; i += 2) @@ -118,7 +118,7 @@ void JumpingFountain::StartAnimation(const JumpingFountainType newType, const Co _fountainDirectionFlags[i] | _fountainPatternFlags[pattern], 0); } break; - case PATTERN::RACING_PAIRS: + case Pattern::racingPairs: // random [0 - 3 and 4 - 7] randomIndex = ScenarioRand() & 3; JumpingFountain::Create( @@ -140,14 +140,14 @@ void JumpingFountain::StartAnimation(const JumpingFountainType newType, const Co } void JumpingFountain::Create( - const JumpingFountainType newType, const CoordsXYZ& newLoc, const int32_t direction, const int32_t newFlags, + const JumpingFountainType newType, const CoordsXYZ& newLoc, const int32_t direction, const OpenRCT2::FountainFlags newFlags, const int32_t iteration) { auto* jumpingFountain = CreateEntity(); if (jumpingFountain != nullptr) { jumpingFountain->Iteration = iteration; - jumpingFountain->FountainFlags = newFlags; + jumpingFountain->fountainFlags = newFlags; jumpingFountain->Orientation = direction << 3; jumpingFountain->SpriteData.Width = 33; jumpingFountain->SpriteData.HeightMin = 36; @@ -177,11 +177,11 @@ void JumpingFountain::Update() switch (FountainType) { case JumpingFountainType::Water: - if (frame == 11 && (FountainFlags & FOUNTAIN_FLAG::FAST)) + if (frame == 11 && (fountainFlags.has(FountainFlag::fast))) { AdvanceAnimation(); } - if (frame == 16 && !(FountainFlags & FOUNTAIN_FLAG::FAST)) + if (frame == 16 && !(fountainFlags.has(FountainFlag::fast))) { AdvanceAnimation(); } @@ -227,24 +227,24 @@ void JumpingFountain::AdvanceAnimation() return; } - if (FountainFlags & FOUNTAIN_FLAG::TERMINATE) + if (fountainFlags.has(FountainFlag::terminate)) { return; } - if (FountainFlags & FOUNTAIN_FLAG::GOTO_EDGE) + if (fountainFlags.has(FountainFlag::goToEdge)) { GoToEdge({ newLoc, z }, availableDirections); return; } - if (FountainFlags & FOUNTAIN_FLAG::BOUNCE) + if (fountainFlags.has(FountainFlag::bounce)) { Bounce({ newLoc, z }, availableDirections); return; } - if (FountainFlags & FOUNTAIN_FLAG::SPLIT) + if (fountainFlags.has(FountainFlag::split)) { Split({ newLoc, z }, availableDirections); return; @@ -304,7 +304,7 @@ void JumpingFountain::GoToEdge(const CoordsXYZ& newLoc, const int32_t availableD return; } - if (FountainFlags & FOUNTAIN_FLAG::SPLIT) + if (fountainFlags.has(FountainFlag::split)) { Split(newLoc, availableDirections); return; @@ -353,14 +353,16 @@ void JumpingFountain::Split(const CoordsXYZ& newLoc, int32_t availableDirections { if (availableDirections & (1 << direction)) { - JumpingFountain::Create( - newType, newLoc, direction >> 1, FountainFlags & ~FOUNTAIN_FLAG::DIRECTION, Iteration + 1); + auto copiedFlags = fountainFlags; + copiedFlags.unset(FountainFlag::direction); + JumpingFountain::Create(newType, newLoc, direction >> 1, copiedFlags, Iteration + 1); } direction++; if (availableDirections & (1 << direction)) { - JumpingFountain::Create( - newType, newLoc, direction >> 1, FountainFlags | FOUNTAIN_FLAG::DIRECTION, Iteration + 1); + auto copiedFlags = fountainFlags; + copiedFlags.set(FountainFlag::direction); + JumpingFountain::Create(newType, newLoc, direction >> 1, copiedFlags, Iteration + 1); } } } @@ -383,11 +385,8 @@ void JumpingFountain::Random(const CoordsXYZ& newLoc, int32_t availableDirection void JumpingFountain::CreateNext(const CoordsXYZ& newLoc, int32_t direction) const { const auto newType = GetType(); - int32_t newFlags = FountainFlags & ~FOUNTAIN_FLAG::DIRECTION; - if (direction & 1) - { - newFlags |= FOUNTAIN_FLAG::DIRECTION; - } + auto newFlags = fountainFlags; + newFlags.set(FountainFlag::direction, !!(direction & 1)); JumpingFountain::Create(newType, newLoc, direction >> 1, newFlags, Iteration); } @@ -397,7 +396,7 @@ void JumpingFountain::Serialise(DataSerialiser& stream) stream << frame; stream << FountainType; stream << NumTicksAlive; - stream << FountainFlags; + stream << fountainFlags.holder; stream << TargetX; stream << TargetY; stream << Iteration; @@ -421,7 +420,7 @@ void JumpingFountain::Paint(PaintSession& session, int32_t imageDirection) const imageDirection = imageDirection / 8; // Fountain is firing anti clockwise - bool reversed = (FountainFlags & FOUNTAIN_FLAG::DIRECTION); + bool reversed = fountainFlags.has(FountainFlag::direction); // Fountain rotation bool rotated = (Orientation / 16) & 1; bool isAntiClockwise = (imageDirection / 2) & 1; // Clockwise or Anti-clockwise diff --git a/src/openrct2/entity/Fountain.h b/src/openrct2/entity/Fountain.h index 4d123c4a55..d3b177b8d6 100644 --- a/src/openrct2/entity/Fountain.h +++ b/src/openrct2/entity/Fountain.h @@ -9,12 +9,27 @@ #pragma once +#include "../core/FlagHolder.hpp" #include "../world/Map.h" #include "EntityBase.h" class DataSerialiser; struct PaintSession; +namespace OpenRCT2 +{ + enum class FountainFlag : uint8_t + { + fast, + goToEdge, + split, + terminate, + bounce, + direction = 7, + }; + using FountainFlags = FlagHolder; +} // namespace OpenRCT2 + enum class JumpingFountainType : uint8_t { Water, @@ -28,7 +43,7 @@ struct JumpingFountain : EntityBase uint16_t frame; JumpingFountainType FountainType; uint8_t NumTicksAlive; - uint8_t FountainFlags; + OpenRCT2::FountainFlags fountainFlags; int16_t TargetX; int16_t TargetY; uint16_t Iteration; @@ -46,16 +61,7 @@ private: void Random(const CoordsXYZ& newLoc, int32_t availableDirections) const; void CreateNext(const CoordsXYZ& newLoc, int32_t direction) const; static void Create( - JumpingFountainType newType, const CoordsXYZ& newLoc, int32_t direction, int32_t newFlags, int32_t iteration); + JumpingFountainType newType, const CoordsXYZ& newLoc, int32_t direction, OpenRCT2::FountainFlags newFlags, + int32_t iteration); static bool IsJumpingFountain(JumpingFountainType newType, const CoordsXYZ& newLoc); }; - -namespace OpenRCT2::FOUNTAIN_FLAG -{ - const uint32_t FAST = 1 << 0; - const uint32_t GOTO_EDGE = 1 << 1; - const uint32_t SPLIT = 1 << 2; - const uint32_t TERMINATE = 1 << 3; - const uint32_t BOUNCE = 1 << 4; - const uint32_t DIRECTION = 1 << 7; -}; // namespace OpenRCT2::FOUNTAIN_FLAG diff --git a/src/openrct2/park/ParkFile.cpp b/src/openrct2/park/ParkFile.cpp index cce8ec806f..57874bd616 100644 --- a/src/openrct2/park/ParkFile.cpp +++ b/src/openrct2/park/ParkFile.cpp @@ -2557,7 +2557,7 @@ namespace OpenRCT2 ReadWriteEntityCommon(cs, fountain); cs.ReadWrite(fountain.NumTicksAlive); cs.ReadWrite(fountain.frame); - cs.ReadWrite(fountain.FountainFlags); + cs.ReadWrite(fountain.fountainFlags.holder); cs.ReadWrite(fountain.TargetX); cs.ReadWrite(fountain.TargetY); cs.ReadWrite(fountain.TargetY); diff --git a/src/openrct2/rct1/RCT1.h b/src/openrct2/rct1/RCT1.h index d346c9b394..36ed2caf32 100644 --- a/src/openrct2/rct1/RCT1.h +++ b/src/openrct2/rct1/RCT1.h @@ -703,7 +703,7 @@ namespace OpenRCT2::RCT1 RCT12EntityLitter Litter; RCT12EntityBalloon Balloon; RCT12EntityDuck Duck; - RCT12EntityJumpingFountain JumpingFountain; + RCT12EntityJumpingFountain JumpingFountain{}; RCT12EntityMoneyEffect MoneyEffect; RCT12EntityCrashedVehicleParticle CrashedVehicleParticle; RCT12EntityCrashSplash CrashSplash; diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 194951cf4d..cba5d5bb15 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -3089,7 +3089,7 @@ namespace OpenRCT2::RCT1 dst->frame = src->Frame; dst->FountainType = fountainType; dst->NumTicksAlive = src->NumTicksAlive; - dst->FountainFlags = src->FountainFlags; + dst->fountainFlags = src->fountainFlags; dst->TargetX = src->TargetX; dst->TargetY = src->TargetY; dst->Iteration = src->Iteration; diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 08cc9b9e5b..17493a58a3 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -12,7 +12,9 @@ // Structures shared between both RCT1 and RCT2. #include "../core/EnumUtils.hpp" +#include "../core/FlagHolder.hpp" #include "../core/Money.hpp" +#include "../entity/Fountain.h" #include "../management/Research.h" #include "../object/Object.h" #include "../ride/RideTypes.h" @@ -1116,9 +1118,9 @@ struct RCT12EntityJumpingFountain : RCT12EntityBase uint8_t NumTicksAlive; // 0x26 uint8_t Frame; // 0x27 uint8_t Pad28[0x2F - 0x28]; - uint8_t FountainFlags; // 0x2F - int16_t TargetX; // 0x30 - int16_t TargetY; // 0x32 + OpenRCT2::FountainFlags fountainFlags{}; // 0x2F + int16_t TargetX; // 0x30 + int16_t TargetY; // 0x32 uint8_t Pad34[0x46 - 0x34]; uint16_t Iteration; // 0x46 }; diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index d913f0aa60..a931fe8342 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -708,7 +708,7 @@ namespace OpenRCT2::RCT2 RCT12EntityLitter Litter; RCT12EntityBalloon Balloon; RCT12EntityDuck Duck; - RCT12EntityJumpingFountain JumpingFountain; + RCT12EntityJumpingFountain JumpingFountain{}; RCT12EntityMoneyEffect MoneyEffect; RCT12EntityCrashedVehicleParticle CrashedVehicleParticle; RCT12EntityCrashSplash CrashSplash; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 95d1e9ccc1..2dc3101bbd 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -2231,7 +2231,7 @@ namespace OpenRCT2::RCT2 ImportEntityCommonProperties(dst, src); dst->NumTicksAlive = src->NumTicksAlive; dst->frame = src->Frame; - dst->FountainFlags = src->FountainFlags; + dst->fountainFlags = src->fountainFlags; dst->TargetX = src->TargetX; dst->TargetY = src->TargetY; dst->Iteration = src->Iteration;