aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp3
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp13
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h2
-rw-r--r--src/server/game/Entities/Object/Object.cpp40
-rw-r--r--src/server/game/Entities/Object/Object.h8
-rw-r--r--src/server/game/Entities/Player/Player.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp34
-rw-r--r--src/server/game/Entities/Unit/Unit.h8
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp6
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp4
-rw-r--r--src/server/game/Spells/Spell.cpp18
12 files changed, 77 insertions, 63 deletions
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
index 234a03aa9d0..14812acb868 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
@@ -235,7 +235,10 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti
}
if (target && HasAreaTriggerFlag(AreaTriggerFieldFlags::Attached))
+ {
m_movementInfo.transport.guid = target->GetGUID();
+ m_updateFlag.MovementTransport = true;
+ }
if (!IsStaticSpawn())
UpdatePositionData();
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index d0f8fb33695..a5742dc17eb 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -430,9 +430,9 @@ public:
return 1;
}
- std::vector<uint32> const* GetPauseTimes() const
+ std::span<uint32 const> GetPauseTimes() const
{
- return &_stopFrames;
+ return _stopFrames;
}
ObjectGuid GetTransportGUID() const override { return _owner.GetGUID(); }
@@ -4136,12 +4136,13 @@ void GameObject::ClearUpdateMask(bool remove)
Object::ClearUpdateMask(remove);
}
-std::vector<uint32> const* GameObject::GetPauseTimes() const
+std::span<uint32 const> GameObject::GetPauseTimes() const
{
+ std::span<uint32 const> result;
if (GameObjectType::Transport const* transport = dynamic_cast<GameObjectType::Transport const*>(m_goTypeImpl.get()))
- return transport->GetPauseTimes();
+ result = transport->GetPauseTimes();
- return nullptr;
+ return result;
}
void GameObject::SetPathProgressForClient(float progress)
@@ -4253,6 +4254,8 @@ void GameObject::SetAnimKitId(uint16 animKitId, bool oneshot)
else
_animKitId = 0;
+ m_updateFlag.AnimKit = _animKitId != 0;
+
WorldPackets::GameObject::GameObjectActivateAnimKit activateAnimKit;
activateAnimKit.ObjectGUID = GetGUID();
activateAnimKit.AnimKitID = animKitId;
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 800ef83a09e..5b1ed3b0b0b 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -290,7 +290,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void SetGoAnimProgress(uint8 animprogress) { SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::PercentHealth), animprogress); }
static void SetGoArtKit(uint32 artkit, GameObject* go, ObjectGuid::LowType lowguid = UI64LIT(0));
- std::vector<uint32> const* GetPauseTimes() const;
+ std::span<uint32 const> GetPauseTimes() const;
Optional<float> GetPathProgressForClient() const { return m_transportPathProgress; }
void SetPathProgressForClient(float progress);
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index ac2219ed5cf..3f68036a278 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -152,24 +152,10 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
if (IsWorldObject())
{
WorldObject const* worldObject = static_cast<WorldObject const*>(this);
- if (!flags.MovementUpdate && !worldObject->m_movementInfo.transport.guid.IsEmpty())
- flags.MovementTransport = true;
-
- if (worldObject->GetAIAnimKitId() || worldObject->GetMovementAnimKitId() || worldObject->GetMeleeAnimKitId())
- flags.AnimKit = true;
-
if (worldObject->GetSmoothPhasing() && worldObject->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID()))
flags.SmoothPhasing = true;
}
- if (Unit const* unit = ToUnit())
- {
- flags.PlayHoverAnim = unit->IsPlayingHoverAnim();
-
- if (unit->GetVictim())
- flags.CombatVictim = true;
- }
-
ByteBuffer& buf = data->GetBuffer();
buf << uint8(updateType);
buf << GetGUID();
@@ -274,7 +260,7 @@ ByteBuffer& Object::PrepareValuesUpdateBuffer(UpdateData* data) const
return buffer;
}
-void Object::DestroyForPlayer(Player* target) const
+void Object::DestroyForPlayer(Player const* target) const
{
ASSERT(target);
@@ -285,7 +271,7 @@ void Object::DestroyForPlayer(Player* target) const
target->SendDirectMessage(&packet);
}
-void Object::SendOutOfRangeForPlayer(Player* target) const
+void Object::SendOutOfRangeForPlayer(Player const* target) const
{
ASSERT(target);
@@ -298,9 +284,9 @@ void Object::SendOutOfRangeForPlayer(Player* target) const
void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const
{
- std::vector<uint32> const* PauseTimes = nullptr;
- if (GameObject const* go = ToGameObject())
- PauseTimes = go->GetPauseTimes();
+ std::span<uint32 const> PauseTimes;
+ if (IsGameObject())
+ PauseTimes = static_cast<GameObject const*>(this)->GetPauseTimes();
data->WriteBit(IsWorldObject()); // HasPositionFragment
data->WriteBit(flags.NoBirthAnim);
@@ -459,7 +445,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(*unit->movespline, *data);
}
- *data << uint32(PauseTimes ? PauseTimes->size() : 0);
+ *data << uint32(PauseTimes.size());
if (flags.Stationary)
{
@@ -512,8 +498,8 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
// *data << uint8(AttachmentFlags);
//}
- if (PauseTimes && !PauseTimes->empty())
- data->append(PauseTimes->data(), PauseTimes->size());
+ if (!PauseTimes.empty())
+ data->append(PauseTimes.data(), PauseTimes.size());
if (flags.MovementTransport)
{
@@ -2591,10 +2577,10 @@ SpellMissInfo WorldObject::MagicSpellHitResult(Unit* victim, SpellInfo const* sp
// Parry
// For spells
// Resist
-SpellMissInfo WorldObject::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect /*= false*/) const
+SpellMissInfo WorldObject::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect, bool canImmune) const
{
// Check for immune
- if (victim->IsImmunedToSpell(spellInfo, this))
+ if (canImmune && victim->IsImmunedToSpell(spellInfo, MAX_EFFECT_MASK, this))
return SPELL_MISS_IMMUNE;
// Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
@@ -3747,6 +3733,12 @@ ObjectGuid WorldObject::GetTransGUID() const
return ObjectGuid::Empty;
}
+void WorldObject::SetTransport(TransportBase* t)
+{
+ m_transport = t;
+ m_updateFlag.MovementTransport = !m_updateFlag.MovementUpdate && t != nullptr;
+}
+
float WorldObject::GetFloorZ() const
{
if (!IsInWorld())
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 72b3a5dd448..6f484f765c4 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -228,8 +228,8 @@ class TC_GAME_API Object
void BuildOutOfRangeUpdateBlock(UpdateData* data) const;
ByteBuffer& PrepareValuesUpdateBuffer(UpdateData* data) const;
- virtual void DestroyForPlayer(Player* target) const;
- void SendOutOfRangeForPlayer(Player* target) const;
+ virtual void DestroyForPlayer(Player const* target) const;
+ void SendOutOfRangeForPlayer(Player const* target) const;
virtual void ClearUpdateMask(bool remove);
@@ -837,7 +837,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
virtual float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo) const;
virtual SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
- SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect = false) const;
+ SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect, bool canImmune) const;
void SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo);
virtual uint32 GetFaction() const = 0;
@@ -921,7 +921,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
uint32 GetTransTime() const { return m_movementInfo.transport.time; }
int8 GetTransSeat() const { return m_movementInfo.transport.seat; }
virtual ObjectGuid GetTransGUID() const;
- void SetTransport(TransportBase* t) { m_transport = t; }
+ void SetTransport(TransportBase* t);
MovementInfo m_movementInfo;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index ecddafd9c28..c579bca7400 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3706,7 +3706,7 @@ void Player::ValuesUpdateForPlayerWithMaskSender::operator()(Player const* playe
player->SendDirectMessage(&packet);
}
-void Player::DestroyForPlayer(Player* target) const
+void Player::DestroyForPlayer(Player const* target) const
{
Unit::DestroyForPlayer(target);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 62b5e410559..93ccffcce1b 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2233,7 +2233,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void operator()(Player const* player) const;
};
- void DestroyForPlayer(Player* target) const override;
+ void DestroyForPlayer(Player const* target) const override;
// notifiers
void SendAttackSwingCancelAttack() const;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 6e888db12d1..f51da1de0f8 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -53,6 +53,7 @@
#include "Loot.h"
#include "LootMgr.h"
#include "LootPackets.h"
+#include "MapUtils.h"
#include "MiscPackets.h"
#include "MotionMaster.h"
#include "MovementGenerator.h"
@@ -312,7 +313,7 @@ Unit::Unit(bool isWorldObject) :
m_unitMovedByMe(nullptr), m_playerMovingMe(nullptr), m_charmer(nullptr), m_charmed(nullptr),
i_motionMaster(std::make_unique<MotionMaster>(this)), m_regenTimer(0), m_vehicle(nullptr),
m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this),
- m_threatManager(this), m_aiLocked(false), _playHoverAnim(false), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
+ m_threatManager(this), m_aiLocked(false), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
_spellHistory(std::make_unique<SpellHistory>(this))
{
m_objectTypeId = TYPEID_UNIT;
@@ -1597,7 +1598,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
// Damage shield can be resisted...
- SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false);
+ SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false, true);
if (missInfo != SPELL_MISS_NONE)
{
victim->SendSpellMiss(this, spellInfo->Id, missInfo);
@@ -5901,6 +5902,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
m_attacking = victim;
m_attacking->_addAttacker(this);
+ m_updateFlag.CombatVictim = true;
// Set our target
SetTarget(victim->GetGUID());
@@ -5951,6 +5953,7 @@ bool Unit::AttackStop()
Unit* victim = m_attacking;
+ m_updateFlag.CombatVictim = false;
m_attacking->_removeAttacker(this);
m_attacking = nullptr;
@@ -7743,7 +7746,7 @@ int32 Unit::SpellAbsorbBonusTaken(Unit* caster, SpellInfo const* spellProto, int
return static_cast<int32>(std::round(absorb));
}
-bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
+bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
{
if (!spellInfo)
return false;
@@ -7754,14 +7757,14 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
if (!requireImmunityPurgesEffectAttribute)
return range.begin() != range.end();
- return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
+ return std::ranges::any_of(range, [](uint32 immunitySpellId)
{
- if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
+ if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(immunitySpellId, DIFFICULTY_NONE))
if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
return true;
return false;
- });
+ }, Trinity::Containers::MapValue);
};
// Single spell immunity.
@@ -7792,7 +7795,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
{
// State/effect immunities applied by aura expect full spell immunity
// Ignore effects with mechanic, they are supposed to be checked separately
- if (!spellEffectInfo.IsEffect())
+ if (!spellEffectInfo.IsEffect() || !(effectMask & (1 << spellEffectInfo.EffectIndex)))
continue;
if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
{
@@ -7820,7 +7823,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
if (!immuneSpellInfo || !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
continue;
- if (spellInfo->IsPositive() && !(immuneSpellInfo && immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
+ if (!(spellInfo->NegativeEffects.to_ulong() & effectMask) && !(immuneSpellInfo && immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
continue;
if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
@@ -7955,14 +7958,14 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo co
if (!requireImmunityPurgesEffectAttribute)
return range.begin() != range.end();
- return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
+ return std::ranges::any_of(range, [](uint32 immunitySpellId)
{
- if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
+ if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(immunitySpellId, DIFFICULTY_NONE))
if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
return true;
return false;
- });
+ }, Trinity::Containers::MapValue);
};
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
@@ -11200,6 +11203,7 @@ void Unit::SetAIAnimKitId(uint16 animKitId)
return;
_aiAnimKitId = animKitId;
+ m_updateFlag.AnimKit = _aiAnimKitId != 0 || _movementAnimKitId != 0 || _meleeAnimKitId != 0;
WorldPackets::Misc::SetAIAnimKit data;
data.Unit = GetGUID();
@@ -11216,6 +11220,7 @@ void Unit::SetMovementAnimKitId(uint16 animKitId)
return;
_movementAnimKitId = animKitId;
+ m_updateFlag.AnimKit = _aiAnimKitId != 0 || _movementAnimKitId != 0 || _meleeAnimKitId != 0;
WorldPackets::Misc::SetMovementAnimKit data;
data.Unit = GetGUID();
@@ -11232,6 +11237,7 @@ void Unit::SetMeleeAnimKitId(uint16 animKitId)
return;
_meleeAnimKitId = animKitId;
+ m_updateFlag.AnimKit = _aiAnimKitId != 0 || _movementAnimKitId != 0 || _meleeAnimKitId != 0;
WorldPackets::Misc::SetMeleeAnimKit data;
data.Unit = GetGUID();
@@ -12283,7 +12289,7 @@ Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target)
if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_DEAD_TARGET))
return nullptr;
- if (target->IsImmunedToSpell(spellInfo, this))
+ if (target->IsImmunedToSpell(spellInfo, effMask, this))
return nullptr;
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
@@ -14073,7 +14079,7 @@ void Unit::SetPlayHoverAnim(bool enable, bool sendUpdate /*= true*/)
if (IsPlayingHoverAnim() == enable)
return;
- _playHoverAnim = enable;
+ m_updateFlag.PlayHoverAnim = enable;
if (!sendUpdate)
return;
@@ -14122,7 +14128,7 @@ UF::UpdateFieldFlag Unit::GetUpdateFieldFlagsFor(Player const* target) const
return flags;
}
-void Unit::DestroyForPlayer(Player* target) const
+void Unit::DestroyForPlayer(Player const* target) const
{
if (Battleground* bg = target->GetBattleground())
{
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 881aee786cb..ed291549b04 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1138,7 +1138,7 @@ class TC_GAME_API Unit : public WorldObject
void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath = false, bool forceDestination = false);
- bool IsPlayingHoverAnim() const { return _playHoverAnim; }
+ bool IsPlayingHoverAnim() const { return m_updateFlag.PlayHoverAnim; }
void SetPlayHoverAnim(bool enable, bool sendUpdate = true);
void CalculateHoverHeight();
void SetHoverHeight(float hoverHeight) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::HoverHeight), hoverHeight); }
@@ -1677,7 +1677,7 @@ class TC_GAME_API Unit : public WorldObject
static uint32 SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim);
void ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply);
- bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const;
+ bool IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const;
uint32 GetSchoolImmunityMask() const;
uint32 GetDamageImmunityMask() const;
uint64 GetMechanicImmunityMask() const;
@@ -1878,7 +1878,7 @@ class TC_GAME_API Unit : public WorldObject
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const override;
- void DestroyForPlayer(Player* target) const override;
+ void DestroyForPlayer(Player const* target) const override;
void ClearUpdateMask(bool remove) override;
void _UpdateSpells(uint32 time);
@@ -2030,8 +2030,6 @@ class TC_GAME_API Unit : public WorldObject
uint32 _oldFactionId; ///< faction before charm
bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
- bool _playHoverAnim;
-
uint16 _aiAnimKitId;
uint16 _movementAnimKitId;
uint16 _meleeAnimKitId;
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 25397d69d62..73fcbe1cefe 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -5629,7 +5629,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
// Consecrate ticks can miss and will not show up in the combat log
// dynobj auras must always have a caster
if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) &&
- ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE)
+ ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE)
return;
CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
@@ -5763,7 +5763,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
// dynobj auras must always have a caster
if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) &&
- ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE)
+ ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE)
return;
CleanDamage cleanDamage = CleanDamage(0, 0, GetSpellInfo()->GetAttackType(), MELEE_HIT_NORMAL);
@@ -5953,7 +5953,7 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con
}
if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) &&
- caster->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE)
+ caster->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE)
return;
// ignore negative values (can be result apply spellmods to aura damage
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 7a4722f9cef..3a68549f238 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -684,7 +684,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
{
// needs readding - remove now, will be applied in next update cycle
// (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed)
- if (itr->first->IsImmunedToSpell(GetSpellInfo(), caster, true) || !CanBeAppliedOn(itr->first))
+ if (itr->first->IsImmunedToSpell(GetSpellInfo(), itr->second, caster, true) || !CanBeAppliedOn(itr->first))
{
targetsToRemove.push_back(applicationPair.second->GetTarget());
continue;
@@ -717,7 +717,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
if (itr->first->IsImmunedToSpellEffect(GetSpellInfo(), spellEffectInfo, caster))
itr->second &= ~(1 << spellEffectInfo.EffectIndex);
- if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo(), caster) || !CanBeAppliedOn(itr->first))
+ if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo(), itr->second, caster) || !CanBeAppliedOn(itr->first))
addUnit = false;
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 50db01b3fec..8cc94e2f59d 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2434,7 +2434,9 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
// Calculate hit result
WorldObject* caster = m_originalCaster ? m_originalCaster : m_caster;
- targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)));
+ targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo,
+ m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)),
+ false /*immunity will be checked after complete EffectMask is known*/);
// Spell have speed - need calculate incoming time
// Incoming time is zero for self casts. At least I think so.
@@ -2479,7 +2481,9 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
{
// Calculate reflected spell result on caster (shouldn't be able to reflect gameobject spells)
Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
- targetInfo.ReflectResult = unitCaster->SpellHitResult(unitCaster, m_spellInfo, false); // can't reflect twice
+ targetInfo.ReflectResult = unitCaster->SpellHitResult(unitCaster, m_spellInfo,
+ false /*can't reflect twice*/,
+ false /*immunity will be checked after complete EffectMask is known*/);
// Proc spell reflect aura when missile hits the original target
target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(Milliseconds(targetInfo.TimeDelay)));
@@ -3099,7 +3103,7 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, TargetInfo& hitInfo)
return SPELL_MISS_EVADE;
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
- if (hitInfo.TimeDelay && unit->IsImmunedToSpell(m_spellInfo, m_caster))
+ if (hitInfo.TimeDelay && unit->IsImmunedToSpell(m_spellInfo, hitInfo.EffectMask, m_caster))
return SPELL_MISS_IMMUNE;
CallScriptBeforeHitHandlers(hitInfo.MissCondition);
@@ -8612,6 +8616,10 @@ void Spell::PreprocessSpellLaunch(TargetInfo& targetInfo)
if (!targetUnit)
return;
+ // Check immunity now that EffectMask is known
+ if (targetUnit->IsImmunedToSpell(GetSpellInfo(), targetInfo.EffectMask, m_caster))
+ targetInfo.MissCondition = SPELL_MISS_IMMUNE;
+
// This will only cause combat - the target will engage once the projectile hits (in Spell::TargetInfo::PreprocessTarget)
if (m_originalCaster && targetInfo.MissCondition != SPELL_MISS_EVADE && !m_originalCaster->IsFriendlyTo(targetUnit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)) && (m_spellInfo->HasInitialAggro() || targetUnit->IsEngaged()))
m_originalCaster->SetInCombatWith(targetUnit, true);
@@ -8622,7 +8630,11 @@ void Spell::PreprocessSpellLaunch(TargetInfo& targetInfo)
unit = targetUnit;
// In case spell reflect from target, do all effect on caster (if hit)
else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
+ {
unit = m_caster->ToUnit();
+ if (unit && unit->IsImmunedToSpell(GetSpellInfo(), targetInfo.EffectMask, unit))
+ targetInfo.ReflectResult = SPELL_MISS_IMMUNE;
+ }
if (!unit)
return;