diff options
| -rw-r--r-- | src/common/Containers/Utilities/ListUtils.h | 53 | ||||
| -rw-r--r-- | src/server/game/Combat/ThreatManager.cpp | 12 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 34 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 38 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 7 | ||||
| -rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 22 | ||||
| -rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 3 | ||||
| -rw-r--r-- | src/server/scripts/Commands/cs_list.cpp | 2 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_generic.cpp | 3 |
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; |
