aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/DataStores/DBCEnums.h26
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp10
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp21
-rw-r--r--src/server/game/Spells/Spell.cpp51
-rw-r--r--src/server/game/Spells/Spell.h30
-rw-r--r--src/server/game/Spells/SpellInfo.cpp3
6 files changed, 85 insertions, 56 deletions
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 95afccc8d13..b367da13854 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -1862,12 +1862,28 @@ enum SpellCategoryFlags
enum class SpellEffectAttributes
{
None = 0,
- UnaffectedByInvulnerability = 0x000001, // not cancelled by immunities
- NoScaleWithStack = 0x000040,
+ NoImmunity = 0x000001, /*NYI*/ // not cancelled by immunities
+ PositionIsFacingRelative = 0x000002, /*NYI*/
+ JumpChargeUnitMeleeRange = 0x000004, /*NYI*/
+ JumpChargeUnitStrictPathCheck = 0x000008, /*NYI*/
+ ExcludeOwnParty = 0x000010, /*NYI*/
+ AlwaysAoeLineOfSight = 0x000020,
+ SuppressPointsStacking = 0x000040,
ChainFromInitialTarget = 0x000080,
- StackAuraAmountOnRecast = 0x008000, // refreshing periodic auras with this attribute will add remaining damage to new aura
- AllowAnyExplicitTarget = 0x100000,
- IgnoreDuringCooldownTimeRateCalculation = 0x800000
+ UncontrolledNoBackwards = 0x000100, /*NYI*/
+ AuraPointsStack = 0x000200, /*NYI*/ // refreshing periodic auras with this attribute will add remaining damage to new aura
+ NoCopyDamageInterruptsOrProcs = 0x000400, /*NYI*/
+ AddTargetCombatReachToAOE = 0x000800, /*NYI*/
+ IsHarmful = 0x001000,
+ ForceScaleToOverrideCameraMinHeight = 0x002000, /*NYI*/
+ PlayersOnly = 0x004000,
+ ComputePointsOnlyAtCastTime = 0x008000, /*NYI*/
+ EnforceLineOfSightToChainTargets = 0x010000,
+ AreaEffectsUseTargetRadius = 0x020000, /*NYI*/
+ TeleportWithVehicle = 0x040000, /*NYI*/
+ ScalePointsByChallengeModeDamageScaler = 0x080000, /*NYI*/
+ DontFailSpellOnTargetingFailure = 0x100000, /*NYI*/
+ IgnoreDuringCooldownTimeRateCalculation = 0x800000, /*NYI*/
};
DEFINE_ENUM_FLAG(SpellEffectAttributes);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 9ad9cc23074..3efbbbf0696 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -714,7 +714,7 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
}
GetBase()->CallScriptEffectCalcAmountHandlers(this, amount, m_canBeRecalculated);
- if (!GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::NoScaleWithStack))
+ if (!GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking))
amount *= GetBase()->GetStackAmount();
_estimatedAmount = CalculateEstimatedAmount(caster, amount);
@@ -725,7 +725,7 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
Optional<float> AuraEffect::CalculateEstimatedAmount(Unit const* caster, Unit* target, SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo,
int32 amount, uint8 stack, AuraEffect const* aurEff)
{
- uint32 stackAmountForBonuses = !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::NoScaleWithStack) ? stack : 1;
+ uint32 stackAmountForBonuses = !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking) ? stack : 1;
switch (spellEffectInfo.ApplyAuraName)
{
@@ -5391,7 +5391,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::NoScaleWithStack) ? GetBase()->GetStackAmount() : 1;
+ uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking) ? GetBase()->GetStackAmount() : 1;
// ignore negative values (can be result apply spellmods to aura damage
uint32 damage = std::max(GetAmount(), 0);
@@ -5525,7 +5525,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
CleanDamage cleanDamage = CleanDamage(0, 0, GetSpellInfo()->GetAttackType(), MELEE_HIT_NORMAL);
- uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::NoScaleWithStack) ? GetBase()->GetStackAmount() : 1;
+ uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking) ? GetBase()->GetStackAmount() : 1;
// ignore negative values (can be result apply spellmods to aura damage
uint32 damage = std::max(GetAmount(), 0);
@@ -5651,7 +5651,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
if (GetBase()->IsPermanent() && target->IsFullHealth())
return;
- uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::NoScaleWithStack) ? GetBase()->GetStackAmount() : 1;
+ uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking) ? GetBase()->GetStackAmount() : 1;
// ignore negative values (can be result apply spellmods to aura damage
uint32 damage = std::max(GetAmount(), 0);
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index cb504c77865..b8095cab43c 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -25,6 +25,7 @@
#include "Log.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "Spell.h"
@@ -2506,7 +2507,7 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* c
if (GetUnitOwner()->HasUnitState(UNIT_STATE_ISOLATED))
continue;
- std::vector<Unit*> units;
+ std::vector<WorldObject*> units;
ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
float radius = spellEffectInfo.CalcRadius(ref);
@@ -2562,16 +2563,20 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* c
if (selectionType != TARGET_CHECK_DEFAULT)
{
- Trinity::WorldObjectSpellAreaTargetCheck check(radius, GetUnitOwner(), ref, GetUnitOwner(), m_spellInfo, selectionType, condList, TARGET_OBJECT_TYPE_UNIT);
- Trinity::UnitListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> searcher(GetUnitOwner(), units, check);
- Cell::VisitAllObjects(GetUnitOwner(), searcher, radius + extraSearchRadius);
+ if (uint32 containerTypeMask = Spell::GetSearcherTypeMask(m_spellInfo, spellEffectInfo, TARGET_OBJECT_TYPE_UNIT, condList))
+ {
+ Trinity::WorldObjectSpellAreaTargetCheck check(radius, GetUnitOwner(), ref, GetUnitOwner(), m_spellInfo, selectionType, condList, TARGET_OBJECT_TYPE_UNIT);
+ Trinity::WorldObjectListSearcher searcher(GetUnitOwner(), units, check, containerTypeMask);
+ searcher.i_phaseShift = &PhasingHandler::GetAlwaysVisiblePhaseShift();
+ Spell::SearchTargets(searcher, containerTypeMask, GetUnitOwner(), GetUnitOwner(), radius + extraSearchRadius);
- // by design WorldObjectSpellAreaTargetCheck allows not-in-world units (for spells) but for auras it is not acceptable
- units.erase(std::remove_if(units.begin(), units.end(), [this](Unit* unit) { return !unit->IsSelfOrInSameMap(GetUnitOwner()); }), units.end());
+ // by design WorldObjectSpellAreaTargetCheck allows not-in-world units (for spells) but for auras it is not acceptable
+ Trinity::Containers::EraseIf(units, [this](WorldObject const* unit) { return !unit->IsSelfOrInSameMap(GetUnitOwner()); });
+ }
}
- for (Unit* unit : units)
- targets[unit] |= 1 << spellEffectInfo.EffectIndex;
+ for (WorldObject* unit : units)
+ targets[static_cast<Unit*>(unit)] |= 1 << spellEffectInfo.EffectIndex;
}
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 4ba4c975c6e..6a5d1eb855e 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -920,6 +920,7 @@ void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo,
spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex::TargetA) == effects[j].CalcRadius(m_caster, SpellTargetIndex::TargetA) &&
spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex::TargetB) == effects[j].CalcRadius(m_caster, SpellTargetIndex::TargetB) &&
+ spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly) == effects[j].EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly) &&
CheckScriptEffectImplicitTargets(spellEffectInfo.EffectIndex, j))
{
effectMask |= 1 << j;
@@ -1176,7 +1177,7 @@ void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo,
}
}
- WorldObject* target = SearchNearbyTarget(range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
+ WorldObject* target = SearchNearbyTarget(spellEffectInfo, range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
float randomRadius = 0.0f;
switch (targetType.GetTarget())
{
@@ -1298,7 +1299,7 @@ void Spell::SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, Sp
ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
- if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList))
+ if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
{
float extraSearchRadius = radius > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
Trinity::WorldObjectSpellConeTargetCheck check(coneSrc, DegToRad(coneAngle), m_spellInfo->Width ? m_spellInfo->Width : m_caster->GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
@@ -1399,15 +1400,15 @@ void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, Sp
if (!m_caster->IsUnit() || !m_caster->ToUnit()->IsInRaidWith(targetedUnit))
targets.push_back(m_targets.GetUnitTarget());
else
- SearchAreaTargets(targets, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
+ SearchAreaTargets(targets, spellEffectInfo, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
}
break;
case TARGET_UNIT_CASTER_AND_SUMMONS:
targets.push_back(m_caster);
- SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
+ SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
break;
default:
- SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
+ SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
break;
}
@@ -1958,7 +1959,7 @@ void Spell::SelectImplicitLineTargets(SpellEffectInfo const& spellEffectInfo, Sp
ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
- if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList))
+ if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
{
Trinity::WorldObjectSpellLineTargetCheck check(m_caster, dst, m_spellInfo->Width ? m_spellInfo->Width : m_caster->GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellLineTargetCheck> searcher(m_caster, targets, check, containerTypeMask);
@@ -2091,7 +2092,7 @@ void Spell::SelectEffectTypeImplicitTargets(SpellEffectInfo const& spellEffectIn
}
}
-uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionContainer* condList)
+uint32 Spell::GetSearcherTypeMask(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const* condList)
{
// this function selects which containers need to be searched for spell target
uint32 retMask = GRID_MAP_TYPE_MASK_ALL;
@@ -2116,11 +2117,11 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionConta
break;
}
- if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
+ if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER) || spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly))
retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER;
- if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_GHOSTS))
+ if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_GHOSTS))
retMask &= GRID_MAP_TYPE_MASK_PLAYER;
- if (m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
+ if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
retMask &= ~GRID_MAP_TYPE_MASK_PLAYER;
if (condList)
@@ -2157,10 +2158,10 @@ void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject*
}
}
-WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList)
+WorldObject* Spell::SearchNearbyTarget(SpellEffectInfo const& spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
{
WorldObject* target = nullptr;
- uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
+ uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
if (!containerTypeMask)
return nullptr;
@@ -2171,9 +2172,9 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objec
return target;
}
-void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList)
+void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, SpellEffectInfo const& spellEffectInfo, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
{
- uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
+ uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
if (!containerTypeMask)
return;
@@ -2226,7 +2227,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
WorldObject* chainSource = m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER) ? m_caster : target;
std::list<WorldObject*> tempTargets;
- SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions);
+ SearchAreaTargets(tempTargets, spellEffectInfo, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions);
tempTargets.remove(target);
// remove targets which are always invalid for chain spells
@@ -2265,13 +2266,17 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
{
for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
{
- if (foundItr == tempTargets.end())
- {
- if (chainSource->IsWithinDist(*itr, jumpRadius) && IsWithinLOS(chainSource, *itr, false, VMAP::ModelIgnoreFlags::M2))
- foundItr = itr;
- }
- else if (chainSource->GetDistanceOrder(*itr, *foundItr) && IsWithinLOS(chainSource, *itr, false, VMAP::ModelIgnoreFlags::M2))
- foundItr = itr;
+ bool isBestDistanceMatch = foundItr != tempTargets.end() ? chainSource->GetDistanceOrder(*itr, *foundItr) : chainSource->IsWithinDist(*itr, jumpRadius);
+ if (!isBestDistanceMatch)
+ continue;
+
+ if (!IsWithinLOS(chainSource, *itr, false, VMAP::ModelIgnoreFlags::M2))
+ continue;
+
+ if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::EnforceLineOfSightToChainTargets) && !IsWithinLOS(m_caster, *itr, false, VMAP::ModelIgnoreFlags::M2))
+ continue;
+
+ foundItr = itr;
}
}
// not found any valid target - chain ends
@@ -7991,7 +7996,7 @@ bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEf
}
default:
{
- if (!losPosition || m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT))
+ if (!losPosition || m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) || spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::AlwaysAoeLineOfSight))
{
// Get GO cast coordinates if original caster -> GO
WorldObject* caster = nullptr;
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 3b3c37f4a80..9c5f969af72 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -445,11 +445,11 @@ class TC_GAME_API Spell
void SelectEffectTypeImplicitTargets(SpellEffectInfo const& spellEffectInfo);
- uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionContainer* condList);
- template<class SEARCHER> void SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius);
+ static uint32 GetSearcherTypeMask(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const* condList);
+ template<class SEARCHER> static void SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius);
- WorldObject* SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList = nullptr);
- void SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList);
+ WorldObject* SearchNearbyTarget(SpellEffectInfo const& spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList = nullptr);
+ void SearchAreaTargets(std::list<WorldObject*>& targets, SpellEffectInfo const& spellEffectInfo, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList);
void SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellEffectInfo const& spellEffectInfo, bool isChainHeal);
GameObject* SearchSpellFocus();
@@ -915,20 +915,20 @@ namespace Trinity
{
struct TC_GAME_API WorldObjectSpellTargetCheck
{
- protected:
- WorldObject* _caster;
- WorldObject* _referer;
- SpellInfo const* _spellInfo;
- SpellTargetCheckTypes _targetSelectionType;
- std::unique_ptr<ConditionSourceInfo> _condSrcInfo;
- ConditionContainer const* _condList;
+ protected:
+ WorldObject* _caster;
+ WorldObject* _referer;
+ SpellInfo const* _spellInfo;
+ SpellTargetCheckTypes _targetSelectionType;
+ std::unique_ptr<ConditionSourceInfo> _condSrcInfo;
+ ConditionContainer const* _condList;
SpellTargetObjectTypes _objectType;
- WorldObjectSpellTargetCheck(WorldObject* caster, WorldObject* referer, SpellInfo const* spellInfo,
- SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType);
- ~WorldObjectSpellTargetCheck();
+ WorldObjectSpellTargetCheck(WorldObject* caster, WorldObject* referer, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType);
+ ~WorldObjectSpellTargetCheck();
- bool operator()(WorldObject* target) const;
+ bool operator()(WorldObject* target) const;
};
struct TC_GAME_API WorldObjectSpellNearbyTargetCheck : public WorldObjectSpellTargetCheck
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 7020e63b246..1fd65ec5199 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -4544,6 +4544,9 @@ bool _isPositiveEffectImpl(SpellInfo const* spellInfo, SpellEffectInfo const& ef
if (spellInfo->HasAttribute(SPELL_ATTR4_AURA_IS_BUFF))
return true;
+ if (effect.EffectAttributes.HasFlag(SpellEffectAttributes::IsHarmful))
+ return false;
+
visited.insert({ spellInfo, effect.EffectIndex });
//We need scaling level info for some auras that compute bp 0 or positive but should be debuffs