mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-18 06:00:10 -04:00
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:
+98
-42
@@ -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
@@ -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
@@ -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); }
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user