aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp151
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h13
2 files changed, 66 insertions, 98 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 72abb394bf6..f9e5a5ebcf1 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -553,10 +553,15 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, spellProto ? spellProto->Id : 0);
+ // We're going to call functions which can modify content of the list during iteration over it's elements
+ // Let's copy the list so we can prevent iterator invalidation
+ AuraEffectList vCopyDamageCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SHARE_DAMAGE_PCT));
// copy damage to casters of this aura
- AuraEffectList const& vCopyDamage = pVictim->GetAuraEffectsByType(SPELL_AURA_SHARE_DAMAGE_PCT);
- for (AuraEffectList::const_iterator i = vCopyDamage.begin(); i != vCopyDamage.end(); ++i)
+ for (AuraEffectList::iterator i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
{
+ // Check if aura was removed during iteration - we don't need to work on such auras
+ if (!((*i)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
+ continue;
// check damage school mask
if (((*i)->GetMiscValue() & damageSchoolMask) == 0)
continue;
@@ -1615,9 +1620,6 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
// Death Prevention Aura
SpellEntry const* preventDeathSpell = NULL;
int32 preventDeathAmount = 0;
- // Need remove expired auras after
- bool existExpired = false;
- TriggeredSpellInfoVct triggeredSpells;
// Incanter's Absorption, for converting to spell power
int32 incanterAbsorption = 0;
@@ -1644,16 +1646,22 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
auraAbsorbMod = (*itr)->GetAmount();
}
- AuraEffectList vSchoolAbsorb;
- pVictim->FillOrderedAbsorbAuras(vSchoolAbsorb);
+ // We're going to call functions which can modify content of the list during iteration over it's elements
+ // Let's copy the list so we can prevent iterator invalidation
+ AuraEffectList vSchoolAbsorbCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB));
+ vSchoolAbsorbCopy.sort(Trinity::AbsorbAuraOrderPred());
// absorb without mana cost
- for (AuraEffectList::const_iterator itr = vSchoolAbsorb.begin(); (itr != vSchoolAbsorb.end()) && (RemainingDamage > 0); ++itr)
+ for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (RemainingDamage > 0); ++itr)
{
- if (!((*itr)->GetMiscValue() & schoolMask))
+ AuraEffect * absorbAurEff = (*itr);
+ // Check if aura was removed during iteration - we don't need to work on such auras
+ if (!(absorbAurEff->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
+ continue;
+ if (!(absorbAurEff->GetMiscValue() & schoolMask))
continue;
- SpellEntry const * spellProto = (*itr)->GetSpellProto();
+ SpellEntry const * spellProto = absorbAurEff->GetSpellProto();
// Frost Warding
// Chaos Bolt ignore the absorption but still proc Frost Warding mana return
@@ -1664,7 +1672,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
if (roll_chance_i(chance))
{
- triggeredSpells.push_back(TriggeredSpellInfo(57776, pVictim, pVictim, RemainingDamage, (*itr)));
+ pVictim->CastCustomSpell(pVictim, 57776, &RemainingDamage, NULL, NULL, true, NULL, absorbAurEff);
RemainingDamage = RemainingDamage * auraAbsorbMod / 100;
continue;
}
@@ -1674,13 +1682,14 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
continue;
// Max Amount can be absorbed by this aura
- int32 currentAbsorb = (*itr)->GetAmount();
- // Found empty aura (impossible but..)
+ int32 currentAbsorb = absorbAurEff->GetAmount();
+ // Found empty aura
if (currentAbsorb <= 0)
{
- existExpired = true;
+ absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
continue;
}
+
currentAbsorb = (100 - auraAbsorbMod) * currentAbsorb / 100;
// Handle custom absorb auras
@@ -1716,9 +1725,8 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
// Reflective Shield (Lady Malande boss)
if (spellProto->Id == 41475)
{
- triggeredSpells.push_back(
- TriggeredSpellInfo(33619, pVictim, this, std::min(RemainingDamage, currentAbsorb) / 2, *itr)
- );
+ int32 bp = std::min(RemainingDamage, currentAbsorb) / 2;
+ pVictim->CastCustomSpell(this, 33619, &bp, NULL, NULL, true, NULL, *itr);
break;
}
if ((spellProto->Id == 39228) || // Argussian Compass
@@ -1748,10 +1756,9 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
if (RemainingDamage < currentAbsorb)
currentAbsorb = RemainingDamage;
- (*itr)->SetAmount(0); // guarantee removal
- existExpired = true; // maybe hacky but not crashy
-
RemainingDamage -= currentAbsorb;
+
+ absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL); // guarantee removal
continue;
}
// Moonkin Form passive
@@ -1770,8 +1777,8 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
if (spellProto->SpellIconID == 2109)
{
if (!preventDeathSpell && pVictim->ToPlayer())
- if (!pVictim->ToPlayer()->HasSpellCooldown(31231) && roll_chance_i((*itr)->GetAmount()))
- preventDeathSpell = (*itr)->GetSpellProto();
+ if (!pVictim->ToPlayer()->HasSpellCooldown(31231) && roll_chance_i(absorbAurEff->GetAmount()))
+ preventDeathSpell = absorbAurEff->GetSpellProto();
continue;
}
break;
@@ -1781,8 +1788,8 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
// Guardian Spirit
if (spellProto->SpellIconID == 2873)
{
- preventDeathSpell = (*itr)->GetSpellProto();
- preventDeathAmount = (*itr)->GetAmount();
+ preventDeathSpell = absorbAurEff->GetSpellProto();
+ preventDeathAmount = absorbAurEff->GetAmount();
continue;
}
// Power Word: Shield
@@ -1791,7 +1798,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
if (pVictim == this)
break;
- Unit * caster = (*itr)->GetCaster();
+ Unit * caster = absorbAurEff->GetCaster();
if (!caster)
break;
@@ -1801,10 +1808,11 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
{
case 5065: // Rank 1
case 5064: // Rank 2
- triggeredSpells.push_back(
- TriggeredSpellInfo(33619, pVictim, this, CalculatePctN(std::min(RemainingDamage, currentAbsorb), aurEff->GetAmount()), *itr)
- );
+ {
+ int32 bp = CalculatePctN(std::min(RemainingDamage, currentAbsorb), aurEff->GetAmount());
+ pVictim->CastCustomSpell(this, 33619, &bp, NULL, NULL, true, NULL, *itr);
break;
+ }
default:
sLog->outError("Unit::CalcAbsorbResist: unknown Reflective Shield spell %d", aurEff->GetId());
break;
@@ -1836,8 +1844,8 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
? 1.0f
: float(defenseSkillValue) / float(reqDefForMaxHeal);
- int32 healAmount = int32(pVictim->CountPctFromMaxHealth(uint32((*itr)->GetAmount() * pctFromDefense)));
- pVictim->CastCustomSpell(pVictim, 66235, &healAmount, NULL, NULL, true);
+ int32 healAmount = int32(pVictim->CountPctFromMaxHealth(uint32(absorbAurEff->GetAmount() * pctFromDefense)));
+ pVictim->CastCustomSpell(pVictim, 66235, &healAmount, NULL, NULL, true, NULL, *itr);
pVictim->ToPlayer()->AddSpellCooldown(66235, 0, time(NULL) + 120);
}
else if (remainingHealth < int32(allowedHealth))
@@ -1869,7 +1877,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
switch (spellProto->Id)
{
case 51271: // Unbreakable Armor
- if (Unit * caster = (*itr)->GetCaster())
+ if (Unit * caster = absorbAurEff->GetCaster())
{
uint32 absorbed = uint32(currentAbsorb * caster->GetArmor() * 0.01f);
@@ -1890,7 +1898,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
uint32 rank = sSpellMgr->GetSpellRank(spellProto->Id);
SpellEntry const * talentProto = sSpellStore.LookupEntry(sSpellMgr->GetSpellWithRank(49189, rank));
- int32 minHp = int32(pVictim->CountPctFromMaxHealth(SpellMgr::CalculateSpellEffectAmount(talentProto, EFFECT_0, (*itr)->GetCaster())));
+ int32 minHp = int32(pVictim->CountPctFromMaxHealth(SpellMgr::CalculateSpellEffectAmount(talentProto, EFFECT_0, absorbAurEff->GetCaster())));
// Damage that would take you below [effect0] health or taken while you are at [effect0]
if (remainingHp < minHp)
{
@@ -1905,14 +1913,15 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
// This, if I'm not mistaken, shows that we get back ~2% of the absorbed damage as runic power.
int32 absorbed = CalculatePctN(RemainingDamage, currentAbsorb);
RemainingDamage -= absorbed;
- triggeredSpells.push_back(TriggeredSpellInfo(49088, pVictim, pVictim, absorbed * 2 / 10, *itr));
+ int32 bp = absorbed * 2 / 10;
+ pVictim->CastCustomSpell(pVictim, 49088, &bp, NULL, NULL, true, NULL, *itr);
continue;
}
case 50462: // Anti-Magic Shell (on single party/raid member)
AddPctN(RemainingDamage, -currentAbsorb);
continue;
case 50461: // Anti-Magic Zone
- if (Unit * caster = (*itr)->GetCaster())
+ if (Unit * caster = absorbAurEff->GetCaster())
{
int32 absorbed = CalculatePctN(RemainingDamage, currentAbsorb);
int32 canabsorb = caster->GetHealth();
@@ -1944,45 +1953,16 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
incanterAbsorption += currentAbsorb;
// Reduce shield amount
- (*itr)->SetAmount((*itr)->GetAmount() - currentAbsorb);
+ absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
// Need remove it later
- if ((*itr)->GetAmount() <= 0)
- existExpired = true;
+ if (absorbAurEff->GetAmount() <= 0)
+ absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
}
- for (TriggeredSpellInfoVct::const_iterator itr = triggeredSpells.begin(); itr != triggeredSpells.end(); ++itr)
- if (itr->spell)
- itr->source->CastCustomSpell(itr->spell, SPELLVALUE_BASE_POINT0, itr->amount, itr->target, true, NULL, itr->auraEff);
- else if (itr->amount > 0)
- {
- uint32 damage = uint32(itr->amount);
- itr->source->DealDamageMods(itr->target, damage, NULL);
- itr->source->DealDamage(itr->target, damage, NULL, damagetype, schoolMask, 0, false);
- }
-
- // Remove all expired absorb auras
- if (existExpired)
- {
- AuraEffectList const & vSchoolAbsorbOri = pVictim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB);
-
- for (AuraEffectList::const_iterator itr = vSchoolAbsorbOri.begin(); itr != vSchoolAbsorbOri.end();)
- {
- AuraEffect * auraEff = (*itr);
- ++itr;
-
- if (auraEff->GetAmount() <= 0)
- {
- uint32 removedAuras = pVictim->m_removedAurasCount;
- auraEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
- if (removedAuras + 1 < pVictim->m_removedAurasCount)
- itr = vSchoolAbsorbOri.begin();
- }
- }
- }
if (auraAbsorbMod < 100) // Do nothing if 100% absorb ignore
{
- existExpired = false;
+ bool existExpired = false;
// absorb by mana cost
AuraEffectList const & vManaShield = pVictim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD);
@@ -2040,15 +2020,18 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
}
}
- // only split damage if not damaging yourself
- if (auraAbsorbMod < 100) // Do nothing if 100% absorb ignore
- if (pVictim != this)
+ // Do nothing if 100% absorb ignore
+ if (auraAbsorbMod < 100)
+ if (pVictim != this) // only split damage if not damaging yourself
{
- AuraEffectList const & vSplitDamageFlat = pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT);
- for (AuraEffectList::const_iterator itr = vSplitDamageFlat.begin(), next; (itr != vSplitDamageFlat.end()) && (RemainingDamage >= 0); itr = next)
+ // We're going to call functions which can modify content of the list during iteration over it's elements
+ // Let's copy the list so we can prevent iterator invalidation
+ AuraEffectList vSplitDamageFlatCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT));
+ for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (RemainingDamage >= 0); ++itr)
{
- next = itr; ++next;
-
+ // Check if aura was removed during iteration - we don't need to work on such auras
+ if (!((*itr)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
+ continue;
// check damage school mask
if (!((*itr)->GetMiscValue() & schoolMask))
continue;
@@ -2077,11 +2060,14 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
}
- AuraEffectList const & vSplitDamagePct = pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT);
- for (AuraEffectList::const_iterator itr = vSplitDamagePct.begin(), next; (itr != vSplitDamagePct.end()) && (RemainingDamage >= 0); itr = next)
+ // We're going to call functions which can modify content of the list during iteration over it's elements
+ // Let's copy the list so we can prevent iterator invalidation
+ AuraEffectList vSplitDamagePctCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
+ for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(), next; (itr != vSplitDamagePctCopy.end()) && (RemainingDamage >= 0); ++itr)
{
- next = itr; ++next;
-
+ // Check if aura was removed during iteration - we don't need to work on such auras
+ if (!((*itr)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
+ continue;
// check damage school mask
if (!((*itr)->GetMiscValue() & schoolMask))
continue;
@@ -2166,12 +2152,6 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
}
}
-void Unit::FillOrderedAbsorbAuras(AuraEffectList & out) const
-{
- out = GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB);
- out.sort(Trinity::AbsorbAuraOrderPred());
-}
-
void Unit::CalcHealAbsorb(Unit *pVictim, const SpellEntry *healSpell, uint32 &healAmount, uint32 &absorb)
{
if (!healAmount)
@@ -15302,6 +15282,7 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
{
if ((*itr)->GetSpellProto()->SpellIconID == 1654)
{
+ AuraEffect * aurEff = *itr;
// save value before aura remove
uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
if (!ressSpellId)
@@ -15312,7 +15293,7 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL,ressSpellId);
// FORM_SPIRITOFREDEMPTION and related auras
- pVictim->CastSpell(pVictim,27827,true,NULL,*itr);
+ pVictim->CastSpell(pVictim,27827,true,NULL,aurEff);
SpiritOfRedemption = true;
break;
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index ddf546080dc..33001d30080 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -865,18 +865,6 @@ struct SpellPeriodicAuraLogInfo
bool critical;
};
-struct TriggeredSpellInfo
-{
- TriggeredSpellInfo(uint32 _spell, Unit *_source, Unit *_target, int32 _amount = 0, AuraEffect *_auraEff = NULL)
- : spell(_spell), amount(_amount), source(_source), target(_target), auraEff(_auraEff) {}
- uint32 spell;
- int32 amount;
- Unit *source, *target;
- AuraEffect *auraEff;
-};
-
-typedef std::vector<TriggeredSpellInfo> TriggeredSpellInfoVct;
-
uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition);
#define MAX_DECLINED_NAME_CASES 5
@@ -1873,7 +1861,6 @@ class Unit : public WorldObject
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellEntry const *spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS);
uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType=MAX_ATTACK);
void CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, SpellEntry const *spellInfo = NULL);
- void FillOrderedAbsorbAuras(AuraEffectList & out) const;
void CalcHealAbsorb(Unit *pVictim, const SpellEntry *spellProto, uint32 &healAmount, uint32 &absorb);
void UpdateSpeed(UnitMoveType mtype, bool forced);