Core/Spells: Defined and implemented more spell effect attributes - AlwaysAoeLineOfSight, IsHarmful, PlayersOnly, EnforceLineOfSightToChainTargets
Port From (https://github.com/TrinityCore/TrinityCore/commit/69317c25947e682036813aa7f6e9200056232a13)
This commit is contained in:
@@ -1973,12 +1973,28 @@ namespace Framework.Constants
|
|||||||
public enum SpellEffectAttributes
|
public enum SpellEffectAttributes
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
UnaffectedByInvulnerability = 0x01, // not cancelled by immunities
|
NoImmunity = 0x01, /*NYI*/ // not cancelled by immunities
|
||||||
NoScaleWithStack = 0x40,
|
PositionIsFacingRelative = 0x02, /*NYI*/
|
||||||
|
JumpChargeUnitMeleeRange = 0x04, /*NYI*/
|
||||||
|
JumpChargeUnitStrictPathCheck = 0x08, /*NYI*/
|
||||||
|
ExcludeOwnParty = 0x10, /*NYI*/
|
||||||
|
AlwaysAoeLineOfSight = 0x20,
|
||||||
|
SuppressPointsStacking = 0x40,
|
||||||
ChainFromInitialTarget = 0x80,
|
ChainFromInitialTarget = 0x80,
|
||||||
StackAuraAmountOnRecast = 0x8000, // refreshing periodic auras with this attribute will add remaining damage to new aura
|
UncontrolledNoBackwards = 0x100, /*NYI*/
|
||||||
AllowAnyExplicitTarget = 0x100000,
|
AuraPointsStack = 0x000200, /*NYI*/ // refreshing periodic auras with this attribute will add remaining damage to new aura
|
||||||
IgnoreDuringCooldownTimeRateCalculation = 0x800000
|
NoCopyDamageInterruptsOrProcs = 0x400, /*NYI*/
|
||||||
|
AddTargetCombatReachToAOE = 0x800, /*NYI*/
|
||||||
|
IsHarmful = 0x1000,
|
||||||
|
ForceScaleToOverrideCameraMinHeight = 0x2000, /*NYI*/
|
||||||
|
PlayersOnly = 0x004000,
|
||||||
|
ComputePointsOnlyAtCastTime = 0x8000, /*NYI*/
|
||||||
|
EnforceLineOfSightToChainTargets = 0x10000,
|
||||||
|
AreaEffectsUseTargetRadius = 0x20000, /*NYI*/
|
||||||
|
TeleportWithVehicle = 0x40000, /*NYI*/
|
||||||
|
ScalePointsByChallengeModeDamageScaler = 0x80000, /*NYI*/
|
||||||
|
DontFailSpellOnTargetingFailure = 0x100000, /*NYI*/
|
||||||
|
IgnoreDuringCooldownTimeRateCalculation = 0x800000, /*NYI*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SpellProcsPerMinuteModType : byte
|
public enum SpellProcsPerMinuteModType : byte
|
||||||
|
|||||||
@@ -1337,7 +1337,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
GridMapTypeMask i_mapTypeMask;
|
GridMapTypeMask i_mapTypeMask;
|
||||||
List<WorldObject> i_objects;
|
List<WorldObject> i_objects;
|
||||||
PhaseShift i_phaseShift;
|
public PhaseShift i_phaseShift;
|
||||||
ICheck<WorldObject> i_check;
|
ICheck<WorldObject> i_check;
|
||||||
|
|
||||||
public WorldObjectListSearcher(WorldObject searcher, List<WorldObject> objects, ICheck<WorldObject> check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All)
|
public WorldObjectListSearcher(WorldObject searcher, List<WorldObject> objects, ICheck<WorldObject> check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All)
|
||||||
|
|||||||
@@ -2748,7 +2748,7 @@ namespace Game.Spells
|
|||||||
if (GetUnitOwner().HasUnitState(UnitState.Isolated))
|
if (GetUnitOwner().HasUnitState(UnitState.Isolated))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
List<Unit> units = new();
|
List<WorldObject> units = new();
|
||||||
var condList = spellEffectInfo.ImplicitTargetConditions;
|
var condList = spellEffectInfo.ImplicitTargetConditions;
|
||||||
|
|
||||||
float radius = spellEffectInfo.CalcRadius(refe);
|
float radius = spellEffectInfo.CalcRadius(refe);
|
||||||
@@ -2804,20 +2804,25 @@ namespace Game.Spells
|
|||||||
|
|
||||||
if (selectionType != SpellTargetCheckTypes.Default)
|
if (selectionType != SpellTargetCheckTypes.Default)
|
||||||
{
|
{
|
||||||
WorldObjectSpellAreaTargetCheck check = new(radius, GetUnitOwner(), refe, GetUnitOwner(), GetSpellInfo(), selectionType, condList, SpellTargetObjectTypes.Unit);
|
var containerTypeMask = Spell.GetSearcherTypeMask(GetSpellInfo(), spellEffectInfo, SpellTargetObjectTypes.Unit, condList);
|
||||||
UnitListSearcher searcher = new(GetUnitOwner(), units, check);
|
if (containerTypeMask != 0)
|
||||||
Cell.VisitAllObjects(GetUnitOwner(), searcher, radius + extraSearchRadius);
|
{
|
||||||
|
WorldObjectSpellAreaTargetCheck check = new(radius, GetUnitOwner(), refe, GetUnitOwner(), GetSpellInfo(), selectionType, condList, SpellTargetObjectTypes.Unit);
|
||||||
|
WorldObjectListSearcher searcher = new(GetUnitOwner(), units, check, containerTypeMask);
|
||||||
|
searcher.i_phaseShift = PhasingHandler.GetAlwaysVisiblePhaseShift();
|
||||||
|
Spell.SearchTargets(searcher, containerTypeMask, GetUnitOwner(), GetUnitOwner(), radius + extraSearchRadius);
|
||||||
|
|
||||||
// by design WorldObjectSpellAreaTargetCheck allows not-in-world units (for spells) but for auras it is not acceptable
|
// by design WorldObjectSpellAreaTargetCheck allows not-in-world units (for spells) but for auras it is not acceptable
|
||||||
units.RemoveAll(unit => !unit.IsSelfOrInSameMap(GetUnitOwner()));
|
units.RemoveAll(unit => !unit.IsSelfOrInSameMap(GetUnitOwner()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Unit unit in units)
|
foreach (WorldObject unit in units)
|
||||||
{
|
{
|
||||||
if (!targets.ContainsKey(unit))
|
if (!targets.ContainsKey(unit))
|
||||||
targets[unit] = 0;
|
targets[unit.ToUnit()] = 0;
|
||||||
|
|
||||||
targets[unit] |= 1u << (int)spellEffectInfo.EffectIndex;
|
targets[unit.ToUnit()] |= 1u << (int)spellEffectInfo.EffectIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
|
|
||||||
GetBase().CallScriptEffectCalcAmountHandlers(this, ref amount, ref m_canBeRecalculated);
|
GetBase().CallScriptEffectCalcAmountHandlers(this, ref amount, ref m_canBeRecalculated);
|
||||||
if (!GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack))
|
if (!GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.SuppressPointsStacking))
|
||||||
amount *= GetBase().GetStackAmount();
|
amount *= GetBase().GetStackAmount();
|
||||||
|
|
||||||
_estimatedAmount = CalculateEstimatedAmount(caster, amount);
|
_estimatedAmount = CalculateEstimatedAmount(caster, amount);
|
||||||
@@ -126,7 +126,7 @@ namespace Game.Spells
|
|||||||
|
|
||||||
public static float? CalculateEstimatedAmount(Unit caster, Unit target, SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, int amount, byte stack, AuraEffect aurEff)
|
public static float? CalculateEstimatedAmount(Unit caster, Unit target, SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, int amount, byte stack, AuraEffect aurEff)
|
||||||
{
|
{
|
||||||
uint stackAmountForBonuses = !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? stack : 1u;
|
uint stackAmountForBonuses = !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.SuppressPointsStacking) ? stack : 1u;
|
||||||
|
|
||||||
switch (spellEffectInfo.ApplyAuraName)
|
switch (spellEffectInfo.ApplyAuraName)
|
||||||
{
|
{
|
||||||
@@ -5057,7 +5057,7 @@ namespace Game.Spells
|
|||||||
|
|
||||||
CleanDamage cleanDamage = new(0, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal);
|
CleanDamage cleanDamage = new(0, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal);
|
||||||
|
|
||||||
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? GetBase().GetStackAmount() : 1u;
|
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.SuppressPointsStacking) ? GetBase().GetStackAmount() : 1u;
|
||||||
|
|
||||||
// ignore non positive values (can be result apply spellmods to aura damage
|
// ignore non positive values (can be result apply spellmods to aura damage
|
||||||
uint damage = (uint)Math.Max(GetAmount(), 0);
|
uint damage = (uint)Math.Max(GetAmount(), 0);
|
||||||
@@ -5184,7 +5184,7 @@ namespace Game.Spells
|
|||||||
|
|
||||||
CleanDamage cleanDamage = new(0, 0, GetSpellInfo().GetAttackType(), MeleeHitOutcome.Normal);
|
CleanDamage cleanDamage = new(0, 0, GetSpellInfo().GetAttackType(), MeleeHitOutcome.Normal);
|
||||||
|
|
||||||
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? GetBase().GetStackAmount() : 1u;
|
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.SuppressPointsStacking) ? GetBase().GetStackAmount() : 1u;
|
||||||
|
|
||||||
// ignore negative values (can be result apply spellmods to aura damage
|
// ignore negative values (can be result apply spellmods to aura damage
|
||||||
uint damage = (uint)Math.Max(GetAmount(), 0);
|
uint damage = (uint)Math.Max(GetAmount(), 0);
|
||||||
@@ -5311,7 +5311,7 @@ namespace Game.Spells
|
|||||||
if (GetBase().IsPermanent() && target.IsFullHealth())
|
if (GetBase().IsPermanent() && target.IsFullHealth())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? GetBase().GetStackAmount() : 1u;
|
uint stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.SuppressPointsStacking) ? GetBase().GetStackAmount() : 1u;
|
||||||
|
|
||||||
// ignore negative values (can be result apply spellmods to aura damage
|
// ignore negative values (can be result apply spellmods to aura damage
|
||||||
uint damage = (uint)Math.Max(GetAmount(), 0);
|
uint damage = (uint)Math.Max(GetAmount(), 0);
|
||||||
|
|||||||
+37
-31
@@ -398,6 +398,7 @@ namespace Game.Spells
|
|||||||
spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
|
spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
|
||||||
spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex.TargetA) == effects[j].CalcRadius(m_caster, SpellTargetIndex.TargetA) &&
|
spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex.TargetA) == effects[j].CalcRadius(m_caster, SpellTargetIndex.TargetA) &&
|
||||||
spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex.TargetB) == effects[j].CalcRadius(m_caster, SpellTargetIndex.TargetB) &&
|
spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex.TargetB) == effects[j].CalcRadius(m_caster, SpellTargetIndex.TargetB) &&
|
||||||
|
spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.PlayersOnly) == effects[j].EffectAttributes.HasFlag(SpellEffectAttributes.PlayersOnly) &&
|
||||||
CheckScriptEffectImplicitTargets(spellEffectInfo.EffectIndex, (uint)j))
|
CheckScriptEffectImplicitTargets(spellEffectInfo.EffectIndex, (uint)j))
|
||||||
{
|
{
|
||||||
effectMask |= 1u << j;
|
effectMask |= 1u << j;
|
||||||
@@ -658,7 +659,7 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldObject target = SearchNearbyTarget(range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
|
WorldObject target = SearchNearbyTarget(spellEffectInfo, range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
|
||||||
float randomRadius = 0.0f;
|
float randomRadius = 0.0f;
|
||||||
switch (targetType.GetTarget())
|
switch (targetType.GetTarget())
|
||||||
{
|
{
|
||||||
@@ -782,7 +783,7 @@ namespace Game.Spells
|
|||||||
var condList = spellEffectInfo.ImplicitTargetConditions;
|
var condList = spellEffectInfo.ImplicitTargetConditions;
|
||||||
float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue.RadiusMod;
|
float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue.RadiusMod;
|
||||||
|
|
||||||
GridMapTypeMask containerTypeMask = GetSearcherTypeMask(objectType, condList);
|
GridMapTypeMask containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
|
||||||
if (containerTypeMask != 0)
|
if (containerTypeMask != 0)
|
||||||
{
|
{
|
||||||
float extraSearchRadius = radius > 0.0f ? SharedConst.ExtraCellSearchRadius : 0.0f;
|
float extraSearchRadius = radius > 0.0f ? SharedConst.ExtraCellSearchRadius : 0.0f;
|
||||||
@@ -892,15 +893,15 @@ namespace Game.Spells
|
|||||||
if (!m_caster.IsUnit() || !m_caster.ToUnit().IsInRaidWith(targetedUnit))
|
if (!m_caster.IsUnit() || !m_caster.ToUnit().IsInRaidWith(targetedUnit))
|
||||||
targets.Add(m_targets.GetUnitTarget());
|
targets.Add(m_targets.GetUnitTarget());
|
||||||
else
|
else
|
||||||
SearchAreaTargets(targets, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
|
SearchAreaTargets(targets, spellEffectInfo, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Targets.UnitCasterAndSummons:
|
case Targets.UnitCasterAndSummons:
|
||||||
targets.Add(m_caster);
|
targets.Add(m_caster);
|
||||||
SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
|
SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
|
SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1484,7 +1485,7 @@ namespace Game.Spells
|
|||||||
var condList = spellEffectInfo.ImplicitTargetConditions;
|
var condList = spellEffectInfo.ImplicitTargetConditions;
|
||||||
float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue.RadiusMod;
|
float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue.RadiusMod;
|
||||||
|
|
||||||
GridMapTypeMask containerTypeMask = GetSearcherTypeMask(objectType, condList);
|
GridMapTypeMask containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
|
||||||
if (containerTypeMask != 0)
|
if (containerTypeMask != 0)
|
||||||
{
|
{
|
||||||
WorldObjectSpellLineTargetCheck check = new(m_caster, dst, m_spellInfo.Width != 0 ? m_spellInfo.Width : m_caster.GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
|
WorldObjectSpellLineTargetCheck check = new(m_caster, dst, m_spellInfo.Width != 0 ? m_spellInfo.Width : m_caster.GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
|
||||||
@@ -1625,7 +1626,7 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GridMapTypeMask GetSearcherTypeMask(SpellTargetObjectTypes objType, List<Condition> condList)
|
public static GridMapTypeMask GetSearcherTypeMask(SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, SpellTargetObjectTypes objType, List<Condition> condList)
|
||||||
{
|
{
|
||||||
// this function selects which containers need to be searched for spell target
|
// this function selects which containers need to be searched for spell target
|
||||||
GridMapTypeMask retMask = GridMapTypeMask.All;
|
GridMapTypeMask retMask = GridMapTypeMask.All;
|
||||||
@@ -1650,11 +1651,11 @@ namespace Game.Spells
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer))
|
if (spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer) || spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.PlayersOnly))
|
||||||
retMask &= GridMapTypeMask.Corpse | GridMapTypeMask.Player;
|
retMask &= GridMapTypeMask.Corpse | GridMapTypeMask.Player;
|
||||||
if (m_spellInfo.HasAttribute(SpellAttr3.OnlyOnGhosts))
|
if (spellInfo.HasAttribute(SpellAttr3.OnlyOnGhosts))
|
||||||
retMask &= GridMapTypeMask.Player;
|
retMask &= GridMapTypeMask.Player;
|
||||||
if (m_spellInfo.HasAttribute(SpellAttr5.NotOnPlayer))
|
if (spellInfo.HasAttribute(SpellAttr5.NotOnPlayer))
|
||||||
retMask &= ~GridMapTypeMask.Player;
|
retMask &= ~GridMapTypeMask.Player;
|
||||||
|
|
||||||
if (condList != null)
|
if (condList != null)
|
||||||
@@ -1662,7 +1663,7 @@ namespace Game.Spells
|
|||||||
return retMask;
|
return retMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchTargets(Notifier notifier, GridMapTypeMask containerMask, WorldObject referer, Position pos, float radius)
|
public static void SearchTargets(Notifier notifier, GridMapTypeMask containerMask, WorldObject referer, Position pos, float radius)
|
||||||
{
|
{
|
||||||
if (containerMask == 0)
|
if (containerMask == 0)
|
||||||
return;
|
return;
|
||||||
@@ -1688,20 +1689,21 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldObject SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, List<Condition> condList)
|
WorldObject SearchNearbyTarget(SpellEffectInfo spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, List<Condition> condList)
|
||||||
{
|
{
|
||||||
GridMapTypeMask containerTypeMask = GetSearcherTypeMask(objectType, condList);
|
GridMapTypeMask containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
|
||||||
if (containerTypeMask == 0)
|
if (containerTypeMask == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var check = new WorldObjectSpellNearbyTargetCheck(range, m_caster, m_spellInfo, selectionType, condList, objectType);
|
var check = new WorldObjectSpellNearbyTargetCheck(range, m_caster, m_spellInfo, selectionType, condList, objectType);
|
||||||
var searcher = new WorldObjectLastSearcher(m_caster, check, containerTypeMask);
|
var searcher = new WorldObjectLastSearcher(m_caster, check, containerTypeMask);
|
||||||
SearchTargets(searcher, containerTypeMask, m_caster, m_caster.GetPosition(), range);
|
SearchTargets(searcher, containerTypeMask, m_caster, m_caster.GetPosition(), range);
|
||||||
return searcher.GetTarget();
|
return searcher.GetTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchAreaTargets(List<WorldObject> targets, float range, Position position, WorldObject referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, List<Condition> condList)
|
void SearchAreaTargets(List<WorldObject> targets, SpellEffectInfo spellEffectInfo, float range, Position position, WorldObject referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, List<Condition> condList)
|
||||||
{
|
{
|
||||||
var containerTypeMask = GetSearcherTypeMask(objectType, condList);
|
var containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
|
||||||
if (containerTypeMask == 0)
|
if (containerTypeMask == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1750,7 +1752,7 @@ namespace Game.Spells
|
|||||||
|
|
||||||
WorldObject chainSource = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target;
|
WorldObject chainSource = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target;
|
||||||
List<WorldObject> tempTargets = new();
|
List<WorldObject> tempTargets = new();
|
||||||
SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions);
|
SearchAreaTargets(tempTargets, spellEffectInfo, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions);
|
||||||
tempTargets.Remove(target);
|
tempTargets.Remove(target);
|
||||||
|
|
||||||
// remove targets which are always invalid for chain spells
|
// remove targets which are always invalid for chain spells
|
||||||
@@ -1761,7 +1763,7 @@ namespace Game.Spells
|
|||||||
while (chainTargets != 0)
|
while (chainTargets != 0)
|
||||||
{
|
{
|
||||||
// try to get unit for next chain jump
|
// try to get unit for next chain jump
|
||||||
WorldObject found = null;
|
WorldObject foundObj = null;
|
||||||
// get unit with highest hp deficit in dist
|
// get unit with highest hp deficit in dist
|
||||||
if (isChainHeal)
|
if (isChainHeal)
|
||||||
{
|
{
|
||||||
@@ -1772,9 +1774,9 @@ namespace Game.Spells
|
|||||||
if (unitTarget != null)
|
if (unitTarget != null)
|
||||||
{
|
{
|
||||||
uint deficit = (uint)(unitTarget.GetMaxHealth() - unitTarget.GetHealth());
|
uint deficit = (uint)(unitTarget.GetMaxHealth() - unitTarget.GetHealth());
|
||||||
if ((deficit > maxHPDeficit || found == null) && chainSource.IsWithinDist(unitTarget, jumpRadius) && IsWithinLOS(chainSource, unitTarget, false, ModelIgnoreFlags.M2))
|
if ((deficit > maxHPDeficit || foundObj == null) && chainSource.IsWithinDist(unitTarget, jumpRadius) && IsWithinLOS(chainSource, unitTarget, false, ModelIgnoreFlags.M2))
|
||||||
{
|
{
|
||||||
found = obj;
|
foundObj = obj;
|
||||||
maxHPDeficit = deficit;
|
maxHPDeficit = deficit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1785,24 +1787,28 @@ namespace Game.Spells
|
|||||||
{
|
{
|
||||||
foreach (var obj in tempTargets)
|
foreach (var obj in tempTargets)
|
||||||
{
|
{
|
||||||
if (found == null)
|
bool isBestDistanceMatch = foundObj != null ? chainSource.GetDistanceOrder(obj, foundObj) : chainSource.IsWithinDist(obj, jumpRadius);
|
||||||
{
|
if (!isBestDistanceMatch)
|
||||||
if (chainSource.IsWithinDist(obj, jumpRadius) && IsWithinLOS(chainSource, obj, false, ModelIgnoreFlags.M2))
|
continue;
|
||||||
found = obj;
|
|
||||||
}
|
if (!IsWithinLOS(chainSource, obj, false, ModelIgnoreFlags.M2))
|
||||||
else if (chainSource.GetDistanceOrder(obj, found) && IsWithinLOS(chainSource, obj, false, ModelIgnoreFlags.M2))
|
continue;
|
||||||
found = obj;
|
|
||||||
|
if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.EnforceLineOfSightToChainTargets) && !IsWithinLOS(m_caster, obj, false, ModelIgnoreFlags.M2))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foundObj = obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not found any valid target - chain ends
|
// not found any valid target - chain ends
|
||||||
if (found == null)
|
if (foundObj == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) && !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.ChainFromInitialTarget))
|
if (!m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) && !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.ChainFromInitialTarget))
|
||||||
chainSource = found;
|
chainSource = foundObj;
|
||||||
|
|
||||||
targets.Add(found);
|
targets.Add(foundObj);
|
||||||
tempTargets.Remove(found);
|
tempTargets.Remove(foundObj);
|
||||||
--chainTargets;
|
--chainTargets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7118,7 +7124,7 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
if (losPosition == null || m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight))
|
if (losPosition == null || m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) || spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.AlwaysAoeLineOfSight))
|
||||||
{
|
{
|
||||||
// Get GO cast coordinates if original caster . GO
|
// Get GO cast coordinates if original caster . GO
|
||||||
WorldObject caster = null;
|
WorldObject caster = null;
|
||||||
|
|||||||
@@ -3379,6 +3379,9 @@ namespace Game.Spells
|
|||||||
if (spellInfo.HasAttribute(SpellAttr4.AuraIsBuff))
|
if (spellInfo.HasAttribute(SpellAttr4.AuraIsBuff))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (effect.EffectAttributes.HasFlag(SpellEffectAttributes.IsHarmful))
|
||||||
|
return false;
|
||||||
|
|
||||||
visited.Add(Tuple.Create(spellInfo, effect.EffectIndex));
|
visited.Add(Tuple.Create(spellInfo, effect.EffectIndex));
|
||||||
|
|
||||||
//We need scaling level info for some auras that compute bp 0 or positive but should be debuffs
|
//We need scaling level info for some auras that compute bp 0 or positive but should be debuffs
|
||||||
|
|||||||
Reference in New Issue
Block a user