aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/Containers/Utilities/ListUtils.h53
-rw-r--r--src/server/game/Combat/ThreatManager.cpp12
-rw-r--r--src/server/game/Entities/Player/Player.cpp34
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp38
-rw-r--r--src/server/game/Entities/Unit/Unit.h7
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp22
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp3
-rw-r--r--src/server/scripts/Commands/cs_list.cpp2
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp3
9 files changed, 113 insertions, 61 deletions
diff --git a/src/common/Containers/Utilities/ListUtils.h b/src/common/Containers/Utilities/ListUtils.h
new file mode 100644
index 00000000000..f5de0d42ec9
--- /dev/null
+++ b/src/common/Containers/Utilities/ListUtils.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITYCORE_LIST_UTILS_H
+#define TRINITYCORE_LIST_UTILS_H
+
+#include <forward_list>
+#include <list>
+
+namespace Trinity::Containers::Lists
+{
+template<typename T, typename Alloc = std::allocator<T>>
+inline typename std::list<T, Alloc>::iterator RemoveUnique(std::list<T, Alloc>& list, T const& value)
+{
+ auto itr = std::find(list.begin(), list.end(), value);
+ if (itr != list.end())
+ return list.erase(itr);
+
+ return list.end();
+}
+
+template<typename T, typename Alloc = std::allocator<T>>
+inline typename std::forward_list<T, Alloc>::iterator RemoveUnique(std::forward_list<T, Alloc>& list, T const& value)
+{
+ auto itr = list.before_begin();
+ auto toErase = std::next(itr);
+ while (toErase != list.end())
+ {
+ if (*toErase == value)
+ return list.erase_after(itr);
+
+ itr = toErase++;
+ }
+
+ return list.end();
+}
+}
+
+#endif // TRINITYCORE_LIST_UTILS_H
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index bc1fe368316..1c18292a295 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -496,19 +496,19 @@ void ThreatManager::MatchUnitThreatToHighestThreat(Unit* target)
void ThreatManager::TauntUpdate()
{
- std::list<AuraEffect*> const& tauntEffects = _owner->GetAuraEffectsByType(SPELL_AURA_MOD_TAUNT);
+ Unit::AuraEffectList const& tauntEffects = _owner->GetAuraEffectsByType(SPELL_AURA_MOD_TAUNT);
- uint32 state = ThreatReference::TAUNT_STATE_TAUNT;
- std::unordered_map<ObjectGuid, ThreatReference::TauntState> tauntStates;
+ uint32 tauntPriority = 0; // lowest is highest
+ std::unordered_map<ObjectGuid, uint32> tauntStates;
// Only the last taunt effect applied by something still on our threat list is considered
- for (auto it = tauntEffects.begin(), end = tauntEffects.end(); it != end; ++it)
- tauntStates[(*it)->GetCasterGUID()] = ThreatReference::TauntState(state++);
+ for (AuraEffect const* tauntEffect : tauntEffects)
+ tauntStates[tauntEffect->GetCasterGUID()] = ++tauntPriority;
for (auto const& pair : _myThreatListEntries)
{
auto it = tauntStates.find(pair.first);
if (it != tauntStates.end())
- pair.second->UpdateTauntState(it->second);
+ pair.second->UpdateTauntState(ThreatReference::TauntState(ThreatReference::TAUNT_STATE_TAUNT + tauntStates.size() - it->second));
else
pair.second->UpdateTauntState();
}
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index f4ccc1e4051..03483e5763b 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1713,28 +1713,26 @@ void Player::RegenerateAll()
// 5 seconds over and over again which confirms my theory that we have a independed timer.
if (m_foodEmoteTimerCount >= 5000)
{
- std::vector<AuraEffect*> auraList;
- AuraEffectList const& ModRegenAuras = GetAuraEffectsByType(SPELL_AURA_MOD_REGEN);
- AuraEffectList const& ModPowerRegenAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN);
-
- auraList.reserve(ModRegenAuras.size() + ModPowerRegenAuras.size());
- auraList.insert(auraList.end(), ModRegenAuras.begin(), ModRegenAuras.end());
- auraList.insert(auraList.end(), ModPowerRegenAuras.begin(), ModPowerRegenAuras.end());
+ auto findInterruptibleEffect = [](AuraEffect const* aurEff)
+ {
+ return aurEff->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing);
+ };
- for (auto itr = auraList.begin(); itr != auraList.end(); ++itr)
+ // Food emote comes above drinking emote if we have to decide (mage regen food for example)
+ AuraEffectList const& ModRegenAuras = GetAuraEffectsByType(SPELL_AURA_MOD_REGEN);
+ auto itr = std::find_if(ModRegenAuras.cbegin(), ModRegenAuras.cend(), findInterruptibleEffect);
+ if (itr != ModRegenAuras.end())
{
- // Food emote comes above drinking emote if we have to decide (mage regen food for example)
- if ((*itr)->GetBase()->HasEffectType(SPELL_AURA_MOD_REGEN) && (*itr)->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing))
- {
- SendPlaySpellVisualKit(SPELL_VISUAL_KIT_FOOD, 0, 0);
- break;
- }
- else if ((*itr)->GetBase()->HasEffectType(SPELL_AURA_MOD_POWER_REGEN) && (*itr)->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing))
- {
+ SendPlaySpellVisualKit(SPELL_VISUAL_KIT_FOOD, 0, 0);
+ }
+ else
+ {
+ AuraEffectList const& ModPowerRegenAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN);
+ itr = std::find_if(ModPowerRegenAuras.cbegin(), ModPowerRegenAuras.cend(), findInterruptibleEffect);
+ if (itr != ModPowerRegenAuras.end())
SendPlaySpellVisualKit(SPELL_VISUAL_KIT_DRINK, 0, 0);
- break;
- }
}
+
m_foodEmoteTimerCount -= 5000;
}
}
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index d3782ec2fd6..67d62eeb8de 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -47,6 +47,7 @@
#include "Item.h"
#include "ItemBonusMgr.h"
#include "KillRewarder.h"
+#include "ListUtils.h"
#include "Log.h"
#include "Loot.h"
#include "LootMgr.h"
@@ -736,8 +737,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons
/*static*/ AuraEffectVector Unit::CopyAuraEffectList(Unit::AuraEffectList const& list)
{
AuraEffectVector effects;
- effects.resize(list.size());
- std::copy(list.begin(), list.end(), effects.begin());
+ std::copy(list.begin(), list.end(), std::back_inserter(effects));
return effects;
}
@@ -3213,20 +3213,20 @@ void Unit::_AddAura(UnitAura* aura, Unit* caster)
* but may be created as a result of aura links.
*/
- // register single target aura
- caster->GetSingleCastAuras().push_back(aura);
-
- std::queue<Aura*> aurasSharingLimit;
+ std::vector<Aura*> aurasSharingLimit;
// remove other single target auras
for (Aura* scAura : caster->GetSingleCastAuras())
- if (scAura != aura && scAura->IsSingleTargetWith(aura))
- aurasSharingLimit.push(scAura);
+ if (scAura->IsSingleTargetWith(aura))
+ aurasSharingLimit.push_back(scAura);
+
+ // register single target aura
+ caster->GetSingleCastAuras().push_front(aura);
uint32 maxOtherAuras = aura->GetSpellInfo()->MaxAffectedTargets - 1;
while (aurasSharingLimit.size() > maxOtherAuras)
{
- aurasSharingLimit.front()->Remove();
- aurasSharingLimit.pop();
+ aurasSharingLimit.back()->Remove();
+ aurasSharingLimit.pop_back();
}
}
}
@@ -3264,7 +3264,7 @@ AuraApplication* Unit::_CreateAuraApplication(Aura* aura, uint32 effMask)
if (aurSpellInfo->HasAnyAuraInterruptFlag())
{
- m_interruptableAuras.push_back(aurApp);
+ m_interruptableAuras.push_front(aurApp);
AddInterruptMask(aurSpellInfo->AuraInterruptFlags, aurSpellInfo->AuraInterruptFlags2);
}
@@ -3359,7 +3359,7 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMo
if (aura->GetSpellInfo()->HasAnyAuraInterruptFlag())
{
- m_interruptableAuras.remove(aurApp);
+ Trinity::Containers::Lists::RemoveUnique(m_interruptableAuras, aurApp);
UpdateInterruptMask();
}
@@ -3483,9 +3483,9 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura)
void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply)
{
if (apply)
- m_modAuras[aurEff->GetAuraType()].push_back(aurEff);
+ m_modAuras[aurEff->GetAuraType()].push_front(aurEff);
else
- m_modAuras[aurEff->GetAuraType()].remove(aurEff);
+ Trinity::Containers::Lists::RemoveUnique(m_modAuras[aurEff->GetAuraType()], aurEff);
}
// All aura base removes should go through this function!
@@ -3499,7 +3499,7 @@ void Unit::RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode)
++m_auraUpdateIterator;
m_ownedAuras.erase(i);
- m_removedAuras.push_back(aura);
+ m_removedAuras.push_front(aura);
// Unregister single target aura
if (aura->IsSingleTarget())
@@ -3836,7 +3836,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, W
newAura->UnregisterSingleTarget();
// bring back single target aura status to the old aura
aura->SetIsSingleTarget(true);
- caster->GetSingleCastAuras().push_back(aura);
+ caster->GetSingleCastAuras().push_front(aura);
}
// FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? stolenCharges : aura->GetCharges(), stolenCharges, recalculateMask, &damage[0]);
@@ -10030,7 +10030,7 @@ void Unit::TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplica
for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr)
{
if (spell->m_appliedMods.count(itr->second->GetBase()) != 0)
- modAuras.push_back(itr->second);
+ modAuras.push_front(itr->second);
}
modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo);
}
@@ -10253,7 +10253,7 @@ void Unit::RestoreDisplayId(bool ignorePositiveAurasPreventingMounting /*= false
if (!transforms.empty())
{
// iterate over already applied transform auras - from newest to oldest
- for (auto i = transforms.rbegin(); i != transforms.rend(); ++i)
+ for (auto i = transforms.begin(); i != transforms.end(); ++i)
{
if (AuraApplication const* aurApp = (*i)->GetBase()->GetApplicationOfTarget(GetGUID()))
{
@@ -11479,7 +11479,7 @@ void Unit::RestoreFaction()
{
if (HasAuraType(SPELL_AURA_MOD_FACTION))
{
- SetFaction(GetAuraEffectsByType(SPELL_AURA_MOD_FACTION).back()->GetMiscValue());
+ SetFaction(GetAuraEffectsByType(SPELL_AURA_MOD_FACTION).front()->GetMiscValue());
return;
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index de2ad5d3756..c45ea2b03d7 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -27,6 +27,7 @@
#include "UnitDefines.h"
#include "Util.h"
#include <array>
+#include <forward_list>
#include <map>
#include <memory>
#include <stack>
@@ -759,9 +760,9 @@ class TC_GAME_API Unit : public WorldObject
typedef std::multimap<AuraStateType, AuraApplication*> AuraStateAurasMap;
typedef std::pair<AuraStateAurasMap::const_iterator, AuraStateAurasMap::const_iterator> AuraStateAurasMapBounds;
- typedef std::list<AuraEffect*> AuraEffectList;
- typedef std::list<Aura*> AuraList;
- typedef std::list<AuraApplication*> AuraApplicationList;
+ typedef std::forward_list<AuraEffect*> AuraEffectList;
+ typedef std::forward_list<Aura*> AuraList;
+ typedef std::forward_list<AuraApplication*> AuraApplicationList;
typedef std::array<DiminishingReturn, DIMINISHING_MAX> Diminishing;
typedef std::vector<std::pair<uint32 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer;
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 03ee64aeeb0..b4908618ce7 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -2298,12 +2298,9 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode,
Unit* target = aurApp->GetTarget();
- //Prevent handling aura twice
AuraType type = GetAuraType();
- if (apply ? target->GetAuraEffectsByType(type).size() > 1 : target->HasAuraType(type))
- return;
- void(*flagChangeFunc)(Unit* u) = nullptr;
+ bool(*flagChangeFunc)(Unit* u) = nullptr;
uint32 slot;
WeaponAttackType attType;
@@ -2311,25 +2308,25 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode,
{
case SPELL_AURA_MOD_DISARM:
if (apply)
- flagChangeFunc = [](Unit* u) { u->SetUnitFlag(UNIT_FLAG_DISARMED); };
+ flagChangeFunc = [](Unit* u) { if (u->HasUnitFlag(UNIT_FLAG_DISARMED)) { return false; } u->SetUnitFlag(UNIT_FLAG_DISARMED); return true; };
else
- flagChangeFunc = [](Unit* u) { u->RemoveUnitFlag(UNIT_FLAG_DISARMED); };
+ flagChangeFunc = [](Unit* u) { if (u->HasAuraType(SPELL_AURA_MOD_DISARM)) { return false; } u->RemoveUnitFlag(UNIT_FLAG_DISARMED); return true; };
slot = EQUIPMENT_SLOT_MAINHAND;
attType = BASE_ATTACK;
break;
case SPELL_AURA_MOD_DISARM_OFFHAND:
if (apply)
- flagChangeFunc = [](Unit* u) { u->SetUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND); };
+ flagChangeFunc = [](Unit* u) { if (u->HasUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND)) { return false; } u->SetUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND); return true; };
else
- flagChangeFunc = [](Unit* u) { u->RemoveUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND); };
+ flagChangeFunc = [](Unit* u) { if (u->HasAuraType(SPELL_AURA_MOD_DISARM_OFFHAND)) { return false; } u->RemoveUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND); return true; };
slot = EQUIPMENT_SLOT_OFFHAND;
attType = OFF_ATTACK;
break;
case SPELL_AURA_MOD_DISARM_RANGED:
if (apply)
- flagChangeFunc = [](Unit* u) { u->SetUnitFlag2(UNIT_FLAG2_DISARM_RANGED); };
+ flagChangeFunc = [](Unit* u) { if (u->HasUnitFlag2(UNIT_FLAG2_DISARM_RANGED)) { return false; } u->SetUnitFlag2(UNIT_FLAG2_DISARM_RANGED); return true; };
else
- flagChangeFunc = [](Unit* u) { u->RemoveUnitFlag2(UNIT_FLAG2_DISARM_RANGED); };
+ flagChangeFunc = [](Unit* u) { if (u->HasAuraType(SPELL_AURA_MOD_DISARM_RANGED)) { return false; } u->RemoveUnitFlag2(UNIT_FLAG2_DISARM_RANGED); return true; };
slot = EQUIPMENT_SLOT_MAINHAND;
attType = RANGED_ATTACK;
break;
@@ -2339,7 +2336,8 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode,
// set/remove flag before weapon bonuses so it's properly reflected in CanUseAttackType
if (flagChangeFunc)
- flagChangeFunc(target);
+ if (!flagChangeFunc(target)) //Prevent handling aura twice
+ return;
// Handle damage modification, shapeshifted druids are not affected
if (target->GetTypeId() == TYPEID_PLAYER && !target->IsInFeralForm())
@@ -6186,7 +6184,7 @@ void AuraEffect::HandleModOverrideZonePVPType(AuraApplication const* aurApp, uin
if (apply)
target->SetOverrideZonePVPType(ZonePVPTypeOverride(GetMiscValue()));
else if (target->HasAuraType(SPELL_AURA_MOD_OVERRIDE_ZONE_PVP_TYPE))
- target->SetOverrideZonePVPType(ZonePVPTypeOverride(target->GetAuraEffectsByType(SPELL_AURA_MOD_OVERRIDE_ZONE_PVP_TYPE).back()->GetMiscValue()));
+ target->SetOverrideZonePVPType(ZonePVPTypeOverride(target->GetAuraEffectsByType(SPELL_AURA_MOD_OVERRIDE_ZONE_PVP_TYPE).front()->GetMiscValue()));
else
target->SetOverrideZonePVPType(ZonePVPTypeOverride::None);
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index eef50859676..e884f1c25e4 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -21,6 +21,7 @@
#include "DynamicObject.h"
#include "GridNotifiersImpl.h"
#include "Item.h"
+#include "ListUtils.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
@@ -1177,7 +1178,7 @@ void Aura::UnregisterSingleTarget()
ASSERT(m_isSingleTarget);
Unit* caster = GetCaster();
ASSERT(caster);
- caster->GetSingleCastAuras().remove(this);
+ Trinity::Containers::Lists::RemoveUnique(caster->GetSingleCastAuras(), this);
SetIsSingleTarget(false);
}
diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp
index 7f456fdef22..1121ae323ea 100644
--- a/src/server/scripts/Commands/cs_list.cpp
+++ b/src/server/scripts/Commands/cs_list.cpp
@@ -489,7 +489,7 @@ public:
if (!sizeLogged)
{
sizeLogged = true;
- handler->PSendSysMessage(LANG_COMMAND_TARGET_LISTAURATYPE, std::to_string(auraList.size()).c_str(), i);
+ handler->PSendSysMessage(LANG_COMMAND_TARGET_LISTAURATYPE, std::to_string(std::distance(auraList.begin(), auraList.end())).c_str(), i);
}
handler->PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, effect->GetId(), effect->GetEffIndex(), effect->GetAmount());
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 131fd6bc8b5..273be7a68bb 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -3121,7 +3121,8 @@ class spell_gen_two_forms : public SpellScript
}
// Player cannot transform to human form if he is forced to be worgen for some reason (Darkflight)
- if (GetCaster()->GetAuraEffectsByType(SPELL_AURA_WORGEN_ALTERED_FORM).size() > 1)
+ Unit::AuraEffectList const& alteredFormAuras = GetCaster()->GetAuraEffectsByType(SPELL_AURA_WORGEN_ALTERED_FORM);
+ if (std::distance(alteredFormAuras.begin(), alteredFormAuras.end()) > 1)
{
SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_CANT_TRANSFORM);
return SPELL_FAILED_CUSTOM_ERROR;