aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Object/Object.cpp6
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp16
-rw-r--r--src/server/game/Entities/Pet/Pet.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp45
-rw-r--r--src/server/game/Entities/Player/Player.h4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp32
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp3
-rw-r--r--src/server/game/Handlers/PetHandler.cpp3
-rw-r--r--src/server/game/Server/Packets/PetPackets.cpp9
-rw-r--r--src/server/game/Server/Packets/PetPackets.h13
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
11 files changed, 96 insertions, 39 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index a83dfea2a48..39b83cf62a1 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -3068,9 +3068,13 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const
if (IsFriendlyTo(target) || target->IsFriendlyTo(this))
return false;
- Player const* playerAffectingAttacker = unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) ? GetAffectingPlayer() : go ? GetAffectingPlayer() : nullptr;
+ Player const* playerAffectingAttacker = (unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) || go ? GetAffectingPlayer() : nullptr;
Player const* playerAffectingTarget = unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) ? unitTarget->GetAffectingPlayer() : nullptr;
+ // Pets of mounted players are immune to NPCs
+ if (!playerAffectingAttacker && unitTarget && unitTarget->IsPet() && playerAffectingTarget && playerAffectingTarget->IsMounted())
+ return false;
+
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
{
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index e4e367c1d94..dd66132f216 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -244,6 +244,8 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
return false;
}
+ owner->SetTemporaryUnsummonedPetNumber(0);
+
Map* map = owner->GetMap();
ObjectGuid::LowType guid = map->GenerateLowGuid<HighGuid::Pet>();
@@ -366,9 +368,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
uint32 newPetIndex = std::distance(petStable->ActivePets.begin(), activePetItr);
- // Check that we either have no pet (unsummoned by player) or it matches temporarily unsummoned pet by server (for example on flying mount)
- ASSERT(!petStable->CurrentPetIndex || petStable->CurrentPetIndex == newPetIndex);
-
petStable->SetCurrentActivePetIndex(newPetIndex);
}
@@ -456,6 +455,9 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
}
}
+ if (owner->IsMounted())
+ owner->DisablePetControlsOnMount(REACT_PASSIVE, COMMAND_FOLLOW);
+
// must be after SetMinion (owner guid check)
LoadTemplateImmunities();
m_loading = false;
@@ -525,7 +527,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
std::string actionBar = GenerateActionBarData();
ASSERT(owner->GetPetStable()->GetCurrentPet() && owner->GetPetStable()->GetCurrentPet()->PetNumber == m_charmInfo->GetPetNumber());
- FillPetInfo(owner->GetPetStable()->GetCurrentPet());
+ FillPetInfo(owner->GetPetStable()->GetCurrentPet(), owner->GetTemporaryPetReactState());
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET);
stmt->setUInt32(0, m_charmInfo->GetPetNumber());
@@ -534,7 +536,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
stmt->setUInt32(3, GetNativeDisplayId());
stmt->setUInt8(4, GetLevel());
stmt->setUInt32(5, m_unitData->PetExperience);
- stmt->setUInt8(6, GetReactState());
+ stmt->setUInt8(6, owner->GetTemporaryPetReactState().value_or(GetReactState()));
stmt->setInt16(7, owner->GetPetStable()->GetCurrentActivePetIndex().value_or(PET_SAVE_NOT_IN_SLOT));
stmt->setString(8, m_name);
stmt->setUInt8(9, HasPetFlag(UNIT_PET_FLAG_CAN_BE_RENAMED) ? 0 : 1);
@@ -557,14 +559,14 @@ void Pet::SavePetToDB(PetSaveMode mode)
}
}
-void Pet::FillPetInfo(PetStable::PetInfo* petInfo) const
+void Pet::FillPetInfo(PetStable::PetInfo* petInfo, Optional<ReactStates> forcedReactState /*= {}*/) const
{
petInfo->PetNumber = m_charmInfo->GetPetNumber();
petInfo->CreatureId = GetEntry();
petInfo->DisplayId = GetNativeDisplayId();
petInfo->Level = GetLevel();
petInfo->Experience = m_unitData->PetExperience;
- petInfo->ReactState = GetReactState();
+ petInfo->ReactState = forcedReactState.value_or(GetReactState());
petInfo->Name = GetName();
petInfo->WasRenamed = !HasPetFlag(UNIT_PET_FLAG_CAN_BE_RENAMED);
petInfo->Health = GetHealth();
diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h
index a03ab823bb4..64bd4836999 100644
--- a/src/server/game/Entities/Pet/Pet.h
+++ b/src/server/game/Entities/Pet/Pet.h
@@ -63,7 +63,7 @@ class TC_GAME_API Pet : public Guardian
bool LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool current, Optional<PetSaveMode> forcedSlot = {});
bool IsLoading() const override { return m_loading;}
void SavePetToDB(PetSaveMode mode);
- void FillPetInfo(PetStable::PetInfo* petInfo) const;
+ void FillPetInfo(PetStable::PetInfo* petInfo, Optional<ReactStates> forcedReactState = {}) const;
void Remove(PetSaveMode mode, bool returnreagent = false);
static void DeleteFromDB(uint32 petNumber);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index a52afe95a6d..ff98de25a2e 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -26686,6 +26686,49 @@ void Player::UpdateFallInformationIfNeed(MovementInfo const& minfo, uint16 opcod
SetFallInformation(minfo.jump.fallTime, minfo.pos.GetPositionZ());
}
+void Player::DisablePetControlsOnMount(ReactStates reactState, CommandStates commandState)
+{
+ Pet* pet = GetPet();
+ if (!pet)
+ return;
+
+ m_temporaryPetReactState = pet->GetReactState();
+ pet->SetReactState(reactState);
+ if (CharmInfo* charmInfo = pet->GetCharmInfo())
+ charmInfo->SetCommandState(commandState);
+
+ pet->GetMotionMaster()->MoveFollow(this, PET_FOLLOW_DIST, pet->GetFollowAngle());
+
+ WorldPackets::Pet::PetMode petMode;
+ petMode.PetGUID = pet->GetGUID();
+ petMode.ReactState = reactState;
+ petMode.CommandState = commandState;
+ petMode.Flag = 0;
+ SendDirectMessage(petMode.Write());
+}
+
+void Player::EnablePetControlsOnDismount()
+{
+ if (Pet* pet = GetPet())
+ {
+ WorldPackets::Pet::PetMode petMode;
+ petMode.PetGUID = pet->GetGUID();
+ if (m_temporaryPetReactState)
+ {
+ petMode.ReactState = *m_temporaryPetReactState;
+ pet->SetReactState(*m_temporaryPetReactState);
+ }
+
+ if (CharmInfo* charmInfo = pet->GetCharmInfo())
+ petMode.CommandState = charmInfo->GetCommandState();
+
+ petMode.Flag = 0;
+ SendDirectMessage(petMode.Write());
+ }
+
+ m_temporaryPetReactState.reset();
+}
+
void Player::UnsummonPetTemporaryIfAny()
{
Pet* pet = GetPet();
@@ -26722,7 +26765,7 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
bool Player::IsPetNeedBeTemporaryUnsummoned() const
{
- return !IsInWorld() || !IsAlive() || IsMounted() /*+in flight*/;
+ return !IsInWorld() || !IsAlive() || HasUnitMovementFlag(MOVEMENTFLAG_FLYING) || HasExtraUnitMovementFlag2(MOVEMENTFLAG3_ADV_FLYING);
}
bool Player::CanSeeSpellClickOn(Creature const* c) const
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index adf692b7507..58adcd3424f 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2531,6 +2531,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
// Temporarily removed pet cache
uint32 GetTemporaryUnsummonedPetNumber() const { return m_temporaryUnsummonedPetNumber; }
void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; }
+ Optional<ReactStates> GetTemporaryPetReactState() const { return m_temporaryPetReactState; }
+ void DisablePetControlsOnMount(ReactStates reactState, CommandStates commandState);
+ void EnablePetControlsOnDismount();
void UnsummonPetTemporaryIfAny();
void ResummonPetTemporaryUnSummonedIfAny();
bool IsPetNeedBeTemporaryUnsummoned() const;
@@ -3172,6 +3175,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
// Temporary removed pet cache
uint32 m_temporaryUnsummonedPetNumber;
+ Optional<ReactStates> m_temporaryPetReactState;
uint32 m_oldpetspell;
std::unique_ptr<PlayerAchievementMgr> m_achievementMgr;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index dd1525cb783..c017eb0261c 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -7766,22 +7766,8 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
}
}
- // unsummon pet
- Pet* pet = player->GetPet();
- if (pet)
- {
- Battleground* bg = ToPlayer()->GetBattleground();
- // don't unsummon pet in arena but SetFlag UNIT_FLAG_STUNNED to disable pet's interface
- if (bg && bg->isArena())
- pet->SetUnitFlag(UNIT_FLAG_STUNNED);
- else
- player->UnsummonPetTemporaryIfAny();
- }
-
- // if we have charmed npc, stun him also (everywhere)
- if (Unit* charm = player->GetCharmed())
- if (charm->GetTypeId() == TYPEID_UNIT)
- charm->SetUnitFlag(UNIT_FLAG_STUNNED);
+ // disable pet controls
+ player->DisablePetControlsOnMount(REACT_PASSIVE, COMMAND_FOLLOW);
player->SendMovementSetCollisionHeight(player->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
}
@@ -7816,18 +7802,8 @@ void Unit::Dismount()
// (it could probably happen when logging in after a previous crash)
if (Player* player = ToPlayer())
{
- if (Pet* pPet = player->GetPet())
- {
- if (pPet->HasUnitFlag(UNIT_FLAG_STUNNED) && !pPet->HasUnitState(UNIT_STATE_STUNNED))
- pPet->RemoveUnitFlag(UNIT_FLAG_STUNNED);
- }
- else
- player->ResummonPetTemporaryUnSummonedIfAny();
-
- // if we have charmed npc, remove stun also
- if (Unit* charm = player->GetCharmed())
- if (charm->GetTypeId() == TYPEID_UNIT && charm->HasUnitFlag(UNIT_FLAG_STUNNED) && !charm->HasUnitState(UNIT_STATE_STUNNED))
- charm->RemoveUnitFlag(UNIT_FLAG_STUNNED);
+ player->EnablePetControlsOnDismount();
+ player->ResummonPetTemporaryUnSummonedIfAny();
}
}
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 6f9dfa69337..103daba53d3 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -401,6 +401,9 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem
if (opcode == CMSG_MOVE_FALL_LAND || opcode == CMSG_MOVE_START_SWIM || opcode == CMSG_MOVE_SET_FLY)
mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::LandingOrFlight); // Parachutes
+ if (opcode == CMSG_MOVE_SET_FLY || opcode == CMSG_MOVE_SET_ADV_FLY)
+ _player->UnsummonPetTemporaryIfAny(); // always do the pet removal on current client activeplayer only
+
/* process position-change */
movementInfo.guid = mover->GetGUID();
movementInfo.time = AdjustClientMovementTime(movementInfo.time);
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index d05e6c5b181..268c839f237 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -62,6 +62,9 @@ void WorldSession::HandleDismissCritter(WorldPackets::Pet::DismissCritter& packe
void WorldSession::HandlePetAction(WorldPackets::Pet::PetAction& packet)
{
+ if (_player->IsMounted())
+ return;
+
ObjectGuid guid1 = packet.PetGUID; //pet guid
ObjectGuid guid2 = packet.TargetGUID; //tag guid
diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp
index ff8b278461a..089db0e4daa 100644
--- a/src/server/game/Server/Packets/PetPackets.cpp
+++ b/src/server/game/Server/Packets/PetPackets.cpp
@@ -195,3 +195,12 @@ WorldPacket const* WorldPackets::Pet::PetTameFailure::Write()
return &_worldPacket;
}
+
+WorldPacket const* WorldPackets::Pet::PetMode::Write()
+{
+ _worldPacket << PetGUID;
+ _worldPacket << uint16(CommandState | Flag << 8);
+ _worldPacket << uint8(ReactState);
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h
index 0d3aaaccbad..5acb43ee839 100644
--- a/src/server/game/Server/Packets/PetPackets.h
+++ b/src/server/game/Server/Packets/PetPackets.h
@@ -257,6 +257,19 @@ namespace WorldPackets
uint8 Result = 0;
};
+
+ class PetMode final : public ServerPacket
+ {
+ public:
+ PetMode() : ServerPacket(SMSG_PET_MODE, 16 + 2 + 1) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid PetGUID;
+ ReactStates ReactState = REACT_PASSIVE;
+ CommandStates CommandState = COMMAND_STAY;
+ uint8 Flag = 0;
+ };
}
}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 9d017c8d871..9c3d530ed5f 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -1810,7 +1810,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_GOD_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_GUIDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_LEARNED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_MODE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_NAME_INVALID, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_NEWLY_TAMED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_SPELLS_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);