2021-12-05 17:54:36 +00:00
# include "PetComponent.h"
# include "GameMessages.h"
# include "BrickDatabase.h"
# include "CDClientDatabase.h"
2024-04-24 15:09:15 +00:00
# include "CDTamingBuildPuzzleTable.h"
2021-12-05 17:54:36 +00:00
# include "ChatPackets.h"
# include "EntityManager.h"
# include "Character.h"
# include "CharacterComponent.h"
# include "InventoryComponent.h"
# include "Item.h"
# include "MissionComponent.h"
# include "SwitchComponent.h"
# include "DestroyableComponent.h"
# include "dpWorld.h"
# include "PetDigServer.h"
2024-01-05 12:31:22 +00:00
# include "ObjectIDManager.h"
2022-09-02 18:49:19 +00:00
# include "eUnequippableActiveType.h"
2023-05-02 22:39:21 +00:00
# include "eTerminateType.h"
# include "ePetTamingNotifyType.h"
# include "eUseItemResponse.h"
# include "ePlayerFlag.h"
2021-12-05 17:54:36 +00:00
# include "Game.h"
2022-06-18 07:03:27 +00:00
# include "dConfig.h"
2021-12-05 17:54:36 +00:00
# include "dChatFilter.h"
# include "Database.h"
2023-01-07 05:17:05 +00:00
# include "EntityInfo.h"
2023-01-22 23:38:47 +00:00
# include "eMissionTaskType.h"
2023-03-20 13:10:52 +00:00
# include "RenderComponent.h"
2023-04-25 18:17:40 +00:00
# include "eObjectBits.h"
2023-03-24 23:16:45 +00:00
# include "eGameMasterLevel.h"
2023-11-13 10:41:27 +00:00
# include "eMissionState.h"
2024-01-19 21:12:05 +00:00
# include "dNavMesh.h"
2024-05-22 01:01:44 +00:00
# include "eGameActivity.h"
# include "eStateChangeType.h"
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
std : : unordered_map < LWOOBJID , LWOOBJID > PetComponent : : currentActivities { } ;
std : : unordered_map < LWOOBJID , LWOOBJID > PetComponent : : activePets { } ;
2021-12-05 17:54:36 +00:00
/**
* 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 .
*/
2024-04-24 15:09:04 +00:00
const std : : map < LOT , int32_t > PetComponent : : petFlags {
2022-07-28 13:39:57 +00:00
{ 3050 , 801 } , // Elephant
{ 3054 , 803 } , // Cat
{ 3195 , 806 } , // Triceratops
{ 3254 , 807 } , // Terrier
{ 3261 , 811 } , // Skunk
{ 3672 , 813 } , // Bunny
{ 3994 , 814 } , // Crocodile
{ 5635 , 815 } , // Doberman
{ 5636 , 816 } , // Buffalo
{ 5637 , 818 } , // Robot Dog
{ 5639 , 819 } , // Red Dragon
{ 5640 , 820 } , // Tortoise
{ 5641 , 821 } , // Green Dragon
{ 5643 , 822 } , // Panda, see mission 786
{ 5642 , 823 } , // Mantis
{ 6720 , 824 } , // Warthog
{ 3520 , 825 } , // Lion, see mission 1318
{ 7638 , 826 } , // Goat
{ 7694 , 827 } , // Crab
{ 12294 , 829 } , // Reindeer
{ 12431 , 830 } , // Stegosaurus, see mission 1386
{ 12432 , 831 } , // Saber cat, see mission 1389
{ 12433 , 832 } , // Gryphon, see mission 1392
{ 12434 , 833 } , // Alien, see mission 1188
// 834: unknown?, see mission 506, 688
{ 16210 , 836 } , // Ninjago Earth Dragon, see mission 1836
{ 13067 , 838 } , // Skeleton dragon
2021-12-05 17:54:36 +00:00
} ;
2024-01-08 23:32:09 +00:00
PetComponent : : PetComponent ( Entity * parentEntity , uint32_t componentId ) : Component { parentEntity } {
2024-02-09 05:40:43 +00:00
m_PetInfo = CDClientManager : : GetTable < CDPetComponentTable > ( ) - > GetByID ( componentId ) ; // TODO: Make reference when safe
2022-07-28 13:39:57 +00:00
m_ComponentId = componentId ;
m_Interaction = LWOOBJID_EMPTY ;
m_Owner = LWOOBJID_EMPTY ;
m_ModerationStatus = 0 ;
m_Tamer = LWOOBJID_EMPTY ;
m_ModelId = LWOOBJID_EMPTY ;
m_Timer = 0 ;
m_TimerAway = 0 ;
m_DatabaseId = LWOOBJID_EMPTY ;
m_Status = 67108866 ; // Tamable
2024-01-08 23:32:09 +00:00
m_Ability = ePetAbilityType : : Invalid ;
2024-01-29 07:53:12 +00:00
m_StartPosition = NiPoint3Constant : : ZERO ;
2022-07-28 13:39:57 +00:00
m_MovementAI = nullptr ;
2024-11-18 02:48:48 +00:00
m_TreasureTime = 0 ;
2022-05-04 03:38:49 +00:00
2024-01-08 23:32:09 +00:00
std : : string checkPreconditions = GeneralUtils : : UTF16ToWTF8 ( parentEntity - > GetVar < std : : u16string > ( u " CheckPrecondition " ) ) ;
2022-05-04 03:38:49 +00:00
if ( ! checkPreconditions . empty ( ) ) {
SetPreconditions ( checkPreconditions ) ;
}
2021-12-05 17:54:36 +00:00
}
2024-02-27 07:25:44 +00:00
void PetComponent : : Serialize ( RakNet : : BitStream & outBitStream , bool bIsInitialUpdate ) {
2022-07-28 13:39:57 +00:00
const bool tamed = m_Owner ! = LWOOBJID_EMPTY ;
2021-12-05 17:54:36 +00:00
2024-02-27 07:25:44 +00:00
outBitStream . Write1 ( ) ; // Always serialize as dirty for now
2021-12-05 17:54:36 +00:00
2024-02-27 07:25:44 +00:00
outBitStream . Write < uint32_t > ( m_Status ) ;
outBitStream . Write ( tamed ? m_Ability : ePetAbilityType : : Invalid ) ; // Something with the overhead icon?
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
const bool interacting = m_Interaction ! = LWOOBJID_EMPTY ;
2022-07-25 02:26:51 +00:00
2024-02-27 07:25:44 +00:00
outBitStream . Write ( interacting ) ;
2022-07-28 13:39:57 +00:00
if ( interacting ) {
2024-02-27 07:25:44 +00:00
outBitStream . Write ( m_Interaction ) ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
2024-02-27 07:25:44 +00:00
outBitStream . Write ( tamed ) ;
2022-07-28 13:39:57 +00:00
if ( tamed ) {
2024-02-27 07:25:44 +00:00
outBitStream . Write ( m_Owner ) ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
2023-01-03 17:22:04 +00:00
if ( bIsInitialUpdate ) {
2024-02-27 07:25:44 +00:00
outBitStream . Write ( tamed ) ;
2023-01-03 17:22:04 +00:00
if ( tamed ) {
2024-02-27 07:25:44 +00:00
outBitStream . Write ( m_ModerationStatus ) ;
2021-12-05 17:54:36 +00:00
2023-01-03 17:22:04 +00:00
const auto nameData = GeneralUtils : : UTF8ToUTF16 ( m_Name ) ;
const auto ownerNameData = GeneralUtils : : UTF8ToUTF16 ( m_OwnerName ) ;
2021-12-05 17:54:36 +00:00
2024-02-27 07:25:44 +00:00
outBitStream . Write < uint8_t > ( nameData . size ( ) ) ;
2023-01-03 17:22:04 +00:00
for ( const auto c : nameData ) {
2024-02-27 07:25:44 +00:00
outBitStream . Write ( c ) ;
2023-01-03 17:22:04 +00:00
}
2021-12-05 17:54:36 +00:00
2024-02-27 07:25:44 +00:00
outBitStream . Write < uint8_t > ( ownerNameData . size ( ) ) ;
2023-01-03 17:22:04 +00:00
for ( const auto c : ownerNameData ) {
2024-02-27 07:25:44 +00:00
outBitStream . Write ( c ) ;
2023-01-03 17:22:04 +00:00
}
2022-07-28 13:39:57 +00:00
}
}
}
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
void PetComponent : : OnUse ( Entity * originator ) {
if ( m_Owner ! = LWOOBJID_EMPTY ) {
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( m_Tamer ! = LWOOBJID_EMPTY ) {
2023-07-15 20:56:33 +00:00
auto * tamer = Game : : entityManager - > GetEntity ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( tamer ! = nullptr ) {
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Tamer = LWOOBJID_EMPTY ;
}
2022-01-13 03:48:27 +00:00
2024-04-24 15:09:15 +00:00
auto * const inventoryComponent = originator - > GetComponent < InventoryComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( inventoryComponent = = nullptr ) {
return ;
}
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:04 +00:00
if ( m_Preconditions . has_value ( ) & & ! m_Preconditions - > Check ( originator , true ) ) {
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:15 +00:00
auto * const movementAIComponent = m_Parent - > GetComponent < MovementAIComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( movementAIComponent ! = nullptr ) {
movementAIComponent - > Stop ( ) ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
inventoryComponent - > DespawnPet ( ) ;
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:15 +00:00
const auto * const entry = CDClientManager : : GetTable < CDTamingBuildPuzzleTable > ( ) - > GetByLOT ( m_Parent - > GetLOT ( ) ) ;
if ( ! entry ) {
ChatPackets : : SendSystemMessage ( originator - > GetSystemAddress ( ) , u " Failed to find the puzzle minigame for this pet. " ) ;
return ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:15 +00:00
const auto * const destroyableComponent = originator - > GetComponent < DestroyableComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( destroyableComponent = = nullptr ) {
return ;
}
2024-04-24 15:09:15 +00:00
const auto imagination = destroyableComponent - > GetImagination ( ) ;
if ( imagination < entry - > imaginationCost ) {
2022-07-28 13:39:57 +00:00
return ;
}
2024-04-24 15:09:15 +00:00
const auto & bricks = BrickDatabase : : GetBricks ( entry - > validPieces ) ;
2022-07-28 13:39:57 +00:00
if ( bricks . empty ( ) ) {
ChatPackets : : SendSystemMessage ( originator - > GetSystemAddress ( ) , u " Failed to load the puzzle minigame for this pet. " ) ;
2024-04-24 15:09:15 +00:00
LOG ( " Couldn't find %s for minigame! " , entry - > validPieces . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2022-07-25 02:26:51 +00:00
2024-04-24 15:09:15 +00:00
const auto petPosition = m_Parent - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:15 +00:00
const auto originatorPosition = originator - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Parent - > SetRotation ( NiQuaternion : : LookAt ( petPosition , originatorPosition ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
float interactionDistance = m_Parent - > GetVar < float > ( u " interaction_distance " ) ;
if ( interactionDistance < = 0 ) {
interactionDistance = 15 ;
}
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
auto position = originatorPosition ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
NiPoint3 forward = NiQuaternion : : LookAt ( m_Parent - > GetPosition ( ) , originator - > GetPosition ( ) ) . GetForwardVector ( ) ;
forward . y = 0 ;
2021-12-05 17:54:36 +00:00
2024-01-19 21:12:05 +00:00
if ( dpWorld : : IsLoaded ( ) ) {
2022-07-28 13:39:57 +00:00
NiPoint3 attempt = petPosition + forward * interactionDistance ;
2022-07-25 02:26:51 +00:00
2024-05-22 01:01:44 +00:00
NiPoint3 nearestPoint = dpWorld : : GetNavMesh ( ) - > NearestPoint ( attempt ) ;
2021-12-05 17:54:36 +00:00
2024-05-22 01:01:44 +00:00
while ( std : : abs ( nearestPoint . y - petPosition . y ) > 4 & & interactionDistance > 10 ) {
2022-07-28 13:39:57 +00:00
const NiPoint3 forward = m_Parent - > GetRotation ( ) . GetForwardVector ( ) ;
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
attempt = originatorPosition + forward * interactionDistance ;
2021-12-05 17:54:36 +00:00
2024-05-22 01:01:44 +00:00
nearestPoint = dpWorld : : GetNavMesh ( ) - > NearestPoint ( attempt ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
interactionDistance - = 0.5f ;
}
2021-12-05 17:54:36 +00:00
2024-05-22 01:01:44 +00:00
position = nearestPoint ;
2022-07-28 13:39:57 +00:00
} else {
position = petPosition + forward * interactionDistance ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto rotation = NiQuaternion : : LookAt ( position , petPosition ) ;
GameMessages : : SendNotifyPetTamingMinigame (
originator - > GetObjectID ( ) ,
m_Parent - > GetObjectID ( ) ,
LWOOBJID_EMPTY ,
true ,
2023-05-02 22:39:21 +00:00
ePetTamingNotifyType : : BEGIN ,
2022-07-28 13:39:57 +00:00
petPosition ,
position ,
rotation ,
UNASSIGNED_SYSTEM_ADDRESS
) ;
GameMessages : : SendNotifyPetTamingMinigame (
m_Parent - > GetObjectID ( ) ,
LWOOBJID_EMPTY ,
originator - > GetObjectID ( ) ,
2024-05-22 01:01:44 +00:00
false ,
2023-05-02 22:39:21 +00:00
ePetTamingNotifyType : : BEGIN ,
2024-05-22 01:01:44 +00:00
NiPoint3Constant : : ZERO ,
NiPoint3Constant : : ZERO ,
NiQuaternion ( 0.0f , 0.0f , 0.0f , 0.0f ) ,
2022-07-28 13:39:57 +00:00
UNASSIGNED_SYSTEM_ADDRESS
) ;
GameMessages : : SendNotifyPetTamingPuzzleSelected ( originator - > GetObjectID ( ) , bricks , originator - > GetSystemAddress ( ) ) ;
m_Tamer = originator - > GetObjectID ( ) ;
SetStatus ( 5 ) ;
2024-05-22 01:01:44 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2022-07-28 13:39:57 +00:00
currentActivities . insert_or_assign ( m_Tamer , m_Parent - > GetObjectID ( ) ) ;
// Notify the start of a pet taming minigame
2024-03-07 01:49:29 +00:00
m_Parent - > GetScript ( ) - > OnNotifyPetTamingMinigame ( m_Parent , originator , ePetTamingNotifyType : : BEGIN ) ;
2024-05-22 01:01:44 +00:00
auto * characterComponent = originator - > GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ! = nullptr ) {
characterComponent - > SetCurrentActivity ( eGameActivity : : PET_TAMING ) ;
Game : : entityManager - > SerializeEntity ( originator ) ;
}
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : Update ( float deltaTime ) {
2024-01-29 07:53:12 +00:00
if ( m_StartPosition = = NiPoint3Constant : : ZERO ) {
2022-07-28 13:39:57 +00:00
m_StartPosition = m_Parent - > GetPosition ( ) ;
}
if ( m_Owner = = LWOOBJID_EMPTY ) {
if ( m_Tamer ! = LWOOBJID_EMPTY ) {
if ( m_Timer > 0 ) {
m_Timer - = deltaTime ;
if ( m_Timer < = 0 ) {
m_Timer = 0 ;
ClientFailTamingMinigame ( ) ;
}
}
} else {
if ( m_Timer > 0 ) {
m_Timer - = deltaTime ;
if ( m_Timer < = 0 ) {
Wander ( ) ;
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2022-07-28 13:39:57 +00:00
}
} else {
m_Timer = 5 ;
}
}
return ;
}
auto * owner = GetOwner ( ) ;
if ( owner = = nullptr ) {
m_Parent - > Kill ( ) ;
return ;
}
m_MovementAI = m_Parent - > GetComponent < MovementAIComponent > ( ) ;
if ( m_MovementAI = = nullptr ) {
return ;
}
2024-11-18 02:48:48 +00:00
if ( m_TreasureTime > 0 ) {
auto * treasure = Game : : entityManager - > GetEntity ( m_Interaction ) ;
2022-07-28 13:39:57 +00:00
2024-11-18 02:48:48 +00:00
if ( treasure = = nullptr ) {
m_TreasureTime = 0 ;
2022-07-28 13:39:57 +00:00
return ;
}
2024-11-18 02:48:48 +00:00
m_TreasureTime - = deltaTime ;
2022-07-28 13:39:57 +00:00
m_MovementAI - > Stop ( ) ;
2024-11-18 02:48:48 +00:00
if ( m_TreasureTime < = 0 ) {
2022-07-28 13:39:57 +00:00
m_Parent - > SetOwnerOverride ( m_Owner ) ;
2024-11-18 02:48:48 +00:00
treasure - > Smash ( m_Parent - > GetObjectID ( ) ) ;
2022-07-28 13:39:57 +00:00
m_Interaction = LWOOBJID_EMPTY ;
2024-11-18 02:48:48 +00:00
m_TreasureTime = 0 ;
2022-07-28 13:39:57 +00:00
}
return ;
}
auto destination = owner - > GetPosition ( ) ;
2023-08-04 02:38:04 +00:00
NiPoint3 position = m_MovementAI - > GetParent ( ) - > GetPosition ( ) ;
2022-07-28 13:39:57 +00:00
float distanceToOwner = Vector3 : : DistanceSquared ( position , destination ) ;
if ( distanceToOwner > 50 * 50 | | m_TimerAway > 5 ) {
m_MovementAI - > Warp ( destination ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Timer = 1 ;
m_TimerAway = 0 ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( distanceToOwner > 15 * 15 | | std : : abs ( destination . y - position . y ) > = 3 ) {
m_TimerAway + = deltaTime ;
} else {
m_TimerAway = 0 ;
}
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
if ( m_Timer > 0 ) {
m_Timer - = deltaTime ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
SwitchComponent * closestSwitch = SwitchComponent : : GetClosestSwitch ( position ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
float haltDistance = 5 ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( closestSwitch ! = nullptr ) {
if ( ! closestSwitch - > GetActive ( ) ) {
NiPoint3 switchPosition = closestSwitch - > GetParentEntity ( ) - > GetPosition ( ) ;
float distance = Vector3 : : DistanceSquared ( position , switchPosition ) ;
if ( distance < 3 * 3 ) {
m_Interaction = closestSwitch - > GetParentEntity ( ) - > GetObjectID ( ) ;
closestSwitch - > EntityEnter ( m_Parent ) ;
} else if ( distance < 20 * 20 ) {
haltDistance = 1 ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
destination = switchPosition ;
}
}
}
2021-12-05 17:54:36 +00:00
2023-11-13 10:41:27 +00:00
auto * missionComponent = owner - > GetComponent < MissionComponent > ( ) ;
if ( ! missionComponent ) return ;
// Determine if the "Lost Tags" mission has been completed and digging has been unlocked
const bool digUnlocked = missionComponent - > GetMissionState ( 842 ) = = eMissionState : : COMPLETE ;
2024-11-18 02:48:48 +00:00
Entity * closestTreasure = PetDigServer : : GetClosestTreasure ( position ) ;
2021-12-05 17:54:36 +00:00
2024-11-18 02:48:48 +00:00
if ( closestTreasure ! = nullptr & & digUnlocked ) {
2022-07-28 13:39:57 +00:00
// Skeleton Dragon Pat special case for bone digging
2024-11-18 02:48:48 +00:00
if ( closestTreasure - > GetLOT ( ) = = 12192 & & m_Parent - > GetLOT ( ) ! = 13067 ) {
goto skipTreasure ;
2022-07-28 13:39:57 +00:00
}
2022-07-25 02:26:51 +00:00
2024-11-18 02:48:48 +00:00
NiPoint3 treasurePosition = closestTreasure - > GetPosition ( ) ;
float distance = Vector3 : : DistanceSquared ( position , treasurePosition ) ;
2023-07-22 09:49:23 +00:00
if ( distance < 5 * 5 ) {
2024-11-18 02:48:48 +00:00
m_Interaction = closestTreasure - > GetObjectID ( ) ;
2021-12-05 17:54:36 +00:00
2024-01-29 07:53:12 +00:00
Command ( NiPoint3Constant : : ZERO , LWOOBJID_EMPTY , 1 , 202 , true ) ;
2021-12-05 17:54:36 +00:00
2024-11-18 02:48:48 +00:00
m_TreasureTime = 2 ;
2022-07-28 13:39:57 +00:00
} else if ( distance < 10 * 10 ) {
haltDistance = 1 ;
2021-12-05 17:54:36 +00:00
2024-11-18 02:48:48 +00:00
destination = treasurePosition ;
2022-07-28 13:39:57 +00:00
}
}
2021-12-05 17:54:36 +00:00
2024-11-18 02:48:48 +00:00
skipTreasure :
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
m_MovementAI - > SetHaltDistance ( haltDistance ) ;
2021-12-05 17:54:36 +00:00
2023-08-04 02:38:04 +00:00
m_MovementAI - > SetMaxSpeed ( 2.5f ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_MovementAI - > SetDestination ( destination ) ;
m_Timer = 1 ;
2021-12-05 17:54:36 +00:00
}
2022-04-07 05:21:54 +00:00
void PetComponent : : TryBuild ( uint32_t numBricks , bool clientFailed ) {
2022-07-28 13:39:57 +00:00
if ( m_Tamer = = LWOOBJID_EMPTY ) return ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * tamer = Game : : entityManager - > GetEntity ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( tamer = = nullptr ) {
m_Tamer = LWOOBJID_EMPTY ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:15 +00:00
const auto * const entry = CDClientManager : : GetTable < CDTamingBuildPuzzleTable > ( ) - > GetByLOT ( m_Parent - > GetLOT ( ) ) ;
if ( ! entry ) return ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * destroyableComponent = tamer - > GetComponent < DestroyableComponent > ( ) ;
2022-04-07 05:21:54 +00:00
2022-07-28 13:39:57 +00:00
if ( destroyableComponent = = nullptr ) return ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto imagination = destroyableComponent - > GetImagination ( ) ;
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:15 +00:00
imagination - = entry - > imaginationCost ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
destroyableComponent - > SetImagination ( imagination ) ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( clientFailed ) {
2024-04-24 15:09:15 +00:00
if ( imagination < entry - > imaginationCost ) {
2022-07-28 13:39:57 +00:00
ClientFailTamingMinigame ( ) ;
}
} else {
m_Timer = 0 ;
}
2022-04-07 05:21:54 +00:00
2022-07-28 13:39:57 +00:00
if ( numBricks = = 0 ) return ;
2022-04-07 05:21:54 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendPetTamingTryBuildResult ( m_Tamer , ! clientFailed , numBricks , tamer - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : NotifyTamingBuildSuccess ( NiPoint3 position ) {
if ( m_Tamer = = LWOOBJID_EMPTY ) return ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * tamer = Game : : entityManager - > GetEntity ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( tamer = = nullptr ) {
m_Tamer = LWOOBJID_EMPTY ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:15 +00:00
const auto * const entry = CDClientManager : : GetTable < CDTamingBuildPuzzleTable > ( ) - > GetByLOT ( m_Parent - > GetLOT ( ) ) ;
if ( ! entry ) return ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendPlayFXEffect ( tamer , - 1 , u " petceleb " , " " , LWOOBJID_EMPTY , 1 , 1 , true ) ;
2023-03-20 13:10:52 +00:00
RenderComponent : : PlayAnimation ( tamer , u " rebuild-celebrate " ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
EntityInfo info { } ;
2024-04-24 15:09:15 +00:00
info . lot = entry - > puzzleModelLot ;
2022-07-28 13:39:57 +00:00
info . pos = position ;
2024-01-29 07:53:12 +00:00
info . rot = NiQuaternionConstant : : IDENTITY ;
2022-07-28 13:39:57 +00:00
info . spawnerID = tamer - > GetObjectID ( ) ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * modelEntity = Game : : entityManager - > CreateEntity ( info ) ;
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
m_ModelId = modelEntity - > GetObjectID ( ) ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
Game : : entityManager - > ConstructEntity ( modelEntity ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendNotifyTamingModelLoadedOnServer ( m_Tamer , tamer - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendPetResponse ( m_Tamer , m_Parent - > GetObjectID ( ) , 0 , 10 , 0 , tamer - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * inventoryComponent = tamer - > GetComponent < InventoryComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( inventoryComponent = = nullptr ) {
return ;
}
2021-12-05 17:54:36 +00:00
2024-01-05 12:31:22 +00:00
LWOOBJID petSubKey = ObjectIDManager : : GenerateRandomObjectID ( ) ;
2021-12-05 17:54:36 +00:00
2023-04-25 18:17:40 +00:00
GeneralUtils : : SetBit ( petSubKey , eObjectBits : : CHARACTER ) ;
GeneralUtils : : SetBit ( petSubKey , eObjectBits : : PERSISTENT ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_DatabaseId = petSubKey ;
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
std : : string petName = tamer - > GetCharacter ( ) - > GetName ( ) ;
petName + = " 's Pet " ;
2021-12-05 17:54:36 +00:00
2022-08-02 13:56:20 +00:00
GameMessages : : SendAddPetToPlayer ( m_Tamer , 0 , GeneralUtils : : UTF8ToUTF16 ( petName ) , petSubKey , m_Parent - > GetLOT ( ) , tamer - > GetSystemAddress ( ) ) ;
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendRegisterPetID ( m_Tamer , m_Parent - > GetObjectID ( ) , tamer - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendRegisterPetDBID ( m_Tamer , petSubKey , tamer - > GetSystemAddress ( ) ) ;
2022-07-25 02:26:51 +00:00
2023-05-02 22:39:21 +00:00
inventoryComponent - > AddItem ( m_Parent - > GetLOT ( ) , 1 , eLootSourceType : : ACTIVITY , eInventoryType : : MODELS , { } , LWOOBJID_EMPTY , true , false , petSubKey ) ;
2022-07-28 13:39:57 +00:00
auto * item = inventoryComponent - > FindItemBySubKey ( petSubKey , MODELS ) ;
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
if ( item = = nullptr ) {
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
DatabasePet databasePet { } ;
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
databasePet . lot = m_Parent - > GetLOT ( ) ;
databasePet . moderationState = 1 ;
databasePet . name = petName ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
inventoryComponent - > SetDatabasePet ( petSubKey , databasePet ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
Activate ( item , false , true ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Timer = 0 ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendNotifyPetTamingMinigame (
m_Tamer ,
LWOOBJID_EMPTY ,
LWOOBJID_EMPTY ,
false ,
2023-05-02 22:39:21 +00:00
ePetTamingNotifyType : : NAMINGPET ,
2024-01-29 07:53:12 +00:00
NiPoint3Constant : : ZERO ,
NiPoint3Constant : : ZERO ,
NiQuaternionConstant : : IDENTITY ,
2022-07-28 13:39:57 +00:00
UNASSIGNED_SYSTEM_ADDRESS
) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
// Triggers the catch a pet missions
if ( petFlags . find ( m_Parent - > GetLOT ( ) ) ! = petFlags . end ( ) ) {
tamer - > GetCharacter ( ) - > SetPlayerFlag ( petFlags . at ( m_Parent - > GetLOT ( ) ) , true ) ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * missionComponent = tamer - > GetComponent < MissionComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( missionComponent ! = nullptr ) {
2023-01-22 23:38:47 +00:00
missionComponent - > Progress ( eMissionTaskType : : PET_TAMING , m_Parent - > GetLOT ( ) ) ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
SetStatus ( 1 ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * characterComponent = tamer - > GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ! = nullptr ) {
characterComponent - > UpdatePlayerStatistic ( PetsTamed ) ;
}
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : RequestSetPetName ( std : : u16string name ) {
if ( m_Tamer = = LWOOBJID_EMPTY ) {
if ( m_Owner ! = LWOOBJID_EMPTY ) {
auto * owner = GetOwner ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_ModerationStatus = 1 ; // Pending
m_Name = " " ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
//Save our pet's new name to the db:
SetPetNameForModeration ( GeneralUtils : : UTF16ToWTF8 ( name ) ) ;
2021-12-05 17:54:36 +00:00
2022-08-02 13:56:20 +00:00
GameMessages : : SendSetPetName ( m_Owner , GeneralUtils : : UTF8ToUTF16 ( m_Name ) , m_DatabaseId , owner - > GetSystemAddress ( ) ) ;
2022-07-28 13:39:57 +00:00
GameMessages : : SendSetPetNameModerated ( m_Owner , m_DatabaseId , m_ModerationStatus , owner - > GetSystemAddress ( ) ) ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * tamer = Game : : entityManager - > GetEntity ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( tamer = = nullptr ) {
m_Tamer = LWOOBJID_EMPTY ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2023-10-21 23:31:55 +00:00
LOG ( " Got set pet name (%s) " , GeneralUtils : : UTF16ToWTF8 ( name ) . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * inventoryComponent = tamer - > GetComponent < InventoryComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( inventoryComponent = = nullptr ) {
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_ModerationStatus = 1 ; // Pending
m_Name = " " ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
//Save our pet's new name to the db:
SetPetNameForModeration ( GeneralUtils : : UTF16ToWTF8 ( name ) ) ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2021-12-05 17:54:36 +00:00
2022-08-02 13:56:20 +00:00
std : : u16string u16name = GeneralUtils : : UTF8ToUTF16 ( m_Name ) ;
std : : u16string u16ownerName = GeneralUtils : : UTF8ToUTF16 ( m_OwnerName ) ;
GameMessages : : SendSetPetName ( m_Tamer , u16name , m_DatabaseId , tamer - > GetSystemAddress ( ) ) ;
GameMessages : : SendSetPetName ( m_Tamer , u16name , LWOOBJID_EMPTY , tamer - > GetSystemAddress ( ) ) ;
GameMessages : : SendPetNameChanged ( m_Parent - > GetObjectID ( ) , m_ModerationStatus , u16name , u16ownerName , UNASSIGNED_SYSTEM_ADDRESS ) ;
2022-07-28 13:39:57 +00:00
GameMessages : : SendSetPetNameModerated ( m_Tamer , m_DatabaseId , m_ModerationStatus , tamer - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendNotifyPetTamingMinigame (
m_Tamer ,
m_Parent - > GetObjectID ( ) ,
m_Tamer ,
false ,
2023-05-02 22:39:21 +00:00
ePetTamingNotifyType : : SUCCESS ,
2024-01-29 07:53:12 +00:00
NiPoint3Constant : : ZERO ,
NiPoint3Constant : : ZERO ,
NiQuaternionConstant : : IDENTITY ,
2022-07-28 13:39:57 +00:00
UNASSIGNED_SYSTEM_ADDRESS
) ;
2021-12-05 17:54:36 +00:00
2024-05-22 01:01:44 +00:00
auto * characterComponent = tamer - > GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ! = nullptr ) {
characterComponent - > SetCurrentActivity ( eGameActivity : : NONE ) ;
Game : : entityManager - > SerializeEntity ( tamer ) ;
}
2022-07-28 13:39:57 +00:00
GameMessages : : SendTerminateInteraction ( m_Tamer , eTerminateType : : FROM_INTERACTION , m_Parent - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * modelEntity = Game : : entityManager - > GetEntity ( m_ModelId ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( modelEntity ! = nullptr ) {
modelEntity - > Smash ( m_Tamer ) ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
currentActivities . erase ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Tamer = LWOOBJID_EMPTY ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
// Notify the end of a pet taming minigame
2024-03-07 01:49:29 +00:00
m_Parent - > GetScript ( ) - > OnNotifyPetTamingMinigame ( m_Parent , tamer , ePetTamingNotifyType : : SUCCESS ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : ClientExitTamingMinigame ( bool voluntaryExit ) {
if ( m_Tamer = = LWOOBJID_EMPTY ) return ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * tamer = Game : : entityManager - > GetEntity ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( tamer = = nullptr ) {
m_Tamer = LWOOBJID_EMPTY ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendNotifyPetTamingMinigame (
m_Tamer ,
m_Parent - > GetObjectID ( ) ,
m_Tamer ,
false ,
2023-05-02 22:39:21 +00:00
ePetTamingNotifyType : : QUIT ,
2024-01-29 07:53:12 +00:00
NiPoint3Constant : : ZERO ,
NiPoint3Constant : : ZERO ,
NiQuaternionConstant : : IDENTITY ,
2022-07-28 13:39:57 +00:00
UNASSIGNED_SYSTEM_ADDRESS
) ;
2021-12-05 17:54:36 +00:00
2024-05-22 01:01:44 +00:00
auto * characterComponent = tamer - > GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ! = nullptr ) {
characterComponent - > SetCurrentActivity ( eGameActivity : : NONE ) ;
Game : : entityManager - > SerializeEntity ( tamer ) ;
}
2022-07-28 13:39:57 +00:00
GameMessages : : SendNotifyTamingModelLoadedOnServer ( m_Tamer , tamer - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendTerminateInteraction ( m_Tamer , eTerminateType : : FROM_INTERACTION , m_Parent - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
currentActivities . erase ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
SetStatus ( 67108866 ) ;
m_Tamer = LWOOBJID_EMPTY ;
m_Timer = 0 ;
2022-07-25 02:26:51 +00:00
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
// Notify the end of a pet taming minigame
2024-03-07 01:49:29 +00:00
m_Parent - > GetScript ( ) - > OnNotifyPetTamingMinigame ( m_Parent , tamer , ePetTamingNotifyType : : QUIT ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : StartTimer ( ) {
2024-04-24 15:09:15 +00:00
const auto * const entry = CDClientManager : : GetTable < CDTamingBuildPuzzleTable > ( ) - > GetByLOT ( m_Parent - > GetLOT ( ) ) ;
if ( ! entry ) return ;
2021-12-05 17:54:36 +00:00
2024-04-24 15:09:15 +00:00
m_Timer = entry - > timeLimit ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : ClientFailTamingMinigame ( ) {
if ( m_Tamer = = LWOOBJID_EMPTY ) return ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * tamer = Game : : entityManager - > GetEntity ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( tamer = = nullptr ) {
m_Tamer = LWOOBJID_EMPTY ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendNotifyPetTamingMinigame (
m_Tamer ,
m_Parent - > GetObjectID ( ) ,
m_Tamer ,
false ,
2023-05-02 22:39:21 +00:00
ePetTamingNotifyType : : FAILED ,
2024-01-29 07:53:12 +00:00
NiPoint3Constant : : ZERO ,
NiPoint3Constant : : ZERO ,
NiQuaternionConstant : : IDENTITY ,
2022-07-28 13:39:57 +00:00
UNASSIGNED_SYSTEM_ADDRESS
) ;
2021-12-05 17:54:36 +00:00
2024-05-22 01:01:44 +00:00
auto * characterComponent = tamer - > GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ! = nullptr ) {
characterComponent - > SetCurrentActivity ( eGameActivity : : NONE ) ;
Game : : entityManager - > SerializeEntity ( tamer ) ;
}
2022-07-28 13:39:57 +00:00
GameMessages : : SendNotifyTamingModelLoadedOnServer ( m_Tamer , tamer - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendTerminateInteraction ( m_Tamer , eTerminateType : : FROM_INTERACTION , m_Parent - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
currentActivities . erase ( m_Tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
SetStatus ( 67108866 ) ;
m_Tamer = LWOOBJID_EMPTY ;
m_Timer = 0 ;
2022-07-25 02:26:51 +00:00
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
// Notify the end of a pet taming minigame
2024-03-07 01:49:29 +00:00
m_Parent - > GetScript ( ) - > OnNotifyPetTamingMinigame ( m_Parent , tamer , ePetTamingNotifyType : : FAILED ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : Wander ( ) {
m_MovementAI = m_Parent - > GetComponent < MovementAIComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( m_MovementAI = = nullptr | | ! m_MovementAI - > AtFinalWaypoint ( ) ) {
return ;
2021-12-05 17:54:36 +00:00
}
m_MovementAI - > SetHaltDistance ( 0 ) ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
const auto & info = m_MovementAI - > GetInfo ( ) ;
const auto div = static_cast < int > ( info . wanderDelayMax ) ;
m_Timer = ( div = = 0 ? 0 : GeneralUtils : : GenerateRandomNumber < int > ( 0 , div ) ) + info . wanderDelayMin ; //set a random timer to stay put.
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
const float radius = info . wanderRadius * sqrt ( static_cast < double > ( GeneralUtils : : GenerateRandomNumber < float > ( 0 , 1 ) ) ) ; //our wander radius + a bit of random range
const float theta = ( ( static_cast < double > ( GeneralUtils : : GenerateRandomNumber < float > ( 0 , 1 ) ) * 2 * PI ) ) ;
const NiPoint3 delta =
{
radius * cos ( theta ) ,
0 ,
radius * sin ( theta )
} ;
auto destination = m_StartPosition + delta ;
2024-01-19 21:12:05 +00:00
if ( dpWorld : : IsLoaded ( ) ) {
destination . y = dpWorld : : GetNavMesh ( ) - > GetHeightAtPoint ( destination ) ;
2021-12-05 17:54:36 +00:00
}
2023-08-04 02:38:04 +00:00
if ( Vector3 : : DistanceSquared ( destination , m_MovementAI - > GetParent ( ) - > GetPosition ( ) ) < 2 * 2 ) {
2021-12-05 17:54:36 +00:00
m_MovementAI - > Stop ( ) ;
return ;
}
2024-01-08 23:32:09 +00:00
m_MovementAI - > SetMaxSpeed ( m_PetInfo . sprintSpeed ) ;
2021-12-05 17:54:36 +00:00
m_MovementAI - > SetDestination ( destination ) ;
2024-01-08 23:32:09 +00:00
m_Timer + = ( m_MovementAI - > GetParent ( ) - > GetPosition ( ) . x - destination . x ) / m_PetInfo . sprintSpeed ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : Activate ( Item * item , bool registerPet , bool fromTaming ) {
m_ItemId = item - > GetId ( ) ;
m_DatabaseId = item - > GetSubKey ( ) ;
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
auto * inventoryComponent = item - > GetInventory ( ) - > GetComponent ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( inventoryComponent = = nullptr ) return ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
inventoryComponent - > DespawnPet ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Owner = inventoryComponent - > GetParent ( ) - > GetObjectID ( ) ;
2024-10-27 03:59:15 +00:00
AddDrainImaginationTimer ( fromTaming ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * owner = GetOwner ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( owner = = nullptr ) return ;
SetStatus ( 1 ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto databaseData = inventoryComponent - > GetDatabasePet ( m_DatabaseId ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_ModerationStatus = databaseData . moderationState ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
bool updatedModerationStatus = false ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
//Load mod status from db:
if ( m_ModerationStatus ! = 2 ) {
LoadPetNameFromModeration ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
databaseData . name = m_Name ;
databaseData . moderationState = m_ModerationStatus ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
inventoryComponent - > SetDatabasePet ( m_DatabaseId , databaseData ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
updatedModerationStatus = true ;
} else {
m_Name = databaseData . name ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_OwnerName = owner - > GetCharacter ( ) - > GetName ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( updatedModerationStatus ) {
2022-08-02 13:56:20 +00:00
GameMessages : : SendSetPetName ( m_Owner , GeneralUtils : : UTF8ToUTF16 ( m_Name ) , m_DatabaseId , owner - > GetSystemAddress ( ) ) ;
2022-07-28 13:39:57 +00:00
GameMessages : : SendSetPetNameModerated ( m_Owner , m_DatabaseId , m_ModerationStatus , owner - > GetSystemAddress ( ) ) ;
}
2021-12-05 17:54:36 +00:00
2022-09-02 18:49:19 +00:00
GameMessages : : SendMarkInventoryItemAsActive ( m_Owner , true , eUnequippableActiveType : : PET , m_ItemId , GetOwner ( ) - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
activePets [ m_Owner ] = m_Parent - > GetObjectID ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Timer = 3 ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2021-12-05 17:54:36 +00:00
2023-05-02 22:39:21 +00:00
owner - > GetCharacter ( ) - > SetPlayerFlag ( ePlayerFlag : : FIRST_MANUAL_PET_HIBERNATE , true ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( registerPet ) {
2022-08-02 13:56:20 +00:00
GameMessages : : SendAddPetToPlayer ( m_Owner , 0 , GeneralUtils : : UTF8ToUTF16 ( m_Name ) , m_DatabaseId , m_Parent - > GetLOT ( ) , owner - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendRegisterPetID ( m_Owner , m_Parent - > GetObjectID ( ) , owner - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendRegisterPetDBID ( m_Owner , m_DatabaseId , owner - > GetSystemAddress ( ) ) ;
}
2021-12-05 17:54:36 +00:00
}
2024-10-27 03:59:15 +00:00
void PetComponent : : AddDrainImaginationTimer ( bool fromTaming ) {
2022-07-28 13:39:57 +00:00
if ( Game : : config - > GetValue ( " pets_take_imagination " ) ! = " 1 " ) return ;
2022-06-18 07:14:24 +00:00
2024-10-27 03:59:15 +00:00
auto * playerEntity = Game : : entityManager - > GetEntity ( m_Owner ) ;
if ( ! playerEntity ) {
LOG ( " owner was null or didnt exist! " ) ;
return ;
}
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
auto playerDestroyableComponent = playerEntity - > GetComponent < DestroyableComponent > ( ) ;
if ( ! playerDestroyableComponent ) return ;
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
// Drain by 1 when you summon pet or when this method is called, but not when we have just tamed this pet.
if ( ! fromTaming ) playerDestroyableComponent - > Imagine ( - 1 ) ;
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
// Set this to a variable so when this is called back from the player the timer doesn't fire off.
2024-10-27 03:59:15 +00:00
m_Parent - > AddCallbackTimer ( m_PetInfo . imaginationDrainRate , [ this ] ( ) {
const auto * owner = Game : : entityManager - > GetEntity ( m_Owner ) ;
if ( ! owner ) {
LOG ( " owner was null or didnt exist! " ) ;
2022-07-28 13:39:57 +00:00
return ;
}
2022-07-25 02:26:51 +00:00
2024-10-27 03:59:15 +00:00
const auto * playerDestroyableComponent = owner - > GetComponent < DestroyableComponent > ( ) ;
if ( ! playerDestroyableComponent ) return ;
2024-01-08 23:32:09 +00:00
// If we are out of imagination despawn the pet.
if ( playerDestroyableComponent - > GetImagination ( ) = = 0 ) {
this - > Deactivate ( ) ;
auto playerEntity = playerDestroyableComponent - > GetParent ( ) ;
if ( ! playerEntity ) return ;
2022-06-18 06:53:09 +00:00
2024-01-08 23:32:09 +00:00
GameMessages : : SendUseItemRequirementsResponse ( playerEntity - > GetObjectID ( ) , playerEntity - > GetSystemAddress ( ) , eUseItemResponse : : NoImaginationForPet ) ;
}
2022-06-18 06:53:09 +00:00
2024-10-27 03:59:15 +00:00
this - > AddDrainImaginationTimer ( ) ;
2022-07-28 13:39:57 +00:00
} ) ;
2022-06-18 06:53:09 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : Deactivate ( ) {
GameMessages : : SendPlayFXEffect ( m_Parent - > GetObjectID ( ) , - 1 , u " despawn " , " " , LWOOBJID_EMPTY , 1 , 1 , true ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
activePets . erase ( m_Owner ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Parent - > Kill ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * owner = GetOwner ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( owner = = nullptr ) return ;
2022-07-25 02:26:51 +00:00
2024-10-27 03:59:15 +00:00
GameMessages : : SendMarkInventoryItemAsActive ( m_Owner , false , eUnequippableActiveType : : PET , m_ItemId , owner - > GetSystemAddress ( ) ) ;
2022-07-28 13:39:57 +00:00
GameMessages : : SendAddPetToPlayer ( m_Owner , 0 , u " " , LWOOBJID_EMPTY , LOT_NULL , owner - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendRegisterPetID ( m_Owner , LWOOBJID_EMPTY , owner - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
GameMessages : : SendRegisterPetDBID ( m_Owner , LWOOBJID_EMPTY , owner - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
2024-01-08 23:32:09 +00:00
GameMessages : : SendShowPetActionButton ( m_Owner , ePetAbilityType : : Invalid , false , owner - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : Release ( ) {
auto * inventoryComponent = GetOwner ( ) - > GetComponent < InventoryComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( inventoryComponent = = nullptr ) {
return ;
}
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
Deactivate ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
inventoryComponent - > RemoveDatabasePet ( m_DatabaseId ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * item = inventoryComponent - > FindItemBySubKey ( m_DatabaseId ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
item - > SetCount ( 0 , false , false ) ;
2021-12-05 17:54:36 +00:00
}
2024-01-08 23:32:09 +00:00
void PetComponent : : Command ( const NiPoint3 & position , const LWOOBJID source , const int32_t commandType , const int32_t typeId , const bool overrideObey ) {
2022-07-28 13:39:57 +00:00
auto * owner = GetOwner ( ) ;
2024-01-08 23:32:09 +00:00
if ( ! owner ) return ;
2022-07-28 13:39:57 +00:00
if ( commandType = = 1 ) {
// Emotes
GameMessages : : SendPlayEmote ( m_Parent - > GetObjectID ( ) , typeId , owner - > GetObjectID ( ) , UNASSIGNED_SYSTEM_ADDRESS ) ;
} else if ( commandType = = 3 ) {
// Follow me, ???
} else if ( commandType = = 6 ) {
// TODO: Go to player
}
2023-03-24 23:16:45 +00:00
if ( owner - > GetGMLevel ( ) > = eGameMasterLevel : : DEVELOPER ) {
2022-07-28 13:39:57 +00:00
ChatPackets : : SendSystemMessage ( owner - > GetSystemAddress ( ) , u " Commmand Type: " + ( GeneralUtils : : to_u16string ( commandType ) ) + u " - Type Id: " + ( GeneralUtils : : to_u16string ( typeId ) ) ) ;
}
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
LWOOBJID PetComponent : : GetOwnerId ( ) const {
return m_Owner ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
Entity * PetComponent : : GetOwner ( ) const {
2023-07-15 20:56:33 +00:00
return Game : : entityManager - > GetEntity ( m_Owner ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
LWOOBJID PetComponent : : GetDatabaseId ( ) const {
return m_DatabaseId ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
LWOOBJID PetComponent : : GetInteraction ( ) const {
return m_Interaction ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
LWOOBJID PetComponent : : GetItemId ( ) const {
return m_ItemId ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
uint32_t PetComponent : : GetStatus ( ) const {
return m_Status ;
2021-12-05 17:54:36 +00:00
}
2024-01-08 23:32:09 +00:00
ePetAbilityType PetComponent : : GetAbility ( ) const {
2022-07-28 13:39:57 +00:00
return m_Ability ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : SetInteraction ( LWOOBJID value ) {
m_Interaction = value ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : SetStatus ( uint32_t value ) {
m_Status = value ;
2021-12-05 17:54:36 +00:00
}
2024-01-08 23:32:09 +00:00
void PetComponent : : SetAbility ( ePetAbilityType value ) {
2022-07-28 13:39:57 +00:00
m_Ability = value ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
PetComponent * PetComponent : : GetTamingPet ( LWOOBJID tamer ) {
const auto & pair = currentActivities . find ( tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( pair = = currentActivities . end ( ) ) {
return nullptr ;
}
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * entity = Game : : entityManager - > GetEntity ( pair - > second ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( entity = = nullptr ) {
currentActivities . erase ( tamer ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return nullptr ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return entity - > GetComponent < PetComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
PetComponent * PetComponent : : GetActivePet ( LWOOBJID owner ) {
const auto & pair = activePets . find ( owner ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( pair = = activePets . end ( ) ) {
return nullptr ;
}
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
auto * entity = Game : : entityManager - > GetEntity ( pair - > second ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( entity = = nullptr ) {
activePets . erase ( owner ) ;
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
return nullptr ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
return entity - > GetComponent < PetComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
Entity * PetComponent : : GetParentEntity ( ) const {
return m_Parent ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
PetComponent : : ~ PetComponent ( ) {
2024-10-27 03:59:15 +00:00
m_Owner = LWOOBJID_EMPTY ;
2021-12-05 17:54:36 +00:00
}
void PetComponent : : SetPetNameForModeration ( const std : : string & petName ) {
2022-07-28 13:39:57 +00:00
int approved = 1 ; //default, in mod
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
//Make sure that the name isn't already auto-approved:
2023-03-24 23:16:45 +00:00
if ( Game : : chatFilter - > IsSentenceOkay ( petName , eGameMasterLevel : : CIVILIAN ) . empty ( ) ) {
2022-07-28 13:39:57 +00:00
approved = 2 ; //approved
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
//Save to db:
2024-01-08 23:32:09 +00:00
Database : : Get ( ) - > SetPetNameModerationStatus ( m_DatabaseId , IPetNames : : Info { petName , approved } ) ;
2021-12-05 17:54:36 +00:00
}
void PetComponent : : LoadPetNameFromModeration ( ) {
2023-11-18 00:47:18 +00:00
auto petNameInfo = Database : : Get ( ) - > GetPetNameInfo ( m_DatabaseId ) ;
if ( petNameInfo ) {
m_ModerationStatus = petNameInfo - > approvalStatus ;
2022-07-28 13:39:57 +00:00
if ( m_ModerationStatus = = 2 ) {
2023-11-18 00:47:18 +00:00
m_Name = petNameInfo - > petName ;
2022-07-28 13:39:57 +00:00
}
}
2021-12-05 17:54:36 +00:00
}
2024-04-24 15:09:04 +00:00
void PetComponent : : SetPreconditions ( const std : : string & preconditions ) {
m_Preconditions = std : : make_optional < PreconditionExpression > ( preconditions ) ;
2021-12-05 17:54:36 +00:00
}