Core/Spell: fix target checks
Port From (https://github.com/TrinityCore/TrinityCore/commit/a2ea26816e19224484377697311f3de1f4cc8f55)
This commit is contained in:
@@ -2277,12 +2277,20 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
// function based on function Unit::CanAttack from 13850 client
|
// function based on function Unit::CanAttack from 13850 client
|
||||||
public bool IsValidAttackTarget(WorldObject target, SpellInfo bySpell = null, bool spellCheck = true)
|
public bool IsValidAttackTarget(WorldObject target, SpellInfo bySpell = null)
|
||||||
{
|
{
|
||||||
Cypher.Assert(target != null);
|
Cypher.Assert(target != null);
|
||||||
|
|
||||||
// can't attack self
|
// some positive spells can be casted at hostile target
|
||||||
if (this == target)
|
bool isPositiveSpell = bySpell != null && bySpell.IsPositive();
|
||||||
|
|
||||||
|
// can't attack self (spells can, attribute check)
|
||||||
|
if (bySpell == null && this == target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// can't attack unattackable units
|
||||||
|
Unit unitTarget = target.ToUnit();
|
||||||
|
if (unitTarget != null && unitTarget.HasUnitState(UnitState.Unattackable))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// can't attack GMs
|
// can't attack GMs
|
||||||
@@ -2290,10 +2298,57 @@ namespace Game.Entities
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit unit = ToUnit();
|
Unit unit = ToUnit();
|
||||||
Unit targetUnit = target.ToUnit();
|
// visibility checks (only units)
|
||||||
|
if (unit != null)
|
||||||
|
{
|
||||||
|
// can't attack invisible
|
||||||
|
if (bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetInvisible))
|
||||||
|
{
|
||||||
|
if (!unit.CanSeeOrDetect(target, bySpell != null && bySpell.IsAffectingArea()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't attack dead
|
||||||
|
if ((bySpell == null || !bySpell.IsAllowingDeadTarget()) && unitTarget != null && !unitTarget.IsAlive())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// can't attack untargetable
|
||||||
|
if ((bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable)) && unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Player playerAttacker = ToPlayer();
|
||||||
|
if (playerAttacker != null)
|
||||||
|
{
|
||||||
|
if (playerAttacker.HasPlayerFlag(PlayerFlags.Uber))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check flags
|
||||||
|
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.NonAttackable | UnitFlags.TaxiFlight | UnitFlags.NotAttackable1 | UnitFlags.Unk16))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// ignore immunity flags when assisting
|
||||||
|
if (isPositiveSpell && !bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
||||||
|
{
|
||||||
|
if (unit != null && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget != null && unitTarget.IsImmuneToNPC())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (unitTarget != null && !unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToNPC())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPCFlag))
|
||||||
|
{
|
||||||
|
if (unit != null && unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToPC())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToPC())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CvC case - can attack each other only when one of them is hostile
|
// CvC case - can attack each other only when one of them is hostile
|
||||||
if (unit && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && targetUnit && !targetUnit.HasUnitFlag(UnitFlags.PvpAttackable))
|
if (unit && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget != null && !unitTarget.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||||
return IsHostileTo(target) || target.IsHostileTo(this);
|
return IsHostileTo(target) || target.IsHostileTo(this);
|
||||||
|
|
||||||
// PvP, PvC, CvP case
|
// PvP, PvC, CvP case
|
||||||
@@ -2301,14 +2356,14 @@ namespace Game.Entities
|
|||||||
if (IsFriendlyTo(target) || target.IsFriendlyTo(this))
|
if (IsFriendlyTo(target) || target.IsFriendlyTo(this))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Player playerAffectingAttacker = unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
|
Player playerAffectingAttacker = unit != null && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
|
||||||
Player playerAffectingTarget = targetUnit && targetUnit.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
|
Player playerAffectingTarget = unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
|
||||||
|
|
||||||
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
|
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
|
||||||
if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
|
if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
|
||||||
{
|
{
|
||||||
Player player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
|
Player player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
|
||||||
Unit creature = playerAffectingAttacker ? targetUnit : unit;
|
Unit creature = playerAffectingAttacker ? unitTarget : unit;
|
||||||
if (creature != null)
|
if (creature != null)
|
||||||
{
|
{
|
||||||
if (creature.IsContestedGuard() && player.HasPlayerFlag(PlayerFlags.ContestedPVP))
|
if (creature.IsContestedGuard() && player.HasPlayerFlag(PlayerFlags.ContestedPVP))
|
||||||
@@ -2337,86 +2392,6 @@ namespace Game.Entities
|
|||||||
if (creatureAttacker && creatureAttacker.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit))
|
if (creatureAttacker && creatureAttacker.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bySpell == null)
|
|
||||||
spellCheck = false;
|
|
||||||
|
|
||||||
if (spellCheck && !IsValidSpellAttackTarget(target, bySpell))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsValidSpellAttackTarget(WorldObject target, SpellInfo bySpell)
|
|
||||||
{
|
|
||||||
Cypher.Assert(target != null);
|
|
||||||
Cypher.Assert(bySpell != null);
|
|
||||||
|
|
||||||
// can't attack unattackable units
|
|
||||||
Unit unitTarget = target.ToUnit();
|
|
||||||
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit unit = ToUnit();
|
|
||||||
// visibility checks (only units)
|
|
||||||
if (unit)
|
|
||||||
{
|
|
||||||
// can't attack invisible
|
|
||||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetInvisible))
|
|
||||||
{
|
|
||||||
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(SpellAttr6.CanTargetInvisible) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Player playerAttacker = ToPlayer();
|
|
||||||
if (playerAttacker != null)
|
|
||||||
{
|
|
||||||
if (playerAttacker.HasPlayerFlag(PlayerFlags.Uber))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check flags
|
|
||||||
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.NonAttackable | UnitFlags.TaxiFlight | UnitFlags.NotAttackable1 | UnitFlags.Unk16))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (unit != null && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToNPC())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (unitTarget != null && !unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToNPC())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPCFlag))
|
|
||||||
{
|
|
||||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToPC())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToPC())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check duel - before sanctuary checks
|
|
||||||
Player playerAffectingAttacker = unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
|
|
||||||
Player playerAffectingTarget = unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
|
|
||||||
if (playerAffectingAttacker && playerAffectingTarget)
|
if (playerAffectingAttacker && playerAffectingTarget)
|
||||||
if (playerAffectingAttacker.duel != null && playerAffectingAttacker.duel.opponent == playerAffectingTarget && playerAffectingAttacker.duel.startTime != 0)
|
if (playerAffectingAttacker.duel != null && playerAffectingAttacker.duel.opponent == playerAffectingTarget && playerAffectingAttacker.duel.startTime != 0)
|
||||||
return true;
|
return true;
|
||||||
@@ -2447,37 +2422,22 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
Cypher.Assert(target);
|
Cypher.Assert(target);
|
||||||
|
|
||||||
|
// some negative spells can be casted at friendly target
|
||||||
|
bool isNegativeSpell = bySpell != null && !bySpell.IsPositive();
|
||||||
|
|
||||||
// can assist to self
|
// can assist to self
|
||||||
if (this == target)
|
if (this == target)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// can't assist GMs
|
|
||||||
if (target.IsPlayer() && target.ToPlayer().IsGameMaster())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// can't assist non-friendly targets
|
|
||||||
if (GetReactionTo(target) < ReputationRank.Neutral && target.GetReactionTo(this) < ReputationRank.Neutral && (!ToCreature() || !ToCreature().GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bySpell == null)
|
|
||||||
spellCheck = false;
|
|
||||||
|
|
||||||
if (spellCheck && !IsValidSpellAssistTarget(target, bySpell))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsValidSpellAssistTarget(WorldObject target, SpellInfo bySpell)
|
|
||||||
{
|
|
||||||
Cypher.Assert(target != null);
|
|
||||||
Cypher.Assert(bySpell != null);
|
|
||||||
|
|
||||||
// can't assist unattackable units
|
// can't assist unattackable units
|
||||||
Unit unitTarget = target.ToUnit();
|
Unit unitTarget = target.ToUnit();
|
||||||
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
|
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// can't assist GMs
|
||||||
|
if (target.IsPlayer() && target.ToPlayer().IsGameMaster())
|
||||||
|
return false;
|
||||||
|
|
||||||
// can't assist own vehicle or passenger
|
// can't assist own vehicle or passenger
|
||||||
Unit unit = ToUnit();
|
Unit unit = ToUnit();
|
||||||
if (unit && unitTarget && unit.GetVehicle())
|
if (unit && unitTarget && unit.GetVehicle())
|
||||||
@@ -2490,39 +2450,48 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
// can't assist invisible
|
// can't assist invisible
|
||||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetInvisible) && !CanSeeOrDetect(target, bySpell.IsAffectingArea()))
|
if ((bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetInvisible)) && !CanSeeOrDetect(target, bySpell != null && bySpell.IsAffectingArea()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// can't assist dead
|
// can't assist dead
|
||||||
if (!bySpell.IsAllowingDeadTarget() && unitTarget && !unitTarget.IsAlive())
|
if ((bySpell == null || !bySpell.IsAllowingDeadTarget()) && unitTarget && !unitTarget.IsAlive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// can't assist untargetable
|
// can't assist untargetable
|
||||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
|
if ((bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable)) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
// check flags for negative spells
|
||||||
|
if (isNegativeSpell && unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.NonAttackable | UnitFlags.TaxiFlight | UnitFlags.NotAttackable1 | UnitFlags.Unk16))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isNegativeSpell || bySpell == null || !bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
||||||
{
|
{
|
||||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
if (unit != null && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||||
{
|
{
|
||||||
if (unitTarget && unitTarget.IsImmuneToPC())
|
if (bySpell == null || !bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPCFlag))
|
||||||
return false;
|
if (unitTarget != null && unitTarget.IsImmuneToPC())
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (unitTarget && unitTarget.IsImmuneToNPC())
|
if (unitTarget != null && unitTarget.IsImmuneToNPC())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// can't assist non-friendly targets
|
||||||
|
if (GetReactionTo(target) < ReputationRank.Neutral && target.GetReactionTo(this) < ReputationRank.Neutral && (!ToCreature() || !ToCreature().GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit)))
|
||||||
|
return false;
|
||||||
|
|
||||||
// PvP case
|
// PvP case
|
||||||
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable))
|
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||||
{
|
{
|
||||||
Player targetPlayerOwner = target.GetAffectingPlayer();
|
Player targetPlayerOwner = target.GetAffectingPlayer();
|
||||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
if (unit != null && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||||
{
|
{
|
||||||
Player selfPlayerOwner = GetAffectingPlayer();
|
Player selfPlayerOwner = GetAffectingPlayer();
|
||||||
if (selfPlayerOwner && targetPlayerOwner)
|
if (selfPlayerOwner != null && targetPlayerOwner != null)
|
||||||
{
|
{
|
||||||
// can't assist player which is dueling someone
|
// can't assist player which is dueling someone
|
||||||
if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner.duel != null)
|
if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner.duel != null)
|
||||||
@@ -2534,21 +2503,23 @@ namespace Game.Entities
|
|||||||
|
|
||||||
// can't assist player out of sanctuary from sanctuary if has pvp enabled
|
// can't assist player out of sanctuary from sanctuary if has pvp enabled
|
||||||
if (unitTarget.IsPvP())
|
if (unitTarget.IsPvP())
|
||||||
if (unit && unit.IsInSanctuary() && !unitTarget.IsInSanctuary())
|
if (unit != null && unit.IsInSanctuary() && !unitTarget.IsInSanctuary())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// PvC case - player can assist creature only if has specific type flags
|
// PvC case - player can assist creature only if has specific type flags
|
||||||
// !target.HasFlag(UNIT_FIELD_FLAGS, UnitFlags.PvpAttackable) &&
|
// !target.HasFlag(UNIT_FIELD_FLAGS, UnitFlags.PvpAttackable) &&
|
||||||
else if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
else if (unit != null && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||||
{
|
{
|
||||||
if (!bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
if (bySpell == null || !bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
||||||
if (unitTarget && !unitTarget.IsPvP())
|
{
|
||||||
|
if (unitTarget != null && !unitTarget.IsPvP())
|
||||||
{
|
{
|
||||||
Creature creatureTarget = target.ToCreature();
|
Creature creatureTarget = target.ToCreature();
|
||||||
if (creatureTarget != null)
|
if (creatureTarget != null)
|
||||||
return (creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit) || creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.CanAssist));
|
return (creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit) || creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.CanAssist));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+18
-15
@@ -1919,7 +1919,7 @@ namespace Game.Spells
|
|||||||
else if (m_caster.IsFriendlyTo(unit))
|
else if (m_caster.IsFriendlyTo(unit))
|
||||||
{
|
{
|
||||||
// for delayed spells ignore negative spells (after duel end) for friendly targets
|
// for delayed spells ignore negative spells (after duel end) for friendly targets
|
||||||
if (m_spellInfo.HasHitDelay() && unit.IsPlayer() && !IsPositive() && !m_caster.IsValidSpellAttackTarget(unit, m_spellInfo))
|
if (m_spellInfo.HasHitDelay() && unit.IsPlayer() && !IsPositive() && !m_caster.IsValidAssistTarget(unit, m_spellInfo))
|
||||||
return SpellMissInfo.Evade;
|
return SpellMissInfo.Evade;
|
||||||
|
|
||||||
// assisting case, healing and resurrection
|
// assisting case, healing and resurrection
|
||||||
@@ -7702,6 +7702,7 @@ namespace Game.Spells
|
|||||||
if (missInfo != SpellMissInfo.Miss)
|
if (missInfo != SpellMissInfo.Miss)
|
||||||
spell.GetCaster().ToUnit().SendSpellMiss(unit, spell.m_spellInfo.Id, missInfo);
|
spell.GetCaster().ToUnit().SendSpellMiss(unit, spell.m_spellInfo.Id, missInfo);
|
||||||
spell.m_damage = 0;
|
spell.m_damage = 0;
|
||||||
|
spell.m_healing = 0;
|
||||||
_spellHitTarget = null;
|
_spellHitTarget = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7966,6 +7967,21 @@ namespace Game.Spells
|
|||||||
else if (spell.GetCaster().IsGameObject() && spell.GetCaster().ToGameObject().GetAI() != null)
|
else if (spell.GetCaster().IsGameObject() && spell.GetCaster().ToGameObject().GetAI() != null)
|
||||||
spell.GetCaster().ToGameObject().GetAI().SpellHitTarget(_spellHitTarget, spell.m_spellInfo);
|
spell.GetCaster().ToGameObject().GetAI().SpellHitTarget(_spellHitTarget, spell.m_spellInfo);
|
||||||
|
|
||||||
|
if (spell.spellAura != null)
|
||||||
|
{
|
||||||
|
AuraApplication aurApp = spell.spellAura.GetApplicationOfTarget(_spellHitTarget.GetGUID());
|
||||||
|
if (aurApp != null)
|
||||||
|
{
|
||||||
|
// only apply unapplied effects (for reapply case)
|
||||||
|
uint effMask = EffectMask & aurApp.GetEffectsToApply();
|
||||||
|
for (uint i = 0; i < spell.m_spellInfo.GetEffects().Count; ++i)
|
||||||
|
if ((effMask & (1 << (int)i)) != 0 && aurApp.HasEffect(i))
|
||||||
|
effMask &= ~(1u << (int)i);
|
||||||
|
|
||||||
|
_spellHitTarget._ApplyAura(aurApp, effMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
|
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
|
||||||
spell.DoTriggersOnSpellHit(_spellHitTarget, EffectMask);
|
spell.DoTriggersOnSpellHit(_spellHitTarget, EffectMask);
|
||||||
|
|
||||||
@@ -8120,7 +8136,7 @@ namespace Game.Spells
|
|||||||
case SpellTargetCheckTypes.Enemy:
|
case SpellTargetCheckTypes.Enemy:
|
||||||
if (unitTarget.IsTotem())
|
if (unitTarget.IsTotem())
|
||||||
return false;
|
return false;
|
||||||
if (!_caster.IsValidAttackTarget(unitTarget, _spellInfo, false))
|
if (!_caster.IsValidAttackTarget(unitTarget, _spellInfo))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case SpellTargetCheckTypes.Ally:
|
case SpellTargetCheckTypes.Ally:
|
||||||
@@ -8186,19 +8202,6 @@ namespace Game.Spells
|
|||||||
default:
|
default:
|
||||||
break;
|
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 == null)
|
if (_condSrcInfo == null)
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -711,10 +711,6 @@ namespace Game.Spells
|
|||||||
aurApp = unitTarget._CreateAuraApplication(spellAura, 1u << (int)effectInfo.EffectIndex);
|
aurApp = unitTarget._CreateAuraApplication(spellAura, 1u << (int)effectInfo.EffectIndex);
|
||||||
else
|
else
|
||||||
aurApp.UpdateApplyEffectMask(aurApp.GetEffectsToApply() | 1u << (int)effectInfo.EffectIndex);
|
aurApp.UpdateApplyEffectMask(aurApp.GetEffectsToApply() | 1u << (int)effectInfo.EffectIndex);
|
||||||
|
|
||||||
// apply effect on target (skip for reapply)
|
|
||||||
if (!aurApp.HasEffect(effectInfo.EffectIndex))
|
|
||||||
unitTarget._ApplyAuraEffect(spellAura, effectInfo.EffectIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[SpellEffectHandler(SpellEffectName.UnlearnSpecialization)]
|
[SpellEffectHandler(SpellEffectName.UnlearnSpecialization)]
|
||||||
|
|||||||
Reference in New Issue
Block a user