Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/game/MotionGenerators/TargetedMovementGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,27 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T& owner, bool up
// allow pets following their master to cheat while generating paths
bool forceDest = (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->IsPet()
&& owner.hasUnitState(UNIT_STAT_FOLLOW));

if (forceDest &&
(owner.m_movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT) ||
i_target->m_movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)))
{
bool outMoved = false;
if (((Creature*)&owner)->HandleTransportFollow(
i_target.getTarget(), i_offset, i_angle, ((D*)this)->EnableWalking(), outMoved))
{
if (outMoved)
{
D::_addUnitStateMove(owner);
i_targetReached = false;
m_speedChanged = false;
}
return;
}
}

i_path->calculate(x, y, z, forceDest);

if (i_path->getPathType() & PATHFIND_NOPATH)
{
return;
Expand Down
2 changes: 2 additions & 0 deletions src/game/Object/Creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,8 @@ class Creature : public Unit
bool IsSwimming() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_SWIMMING))); }
bool CanFly() const override { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_LEVITATING | MOVEFLAG_CAN_FLY)); }
bool IsFlying() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING | MOVEFLAG_LEVITATING))); }

virtual bool HandleTransportFollow(Unit* /*target*/, float /*offset*/, float /*angle*/, bool /*walking*/, bool& outMoved) { outMoved = false; return false; }
bool IsTrainerOf(Player* player, bool msg) const;
bool CanInteractWithBattleMaster(Player* player, bool msg) const;
bool CanTrainAndResetTalentsOf(Player* pPlayer) const;
Expand Down
192 changes: 186 additions & 6 deletions src/game/Object/Pet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
#include "Formulas.h"
#include "SpellAuras.h"
#include "Unit.h"
#include "Transports.h"
#include "movement/MoveSpline.h"
#include "movement/MoveSplineInit.h"


// numbers represent minutes * 100 while happy (you get 100 loyalty points per min while happy)
uint32 const LevelUpLoyalty[6] =
Expand All @@ -56,7 +60,7 @@ uint32 const LevelStartLoyalty[6] =
Pet::Pet(PetType type) :
Creature(CREATURE_SUBTYPE_PET),
m_TrainingPoints(0), m_resetTalentsCost(0), m_resetTalentsTime(0),
m_removed(false), m_happinessTimer(7500), m_loyaltyTimer(12000), m_petType(type), m_duration(0),
m_removed(false), m_pendingTransportReboard(false), m_transport(nullptr), m_happinessTimer(7500), m_loyaltyTimer(12000), m_petType(type), m_duration(0),
m_loyaltyPoints(0), m_bonusdamage(0), m_auraUpdateMask(0), m_loading(false),
m_petModeFlags(PET_MODE_DEFAULT)
{
Expand Down Expand Up @@ -351,6 +355,20 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c

}

Player* p_owner = owner->GetTypeId() == TYPEID_PLAYER ? (Player*)owner : nullptr;
Transport* ownerTransport = p_owner ? p_owner->GetTransport() : nullptr;

if (ownerTransport)
{
Position const* tpos = p_owner->m_movementInfo.GetTransportPos();
float petTo = tpos->o;
float petTx = tpos->x + cos(petTo + PET_FOLLOW_ANGLE) * PET_FOLLOW_DIST;
float petTy = tpos->y + sin(petTo + PET_FOLLOW_ANGLE) * PET_FOLLOW_DIST;
float petTz = tpos->z;
m_movementInfo.SetTransportData(ownerTransport->GetObjectGuid(), petTx, petTy, petTz, petTo, 0);
m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
}

map->Add((Creature*)this);
AIM_Initialize();

Expand All @@ -363,17 +381,25 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
owner->SetPet(this); // in DB stored only full controlled creature
DEBUG_LOG("New Pet has guid %u", GetGUIDLow());

if (owner->GetTypeId() == TYPEID_PLAYER)
if (p_owner)
{
((Player*)owner)->PetSpellInitialize();
if (((Player*)owner)->GetGroup())
p_owner->PetSpellInitialize();
if (p_owner->GetGroup())
{
((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_PET);
p_owner->SetGroupUpdateFlag(GROUP_UPDATE_PET);
}
}

m_loading = false;

if (ownerTransport)
{
ownerTransport->AddPassenger(this);
m_transport = ownerTransport;
GetMotionMaster()->Clear(false);
m_pendingTransportReboard = true;
}

SynchronizeLevelWithOwner();
return true;
}
Expand Down Expand Up @@ -619,13 +645,14 @@ void Pet::Update(uint32 update_diff, uint32 diff)
// unsummon pet that lost owner
Unit* owner = GetOwner();
if (!owner ||
(!IsWithinDistInMap(owner, GetMap()->GetVisibilityDistance()) && (owner->GetCharmGuid() && (owner->GetCharmGuid() != GetObjectGuid()))) ||
(!m_transport && !IsWithinDistInMap(owner, GetMap()->GetVisibilityDistance()) && (owner->GetCharmGuid() && (owner->GetCharmGuid() != GetObjectGuid()))) ||
(isControlled() && !owner->GetPetGuid()))
{
Unsummon(PET_SAVE_REAGENTS);
return;
}


