Core/Spells: expand the single target aura system to support a specific amount of targets

* limit Living Bomb targets to three per caster
This commit is contained in:
Ovahlord committed 2019-05-12 20:03:17 +02:00
1 parent 3d93df80a6
commit 9bf40cfee4
9 files changed
+101 -66

No files matched your search

+14 -9
View File
@@ -27234,19 +27234,24 @@ void Player::ActivateSpec(uint8 spec)
ExitVehicle();
RemoveAllControlled();
// remove single target auras at other targets
AuraList& scAuras = GetSingleCastAuras();
for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
// remove limited target auras at other targets
AurasBySpellIdMap& ltAurasBySpellId = GetAllLimitedCastAuras();
for (AurasBySpellIdMap::iterator itr = ltAurasBySpellId.begin(); itr != ltAurasBySpellId.end(); itr++)
{
Aura* aura = *iter;
if (aura->GetUnitOwner() != this)
AuraList list = itr->second;
for (AuraList::iterator iter = list.begin(); iter != list.end();)
{
aura->Remove();
iter = scAuras.begin();
Aura* aura = *iter;
if (aura->GetUnitOwner() != this)
{
aura->Remove();
iter = list.begin();
}
else
++iter;
}
else
++iter;
}
/*RemoveAllAurasOnDeath();
if (GetPet())
GetPet()->RemoveAllAurasOnDeath();*/
+51 -32
View File
@@ -3390,8 +3390,9 @@ void Unit::_AddAura(UnitAura* aura, Unit* caster)
if (aura->IsRemoved())
return;
aura->SetIsSingleTarget(caster && (aura->GetSpellInfo()->IsSingleTarget() || aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE)));
if (aura->IsSingleTarget())
aura->SetIsLimitedTarget(caster && (aura->GetSpellInfo()->IsSingleTarget() || aura->GetSpellInfo()->GetAuraTargetLimit() || aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE)));
if (aura->IsLimitedTarget())
{
ASSERT((IsInWorld() && !IsDuringRemoveFromWorld()) || (aura->GetCasterGUID() == GetGUID()) ||
(IsLoading() && aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE)));
@@ -3400,17 +3401,31 @@ void Unit::_AddAura(UnitAura* aura, Unit* caster)
* but may be created as a result of aura links (player mounts with passengers)
*/
// register single target aura
caster->GetSingleCastAuras().push_back(aura);
// remove other single target auras
Unit::AuraList& scAuras = caster->GetSingleCastAuras();
for (Unit::AuraList::iterator itr = scAuras.begin(); itr != scAuras.end();)
// register limited target aura
caster->GetLimitedCastAuras(aura->GetSpellInfo()->Id).push_back(aura);
Unit::AuraList& ltAuras = caster->GetLimitedCastAuras(aura->GetSpellInfo()->Id);
bool isSingleTarget = aura->GetSpellInfo()->IsSingleTarget();
uint32 targetLimit = aura->GetSpellInfo()->GetAuraTargetLimit();
// remove other limited target auras
for (Unit::AuraList::iterator itr = ltAuras.begin(); itr != ltAuras.end();)
{
if ((*itr) != aura &&
(*itr)->IsSingleTargetWith(aura))
if ((*itr) != aura && (*itr)->IsLimitedTargetWith(aura) && isSingleTarget)
{
(*itr)->Remove();
itr = scAuras.begin();
itr = ltAuras.begin();
}
else if ((*itr) != aura && (*itr)->IsLimitedTargetWith(aura) && targetLimit && ltAuras.size() > targetLimit)
{
// We have more auras in our target limit list than we are allowed to have so we remove the oldest entry
if ((*itr) == ltAuras.front())
{
(*itr)->Remove();
itr = ltAuras.begin();
}
else
++itr;
}
else
++itr;
@@ -3667,8 +3682,8 @@ void Unit::RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode)
m_removedAuras.push_back(aura);
// Unregister single target aura
if (aura->IsSingleTarget())
aura->UnregisterSingleTarget();
if (aura->IsLimitedTarget())
aura->UnregisterLimitedTarget();
aura->_Remove(removeMode);
@@ -3980,19 +3995,19 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U
}
else
{
// single target state must be removed before aura creation to preserve existing single target aura
if (aura->IsSingleTarget())
aura->UnregisterSingleTarget();
// limited target state must be removed before aura creation to preserve existing limited target aura
if (aura->IsLimitedTarget())
aura->UnregisterLimitedTarget();
if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, nullptr, &baseDamage[0], nullptr, aura->GetCasterGUID()))
{
// created aura must not be single target aura,, so stealer won't loose it on recast
if (newAura->IsSingleTarget())
// created aura must not be limited target aura, so stealer won't loose it on recast
if (newAura->IsLimitedTarget())
{
newAura->UnregisterSingleTarget();
newAura->UnregisterLimitedTarget();
// bring back single target aura status to the old aura
aura->SetIsSingleTarget(true);
caster->GetSingleCastAuras().push_back(aura);
aura->SetIsLimitedTarget(true);
caster->GetLimitedCastAuras(aura->GetSpellInfo()->Id).push_back(aura);
}
// FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, &damage[0]);
@@ -4058,7 +4073,7 @@ void Unit::RemoveAurasWithAttribute(uint32 flags)
}
}
void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
void Unit::RemoveNotOwnLimitedTargetAuras(bool onPhaseChange /*= false*/)
{
// single target auras from other casters
// Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras).
@@ -4073,7 +4088,7 @@ void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
{
Aura const* aura = iter->second;
if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget())
if (aura->GetCasterGUID() != GetGUID() && aura->IsLimitedTarget())
{
if (!onPhaseChange)
RemoveOwnedAura(iter);
@@ -4090,18 +4105,22 @@ void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
++iter;
}
// single target auras at other targets
AuraList& scAuras = GetSingleCastAuras();
for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
// limited target auras at other targets
AurasBySpellIdMap& ltAurasBySpellId = GetAllLimitedCastAuras();
for (AurasBySpellIdMap::iterator itr = ltAurasBySpellId.begin(); itr != ltAurasBySpellId.end(); ++itr)
{
Aura* aura = *iter;
if (aura->GetUnitOwner() != this && (!onPhaseChange || !aura->GetUnitOwner()->IsInPhase(this)))
AuraList& list = itr->second;
for (AuraList::iterator iter = list.begin(); iter != list.end();)
{
aura->Remove();
iter = scAuras.begin();
Aura* aura = *iter;
if (aura->GetUnitOwner() != this && (!onPhaseChange || !aura->GetUnitOwner()->IsInPhase(this)))
{
aura->Remove();
iter = list.begin();
}
else
++iter;
}
else
++iter;
}
}
@@ -10275,7 +10294,7 @@ void Unit::RemoveFromWorld()
RemoveCharmAuras();
RemoveBindSightAuras();
RemoveNotOwnSingleTargetAuras();
RemoveNotOwnLimitedTargetAuras();
RemoveAllGameObjects();
RemoveAllDynObjects();
+6 -4
View File
@@ -974,6 +974,8 @@ class TC_GAME_API Unit : public WorldObject
typedef std::map<uint8, AuraApplication*> VisibleAuraMap;
typedef std::unordered_map<uint32 /*spellId*/, AuraList> AurasBySpellIdMap;
virtual ~Unit();
UnitAI* GetAI() { return i_AI; }
@@ -1465,7 +1467,7 @@ class TC_GAME_API Unit : public WorldObject
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, Unit* stealer);
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid);
void RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID = ObjectGuid::Empty, Aura* except = nullptr, bool negative = true, bool positive = true);
void RemoveNotOwnSingleTargetAuras(bool onPhaseChange = false);
void RemoveNotOwnLimitedTargetAuras(bool onPhaseChange = false);
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except = 0);
void RemoveAurasWithAttribute(uint32 flags);
void RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, ObjectGuid casterGUID);
@@ -1487,8 +1489,8 @@ class TC_GAME_API Unit : public WorldObject
void _ApplyAllAuraStatMods();
AuraEffectList const& GetAuraEffectsByType(AuraType type) const { return m_modAuras[type]; }
AuraList & GetSingleCastAuras() { return m_scAuras; }
AuraList const& GetSingleCastAuras() const { return m_scAuras; }
AuraList& GetLimitedCastAuras(uint32 spellId) { return m_ltAuras[spellId]; }
AurasBySpellIdMap& GetAllLimitedCastAuras() { return m_ltAuras; }
AuraEffect* GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID = ObjectGuid::Empty) const;
AuraEffect* GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID = ObjectGuid::Empty) const;
@@ -1949,7 +1951,7 @@ class TC_GAME_API Unit : public WorldObject
uint32 m_removedAurasCount;
AuraEffectList m_modAuras[TOTAL_AURAS];
AuraList m_scAuras; // cast singlecast auras
AurasBySpellIdMap m_ltAuras; // cast limited target auras
AuraApplicationList m_interruptableAuras; // auras which have interrupt mask applied on unit
AuraStateAurasMap m_auraStateAuras; // Used for improve performance of aura state checks on aura apply/remove
uint32 m_interruptMask;
+6 -6
View File
@@ -70,7 +70,7 @@ void PhasingHandler::AddPhase(WorldObject* object, uint32 phaseId, bool updateVi
{
AddPhase(controlled, phaseId, updateVisibility);
});
unit->RemoveNotOwnSingleTargetAuras(true);
unit->RemoveNotOwnLimitedTargetAuras(true);
}
UpdateVisibilityIfNeeded(object, updateVisibility, changed);
@@ -87,7 +87,7 @@ void PhasingHandler::RemovePhase(WorldObject* object, uint32 phaseId, bool updat
{
RemovePhase(controlled, phaseId, updateVisibility);
});
unit->RemoveNotOwnSingleTargetAuras(true);
unit->RemoveNotOwnLimitedTargetAuras(true);
}
UpdateVisibilityIfNeeded(object, updateVisibility, changed);
@@ -110,7 +110,7 @@ void PhasingHandler::AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, boo
{
AddPhaseGroup(controlled, phaseGroupId, updateVisibility);
});
unit->RemoveNotOwnSingleTargetAuras(true);
unit->RemoveNotOwnLimitedTargetAuras(true);
}
UpdateVisibilityIfNeeded(object, updateVisibility, changed);
@@ -133,7 +133,7 @@ void PhasingHandler::RemovePhaseGroup(WorldObject* object, uint32 phaseGroupId,
{
RemovePhaseGroup(controlled, phaseGroupId, updateVisibility);
});
unit->RemoveNotOwnSingleTargetAuras(true);
unit->RemoveNotOwnLimitedTargetAuras(true);
}
UpdateVisibilityIfNeeded(object, updateVisibility, changed);
@@ -275,7 +275,7 @@ void PhasingHandler::OnAreaChange(WorldObject* object)
});
if (changed)
unit->RemoveNotOwnSingleTargetAuras(true);
unit->RemoveNotOwnLimitedTargetAuras(true);
}
UpdateVisibilityIfNeeded(object, true, changed);
@@ -386,7 +386,7 @@ void PhasingHandler::OnConditionChange(WorldObject* object)
});
if (changed)
unit->RemoveNotOwnSingleTargetAuras(true);
unit->RemoveNotOwnLimitedTargetAuras(true);
}
UpdateVisibilityIfNeeded(object, true, changed);
+9 -9
View File
@@ -325,7 +325,7 @@ Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owne
if (owner->isType(TYPEMASK_UNIT))
if (!owner->IsInWorld() || ((Unit*)owner)->IsDuringRemoveFromWorld())
// owner not in world so don't allow to own not self cast single target auras
if (casterGUID != owner->GetGUID() && spellproto->IsSingleTarget())
if (casterGUID != owner->GetGUID() && (spellproto->IsSingleTarget() || spellproto->GetAuraTargetLimit()))
return nullptr;
Aura* aura = nullptr;
@@ -354,7 +354,7 @@ m_spellInfo(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID(
m_castItemGuid(castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_applyTime(time(nullptr)),
m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0),
m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1),
m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr),
m_isRemoved(false), m_isLimitedTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr),
m_procCooldown(std::chrono::steady_clock::time_point::min())
{
if (m_spellInfo->ManaPerSecond)
@@ -983,7 +983,7 @@ bool Aura::CanBeSaved() const
return false;
}
if (IsSingleTarget() || GetSpellInfo()->IsSingleTarget())
if (IsLimitedTarget() || GetSpellInfo()->IsSingleTarget() || GetSpellInfo()->GetAuraTargetLimit())
return false;
}
@@ -1054,7 +1054,7 @@ bool Aura::CanBeSentToClient() const
|| HasEffectType(SPELL_AURA_CAST_WHILE_WALKING) || HasEffectType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS);
}
bool Aura::IsSingleTargetWith(Aura const* aura) const
bool Aura::IsLimitedTargetWith(Aura const* aura) const
{
// Same spell?
if (GetSpellInfo()->IsRankOf(aura->GetSpellInfo()))
@@ -1079,13 +1079,13 @@ bool Aura::IsSingleTargetWith(Aura const* aura) const
return false;
}
void Aura::UnregisterSingleTarget()
void Aura::UnregisterLimitedTarget()
{
ASSERT(m_isSingleTarget);
ASSERT(m_isLimitedTarget);
Unit* caster = GetCaster();
ASSERT(caster);
caster->GetSingleCastAuras().remove(this);
SetIsSingleTarget(false);
caster->GetLimitedCastAuras(GetSpellInfo()->Id).remove(this);
SetIsLimitedTarget(false);
}
int32 Aura::CalcDispelChance(Unit const* auraTarget, bool offensive) const
@@ -1525,7 +1525,7 @@ bool Aura::CanBeAppliedOn(Unit* target)
if (GetOwner() != target)
return false;
// do not apply non-selfcast single target auras
if (GetCasterGUID() != GetOwner()->GetGUID() && GetSpellInfo()->IsSingleTarget())
if (GetCasterGUID() != GetOwner()->GetGUID() && (GetSpellInfo()->IsSingleTarget() || GetSpellInfo()->GetAuraTargetLimit()))
return false;
return true;
}
+6 -6
View File
@@ -166,11 +166,11 @@ class TC_GAME_API Aura
bool CanBeSaved() const;
bool IsRemoved() const { return m_isRemoved; }
bool CanBeSentToClient() const;
// Single cast aura helpers
bool IsSingleTarget() const {return m_isSingleTarget; }
bool IsSingleTargetWith(Aura const* aura) const;
void SetIsSingleTarget(bool val) { m_isSingleTarget = val; }
void UnregisterSingleTarget();
// Limited cast aura helpers
bool IsLimitedTarget() const {return m_isLimitedTarget; }
bool IsLimitedTargetWith(Aura const* aura) const;
void SetIsLimitedTarget(bool val) { m_isLimitedTarget = val; }
void UnregisterLimitedTarget();
int32 CalcDispelChance(Unit const* auraTarget, bool offensive) const;
void SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount);
@@ -266,7 +266,7 @@ class TC_GAME_API Aura
ApplicationMap m_applications;
bool m_isRemoved:1;
bool m_isSingleTarget:1; // true if it's a single target spell and registered at caster - can change at spell steal for example
bool m_isLimitedTarget:1; // true if it's a limited target spell and registered at caster - can change at spell steal for example
bool m_isUsingCharges:1;
ChargeDropEvent* m_dropEvent;
+1
View File
@@ -1034,6 +1034,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effe
_auraState = AURA_STATE_NONE;
_allowedMechanicMask = 0;
MaxAuraTargets = 0;
}
SpellInfo::~SpellInfo()
+2
View File
@@ -429,6 +429,7 @@ class TC_GAME_API SpellInfo
SpellEffectInfo Effects[MAX_SPELL_EFFECTS];
uint32 ExplicitTargetMask;
SpellChainNode const* ChainEntry;
uint32 MaxAuraTargets;
// struct access functions
SpellTargetRestrictionsEntry const* GetSpellTargetRestrictions() const;
@@ -517,6 +518,7 @@ class TC_GAME_API SpellInfo
bool CanDispelAura(SpellInfo const* auraSpellInfo) const;
bool IsSingleTarget() const;
uint32 GetAuraTargetLimit() const { return MaxAuraTargets; };
bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const;
bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
+6
View File
@@ -5257,6 +5257,12 @@ void SpellMgr::LoadSpellInfoCorrections()
// END OF BLACKWING DESCENT SPELLS
// Living Bomb
ApplySpellFix({ 44457 }, [](SpellInfo* spellInfo)
{
spellInfo->MaxAuraTargets = 3;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];