Make spellsteal respect dispel-resistances - patch by dr.tenma (thank you!)

This changes the way SPELL_AURA_MOD_DISPEL_RESIST works and fixes mages root diminishing returns
Closes issue #1045.

--HG--
branch : trunk
This commit is contained in:
click
2010-05-25 10:36:33 +02:00
parent 8f908f9df7
commit b4e19528ef
4 changed files with 122 additions and 57 deletions
+98 -42
View File
@@ -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)
+23 -11
View File
@@ -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:
+1 -1
View File
@@ -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); }
-3
View File
@@ -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