if (isControlled())
{
if (owner->GetPetGuid() != GetObjectGuid())
Expand All @@ -647,6 +674,10 @@ void Pet::Update(uint32 update_diff, uint32 diff)
return;
}
}

if (Player* plOwner = owner->ToPlayer())
UpdateTransport(plOwner);

break;
}
default:
Expand All @@ -656,6 +687,144 @@ void Pet::Update(uint32 update_diff, uint32 diff)
Creature::Update(update_diff, diff);
}

void Pet::UpdateTransport(Player* plOwner)
{
Transport* tr = plOwner->GetTransport();

// Disembark if the owner has left the transport but the pet hasn't yet.
if (m_transport && tr != m_transport)
{
m_transport->RemovePassenger(this);
m_transport = nullptr;
m_movementInfo.RemoveMovementFlag(MOVEFLAG_ONTRANSPORT);
m_movementInfo.ClearTransportData();
NearTeleportTo(plOwner->GetPositionX(), plOwner->GetPositionY(),
plOwner->GetPositionZ(), plOwner->GetOrientation());
}
else // Board pet onto transport once it has swum/walked close enough to the owner.
if (!m_transport && tr)
{
float dx = GetPositionX() - plOwner->GetPositionX();
float dy = GetPositionY() - plOwner->GetPositionY();
float dist2d = sqrt(dx*dx + dy*dy);
if (dist2d <= 6.0f)
{
tr->AddPassenger(this);
m_transport = tr;
Position const* tpos = plOwner->m_movementInfo.GetTransportPos();
m_movementInfo.SetTransportData(tr->GetObjectGuid(), tpos->x, tpos->y, tpos->z, tpos->o, 0);
m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
m_movementInfo.ChangePosition(plOwner->GetPositionX(), plOwner->GetPositionY(), plOwner->GetPositionZ(), plOwner->GetOrientation());
GetMotionMaster()->Clear(false);
if (GetCharmInfo())
GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
NearTeleportTo(plOwner->GetPositionX(), plOwner->GetPositionY(), plOwner->GetPositionZ(), plOwner->GetOrientation());
if (movespline)
{
WorldPacket moveData(SMSG_MONSTER_MOVE_TRANSPORT, 64);
moveData << GetPackGUID();
moveData << tr->GetPackGUID();
moveData << tpos->x << tpos->y << tpos->z;
moveData << movespline->GetId();
moveData << uint8(Movement::MonsterMoveStop);
SendMessageToSet(&moveData, true);
}
SendCreateUpdateToPlayer(plOwner);
}
}

if (m_pendingTransportReboard)
{
m_pendingTransportReboard = false;
plOwner->PetSpellInitialize();
if (tr && movespline)
{
Position const* tpos = m_movementInfo.GetTransportPos();
WorldPacket moveData(SMSG_MONSTER_MOVE_TRANSPORT, 64);
moveData << GetPackGUID();
moveData << tr->GetPackGUID();
moveData << tpos->x << tpos->y << tpos->z;
moveData << movespline->GetId();
moveData << uint8(Movement::MonsterMoveStop);
plOwner->SendDirectMessage(&moveData);
}
SendCreateUpdateToPlayer(plOwner);
}
}

bool Pet::HandleTransportFollow(Unit* target, float offset, float angle, bool walking, bool& outMoved)
{
outMoved = false;
if (!target || target->GetTypeId() != TYPEID_PLAYER)
return false;

Transport* masterTransport = static_cast<Player*>(target)->GetTransport();
if (!masterTransport)
return false;

if (m_transport == masterTransport)
{
// Both on the same transport — move in transport-relative space.
float tx = masterTransport->GetPositionX();
float ty = masterTransport->GetPositionY();
float tz = masterTransport->GetPositionZ();
float to = masterTransport->GetOrientation();
float cos_o = cos(to), sin_o = sin(to);

Position const* curRelPos = m_movementInfo.GetTransportPos();
float startRelX = curRelPos->x, startRelY = curRelPos->y, startRelZ = curRelPos->z;

Position const* masterTPos = target->m_movementInfo.GetTransportPos();
float followDist = offset + GetObjectBoundingRadius() + target->GetObjectBoundingRadius();
float destRelX = masterTPos->x + cos(angle) * followDist;
float destRelY = masterTPos->y + sin(angle) * followDist;
float destRelZ = masterTPos->z;

float relDx = destRelX - startRelX, relDy = destRelY - startRelY, relDz = destRelZ - startRelZ;
float relDist = sqrt(relDx * relDx + relDy * relDy + relDz * relDz);
if (relDist < 0.5f)
return true;

m_movementInfo.SetTransportData(masterTransport->GetObjectGuid(), destRelX, destRelY, destRelZ, 0.0f, 0);

float speed = GetSpeed(walking ? MOVE_WALK : MOVE_RUN);
uint32 durationMs = (speed > 0.0f) ? uint32(relDist / speed * 1000.0f) : 0;

float destWX = tx + cos_o * destRelX - sin_o * destRelY;
float destWY = ty + sin_o * destRelX + cos_o * destRelY;
float destWZ = tz + destRelZ;
GetMap()->CreatureRelocation(this, destWX, destWY, destWZ, GetOrientation());

if (durationMs > 0)
{
WorldPacket moveTransport(SMSG_MONSTER_MOVE_TRANSPORT, 80);
moveTransport << GetPackGUID();
moveTransport << masterTransport->GetPackGUID();
moveTransport << startRelX << startRelY << startRelZ;
moveTransport << movespline->GetId();
moveTransport << uint8(Movement::MonsterMoveNormal);
moveTransport << uint32(Movement::MoveSplineFlag::Runmode);
moveTransport << durationMs;
moveTransport << uint32(0);
moveTransport << destRelX << destRelY << destRelZ;
SendMessageToSet(&moveTransport, true);
}

outMoved = true;
return true;
}

// Master is on a transport the pet hasn't boarded yet — approach in world space.
float tx, ty, tz;
target->GetPosition(tx, ty, tz);
Movement::MoveSplineInit init(*this);
init.MoveTo(tx, ty, tz);
init.SetWalk(walking);
init.Launch();
outMoved = true;
return true;
}

