Core/Spells: Implemented SPELL_ATTR5_NOT_ON_PLAYER and SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC

Port From (https://github.com/TrinityCore/TrinityCore/commit/acda6f9dcf411a1406b81e1a100125dbe34f942b)
This commit is contained in:
hondacrx
2022-06-01 15:37:28 -04:00
parent da9cd08caa
commit 68d8f664d7
5 changed files with 71 additions and 16 deletions
@@ -1764,8 +1764,8 @@ namespace Framework.Constants
TriggersChanneling = 0x10, // Triggers Channeling
LimitN = 0x20, // Limit N Description Remove Previous Application To Another Unit If Applied
IgnoreAreaEffectPvpCheck = 0x40, // Ignore Area Effect Pvp Check
NotOnPlayer = 0x80, /*Nyi*/ // Not On Player
NotOnPlayerControlledNpc = 0x100, /*Nyi*/ // Not On Player Controlled Npc
NotOnPlayer = 0x80, // Not On Player
NotOnPlayerControlledNpc = 0x100, // Not On Player Controlled Npc
ExtraInitialPeriod = 0x200, // Extra Initial Period Description Immediately Do Periodic Tick On Apply
DoNotDisplayDuration = 0x400, // Do Not Display Duration
ImpliedTargeting = 0x800, // Implied Targeting (Client Only)
+44 -10
View File
@@ -124,11 +124,17 @@ namespace Game.AI
return SelectTarget(targetType, offset, new DefaultTargetSelector(me, dist, playerOnly, withTank, aura));
}
public Unit SelectTarget(SelectTargetMethod targetType, uint offset, ICheck<Unit> selector)
{
return SelectTarget(targetType, offset, selector.Invoke);
}
/// <summary>
/// Select the best target (in <targetType> order) satisfying <predicate> from the threat list.
/// If <offset> is nonzero, the first <offset> entries in <targetType> order (or MAXTHREAT order, if <targetType> is RANDOM) are skipped.
/// </summary>
public Unit SelectTarget(SelectTargetMethod targetType, uint offset, ICheck<Unit> selector)
public delegate bool SelectTargetDelegate(Unit unit);
public Unit SelectTarget(SelectTargetMethod targetType, uint offset, SelectTargetDelegate selector)
{
ThreatManager mgr = GetThreatManager();
// shortcut: if we ignore the first <offset> elements, and there are at most <offset> elements, then we ignore ALL elements
@@ -162,14 +168,14 @@ namespace Game.AI
/// </summary>
public List<Unit> SelectTargetList(uint num, SelectTargetMethod targetType, uint offset = 0, float dist = 0f, bool playerOnly = false, bool withTank = true, int aura = 0)
{
return SelectTargetList(num, targetType, offset, new DefaultTargetSelector(me, dist, playerOnly, withTank, aura));
return SelectTargetList(num, targetType, offset, new DefaultTargetSelector(me, dist, playerOnly, withTank, aura).Invoke);
}
/// <summary>
/// Select the best (up to) <num> targets (in <targetType> order) satisfying <predicate> from the threat list and stores them in <targetList> (which is cleared first).
/// If <offset> is nonzero, the first <offset> entries in <targetType> order (or MAXTHREAT order, if <targetType> is RANDOM) are skipped.
/// </summary>
public List<Unit> SelectTargetList(uint num, SelectTargetMethod targetType, uint offset, ICheck<Unit> selector)
public List<Unit> SelectTargetList(uint num, SelectTargetMethod targetType, uint offset, SelectTargetDelegate selector)
{
var targetList = new List<Unit>();
@@ -228,7 +234,7 @@ namespace Game.AI
}
// then finally filter by predicate
targetList.RemoveAll(unit => !selector.Invoke(unit));
targetList.RemoveAll(unit => !selector(unit));
if (targetList.Count <= num)
return targetList;
@@ -264,8 +270,23 @@ namespace Game.AI
var spellInfo = Global.SpellMgr.GetSpellInfo(spellId, me.GetMap().GetDifficultyID());
if (spellInfo != null)
{
bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer);
target = SelectTarget(SelectTargetMethod.Random, 0, spellInfo.GetMaxRange(false), playerOnly);
DefaultTargetSelector targetSelectorInner = new(me, spellInfo.GetMaxRange(false), false, true, 0);
bool targetSelector(Unit candidate)
{
if (!candidate.IsPlayer())
{
if (spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer))
return false;
if (spellInfo.HasAttribute(SpellAttr5.NotOnPlayerControlledNpc) && candidate.IsControlledByPlayer())
return false;
}
else if (spellInfo.HasAttribute(SpellAttr5.NotOnPlayer))
return false;
return targetSelectorInner.Invoke(candidate);
};
target = SelectTarget(SelectTargetMethod.Random, 0, targetSelector);
}
break;
}
@@ -278,12 +299,25 @@ namespace Game.AI
var spellInfo = Global.SpellMgr.GetSpellInfo(spellId, me.GetMap().GetDifficultyID());
if (spellInfo != null)
{
bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer);
float range = spellInfo.GetMaxRange(false);
DefaultTargetSelector targetSelector = new(me, range, playerOnly, true, -(int)spellId);
if (!spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.NotVictim)
&& targetSelector.Invoke(me.GetVictim()))
DefaultTargetSelector targetSelectorInner = new(me, range, false, true, -(int)spellId);
bool targetSelector(Unit candidate)
{
if (!candidate.IsPlayer())
{
if (spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer))
return false;
if (spellInfo.HasAttribute(SpellAttr5.NotOnPlayerControlledNpc) && candidate.IsControlledByPlayer())
return false;
}
else if (spellInfo.HasAttribute(SpellAttr5.NotOnPlayer))
return false;
return targetSelectorInner.Invoke(candidate);
};
if (!spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.NotVictim) && targetSelector(me.GetVictim()))
target = me.GetVictim();
else
target = SelectTarget(SelectTargetMethod.Random, 0, targetSelector);
+13 -2
View File
@@ -2173,8 +2173,19 @@ namespace Game.Maps
if (u.IsTypeId(TypeId.Unit) && u.IsTotem())
return false;
if (_spellInfo != null && _spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer) && !u.IsPlayer())
return false;
if (_spellInfo != null)
{
if (!u.IsPlayer())
{
if (_spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer))
return false;
if (_spellInfo.HasAttribute(SpellAttr5.NotOnPlayerControlledNpc) && u.IsControlledByPlayer())
return false;
}
else if (_spellInfo.HasAttribute(SpellAttr5.NotOnPlayer))
return false;
}
if (!i_funit.IsValidAttackTarget(u, _spellInfo))
return false;
+2
View File
@@ -1594,6 +1594,8 @@ namespace Game.Spells
retMask &= GridMapTypeMask.Corpse | GridMapTypeMask.Player;
if (m_spellInfo.HasAttribute(SpellAttr3.OnlyOnGhosts))
retMask &= GridMapTypeMask.Player;
if (m_spellInfo.HasAttribute(SpellAttr5.NotOnPlayer))
retMask &= ~GridMapTypeMask.Player;
if (condList != null)
retMask &= Global.ConditionMgr.GetSearcherTypeMaskForConditionList(condList);
+10 -2
View File
@@ -1080,8 +1080,16 @@ namespace Game.Spells
return SpellCastResult.SpellCastOk;
// corpseOwner and unit specific target checks
if (HasAttribute(SpellAttr3.OnlyOnPlayer) && !unitTarget.IsTypeId(TypeId.Player))
return SpellCastResult.TargetNotPlayer;
if (!unitTarget.IsPlayer())
{
if (HasAttribute(SpellAttr3.OnlyOnPlayer))
return SpellCastResult.TargetNotPlayer;
if (HasAttribute(SpellAttr5.NotOnPlayerControlledNpc) && unitTarget.IsControlledByPlayer())
return SpellCastResult.TargetIsPlayerControlled;
}
else if (HasAttribute(SpellAttr5.NotOnPlayer))
return SpellCastResult.TargetIsPlayer;
if (!IsAllowingDeadTarget() && !unitTarget.IsAlive())
return SpellCastResult.TargetsDead;