diff options
author | ariel- <ariel-@users.noreply.github.com> | 2018-03-13 13:46:25 -0300 |
---|---|---|
committer | ariel- <ariel-@users.noreply.github.com> | 2018-03-13 13:46:25 -0300 |
commit | 28288698441524081d583af95f19cb1c9fb90387 (patch) | |
tree | 053b793c77e10de3efb60be3f6d14f3060bede0c /src | |
parent | 7d118f05baf9c9e4d7c13987e1530988c9a6a921 (diff) |
Core/Spells: fix issues with delayed spells and auras
- Was losing info of delayed targets due to remove_if move-assigning targets, it needs to be saved into delayed target vector before returning from lambda
- Delayed auras applying on many targets are now handled gracefully
Closes #21609
Closes #21612
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index de27afaf860..d4c42db9563 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2763,6 +2763,14 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo) { bool refresh = false; + // delayed spells with multiple targets need to create a new aura object, otherwise we'll access a deleted aura + if (m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled()) + { + _spellAura = nullptr; + if (Aura* aura = unit->GetAura(m_spellInfo->Id, caster->GetGUID(), m_CastItem ? m_CastItem->GetGUID() : ObjectGuid::Empty, aura_effmask)) + _spellAura = aura->ToUnitAura(); + } + if (!_spellAura) { bool const resetPeriodicTimer = !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER); @@ -3546,21 +3554,19 @@ uint64 Spell::handle_delayed(uint64 t_offset) // now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases) { std::vector<TargetInfo> delayedTargets; - auto itr = std::remove_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [&](TargetInfo& target) -> bool + m_UniqueTargetInfo.erase(std::remove_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo& target) -> bool { if (single_missile || target.TimeDelay <= t_offset) { target.TimeDelay = t_offset; + delayedTargets.emplace_back(std::move(target)); return true; } else if (next_time == 0 || target.TimeDelay < next_time) next_time = target.TimeDelay; return false; - }); - - delayedTargets.insert(delayedTargets.end(), std::make_move_iterator(itr), std::make_move_iterator(m_UniqueTargetInfo.end())); - m_UniqueTargetInfo.erase(itr, m_UniqueTargetInfo.end()); + }), m_UniqueTargetInfo.end()); DoProcessTargetContainer(delayedTargets); } @@ -3568,21 +3574,19 @@ uint64 Spell::handle_delayed(uint64 t_offset) // now recheck gameobject targeting correctness { std::vector<GOTargetInfo> delayedGOTargets; - auto itr = std::remove_if(std::begin(m_UniqueGOTargetInfo), std::end(m_UniqueGOTargetInfo), [&](GOTargetInfo& goTarget) -> bool + m_UniqueGOTargetInfo.erase(std::remove_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [&](GOTargetInfo& goTarget) -> bool { if (single_missile || goTarget.TimeDelay <= t_offset) { goTarget.TimeDelay = t_offset; + delayedGOTargets.emplace_back(std::move(goTarget)); return true; } else if (next_time == 0 || goTarget.TimeDelay < next_time) next_time = goTarget.TimeDelay; return false; - }); - - delayedGOTargets.insert(delayedGOTargets.end(), std::make_move_iterator(itr), std::make_move_iterator(m_UniqueGOTargetInfo.end())); - m_UniqueGOTargetInfo.erase(itr, m_UniqueGOTargetInfo.end()); + }), m_UniqueGOTargetInfo.end()); DoProcessTargetContainer(delayedGOTargets); } |