diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 063a00d8c..5139ce329 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -40,7 +40,7 @@ char const* petTypeSuffix[MAX_PET_TYPE] = Pet::Pet(PetType type) : Creature(), m_removed(false), m_petType(type), m_happinessTimer(7500), m_duration(0), m_resetTalentsCost(0), m_bonusdamage(0), m_resetTalentsTime(0), m_usedTalentCount(0), m_auraUpdateMask(0), m_loading(false), -m_declinedname(NULL) +m_declinedname(NULL), m_petModeFlags(PET_MODE_DEFAULT) { m_isPet = true; m_name = "Pet"; @@ -1948,3 +1948,20 @@ void Pet::SynchronizeLevelWithOwner() break; } } + +void Pet::ApplyModeFlags(PetModeFlags mode, bool apply) +{ + if (apply) + m_petModeFlags = PetModeFlags(m_petModeFlags | mode); + else + m_petModeFlags = PetModeFlags(m_petModeFlags & ~mode); + + Unit* owner = GetOwner(); + if(!owner || owner->GetTypeId()!=TYPEID_PLAYER) + return; + + WorldPacket data(SMSG_PET_MODE, 12); + data << uint64(GetGUID()); + data << uint32(m_petModeFlags); + ((Player*)owner)->GetSession()->SendPacket(&data); +} diff --git a/src/game/Pet.h b/src/game/Pet.h index 600a1d535..4c6d3f70e 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -46,6 +46,17 @@ enum PetSaveMode PET_SAVE_NOT_IN_SLOT = 100 // for avoid conflict with stable size grow will use 100 }; +// There might be a lot more +enum PetModeFlags +{ + PET_MODE_UNKNOWN_0 = 0x0000001, + PET_MODE_UNKNOWN_2 = 0x0000100, + PET_MODE_DISABLE_ACTIONS = 0x8000000, + + // autoset in client at summon + PET_MODE_DEFAULT = PET_MODE_UNKNOWN_0 | PET_MODE_UNKNOWN_2, +}; + enum HappinessState { UNHAPPY = 1, @@ -182,6 +193,9 @@ class Pet : public Creature bool CanTakeMoreActiveSpells(uint32 SpellIconID); void ToggleAutocast(uint32 spellid, bool apply); + void ApplyModeFlags(PetModeFlags mode, bool apply); + PetModeFlags GetModeFlags() const { return m_petModeFlags; } + bool HasSpell(uint32 spell) const; void LearnPetPassives(); @@ -242,6 +256,8 @@ class Pet : public Creature DeclinedName *m_declinedname; private: + PetModeFlags m_petModeFlags; + void SaveToDB(uint32, uint8) // overwrited of Creature::SaveToDB - don't must be called { assert(false); diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp index 354ef371a..3b305dfc7 100644 --- a/src/game/PetAI.cpp +++ b/src/game/PetAI.cpp @@ -44,9 +44,16 @@ PetAI::PetAI(Creature *c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK), inComb void PetAI::MoveInLineOfSight(Unit *u) { - if( !m_creature->getVictim() && m_creature->GetCharmInfo() && - m_creature->GetCharmInfo()->HasReactState(REACT_AGGRESSIVE) && - u->isTargetableForAttack() && m_creature->IsHostileTo( u ) && + if (m_creature->getVictim()) + return; + + if (m_creature->isPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) + return; + + if (!m_creature->GetCharmInfo() || !m_creature->GetCharmInfo()->HasReactState(REACT_AGGRESSIVE)) + return; + + if (u->isTargetableForAttack() && m_creature->IsHostileTo( u ) && u->isInAccessablePlaceFor(m_creature)) { float attackRadius = m_creature->GetAttackDistance(u); @@ -139,7 +146,7 @@ void PetAI::UpdateAI(const uint32 diff) else m_updateAlliesTimer -= diff; - if (inCombat && !m_creature->getVictim()) + if (inCombat && (!m_creature->getVictim() || m_creature->isPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)) _stopAttack(); // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 8dc158f3d..a732d69d2 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -44,23 +44,33 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) // used also for charmed creature Unit* pet= ObjectAccessor::GetUnit(*_player, guid1); sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2)) ); - if(!pet) + if (!pet) { sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid1)) ); return; } - if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm()) + if (pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm()) { sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName() ); return; } - if(!pet->isAlive()) + if (!pet->isAlive()) return; - if(pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK)) - return; + if (pet->GetTypeId() == TYPEID_PLAYER) + { + // controller player can only do melee attack + if (!(flag == ACT_COMMAND && spellid == COMMAND_ATTACK)) + return; + } + else if (((Creature*)pet)->isPet()) + { + // pet can have action bar disabled + if(((Pet*)pet)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) + return; + } CharmInfo *charmInfo = pet->GetCharmInfo(); if(!charmInfo) @@ -316,6 +326,10 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) return; } + // pet can have action bar disabled + if(pet->isPet() && ((Pet*)pet)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) + return; + CharmInfo *charmInfo = pet->GetCharmInfo(); if(!charmInfo) { diff --git a/src/game/Player.cpp b/src/game/Player.cpp index fdc8e9adf..f9a7af4b9 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -17095,6 +17095,18 @@ void Player::PetSpellInitialize() GetSession()->SendPacket(&data); } +void Player::SendPetGUIDs() +{ + if(!GetPetGUID()) + return; + + // Later this function might get modified for multiple guids + WorldPacket data(SMSG_PET_GUIDS, 12); + data << uint32(1); // count + data << uint64(GetPetGUID()); + GetSession()->SendPacket(&data); +} + void Player::PossessSpellInitialize() { Unit* charm = GetCharm(); diff --git a/src/game/Player.h b/src/game/Player.h index 97412964d..9b3669a55 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1551,6 +1551,7 @@ class MANGOS_DLL_SPEC Player : public Unit } void PetSpellInitialize(); + void SendPetGUIDs(); void CharmSpellInitialize(); void PossessSpellInitialize(); void RemovePetActionBar(); diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 83488b3d4..43f87c5f9 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -2817,7 +2817,7 @@ void Aura::HandleAuraMounted(bool apply, bool Real) if (minfo) display_id = minfo->modelid; - m_target->Mount(display_id); + m_target->Mount(display_id, m_spellProto->Id); } else { diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index d59a2bcb8..57feb9ddd 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -8382,6 +8382,9 @@ void Unit::SetPet(Pet* pet) { SetPetGUID(pet ? pet->GetGUID() : 0); + if(pet && GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SendPetGUIDs(); + // FIXME: hack, speed must be set only at follow if(pet && GetTypeId()==TYPEID_PLAYER) for(int i = 0; i < MAX_MOVE_TYPE; ++i) @@ -9866,9 +9869,9 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const return WeaponSpeed * PPM / 600.0f; // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) } -void Unit::Mount(uint32 mount) +void Unit::Mount(uint32 mount, uint32 spellId) { - if(!mount) + if (!mount) return; RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING); @@ -9877,9 +9880,27 @@ void Unit::Mount(uint32 mount) SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); - // unsummon pet - if(GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->UnsummonPetTemporaryIfAny(); + if (GetTypeId() == TYPEID_PLAYER) + { + // Called by Taxi system / GM command + if (!spellId) + ((Player*)this)->UnsummonPetTemporaryIfAny(); + // Called by mount aura + else if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId)) + { + // Flying case (Unsummon any pet) + if (IsSpellHaveAura(spellInfo, SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED)) + ((Player*)this)->UnsummonPetTemporaryIfAny(); + // Normal case (Unsummon only permanent pet) + else if (Pet* pet = GetPet()) + { + if (pet->IsPermanentPetFor((Player*)this)) + ((Player*)this)->UnsummonPetTemporaryIfAny(); + else + pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS,true); + } + } + } } void Unit::Unmount() @@ -9896,7 +9917,12 @@ void Unit::Unmount() // this prevents adding a pet to a not created map which would otherwise cause a crash // (it could probably happen when logging in after a previous crash) if(GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny(); + { + if(Pet* pet = GetPet()) + pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS,false); + else + ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny(); + } } void Unit::SetInCombatWith(Unit* enemy) diff --git a/src/game/Unit.h b/src/game/Unit.h index 81b84dc33..304070422 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1026,7 +1026,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject bool IsMounted() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); } uint32 GetMountID() const { return GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID); } - void Mount(uint32 mount); + void Mount(uint32 mount, uint32 spellId = 0); void Unmount(); uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index ab8406b93..638ad70bf 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "9076" + #define REVISION_NR "9077" #endif // __REVISION_NR_H__