diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 55658389..d549ec01 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -111,7 +111,7 @@ void PetComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpd outBitStream.Write1(); // Always serialize as dirty for now - outBitStream.Write(m_Flags); + outBitStream.Write(m_Flags); outBitStream.Write(tamed ? m_Ability : ePetAbilityType::Invalid); // Something with the overhead icon? const bool interacting = m_Interaction != LWOOBJID_EMPTY; @@ -324,7 +324,7 @@ void PetComponent::OnUse(Entity* originator) { GameMessages::SendNotifyPetTamingPuzzleSelected(originator->GetObjectID(), bricks, originator->GetSystemAddress()); m_Tamer = originator->GetObjectID(); - SetFlag(IDLE, UNKNOWN4); //SetStatus(5); + SetFlag(PetFlag::IDLE, PetFlag::UNKNOWN4); //SetStatus(5); currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID()); @@ -354,7 +354,7 @@ void PetComponent::Update(float deltaTime) { ClientFailTamingMinigame(); // TODO: This is not despawning the built model correctly } - if (HasFlag(SPAWNING)) OnSpawn(); + if (HasFlag(PetFlag::SPAWNING)) OnSpawn(); // Handle pet AI states switch (m_State) { @@ -521,7 +521,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { missionComponent->Progress(eMissionTaskType::PET_TAMING, m_Parent->GetLOT()); } - SetOnlyFlag(IDLE); + SetOnlyFlag(PetFlag::IDLE); auto* const characterComponent = tamer->GetComponent(); if (characterComponent != nullptr) { @@ -634,7 +634,7 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) { currentActivities.erase(m_Tamer); - SetOnlyFlag(TAMEABLE); //SetStatus(PetFlag::TAMEABLE); + SetOnlyFlag(PetFlag::TAMEABLE); //SetStatus(PetFlag::TAMEABLE); m_Tamer = LWOOBJID_EMPTY; m_Timer = 0; @@ -685,7 +685,7 @@ void PetComponent::ClientFailTamingMinigame() { currentActivities.erase(m_Tamer); - SetOnlyFlag(TAMEABLE); //SetStatus(PetFlag::TAMEABLE); + SetOnlyFlag(PetFlag::TAMEABLE); //SetStatus(PetFlag::TAMEABLE); m_Tamer = LWOOBJID_EMPTY; m_Timer = 0; @@ -750,12 +750,12 @@ void PetComponent::OnSpawn() { //SetOnlyFlag(IDLE); //SetStatus(PetFlag::NONE); SetPetAiState(PetAiState::follow); } else { - SetFlag(TAMEABLE); + SetFlag(PetFlag::TAMEABLE); SetPetAiState(PetAiState::idle); } - SetFlag(IDLE); - UnsetFlag(SPAWNING); + SetFlag(PetFlag::IDLE); + UnsetFlag(PetFlag::SPAWNING); Game::entityManager->SerializeEntity(m_Parent); } @@ -874,7 +874,7 @@ void PetComponent::StopInteract(bool bDontSerialize) { SetInteractType(PetInteractType::none); SetAbility(petAbility); SetPetAiState(PetAiState::follow); - SetOnlyFlag(IDLE); + SetOnlyFlag(PetFlag::IDLE); SetIsReadyToInteract(false); SetIsHandlingInteraction(false); // Needed? m_MovementAI->SetMaxSpeed(m_PetInfo.sprintSpeed); @@ -897,8 +897,8 @@ void PetComponent::SetupInteractBouncer() { const auto petAbility = ePetAbilityType::JumpOnObject; SetAbility(petAbility); - UnsetFlag(IDLE); - SetFlag(ON_SWITCH, NOT_WAITING); //SetStatus(PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set + UnsetFlag(PetFlag::IDLE); + SetFlag(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); //SetStatus(PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set LOG_DEBUG("m_Flags = %d", m_Flags); Game::entityManager->SerializeEntity(m_Parent); // TODO: Double-check pet packet captures @@ -962,7 +962,7 @@ void PetComponent::HandleInteractBouncer() { RenderComponent::PlayAnimation(petSwitchEntity, u"launch"); //u"engaged"); //TODO: Check if the timing on this is right // TODO: Need to freeze player movement until the bounce begins! - Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, PetEmote::ActivateSwitch, true); // Plays 'jump on switch' animation + Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::CastUnderlyingType(PetEmote::ActivateSwitch), true); // Plays 'jump on switch' animation StopInteract(); } m_Timer += 0.5f; @@ -977,8 +977,8 @@ void PetComponent::SetupInteractTreasureDig() { const auto petAbility = ePetAbilityType::DigAtPosition; SetAbility(petAbility); - UnsetFlag(IDLE); - SetFlag(ON_SWITCH, NOT_WAITING); //SetStatus(PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set + UnsetFlag(PetFlag::IDLE); + SetFlag(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); //SetStatus(PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set LOG_DEBUG("m_Flags = %d", m_Flags); Game::entityManager->SerializeEntity(m_Parent); // TODO: Double-check pet packet captures @@ -1010,12 +1010,12 @@ void PetComponent::StartInteractTreasureDig() { Game::entityManager->SerializeEntity(user); SetIsHandlingInteraction(true); - UnsetFlag(ON_SWITCH, NOT_WAITING); // TODO: FIND THE CORRECT STATUS TO USE HERE - SetFlag(IDLE); + UnsetFlag(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); // TODO: FIND THE CORRECT STATUS TO USE HERE + SetFlag(PetFlag::IDLE); LOG_DEBUG("StartInteractTreasureDig() m_Flags = %d", m_Flags); Game::entityManager->SerializeEntity(m_Parent); - Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, PetEmote::DigTreasure, true); // Plays 'dig' animation + Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::CastUnderlyingType(PetEmote::DigTreasure), true); // Plays 'dig' animation m_Timer = 2.0f; } @@ -1036,7 +1036,7 @@ void PetComponent::HandleInteractTreasureDig() { } if (m_TimerBounce <= 0.0f) { - Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, PetEmote::Bounce, true); // Plays 'bounce' animation + Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::CastUnderlyingType(PetEmote::Bounce), true); // Plays 'bounce' animation m_TimerBounce = 1.0f; } @@ -1060,7 +1060,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { // auto* const owner = GetOwner(); if (!owner) return; - SetFlag(SPAWNING); + SetFlag(PetFlag::SPAWNING); auto databaseData = inventoryComponent->GetDatabasePet(m_DatabaseId); diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 0d823b53..218c98bc 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -26,7 +26,7 @@ enum class PetAiState : uint8_t { /* * The type of object the pet is interacting with */ -enum PetInteractType : uint8_t { +enum class PetInteractType : uint8_t { none, // Not interacting treasure, // Treasure dig bouncer // Bouncer switch @@ -35,7 +35,7 @@ enum PetInteractType : uint8_t { /** * The flags governing the status of the pet: Governs the icon above their head and the interactions available */ -enum PetFlag : uint32_t { +enum class PetFlag : uint32_t { NONE, IDLE = 1 << 0, //0x01 - Seems to be "idle," which the game doesn't differentiate from "follow" UNKNOWN2 = 1 << 1, //0x02, @@ -49,14 +49,36 @@ enum PetFlag : uint32_t { TAMEABLE = 1 << 26 //0x4000000 }; -/* -132 = 128 + 4 +/** + * Define bitwise operators for PetFlag (TODO: Encapsulate into proper class) */ +constexpr PetFlag operator|(const PetFlag lhs, const PetFlag rhs) { + using underlying_type = std::underlying_type_t; + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +constexpr PetFlag& operator|=(PetFlag& lhs, const PetFlag rhs) { + return lhs = lhs | rhs; +} + +constexpr PetFlag operator&(const PetFlag lhs, const PetFlag rhs) { + using underlying_type = std::underlying_type_t; + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +constexpr PetFlag& operator&=(PetFlag& lhs, const PetFlag rhs) { + return lhs = lhs & rhs; +} + +constexpr PetFlag operator~(const PetFlag flag) { + using underlying_type = std::underlying_type_t; + return static_cast(~static_cast(flag)); +} /** * The pet emote animation ids that can used in PetComponent::Command() */ -enum PetEmote : int32_t { +enum class PetEmote : int32_t { ActivateSwitch = 201, DigTreasure, Bounce @@ -96,42 +118,52 @@ public: /** * Gets the AI state of the pet */ - PetAiState GetPetAiState() { return m_State; }; + PetAiState GetPetAiState() const { return m_State; } /** * Sets one or more pet flags * @param flag PetFlag(s) to set */ template - void SetFlag(varArg... flag) { m_Flags |= (static_cast(flag) | ...); }; + void SetFlag(varArg... flag) { + m_Flags |= (flag | ...); + } /** * Sets the pet to ONLY have the specified flag(s), clearing all others * @param flag PetFlag(s) to set exclusively */ template - void SetOnlyFlag(varArg... flag) { m_Flags = (static_cast(flag) | ...); }; + void SetOnlyFlag(varArg... flag) { + m_Flags = (flag | ...); + } /** * Unsets one or more pet flags * @param flag PetFlag(s) to unset */ template - void UnsetFlag(varArg... flag) { m_Flags &= ~(static_cast(flag) | ...); }; + void UnsetFlag(varArg... flag) { + m_Flags &= ~(flag | ...); + } /** * Returns true if the pet has all the specified flag(s) * @param flag PetFlag(s) to check */ template - const bool HasFlag(varArg... flag) { return (m_Flags & (static_cast(flag) | ...)) == (static_cast(flag) | ...); }; + bool HasFlag(varArg... flag) const { + return (m_Flags & (flag | ...)) == (flag | ...); + } /** * Returns true if the pet has ONLY the specified flag(s) * @param flag PetFlag(s) to check if the pet has exclusively */ template - const bool HasOnlyFlag(varArg... flag) { return m_Flags == (static_cast(flag) | ...); }; + bool HasOnlyFlag(varArg... flag) const { + return m_Flags == (flag | ...); + } /** * Governs the pet update loop @@ -526,7 +558,7 @@ private: /** * The current flags of the pet (e.g. tamable, tamed, etc). */ - uint32_t m_Flags; + PetFlag m_Flags; /** * The current state of the pet AI diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 23d1ba99..c89694e8 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -732,7 +732,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit petComponent->SetFlag(petFlag); - std::u16string msg = u"Set pet flag to " + (GeneralUtils::to_u16string(petFlag)); + std::u16string msg = u"Set pet flag to " + (GeneralUtils::to_u16string(GeneralUtils::CastUnderlyingType(petFlag))); ChatPackets::SendSystemMessage(sysAddr, msg); } diff --git a/tests/dGameTests/dComponentsTests/PetComponentTests.cpp b/tests/dGameTests/dComponentsTests/PetComponentTests.cpp index 9e063f21..4ded6219 100644 --- a/tests/dGameTests/dComponentsTests/PetComponentTests.cpp +++ b/tests/dGameTests/dComponentsTests/PetComponentTests.cpp @@ -32,6 +32,8 @@ protected: }; TEST_F(PetTest, PlacementNewAddComponentTest) { + using enum PetFlag; + // Test adding component ASSERT_NE(petComponent, nullptr); baseEntity->AddComponent(1); @@ -48,6 +50,8 @@ TEST_F(PetTest, PlacementNewAddComponentTest) { * Test bitset pet flags */ TEST_F(PetTest, PetComponentFlagTest) { + using enum PetFlag; + // Test setting and reading single flags, exclusively petComponent->SetOnlyFlag(NONE); ASSERT_TRUE(petComponent->HasOnlyFlag(NONE));