3131#include " Formulas.h"
3232#include " SpellAuras.h"
3333#include " Unit.h"
34+ #include " Transports.h"
35+ #include " movement/MoveSpline.h"
36+ #include " movement/MoveSplineInit.h"
37+
3438
3539// numbers represent minutes * 100 while happy (you get 100 loyalty points per min while happy)
3640uint32 const LevelUpLoyalty[6 ] =
@@ -56,7 +60,7 @@ uint32 const LevelStartLoyalty[6] =
5660Pet::Pet (PetType type) :
5761 Creature(CREATURE_SUBTYPE_PET),
5862 m_TrainingPoints(0 ), m_resetTalentsCost(0 ), m_resetTalentsTime(0 ),
59- m_removed(false ), m_happinessTimer(7500 ), m_loyaltyTimer(12000 ), m_petType(type), m_duration(0 ),
63+ m_removed(false ), m_pendingTransportReboard( false ), m_transport( nullptr ), m_happinessTimer(7500 ), m_loyaltyTimer(12000 ), m_petType(type), m_duration(0 ),
6064 m_loyaltyPoints(0 ), m_bonusdamage(0 ), m_auraUpdateMask(0 ), m_loading(false ),
6165 m_petModeFlags(PET_MODE_DEFAULT)
6266{
@@ -351,6 +355,20 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
351355
352356 }
353357
358+ Player* p_owner = owner->GetTypeId () == TYPEID_PLAYER ? (Player*)owner : nullptr ;
359+ Transport* ownerTransport = p_owner ? p_owner->GetTransport () : nullptr ;
360+
361+ if (ownerTransport)
362+ {
363+ Position const * tpos = p_owner->m_movementInfo .GetTransportPos ();
364+ float petTo = tpos->o ;
365+ float petTx = tpos->x + cos (petTo + PET_FOLLOW_ANGLE) * PET_FOLLOW_DIST;
366+ float petTy = tpos->y + sin (petTo + PET_FOLLOW_ANGLE) * PET_FOLLOW_DIST;
367+ float petTz = tpos->z ;
368+ m_movementInfo.SetTransportData (ownerTransport->GetObjectGuid (), petTx, petTy, petTz, petTo, 0 );
369+ m_movementInfo.AddMovementFlag (MOVEFLAG_ONTRANSPORT);
370+ }
371+
354372 map->Add ((Creature*)this );
355373 AIM_Initialize ();
356374
@@ -363,17 +381,25 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
363381 owner->SetPet (this ); // in DB stored only full controlled creature
364382 DEBUG_LOG (" New Pet has guid %u" , GetGUIDLow ());
365383
366- if (owner-> GetTypeId () == TYPEID_PLAYER )
384+ if (p_owner )
367385 {
368- ((Player*)owner) ->PetSpellInitialize ();
369- if (((Player*)owner) ->GetGroup ())
386+ p_owner ->PetSpellInitialize ();
387+ if (p_owner ->GetGroup ())
370388 {
371- ((Player*)owner) ->SetGroupUpdateFlag (GROUP_UPDATE_PET);
389+ p_owner ->SetGroupUpdateFlag (GROUP_UPDATE_PET);
372390 }
373391 }
374392
375393 m_loading = false ;
376394
395+ if (ownerTransport)
396+ {
397+ ownerTransport->AddPassenger (this );
398+ m_transport = ownerTransport;
399+ GetMotionMaster ()->Clear (false );
400+ m_pendingTransportReboard = true ;
401+ }
402+
377403 SynchronizeLevelWithOwner ();
378404 return true ;
379405}
@@ -619,13 +645,14 @@ void Pet::Update(uint32 update_diff, uint32 diff)
619645 // unsummon pet that lost owner
620646 Unit* owner = GetOwner ();
621647 if (!owner ||
622- (!IsWithinDistInMap (owner, GetMap ()->GetVisibilityDistance ()) && (owner->GetCharmGuid () && (owner->GetCharmGuid () != GetObjectGuid ()))) ||
648+ (!m_transport && ! IsWithinDistInMap (owner, GetMap ()->GetVisibilityDistance ()) && (owner->GetCharmGuid () && (owner->GetCharmGuid () != GetObjectGuid ()))) ||
623649 (isControlled () && !owner->GetPetGuid ()))
624650 {
625651 Unsummon (PET_SAVE_REAGENTS);
626652 return ;
627653 }
628654
655+
629656 if (isControlled ())
630657 {
631658 if (owner->GetPetGuid () != GetObjectGuid ())
@@ -647,6 +674,10 @@ void Pet::Update(uint32 update_diff, uint32 diff)
647674 return ;
648675 }
649676 }
677+
678+ if (Player* plOwner = owner->ToPlayer ())
679+ UpdateTransport (plOwner);
680+
650681 break ;
651682 }
652683 default :
@@ -656,6 +687,144 @@ void Pet::Update(uint32 update_diff, uint32 diff)
656687 Creature::Update (update_diff, diff);
657688}
658689
690+ void Pet::UpdateTransport (Player* plOwner)
691+ {
692+ Transport* tr = plOwner->GetTransport ();
693+
694+ // Disembark if the owner has left the transport but the pet hasn't yet.
695+ if (m_transport && tr != m_transport)
696+ {
697+ m_transport->RemovePassenger (this );
698+ m_transport = nullptr ;
699+ m_movementInfo.RemoveMovementFlag (MOVEFLAG_ONTRANSPORT);
700+ m_movementInfo.ClearTransportData ();
701+ NearTeleportTo (plOwner->GetPositionX (), plOwner->GetPositionY (),
702+ plOwner->GetPositionZ (), plOwner->GetOrientation ());
703+ }
704+ else // Board pet onto transport once it has swum/walked close enough to the owner.
705+ if (!m_transport && tr)
706+ {
707+ float dx = GetPositionX () - plOwner->GetPositionX ();
708+ float dy = GetPositionY () - plOwner->GetPositionY ();
709+ float dist2d = sqrt (dx*dx + dy*dy);
710+ if (dist2d <= 6 .0f )
711+ {
712+ tr->AddPassenger (this );
713+ m_transport = tr;
714+ Position const * tpos = plOwner->m_movementInfo .GetTransportPos ();
715+ m_movementInfo.SetTransportData (tr->GetObjectGuid (), tpos->x , tpos->y , tpos->z , tpos->o , 0 );
716+ m_movementInfo.AddMovementFlag (MOVEFLAG_ONTRANSPORT);
717+ m_movementInfo.ChangePosition (plOwner->GetPositionX (), plOwner->GetPositionY (), plOwner->GetPositionZ (), plOwner->GetOrientation ());
718+ GetMotionMaster ()->Clear (false );
719+ if (GetCharmInfo ())
720+ GetCharmInfo ()->SetCommandState (COMMAND_FOLLOW);
721+ NearTeleportTo (plOwner->GetPositionX (), plOwner->GetPositionY (), plOwner->GetPositionZ (), plOwner->GetOrientation ());
722+ if (movespline)
723+ {
724+ WorldPacket moveData (SMSG_MONSTER_MOVE_TRANSPORT, 64 );
725+ moveData << GetPackGUID ();
726+ moveData << tr->GetPackGUID ();
727+ moveData << tpos->x << tpos->y << tpos->z ;
728+ moveData << movespline->GetId ();
729+ moveData << uint8 (Movement::MonsterMoveStop);
730+ SendMessageToSet (&moveData, true );
731+ }
732+ SendCreateUpdateToPlayer (plOwner);
733+ }
734+ }
735+
736+ if (m_pendingTransportReboard)
737+ {
738+ m_pendingTransportReboard = false ;
739+ plOwner->PetSpellInitialize ();
740+ if (tr && movespline)
741+ {
742+ Position const * tpos = m_movementInfo.GetTransportPos ();
743+ WorldPacket moveData (SMSG_MONSTER_MOVE_TRANSPORT, 64 );
744+ moveData << GetPackGUID ();
745+ moveData << tr->GetPackGUID ();
746+ moveData << tpos->x << tpos->y << tpos->z ;
747+ moveData << movespline->GetId ();
748+ moveData << uint8 (Movement::MonsterMoveStop);
749+ plOwner->SendDirectMessage (&moveData);
750+ }
751+ SendCreateUpdateToPlayer (plOwner);
752+ }
753+ }
754+
755+ bool Pet::HandleTransportFollow (Unit* target, float offset, float angle, bool walking, bool & outMoved)
756+ {
757+ outMoved = false ;
758+ if (!target || target->GetTypeId () != TYPEID_PLAYER)
759+ return false ;
760+
761+ Transport* masterTransport = static_cast <Player*>(target)->GetTransport ();
762+ if (!masterTransport)
763+ return false ;
764+
765+ if (m_transport == masterTransport)
766+ {
767+ // Both on the same transport — move in transport-relative space.
768+ float tx = masterTransport->GetPositionX ();
769+ float ty = masterTransport->GetPositionY ();
770+ float tz = masterTransport->GetPositionZ ();
771+ float to = masterTransport->GetOrientation ();
772+ float cos_o = cos (to), sin_o = sin (to);
773+
774+ Position const * curRelPos = m_movementInfo.GetTransportPos ();
775+ float startRelX = curRelPos->x , startRelY = curRelPos->y , startRelZ = curRelPos->z ;
776+
777+ Position const * masterTPos = target->m_movementInfo .GetTransportPos ();
778+ float followDist = offset + GetObjectBoundingRadius () + target->GetObjectBoundingRadius ();
779+ float destRelX = masterTPos->x + cos (angle) * followDist;
780+ float destRelY = masterTPos->y + sin (angle) * followDist;
781+ float destRelZ = masterTPos->z ;
782+
783+ float relDx = destRelX - startRelX, relDy = destRelY - startRelY, relDz = destRelZ - startRelZ;
784+ float relDist = sqrt (relDx * relDx + relDy * relDy + relDz * relDz);
785+ if (relDist < 0 .5f )
786+ return true ;
787+
788+ m_movementInfo.SetTransportData (masterTransport->GetObjectGuid (), destRelX, destRelY, destRelZ, 0 .0f , 0 );
789+
790+ float speed = GetSpeed (walking ? MOVE_WALK : MOVE_RUN);
791+ uint32 durationMs = (speed > 0 .0f ) ? uint32 (relDist / speed * 1000 .0f ) : 0 ;
792+
793+ float destWX = tx + cos_o * destRelX - sin_o * destRelY;
794+ float destWY = ty + sin_o * destRelX + cos_o * destRelY;
795+ float destWZ = tz + destRelZ;
796+ GetMap ()->CreatureRelocation (this , destWX, destWY, destWZ, GetOrientation ());
797+
798+ if (durationMs > 0 )
799+ {
800+ WorldPacket moveTransport (SMSG_MONSTER_MOVE_TRANSPORT, 80 );
801+ moveTransport << GetPackGUID ();
802+ moveTransport << masterTransport->GetPackGUID ();
803+ moveTransport << startRelX << startRelY << startRelZ;
804+ moveTransport << movespline->GetId ();
805+ moveTransport << uint8 (Movement::MonsterMoveNormal);
806+ moveTransport << uint32 (Movement::MoveSplineFlag::Runmode);
807+ moveTransport << durationMs;
808+ moveTransport << uint32 (0 );
809+ moveTransport << destRelX << destRelY << destRelZ;
810+ SendMessageToSet (&moveTransport, true );
811+ }
812+
813+ outMoved = true ;
814+ return true ;
815+ }
816+
817+ // Master is on a transport the pet hasn't boarded yet — approach in world space.
818+ float tx, ty, tz;
819+ target->GetPosition (tx, ty, tz);
820+ Movement::MoveSplineInit init (*this );
821+ init.MoveTo (tx, ty, tz);
822+ init.SetWalk (walking);
823+ init.Launch ();
824+ outMoved = true ;
825+ return true ;
826+ }
827+
659828void Pet::RegenerateAll (uint32 update_diff)
660829{
661830 // regenerate focus
@@ -1049,6 +1218,17 @@ void Pet::Unsummon(PetSaveMode mode, Unit* owner /*= NULL*/)
10491218 }
10501219 break ;
10511220 }
1221+
1222+ if (m_transport)
1223+ {
1224+ m_transport->RemovePassenger (this );
1225+ m_transport = nullptr ;
1226+ }
1227+ }
1228+ else if (m_transport)
1229+ {
1230+ m_transport->RemovePassenger (this );
1231+ m_transport = nullptr ;
10521232 }
10531233
10541234 SavePetToDB (mode);
0 commit comments