diff options
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 61 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 1 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 66 |
3 files changed, 54 insertions, 74 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 8901b638c03..c5d1084cc41 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -13336,43 +13336,46 @@ int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEf bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/) { for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i) - { if (AuraEffect const* aurEff = aura->GetEffect(i)) + if (!IsHighestExclusiveAuraEffect(aura->GetSpellInfo(), aurEff->GetAuraType(), aurEff->GetAmount(), aura->GetEffectMask(), removeOtherAuraApplications)) + return false; + + return true; +} + +bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications /*= false*/) +{ + AuraEffectList const& auras = GetAuraEffectsByType(auraType); + for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();) + { + AuraEffect const* existingAurEff = (*itr); + ++itr; + + if (sSpellMgr->CheckSpellGroupStackRules(spellInfo, existingAurEff->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST) { - AuraType const auraType = AuraType(aura->GetSpellInfo()->Effects[i].ApplyAuraName); - AuraEffectList const& auras = GetAuraEffectsByType(auraType); - for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();) - { - AuraEffect const* existingAurEff = (*itr); - ++itr; + int32 diff = abs(effectAmount) - abs(existingAurEff->GetAmount()); + if (!diff) + for (int32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + diff += int32((auraEffectMask & (1 << i)) >> i) - int32((existingAurEff->GetBase()->GetEffectMask() & (1 << i)) >> i); - if (sSpellMgr->CheckSpellGroupStackRules(aura->GetSpellInfo(), existingAurEff->GetSpellInfo()) - == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST) + if (diff > 0) + { + Aura const* base = existingAurEff->GetBase(); + // no removing of area auras from the original owner, as that completely cancels them + if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this)) { - int32 diff = abs(aurEff->GetAmount()) - abs(existingAurEff->GetAmount()); - if (!diff) - diff = int32(aura->GetEffectMask()) - int32(existingAurEff->GetBase()->GetEffectMask()); - - if (diff > 0) + if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID())) { - Aura const* base = existingAurEff->GetBase(); - // no removing of area auras from the original owner, as that completely cancels them - if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this)) - { - if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID())) - { - bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType); - uint32 removedAuras = m_removedAurasCount; - RemoveAura(aurApp); - if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) - itr = auras.begin(); - } - } + bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType); + uint32 removedAuras = m_removedAurasCount; + RemoveAura(aurApp); + if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) + itr = auras.begin(); } - else if (diff < 0) - return false; } } + else if (diff < 0) + return false; } } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 474f43a9e94..ed0674459cb 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1668,6 +1668,7 @@ class TC_GAME_API Unit : public WorldObject int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue = false, int32 miscValue = 0) const; bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false); + bool IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications = false); virtual void Talk(std::string const& text, ChatMsg msgType, Language language, float textRange, WorldObject const* target); virtual void Say(std::string const& text, Language language, WorldObject const* target = nullptr); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 5ff5a66bcd6..ad50ab6d184 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3244,21 +3244,21 @@ void Spell::_cast(bool skipCheck) CallScriptBeforeCastHandlers(); - auto cleanupSpell = [this, modOwner](SpellCastResult res, uint32* p1 = nullptr, uint32* p2 = nullptr) + // skip check if done already (for instant cast spells for example) + if (!skipCheck) { - SendCastResult(res, p1, p2); - SendInterrupted(0); + auto cleanupSpell = [this, modOwner](SpellCastResult res, uint32* p1 = nullptr, uint32* p2 = nullptr) + { + SendCastResult(res, p1, p2); + SendInterrupted(0); - if (modOwner) - modOwner->SetSpellModTakingSpell(this, false); + if (modOwner) + modOwner->SetSpellModTakingSpell(this, false); - finish(false); - SetExecutedCurrently(false); - }; + finish(false); + SetExecutedCurrently(false); + }; - // skip check if done already (for instant cast spells for example) - if (!skipCheck) - { uint32 param1 = 0, param2 = 0; SpellCastResult castResult = CheckCast(false, ¶m1, ¶m2); if (castResult != SPELL_CAST_OK) @@ -3316,40 +3316,6 @@ void Spell::_cast(bool skipCheck) } } - // check if target already has the same type, but more powerful aura - if (modOwner) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (!GetSpellInfo()->Effects[i].IsAura()) - continue; - - Unit::AuraEffectList const& auras = modOwner->GetAuraEffectsByType(SPELL_AURA_MOD_STAT); - for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt) - { - // check if both spells are in same SpellGroups - if (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST) - { - // compare new aura vs existing aura - if (abs(GetSpellInfo()->Effects[i].BasePoints) < abs((*auraIt)->GetSpellInfo()->Effects[i].BasePoints)) - { - cleanupSpell(SPELL_FAILED_AURA_BOUNCED); - return; - } - else if (abs(GetSpellInfo()->Effects[i].BasePoints) == abs((*auraIt)->GetSpellInfo()->Effects[i].BasePoints)) - { - // in case when baseboints match and to avoid false positive, example, spell 8097 vs 8116 - if (abs(GetSpellInfo()->Effects[i].MiscValue) == abs((*auraIt)->GetSpellInfo()->Effects[i].MiscValue)) - { - cleanupSpell(SPELL_FAILED_AURA_BOUNCED); - return; - } - } - } - } - } - } - // if the spell allows the creature to turn while casting, then adjust server-side orientation to face the target now // client-side orientation is handled by the client itself, as the cast target is targeted due to Creature::SetSpellFocusTarget if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED)) @@ -5426,6 +5392,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint } } + uint8 approximateAuraEffectMask = 0; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { // for effects of spells that have only one target @@ -5844,6 +5811,9 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint default: break; } + + if (m_spellInfo->Effects[i].IsAura()) + approximateAuraEffectMask |= 1 << i; } for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -5968,6 +5938,12 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint default: break; } + + // check if target already has the same type, but more powerful aura + if (!m_spellInfo->IsTargetingArea()) + if (Unit* target = m_targets.GetUnitTarget()) + if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, AuraType(m_spellInfo->Effects[i].ApplyAuraName), m_spellInfo->Effects[i].CalcValue(), approximateAuraEffectMask, false)) + return SPELL_FAILED_AURA_BOUNCED; } // check trade slot case (last, for allow catch any another cast problems) |