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+ if (owner->GetTypeId () == TYPEID_PLAYER)
359+ {
360+ if (Transport* tr = ((Player*)owner)->GetTransport ())
361+ {
362+ Position const * tpos = ((Player*)owner)->m_movementInfo .GetTransportPos ();
363+ float petTo = tpos->o ;
364+ float petTx = tpos->x + cos (petTo + PET_FOLLOW_ANGLE) * PET_FOLLOW_DIST;
365+ float petTy = tpos->y + sin (petTo + PET_FOLLOW_ANGLE) * PET_FOLLOW_DIST;
366+ float petTz = tpos->z ;
367+ m_movementInfo.SetTransportData (tr->GetObjectGuid (), petTx, petTy, petTz, petTo, 0 );
368+ m_movementInfo.AddMovementFlag (MOVEFLAG_ONTRANSPORT);
369+ }
370+ }
371+
354372 map->Add ((Creature*)this );
355373 AIM_Initialize ();
356374
@@ -374,6 +392,17 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
374392
375393 m_loading = false ;
376394
395+ if (owner->GetTypeId () == TYPEID_PLAYER)
396+ {
397+ if (Transport* tr = ((Player*)owner)->GetTransport ())
398+ {
399+ tr->AddPassenger (this );
400+ m_transport = tr;
401+ GetMotionMaster ()->Clear (false );
402+ m_pendingTransportReboard = true ;
403+ }
404+ }
405+
377406 SynchronizeLevelWithOwner ();
378407 return true ;
379408}
@@ -619,13 +648,14 @@ void Pet::Update(uint32 update_diff, uint32 diff)
619648 // unsummon pet that lost owner
620649 Unit* owner = GetOwner ();
621650 if (!owner ||
622- (!IsWithinDistInMap (owner, GetMap ()->GetVisibilityDistance ()) && (owner->GetCharmGuid () && (owner->GetCharmGuid () != GetObjectGuid ()))) ||
651+ (!m_transport && ! IsWithinDistInMap (owner, GetMap ()->GetVisibilityDistance ()) && (owner->GetCharmGuid () && (owner->GetCharmGuid () != GetObjectGuid ()))) ||
623652 (isControlled () && !owner->GetPetGuid ()))
624653 {
625654 Unsummon (PET_SAVE_REAGENTS);
626655 return ;
627656 }
628657
658+
629659 if (isControlled ())
630660 {
631661 if (owner->GetPetGuid () != GetObjectGuid ())
@@ -647,6 +677,10 @@ void Pet::Update(uint32 update_diff, uint32 diff)
647677 return ;
648678 }
649679 }
680+
681+ if (Player* plOwner = owner->ToPlayer ())
682+ UpdateTransport (plOwner);
683+
650684 break ;
651685 }
652686 default :
@@ -656,6 +690,144 @@ void Pet::Update(uint32 update_diff, uint32 diff)
656690 Creature::Update (update_diff, diff);
657691}
658692
693+ void Pet::UpdateTransport (Player* plOwner)
694+ {
695+ Transport* tr = plOwner->GetTransport ();
696+
697+ // Disembark if the owner has left the transport but the pet hasn't yet.
698+ if (m_transport && tr != m_transport)
699+ {
700+ m_transport->RemovePassenger (this );
701+ m_transport = nullptr ;
702+ m_movementInfo.RemoveMovementFlag (MOVEFLAG_ONTRANSPORT);
703+ m_movementInfo.ClearTransportData ();
704+ NearTeleportTo (plOwner->GetPositionX (), plOwner->GetPositionY (),
705+ plOwner->GetPositionZ (), plOwner->GetOrientation ());
706+ }
707+ else // Board pet onto transport once it has swum/walked close enough to the owner.
708+ if (!m_transport && tr)
709+ {
710+ float dx = GetPositionX () - plOwner->GetPositionX ();
711+ float dy = GetPositionY () - plOwner->GetPositionY ();
712+ float dist2d = sqrt (dx*dx + dy*dy);
713+ if (dist2d <= 6 .0f )
714+ {
715+ tr->AddPassenger (this );
716+ m_transport = tr;
717+ Position const * tpos = plOwner->m_movementInfo .GetTransportPos ();
718+ m_movementInfo.SetTransportData (tr->GetObjectGuid (), tpos->x , tpos->y , tpos->z , tpos->o , 0 );
719+ m_movementInfo.AddMovementFlag (MOVEFLAG_ONTRANSPORT);
720+ m_movementInfo.ChangePosition (plOwner->GetPositionX (), plOwner->GetPositionY (), plOwner->GetPositionZ (), plOwner->GetOrientation ());
721+ GetMotionMaster ()->Clear (false );
722+ if (GetCharmInfo ())
723+ GetCharmInfo ()->SetCommandState (COMMAND_FOLLOW);
724+ NearTeleportTo (plOwner->GetPositionX (), plOwner->GetPositionY (), plOwner->GetPositionZ (), plOwner->GetOrientation ());
725+ if (movespline)
726+ {
727+ WorldPacket moveData (SMSG_MONSTER_MOVE_TRANSPORT, 64 );
728+ moveData << GetPackGUID ();
729+ moveData << tr->GetPackGUID ();
730+ moveData << tpos->x << tpos->y << tpos->z ;
731+ moveData << movespline->GetId ();
732+ moveData << uint8 (Movement::MonsterMoveStop);
733+ SendMessageToSet (&moveData, true );
734+ }
735+ SendCreateUpdateToPlayer (plOwner);
736+ }
737+ }
738+
739+ if (m_pendingTransportReboard)
740+ {
741+ m_pendingTransportReboard = false ;
742+ plOwner->PetSpellInitialize ();
743+ if (tr && movespline)
744+ {
745+ Position const * tpos = m_movementInfo.GetTransportPos ();
746+ WorldPacket moveData (SMSG_MONSTER_MOVE_TRANSPORT, 64 );
747+ moveData << GetPackGUID ();
748+ moveData << tr->GetPackGUID ();
749+ moveData << tpos->x << tpos->y << tpos->z ;
750+ moveData << movespline->GetId ();
751+ moveData << uint8 (Movement::MonsterMoveStop);
752+ plOwner->SendDirectMessage (&moveData);
753+ }
754+ SendCreateUpdateToPlayer (plOwner);
755+ }
756+ }
757+
758+ bool Pet::HandleTransportFollow (Unit* target, float offset, float angle, bool walking, bool & outMoved)
759+ {
760+ outMoved = false ;
761+ if (!target || target->GetTypeId () != TYPEID_PLAYER)
762+ return false ;
763+
764+ Transport* masterTransport = static_cast <Player*>(target)->GetTransport ();
765+ if (!masterTransport)
766+ return false ;
767+
768+ if (m_transport == masterTransport)
769+ {
770+ // Both on the same transport — move in transport-relative space.
771+ float tx = masterTransport->GetPositionX ();
772+ float ty = masterTransport->GetPositionY ();
773+ float tz = masterTransport->GetPositionZ ();
774+ float to = masterTransport->GetOrientation ();
775+ float cos_o = cos (to), sin_o = sin (to);
776+
777+ Position const * curRelPos = m_movementInfo.GetTransportPos ();
778+ float startRelX = curRelPos->x , startRelY = curRelPos->y , startRelZ = curRelPos->z ;
779+
780+ Position const * masterTPos = target->m_movementInfo .GetTransportPos ();
781+ float followDist = offset + GetObjectBoundingRadius () + target->GetObjectBoundingRadius ();
782+ float destRelX = masterTPos->x + cos (angle) * followDist;
783+ float destRelY = masterTPos->y + sin (angle) * followDist;
784+ float destRelZ = masterTPos->z ;
785+
786+ float relDx = destRelX - startRelX, relDy = destRelY - startRelY, relDz = destRelZ - startRelZ;
787+ float relDist = sqrt (relDx * relDx + relDy * relDy + relDz * relDz);
788+ if (relDist < 0 .5f )
789+ return true ;
790+
791+ m_movementInfo.SetTransportData (masterTransport->GetObjectGuid (), destRelX, destRelY, destRelZ, 0 .0f , 0 );
792+
793+ float speed = GetSpeed (walking ? MOVE_WALK : MOVE_RUN);
794+ uint32 durationMs = (speed > 0 .0f ) ? uint32 (relDist / speed * 1000 .0f ) : 0 ;
795+
796+ float destWX = tx + cos_o * destRelX - sin_o * destRelY;
797+ float destWY = ty + sin_o * destRelX + cos_o * destRelY;
798+ float destWZ = tz + destRelZ;
799+ GetMap ()->CreatureRelocation (this , destWX, destWY, destWZ, GetOrientation ());
800+
801+ if (durationMs > 0 )
802+ {
803+ WorldPacket moveTransport (SMSG_MONSTER_MOVE_TRANSPORT, 80 );
804+ moveTransport << GetPackGUID ();
805+ moveTransport << masterTransport->GetPackGUID ();
806+ moveTransport << startRelX << startRelY << startRelZ;
807+ moveTransport << uint32 (0 );
808+ moveTransport << uint8 (Movement::MonsterMoveNormal);
809+ moveTransport << uint32 (Movement::MoveSplineFlag::Runmode);
810+ moveTransport << durationMs;
811+ moveTransport << uint32 (0 );
812+ moveTransport << destRelX << destRelY << destRelZ;
813+ SendMessageToSet (&moveTransport, true );
814+ }
815+
816+ outMoved = true ;
817+ return true ;
818+ }
819+
820+ // Master is on a transport the pet hasn't boarded yet — approach in world space.
821+ float tx, ty, tz;
822+ target->GetPosition (tx, ty, tz);
823+ Movement::MoveSplineInit init (*this );
824+ init.MoveTo (tx, ty, tz);
825+ init.SetWalk (walking);
826+ init.Launch ();
827+ outMoved = true ;
828+ return true ;
829+ }
830+
659831void Pet::RegenerateAll (uint32 update_diff)
660832{
661833 // regenerate focus
@@ -1049,6 +1221,12 @@ void Pet::Unsummon(PetSaveMode mode, Unit* owner /*= NULL*/)
10491221 }
10501222 break ;
10511223 }
1224+
1225+ if (m_transport)
1226+ {
1227+ m_transport->RemovePassenger (this );
1228+ m_transport = nullptr ;
1229+ }
10521230 }
10531231
10541232 SavePetToDB (mode);
0 commit comments