diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/game/SpellEffects.cpp | 140 | ||||
-rw-r--r-- | src/game/SpellMgr.cpp | 34 | ||||
-rw-r--r-- | src/game/SpellMgr.h | 2 | ||||
-rw-r--r-- | src/game/Unit.cpp | 3 |
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 |