mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-12-23 14:03:34 +00:00
clean up PetComponent
This commit is contained in:
parent
d88b982904
commit
0b2453241b
@ -4,6 +4,7 @@ set(DCOMMON_SOURCES
|
||||
"BinaryIO.cpp"
|
||||
"dConfig.cpp"
|
||||
"Diagnostics.cpp"
|
||||
"Flag.h"
|
||||
"Logger.cpp"
|
||||
"Game.cpp"
|
||||
"GeneralUtils.cpp"
|
||||
|
82
dCommon/Flag.h
Normal file
82
dCommon/Flag.h
Normal file
@ -0,0 +1,82 @@
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
#include <bit>
|
||||
// TODO: Test bounds checking
|
||||
|
||||
template <typename T>
|
||||
requires std::is_enum_v<T>
|
||||
class Flag {
|
||||
public:
|
||||
using type = T;
|
||||
using underlying_type = std::underlying_type_t<T>;
|
||||
static constexpr auto MAX_FLAG_VAL = std::bit_width(sizeof(underlying_type));
|
||||
|
||||
/**
|
||||
* Sets one or more flags
|
||||
* @param flag Flag(s) to set
|
||||
*/
|
||||
template <std::same_as<T>... varArg>
|
||||
constexpr void Set(varArg... flag) noexcept {
|
||||
m_Flags |= (ConvertFlag(flag) | ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets ONLY have the specified flag(s), clearing all others
|
||||
* @param flag Flag(s) to set exclusively
|
||||
*/
|
||||
template <std::same_as<T>... varArg>
|
||||
constexpr void Reset(varArg... flag) {
|
||||
m_Flags = (ConvertFlag(flag) | ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets one or more flags
|
||||
* @param flag Flag(s) to unset
|
||||
*/
|
||||
template <std::same_as<T>... varArg>
|
||||
constexpr void Unset(varArg... flag) {
|
||||
m_Flags &= ~(ConvertFlag(flag) | ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true all the specified flag(s) are set
|
||||
* @param flag Flag(s) to check
|
||||
*/
|
||||
template <std::same_as<T>... varArg>
|
||||
constexpr bool Has(varArg... flag) const {
|
||||
return (m_Flags & (ConvertFlag(flag) | ...)) == (ConvertFlag(flag) | ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true ONLY the specified flag(s) are set
|
||||
* @param flag Flag(s) to check
|
||||
*/
|
||||
template <std::same_as<T>... varArg>
|
||||
constexpr bool HasOnly(varArg... flag) const {
|
||||
return m_Flags == (ConvertFlag(flag) | ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator overload to allow for '=' assignment
|
||||
*/
|
||||
constexpr Flag& operator=(const T value) {
|
||||
Reset(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]]
|
||||
static constexpr underlying_type ConvertFlag(const T flag) {
|
||||
auto flag_val = GeneralUtils::ToUnderlying(flag);
|
||||
if (flag_val != 0) {
|
||||
return 1 << flag_val;
|
||||
}
|
||||
// This should theoeretically be possible to do at compile time, but idk how
|
||||
if (std::bit_width(flag_val) > MAX_FLAG_VAL) {
|
||||
throw std::runtime_error{ "Enum value too large to be a flag!" };
|
||||
}
|
||||
return flag_val;
|
||||
}
|
||||
|
||||
underlying_type m_Flags;
|
||||
};
|
@ -37,7 +37,7 @@
|
||||
#include "eMissionState.h"
|
||||
#include "dNavMesh.h"
|
||||
|
||||
std::unordered_map<LOT, PetComponent::PetPuzzleData> PetComponent::buildCache{};
|
||||
std::unordered_map<LOT, PetComponent::PuzzleData> PetComponent::buildCache{};
|
||||
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
|
||||
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
|
||||
|
||||
@ -45,7 +45,7 @@ std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
|
||||
* Maps all the pet lots to a flag indicating that the player has caught it. All basic pets have been guessed by ObjID
|
||||
* while the faction ones could be checked using their respective missions.
|
||||
*/
|
||||
std::map<LOT, int32_t> PetComponent::petFlags = {
|
||||
std::map<LOT, int32_t> PetComponent::petFlags{
|
||||
{ 3050, 801 }, // Elephant
|
||||
{ 3054, 803 }, // Cat
|
||||
{ 3195, 806 }, // Triceratops
|
||||
@ -78,31 +78,17 @@ std::map<LOT, int32_t> PetComponent::petFlags = {
|
||||
PetComponent::PetComponent(Entity* parentEntity, uint32_t componentId) : Component{ parentEntity } {
|
||||
m_PetInfo = CDClientManager::GetTable<CDPetComponentTable>()->GetByID(componentId); // TODO: Make reference when safe
|
||||
m_ComponentId = componentId;
|
||||
m_Interaction = LWOOBJID_EMPTY;
|
||||
m_InteractType = PetInteractType::none;
|
||||
m_Owner = LWOOBJID_EMPTY;
|
||||
m_ModerationStatus = 0;
|
||||
m_Tamer = LWOOBJID_EMPTY;
|
||||
m_ModelId = LWOOBJID_EMPTY;
|
||||
m_Timer = 0;
|
||||
m_TimerAway = 0;
|
||||
m_TimerBounce = 0;
|
||||
m_DatabaseId = LWOOBJID_EMPTY;
|
||||
m_Flags = PetFlag::SPAWNING; // Tameable
|
||||
m_Ability = ePetAbilityType::Invalid;
|
||||
m_StartPosition = m_Parent->GetPosition();
|
||||
m_MovementAI = nullptr;
|
||||
m_Preconditions = nullptr;
|
||||
|
||||
m_ReadyToInteract = false;
|
||||
SetPetAiState(PetAiState::spawn);
|
||||
m_State = PetAiState::spawn;
|
||||
SetIsHandlingInteraction(false);
|
||||
|
||||
std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parentEntity->GetVar<std::u16string>(u"CheckPrecondition"));
|
||||
|
||||
if (!checkPreconditions.empty()) {
|
||||
SetPreconditions(checkPreconditions);
|
||||
}
|
||||
m_Preconditions =
|
||||
checkPreconditions.empty() ? std::nullopt : std::make_optional(PreconditionExpression(checkPreconditions));
|
||||
|
||||
m_FollowRadius = 8.0f; //Game::zoneManager->GetPetFollowRadius(); // TODO: FIX THIS TO LOAD DYNAMICALLY
|
||||
}
|
||||
@ -113,13 +99,13 @@ void PetComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpd
|
||||
outBitStream.Write1(); // Always serialize as dirty for now
|
||||
|
||||
outBitStream.Write(m_Flags);
|
||||
outBitStream.Write(tamed ? m_Ability : ePetAbilityType::Invalid); // Something with the overhead icon?
|
||||
outBitStream.Write(tamed ? m_Interaction.ability : ePetAbilityType::Invalid); // Something with the overhead icon?
|
||||
|
||||
const bool interacting = m_Interaction != LWOOBJID_EMPTY;
|
||||
const bool interacting = m_Interaction.obj != LWOOBJID_EMPTY;
|
||||
|
||||
outBitStream.Write(interacting);
|
||||
if (interacting) {
|
||||
outBitStream.Write(m_Interaction);
|
||||
outBitStream.Write(m_Interaction.obj);
|
||||
}
|
||||
|
||||
outBitStream.Write(tamed);
|
||||
@ -148,16 +134,11 @@ void PetComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpd
|
||||
}
|
||||
}
|
||||
|
||||
void PetComponent::SetPetAiState(PetAiState newState) {
|
||||
if (newState == GetPetAiState()) return;
|
||||
this->m_State = newState;
|
||||
}
|
||||
|
||||
void PetComponent::OnUse(Entity* originator) {
|
||||
LOG_DEBUG("PET USE!");
|
||||
|
||||
if (IsReadyToInteract()) {
|
||||
switch (GetAbility()) {
|
||||
switch (m_Interaction.ability) {
|
||||
case ePetAbilityType::DigAtPosition: // Treasure dig
|
||||
StartInteractTreasureDig();
|
||||
break;
|
||||
@ -186,7 +167,7 @@ void PetComponent::OnUse(Entity* originator) {
|
||||
|
||||
if (!inventoryComponent) return;
|
||||
|
||||
if (m_Preconditions != nullptr && !m_Preconditions->Check(originator, true)) return;
|
||||
if (m_Preconditions.has_value() && !m_Preconditions->Check(originator, true)) return;
|
||||
|
||||
auto* const movementAIComponent = m_Parent->GetComponent<MovementAIComponent>();
|
||||
|
||||
@ -223,7 +204,7 @@ void PetComponent::OnUse(Entity* originator) {
|
||||
|
||||
buildFile = std::string(result.getStringField("ValidPiecesLXF"));
|
||||
|
||||
PetPuzzleData data;
|
||||
PuzzleData data;
|
||||
data.buildFile = buildFile;
|
||||
data.puzzleModelLot = result.getIntField("PuzzleModelLot");
|
||||
data.timeLimit = result.getFloatField("Timelimit");
|
||||
@ -324,7 +305,7 @@ void PetComponent::OnUse(Entity* originator) {
|
||||
GameMessages::SendNotifyPetTamingPuzzleSelected(originator->GetObjectID(), bricks, originator->GetSystemAddress());
|
||||
|
||||
m_Tamer = originator->GetObjectID();
|
||||
SetFlag(PetFlag::IDLE, PetFlag::UNKNOWN4);
|
||||
m_Flags.Set(PetFlag::IDLE, PetFlag::UNKNOWN4);
|
||||
|
||||
currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID());
|
||||
|
||||
@ -352,7 +333,7 @@ void PetComponent::Update(float deltaTime) {
|
||||
ClientFailTamingMinigame(); // TODO: This is not despawning the built model correctly
|
||||
}
|
||||
|
||||
if (HasFlag(PetFlag::SPAWNING)) OnSpawn();
|
||||
if (m_Flags.Has(PetFlag::SPAWNING)) OnSpawn();
|
||||
|
||||
// Handle pet AI states
|
||||
switch (m_State) {
|
||||
@ -519,7 +500,7 @@ void PetComponent::NotifyTamingBuildSuccess(const NiPoint3 position) {
|
||||
missionComponent->Progress(eMissionTaskType::PET_TAMING, m_Parent->GetLOT());
|
||||
}
|
||||
|
||||
SetOnlyFlag(PetFlag::IDLE);
|
||||
m_Flags.Reset(PetFlag::IDLE);
|
||||
|
||||
auto* const characterComponent = tamer->GetComponent<CharacterComponent>();
|
||||
if (characterComponent != nullptr) {
|
||||
@ -630,7 +611,7 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) {
|
||||
|
||||
currentActivities.erase(m_Tamer);
|
||||
|
||||
SetOnlyFlag(PetFlag::TAMEABLE);
|
||||
m_Flags.Reset(PetFlag::TAMEABLE);
|
||||
m_Tamer = LWOOBJID_EMPTY;
|
||||
m_Timer = 0;
|
||||
|
||||
@ -679,7 +660,7 @@ void PetComponent::ClientFailTamingMinigame() {
|
||||
|
||||
currentActivities.erase(m_Tamer);
|
||||
|
||||
SetOnlyFlag(PetFlag::TAMEABLE);
|
||||
m_Flags.Reset(PetFlag::TAMEABLE);
|
||||
m_Tamer = LWOOBJID_EMPTY;
|
||||
m_Timer = 0;
|
||||
|
||||
@ -742,12 +723,12 @@ void PetComponent::OnSpawn() {
|
||||
//SetOnlyFlag(IDLE); //SetStatus(PetFlag::NONE);
|
||||
SetPetAiState(PetAiState::follow);
|
||||
} else {
|
||||
SetFlag(PetFlag::TAMEABLE);
|
||||
m_Flags.Set(PetFlag::TAMEABLE);
|
||||
SetPetAiState(PetAiState::idle);
|
||||
}
|
||||
|
||||
SetFlag(PetFlag::IDLE);
|
||||
UnsetFlag(PetFlag::SPAWNING);
|
||||
m_Flags.Set(PetFlag::IDLE);
|
||||
m_Flags.Unset(PetFlag::SPAWNING);
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
@ -825,7 +806,7 @@ void PetComponent::OnInteract() {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (GetInteractType()) {
|
||||
switch (m_Interaction.type) {
|
||||
case PetInteractType::bouncer:
|
||||
if (IsReadyToInteract()) HandleInteractBouncer();
|
||||
else SetupInteractBouncer();
|
||||
@ -844,10 +825,10 @@ void PetComponent::OnInteract() {
|
||||
}
|
||||
}
|
||||
|
||||
void PetComponent::StartInteract(const NiPoint3& position, const PetInteractType interactType, const LWOOBJID& interactID) {
|
||||
SetInteraction(interactID); // TODO: Check if this should be serialized for goToObj
|
||||
SetInteractType(interactType);
|
||||
SetAbility(ePetAbilityType::GoToObject);
|
||||
void PetComponent::StartInteract(const NiPoint3& position, const PetInteractType interactionType, const LWOOBJID& interactID) {
|
||||
m_Interaction.obj; // TODO: Check if this should be serialized for goToObj
|
||||
m_Interaction.type = interactionType;
|
||||
m_Interaction.ability = ePetAbilityType::GoToObject;
|
||||
SetPetAiState(PetAiState::goToObj);
|
||||
m_MovementAI->SetMaxSpeed(m_PetInfo.runSpeed);
|
||||
m_MovementAI->SetHaltDistance(0.0f);
|
||||
@ -860,13 +841,13 @@ void PetComponent::StopInteract(bool bDontSerialize) {
|
||||
Entity* const owner = GetOwner();
|
||||
if (!owner) return;
|
||||
|
||||
const auto petAbility = ePetAbilityType::Invalid;
|
||||
constexpr auto petAbility = ePetAbilityType::Invalid;
|
||||
|
||||
SetInteraction(LWOOBJID_EMPTY);
|
||||
SetInteractType(PetInteractType::none);
|
||||
SetAbility(petAbility);
|
||||
m_Interaction.obj = LWOOBJID_EMPTY;
|
||||
m_Interaction.type = PetInteractType::none;
|
||||
m_Interaction.ability = petAbility;
|
||||
SetPetAiState(PetAiState::follow);
|
||||
SetOnlyFlag(PetFlag::IDLE);
|
||||
m_Flags.Reset(PetFlag::IDLE);
|
||||
SetIsReadyToInteract(false);
|
||||
SetIsHandlingInteraction(false); // Needed?
|
||||
m_MovementAI->SetMaxSpeed(m_PetInfo.sprintSpeed);
|
||||
@ -886,11 +867,11 @@ void PetComponent::SetupInteractBouncer() {
|
||||
|
||||
LOG_DEBUG("Setting up bouncer interaction!");
|
||||
SetIsReadyToInteract(true);
|
||||
const auto petAbility = ePetAbilityType::JumpOnObject;
|
||||
constexpr auto petAbility = ePetAbilityType::JumpOnObject;
|
||||
|
||||
SetAbility(petAbility);
|
||||
UnsetFlag(PetFlag::IDLE);
|
||||
SetFlag(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); //SetStatus(PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set
|
||||
m_Interaction.ability = petAbility;
|
||||
m_Flags.Unset(PetFlag::IDLE);
|
||||
m_Flags.Set(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
|
||||
|
||||
@ -969,11 +950,11 @@ void PetComponent::SetupInteractTreasureDig() {
|
||||
|
||||
LOG_DEBUG("Setting up dig interaction!");
|
||||
SetIsReadyToInteract(true);
|
||||
const auto petAbility = ePetAbilityType::DigAtPosition;
|
||||
constexpr auto petAbility = ePetAbilityType::DigAtPosition;
|
||||
|
||||
SetAbility(petAbility);
|
||||
UnsetFlag(PetFlag::IDLE);
|
||||
SetFlag(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set
|
||||
m_Interaction.ability = petAbility;
|
||||
m_Flags.Unset(PetFlag::IDLE);
|
||||
m_Flags.Set(PetFlag::ON_SWITCH, 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
|
||||
|
||||
@ -1007,8 +988,8 @@ void PetComponent::StartInteractTreasureDig() {
|
||||
Game::entityManager->SerializeEntity(user);
|
||||
|
||||
SetIsHandlingInteraction(true);
|
||||
UnsetFlag(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); // TODO: FIND THE CORRECT STATUS TO USE HERE
|
||||
SetFlag(PetFlag::IDLE);
|
||||
m_Flags.Unset(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); // TODO: FIND THE CORRECT STATUS TO USE HERE
|
||||
m_Flags.Set(PetFlag::IDLE);
|
||||
LOG_DEBUG("StartInteractTreasureDig() m_Flags = %d", m_Flags);
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
|
||||
@ -1057,7 +1038,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { //
|
||||
auto* const owner = GetOwner();
|
||||
|
||||
if (!owner) return;
|
||||
SetFlag(PetFlag::SPAWNING);
|
||||
m_Flags.Set(PetFlag::SPAWNING);
|
||||
|
||||
auto databaseData = inventoryComponent->GetDatabasePet(m_DatabaseId);
|
||||
|
||||
@ -1203,39 +1184,11 @@ void PetComponent::Command(const NiPoint3& position, const LWOOBJID source, cons
|
||||
}
|
||||
}
|
||||
|
||||
LWOOBJID PetComponent::GetOwnerId() const {
|
||||
return m_Owner;
|
||||
}
|
||||
|
||||
Entity* PetComponent::GetOwner() const {
|
||||
return Game::entityManager->GetEntity(m_Owner);
|
||||
}
|
||||
|
||||
LWOOBJID PetComponent::GetDatabaseId() const {
|
||||
return m_DatabaseId;
|
||||
}
|
||||
|
||||
LWOOBJID PetComponent::GetInteraction() const {
|
||||
return m_Interaction;
|
||||
}
|
||||
|
||||
LWOOBJID PetComponent::GetItemId() const {
|
||||
return m_ItemId;
|
||||
}
|
||||
|
||||
ePetAbilityType PetComponent::GetAbility() const {
|
||||
return m_Ability;
|
||||
}
|
||||
|
||||
void PetComponent::SetInteraction(LWOOBJID value) {
|
||||
m_Interaction = value;
|
||||
}
|
||||
|
||||
void PetComponent::SetAbility(ePetAbilityType value) {
|
||||
m_Ability = value;
|
||||
}
|
||||
|
||||
PetComponent* PetComponent::GetTamingPet(LWOOBJID tamer) {
|
||||
PetComponent* PetComponent::GetTamingPet(const LWOOBJID tamer) {
|
||||
const auto& pair = currentActivities.find(tamer);
|
||||
|
||||
if (pair == currentActivities.end()) {
|
||||
@ -1253,7 +1206,7 @@ PetComponent* PetComponent::GetTamingPet(LWOOBJID tamer) {
|
||||
return entity->GetComponent<PetComponent>();
|
||||
}
|
||||
|
||||
PetComponent* PetComponent::GetActivePet(LWOOBJID owner) {
|
||||
PetComponent* PetComponent::GetActivePet(const LWOOBJID owner) {
|
||||
const auto& pair = activePets.find(owner);
|
||||
|
||||
if (pair == activePets.end()) {
|
||||
@ -1271,13 +1224,6 @@ PetComponent* PetComponent::GetActivePet(LWOOBJID owner) {
|
||||
return entity->GetComponent<PetComponent>();
|
||||
}
|
||||
|
||||
Entity* PetComponent::GetParentEntity() const {
|
||||
return m_Parent;
|
||||
}
|
||||
|
||||
PetComponent::~PetComponent() {
|
||||
}
|
||||
|
||||
void PetComponent::SetPetNameForModeration(const std::string& petName) {
|
||||
int approved = 1; //default, in mod
|
||||
|
||||
@ -1291,7 +1237,7 @@ void PetComponent::SetPetNameForModeration(const std::string& petName) {
|
||||
}
|
||||
|
||||
void PetComponent::LoadPetNameFromModeration() {
|
||||
auto petNameInfo = Database::Get()->GetPetNameInfo(m_DatabaseId);
|
||||
const auto petNameInfo = Database::Get()->GetPetNameInfo(m_DatabaseId);
|
||||
if (petNameInfo) {
|
||||
m_ModerationStatus = petNameInfo->approvalStatus;
|
||||
if (m_ModerationStatus == 2) {
|
||||
@ -1299,7 +1245,3 @@ void PetComponent::LoadPetNameFromModeration() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PetComponent::SetPreconditions(std::string& preconditions) {
|
||||
m_Preconditions = new PreconditionExpression(preconditions);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define PETCOMPONENT_H
|
||||
|
||||
#include "Entity.h"
|
||||
#include "Flag.h"
|
||||
#include "MovementAIComponent.h"
|
||||
#include "Component.h"
|
||||
#include "Preconditions.h"
|
||||
@ -11,6 +12,13 @@
|
||||
#include "CDPetComponentTable.h"
|
||||
#include "CDClientManager.h"
|
||||
|
||||
#include <optional>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Forward declarations
|
||||
class PetTest;
|
||||
class PetComponentFlagTest;
|
||||
|
||||
/*
|
||||
* The current state of the pet AI
|
||||
*/
|
||||
@ -37,44 +45,18 @@ enum class PetInteractType : uint8_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,
|
||||
UNKNOWN4 = 1 << 2, //0x04 - FOLLOWING(?)
|
||||
BEING_TAMED = 1 << 4, //0x10,
|
||||
NOT_WAITING = 1 << 5, //0x20,
|
||||
IMMOBILE = 1 << 6, //0x40 - Seems to be the "stop moving" flag - called when taming begins and stays active until a name is submitted
|
||||
SPAWNING = 1 << 7, //0x80
|
||||
ON_SWITCH = 1 << 8, //0x100
|
||||
UNKNOWN1024 = 1 << 10, //0x400
|
||||
TAMEABLE = 1 << 26 //0x4000000
|
||||
IDLE, //0x01 - Seems to be "idle," which the game doesn't differentiate from "follow"
|
||||
UNKNOWN2, //0x02,
|
||||
UNKNOWN4, //0x04 - FOLLOWING(?)
|
||||
BEING_TAMED, //0x10,
|
||||
NOT_WAITING, //0x20,
|
||||
IMMOBILE, //0x40 - Seems to be the "stop moving" flag - called when taming begins and stays active until a name is submitted
|
||||
SPAWNING, //0x80
|
||||
ON_SWITCH, //0x100
|
||||
UNKNOWN1024 = 10, //0x400
|
||||
TAMEABLE = 26 //0x4000000
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<PetFlag>;
|
||||
return static_cast<PetFlag>(static_cast<underlying_type>(lhs) | static_cast<underlying_type>(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<PetFlag>;
|
||||
return static_cast<PetFlag>(static_cast<underlying_type>(lhs) & static_cast<underlying_type>(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<PetFlag>;
|
||||
return static_cast<PetFlag>(~static_cast<underlying_type>(flag));
|
||||
}
|
||||
|
||||
/**
|
||||
* The pet emote animation ids that can used in PetComponent::Command()
|
||||
*/
|
||||
@ -88,8 +70,7 @@ enum class PetEmote : int32_t {
|
||||
* Represents an entity that is a pet. This pet can be tamed and consequently follows the tamer around, allowing it
|
||||
* to dig for treasure and activate pet bouncers.
|
||||
*/
|
||||
class PetComponent final : public Component
|
||||
{
|
||||
class PetComponent final : public Component {
|
||||
public:
|
||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::PET;
|
||||
|
||||
@ -99,8 +80,8 @@ public:
|
||||
* @param componentId The component id
|
||||
*/
|
||||
explicit PetComponent(Entity* parentEntity, uint32_t componentId);
|
||||
|
||||
~PetComponent() override;
|
||||
|
||||
~PetComponent() override = default;
|
||||
|
||||
/**
|
||||
* Serializes the pet
|
||||
@ -113,56 +94,16 @@ public:
|
||||
* Sets the AI state of the pet
|
||||
* @param newState New pet AI state
|
||||
*/
|
||||
void SetPetAiState(PetAiState newState);
|
||||
void SetPetAiState(const PetAiState newState) noexcept {
|
||||
m_State = newState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the AI state of the pet
|
||||
*/
|
||||
PetAiState GetPetAiState() const { return m_State; }
|
||||
|
||||
/**
|
||||
* Sets one or more pet flags
|
||||
* @param flag PetFlag(s) to set
|
||||
*/
|
||||
template <typename... varArg>
|
||||
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 <typename... varArg>
|
||||
void SetOnlyFlag(varArg... flag) {
|
||||
m_Flags = (flag | ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets one or more pet flags
|
||||
* @param flag PetFlag(s) to unset
|
||||
*/
|
||||
template <typename... varArg>
|
||||
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 <typename... varArg>
|
||||
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 <typename... varArg>
|
||||
bool HasOnlyFlag(varArg... flag) const {
|
||||
return m_Flags == (flag | ...);
|
||||
[[nodiscard]]
|
||||
PetAiState GetPetAiState() const noexcept {
|
||||
return m_State;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -238,7 +179,7 @@ public:
|
||||
/**
|
||||
* Start a pet interaction with an object at a given position
|
||||
*/
|
||||
void StartInteract(const NiPoint3& position, const PetInteractType interactType, const LWOOBJID& interactID);
|
||||
void StartInteract(const NiPoint3& position, const PetInteractType interactionType, const LWOOBJID& interactID);
|
||||
|
||||
/**
|
||||
* Stop a pet interaction with an object
|
||||
@ -246,16 +187,6 @@ public:
|
||||
*/
|
||||
void StopInteract(bool bDontSerialize = false);
|
||||
|
||||
/**
|
||||
* Set the type of interaction the pet is executing
|
||||
*/
|
||||
void SetInteractType(PetInteractType interactType) { m_InteractType = interactType; };
|
||||
|
||||
/**
|
||||
* Get the type of interaction the pet is executing
|
||||
*/
|
||||
PetInteractType GetInteractType() { return m_InteractType; };
|
||||
|
||||
/**
|
||||
* Spawns a pet from an item in the inventory of an owner
|
||||
* @param item the item to create the pet from
|
||||
@ -287,90 +218,75 @@ public:
|
||||
* Returns the ID of the owner of this pet (if any)
|
||||
* @return the ID of the owner of this pet
|
||||
*/
|
||||
LWOOBJID GetOwnerId() const;
|
||||
[[nodiscard]]
|
||||
LWOOBJID GetOwnerId() const noexcept {
|
||||
return m_Owner;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the entity that owns this pet (if any)
|
||||
* @return the entity that owns this pet
|
||||
*/
|
||||
[[nodiscard]]
|
||||
Entity* GetOwner() const;
|
||||
|
||||
/**
|
||||
* Returns the ID that is stored in the database with regards to this pet, only set for pets that are tamed
|
||||
* @return the ID that is stored in the database with regards to this pet
|
||||
*/
|
||||
LWOOBJID GetDatabaseId() const;
|
||||
|
||||
/**
|
||||
* Returns the ID of the object that the pet is currently interacting with, could be a treasure chest or a switch
|
||||
* @return the ID of the object that the pet is currently interacting with
|
||||
*/
|
||||
LWOOBJID GetInteraction() const;
|
||||
|
||||
/**
|
||||
* Sets the ID that the pet is interacting with
|
||||
* @param value the ID that the pet is interacting with
|
||||
*/
|
||||
void SetInteraction(LWOOBJID value);
|
||||
[[nodiscard]]
|
||||
LWOOBJID GetDatabaseId() const noexcept {
|
||||
return m_DatabaseId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID that this pet was spawned from, only set for tamed pets
|
||||
* @return the ID that this pet was spawned from
|
||||
*/
|
||||
LWOOBJID GetItemId() const;
|
||||
|
||||
/**
|
||||
* Returns the status of this pet, e.g. tamable or tamed. The values here are still a bit of mystery and likely a
|
||||
* bit map
|
||||
* @return the status of this pet
|
||||
*/
|
||||
/*uint32_t GetStatus() const;*/
|
||||
|
||||
/**
|
||||
* Sets the current status of the pet
|
||||
* @param value the current status of the pet to set
|
||||
*/
|
||||
/*void SetStatus(uint32_t value);*/
|
||||
|
||||
/**
|
||||
* Returns an ability the pet may perform, currently unused
|
||||
* @return an ability the pet may perform
|
||||
*/
|
||||
ePetAbilityType GetAbility() const;
|
||||
|
||||
/**
|
||||
* Sets the ability of the pet, currently unused
|
||||
* @param value the ability to set
|
||||
*/
|
||||
void SetAbility(ePetAbilityType value);
|
||||
[[nodiscard]]
|
||||
LWOOBJID GetItemId() const noexcept {
|
||||
return m_ItemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets preconditions for the pet that need to be met before it can be tamed
|
||||
* @param conditions the preconditions to set
|
||||
*/
|
||||
void SetPreconditions(std::string& conditions);
|
||||
void SetPreconditions(const std::string& preconditions) {
|
||||
m_Preconditions = PreconditionExpression(preconditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the pet is ready to interact with an object
|
||||
* @param isReady whether the pet is ready to interact (true) or not (false)
|
||||
*/
|
||||
void SetIsReadyToInteract(bool isReady) { m_ReadyToInteract = isReady; };
|
||||
void SetIsReadyToInteract(const bool isReady) {
|
||||
m_ReadyToInteract = isReady;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return is pet ready to interact with an object
|
||||
*/
|
||||
bool IsReadyToInteract() { return m_ReadyToInteract; };
|
||||
[[nodiscard]]
|
||||
bool IsReadyToInteract() const noexcept {
|
||||
return m_ReadyToInteract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the pet is currently handling an interaction with an object
|
||||
* @param isHandlingInteraction whether the pet is currently handling an interaction with an object
|
||||
*/
|
||||
void SetIsHandlingInteraction(bool isHandlingInteraction) { m_IsHandlingInteraction = isHandlingInteraction; };
|
||||
void SetIsHandlingInteraction(const bool isHandlingInteraction) {
|
||||
m_IsHandlingInteraction = isHandlingInteraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return is pet currently handling an interaction with an object
|
||||
*/
|
||||
bool IsHandlingInteraction() { return m_IsHandlingInteraction; };
|
||||
[[nodiscard]]
|
||||
bool IsHandlingInteraction() const noexcept {
|
||||
return m_IsHandlingInteraction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set up the pet bouncer interaction
|
||||
@ -406,7 +322,10 @@ public:
|
||||
* Returns the entity that this component belongs to
|
||||
* @return the entity that this component belongs to
|
||||
*/
|
||||
Entity* GetParentEntity() const;
|
||||
[[nodiscard]]
|
||||
Entity* GetParentEntity() const noexcept {
|
||||
return m_Parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the pet to be moderated
|
||||
@ -425,6 +344,7 @@ public:
|
||||
* @param tamer the entity that's currently taming
|
||||
* @return the pet component of the entity that's being tamed
|
||||
*/
|
||||
[[nodiscard]]
|
||||
static PetComponent* GetTamingPet(LWOOBJID tamer);
|
||||
|
||||
/**
|
||||
@ -432,6 +352,7 @@ public:
|
||||
* @param owner the owner of the pet that's spawned
|
||||
* @return the pet component of the entity that was spawned by the owner
|
||||
*/
|
||||
[[nodiscard]]
|
||||
static PetComponent* GetActivePet(LWOOBJID owner);
|
||||
|
||||
/**
|
||||
@ -443,11 +364,15 @@ public:
|
||||
void AddDrainImaginationTimer(Item* item, bool fromTaming = false);
|
||||
|
||||
private:
|
||||
// Needed so these can access flags
|
||||
friend class DamagingPets;
|
||||
friend class PetTest;
|
||||
FRIEND_TEST(PetTest, PetComponentFlagTest);
|
||||
|
||||
/**
|
||||
* Information for the minigame to be completed
|
||||
*/
|
||||
struct PetPuzzleData
|
||||
struct PuzzleData
|
||||
{
|
||||
/**
|
||||
* The LOT of the object that is to be created
|
||||
@ -475,6 +400,28 @@ private:
|
||||
int32_t numValidPieces;
|
||||
};
|
||||
|
||||
struct Interaction {
|
||||
/**
|
||||
* The type of object that the pet is currently interacting with (e.g. a treasure chest or switch)
|
||||
*/
|
||||
PetInteractType type = PetInteractType::none;
|
||||
|
||||
/**
|
||||
* The interaction ability
|
||||
*/
|
||||
ePetAbilityType ability = ePetAbilityType::Invalid;
|
||||
|
||||
/**
|
||||
* The ID of the object that the pet is currently interacting with (e.g. a treasure chest or switch)
|
||||
*/
|
||||
LWOOBJID obj = LWOOBJID_EMPTY;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pet interaction info
|
||||
*/
|
||||
Interaction m_Interaction{};
|
||||
|
||||
/**
|
||||
* Cache of all the pets that are currently spawned, indexed by tamer
|
||||
*/
|
||||
@ -488,7 +435,7 @@ private:
|
||||
/**
|
||||
* Cache of all the minigames and their information from the database
|
||||
*/
|
||||
static std::unordered_map<LOT, PetComponent::PetPuzzleData> buildCache;
|
||||
static std::unordered_map<LOT, PetComponent::PuzzleData> buildCache;
|
||||
|
||||
/**
|
||||
* Flags that indicate that a player has tamed a pet, indexed by the LOT of the pet
|
||||
@ -508,32 +455,22 @@ private:
|
||||
/**
|
||||
* The ID of the model that was built to complete the taming minigame for this pet
|
||||
*/
|
||||
LWOOBJID m_ModelId;
|
||||
|
||||
/**
|
||||
* The ID of the object that the pet is currently interacting with (e.g. a treasure chest or switch)
|
||||
*/
|
||||
LWOOBJID m_Interaction;
|
||||
|
||||
/**
|
||||
* The type of object that the pet is currently interacting with (e.g. a treasure chest or switch)
|
||||
*/
|
||||
PetInteractType m_InteractType;
|
||||
LWOOBJID m_ModelId = LWOOBJID_EMPTY;
|
||||
|
||||
/**
|
||||
* The ID of the entity that owns this pet
|
||||
*/
|
||||
LWOOBJID m_Owner;
|
||||
LWOOBJID m_Owner = LWOOBJID_EMPTY;
|
||||
|
||||
/**
|
||||
* The ID of the entity that is currently taming this pet
|
||||
*/
|
||||
LWOOBJID m_Tamer;
|
||||
LWOOBJID m_Tamer = LWOOBJID_EMPTY;
|
||||
|
||||
/**
|
||||
* The ID under which this pet is stored in the database (if it's tamed)
|
||||
*/
|
||||
LWOOBJID m_DatabaseId;
|
||||
LWOOBJID m_DatabaseId = LWOOBJID_EMPTY;
|
||||
|
||||
/**
|
||||
* The ID of the item from which this pet was created
|
||||
@ -543,7 +480,7 @@ private:
|
||||
/**
|
||||
* The moderation status for the name of this pet
|
||||
*/
|
||||
uint32_t m_ModerationStatus;
|
||||
uint32_t m_ModerationStatus = 0;
|
||||
|
||||
/**
|
||||
* The name of this pet
|
||||
@ -558,32 +495,27 @@ private:
|
||||
/**
|
||||
* The current flags of the pet (e.g. tamable, tamed, etc).
|
||||
*/
|
||||
PetFlag m_Flags;
|
||||
Flag<PetFlag> m_Flags;
|
||||
|
||||
/**
|
||||
* The current state of the pet AI
|
||||
*/
|
||||
PetAiState m_State;
|
||||
|
||||
/**
|
||||
* A currently active ability, mostly unused
|
||||
*/
|
||||
ePetAbilityType m_Ability;
|
||||
|
||||
/**
|
||||
* The time an entity has left to complete the minigame
|
||||
*/
|
||||
float m_Timer;
|
||||
float m_Timer = 0;
|
||||
|
||||
/**
|
||||
* A timer that tracks how long a tamed pet has been to far away from its owner, triggering a teleport after timeout
|
||||
*/
|
||||
float m_TimerAway;
|
||||
float m_TimerAway = 0;
|
||||
|
||||
/**
|
||||
* A timer that tracks how long until a tamed pet will bounce again when standing over a treasure dig site
|
||||
*/
|
||||
float m_TimerBounce;
|
||||
float m_TimerBounce = 0;
|
||||
|
||||
/**
|
||||
* Boolean that sets if a pet is ready to interact with an object
|
||||
@ -608,7 +540,7 @@ private:
|
||||
/**
|
||||
* Preconditions that need to be met before an entity can tame this pet
|
||||
*/
|
||||
PreconditionExpression* m_Preconditions;
|
||||
std::optional<PreconditionExpression> m_Preconditions;
|
||||
|
||||
/**
|
||||
* Pet information loaded from the CDClientDatabase
|
||||
|
@ -77,10 +77,10 @@ void DamagingPets::MakeUntamable(Entity* self) {
|
||||
auto* const petComponent = self->GetComponent<PetComponent>();
|
||||
|
||||
// If the pet is currently not being tamed, make it hostile
|
||||
if (petComponent != nullptr && !petComponent->HasFlag(PetFlag::NOT_WAITING)) {
|
||||
if (petComponent != nullptr && !petComponent->m_Flags.Has(PetFlag::NOT_WAITING)) {
|
||||
self->SetNetworkVar<bool>(u"bIAmTamable", false);
|
||||
self->SetVar<bool>(u"IsEvil", true);
|
||||
petComponent->SetFlag(PetFlag::IDLE);
|
||||
petComponent->m_Flags.Set(PetFlag::IDLE);
|
||||
|
||||
auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>();
|
||||
if (combatAIComponent != nullptr) {
|
||||
@ -110,7 +110,7 @@ void DamagingPets::ClearEffects(Entity* self) {
|
||||
|
||||
auto* petComponent = self->GetComponent<PetComponent>();
|
||||
if (petComponent != nullptr) {
|
||||
petComponent->SetFlag(PetFlag::TAMEABLE, PetFlag::UNKNOWN2);
|
||||
petComponent->m_Flags.Set(PetFlag::TAMEABLE, PetFlag::UNKNOWN2);
|
||||
}
|
||||
|
||||
auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>();
|
||||
|
@ -1,6 +1,7 @@
|
||||
set(DCOMMONTEST_SOURCES
|
||||
"AMFDeserializeTests.cpp"
|
||||
"Amf3Tests.cpp"
|
||||
"FlagTests.cpp"
|
||||
"ToUnderlyingTests.cpp"
|
||||
"HeaderSkipTest.cpp"
|
||||
"TestCDFeatureGatingTable.cpp"
|
||||
|
67
tests/dCommonTests/FlagTests.cpp
Normal file
67
tests/dCommonTests/FlagTests.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "Flag.h"
|
||||
|
||||
enum class TestFlag : uint8_t {
|
||||
FLAG0,
|
||||
FLAG1,
|
||||
FLAG2,
|
||||
FLAG3,
|
||||
FLAG4
|
||||
};
|
||||
|
||||
/**
|
||||
* Test bitset flags
|
||||
*/
|
||||
TEST(FlagTests, FlagMethodTest) {
|
||||
using enum TestFlag;
|
||||
|
||||
auto flag = Flag<TestFlag>{};
|
||||
|
||||
// Test setting and reading single flags, exclusively
|
||||
flag.Reset(FLAG0);
|
||||
ASSERT_TRUE(flag.HasOnly(FLAG0));
|
||||
flag.Reset(FLAG2);
|
||||
ASSERT_TRUE(flag.HasOnly(FLAG2));
|
||||
ASSERT_FALSE(flag.HasOnly(FLAG1));
|
||||
|
||||
// Test setting and reading multiple flags, exclusively
|
||||
flag.Reset(FLAG3, FLAG1);
|
||||
ASSERT_FALSE(flag.Has(FLAG2));
|
||||
ASSERT_TRUE(flag.Has(FLAG3));
|
||||
ASSERT_TRUE(flag.Has(FLAG1));
|
||||
ASSERT_TRUE(flag.Has(FLAG3, FLAG1));
|
||||
ASSERT_FALSE(flag.HasOnly(FLAG3));
|
||||
ASSERT_FALSE(flag.HasOnly(FLAG1));
|
||||
ASSERT_TRUE(flag.HasOnly(FLAG3, FLAG1));
|
||||
|
||||
// Test flags are being properly reset for next batch of tests
|
||||
flag.Reset(FLAG0);
|
||||
ASSERT_TRUE(flag.Has(FLAG0));
|
||||
ASSERT_TRUE(flag.HasOnly(FLAG0));
|
||||
ASSERT_FALSE(flag.Has(FLAG3));
|
||||
ASSERT_FALSE(flag.Has(FLAG3, FLAG1, FLAG2));
|
||||
|
||||
// Test setting and reading single flags, non-exclusively
|
||||
flag.Set(FLAG3);
|
||||
ASSERT_TRUE(flag.Has(FLAG3));
|
||||
ASSERT_FALSE(flag.Has(FLAG1));
|
||||
|
||||
// Test setting and reading multiple flags, non-exclusively
|
||||
flag.Set(FLAG2, FLAG4);
|
||||
ASSERT_TRUE(flag.Has(FLAG2, FLAG4));
|
||||
ASSERT_TRUE(flag.Has(FLAG3));
|
||||
ASSERT_FALSE(flag.Has(FLAG3, FLAG1));
|
||||
ASSERT_TRUE(flag.Has(FLAG3, FLAG2, FLAG4));
|
||||
ASSERT_FALSE(flag.Has(FLAG1));
|
||||
ASSERT_FALSE(flag.Has(FLAG1, FLAG3, FLAG2, FLAG4));
|
||||
|
||||
// Test unsetting and reading multiple flags, non-exclusively
|
||||
flag.Unset(FLAG3, FLAG1);
|
||||
ASSERT_FALSE(flag.Has(FLAG3, FLAG1));
|
||||
ASSERT_FALSE(flag.Has(FLAG3));
|
||||
ASSERT_TRUE(flag.Has(FLAG2, FLAG4));
|
||||
ASSERT_FALSE(flag.Has(FLAG3, FLAG2, FLAG4));
|
||||
ASSERT_FALSE(flag.Has(FLAG1));
|
||||
ASSERT_FALSE(flag.Has(FLAG1, FLAG3, FLAG2, FLAG4));
|
||||
}
|
||||
|
@ -31,6 +31,60 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test bitset pet flags
|
||||
*/
|
||||
TEST_F(PetTest, PetComponentFlagTest) {
|
||||
using enum PetFlag;
|
||||
|
||||
// Test setting and reading single flags, exclusively
|
||||
petComponent->m_Flags.Reset(NONE);
|
||||
ASSERT_TRUE(petComponent->m_Flags.HasOnly(NONE));
|
||||
petComponent->m_Flags.Reset(TAMEABLE);
|
||||
ASSERT_TRUE(petComponent->m_Flags.HasOnly(TAMEABLE));
|
||||
ASSERT_FALSE(petComponent->m_Flags.HasOnly(SPAWNING));
|
||||
|
||||
// Test setting and reading multiple flags, exclusively
|
||||
petComponent->m_Flags.Reset(NOT_WAITING, SPAWNING);
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(TAMEABLE));
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(NOT_WAITING));
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(SPAWNING));
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(NOT_WAITING, SPAWNING));
|
||||
ASSERT_FALSE(petComponent->m_Flags.HasOnly(NOT_WAITING));
|
||||
ASSERT_FALSE(petComponent->m_Flags.HasOnly(SPAWNING));
|
||||
ASSERT_TRUE(petComponent->m_Flags.HasOnly(NOT_WAITING, SPAWNING));
|
||||
|
||||
// Test flags are being properly reset for next batch of tests
|
||||
petComponent->m_Flags.Reset(NONE);
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(NONE));
|
||||
ASSERT_TRUE(petComponent->m_Flags.HasOnly(NONE));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(NOT_WAITING));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(NOT_WAITING, SPAWNING, TAMEABLE));
|
||||
|
||||
// Test setting and reading single flags, non-exclusively
|
||||
petComponent->m_Flags.Set(NOT_WAITING);
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(NOT_WAITING));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(SPAWNING));
|
||||
|
||||
// Test setting and reading multiple flags, non-exclusively
|
||||
petComponent->m_Flags.Set(TAMEABLE, BEING_TAMED);
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(TAMEABLE, BEING_TAMED));
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(NOT_WAITING));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(NOT_WAITING, SPAWNING));
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(NOT_WAITING, TAMEABLE, BEING_TAMED));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(SPAWNING));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(SPAWNING, NOT_WAITING, TAMEABLE, BEING_TAMED));
|
||||
|
||||
// Test unsetting and reading multiple flags, non-exclusively
|
||||
petComponent->m_Flags.Unset(NOT_WAITING, SPAWNING);
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(NOT_WAITING, SPAWNING));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(NOT_WAITING));
|
||||
ASSERT_TRUE(petComponent->m_Flags.Has(TAMEABLE, BEING_TAMED));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(NOT_WAITING, TAMEABLE, BEING_TAMED));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(SPAWNING));
|
||||
ASSERT_FALSE(petComponent->m_Flags.Has(SPAWNING, NOT_WAITING, TAMEABLE, BEING_TAMED));
|
||||
}
|
||||
|
||||
TEST_F(PetTest, PlacementNewAddComponentTest) {
|
||||
using enum PetFlag;
|
||||
|
||||
@ -41,64 +95,9 @@ TEST_F(PetTest, PlacementNewAddComponentTest) {
|
||||
|
||||
// Test getting initial status
|
||||
ASSERT_EQ(petComponent->GetParent()->GetObjectID(), 15);
|
||||
ASSERT_TRUE(petComponent->HasFlag(NONE));
|
||||
ASSERT_EQ(petComponent->GetPetAiState(), PetAiState::spawn);
|
||||
ASSERT_EQ(petComponent->GetAbility(), ePetAbilityType::Invalid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
petComponent->SetOnlyFlag(TAMEABLE);
|
||||
ASSERT_TRUE(petComponent->HasOnlyFlag(TAMEABLE));
|
||||
ASSERT_FALSE(petComponent->HasOnlyFlag(SPAWNING));
|
||||
|
||||
// Test setting and reading multiple flags, exclusively
|
||||
petComponent->SetOnlyFlag(NOT_WAITING, SPAWNING);
|
||||
ASSERT_FALSE(petComponent->HasFlag(TAMEABLE));
|
||||
ASSERT_TRUE(petComponent->HasFlag(NOT_WAITING));
|
||||
ASSERT_TRUE(petComponent->HasFlag(SPAWNING));
|
||||
ASSERT_TRUE(petComponent->HasFlag(NOT_WAITING, SPAWNING));
|
||||
ASSERT_FALSE(petComponent->HasOnlyFlag(NOT_WAITING));
|
||||
ASSERT_FALSE(petComponent->HasOnlyFlag(SPAWNING));
|
||||
ASSERT_TRUE(petComponent->HasOnlyFlag(NOT_WAITING, SPAWNING));
|
||||
|
||||
// Test flags are being properly reset for next batch of tests
|
||||
petComponent->SetOnlyFlag(NONE);
|
||||
ASSERT_TRUE(petComponent->HasFlag(NONE));
|
||||
ASSERT_TRUE(petComponent->HasOnlyFlag(NONE));
|
||||
ASSERT_FALSE(petComponent->HasFlag(NOT_WAITING));
|
||||
ASSERT_FALSE(petComponent->HasFlag(NOT_WAITING, SPAWNING, TAMEABLE));
|
||||
|
||||
// Test setting and reading single flags, non-exclusively
|
||||
petComponent->SetFlag(NOT_WAITING);
|
||||
ASSERT_TRUE(petComponent->HasFlag(NOT_WAITING));
|
||||
ASSERT_FALSE(petComponent->HasFlag(SPAWNING));
|
||||
|
||||
// Test setting and reading multiple flags, non-exclusively
|
||||
petComponent->SetFlag(TAMEABLE, BEING_TAMED);
|
||||
ASSERT_TRUE(petComponent->HasFlag(TAMEABLE, BEING_TAMED));
|
||||
ASSERT_TRUE(petComponent->HasFlag(NOT_WAITING));
|
||||
ASSERT_FALSE(petComponent->HasFlag(NOT_WAITING, SPAWNING));
|
||||
ASSERT_TRUE(petComponent->HasFlag(NOT_WAITING, TAMEABLE, BEING_TAMED));
|
||||
ASSERT_FALSE(petComponent->HasFlag(SPAWNING));
|
||||
ASSERT_FALSE(petComponent->HasFlag(SPAWNING, NOT_WAITING, TAMEABLE, BEING_TAMED));
|
||||
|
||||
// Test unsetting and reading multiple flags, non-exclusively
|
||||
petComponent->UnsetFlag(NOT_WAITING, SPAWNING);
|
||||
ASSERT_FALSE(petComponent->HasFlag(NOT_WAITING, SPAWNING));
|
||||
ASSERT_FALSE(petComponent->HasFlag(NOT_WAITING));
|
||||
ASSERT_TRUE(petComponent->HasFlag(TAMEABLE, BEING_TAMED));
|
||||
ASSERT_FALSE(petComponent->HasFlag(NOT_WAITING, TAMEABLE, BEING_TAMED));
|
||||
ASSERT_FALSE(petComponent->HasFlag(SPAWNING));
|
||||
ASSERT_FALSE(petComponent->HasFlag(SPAWNING, NOT_WAITING, TAMEABLE, BEING_TAMED));
|
||||
}
|
||||
|
||||
TEST_F(PetTest, PetAiState) {
|
||||
const auto initialState = petComponent->GetPetAiState();
|
||||
@ -126,9 +125,6 @@ TEST_F(PetTest, PetUse) {
|
||||
|
||||
// Test bouncer logic
|
||||
ASSERT_FALSE(petComponent->IsHandlingInteraction());
|
||||
petComponent->SetAbility(ePetAbilityType::JumpOnObject);
|
||||
ASSERT_EQ(petComponent->GetAbility(), ePetAbilityType::JumpOnObject);
|
||||
petComponent->SetInteractType(PetInteractType::bouncer);
|
||||
petComponent->OnUse(baseEntity);
|
||||
|
||||
// need to add a destroyable component to the test entity and test the imagination drain
|
||||
|
Loading…
Reference in New Issue
Block a user