aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2016-12-11 15:04:25 -0300
committerjoschiwald <joschiwald.trinity@gmail.com>2018-04-21 13:52:37 +0200
commit76831d16bea0a4fdf7e11656c69949fd706971f9 (patch)
tree53530b5caee70d3e9d44b4fc167c907f660e1231 /src
parent4aaf4245646e4f117cb2de7855b5672ce2fff14f (diff)
Core/Spell: implemented dispel reflection
Closes #18323 (cherry picked from commit f0772eea98c66f7fd2e745c0cfb8599d6c21ef19) # Conflicts: # src/server/game/Spells/Spell.cpp # src/server/game/Spells/Spell.h # src/server/game/Spells/SpellEffects.cpp
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp25
-rw-r--r--src/server/game/Entities/Unit/Unit.h30
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp2
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h2
-rw-r--r--src/server/game/Spells/Spell.cpp6
-rw-r--r--src/server/game/Spells/Spell.h23
-rw-r--r--src/server/game/Spells/SpellEffects.cpp140
7 files changed, 135 insertions, 93 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 847a8e6f51e..f0af80b721e 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -105,6 +105,11 @@ float playerBaseMoveSpeed[MAX_MOVE_TYPE] =
3.14f // MOVE_PITCH_RATE
};
+bool DispelableAura::RollDispel() const
+{
+ return roll_chance_i(_chance);
+}
+
DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
: m_attacker(attacker), m_victim(victim), m_damage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_damageType(damageType), m_attackType(attackType),
m_absorb(0), m_resist(0), m_block(0), m_hitMask(0)
@@ -4261,13 +4266,13 @@ Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGu
return aurApp ? aurApp->GetBase() : NULL;
}
-void Unit::GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelChargesList& dispelList)
+void Unit::GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect /*= false*/) const
{
AuraMap const& auras = GetOwnedAuras();
- for (AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
+ for (auto itr = auras.begin(); itr != auras.end(); ++itr)
{
Aura* aura = itr->second;
- AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID());
+ AuraApplication const* aurApp = aura->GetApplicationOfTarget(GetGUID());
if (!aurApp)
continue;
@@ -4278,17 +4283,23 @@ void Unit::GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelCharges
if (aura->GetSpellInfo()->GetDispelMask() & dispelMask)
{
// do not remove positive auras if friendly target
- // negative auras if non-friendly target
- if (aurApp->IsPositive() == IsFriendlyTo(caster))
+ // negative auras if non-friendly
+ // unless we're reflecting (dispeller eliminates one of it's benefitial buffs)
+ if (isReflect != (aurApp->IsPositive() == IsFriendlyTo(caster)))
+ continue;
+
+ // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
+ int32 chance = aura->CalcDispelChance(this, !IsFriendlyTo(caster));
+ if (!chance)
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 dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
+ bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
if (charges > 0)
- dispelList.push_back(std::make_pair(aura, charges));
+ dispelList.emplace_back(aura, chance, charges);
}
}
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index b5a023620da..6d8f9c81cbd 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -228,7 +228,33 @@ namespace WorldPackets
}
typedef std::list<Unit*> UnitList;
-typedef std::list<std::pair<Aura*, uint8>> DispelChargesList;
+
+class DispelableAura
+{
+ public:
+ DispelableAura(Aura* aura, int32 dispelChance, uint8 dispelCharges) :
+ _aura(aura), _chance(dispelChance), _charges(dispelCharges) { }
+
+ Aura* GetAura() const { return _aura; }
+ bool RollDispel() const;
+ uint8 GetDispelCharges() const { return _charges; }
+
+ void IncrementCharges() { ++_charges; }
+ bool DecrementCharge()
+ {
+ if (!_charges)
+ return false;
+
+ --_charges;
+ return _charges > 0;
+ }
+
+ private:
+ Aura* _aura;
+ int32 _chance;
+ uint8 _charges;
+};
+typedef std::vector<DispelableAura> DispelChargesList;
typedef std::unordered_multimap<uint32 /*type*/, uint32 /*spellId*/> SpellImmuneContainer;
@@ -1471,7 +1497,7 @@ class TC_GAME_API Unit : public WorldObject
AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0, AuraApplication * except = NULL) const;
Aura* GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0) const;
- void GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelChargesList& dispelList);
+ void GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect = false) const;
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster = ObjectGuid::Empty) const;
uint32 GetAuraCount(uint32 spellId) const;
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index e81659a298a..3d7852e8337 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -1086,7 +1086,7 @@ void Aura::UnregisterSingleTarget()
SetIsSingleTarget(false);
}
-int32 Aura::CalcDispelChance(Unit* auraTarget, bool offensive) const
+int32 Aura::CalcDispelChance(Unit const* auraTarget, bool offensive) const
{
// we assume that aura dispel chance is 100% on start
// need formula for level difference based chance
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index f4d4125aaec..eb20d56ff7b 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -206,7 +206,7 @@ class TC_GAME_API Aura
bool IsSingleTargetWith(Aura const* aura) const;
void SetIsSingleTarget(bool val) { m_isSingleTarget = val; }
void UnregisterSingleTarget();
- int32 CalcDispelChance(Unit* auraTarget, bool offensive) const;
+ int32 CalcDispelChance(Unit const* auraTarget, bool offensive) const;
/**
* @fn AuraKey Aura::GenerateKey(uint32& recalculateMask) const
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 5ce5123f762..245b2a64ac7 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -581,6 +581,7 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo))
gameObjTarget = NULL;
destTarget = NULL;
damage = 0;
+ targetMissInfo = SPELL_MISS_NONE;
variance = 0.0f;
effectHandleMode = SPELL_EFFECT_HANDLE_LAUNCH;
effectInfo = nullptr;
@@ -611,7 +612,7 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo))
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
m_canReflect = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY)
&& !m_spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REFLECTED) && !m_spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
- && !m_spellInfo->IsPassive() && !m_spellInfo->IsPositive();
+ && !m_spellInfo->IsPassive();
CleanupTargetList();
@@ -2160,7 +2161,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
// Calculate hit result
if (m_originalCaster)
{
- targetInfo.missCondition = m_originalCaster->SpellHitResult(target, m_spellInfo, m_canReflect);
+ targetInfo.missCondition = m_originalCaster->SpellHitResult(target, m_spellInfo, m_canReflect && !(m_spellInfo->IsPositive() && m_caster->IsFriendlyTo(target)));
if (m_skipCheck && targetInfo.missCondition != SPELL_MISS_IMMUNE)
targetInfo.missCondition = SPELL_MISS_NONE;
}
@@ -2358,6 +2359,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Need init unitTarget by default unit (can changed in code on reflect)
// Or on missInfo != SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
unitTarget = unit;
+ targetMissInfo = missInfo;
// Reset damage/healing counter
m_damage = target->damage;
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 453e1b58543..88ca04bd7a8 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -320,7 +320,7 @@ enum SpellEffectHandleMode
SPELL_EFFECT_HANDLE_HIT_TARGET
};
-typedef std::list<std::pair<uint32, ObjectGuid>> DispelList;
+typedef std::vector<std::pair<uint32, ObjectGuid>> DispelList;
static const uint32 SPELL_INTERRUPT_NONPLAYER = 32747;
@@ -748,6 +748,7 @@ class TC_GAME_API Spell
GameObject* gameObjTarget;
WorldLocation* destTarget;
int32 damage;
+ SpellMissInfo targetMissInfo;
float variance;
SpellEffectHandleMode effectHandleMode;
SpellEffectInfo const* effectInfo;
@@ -775,18 +776,18 @@ class TC_GAME_API Spell
// Targets store structures and data
struct TargetInfo
{
- // a bug in gcc-4.7 needs a destructor to call move operator instead of copy operator in std::vector remove
- ~TargetInfo() { }
ObjectGuid targetGUID;
uint64 timeDelay;
- SpellMissInfo missCondition:8;
- SpellMissInfo reflectResult:8;
- uint32 effectMask;
- bool processed:1;
- bool alive:1;
- bool crit:1;
- bool scaleAura:1;
int32 damage;
+
+ SpellMissInfo missCondition;
+ SpellMissInfo reflectResult;
+
+ uint32 effectMask;
+ bool processed;
+ bool alive;
+ bool crit;
+ bool scaleAura;
};
std::vector<TargetInfo> m_UniqueTargetInfo;
uint32 m_channelTargetEffectMask; // Mask req. alive targets
@@ -795,7 +796,7 @@ class TC_GAME_API Spell
{
ObjectGuid targetGUID;
uint64 timeDelay;
- uint32 effectMask;
+ uint32 effectMask;
bool processed;
};
std::vector<GOTargetInfo> m_UniqueGOTargetInfo;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 0c2e55e7025..1512e39f946 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -2166,62 +2166,63 @@ void Spell::EffectDispel(SpellEffIndex effIndex)
uint32 dispel_type = effectInfo->MiscValue;
uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(dispel_type));
- DispelChargesList dispel_list;
- unitTarget->GetDispellableAuraList(m_caster, dispelMask, dispel_list);
- if (dispel_list.empty())
+ DispelChargesList dispelList;
+ unitTarget->GetDispellableAuraList(m_caster, dispelMask, dispelList, targetMissInfo == SPELL_MISS_REFLECT);
+ if (dispelList.empty())
return;
+ size_t remaining = dispelList.size();
+
// Ok if exist some buffs for dispel try dispel it
- DispelChargesList success_list;
+ uint32 failCount = 0;
+ DispelChargesList successList;
+ successList.reserve(damage);
+
WorldPackets::Spells::DispelFailed dispelFailed;
dispelFailed.CasterGUID = m_caster->GetGUID();
dispelFailed.VictimGUID = unitTarget->GetGUID();
dispelFailed.SpellID = m_spellInfo->Id;
// dispel N = damage buffs (or while exist buffs for dispel)
- for (int32 count = 0; count < damage && !dispel_list.empty();)
+ for (int32 count = 0; count < damage && remaining > 0;)
{
// Random select buff for dispel
- DispelChargesList::iterator itr = dispel_list.begin();
- std::advance(itr, urand(0, dispel_list.size() - 1));
+ auto itr = dispelList.begin();
+ std::advance(itr, urand(0, remaining - 1));
- int32 chance = itr->first->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster));
- // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
- if (!chance)
- {
- dispel_list.erase(itr);
- continue;
- }
- else
+ if (itr->RollDispel())
{
- if (roll_chance_i(chance))
+ auto successItr = std::find_if(successList.begin(), successList.end(), [&itr](DispelableAura& dispelAura) -> bool
{
- bool alreadyListed = false;
- for (DispelChargesList::iterator successItr = success_list.begin(); successItr != success_list.end(); ++successItr)
- {
- if (successItr->first->GetId() == itr->first->GetId())
- {
- ++successItr->second;
- alreadyListed = true;
- }
- }
- if (!alreadyListed)
- success_list.push_back(std::make_pair(itr->first, 1));
- --itr->second;
- if (itr->second <= 0)
- dispel_list.erase(itr);
- }
+ if (dispelAura.GetAura()->GetId() == itr->GetAura()->GetId())
+ return true;
+
+ return false;
+ });
+
+ if (successItr == successList.end())
+ successList.emplace_back(itr->GetAura(), 0, 1);
else
- dispelFailed.FailedSpells.push_back(int32(itr->first->GetId()));
+ successItr->IncrementCharges();
- ++count;
+ if (!itr->DecrementCharge())
+ {
+ --remaining;
+ std::swap(*itr, dispelList[remaining]);
+ }
}
+ else
+ {
+ ++failCount;
+ dispelFailed.FailedSpells.push_back(int32(itr->GetAura()->GetId()));
+ }
+ ++count;
}
if (!dispelFailed.FailedSpells.empty())
m_caster->SendMessageToSet(dispelFailed.Write(), true);
- if (success_list.empty())
+ if (successList.empty())
return;
WorldPackets::CombatLog::SpellDispellLog spellDispellLog;
@@ -2232,15 +2233,15 @@ void Spell::EffectDispel(SpellEffIndex effIndex)
spellDispellLog.CasterGUID = m_caster->GetGUID();
spellDispellLog.DispelledBySpellID = m_spellInfo->Id;
- for (std::pair<Aura*, uint8> const& dispellCharge : success_list)
+ for (DispelableAura const& dispelableAura : successList)
{
WorldPackets::CombatLog::SpellDispellData dispellData;
- dispellData.SpellID = dispellCharge.first->GetId();
+ dispellData.SpellID = dispelableAura.GetAura()->GetId();
dispellData.Harmful = false; // TODO: use me
dispellData.Rolled = boost::none; // TODO: use me
dispellData.Needed = boost::none; // TODO: use me
- unitTarget->RemoveAurasDueToSpellByDispel(dispellCharge.first->GetId(), m_spellInfo->Id, dispellCharge.first->GetCasterGUID(), m_caster, dispellCharge.second);
+ unitTarget->RemoveAurasDueToSpellByDispel(dispelableAura.GetAura()->GetId(), m_spellInfo->Id, dispelableAura.GetAura()->GetCasterGUID(), m_caster, dispelableAura.GetDispelCharges());
spellDispellLog.DispellData.emplace_back(dispellData);
}
@@ -4426,14 +4427,11 @@ void Spell::EffectDispelMechanic(SpellEffIndex /*effIndex*/)
continue;
if (roll_chance_i(aura->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster))))
if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & (1 << mechanic)))
- dispel_list.push_back(std::make_pair(aura->GetId(), aura->GetCasterGUID()));
+ dispel_list.emplace_back(aura->GetId(), aura->GetCasterGUID());
}
- while (!dispel_list.empty())
- {
- unitTarget->RemoveAura(dispel_list.front().first, dispel_list.front().second, 0, AURA_REMOVE_BY_ENEMY_SPELL);
- dispel_list.pop_front();
- }
+ for (auto itr = dispel_list.begin(); itr != dispel_list.end(); ++itr)
+ unitTarget->RemoveAura(itr->first, itr->second, 0, AURA_REMOVE_BY_ENEMY_SPELL);
}
void Spell::EffectResurrectPet(SpellEffIndex /*effIndex*/)
@@ -4837,7 +4835,7 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex /*effIndex*/)
if (!unitTarget || unitTarget == m_caster) // can't steal from self
return;
- DispelChargesList steal_list;
+ DispelChargesList stealList;
// Create dispel mask by dispel type
uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(effectInfo->MiscValue));
@@ -4845,7 +4843,7 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex /*effIndex*/)
for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
Aura* aura = itr->second;
- AuraApplication * aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID());
+ AuraApplication const* aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID());
if (!aurApp)
continue;
@@ -4855,60 +4853,64 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex /*effIndex*/)
if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_NOT_STEALABLE))
continue;
+ // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
+ int32 chance = aura->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster));
+ if (!chance)
+ 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 dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
if (charges > 0)
- steal_list.push_back(std::make_pair(aura, charges));
+ stealList.emplace_back(aura, chance, charges);
}
}
- if (steal_list.empty())
+ if (stealList.empty())
return;
+ size_t remaining = stealList.size();
+
// Ok if exist some buffs for dispel try dispel it
- DispelList success_list;
+ uint32 failCount = 0;
+ DispelList successList;
+ successList.reserve(damage);
+
WorldPackets::Spells::DispelFailed dispelFailed;
dispelFailed.CasterGUID = m_caster->GetGUID();
dispelFailed.VictimGUID = unitTarget->GetGUID();
dispelFailed.SpellID = m_spellInfo->Id;
// dispel N = damage buffs (or while exist buffs for dispel)
- for (int32 count = 0; count < damage && !steal_list.empty();)
+ for (int32 count = 0; count < damage && remaining > 0;)
{
// Random select buff for dispel
- DispelChargesList::iterator itr = steal_list.begin();
- std::advance(itr, urand(0, steal_list.size() - 1));
+ DispelChargesList::iterator itr = stealList.begin();
+ std::advance(itr, urand(0, remaining - 1));
- int32 chance = itr->first->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster));
- // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
- if (!chance)
+ if (itr->RollDispel())
{
- steal_list.erase(itr);
- continue;
+ successList.emplace_back(itr->GetAura()->GetId(), itr->GetAura()->GetCasterGUID());
+ if (!itr->DecrementCharge())
+ {
+ --remaining;
+ std::swap(*itr, stealList[remaining]);
+ }
}
else
{
- if (roll_chance_i(chance))
- {
- success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID()));
- --itr->second;
- if (itr->second <= 0)
- steal_list.erase(itr);
- }
- else
- dispelFailed.FailedSpells.push_back(int32(itr->first->GetId()));
-
- ++count;
+ ++failCount;
+ dispelFailed.FailedSpells.push_back(int32(itr->GetAura()->GetId()));
}
+ ++count;
}
if (!dispelFailed.FailedSpells.empty())
m_caster->SendMessageToSet(dispelFailed.Write(), true);
- if (success_list.empty())
+ if (successList.empty())
return;
WorldPackets::CombatLog::SpellDispellLog spellDispellLog;
@@ -4919,7 +4921,7 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex /*effIndex*/)
spellDispellLog.CasterGUID = m_caster->GetGUID();
spellDispellLog.DispelledBySpellID = m_spellInfo->Id;
- for (std::pair<uint32, ObjectGuid> const& dispell : success_list)
+ for (std::pair<uint32, ObjectGuid> const& dispell : successList)
{
WorldPackets::CombatLog::SpellDispellData dispellData;
dispellData.SpellID = dispell.first;