diff --git a/src/game/Creature.h b/src/game/Creature.h index b4f335cc9..f0025a9c6 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -238,13 +238,18 @@ struct CreatureInfo return SKILL_SKINNING; // normal case } + bool IsExotic() const + { + return (type_flags & CREATURE_TYPEFLAGS_EXOTIC); + } + bool isTameable(bool exotic) const { - if(type != CREATURE_TYPE_BEAST || family == 0 || (type_flags & CREATURE_TYPEFLAGS_TAMEABLE)==0) + if(type != CREATURE_TYPE_BEAST || family == 0 || (type_flags & CREATURE_TYPEFLAGS_TAMEABLE) == 0) return false; // if can tame exotic then can tame any temable - return exotic || (type_flags & CREATURE_TYPEFLAGS_EXOTIC)==0; + return exotic || !IsExotic(); } }; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 8f61a741d..ed1232e8e 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -12572,6 +12572,13 @@ bool Player::CanRewardQuest( Quest const *pQuest, uint32 reward, bool msg ) return true; } +void Player::SendPetTameFailure(PetTameFailureReason reason) +{ + WorldPacket data(SMSG_PET_TAME_FAILURE, 1); + data << uint8(reason); + GetSession()->SendPacket(&data); +} + void Player::AddQuest( Quest const *pQuest, Object *questGiver ) { uint16 log_slot = FindQuestSlot( 0 ); diff --git a/src/game/Player.h b/src/game/Player.h index 78aa5d945..ff6a185d3 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1418,6 +1418,8 @@ class MANGOS_DLL_SPEC Player : public Unit bool m_mailsLoaded; bool m_mailsUpdated; + void SendPetTameFailure(PetTameFailureReason reason); + void SetBindPoint(uint64 guid); void SendTalentWipeConfirm(uint64 guid); void RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ); diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 37c38c742..83945c8e2 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -2640,4 +2640,23 @@ enum MailResponseResult MAIL_ERR_ITEM_HAS_EXPIRED = 21, }; +// reasons for why pet tame may fail +// in fact, these are also used elsewhere +enum PetTameFailureReason +{ + PETTAME_INVALIDCREATURE = 0, + PETTAME_TOOMANY = 1, + PETTAME_CREATUREALREADYOWNED = 2, + PETTAME_NOTTAMEABLE = 3, + PETTAME_ANOTHERSUMMONACTIVE = 4, + PETTAME_UNITSCANTTAME = 5, + PETTAME_NOPETAVAILABLE = 6, // not used in taming + PETTAME_INTERNALERROR = 7, + PETTAME_TOOHIGHLEVEL = 8, + PETTAME_DEAD = 9, // not used in taming + PETTAME_NOTDEAD = 10, // not used in taming + PETTAME_CANTCONTROLEXOTIC = 11, // 3.x + PETTAME_UNKNOWNERROR = 12 +}; + #endif diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index d3e1c0786..964edcb9a 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -4313,26 +4313,51 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_EFFECT_TAMECREATURE: { - if (m_caster->GetTypeId() != TYPEID_PLAYER) + if (m_caster->GetTypeId() != TYPEID_PLAYER || + !m_targets.getUnitTarget() || + m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER || + m_targets.getUnitTarget()->isPet()) return SPELL_FAILED_BAD_TARGETS; - if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + Player* plrCaster = (Player*)m_caster; + + if(plrCaster->getClass() != CLASS_HUNTER) + { + plrCaster->SendPetTameFailure(PETTAME_UNITSCANTTAME); + return SPELL_FAILED_DONT_REPORT; + } Creature* target = (Creature*)m_targets.getUnitTarget(); - if (target->getLevel() > m_caster->getLevel()) - return SPELL_FAILED_HIGHLEVEL; + if(target->isPet() || target->isCharmed()) + { + plrCaster->SendPetTameFailure(PETTAME_CREATUREALREADYOWNED); + return SPELL_FAILED_DONT_REPORT; + } - // use SMSG_PET_TAME_FAILURE? - if (!target->GetCreatureInfo()->isTameable (((Player*)m_caster)->CanTameExoticPets())) - return SPELL_FAILED_BAD_TARGETS; + if (target->getLevel() > plrCaster->getLevel()) + { + plrCaster->SendPetTameFailure(PETTAME_TOOHIGHLEVEL); + return SPELL_FAILED_DONT_REPORT; + } - if(m_caster->GetPetGUID()) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; + if (target->GetCreatureInfo()->IsExotic() && !plrCaster->CanTameExoticPets()) + { + plrCaster->SendPetTameFailure(PETTAME_CANTCONTROLEXOTIC); + return SPELL_FAILED_DONT_REPORT; + } - if(m_caster->GetCharmGUID()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; + if (!target->GetCreatureInfo()->isTameable(plrCaster->CanTameExoticPets())) + { + plrCaster->SendPetTameFailure(PETTAME_NOTTAMEABLE); + return SPELL_FAILED_DONT_REPORT; + } + + if(plrCaster->GetPetGUID() || plrCaster->GetCharmGUID()) + { + plrCaster->SendPetTameFailure(PETTAME_ANOTHERSUMMONACTIVE); + return SPELL_FAILED_DONT_REPORT; + } break; } diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index f81f94474..2033b9294 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -4097,35 +4097,23 @@ void Spell::EffectEnchantItemTmp(uint32 i) void Spell::EffectTameCreature(uint32 /*i*/) { - if(m_caster->GetPetGUID()) - return; - - if(!unitTarget) - return; - - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - return; + // Caster must be player, checked in Spell::CheckCast + Player* plr = (Player*)m_caster; Creature* creatureTarget = (Creature*)unitTarget; - if(creatureTarget->isPet()) - return; - - if(m_caster->getClass() != CLASS_HUNTER) - return; - // cast finish successfully //SendChannelUpdate(0); finish(); - Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id); + Pet* pet = plr->CreateTamedPetFrom(creatureTarget, m_spellInfo->Id); if(!pet) // in versy specific state like near world end/etc. return; // "kill" original creature creatureTarget->ForcedDespawn(); - uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel(); + uint32 level = (creatureTarget->getLevel() < (plr->getLevel() - 5)) ? (plr->getLevel() - 5) : creatureTarget->getLevel(); // prepare visual effect for levelup pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1); @@ -4137,13 +4125,10 @@ void Spell::EffectTameCreature(uint32 /*i*/) pet->SetUInt32Value(UNIT_FIELD_LEVEL, level); // caster have pet now - m_caster->SetPet(pet); + plr->SetPet(pet); - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - ((Player*)m_caster)->PetSpellInitialize(); - } + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + plr->PetSpellInitialize(); } void Spell::EffectSummonPet(uint32 i) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b157ee884..8fd4f3547 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 "8670" + #define REVISION_NR "8671" #endif // __REVISION_NR_H__