Skip to content

Commit 42a24e7

Browse files
committed
Pets on Transports
1 parent 37120ec commit 42a24e7

8 files changed

Lines changed: 268 additions & 19 deletions

File tree

src/game/MotionGenerators/TargetedMovementGenerator.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,27 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T& owner, bool up
9696
// allow pets following their master to cheat while generating paths
9797
bool forceDest = (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->IsPet()
9898
&& owner.hasUnitState(UNIT_STAT_FOLLOW));
99+
100+
if (forceDest &&
101+
(owner.m_movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT) ||
102+
i_target->m_movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)))
103+
{
104+
bool outMoved = false;
105+
if (((Creature*)&owner)->HandleTransportFollow(
106+
i_target.getTarget(), i_offset, i_angle, ((D*)this)->EnableWalking(), outMoved))
107+
{
108+
if (outMoved)
109+
{
110+
D::_addUnitStateMove(owner);
111+
i_targetReached = false;
112+
m_speedChanged = false;
113+
}
114+
return;
115+
}
116+
}
117+
99118
i_path->calculate(x, y, z, forceDest);
119+
100120
if (i_path->getPathType() & PATHFIND_NOPATH)
101121
{
102122
return;

src/game/Object/Creature.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,8 @@ class Creature : public Unit
554554
bool IsSwimming() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_SWIMMING))); }
555555
bool CanFly() const override { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_LEVITATING | MOVEFLAG_CAN_FLY)); }
556556
bool IsFlying() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING | MOVEFLAG_LEVITATING))); }
557+
558+
virtual bool HandleTransportFollow(Unit* /*target*/, float /*offset*/, float /*angle*/, bool /*walking*/, bool& outMoved) { outMoved = false; return false; }
557559
bool IsTrainerOf(Player* player, bool msg) const;
558560
bool CanInteractWithBattleMaster(Player* player, bool msg) const;
559561
bool CanTrainAndResetTalentsOf(Player* pPlayer) const;

src/game/Object/Pet.cpp

Lines changed: 180 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
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)
3640
uint32 const LevelUpLoyalty[6] =
@@ -56,7 +60,7 @@ uint32 const LevelStartLoyalty[6] =
5660
Pet::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+
659831
void 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);

src/game/Object/Pet.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include "Creature.h"
3131
#include "Unit.h"
3232

33+
class Transport;
34+
3335
enum PetType
3436
{
3537
SUMMON_PET = 0,
@@ -298,6 +300,13 @@ class Pet : public Creature
298300
const char* GetNameForLocaleIdx(int32 locale_idx) const override { return WorldObject::GetNameForLocaleIdx(locale_idx); }
299301

300302
bool m_removed; // prevent overwrite pet state in DB at next Pet::Update if pet already removed(saved)
303+
304+
bool HandleTransportFollow(Unit* target, float offset, float angle, bool walking, bool& outMoved) override;
305+
306+
Transport* GetTransport() const { return m_transport; }
307+
void SetTransport(Transport* t) { m_transport = t; }
308+
void SetPendingTransportReboard() { m_pendingTransportReboard = true; }
309+
301310
protected:
302311
uint32 m_happinessTimer;
303312
uint32 m_loyaltyTimer;
@@ -309,6 +318,11 @@ class Pet : public Creature
309318
bool m_loading;
310319

311320
private:
321+
void UpdateTransport(Player* plOwner);
322+
323+
bool m_pendingTransportReboard; ///< fires PetSpellInitialize + SMSG_MONSTER_MOVE_TRANSPORT on next tick after map re-add
324+
Transport* m_transport; ///< transport this pet is riding; set/cleared alongside AddPassenger/RemovePassenger
325+
312326
PetModeFlags m_petModeFlags;
313327

314328
void SaveToDB(uint32) override // overwrited of Creature::SaveToDB - don't must be called

src/game/Object/Player.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20901,6 +20901,9 @@ void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* targe
2090120901

2090220902
if (target->GetTypeId() == TYPEID_UNIT)
2090320903
{
20904+
if (Creature* c = ((WorldObject*)target)->ToCreature())
20905+
if (c->IsPet() && GetPetGuid() == c->GetObjectGuid() && ((Pet*)c)->GetTransport())
20906+
return;
2090420907
BeforeVisibilityDestroy(target, this);
2090520908
}
2090620909

@@ -20939,6 +20942,13 @@ void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* targe
2093920942
{
2094020943
if (!target->IsVisibleForInState(this, viewPoint, true))
2094120944
{
20945+
if (target->GetTypeId() == TYPEID_UNIT)
20946+
{
20947+
if (Creature* c = ((WorldObject*)target)->ToCreature())
20948+
if (c->IsPet() && GetPetGuid() == c->GetObjectGuid() && ((Pet*)c)->GetTransport())
20949+
return;
20950+
}
20951+
2094220952
BeforeVisibilityDestroy(target, this);
2094320953

2094420954
ObjectGuid t_guid = target->GetObjectGuid();
@@ -23049,6 +23059,12 @@ void Player::UnsummonPetTemporaryIfAny()
2304923059
m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber();
2305023060
}
2305123061

23062+
if (Transport* petTransport = pet->GetTransport())
23063+
{
23064+
petTransport->RemovePassenger(pet);
23065+
pet->SetTransport(nullptr);
23066+
}
23067+
2305223068
pet->Unsummon(PET_SAVE_AS_CURRENT, this);
2305323069
}
2305423070

src/game/WorldHandlers/MovementHandler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#define MOVEMENT_PACKET_TIME_DELAY 300
3939

40+
4041
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket& /*recv_data*/)
4142
{
4243
DEBUG_LOG("WORLD: got MSG_MOVE_WORLDPORT_ACK.");

0 commit comments

Comments
 (0)