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
This commit is contained in:
ariel- authored and Ovahlord committed 2022-09-12 09:15:13 +02:00
1 parent 95bc5dcc40
commit 98a988a77a
6 files changed
+140 -110

No files matched your search

+106 -90
View File
@@ -6390,7 +6390,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)
@@ -6415,7 +6415,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()))
@@ -8484,13 +8484,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);
@@ -8498,9 +8493,55 @@ 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_PLAYER_CONTROLLED) && !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
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_PLAYER_CONTROLLED) ? GetAffectingPlayer() : nullptr;
Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? 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
@@ -8526,7 +8567,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))
@@ -8540,64 +8581,34 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
}
// check flags
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_NOT_ATTACKABLE_2)
|| (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && target->IsImmuneToNPC())
|| (!target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && IsImmuneToNPC()))
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_NOT_ATTACKABLE_2))
return false;
if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG))
&& (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && 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 (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && target->IsImmuneToNPC())
return false;
// CvC case - can attack each other only when one of them is hostile
if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
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->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && IsImmuneToNPC())
return false;
Player const* playerAffectingAttacker = HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? GetAffectingPlayer() : nullptr;
Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? 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)
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && 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_PLAYER_CONTROLLED) && IsImmuneToPC())
if (GetEntry() != WORLD_TRIGGER && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT)))
return false;
// check duel - before sanctuary checks
Player const* playerAffectingAttacker = HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? GetAffectingPlayer() : nullptr;
Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? target->GetAffectingPlayer() : nullptr;
if (playerAffectingAttacker && playerAffectingTarget)
if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->opponent == playerAffectingTarget && playerAffectingAttacker->duel->startTime != 0)
return true;
// PvP case - can't attack when attacker or target are in sanctuary
// however, 13850 client doesn't allow to attack when one of the unit's has sanctuary flag and is pvp
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)
&& ((target->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_SANCTUARY) || (GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_SANCTUARY)))
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && (target->IsInSanctuary() || IsInSanctuary()))
return false;
// additional checks - only PvP case
@@ -8612,16 +8623,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);
}
// 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);
@@ -8629,27 +8636,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->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))
@@ -8666,18 +8692,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_PLAYER_CONTROLLED))
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
{
Player const* targetPlayerOwner = target->GetAffectingPlayer();
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
@@ -8686,29 +8702,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 ((GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG) & UNIT_BYTE2_FLAG_SANCTUARY) && !(target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_SANCTUARY))
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_PLAYER_CONTROLLED)
&& (!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_PLAYER_CONTROLLED))
{
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;
}
+5 -4
View File
@@ -1009,6 +1009,7 @@ class TC_GAME_API Unit : public WorldObject
bool IsInRaidWith(Unit const* unit) const;
void GetPartyMembers(std::list<Unit*> &units);
bool IsContestedGuard() const;
bool IsInSanctuary() const { return HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_SANCTUARY); }
bool IsPvP() const { return HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_PVP); }
bool IsFFAPvP() const { return HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_FFA_PVP); }
virtual void SetPvP(bool state);
@@ -1168,11 +1169,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;
bool IsInWater() const;
bool IsUnderWater() const;
+2 -2
View File
@@ -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_PLAYER_CONTROLLED | 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
@@ -930,7 +930,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);
@@ -1088,7 +1088,7 @@ namespace Trinity
if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR5_DONT_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;
+23 -10
View File
@@ -2817,15 +2817,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(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->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
@@ -8395,32 +8392,34 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
Unit* unitTarget = target->ToUnit();
if (Corpse* corpse = target->ToCorpse())
{
// use ofter for party/assistance checks
// use owner for party/assistance checks
if (Player* owner = ObjectAccessor::FindPlayer(corpse->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 (!target->IsCorpse() && !_caster->_IsValidAttackTarget(unitTarget, _spellInfo))
if (!target->IsCorpse() && !_caster->IsValidAttackTarget(unitTarget, _spellInfo, nullptr, false))
return false;
break;
case TARGET_CHECK_ALLY:
if (unitTarget->IsTotem())
return false;
if (!target->IsCorpse() && !_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
return false;
break;
case TARGET_CHECK_PARTY:
if (unitTarget->IsTotem())
return false;
if (!target->IsCorpse() && !_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
return false;
if (!_referer->IsInPartyWith(unitTarget))
return false;
@@ -8432,7 +8431,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
case TARGET_CHECK_RAID:
if (unitTarget->IsTotem())
return false;
if (!target->IsCorpse() && !_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
return false;
if (!_referer->IsInRaidWith(unitTarget))
return false;
@@ -8456,7 +8455,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;
+2 -2
View File
@@ -2048,12 +2048,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())