aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2018-03-10 19:40:05 -0300
committerariel- <ariel-@users.noreply.github.com>2018-03-10 19:40:19 -0300
commitd6b9f148a772d07b9353a0db95a6f05c9c848a63 (patch)
tree57b08bafa579a066de8206310dc9574720fbb5b9
parente7e46b2a822cd0179b30ba5b0fa7c6fe7cea8774 (diff)
Core/Spell: fix target checks
- Aura will be applied at last moment possible (after damage) to prevent regressions on #18395 - Partial revert of 9b38a6352c0fe2499de54fd769aa1c721a410bda as it wasnt handling correctly checks without spells Closes #21578 Closes #21579 Closes #21581
-rw-r--r--src/server/game/Entities/Object/Object.cpp185
-rw-r--r--src/server/game/Entities/Object/Object.h7
-rw-r--r--src/server/game/Spells/Spell.cpp38
-rw-r--r--src/server/game/Spells/SpellEffects.cpp4
4 files changed, 100 insertions, 134 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index da0b7c3ba15..37a55a2a7ea 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -2819,18 +2819,72 @@ void WorldObject::CastSpell(Position const& dest, uint32 spellId, CastSpellExtra
}
// function based on function Unit::CanAttack from 13850 client
-bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const
+bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/) const
{
ASSERT(target);
- // can't attack self
- if (this == target)
+ // some positive spells can be casted at hostile target
+ bool isPositiveSpell = bySpell && bySpell->IsPositive();
+
+ // can't attack self (spells can, attribute check)
+ if (!bySpell && this == target)
+ return false;
+
+ // can't attack unattackable units
+ Unit const* unitTarget = target->ToUnit();
+ if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
return false;
// can't attack GMs
if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
return false;
+ Unit const* unit = ToUnit();
+ // visibility checks (only units)
+ if (unit)
+ {
+ // can't attack invisible
+ if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE))
+ {
+ if (!unit->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
+ return false;
+ }
+ }
+
+ // can't attack dead
+ if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive())
+ return false;
+
+ // can't attack untargetable
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
+ return false;
+
+ if (Player const* playerAttacker = ToPlayer())
+ {
+ if (playerAttacker->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_UBER))
+ return false;
+ }
+
+ // check flags
+ if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))
+ return false;
+
+ // ignore immunity flags when assisting
+ if (isPositiveSpell && !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
+ {
+ if (unit && !unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToNPC())
+ return false;
+
+ if (unitTarget && !unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToNPC())
+ return false;
+
+ if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToPC())
+ return false;
+
+ if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToPC())
+ return false;
+ }
+
// CvC case - can attack each other only when one of them is hostile
if (ToUnit() && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && target->ToUnit() && !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
return IsHostileTo(target) || target->IsHostileTo(this);
@@ -2869,82 +2923,6 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const
if (creatureAttacker && (creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))
return false;
- if (!bySpell)
- spellCheck = false;
-
- if (spellCheck && !IsValidSpellAttackTarget(target, bySpell))
- return false;
-
- return true;
-}
-
-bool WorldObject::IsValidSpellAttackTarget(WorldObject const* target, SpellInfo const* bySpell) const
-{
- ASSERT(target);
- ASSERT(bySpell);
-
- // can't attack unattackable units
- Unit const* unitTarget = target->ToUnit();
- if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
- return false;
-
- Unit const* unit = ToUnit();
- // visibility checks (only units)
- if (unit)
- {
- // can't attack invisible
- if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE))
- {
- if (!unit->CanSeeOrDetect(target, bySpell->IsAffectingArea()))
- return false;
-
- /*
- else if (!obj)
- {
- // ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player
- bool const ignoreStealthCheck = (bySpell && bySpell->IsAffectingArea()) ||
- (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && IsInCombatWith(target));
-
- if (!CanSeeOrDetect(target, ignoreStealthCheck))
- return false;
- }
- */
- }
- }
-
- // can't attack dead
- if (!bySpell->IsAllowingDeadTarget() && unitTarget && !unitTarget->IsAlive())
- return false;
-
- // can't attack untargetable
- if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
- return false;
-
- if (Player const* playerAttacker = ToPlayer())
- {
- if (playerAttacker->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_UBER))
- return false;
- }
-
- // check flags
- if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))
- return false;
-
- if (unit && !unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToNPC())
- return false;
-
- if (unitTarget && !unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToNPC())
- return false;
-
- if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToPC())
- return false;
-
- if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToPC())
- return false;
-
- // check duel - before sanctuary checks
- Player const* playerAffectingAttacker = unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
- Player const* playerAffectingTarget = unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr;
if (playerAffectingAttacker && playerAffectingTarget)
if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->opponent == playerAffectingTarget && playerAffectingAttacker->duel->startTime != 0)
return true;
@@ -2971,41 +2949,26 @@ bool WorldObject::IsValidSpellAttackTarget(WorldObject const* target, SpellInfo
}
// function based on function Unit::CanAssist from 13850 client
-bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const
+bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/) const
{
ASSERT(target);
+ // some negative spells can be casted at friendly target
+ bool isNegativeSpell = bySpell && !bySpell->IsPositive();
+
// can assist to self
if (this == target)
return true;
- // can't assist GMs
- if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
- return false;
-
- // can't assist non-friendly targets
- if (GetReactionTo(target) < REP_NEUTRAL && target->GetReactionTo(this) < REP_NEUTRAL && (!ToCreature() || !(ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)))
- return false;
-
- if (!bySpell)
- spellCheck = false;
-
- if (spellCheck && !IsValidSpellAssistTarget(target, bySpell))
- return false;
-
- return true;
-}
-
-bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo const* bySpell) const
-{
- ASSERT(target);
- ASSERT(bySpell);
-
// can't assist unattackable units
Unit const* unitTarget = target->ToUnit();
if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
return false;
+ // can't assist GMs
+ if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
+ return false;
+
// can't assist own vehicle or passenger
Unit const* unit = ToUnit();
if (unit && unitTarget && unit->GetVehicle())
@@ -3018,18 +2981,22 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo
}
// can't assist invisible
- if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !CanSeeOrDetect(target, bySpell->IsAffectingArea()))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
return false;
// can't assist dead
- if (!bySpell->IsAllowingDeadTarget() && unitTarget && !unitTarget->IsAlive())
+ if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive())
return false;
// can't assist untargetable
- if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
+ return false;
+
+ // check flags for negative spells
+ if (isNegativeSpell && unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))
return false;
- if (!bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
+ if (isNegativeSpell || !bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
{
if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
{
@@ -3043,6 +3010,10 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo
}
}
+ // can't assist non-friendly targets
+ if (GetReactionTo(target) < REP_NEUTRAL && target->GetReactionTo(this) < REP_NEUTRAL && (!ToCreature() || !(ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)))
+ return false;
+
// PvP case
if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
{
@@ -3070,7 +3041,7 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo
// !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) &&
else if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
{
- if (!bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
+ if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
if (unitTarget && !unitTarget->IsPvP())
if (Creature const* creatureTarget = target->ToCreature())
return ((creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) || (creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST));
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 769e293f4ce..6d9834f8282 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -443,11 +443,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
void CastSpell(WorldObject* target, uint32 spellId, CastSpellExtraArgs const& args = { });
void CastSpell(Position const& dest, uint32 spellId, CastSpellExtraArgs const& args = { });
- bool IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const;
- bool IsValidSpellAttackTarget(WorldObject const* target, SpellInfo const* bySpell) const;
-
- bool IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const;
- bool IsValidSpellAssistTarget(WorldObject const* target, SpellInfo const* bySpell) const;
+ bool IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr) const;
+ bool IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr) const;
Unit* GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index bbd290df5a4..4293ee5e268 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2293,6 +2293,7 @@ void Spell::TargetInfo::PreprocessTarget(Spell* spell)
if (missInfo != SPELL_MISS_MISS)
spell->m_caster->ToUnit()->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo);
spell->m_damage = 0;
+ spell->m_healing = 0;
_spellHitTarget = nullptr;
}
}
@@ -2555,6 +2556,20 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
spell->m_caster->ToGameObject()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
+ if (spell->_spellAura)
+ {
+ if (AuraApplication* aurApp = spell->_spellAura->GetApplicationOfTarget(_spellHitTarget->GetGUID()))
+ {
+ // only apply unapplied effects (for reapply case)
+ uint8 effMask = EffectMask & aurApp->GetEffectsToApply();
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if ((effMask & (1 << i)) && aurApp->HasEffect(i))
+ effMask &= ~(1 << i);
+
+ _spellHitTarget->_ApplyAura(aurApp, effMask);
+ }
+ }
+
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
spell->DoTriggersOnSpellHit(_spellHitTarget, EffectMask);
@@ -2643,7 +2658,7 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, bool scaleAura, TargetInfo&
else if (m_caster->IsFriendlyTo(unit))
{
// for delayed spells ignore negative spells (after duel end) for friendly targets
- if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidSpellAttackTarget(unit, m_spellInfo))
+ if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidAssistTarget(unit, m_spellInfo))
return SPELL_MISS_EVADE;
// assisting case, healing and resurrection
@@ -8005,13 +8020,13 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const
case TARGET_CHECK_ENEMY:
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo, false))
+ if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo))
return false;
break;
case TARGET_CHECK_ALLY:
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
+ if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo))
return false;
break;
case TARGET_CHECK_PARTY:
@@ -8019,7 +8034,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const
return false;
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
+ if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo))
return false;
if (!refUnit->IsInPartyWith(unitTarget))
return false;
@@ -8035,7 +8050,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const
return false;
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
+ if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo))
return false;
if (!refUnit->IsInRaidWith(unitTarget))
return false;
@@ -8043,19 +8058,6 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const
default:
break;
}
-
- // then check actual spell positivity to determine if the target is valid
- // (negative spells may be targeted on allies)
- if (_spellInfo->IsPositive())
- {
- if (!_caster->IsValidSpellAssistTarget(unitTarget, _spellInfo))
- return false;
- }
- else
- {
- if (!_caster->IsValidSpellAttackTarget(unitTarget, _spellInfo))
- return false;
- }
}
if (!_condSrcInfo)
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index e1a374596f8..96dec8e753b 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -1212,10 +1212,6 @@ void Spell::EffectApplyAura(SpellEffIndex effIndex)
aurApp = unitTarget->_CreateAuraApplication(_spellAura, 1 << effIndex);
else
aurApp->UpdateApplyEffectMask(aurApp->GetEffectsToApply() | 1 << effIndex);
-
- // apply effect on target (skip for reapply)
- if (!aurApp->HasEffect(effIndex))
- unitTarget->_ApplyAuraEffect(_spellAura, effIndex);
}
void Spell::EffectUnlearnSpecialization(SpellEffIndex effIndex)