aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp189
-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
6 files changed, 139 insertions, 103 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index d6322aed39c..1538c5ffac6 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -6604,7 +6604,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->Speed > 0.0f)
@@ -6629,7 +6629,7 @@ Unit* Unit::GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo)
for (AuraEffectList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.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)))
if (roll_chance_i((*i)->GetAmount()))
@@ -8761,13 +8761,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);
@@ -8775,9 +8770,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 (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && !target->HasFlag(UNIT_FIELD_FLAGS, 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 = HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
+ Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, 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->HasFlag(PLAYER_FLAGS, 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 & FACTION_FLAG_AT_WAR))
+ 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
@@ -8803,7 +8845,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))
@@ -8815,54 +8857,29 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
if (playerAttacker->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_UBER))
return false;
}
+
// check flags
- if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16)
- || (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToNPC())
- || (!target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToNPC())
- || (HasFlag(UNIT_FIELD_FLAGS, 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 && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT))) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToPC()))
+ if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16))
return false;
- // CvC case - can attack each other only when one of them is hostile
- if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && !target->HasFlag(UNIT_FIELD_FLAGS, 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 (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && target->IsImmuneToNPC())
return false;
- Player const* playerAffectingAttacker = HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
- Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, 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->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP))
- return true;
+ if (!target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && IsImmuneToNPC())
+ return false;
- 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 & FACTION_FLAG_AT_WAR))
- return false;
+ if (HasFlag(UNIT_FIELD_FLAGS, 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->HasFlag(UNIT_FIELD_FLAGS, 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 = HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
+ Player const* playerAffectingTarget = target->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;
@@ -8884,16 +8901,12 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
return HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_UNK1)
|| target->HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, 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);
@@ -8901,15 +8914,35 @@ 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()))
@@ -8917,11 +8950,10 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
// 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->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
return false;
if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
@@ -8938,17 +8970,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->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
+ if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
{
Player const* targetPlayerOwner = target->GetAffectingPlayer();
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
@@ -8957,29 +8980,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->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_FFA_PVP)
- && !(GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & 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->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & 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 (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)
- && (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
- && !((target->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_PVP)))
+ else if (HasFlag(UNIT_FIELD_FLAGS, 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 9186551a23d..642c25f49f9 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1081,11 +1081,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 6e4c09a9e2c..4ae0f7b54f6 100644
--- a/src/server/game/Entities/Unit/UnitDefines.h
+++ b/src/server/game/Entities/Unit/UnitDefines.h
@@ -128,8 +128,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 b6e6ae7e534..b43a8bc5cdb 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -908,7 +908,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);
@@ -1062,7 +1062,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 3e22493cbce..a92024361c8 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2578,15 +2578,12 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
if (m_spellInfo->Speed > 0.0f && unit->HasFlag(UNIT_FIELD_FLAGS, 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(AURA_INTERRUPT_FLAG_HITBYSPELL);
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->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && m_spellInfo->Id != 63881 && m_spellInfo->Id != 45034)
+ if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidSpellAttackTarget(unit, m_spellInfo))
return SPELL_MISS_EVADE;
// assisting case, healing and resurrection
@@ -7864,32 +7861,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;
@@ -7901,7 +7900,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;
@@ -7909,7 +7908,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 41ca8d54cb5..d581e1cc52e 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1792,12 +1792,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())