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:
1 parent
95bc5dcc40
commit
98a988a77a
6 files changed
+140
-110
No files matched your search
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
Reference in new issue
Block a user