mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 19:37:03 +00:00
[10445] Re-implement in more safe way single cast spell targets system.
It also fix case when target can unexpected lost single target aura at phase switch in case when target still visible in new phase (pet for example)
This commit is contained in:
parent
6e6936c321
commit
dfc9966d3b
4 changed files with 68 additions and 53 deletions
|
|
@ -3945,39 +3945,34 @@ bool Unit::AddSpellAuraHolder(SpellAuraHolder *holder)
|
|||
}
|
||||
|
||||
// update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
|
||||
if (holder->IsSingleTarget() && holder->GetTarget())
|
||||
if (holder->IsSingleTarget())
|
||||
{
|
||||
// caster pointer can be deleted in time aura remove, find it by guid at each iteration
|
||||
for(;;)
|
||||
if (Unit* caster = holder->GetCaster()) // caster not in world
|
||||
{
|
||||
Unit* caster = holder->GetCaster();
|
||||
if(!caster) // caster deleted and not required adding scAura
|
||||
break;
|
||||
|
||||
bool restart = false;
|
||||
SpellAuraHolderList& scAuras = caster->GetSingleCastSpellAuraHolders();
|
||||
for(SpellAuraHolderList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr)
|
||||
SingleCastSpellTargetMap& scTargets = caster->GetSingleCastSpellTargets();
|
||||
for(SingleCastSpellTargetMap::const_iterator itr = scTargets.begin(); itr != scTargets.end();)
|
||||
{
|
||||
if( (*itr)->GetTarget() != holder->GetTarget() &&
|
||||
IsSingleTargetSpells((*itr)->GetSpellProto(),aurSpellInfo) )
|
||||
SpellEntry const* itr_spellEntry = itr->first;
|
||||
ObjectGuid itr_targetGuid = itr->second;
|
||||
|
||||
if (itr_targetGuid != GetObjectGuid() &&
|
||||
IsSingleTargetSpells(itr_spellEntry, aurSpellInfo))
|
||||
{
|
||||
if ((*itr)->IsInUse())
|
||||
{
|
||||
sLog.outError("Holder (Spell %u) is in process but attempt removed at aura (Spell %u) adding, need add stack rule for IsSingleTargetSpell", (*itr)->GetId(), holder->GetId());
|
||||
continue;
|
||||
}
|
||||
(*itr)->GetTarget()->RemoveSpellAuraHolder((*itr));
|
||||
restart = true;
|
||||
break;
|
||||
scTargets.erase(itr); // remove for caster in any case
|
||||
|
||||
// remove from target if target found
|
||||
if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid))
|
||||
itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id);
|
||||
|
||||
itr = scTargets.begin(); // list can be chnaged at remove aura
|
||||
continue;
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
if(!restart)
|
||||
{
|
||||
// done
|
||||
scAuras.push_back(holder);
|
||||
break;
|
||||
}
|
||||
// register spell holder single target
|
||||
scTargets[aurSpellInfo] = GetObjectGuid();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4493,12 +4488,13 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
|
|||
// single target auras from other casters
|
||||
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end(); )
|
||||
{
|
||||
if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto()))
|
||||
if (iter->second->GetCasterGUID() != GetGUID() && iter->second->IsSingleTarget())
|
||||
{
|
||||
if(!newPhase)
|
||||
{
|
||||
RemoveSpellAuraHolder(iter->second);
|
||||
iter = m_spellAuraHolders.begin();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -4507,29 +4503,52 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
|
|||
{
|
||||
RemoveSpellAuraHolder(iter->second);
|
||||
iter = m_spellAuraHolders.begin();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
// single cast!!
|
||||
// single target auras at other targets
|
||||
SpellAuraHolderList& scAuras = GetSingleCastSpellAuraHolders();
|
||||
for (SpellAuraHolderList::iterator iter = scAuras.begin(); iter != scAuras.end(); )
|
||||
SingleCastSpellTargetMap& scTargets = GetSingleCastSpellTargets();
|
||||
for (SingleCastSpellTargetMap::iterator itr = scTargets.begin(); itr != scTargets.end(); )
|
||||
{
|
||||
SpellAuraHolder* holder = *iter;
|
||||
if (holder->GetTarget() != this && !holder->GetTarget()->InSamePhase(newPhase))
|
||||
SpellEntry const* itr_spellEntry = itr->first;
|
||||
ObjectGuid itr_targetGuid = itr->second;
|
||||
|
||||
if (itr_targetGuid != GetObjectGuid())
|
||||
{
|
||||
scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveSpellAuraHolder
|
||||
holder->GetTarget()->RemoveSpellAuraHolder(holder);
|
||||
iter = scAuras.begin();
|
||||
if(!newPhase)
|
||||
{
|
||||
scTargets.erase(itr); // remove for caster in any case
|
||||
|
||||
// remove from target if target found
|
||||
if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid))
|
||||
itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id);
|
||||
|
||||
itr = scTargets.begin(); // list can be changed at remove aura
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
Unit* itr_target = GetMap()->GetUnit(itr_targetGuid);
|
||||
if(!itr_target || !itr_target->InSamePhase(newPhase))
|
||||
{
|
||||
scTargets.erase(itr); // remove for caster in any case
|
||||
|
||||
// remove from target if target found
|
||||
if (itr_target)
|
||||
itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id);
|
||||
|
||||
itr = scTargets.begin(); // list can be changed at remove aura
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue