aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/SpellEffects.cpp140
-rw-r--r--src/game/SpellMgr.cpp34
-rw-r--r--src/game/SpellMgr.h2
-rw-r--r--src/game/Unit.cpp3
4 files changed, 122 insertions, 57 deletions
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index acd610d20fb..25f40cb5455 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -3766,12 +3766,13 @@ void Spell::EffectLearnSpell(uint32 i)
}
typedef std::list< std::pair<uint32, uint64> > DispelList;
+typedef std::list< std::pair<Aura *, uint8> > DispelChargesList;
void Spell::EffectDispel(uint32 i)
{
if (!unitTarget)
return;
- Unit::AuraList dispel_list;
+ DispelChargesList dispel_list;
// Create dispel mask by dispel type
uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
@@ -3796,10 +3797,13 @@ void Spell::EffectDispel(uint32 i)
continue;
}
+ // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
+ // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
+ // Polymorph instead of 1 / (5 + 1) -> 16%.
bool dispel_charges = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR_EX7_DISPEL_CHARGES;
-
- for (uint8 i = dispel_charges ? aura->GetCharges() : aura->GetStackAmount(); i; --i)
- dispel_list.push_back(aura);
+ uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
+ if (charges > 0)
+ dispel_list.push_back(std::make_pair(aura, charges));
}
}
@@ -3811,28 +3815,41 @@ void Spell::EffectDispel(uint32 i)
DispelList success_list;
WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4);
// dispel N = damage buffs (or while exist buffs for dispel)
- for (int32 count = 0; count < damage && !dispel_list.empty(); ++count)
+ for (int32 count = 0; count < damage && !dispel_list.empty();)
{
// Random select buff for dispel
- Unit::AuraList::iterator itr = dispel_list.begin();
+ DispelChargesList::iterator itr = dispel_list.begin();
std::advance(itr, urand(0, dispel_list.size() - 1));
- if (GetDispelChance((*itr)->GetCaster(), (*itr)->GetId()))
+ bool success = false;
+ // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
+ if (GetDispelChance(itr->first->GetCaster(), unitTarget, itr->first->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success) > 99)
{
- success_list.push_back(std::make_pair((*itr)->GetId(), (*itr)->GetCasterGUID()));
dispel_list.erase(itr);
+ continue;
}
else
{
- if (!failCount)
+ if (success)
{
- // Failed to dispell
- dataFail << uint64(m_caster->GetGUID()); // Caster GUID
- dataFail << uint64(unitTarget->GetGUID()); // Victim GUID
- dataFail << uint32(m_spellInfo->Id); // dispel spell id
+ success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID()));
+ --itr->second;
+ if (itr->second <= 0)
+ dispel_list.erase(itr);
}
- ++failCount;
- dataFail << uint32((*itr)->GetId()); // Spell Id
+ else
+ {
+ if (!failCount)
+ {
+ // Failed to dispell
+ dataFail << uint64(m_caster->GetGUID()); // Caster GUID
+ dataFail << uint64(unitTarget->GetGUID()); // Victim GUID
+ dataFail << uint32(m_spellInfo->Id); // dispel spell id
+ }
+ ++failCount;
+ dataFail << uint32(itr->first->GetId()); // Spell Id
+ }
+ ++count;
}
}
@@ -7127,10 +7144,10 @@ void Spell::EffectDispelMechanic(uint32 i)
Aura * aura = itr->second;
if (!aura->GetApplicationOfTarget(unitTarget->GetGUID()))
continue;
- if ((GetAllSpellMechanicMask(aura->GetSpellProto()) & (1<<(mechanic))) && GetDispelChance(aura->GetCaster(), aura->GetId()))
- {
+ bool success = false;
+ GetDispelChance(aura->GetCaster(), unitTarget, aura->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success);
+ if((GetAllSpellMechanicMask(aura->GetSpellProto()) & (1<<(mechanic))) && success)
dispel_list.push(std::make_pair(aura->GetId(), aura->GetCasterGUID()));
- }
}
for (; dispel_list.size(); dispel_list.pop())
@@ -7481,7 +7498,8 @@ void Spell::EffectStealBeneficialBuff(uint32 i)
if (!unitTarget || unitTarget == m_caster) // can't steal from self
return;
- Unit::AuraList steal_list;
+ DispelChargesList steal_list;
+
// Create dispel mask by dispel type
uint32 dispelMask = GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i]));
Unit::AuraMap const& auras = unitTarget->GetOwnedAuras();
@@ -7498,43 +7516,81 @@ void Spell::EffectStealBeneficialBuff(uint32 i)
if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_NOT_STEALABLE)
continue;
+ // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
+ // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
+ // Polymorph instead of 1 / (5 + 1) -> 16%.
bool dispel_charges = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR_EX7_DISPEL_CHARGES;
-
- for (uint8 i = dispel_charges ? aura->GetCharges() : aura->GetStackAmount(); i; --i)
- steal_list.push_back(aura);
+ uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
+ if (charges > 0)
+ steal_list.push_back(std::make_pair(aura, charges));
}
}
+
+ if (steal_list.empty())
+ return;
+
// Ok if exist some buffs for dispel try dispel it
- if (uint32 list_size = steal_list.size())
+ uint32 failCount = 0;
+ DispelList success_list;
+ WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4);
+ // dispel N = damage buffs (or while exist buffs for dispel)
+ for (int32 count = 0; count < damage && !steal_list.empty();)
{
- DispelList success_list;
+ // Random select buff for dispel
+ DispelChargesList::iterator itr = steal_list.begin();
+ std::advance(itr, urand(0, steal_list.size() - 1));
- // dispel N = damage buffs (or while exist buffs for dispel)
- for (int32 count=0; count < damage && list_size > 0; ++count, list_size = steal_list.size())
+ bool success = false;
+ // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
+ if (GetDispelChance(itr->first->GetCaster(), unitTarget, itr->first->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success) > 99)
{
- // Random select buff for dispel
- Unit::AuraList::iterator itr = steal_list.begin();
- std::advance(itr, urand(0, list_size-1));
- success_list.push_back(std::make_pair((*itr)->GetId(), (*itr)->GetCasterGUID()));
steal_list.erase(itr);
+ continue;
}
- if (success_list.size())
+ else
{
- WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+damage*5);
- data.append(unitTarget->GetPackGUID()); // Victim GUID
- data.append(m_caster->GetPackGUID()); // Caster GUID
- data << uint32(m_spellInfo->Id); // dispel spell id
- data << uint8(0); // not used
- data << uint32(success_list.size()); // count
- for (DispelList::iterator itr = success_list.begin(); itr != success_list.end(); ++itr)
+ if (success)
{
- data << uint32(itr->first); // Spell Id
- data << uint8(0); // 0 - steals !=0 transfers
- unitTarget->RemoveAurasDueToSpellBySteal(itr->first, itr->second, m_caster);
+ success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID()));
+ --itr->second;
+ if (itr->second <= 0)
+ steal_list.erase(itr);
}
- m_caster->SendMessageToSet(&data, true);
+ else
+ {
+ if (!failCount)
+ {
+ // Failed to dispell
+ dataFail << uint64(m_caster->GetGUID()); // Caster GUID
+ dataFail << uint64(unitTarget->GetGUID()); // Victim GUID
+ dataFail << uint32(m_spellInfo->Id); // dispel spell id
+ }
+ ++failCount;
+ dataFail << uint32(itr->first->GetId()); // Spell Id
+ }
+ ++count;
}
}
+
+ if (failCount)
+ m_caster->SendMessageToSet(&dataFail, true);
+
+ if (success_list.empty())
+ return;
+
+ WorldPacket dataSuccess(SMSG_SPELLSTEALLOG, 8+8+4+1+4+damage*5);
+ dataSuccess.append(unitTarget->GetPackGUID()); // Victim GUID
+ dataSuccess.append(m_caster->GetPackGUID()); // Caster GUID
+ dataSuccess << uint32(m_spellInfo->Id); // dispel spell id
+ dataSuccess << uint8(0); // not used
+ dataSuccess << uint32(success_list.size()); // count
+ for (DispelList::iterator itr = success_list.begin(); itr!=success_list.end(); ++itr)
+ {
+ dataSuccess << uint32(itr->first); // Spell Id
+ dataSuccess << uint8(0); // 0 - steals !=0 transfers
+ unitTarget->RemoveAurasDueToSpellBySteal(itr->first, itr->second, m_caster);
+ }
+ m_caster->SendMessageToSet(&dataSuccess, true);
}
void Spell::EffectKillCreditPersonal(uint32 i)
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index d7da9bb1e3b..5377ea23b81 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -290,19 +290,27 @@ int32 GetSpellMaxDuration(SpellEntry const *spellInfo)
return (du->Duration[2] == -1) ? -1 : abs(du->Duration[2]);
}
-bool GetDispelChance(Unit* caster, uint32 spellId)
+int32 GetDispelChance(Unit* auraCaster, Unit* target, uint32 spellId, bool offensive, bool *result)
{
// we assume that aura dispel chance is 100% on start
// need formula for level difference based chance
- int32 miss_chance = 0;
+ int32 resist_chance = 0;
+
// Apply dispel mod from aura caster
- if (caster)
- {
- if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance);
- }
+ if (auraCaster)
+ if (Player* modOwner = auraCaster->GetSpellModOwner())
+ modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_DISPEL_CHANCE, resist_chance);
+
+ // Dispel resistance from target SPELL_AURA_MOD_DISPEL_RESIST
+ // Only affects offensive dispels
+ if (offensive && target)
+ resist_chance += target->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST);
+
// Try dispel
- return !roll_chance_i(miss_chance);
+ if (result)
+ *result = !roll_chance_i(resist_chance);
+
+ return resist_chance;
}
uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell * spell)
@@ -2860,9 +2868,13 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
// Frostbite
if (spellproto->SpellFamilyFlags[1] & 0x80000000)
return DIMINISHING_TRIGGER_ROOT;
- // Frost Nova, Shatterd Barrier
- if (spellproto->SpellFamilyFlags[0] & 0x00080040)
- return DIMINISHING_CONTROL_ROOT;
+ //Shattered Barrier: only flag SpellFamilyFlags[0] = 0x00080000 shared
+ //by most frost spells, using id instead
+ if (spellproto->Id == 55080)
+ return DIMINISHING_TRIGGER_ROOT;
+ // Frost Nova / Freeze (Water Elemental)
+ if (spellproto->SpellIconID == 193)
+ return DIMINISHING_CONTROL_ROOT;
break;
}
case SPELLFAMILY_ROGUE:
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index b6211dc2259..94121d4610d 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -192,7 +192,7 @@ AuraState GetSpellAuraState(SpellEntry const * spellInfo);
inline float GetSpellRadiusForHostile(SpellRadiusEntry const *radius) { return (radius ? radius->radiusHostile : 0); }
inline float GetSpellRadiusForFriend(SpellRadiusEntry const *radius) { return (radius ? radius->radiusFriend : 0); }
uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell * spell = NULL);
-bool GetDispelChance(Unit* caster, uint32 spellId);
+int32 GetDispelChance(Unit* auraCaster, Unit* target, uint32 spellId, bool offensive, bool *result);
inline float GetSpellMinRangeForHostile(SpellRangeEntry const *range) { return (range ? range->minRangeHostile : 0); }
inline float GetSpellMaxRangeForHostile(SpellRangeEntry const *range) { return (range ? range->maxRangeHostile : 0); }
inline float GetSpellMinRangeForFriend(SpellRangeEntry const *range) { return (range ? range->minRangeFriend : 0); }
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index 13538a74541..0b3b075b2b6 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -2823,9 +2823,6 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell)
// Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
if (IsAreaOfEffectSpell(spell))
modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
- // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
- if (IsDispelSpell(spell))
- modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST);
int32 HitChance = modHitChance * 100;
// Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings