2021-12-05 17:54:36 +00:00
# include "PetComponent.h"
# include "GameMessages.h"
# include "BrickDatabase.h"
# include "CDClientDatabase.h"
# 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"
# include "../dWorldServer/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"
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
std : : unordered_map < LOT , PetComponent : : PetPuzzleData > PetComponent : : buildCache { } ;
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 .
*/
2023-05-02 22:39:21 +00:00
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
} ;
2023-01-03 17:22:04 +00:00
PetComponent : : PetComponent ( Entity * parent , uint32_t componentId ) : Component ( parent ) {
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 ;
2023-11-19 22:46:27 +00:00
m_Status = PetStatus : : TAMEABLE ; // Tameable
2022-07-28 13:39:57 +00:00
m_Ability = PetAbilityType : : Invalid ;
m_StartPosition = NiPoint3 : : ZERO ;
m_MovementAI = nullptr ;
m_TresureTime = 0 ;
m_Preconditions = nullptr ;
2022-05-04 03:38:49 +00:00
2023-11-19 00:43:47 +00:00
m_ReadyToDig = false ;
m_InInteract = false ;
2022-05-04 03:38:49 +00:00
std : : string checkPreconditions = GeneralUtils : : UTF16ToWTF8 ( parent - > GetVar < std : : u16string > ( u " CheckPrecondition " ) ) ;
if ( ! checkPreconditions . empty ( ) ) {
SetPreconditions ( checkPreconditions ) ;
}
2022-07-28 13:39:57 +00:00
// Get the imagination drain rate from the CDClient
auto query = CDClientDatabase : : CreatePreppedStmt ( " SELECT imaginationDrainRate FROM PetComponent WHERE id = ?; " ) ;
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
query . bind ( 1 , static_cast < int > ( componentId ) ) ;
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
auto result = query . execQuery ( ) ;
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
// Should a result not exist for this pet default to 60 seconds.
if ( ! result . eof ( ) & & ! result . fieldIsNull ( 0 ) ) {
imaginationDrainRate = result . getFloatField ( 0 , 60.0f ) ;
} else {
imaginationDrainRate = 60.0f ;
}
result . finalize ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-08-10 21:33:15 +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
2022-07-28 13:39:57 +00:00
outBitStream - > Write1 ( ) ; // Always serialize as dirty for now
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
outBitStream - > Write < uint32_t > ( static_cast < unsigned int > ( m_Status ) ) ;
outBitStream - > Write < uint32_t > ( static_cast < uint32_t > ( tamed ? m_Ability : PetAbilityType : : 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
2022-07-28 13:39:57 +00:00
outBitStream - > Write ( interacting ) ;
if ( interacting ) {
outBitStream - > Write ( m_Interaction ) ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
outBitStream - > Write ( tamed ) ;
if ( tamed ) {
outBitStream - > Write ( m_Owner ) ;
}
2021-12-05 17:54:36 +00:00
2023-01-03 17:22:04 +00:00
if ( bIsInitialUpdate ) {
outBitStream - > Write ( tamed ) ;
if ( tamed ) {
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
2023-01-03 17:22:04 +00:00
outBitStream - > Write ( static_cast < uint8_t > ( nameData . size ( ) ) ) ;
for ( const auto c : nameData ) {
outBitStream - > Write ( c ) ;
}
2021-12-05 17:54:36 +00:00
2023-01-03 17:22:04 +00:00
outBitStream - > Write ( static_cast < uint8_t > ( ownerNameData . size ( ) ) ) ;
for ( const auto c : ownerNameData ) {
outBitStream - > Write ( c ) ;
}
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 ) {
2023-11-19 00:43:47 +00:00
LOG ( " PET USE! " ) ;
if ( m_ReadyToDig ) {
LOG ( " Dig initiated! " ) ;
m_TresureTime = 2.0f ;
//m_ReadyToDig = false;
SetAbility ( PetAbilityType : : DigAtPosition ) ;
}
2022-07-28 13:39:57 +00:00
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
2022-07-28 13:39:57 +00:00
auto * inventoryComponent = originator - > 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
if ( m_Preconditions ! = nullptr & & ! m_Preconditions - > Check ( originator , true ) ) {
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * movementAIComponent = m_Parent - > GetComponent < MovementAIComponent > ( ) ;
2021-12-05 17:54:36 +00:00
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
2022-07-28 13:39:57 +00:00
const auto & cached = buildCache . find ( m_Parent - > GetLOT ( ) ) ;
int32_t imaginationCost = 0 ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
std : : string buildFile ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( cached = = buildCache . end ( ) ) {
auto query = CDClientDatabase : : CreatePreppedStmt (
" SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = ?; " ) ;
query . bind ( 1 , ( int ) m_Parent - > GetLOT ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto result = query . execQuery ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( result . eof ( ) ) {
ChatPackets : : SendSystemMessage ( originator - > GetSystemAddress ( ) , u " Failed to find the puzzle minigame for this pet. " ) ;
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 ( result . fieldIsNull ( 0 ) ) {
result . finalize ( ) ;
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-11-06 00:09:26 +00:00
buildFile = std : : string ( result . getStringField ( 0 ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
PetPuzzleData data ;
data . buildFile = buildFile ;
data . puzzleModelLot = result . getIntField ( 1 ) ;
data . timeLimit = result . getFloatField ( 2 ) ;
data . numValidPieces = result . getIntField ( 3 ) ;
data . imaginationCost = result . getIntField ( 4 ) ;
if ( data . timeLimit < = 0 ) data . timeLimit = 60 ;
imaginationCost = data . imaginationCost ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
buildCache [ m_Parent - > GetLOT ( ) ] = data ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
result . finalize ( ) ;
} else {
buildFile = cached - > second . buildFile ;
imaginationCost = cached - > second . imaginationCost ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
auto * destroyableComponent = originator - > GetComponent < DestroyableComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( destroyableComponent = = nullptr ) {
return ;
}
auto imagination = destroyableComponent - > GetImagination ( ) ;
if ( imagination < imaginationCost ) {
return ;
}
2023-07-17 22:55:25 +00:00
const auto & bricks = BrickDatabase : : GetBricks ( buildFile ) ;
2021-12-05 17:54:36 +00:00
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. " ) ;
2023-10-21 23:31:55 +00:00
LOG ( " Couldn't find %s for minigame! " , buildFile . 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
2022-07-28 13:39:57 +00:00
auto petPosition = m_Parent - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
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 " ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
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
2022-07-28 13:39:57 +00:00
if ( dpWorld : : Instance ( ) . IsLoaded ( ) ) {
NiPoint3 attempt = petPosition + forward * interactionDistance ;
2022-07-25 02:26:51 +00:00
2022-08-02 05:30:19 +00:00
float y = dpWorld : : Instance ( ) . GetNavMesh ( ) - > GetHeightAtPoint ( attempt ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
while ( std : : abs ( y - petPosition . y ) > 4 & & interactionDistance > 10 ) {
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
2022-08-02 05:30:19 +00:00
y = dpWorld : : Instance ( ) . GetNavMesh ( ) - > GetHeightAtPoint ( 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
2022-07-28 13:39:57 +00:00
position = attempt ;
} 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 ( ) ,
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 : : SendNotifyPetTamingPuzzleSelected ( originator - > GetObjectID ( ) , bricks , originator - > GetSystemAddress ( ) ) ;
m_Tamer = originator - > GetObjectID ( ) ;
SetStatus ( 5 ) ;
currentActivities . insert_or_assign ( m_Tamer , m_Parent - > GetObjectID ( ) ) ;
// Notify the start of a pet taming minigame
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( m_Parent ) ) {
2023-05-02 22:39:21 +00:00
script - > OnNotifyPetTamingMinigame ( m_Parent , originator , ePetTamingNotifyType : : BEGIN ) ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : Update ( float deltaTime ) {
if ( m_StartPosition = = NiPoint3 : : ZERO ) {
m_StartPosition = m_Parent - > GetPosition ( ) ;
}
if ( m_Owner = = LWOOBJID_EMPTY ) {
2023-11-22 03:19:30 +00:00
UpdateUnowned ( deltaTime ) ;
2022-07-28 13:39:57 +00:00
return ;
}
auto * owner = GetOwner ( ) ;
2023-11-22 03:19:30 +00:00
if ( ! owner ) {
2022-07-28 13:39:57 +00:00
m_Parent - > Kill ( ) ;
return ;
}
m_MovementAI = m_Parent - > GetComponent < MovementAIComponent > ( ) ;
2023-11-22 03:19:30 +00:00
if ( ! m_MovementAI ) return ;
2022-07-28 13:39:57 +00:00
2023-11-19 23:31:31 +00:00
if ( m_TresureTime > 0.0f ) { //TODO: Find better trigger?
2023-11-19 00:43:47 +00:00
InteractDig ( deltaTime ) ;
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 ;
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-19 00:43:47 +00:00
// Determine if the "Lost Tags" mission has been completed and digging has been unlocked
2023-11-13 10:41:27 +00:00
auto * missionComponent = owner - > GetComponent < MissionComponent > ( ) ;
if ( ! missionComponent ) return ;
const bool digUnlocked = missionComponent - > GetMissionState ( 842 ) = = eMissionState : : COMPLETE ;
2022-07-28 13:39:57 +00:00
Entity * closestTresure = PetDigServer : : GetClosestTresure ( position ) ;
2023-11-13 10:41:27 +00:00
if ( closestTresure ! = nullptr & & digUnlocked ) {
2022-07-28 13:39:57 +00:00
// Skeleton Dragon Pat special case for bone digging
if ( closestTresure - > GetLOT ( ) = = 12192 & & m_Parent - > GetLOT ( ) ! = 13067 ) {
goto skipTresure ;
}
2022-07-25 02:26:51 +00:00
2022-07-28 13:39:57 +00:00
NiPoint3 tresurePosition = closestTresure - > GetPosition ( ) ;
float distance = Vector3 : : DistanceSquared ( position , tresurePosition ) ;
2023-07-22 09:49:23 +00:00
if ( distance < 5 * 5 ) {
2022-07-28 13:39:57 +00:00
m_Interaction = closestTresure - > GetObjectID ( ) ;
2021-12-05 17:54:36 +00:00
2023-11-22 02:16:17 +00:00
Command ( NiPoint3 : : ZERO , LWOOBJID_EMPTY , 1 , PetEmote : : Bounce , true ) ; // Plays 'bounce' animation
2021-12-05 17:54:36 +00:00
2023-11-19 00:43:47 +00:00
SetIsReadyToDig ( true ) ;
2022-07-28 13:39:57 +00:00
} else if ( distance < 10 * 10 ) {
haltDistance = 1 ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
destination = tresurePosition ;
2023-11-19 00:43:47 +00:00
SetIsReadyToDig ( false ) ;
2022-07-28 13:39:57 +00:00
}
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
skipTresure :
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
}
2023-11-22 03:19:30 +00:00
void PetComponent : : UpdateUnowned ( float deltaTime ) {
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 ( ) ;
} else {
m_Timer = 5 ;
}
}
}
2023-11-19 00:43:47 +00:00
void PetComponent : : SetIsReadyToDig ( bool isReady ) {
if ( isReady ) {
LOG ( " Dig state reached! " ) ;
//m_Interaction = closestTresure->GetObjectID();
2023-11-19 22:46:27 +00:00
//SetAbility(PetAbilityType::JumpOnObject);
SetStatus ( PetStatus : : IS_NOT_WAITING ) ; // Treasure dig status
2023-11-19 00:43:47 +00:00
m_ReadyToDig = true ;
}
else {
LOG ( " Dig state ended! " ) ;
//m_Interaction = LWOOBJID_EMPTY;
2023-11-19 22:46:27 +00:00
//SetAbility(PetAbilityType::Invalid);
2023-11-19 00:43:47 +00:00
SetStatus ( 0 ) ; // TODO: Check status
m_ReadyToDig = false ;
}
}
2023-11-19 22:46:27 +00:00
void PetComponent : : InteractDig ( float deltaTime ) {
2023-11-19 00:43:47 +00:00
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 ) ;
}
}
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
2022-07-28 13:39:57 +00:00
const auto & cached = buildCache . find ( m_Parent - > GetLOT ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( cached = = buildCache . end ( ) ) 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
2022-07-28 13:39:57 +00:00
imagination - = cached - > second . 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 ) {
if ( imagination < cached - > second . imaginationCost ) {
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
2022-07-28 13:39:57 +00:00
const auto & cached = buildCache . find ( m_Parent - > GetLOT ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( cached = = buildCache . end ( ) ) {
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 { } ;
info . lot = cached - > second . puzzleModelLot ;
info . pos = position ;
info . rot = NiQuaternion : : IDENTITY ;
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
2022-07-28 13:39:57 +00:00
LWOOBJID petSubKey = ObjectIDManager : : Instance ( ) - > 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 ,
2022-07-28 13:39:57 +00:00
NiPoint3 : : ZERO ,
NiPoint3 : : ZERO ,
NiQuaternion : : IDENTITY ,
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 ,
2022-07-28 13:39:57 +00:00
NiPoint3 : : ZERO ,
NiPoint3 : : ZERO ,
NiQuaternion : : IDENTITY ,
UNASSIGNED_SYSTEM_ADDRESS
) ;
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
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
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( m_Parent ) ) {
2023-05-02 22:39:21 +00:00
script - > OnNotifyPetTamingMinigame ( m_Parent , tamer , ePetTamingNotifyType : : SUCCESS ) ;
2022-07-28 13:39:57 +00:00
}
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 ,
2022-07-28 13:39:57 +00:00
NiPoint3 : : ZERO ,
NiPoint3 : : ZERO ,
NiQuaternion : : IDENTITY ,
UNASSIGNED_SYSTEM_ADDRESS
) ;
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 : : 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
2023-11-19 22:46:27 +00:00
SetStatus ( PetStatus : : TAMEABLE ) ;
2022-07-28 13:39:57 +00:00
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
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( m_Parent ) ) {
2023-05-02 22:39:21 +00:00
script - > OnNotifyPetTamingMinigame ( m_Parent , tamer , ePetTamingNotifyType : : QUIT ) ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void PetComponent : : StartTimer ( ) {
const auto & cached = buildCache . find ( m_Parent - > GetLOT ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( cached = = buildCache . end ( ) ) {
return ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
m_Timer = cached - > second . 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 ,
2022-07-28 13:39:57 +00:00
NiPoint3 : : ZERO ,
NiPoint3 : : ZERO ,
NiQuaternion : : IDENTITY ,
UNASSIGNED_SYSTEM_ADDRESS
) ;
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 : : 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
2023-11-19 22:46:27 +00:00
SetStatus ( PetStatus : : TAMEABLE ) ;
2022-07-28 13:39:57 +00:00
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
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( m_Parent ) ) {
2023-05-02 22:39:21 +00:00
script - > OnNotifyPetTamingMinigame ( m_Parent , tamer , ePetTamingNotifyType : : FAILED ) ;
2022-07-28 13:39:57 +00:00
}
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 ;
if ( dpWorld : : Instance ( ) . IsLoaded ( ) ) {
2022-08-02 05:30:19 +00:00
destination . y = dpWorld : : Instance ( ) . 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 ;
}
2023-08-04 02:38:04 +00:00
m_MovementAI - > SetMaxSpeed ( info . wanderSpeed ) ;
2021-12-05 17:54:36 +00:00
m_MovementAI - > SetDestination ( destination ) ;
2023-08-04 02:38:04 +00:00
m_Timer + = ( m_MovementAI - > GetParent ( ) - > GetPosition ( ) . x - destination . x ) / info . wanderSpeed ;
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 ) {
AddDrainImaginationTimer ( item , fromTaming ) ;
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
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 ( ) ;
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
2022-07-28 13:39:57 +00:00
GameMessages : : SendShowPetActionButton ( m_Owner , 3 , true , owner - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
}
2022-06-18 07:14:24 +00:00
void PetComponent : : AddDrainImaginationTimer ( Item * item , 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
2022-07-28 13:39:57 +00:00
auto playerInventory = item - > GetInventory ( ) ;
if ( ! playerInventory ) return ;
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
auto playerInventoryComponent = playerInventory - > GetComponent ( ) ;
if ( ! playerInventoryComponent ) return ;
2022-06-18 06:53:09 +00:00
2022-07-28 13:39:57 +00:00
auto playerEntity = playerInventoryComponent - > GetParent ( ) ;
if ( ! playerEntity ) 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.
m_Parent - > AddCallbackTimer ( imaginationDrainRate , [ playerDestroyableComponent , this , item ] ( ) {
if ( ! playerDestroyableComponent ) {
2023-10-21 23:31:55 +00:00
LOG ( " No petComponent and/or no playerDestroyableComponent " ) ;
2022-07-28 13:39:57 +00:00
return ;
}
2022-07-25 02:26:51 +00:00
2023-01-03 17:22:04 +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
2023-05-02 22:39:21 +00:00
GameMessages : : SendUseItemRequirementsResponse ( playerEntity - > GetObjectID ( ) , playerEntity - > GetSystemAddress ( ) , eUseItemResponse : : NoImaginationForPet ) ;
2023-01-03 17:22:04 +00:00
}
2022-06-18 06:53:09 +00:00
2023-01-03 17:22:04 +00:00
this - > AddDrainImaginationTimer ( item ) ;
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-09-02 18:49:19 +00:00
GameMessages : : SendMarkInventoryItemAsActive ( m_Owner , false , eUnequippableActiveType : : PET , m_ItemId , GetOwner ( ) - > GetSystemAddress ( ) ) ;
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
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
2022-07-28 13:39:57 +00:00
GameMessages : : SendShowPetActionButton ( m_Owner , 0 , 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
}
2022-07-28 13:39:57 +00:00
void PetComponent : : Command ( NiPoint3 position , LWOOBJID source , int32_t commandType , int32_t typeId , bool overrideObey ) {
auto * owner = GetOwner ( ) ;
2023-11-19 22:46:27 +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 ) ) ) ;
}
2023-11-19 23:31:31 +00:00
// Add movement functionality
if ( position ! = NiPoint3 : : ZERO ) {
m_MovementAI - > SetDestination ( position ) ;
m_Timer = 9 ; //Is this setting how long until the next update tick?
}
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
}
2022-07-28 13:39:57 +00:00
PetAbilityType PetComponent : : GetAbility ( ) const {
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
}
2022-07-28 13:39:57 +00:00
void PetComponent : : SetAbility ( PetAbilityType value ) {
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 ( ) {
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:
2023-11-18 00:47:18 +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
}
void PetComponent : : SetPreconditions ( std : : string & preconditions ) {
2022-07-28 13:39:57 +00:00
m_Preconditions = new PreconditionExpression ( preconditions ) ;
2021-12-05 17:54:36 +00:00
}
2023-11-19 22:46:27 +00:00
void PetComponent : : StartInteractDig ( ) {
//m_InInteract = true;
m_TresureTime = 2.0f ; //TODO: Remove magic number
2023-11-22 02:16:17 +00:00
Command ( NiPoint3 : : ZERO , LWOOBJID_EMPTY , 1 , PetEmote : : DigTreasure , true ) ;
2023-11-19 22:46:27 +00:00
}
void PetComponent : : EndInteractDig ( ) {
//m_InInteract = false;
}