diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 35b75a8b7..013378e45 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -3991,41 +3991,47 @@ namespace Game.Entities if (aurEff == null) continue; - AuraType auraType = aurEff.GetSpellEffectInfo().ApplyAuraName; - var auras = GetAuraEffectsByType(auraType); - for (var i = 0; i < auras.Count;) + if (!IsHighestExclusiveAuraEffect(aura.GetSpellInfo(), aurEff.GetAuraType(), aurEff.GetAmount(), aura.GetEffectMask(), removeOtherAuraApplications)) + return false; + } + + return true; + } + + public bool IsHighestExclusiveAuraEffect(SpellInfo spellInfo, AuraType auraType, int effectAmount, uint auraEffectMask, bool removeOtherAuraApplications = false) + { + var auras = GetAuraEffectsByType(auraType); + foreach (AuraEffect existingAurEff in auras) + { + if (Global.SpellMgr.CheckSpellGroupStackRules(spellInfo, existingAurEff.GetSpellInfo()) == SpellGroupStackRule.ExclusiveHighest) { - AuraEffect existingAurEff = auras[i]; - ++i; - - if (Global.SpellMgr.CheckSpellGroupStackRules(aura.GetSpellInfo(), existingAurEff.GetSpellInfo()) == SpellGroupStackRule.ExclusiveHighest) + long diff = Math.Abs(effectAmount) - Math.Abs(existingAurEff.GetAmount()); + if (diff == 0) { - int diff = Math.Abs(aurEff.GetAmount()) - Math.Abs(existingAurEff.GetAmount()); - if (diff == 0) - diff = (int)(aura.GetEffectMask() - existingAurEff.GetBase().GetEffectMask()); + for (int i = 0; i < SpellConst.MaxEffects; ++i) + diff += (long)((auraEffectMask & (1 << i)) >> i) - (long)((existingAurEff.GetBase().GetEffectMask() & (1 << i)) >> i); + } - if (diff > 0) + if (diff > 0) + { + Aura auraBase = existingAurEff.GetBase(); + // no removing of area auras from the original owner, as that completely cancels them + if (removeOtherAuraApplications && (!auraBase.IsArea() || auraBase.GetOwner() != this)) { - Aura auraBase = existingAurEff.GetBase(); - // no removing of area auras from the original owner, as that completely cancels them - if (removeOtherAuraApplications && (!auraBase.IsArea() || auraBase.GetOwner() != this)) + AuraApplication aurApp = existingAurEff.GetBase().GetApplicationOfTarget(GetGUID()); + if (aurApp != null) { - AuraApplication aurApp = existingAurEff.GetBase().GetApplicationOfTarget(GetGUID()); - if (aurApp != null) - { - bool hasMoreThanOneEffect = auraBase.HasMoreThanOneEffectForType(auraType); - uint removedAuras = m_removedAurasCount; - RemoveAura(aurApp); - if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) - i = 0; - } + //bool hasMoreThanOneEffect = auraBase.HasMoreThanOneEffectForType(auraType); + //uint removedAuras = m_removedAurasCount; + RemoveAura(aurApp); + //if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) + //continue; } } - else if (diff < 0) - return false; } + else if (diff < 0) + return false; } - } return true; diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index c7860eb75..ff1f825dd 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2605,21 +2605,21 @@ namespace Game.Spells CallScriptBeforeCastHandlers(); - void cleanupSpell(SpellCastResult result, int? param1 = null, int? param2 = null) - { - SendCastResult(result, param1, param2); - SendInterrupted(0); - - if (modOwner) - modOwner.SetSpellModTakingSpell(this, false); - - Finish(false); - SetExecutedCurrently(false); - } - // skip check if done already (for instant cast spells for example) if (!skipCheck) { + void cleanupSpell(SpellCastResult result, int? param1 = null, int? param2 = null) + { + SendCastResult(result, param1, param2); + SendInterrupted(0); + + if (modOwner) + modOwner.SetSpellModTakingSpell(this, false); + + Finish(false); + SetExecutedCurrently(false); + } + int param1 = 0, param2 = 0; SpellCastResult castResult = CheckCast(false, ref param1, ref param2); if (castResult != SpellCastResult.SpellCastOk) @@ -2679,40 +2679,6 @@ namespace Game.Spells } } - // check if target already has the same type, but more powerful aura - if (modOwner) - { - foreach (SpellEffectInfo spellEffectInfo in GetSpellInfo().GetEffects()) - { - if (!spellEffectInfo.IsAura()) - continue; - - var auras = modOwner.GetAuraEffectsByType(AuraType.ModStat); - foreach (var auraIt in auras) - { - // check if both spells are in same SpellGroups - if (Global.SpellMgr.CheckSpellGroupStackRules(GetSpellInfo(), auraIt.GetSpellInfo()) == SpellGroupStackRule.ExclusiveHighest) - { - // compare new aura vs existing aura - if (Math.Abs(spellEffectInfo.CalcBaseValue(m_caster, null, m_castItemEntry, m_castItemLevel)) < Math.Abs(auraIt.GetSpellEffectInfo().CalcBaseValue(m_caster, null, m_castItemEntry, m_castItemLevel))) - { - cleanupSpell(SpellCastResult.AuraBounced); - return; - } - else if (Math.Abs(spellEffectInfo.BasePoints) == Math.Abs(auraIt.GetSpellEffectInfo().BasePoints)) - { - // in case when baseboints match and to avoid false positive, example, spell 8097 vs 8116 - if (Math.Abs(spellEffectInfo.MiscValue) == Math.Abs(auraIt.GetSpellEffectInfo().MiscValue)) - { - cleanupSpell(SpellCastResult.AuraBounced); - 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::FocusTarget if (m_caster.IsTypeId(TypeId.Unit) && !m_caster.ToUnit().HasUnitFlag(UnitFlags.Possessed)) @@ -4845,6 +4811,7 @@ namespace Game.Spells if (castResult != SpellCastResult.SpellCastOk) return castResult; + uint approximateAuraEffectMask = 0; foreach (var spellEffectInfo in m_spellInfo.GetEffects()) { // for effects of spells that have only one target @@ -5423,6 +5390,9 @@ namespace Game.Spells default: break; } + + if (spellEffectInfo.IsAura()) + approximateAuraEffectMask |= 1u << (int)spellEffectInfo.EffectIndex; } foreach (var spellEffectInfo in m_spellInfo.GetEffects()) @@ -5545,6 +5515,15 @@ namespace Game.Spells default: break; } + + // check if target already has the same type, but more powerful aura + if (!m_spellInfo.IsTargetingArea()) + { + Unit target = m_targets.GetUnitTarget(); + if (target != null) + if (!target.IsHighestExclusiveAuraEffect(m_spellInfo, spellEffectInfo.ApplyAuraName, spellEffectInfo.CalcBaseValue(m_caster, null, m_castItemEntry, m_castItemLevel), approximateAuraEffectMask, false)) + return SpellCastResult.AuraBounced; + } } // check trade slot case (last, for allow catch any another cast problems)