Files
DarkflameServer/dGame/dComponents/PetComponent.h
Aaron Kimbrell 260e6cb1b1 refactor(entity): each component type has an allocator, as the client
DoObjectComponentLoad walks the client's load order and calls the type's
allocator from a table, like ObjectLoader2, instead of one 76-case switch.
Components with rules of their own have a static Allocator (the client's
LWOxComponent::Allocator); the rest share a registry allocator. The load
state moves to ObjectLoadState.h so the allocators can take it.

Construction bytes are identical for all 15,962 LOTs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 08:11:58 -05:00

426 lines
12 KiB
C++

#ifndef PETCOMPONENT_H
#define PETCOMPONENT_H
#include "Entity.h"
#include "MovementAIComponent.h"
#include "Component.h"
#include "Preconditions.h"
#include "ePetAbilityType.h"
#include "eReplicaComponentType.h"
#include "CDPetComponentTable.h"
#include "eHelpType.h"
struct ObjectLoadState;
/**
* 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
{
public:
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::PET;
// The client's allocator for this type (ObjectLoader2::DoObjectComponentLoad calls it in load order)
static void Allocator(Entity& entity, ObjectLoadState& state);
// Bits of the serialized pet status. State number N is bit 1 << (N - 1) (the client's StateNumToIndex,
// 0x00bd19b0); the meanings are what the live server sent (2014 packet captures) and what the client does with them.
// State 8: a pet constructed with it plays its spawnAnim (LWOPetComponent::Deserialize, 0x00cd1270). Live
// constructed summoned pets with 0x84 and cleared this bit once the spawn animation was over.
static constexpr uint32_t PET_STATE_SPAWNING = 1 << 7;
// State 6: the pet is at the object of its ability (a pet switch or a dig) and waits for its owner to use it.
static constexpr uint32_t PET_STATE_AT_ABILITY_OBJECT = 1 << 5;
// State 9: the pet is on its way to, or waiting at, the object of its ability (the client's IsPetUsingAbility
// checks it).
static constexpr uint32_t PET_STATE_USING_ABILITY = 1 << 8;
// State 11: the pet is on its way to the object of its ability.
static constexpr uint32_t PET_STATE_GOING_TO_ABILITY_OBJECT = 1 << 10;
explicit PetComponent(Entity* parentEntity, const int32_t componentID);
void LoadDataFromTemplate() override;
void LoadConfigData() override;
~PetComponent() override;
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
void Run(float deltaTime) override;
/**
* Handles a RequestUse from another entity, initializing the pet taming minigame if this pet is untamed.
* @param originator the entity that triggered the event
*/
bool OnRequestUse(GameMessages::RequestUseEvent& event);
/**
* Attempts to complete the pet minigame by passing a list of bricks to build the minigame model.
* @param bricks the bricks to try to complete the minigame with
* @param clientFailed unused
*/
void TryBuild(uint32_t numBricks, bool clientFailed);
/**
* Handles a notification from the client regarding the completion of the pet minigame, adding the pet to their
* inventory.
* @param position the position to spawn the completed model at
*/
void NotifyTamingBuildSuccess(NiPoint3 position);
/**
* Handles the notification of the client to set the name of the pet (indicating that minigame was completed
* successfully).
* @param name the name of the pet to set
*/
void RequestSetPetName(std::u16string name);
/**
* Handles a notification of the client that the taming entity is leaving the minigame, either voluntary or because
* time ran out.
* @param voluntaryExit whether the client voluntarily exited the minigame
*/
void ClientExitTamingMinigame(bool voluntaryExit);
/**
* Starts the internal timer for the build limit for building the minigame model
*/
void StartTimer();
/**
* Notifies the client that they failed the minigame because time ran out
*/
void ClientFailTamingMinigame();
/**
* Makes the pet wander around
*/
void Wander();
/**
* Spawns a pet from an item in the inventory of an owner
* @param item the item to create the pet from
* @param registerPet notifies the client that the pet was spawned, not necessary if this pet is being tamed
*/
void Activate(Item* item, bool registerPet = true, bool fromTaming = false);
/**
* Despawns the pet
*/
void Deactivate();
/**
* Removes the pet from the inventory
*/
void Release();
/**
* Commands the pet to do an action, actions are still a relative mystery, next to playing emotes
* @param position a position to execute the command at, currently unused
* @param source the source object that triggered the command
* @param commandType the type of the command (see function body for types)
* @param typeId extra information about the command, e.g. the emote to play
* @param overrideObey unused
*/
void Command(const NiPoint3& position, const LWOOBJID source, const int32_t commandType, const int32_t typeId, const bool overrideObey);
/**
* Returns the ID of the owner of this pet (if any)
* @return the ID of the owner of this pet
*/
LWOOBJID GetOwnerId() const;
/**
* Returns the entity that owns this pet (if any)
* @return the entity that owns this pet
*/
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;
// A moderator approved or rejected this pet's name (from the dashboard); updates it live for everyone
void ApplyNameModeration(bool approved);
/**
* 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);
/**
* 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);
/**
* Sets preconditions for the pet that need to be met before it can be tamed
* @param conditions the preconditions to set
*/
void SetPreconditions(const std::string& conditions);
/**
* Returns the entity that this component belongs to
* @return the entity that this component belongs to
*/
Entity* GetParentEntity() const;
/**
* Sets the name of the pet to be moderated
* @param petName the name of the pet to set
* @param owner the character that owns the pet, saved with the name
*/
void SetPetNameForModeration(const std::string& petName, const LWOOBJID owner);
/**
* Loads the pet name up for moderation along with the moderation status from the database and sets them for this
* pet.
*/
void LoadPetNameFromModeration();
/**
* Returns the component of the pet some entity is currently taming (if any)
* @param tamer the entity that's currently taming
* @return the pet component of the entity that's being tamed
*/
static PetComponent* GetTamingPet(LWOOBJID tamer);
/**
* Returns the pet that's currently spawned for some entity (if any)
* @param owner the owner of the pet that's spawned
* @return the pet component of the entity that was spawned by the owner
*/
static PetComponent* GetActivePet(LWOOBJID owner);
/**
* Adds the timer to the owner of this pet to drain imagination at the rate
* specified by the parameter imaginationDrainRate
*
* @param item The item that represents this pet in the inventory.
*/
void AddDrainImaginationTimer(bool fromTaming = false);
private:
/**
* Sets the object the pet goes to use its ability on (a pet switch or a dig), or none. The pet first goes to it; once it is there
* its owner gets the pet's action button, which uses the ability.
* @param object the object, nullptr for none
* @param ability the ability the object is for
* @param atObject whether the pet has reached the object
*/
void SetAbilityObject(Entity* object, ePetAbilityType ability, bool atObject);
/**
* Uses the ability the owner's action button shows (the owner used the pet: SHIFT or the pet menu)
*/
void UseAbility();
/**
* Takes the action button away from the owner, if they have it
*/
void HideAbilityButton();
/**
* Shows the owner a one-time tutorial tooltip
* @param helpId the tooltip
*/
void SendHelp(eHelpType helpId) const;
/**
* Returns the imagination using an ability costs (PetAbilities.ImaginationCost)
*/
static int32_t GetAbilityImaginationCost(ePetAbilityType ability);
/**
* Information for the minigame to be completed
*/
struct PetPuzzleData
{
/**
* The LOT of the object that is to be created
*/
LOT puzzleModelLot;
/**
* That file that contains the bricks required to build the model
*/
std::string buildFile;
/**
* The time limit to complete the build
*/
int32_t timeLimit;
/**
* The imagination cost for the tamer to start the minigame
*/
int32_t imaginationCost;
/**
* The number of pieces required to complete the minigame
*/
int32_t numValidPieces;
};
/**
* Cache of all the pets that are currently spawned, indexed by tamer
*/
static std::unordered_map<LWOOBJID, LWOOBJID> activePets;
/**
* Cache of all the pets that are currently being tamed, indexed by tamer
*/
static std::unordered_map<LWOOBJID, LWOOBJID> currentActivities;
/**
* 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 ID of the entity that owns this pet
*/
LWOOBJID m_Owner;
/**
* The ID of the entity that is currently taming this pet
*/
LWOOBJID m_Tamer;
/**
* The ID under which this pet is stored in the database (if it's tamed)
*/
LWOOBJID m_DatabaseId;
/**
* The ID of the item from which this pet was created
*/
LWOOBJID m_ItemId;
/**
* The moderation status for the name of this pet
*/
uint32_t m_ModerationStatus;
/**
* The name of this pet
*/
std::string m_Name;
/**
* The name of the owner of this pet
*/
std::string m_OwnerName;
/**
* The current state of the pet (e.g. tamable, tamed, etc).
*/
uint32_t m_Status;
/**
* A currently active ability, mostly unused
*/
ePetAbilityType m_Ability;
/**
* The time an entity has left to complete the minigame
*/
float m_Timer;
/**
* 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;
/**
* Timer that tracks how long a pet has been digging up some treasure, required to spawn the treasure contents
* on time
*/
float m_TreasureTime;
/**
* The position that this pet was spawned at
*/
NiPoint3 m_StartPosition;
/**
* The rotation that this pet was spawned with
*/
NiQuaternion m_StartRotation{ QuatUtils::IDENTITY };
/**
* The movement AI component that is related to this pet, required to move it around
*/
MovementAIComponent* m_MovementAI;
/**
* Preconditions that need to be met before an entity can tame this pet
*/
std::optional<PreconditionExpression> m_Preconditions{};
/**
* Pet information loaded from the CDClientDatabase
*/
CDPetComponent m_PetInfo;
/**
* Set once the pet has been sent back to the backpack; it is removed after its despawn effect has played
*/
bool m_Despawning{ false };
/**
* The object the pet goes to use its ability on (a pet switch or a dig), if any. Live did not serialize it as the interaction.
*/
LWOOBJID m_AbilityObject{ LWOOBJID_EMPTY };
/**
* Whether the owner has the pet's action button
*/
bool m_AbilityButtonShown{ false };
};
#endif // !PETCOMPONENT_H