Re-implemented treasure dig handling

This commit is contained in:
jadebenn 2023-12-13 00:14:53 -06:00
parent 5b738dfc58
commit a99f7a7fc1
3 changed files with 144 additions and 124 deletions

View File

@ -80,17 +80,17 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(pare
m_ModelId = LWOOBJID_EMPTY;
m_Timer = 0;
m_TimerAway = 0;
m_TimerBounce = 0;
m_DatabaseId = LWOOBJID_EMPTY;
m_Status = PetStatus::TAMEABLE; // Tameable
m_Ability = PetAbilityType::Invalid;
m_StartPosition = m_Parent->GetPosition(); //NiPoint3::ZERO;
m_MovementAI = nullptr;
m_TresureTime = 0;
m_Preconditions = nullptr;
m_ReadyToDig = false;
m_ReadyToInteract = false;
SetPetAiState(PetAiState::spawn);
m_FollowRadius = 5.0f;
//m_FollowRadius = 8.0f;
std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parent->GetVar<std::u16string>(u"CheckPrecondition"));
@ -160,7 +160,6 @@ void PetComponent::SetPetAiState(PetAiState newState) {
if (newState == GetPetAiState()) return;
this->m_State = newState;
LOG_DEBUG("Set pet AI state!");
//Game::entityManager->SerializeEntity(m_Parent); // Do we need to serialize entity?
}
void PetComponent::OnUse(Entity* originator) {
@ -341,16 +340,24 @@ void PetComponent::Update(float deltaTime) {
return;
}*/
if (m_StartPosition == NiPoint3::ZERO) {
m_StartPosition = m_Parent->GetPosition();
}
// Update timers
m_TimerBounce -= deltaTime;
// Update timer
if (m_Timer > 0) {
m_Timer -= deltaTime;
return;
}
// Remove "left behind" pets
if (m_Owner != LWOOBJID_EMPTY) {
Entity* owner = GetOwner();
if (!owner) {
m_Parent->Kill();
return;
}
}
// Handle pet AI states
switch (m_State) {
case PetAiState::spawn:
LOG_DEBUG("Pet spawn beginning!");
@ -468,7 +475,7 @@ skipTresure:
m_Timer = 1;*/
}
void PetComponent::UpdateUnowned(float deltaTime) { //CURRENTLY UNUSED
void PetComponent::UpdateUnowned(float deltaTime) { //TODO: CURRENTLY UNUSED
if (m_Tamer != LWOOBJID_EMPTY) {
if (m_Timer > 0) {
m_Timer -= deltaTime;
@ -491,7 +498,7 @@ void PetComponent::UpdateUnowned(float deltaTime) { //CURRENTLY UNUSED
}
}
void PetComponent::SetIsReadyToDig(bool isReady) {
/*void PetComponent::SetIsReadyToDig(bool isReady) {
if (isReady) {
LOG("Dig state reached!");
//m_Interaction = closestTresure->GetObjectID();
@ -508,33 +515,7 @@ void PetComponent::SetIsReadyToDig(bool isReady) {
m_ReadyToDig = false;
Game::entityManager->SerializeEntity(m_Parent);
}
}
void PetComponent::InteractDig(float deltaTime) {
LOG("Pet digging!");
auto* tresure = Game::entityManager->GetEntity(m_Interaction);
if (tresure == nullptr) {
m_TresureTime = 0.0f;
return;
}
m_TresureTime -= deltaTime;
m_MovementAI->Stop();
if (m_TresureTime <= 0.0f) {
m_Parent->SetOwnerOverride(m_Owner);
tresure->Smash(m_Parent->GetObjectID());
LOG("Pet dig completed!");
m_Interaction = LWOOBJID_EMPTY;
m_TresureTime = 0.0f;
SetIsReadyToDig(false);
}
}
}*/
void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) {
if (m_Tamer == LWOOBJID_EMPTY) return;
@ -856,9 +837,9 @@ void PetComponent::ClientFailTamingMinigame() {
}
void PetComponent::Wander() {
m_MovementAI = m_Parent->GetComponent<MovementAIComponent>();
//m_MovementAI = m_Parent->GetComponent<MovementAIComponent>();
if (m_MovementAI == nullptr || !m_MovementAI->AtFinalWaypoint()) return;
if (/*m_MovementAI == nullptr ||*/ !m_MovementAI->AtFinalWaypoint()) return;
m_MovementAI->SetHaltDistance(0);
@ -889,48 +870,48 @@ void PetComponent::Wander() {
return;
}
m_MovementAI->SetMaxSpeed(info.wanderSpeed);
m_MovementAI->SetMaxSpeed(m_SprintSpeed); //info.wanderSpeed);
m_MovementAI->SetDestination(destination);
m_Timer += (m_MovementAI->GetParent()->GetPosition().x - destination.x) / info.wanderSpeed;
m_Timer += (m_MovementAI->GetParent()->GetPosition().x - destination.x) / m_SprintSpeed; //info.wanderSpeed;
}
void PetComponent::OnSpawn() {
m_MovementAI = m_Parent->GetComponent<MovementAIComponent>();
if (!m_MovementAI) return;
//if (!m_MovementAI) return;
if (m_StartPosition == NiPoint3::ZERO) {
m_StartPosition = m_Parent->GetPosition();
}
LOG_DEBUG("Pet spawn complete, setting AI state.");
if (m_Owner != LWOOBJID_EMPTY) SetPetAiState(PetAiState::follow);
else SetPetAiState(PetAiState::idle);
if (m_Owner != LWOOBJID_EMPTY) {
m_Parent->SetOwnerOverride(m_Owner);
m_MovementAI->SetMaxSpeed(m_SprintSpeed);
m_MovementAI->SetHaltDistance(m_FollowRadius);
SetStatus(PetStatus::NONE);
SetPetAiState(PetAiState::follow);
}
else {
SetPetAiState(PetAiState::idle);
}
}
void PetComponent::OnFollow() {
m_MovementAI->SetHaltDistance(5.0f); // TODO: Remove this magic number
Entity* owner = GetOwner();
NiPoint3 ownerPos = owner->GetPosition();
NiPoint3 currentPos = m_MovementAI->GetParent()->GetPosition();
if (!owner) return;
const NiPoint3 ownerPos = owner->GetPosition();
// If the player's position is within range, stop moving
if (Vector3::DistanceSquared(currentPos, ownerPos) <= m_FollowRadius * m_FollowRadius) {
m_MovementAI->Stop();
}
else { // Chase the player's new position
m_MovementAI->SetMaxSpeed(m_SprintSpeed);
m_MovementAI->SetDestination(ownerPos);
LOG_DEBUG("New pet destination: %f %f %f", ownerPos.x, ownerPos.y, ownerPos.z);
//SetPetAiState(PetAiState::tether);
}
//TEST SECTION
// Find interactions
SwitchComponent* closestSwitch = SwitchComponent::GetClosestSwitch(ownerPos);
if (closestSwitch != nullptr && !closestSwitch->GetActive()) {
NiPoint3 switchPos = closestSwitch->GetParentEntity()->GetPosition();
const NiPoint3 switchPos = closestSwitch->GetParentEntity()->GetPosition();
const LWOOBJID switchID = closestSwitch->GetParentEntity()->GetObjectID();
const float distance = Vector3::DistanceSquared(ownerPos, switchPos);
if (distance < 20 * 20) {
StartInteract(switchPos, PetInteractType::bouncer);
if (distance < 16 * 16) {
StartInteract(switchPos, PetInteractType::bouncer, switchID);
return;
}
}
@ -942,22 +923,36 @@ void PetComponent::OnFollow() {
Entity* closestTreasure = PetDigServer::GetClosestTresure(ownerPos);
if (closestTreasure != nullptr && digUnlocked) {
NiPoint3 treasurePos = closestTreasure->GetPosition();
const NiPoint3 treasurePos = closestTreasure->GetPosition();
const LWOOBJID treasureID = closestTreasure->GetObjectID();
const float distance = Vector3::DistanceSquared(ownerPos, treasurePos);
if (distance < 10 * 10) {
StartInteract(treasurePos, PetInteractType::treasure);
if (distance < 16 * 16) {
StartInteract(treasurePos, PetInteractType::treasure, treasureID);
return;
}
}
// Handle actual following logic
const NiPoint3 currentPos = m_MovementAI->GetParent()->GetPosition();
// If the player's position is within range, stop moving
if (Vector3::DistanceSquared(currentPos, ownerPos) <= m_FollowRadius * m_FollowRadius) {
m_MovementAI->Stop();
}
else { // Chase the player's new position
m_MovementAI->SetDestination(ownerPos);
LOG_DEBUG("New pet destination: %f %f %f", ownerPos.x, ownerPos.y, ownerPos.z);
}
m_Timer += 0.5f;
}
void PetComponent::OnInteract() {
LOG_DEBUG("Beginning interaction with object!");
Entity* owner = GetOwner();
if (!owner) return;
NiPoint3 ownerPos = GetOwner()->GetPosition();
NiPoint3 currentPos = m_MovementAI->GetParent()->GetPosition();
const NiPoint3 ownerPos = owner->GetPosition();
const NiPoint3 currentPos = m_MovementAI->GetParent()->GetPosition();
const float distanceFromOwner = Vector3::DistanceSquared(ownerPos, currentPos);
if (distanceFromOwner > 25 * 25) {
@ -968,11 +963,13 @@ void PetComponent::OnInteract() {
switch (GetInteractType()) {
case PetInteractType::bouncer:
StartInteractBouncer();
if (GetIsReadyToInteract()) LOG_DEBUG("Add the HandleInteractBouncer()!");
else SetupInteractBouncer();
break;
case PetInteractType::treasure:
StartInteractDig();
if (GetIsReadyToInteract()) HandleInteractTreasureDig();
else SetupInteractTreasureDig();
break;
default:
@ -983,11 +980,8 @@ void PetComponent::OnInteract() {
}
}
void PetComponent::OnTether() {
m_Timer += 0.5f;
}
void PetComponent::StartInteract(NiPoint3 position, PetInteractType interactType) {
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(PetAbilityType::GoToObject);
SetPetAiState(PetAiState::goToObj);
@ -999,30 +993,68 @@ void PetComponent::StartInteract(NiPoint3 position, PetInteractType interactType
}
void PetComponent::StopInteract() {
SetInteraction(LWOOBJID_EMPTY);
SetInteractType(PetInteractType::none);
SetAbility(PetAbilityType::Invalid);
SetPetAiState(PetAiState::follow);
SetStatus(PetStatus::NONE);
SetIsReadyToInteract(false);
m_MovementAI->SetMaxSpeed(m_SprintSpeed);
m_MovementAI->SetHaltDistance(m_FollowRadius);
LOG_DEBUG("Stopping interaction!");
Game::entityManager->SerializeEntity(m_Parent);
}
void PetComponent::StartInteractBouncer() {
SetAbility(PetAbilityType::JumpOnObject);
void PetComponent::SetupInteractBouncer() {
// THIS IS ALL BAD, BAD, BAD! FIX IT, ME! >:(
/*SetAbility(PetAbilityType::JumpOnObject);
NiPoint3 destination = m_MovementAI->GetDestination();
SwitchComponent* closestSwitch = SwitchComponent::GetClosestSwitch(destination);
m_Interaction = closestSwitch->GetParentEntity()->GetObjectID();
Game::entityManager->SerializeEntity(m_Parent);
closestSwitch->EntityEnter(m_Parent);
closestSwitch->EntityEnter(m_Parent);*/
}
void PetComponent::StartInteractDig() {
//m_InInteract = true;
//m_TresureTime = 2.0f; //TODO: Remove magic number
m_Interaction == LWOOBJID_EMPTY; //TODO: Make this not empty
Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, PetEmote::Bounce, true);\
m_Timer = 2.0f;
void PetComponent::SetupInteractTreasureDig() {
LOG_DEBUG("Setting up dig interaction!");
Entity* closestTreasure = Game::entityManager->GetEntity(GetInteraction());
if (!closestTreasure) return;
SetIsReadyToInteract(true);
SetStatus(PetStatus::IS_NOT_WAITING); // TODO: Double-check this is the right flag being set
Game::entityManager->SerializeEntity(m_Parent); // TODO: Double-check pet packet captures
m_Timer += 0.5f;
}
void PetComponent::StartInteractTreasureDig() {
SetAbility(PetAbilityType::DigAtPosition);
Game::entityManager->SerializeEntity(m_Parent);
Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, PetEmote::DigTreasure, true); // Plays 'dig' animation
m_Timer = 1.5f;
}
void PetComponent::HandleInteractTreasureDig() {
if (GetAbility() == PetAbilityType::DigAtPosition) {
auto* owner = GetOwner();
auto* treasure = Game::entityManager->GetEntity(GetInteraction());
if (!treasure) return;
treasure->Smash(m_Parent->GetObjectID());
LOG_DEBUG("Pet dig completed!");
StopInteract(); //TODO: This may not be totally consistent with live behavior, where the pet seems to stay near the dig and not immediately follow
m_Timer = 1.5f;
return;
}
if (m_TimerBounce <= 0.0f) {
Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, PetEmote::Bounce, true); // Plays 'bounce' animation
m_TimerBounce = 1.0f;
}
m_Timer += 0.5f;
}
void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
@ -1042,7 +1074,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
auto* owner = GetOwner();
if (owner == nullptr) return;
SetStatus(1);
SetStatus(PetStatus::PLAY_SPAWN_ANIM);
auto databaseData = inventoryComponent->GetDatabasePet(m_DatabaseId);
@ -1075,7 +1107,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
activePets[m_Owner] = m_Parent->GetObjectID();
m_Timer = 3;
//m_Timer = 3;
Game::entityManager->SerializeEntity(m_Parent);

View File

@ -32,6 +32,7 @@ enum class PetInteractType : uint8_t {
*/
enum PetStatus : uint32_t {
NONE,
//READY_TO_DIG,
BEING_TAMED = 0x10,
IS_NOT_WAITING = 0x20,
PLAY_SPAWN_ANIM = 0x80,
@ -148,15 +149,10 @@ public:
*/
void OnInteract();
/**
* Continues a step in the tether state, making the entity run towards its target
*/
void OnTether();
/**
* Start a pet interaction with an object at a given position
*/
void StartInteract(NiPoint3 position, PetInteractType interactType);
void StartInteract(const NiPoint3 position, const PetInteractType interactType, const LWOOBJID interactID);
/**
* Stop a pet interaction with an object
@ -268,42 +264,35 @@ public:
void SetPreconditions(std::string& conditions);
/**
* Sets if the pet is ready to dig
* @param isReady whether the pet is ready to dig (true) or not (false)
* 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 SetIsReadyToDig(bool isReady);
void SetIsReadyToInteract(bool isReady) { m_ReadyToInteract = isReady; };
/**
* @return is pet ready to dig
* @return is pet ready to interact with an object
*/
bool GetIsReadyToDig() { return m_ReadyToDig; };
bool GetIsReadyToInteract() { return m_ReadyToInteract; };
/**
* Start the pet bouncer interaction
* Set up the pet bouncer interaction
*/
void StartInteractBouncer();
void SetupInteractBouncer();
/**
* Start the treasure dig interaction
* Set up the treasure dig interaction
*/
void StartInteractDig();
void SetupInteractTreasureDig();
/**
* Handles the pet dig interaction
* @param deltaTime time elapsed
* Starts the pet treasure dig interaction
*/
void InteractDig(float deltaTime);
void StartInteractTreasureDig();
/**
* End the dig interaction
* Handles the pet treasure dig interaction
*/
void EndInteractDig();
/**
* Sets pet's treasure timer
* @param digTime float representing the treasure dig time in seconds
*/
void SetTreasureTime(float digTime) { m_TresureTime = digTime; };
void HandleInteractTreasureDig();
/**
* Returns the entity that this component belongs to
@ -479,15 +468,14 @@ private:
float m_TimerAway;
/**
* Timer that tracks how long a pet has been digging up some treasure, required to spawn the treasure contents
* on time
* A timer that tracks how long until a tamed pet will bounce again when standing over a treasure dig site
*/
float m_TresureTime;
float m_TimerBounce;
/**
* Boolean that sets if a pet is ready to dig and display the interact prompt
* Boolean that sets if a pet is ready to interact with an object
*/
bool m_ReadyToDig;
bool m_ReadyToInteract;
/**
* The position that this pet was spawned at
@ -497,7 +485,7 @@ private:
/**
* The halting radius of the pet while following a player
*/
float m_FollowRadius;
const float m_FollowRadius = 8.0f;
/**
* The movement AI component that is related to this pet, required to move it around

View File

@ -108,14 +108,14 @@ void PetDigServer::OnUse(Entity* self, Entity* user) {
auto* petComponent = PetComponent::GetActivePet(user->GetObjectID());
if (!petComponent) return;
if(petComponent->GetIsReadyToDig()) { // TODO: Add handling of the "first time" dig message
if(petComponent->GetIsReadyToInteract()) { // TODO: Add handling of the "first time" dig message
auto* destroyableComponent = user->GetComponent<DestroyableComponent>();
if (!destroyableComponent) return;
auto imagination = destroyableComponent->GetImagination();
if (imagination == 0) return; // TODO: Check if there was special behavior for this in the live game (PR_NEED_IMAGINATION)
petComponent->StartInteractDig();
petComponent->StartInteractTreasureDig();
imagination -= 1; // TODO: Get rid of this magic number
destroyableComponent->SetImagination(imagination);