aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2018-01-23 01:40:58 -0300
committerShauren <shauren.trinity@gmail.com>2021-08-28 15:59:11 +0200
commit52ae3c89d1d4dbcff309d940fd41c7212edc77b7 (patch)
treedc7940d0ea54ed3cad40edbf1df48a622860593c /src
parent1e1415a49128d034c8d48aa8cbb5d157200371b0 (diff)
Core/Spells: rework part 2: Split up target selection logic
Target check only determines what kind of entities we can target, spell positivity determines if that entity is valid for attack/assist Closes #8844 (cherry picked from commit 9b38a6352c0fe2499de54fd769aa1c721a410bda)
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp190
-rw-r--r--src/server/game/Entities/Unit/Unit.h8
-rw-r--r--src/server/game/Entities/Unit/UnitDefines.h4
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h4
-rw-r--r--src/server/game/Spells/Spell.cpp33
-rw-r--r--src/server/game/Spells/SpellInfo.cpp4
7 files changed, 140 insertions, 107 deletions
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
index e389d58d543..773226e43fe 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
@@ -605,11 +605,11 @@ bool UnitFitToActionRequirement(Unit* unit, Unit* caster, AreaTriggerAction cons
{
case AREATRIGGER_ACTION_USER_FRIEND:
{
- return caster->_IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
+ return caster->IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
}
case AREATRIGGER_ACTION_USER_ENEMY:
{
- return caster->_IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
+ return caster->IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
}
case AREATRIGGER_ACTION_USER_RAID:
{
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 94cbeaf9bc0..fadd871a970 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -6540,7 +6540,7 @@ Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo)
{
if (Unit* magnet = (*itr)->GetBase()->GetCaster())
if (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
- && _IsValidAttackTarget(magnet, spellInfo))
+ && IsValidAttackTarget(magnet, spellInfo))
{
/// @todo handle this charge drop by proc in cast phase on explicit target
if (spellInfo->HasHitDelay())
@@ -6571,7 +6571,7 @@ Unit* Unit::GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo /
for (AuraEffectList::const_iterator i = interceptAuras.begin(); i != interceptAuras.end(); ++i)
{
if (Unit* magnet = (*i)->GetBase()->GetCaster())
- if (_IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this)
+ if (IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this)
&& (!spellInfo || (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
&& spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK)))
{
@@ -8270,13 +8270,8 @@ bool Unit::isTargetableForAttack(bool checkFakeDeath) const
return !HasUnitState(UNIT_STATE_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STATE_DIED));
}
-bool Unit::IsValidAttackTarget(Unit const* target) const
-{
- return _IsValidAttackTarget(target, nullptr);
-}
-
// function based on function Unit::CanAttack from 13850 client
-bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj) const
+bool Unit::IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell /*= nullptr*/, WorldObject const* obj /*= nullptr*/, bool spellCheck /*= true*/) const
{
ASSERT(target);
@@ -8284,9 +8279,56 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
if (this == target)
return false;
- // can't attack unattackable units or GMs
- if (target->HasUnitState(UNIT_STATE_UNATTACKABLE)
- || (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster()))
+ // can't attack GMs
+ if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
+ return false;
+
+ // CvC case - can attack each other only when one of them is hostile
+ if (!HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && !target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
+ return IsHostileTo(target) || target->IsHostileTo(this);
+
+ // PvP, PvC, CvP case
+ // can't attack friendly targets
+ if (IsFriendlyTo(target) || target->IsFriendlyTo(this))
+ return false;
+
+ Player const* playerAffectingAttacker = HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
+ Player const* playerAffectingTarget = target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr;
+
+ // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
+ if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
+ {
+ Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
+ Unit const* creature = playerAffectingAttacker ? target : this;
+
+ if (creature->IsContestedGuard() && player->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP))
+ return true;
+
+ if (FactionTemplateEntry const* factionTemplate = creature->GetFactionTemplateEntry())
+ {
+ if (!(player->GetReputationMgr().GetForcedRankIfAny(factionTemplate)))
+ if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->Faction))
+ if (FactionState const* repState = player->GetReputationMgr().GetState(factionEntry))
+ if (!repState->Flags.HasFlag(ReputationFlags::AtWar))
+ return false;
+
+ }
+ }
+
+ Creature const* creatureAttacker = ToCreature();
+ if (creatureAttacker && (creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))
+ return false;
+
+ if (spellCheck && !IsValidSpellAttackTarget(target, bySpell, obj))
+ return false;
+
+ return true;
+}
+
+bool Unit::IsValidSpellAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj /*= nullptr*/) const
+{
+ // can't attack unattackable units
+ if (target->HasUnitState(UNIT_STATE_UNATTACKABLE))
return false;
// visibility checks
@@ -8312,7 +8354,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
// can't attack dead
if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && !target->IsAlive())
- return false;
+ return false;
// can't attack untargetable
if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
@@ -8326,56 +8368,28 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
}
// check flags
- if (target->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))
- || (!HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToNPC())
- || (!target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToNPC()))
+ if (target->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16)))
return false;
- if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG))
- && (HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToPC())
- // check if this is a world trigger cast - GOs are using world triggers to cast their spells, so we need to ignore their immunity flag here, this is a temp workaround, needs removal when go cast is implemented properly
- && GetEntry() != WORLD_TRIGGER)
+ if (!HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToNPC())
return false;
- // CvC case - can attack each other only when one of them is hostile
- if (!HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && !target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
- return GetReactionTo(target) <= REP_HOSTILE || target->GetReactionTo(this) <= REP_HOSTILE;
-
- // PvP, PvC, CvP case
- // can't attack friendly targets
- if (GetReactionTo(target) > REP_NEUTRAL
- || target->GetReactionTo(this) > REP_NEUTRAL)
+ if (!target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToNPC())
return false;
- Player const* playerAffectingAttacker = HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
- Player const* playerAffectingTarget = target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr;
-
- // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
- if ((playerAffectingAttacker && !playerAffectingTarget) ||
- (!playerAffectingAttacker && playerAffectingTarget))
- {
- Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
- Unit const* creature = playerAffectingAttacker ? target : this;
-
- if (creature->IsContestedGuard() && player->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP))
- return true;
-
- if (FactionTemplateEntry const* factionTemplate = creature->GetFactionTemplateEntry())
- {
- if (!(player->GetReputationMgr().GetForcedRankIfAny(factionTemplate)))
- if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->Faction))
- if (FactionState const* repState = player->GetReputationMgr().GetState(factionEntry))
- if (!repState->Flags.HasFlag(ReputationFlags::AtWar))
- return false;
+ if ((!bySpell || bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG))
+ && HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToPC())
+ return false;
- }
- }
+ // check if this is a world trigger cast - GOs are using world triggers to cast their spells, so we need to ignore their immunity flag here, this is a temp workaround, needs removal when go cast is implemented properly
+ if (target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToPC())
+ if (GetEntry() != WORLD_TRIGGER && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT)))
+ return false;
- Creature const* creatureAttacker = ToCreature();
- if (creatureAttacker && creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)
- return false;
// check duel - before sanctuary checks
+ Player const* playerAffectingAttacker = HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
+ Player const* playerAffectingTarget = target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr;
if (playerAffectingAttacker && playerAffectingTarget)
if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->opponent == playerAffectingTarget && playerAffectingAttacker->duel->startTime != 0)
return true;
@@ -8397,16 +8411,12 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
return HasPvpFlag(UNIT_BYTE2_FLAG_UNK1)
|| target->HasPvpFlag(UNIT_BYTE2_FLAG_UNK1);
}
- return true;
-}
-bool Unit::IsValidAssistTarget(Unit const* target) const
-{
- return _IsValidAssistTarget(target, nullptr);
+ return true;
}
// function based on function Unit::CanAssist from 13850 client
-bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) const
+bool Unit::IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const
{
ASSERT(target);
@@ -8414,27 +8424,46 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
if (this == target)
return true;
- // can't assist unattackable units or GMs
- if (target->HasUnitState(UNIT_STATE_UNATTACKABLE)
- || (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster()))
+ // 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 (spellCheck && !IsValidSpellAssistTarget(target, bySpell))
+ return false;
+
+ return true;
+}
+
+bool Unit::IsValidSpellAssistTarget(Unit const* target, SpellInfo const* bySpell) const
+{
+ // can't assist unattackable units
+ if (target->HasUnitState(UNIT_STATE_UNATTACKABLE))
return false;
// can't assist own vehicle or passenger
if (m_vehicle)
- if (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target))
+ {
+ if (IsOnVehicle(target))
return false;
+ if (m_vehicle->GetBase()->IsOnVehicle(target))
+ return false;
+ }
+
// can't assist invisible
if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
return false;
// can't assist dead
if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && !target->IsAlive())
- return false;
+ return false;
// can't assist untargetable
- if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
- && target->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && target->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
return false;
if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
@@ -8451,17 +8480,8 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
}
}
- // 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;
-
- // Controlled player case, we can assist creatures (reaction already checked above, our faction == charmer faction)
- if (GetTypeId() == TYPEID_PLAYER && IsCharmed() && GetCharmerGUID().IsCreature())
- return true;
// PvP case
- else if (target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
+ if (target->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
{
Player const* targetPlayerOwner = target->GetAffectingPlayer();
if (HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
@@ -8470,29 +8490,29 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
if (selfPlayerOwner && targetPlayerOwner)
{
// can't assist player which is dueling someone
- if (selfPlayerOwner != targetPlayerOwner
- && targetPlayerOwner->duel)
+ if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner->duel)
return false;
}
// can't assist player in ffa_pvp zone from outside
- if (target->HasPvpFlag(UNIT_BYTE2_FLAG_FFA_PVP)
- && !HasPvpFlag(UNIT_BYTE2_FLAG_FFA_PVP))
+ if (target->IsFFAPvP() && !IsFFAPvP())
return false;
+
// can't assist player out of sanctuary from sanctuary if has pvp enabled
- if (target->HasPvpFlag(UNIT_BYTE2_FLAG_PVP))
+ if (target->IsPvP())
if (IsInSanctuary() && !target->IsInSanctuary())
return false;
}
}
// PvC case - player can assist creature only if has specific type flags
// !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) &&
- else if (HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)
- && (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
- && !target->HasPvpFlag(UNIT_BYTE2_FLAG_PVP))
+ else if (HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
{
- 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;
+ if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
+ if (!target->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;
}
+
return true;
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index da63f0558c7..a2bb7f1a301 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1161,11 +1161,11 @@ class TC_GAME_API Unit : public WorldObject
bool isTargetableForAttack(bool checkFakeDeath = true) const;
- bool IsValidAttackTarget(Unit const* target) const;
- bool _IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj = nullptr) const;
+ bool IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell = nullptr, WorldObject const* obj = nullptr, bool spellCheck = true) const;
+ bool IsValidSpellAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj = nullptr) const;
- bool IsValidAssistTarget(Unit const* target) const;
- bool _IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) const;
+ bool IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const;
+ bool IsValidSpellAssistTarget(Unit const* target, SpellInfo const* bySpell) const;
virtual bool IsInWater() const;
virtual bool IsUnderWater() const;
diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h
index b0191780ae8..fac8eda8d46 100644
--- a/src/server/game/Entities/Unit/UnitDefines.h
+++ b/src/server/game/Entities/Unit/UnitDefines.h
@@ -124,8 +124,8 @@ enum UnitFlags : uint32
UNIT_FLAG_PREPARATION = 0x00000020, // don't take reagents for spells with SPELL_ATTR5_NO_REAGENT_WHILE_PREP
UNIT_FLAG_UNK_6 = 0x00000040,
UNIT_FLAG_NOT_ATTACKABLE_1 = 0x00000080, // ?? (UNIT_FLAG_PVP_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1) is NON_PVP_ATTACKABLE
- UNIT_FLAG_IMMUNE_TO_PC = 0x00000100, // disables combat/assistance with PlayerCharacters (PC) - see Unit::_IsValidAttackTarget, Unit::_IsValidAssistTarget
- UNIT_FLAG_IMMUNE_TO_NPC = 0x00000200, // disables combat/assistance with NonPlayerCharacters (NPC) - see Unit::_IsValidAttackTarget, Unit::_IsValidAssistTarget
+ UNIT_FLAG_IMMUNE_TO_PC = 0x00000100, // disables combat/assistance with PlayerCharacters (PC) - see Unit::IsValidAttackTarget, Unit::IsValidAssistTarget
+ UNIT_FLAG_IMMUNE_TO_NPC = 0x00000200, // disables combat/assistance with NonPlayerCharacters (NPC) - see Unit::IsValidAttackTarget, Unit::IsValidAssistTarget
UNIT_FLAG_LOOTING = 0x00000400, // loot animation
UNIT_FLAG_PET_IN_COMBAT = 0x00000800, // on player pets: whether the pet is chasing a target to attack || on other units: whether any of the unit's minions is in combat
UNIT_FLAG_PVP = 0x00001000, // changed in 3.0.3
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 0f584f9a999..31fb37fd15e 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -951,7 +951,7 @@ namespace Trinity
if (!u->isTargetableForAttack(false))
return false;
- if (!i_obj->IsWithinDistInMap(u, i_range) || !i_funit->_IsValidAttackTarget(u, nullptr, i_obj))
+ if (!i_obj->IsWithinDistInMap(u, i_range) || !i_funit->IsValidAttackTarget(u))
return false;
i_range = i_obj->GetDistance(*u);
@@ -1106,7 +1106,7 @@ namespace Trinity
if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS) && u->GetTypeId() != TYPEID_PLAYER)
return false;
- if (!i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr))
+ if (!i_funit->IsValidAttackTarget(u, _spellInfo))
return false;
float searchRadius = i_range;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index f803210e6d2..cfb0e4703e9 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2718,15 +2718,12 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
if (m_spellInfo->HasHitDelay() && unit->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) && unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
return SPELL_MISS_EVADE;
- if (m_caster->_IsValidAttackTarget(unit, m_spellInfo))
+ if (m_caster->IsValidAttackTarget(unit, m_spellInfo))
unit->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::HostileActionReceived);
else if (m_caster->IsFriendlyTo(unit))
{
// for delayed spells ignore negative spells (after duel end) for friendly targets
- /// @todo this cause soul transfer bugged
- // 63881 - Malady of the Mind jump spell (Yogg-Saron)
- // 45034 - Curse of Boundless Agony jump spell (Kalecgos)
- if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && m_spellInfo->Id != 63881 && m_spellInfo->Id != 45034)
+ if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidSpellAttackTarget(unit, m_spellInfo))
return SPELL_MISS_EVADE;
// assisting case, healing and resurrection
@@ -8090,32 +8087,34 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
Unit* unitTarget = target->ToUnit();
if (Corpse* corpseTarget = target->ToCorpse())
{
- // use ofter for party/assistance checks
+ // use owner for party/assistance checks
if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
unitTarget = owner;
else
return false;
}
+
if (unitTarget)
{
+ // do only faction checks here
switch (_targetSelectionType)
{
case TARGET_CHECK_ENEMY:
if (unitTarget->IsTotem())
return false;
- if (!_caster->_IsValidAttackTarget(unitTarget, _spellInfo))
+ if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo, nullptr, false))
return false;
break;
case TARGET_CHECK_ALLY:
if (unitTarget->IsTotem())
return false;
- if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
+ if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
return false;
break;
case TARGET_CHECK_PARTY:
if (unitTarget->IsTotem())
return false;
- if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
+ if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
return false;
if (!_referer->IsInPartyWith(unitTarget))
return false;
@@ -8127,7 +8126,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
case TARGET_CHECK_RAID:
if (unitTarget->IsTotem())
return false;
- if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
+ if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
return false;
if (!_referer->IsInRaidWith(unitTarget))
return false;
@@ -8162,7 +8161,21 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
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)
return true;
_condSrcInfo->mConditionTargets[0] = target;
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 5e319774fc4..e1aceb1de97 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -2265,12 +2265,12 @@ SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject c
if (neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT_ALLY | TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_UNIT_PASSENGER))
{
if (neededTargets & TARGET_FLAG_UNIT_ENEMY)
- if (caster->_IsValidAttackTarget(unitTarget, this))
+ if (caster->IsValidAttackTarget(unitTarget, this))
return SPELL_CAST_OK;
if (neededTargets & TARGET_FLAG_UNIT_ALLY
|| (neededTargets & TARGET_FLAG_UNIT_PARTY && caster->IsInPartyWith(unitTarget))
|| (neededTargets & TARGET_FLAG_UNIT_RAID && caster->IsInRaidWith(unitTarget)))
- if (caster->_IsValidAssistTarget(unitTarget, this))
+ if (caster->IsValidAssistTarget(unitTarget, this))
return SPELL_CAST_OK;
if (neededTargets & TARGET_FLAG_UNIT_MINIPET)
if (unitTarget->GetGUID() == caster->GetCritterGUID())