aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp61
-rw-r--r--src/server/game/Entities/Unit/Unit.h1
-rw-r--r--src/server/game/Spells/Spell.cpp66
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, &param1, &param2);
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)