Core/Spell: fix target checks
- Aura will be applied at last moment possible (after damage) to prevent regressions on #18395 - Partial revert of 9b38a6352c0fe2499de54fd769aa1c721a410bda as it wasnt handling correctly checks without spells Closes #21578 Closes #21579 Closes #21581 (cherry picked from commit d6b9f148a772d07b9353a0db95a6f05c9c848a63)
This commit is contained in:
@@ -2661,12 +2661,20 @@ void WorldObject::CastSpell(Position const& dest, uint32 spellId, CastSpellExtra
|
||||
}
|
||||
|
||||
// function based on function Unit::CanAttack from 13850 client
|
||||
bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const
|
||||
bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/) const
|
||||
{
|
||||
ASSERT(target);
|
||||
|
||||
// can't attack self
|
||||
if (this == target)
|
||||
// some positive spells can be casted at hostile target
|
||||
bool isPositiveSpell = bySpell && bySpell->IsPositive();
|
||||
|
||||
// can't attack self (spells can, attribute check)
|
||||
if (!bySpell && this == target)
|
||||
return false;
|
||||
|
||||
// can't attack unattackable units
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
|
||||
return false;
|
||||
|
||||
// can't attack GMs
|
||||
@@ -2674,10 +2682,56 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const
|
||||
return false;
|
||||
|
||||
Unit const* unit = ToUnit();
|
||||
Unit const* targetUnit = target->ToUnit();
|
||||
// visibility checks (only units)
|
||||
if (unit)
|
||||
{
|
||||
// can't attack invisible
|
||||
if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE))
|
||||
{
|
||||
if (!unit->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// can't attack dead
|
||||
if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive())
|
||||
return false;
|
||||
|
||||
// can't attack untargetable
|
||||
if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
return false;
|
||||
|
||||
if (Player const* playerAttacker = ToPlayer())
|
||||
{
|
||||
if (playerAttacker->HasPlayerFlag(PLAYER_FLAGS_UBER))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check flags
|
||||
if (unitTarget && unitTarget->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16)))
|
||||
return false;
|
||||
|
||||
// ignore immunity flags when assisting
|
||||
if (isPositiveSpell && !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
|
||||
{
|
||||
if (unit && !unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (unitTarget && !unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG))
|
||||
{
|
||||
if (unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToPC())
|
||||
return false;
|
||||
|
||||
if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// CvC case - can attack each other only when one of them is hostile
|
||||
if (unit && !unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && targetUnit && !targetUnit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
|
||||
if (unit && !unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && !unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
|
||||
return IsHostileTo(target) || target->IsHostileTo(this);
|
||||
|
||||
// PvP, PvC, CvP case
|
||||
@@ -2686,14 +2740,14 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const
|
||||
return false;
|
||||
|
||||
Player const* playerAffectingAttacker = unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
|
||||
Player const* playerAffectingTarget = targetUnit && targetUnit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr;
|
||||
Player const* playerAffectingTarget = unitTarget && unitTarget->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;
|
||||
|
||||
if (Unit const* creature = playerAffectingAttacker ? targetUnit : unit)
|
||||
if (Unit const* creature = playerAffectingAttacker ? unitTarget : unit)
|
||||
{
|
||||
if (creature->IsContestedGuard() && player->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP))
|
||||
return true;
|
||||
@@ -2714,85 +2768,6 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const
|
||||
if (creatureAttacker && (creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))
|
||||
return false;
|
||||
|
||||
if (!bySpell)
|
||||
spellCheck = false;
|
||||
|
||||
if (spellCheck && !IsValidSpellAttackTarget(target, bySpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorldObject::IsValidSpellAttackTarget(WorldObject const* target, SpellInfo const* bySpell) const
|
||||
{
|
||||
ASSERT(target);
|
||||
ASSERT(bySpell);
|
||||
|
||||
// can't attack unattackable units
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
|
||||
return false;
|
||||
|
||||
Unit const* unit = ToUnit();
|
||||
// visibility checks (only units)
|
||||
if (unit)
|
||||
{
|
||||
// can't attack invisible
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE))
|
||||
{
|
||||
if (!unit->CanSeeOrDetect(target, bySpell->IsAffectingArea()))
|
||||
return false;
|
||||
|
||||
/*
|
||||
else if (!obj)
|
||||
{
|
||||
// ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player
|
||||
bool const ignoreStealthCheck = (bySpell && bySpell->IsAffectingArea()) ||
|
||||
(target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && IsInCombatWith(target));
|
||||
|
||||
if (!CanSeeOrDetect(target, ignoreStealthCheck))
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// can't attack dead
|
||||
if (!bySpell->IsAllowingDeadTarget() && unitTarget && !unitTarget->IsAlive())
|
||||
return false;
|
||||
|
||||
// can't attack untargetable
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
return false;
|
||||
|
||||
if (Player const* playerAttacker = ToPlayer())
|
||||
{
|
||||
if (playerAttacker->HasPlayerFlag(PLAYER_FLAGS_UBER))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check flags
|
||||
if (unitTarget && unitTarget->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16)))
|
||||
return false;
|
||||
|
||||
if (unit && !unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (unitTarget && !unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG))
|
||||
{
|
||||
if (unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unitTarget && unitTarget->IsImmuneToPC())
|
||||
return false;
|
||||
|
||||
if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) && unit && unit->IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
|
||||
// check duel - before sanctuary checks
|
||||
Player const* playerAffectingAttacker = unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? GetAffectingPlayer() : nullptr;
|
||||
Player const* playerAffectingTarget = unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr;
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->opponent == playerAffectingTarget && playerAffectingAttacker->duel->startTime != 0)
|
||||
return true;
|
||||
@@ -2819,41 +2794,26 @@ bool WorldObject::IsValidSpellAttackTarget(WorldObject const* target, SpellInfo
|
||||
}
|
||||
|
||||
// function based on function Unit::CanAssist from 13850 client
|
||||
bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const
|
||||
bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/) const
|
||||
{
|
||||
ASSERT(target);
|
||||
|
||||
// some negative spells can be casted at friendly target
|
||||
bool isNegativeSpell = bySpell && !bySpell->IsPositive();
|
||||
|
||||
// can assist to self
|
||||
if (this == target)
|
||||
return true;
|
||||
|
||||
// can't assist GMs
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
|
||||
return false;
|
||||
|
||||
// can't assist non-friendly targets
|
||||
if (GetReactionTo(target) < REP_NEUTRAL && target->GetReactionTo(this) < REP_NEUTRAL && (!ToCreature() || !(ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)))
|
||||
return false;
|
||||
|
||||
if (!bySpell)
|
||||
spellCheck = false;
|
||||
|
||||
if (spellCheck && !IsValidSpellAssistTarget(target, bySpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo const* bySpell) const
|
||||
{
|
||||
ASSERT(target);
|
||||
ASSERT(bySpell);
|
||||
|
||||
// can't assist unattackable units
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
|
||||
return false;
|
||||
|
||||
// can't assist GMs
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
|
||||
return false;
|
||||
|
||||
// can't assist own vehicle or passenger
|
||||
Unit const* unit = ToUnit();
|
||||
if (unit && unitTarget && unit->GetVehicle())
|
||||
@@ -2866,23 +2826,28 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo
|
||||
}
|
||||
|
||||
// can't assist invisible
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !CanSeeOrDetect(target, bySpell->IsAffectingArea()))
|
||||
if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
|
||||
return false;
|
||||
|
||||
// can't assist dead
|
||||
if (!bySpell->IsAllowingDeadTarget() && unitTarget && !unitTarget->IsAlive())
|
||||
if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive())
|
||||
return false;
|
||||
|
||||
// can't assist untargetable
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
return false;
|
||||
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
|
||||
// check flags for negative spells
|
||||
if (isNegativeSpell && unitTarget && unitTarget->HasUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16)))
|
||||
return false;
|
||||
|
||||
if (isNegativeSpell || !bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
|
||||
{
|
||||
if (unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
|
||||
{
|
||||
if (unitTarget && unitTarget->IsImmuneToPC())
|
||||
return false;
|
||||
if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG))
|
||||
if (unitTarget && unitTarget->IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2891,6 +2856,10 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo
|
||||
}
|
||||
}
|
||||
|
||||
// can't assist non-friendly targets
|
||||
if (GetReactionTo(target) < REP_NEUTRAL && target->GetReactionTo(this) < REP_NEUTRAL && (!ToCreature() || !(ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)))
|
||||
return false;
|
||||
|
||||
// PvP case
|
||||
if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
|
||||
{
|
||||
@@ -2918,7 +2887,7 @@ bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo
|
||||
// !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) &&
|
||||
else if (unit && unit->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE))
|
||||
{
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
|
||||
if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
|
||||
if (unitTarget && !unitTarget->IsPvP())
|
||||
if (Creature const* creatureTarget = target->ToCreature())
|
||||
return ((creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) || (creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST));
|
||||
|
||||
Reference in New Issue
Block a user