void Pet::RegenerateAll(uint32 update_diff)
{
// regenerate focus
Expand Down Expand Up @@ -1049,6 +1218,17 @@ void Pet::Unsummon(PetSaveMode mode, Unit* owner /*= NULL*/)
}
break;
}

if (m_transport)
{
m_transport->RemovePassenger(this);
m_transport = nullptr;
}
}
else if (m_transport)
{
m_transport->RemovePassenger(this);
m_transport = nullptr;
}

SavePetToDB(mode);
Expand Down
14 changes: 14 additions & 0 deletions src/game/Object/Pet.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include "Creature.h"
#include "Unit.h"

class Transport;

enum PetType
{
SUMMON_PET = 0,
Expand Down Expand Up @@ -298,6 +300,13 @@ class Pet : public Creature
const char* GetNameForLocaleIdx(int32 locale_idx) const override { return WorldObject::GetNameForLocaleIdx(locale_idx); }

bool m_removed; // prevent overwrite pet state in DB at next Pet::Update if pet already removed(saved)

bool HandleTransportFollow(Unit* target, float offset, float angle, bool walking, bool& outMoved) override;

Transport* GetTransport() const { return m_transport; }
void SetTransport(Transport* t) { m_transport = t; }
void SetPendingTransportReboard() { m_pendingTransportReboard = true; }

protected:
uint32 m_happinessTimer;
uint32 m_loyaltyTimer;
Expand All @@ -309,6 +318,11 @@ class Pet : public Creature
bool m_loading;

private:
void UpdateTransport(Player* plOwner);

bool m_pendingTransportReboard; ///< fires PetSpellInitialize + SMSG_MONSTER_MOVE_TRANSPORT on next tick after map re-add
Transport* m_transport; ///< transport this pet is riding; set/cleared alongside AddPassenger/RemovePassenger

PetModeFlags m_petModeFlags;

void SaveToDB(uint32) override // overwrited of Creature::SaveToDB - don't must be called
Expand Down
16 changes: 16 additions & 0 deletions src/game/Object/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20901,6 +20901,9 @@ void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* targe

if (target->GetTypeId() == TYPEID_UNIT)
{
Creature* c = target->ToCreature();
if (c->IsPet() && GetPetGuid() == c->GetObjectGuid() && ((Pet*)c)->GetTransport())
return;
BeforeVisibilityDestroy(target, this);
}

Expand Down Expand Up @@ -20939,6 +20942,13 @@ void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* targe
{
if (!target->IsVisibleForInState(this, viewPoint, true))
{
if (target->GetTypeId() == TYPEID_UNIT)
{
Creature* c = target->ToCreature();
if (c->IsPet() && GetPetGuid() == c->GetObjectGuid() && ((Pet*)c)->GetTransport())
return;
}

BeforeVisibilityDestroy(target, this);

ObjectGuid t_guid = target->GetObjectGuid();
Expand Down Expand Up @@ -23049,6 +23059,12 @@ void Player::UnsummonPetTemporaryIfAny()
m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber();
}

if (Transport* petTransport = pet->GetTransport())
{
petTransport->RemovePassenger(pet);
pet->SetTransport(nullptr);
}

pet->Unsummon(PET_SAVE_AS_CURRENT, this);
}

Expand Down
1 change: 1 addition & 0 deletions src/game/WorldHandlers/MovementHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#define MOVEMENT_PACKET_TIME_DELAY 300


void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket& /*recv_data*/)
{
DEBUG_LOG("WORLD: got MSG_MOVE_WORLDPORT_ACK.");
Expand Down
Loading