public static void AddChannelObject(this SpellTargetCollection targets, TargetFilter filter, ref SpellFailedReason failReason)
        {
            var caster = targets.Cast.CasterUnit;

            if (caster != null)
            {
                if (caster.ChannelObject != null)
                {
                    if ((failReason = targets.ValidateTarget(caster.ChannelObject, filter)) == SpellFailedReason.Ok)
                    {
                        targets.Add(caster.ChannelObject);
                    }
                }
                else
                {
                    failReason = SpellFailedReason.BadTargets;
                }
            }
        }
        public static void AddTargetsInArea(this SpellTargetCollection targets, Vector3 pos, TargetFilter targetFilter, float radius)
        {
            var handler = targets.FirstHandler;
            var spell   = handler.Effect.Spell;
            var cast    = handler.Cast;

            int limit;

            if (spell.MaxTargetEffect != null)
            {
                limit = spell.MaxTargetEffect.CalcEffectValue(cast.CasterReference);
            }
            else
            {
                //if IsAllied (used by group/raid spell targeting) it's save to asume the limit is the raid max size (40 players) since some spells have wrong dbc values
                if (targetFilter == DefaultTargetFilters.IsAllied)
                {
                    limit = 40;
                }
                else
                {
                    limit = (int)spell.MaxTargets;
                }
            }

            if (limit < 1)
            {
                limit = int.MaxValue;
            }

            cast.Map.IterateObjects(pos, radius > 0 ? radius : 5, cast.Phase,
                                    obj =>
            {
                // AoE spells only make sense on Unit targets (at least there is no known spell that does anything else)
                if (obj is Unit && targets.ValidateTarget(obj, targetFilter) == SpellFailedReason.Ok)
                {
                    return(targets.AddOrReplace(obj, limit));
                }
                return(true);
            });
        }
        public static void AddChannelObject(this SpellTargetCollection targets, TargetFilter filter,
                                            ref SpellFailedReason failReason)
        {
            Unit casterUnit = targets.Cast.CasterUnit;

            if (casterUnit == null)
            {
                return;
            }
            if (casterUnit.ChannelObject != null)
            {
                if ((sbyte)(failReason = targets.ValidateTarget(casterUnit.ChannelObject, filter)) != (sbyte)-1)
                {
                    return;
                }
                targets.Add(casterUnit.ChannelObject);
            }
            else
            {
                failReason = SpellFailedReason.BadTargets;
            }
        }
        public static void AddTargetsInArea(this SpellTargetCollection targets, Vector3 pos, TargetFilter targetFilter,
                                            float radius)
        {
            SpellEffectHandler firstHandler = targets.FirstHandler;
            Spell     spell = firstHandler.Effect.Spell;
            SpellCast cast  = firstHandler.Cast;
            int       limit = spell.MaxTargetEffect == null
                ? (!(targetFilter == new TargetFilter(DefaultTargetFilters.IsAllied)) ? (int)spell.MaxTargets : 40)
                : spell.MaxTargetEffect.CalcEffectValue(cast.CasterReference);

            if (limit < 1)
            {
                limit = int.MaxValue;
            }
            cast.Map.IterateObjects(pos, (double)radius > 0.0 ? radius : 5f, cast.Phase,
                                    (Func <WorldObject, bool>)(obj =>
            {
                if (obj is Unit && targets.ValidateTarget(obj, targetFilter) == SpellFailedReason.Ok)
                {
                    return(targets.AddOrReplace(obj, limit));
                }
                return(true);
            }));
        }
        /// <summary>
        /// Adds the selected targets and chain-targets (if any)
        /// </summary>
        public static void AddSelection(this SpellTargetCollection targets, TargetFilter filter, ref SpellFailedReason failReason, bool harmful)
        {
            var cast = targets.Cast;

            if (cast == null)
            {
                return;
            }

            var caster   = cast.CasterObject as Unit;
            var selected = cast.SelectedTarget;

            if (selected == null)
            {
                if (caster == null)
                {
                    log.Warn("Invalid SpellCast, tried to add Selection but nothing selected and no Caster present: {0}", targets.Cast);
                    failReason = SpellFailedReason.Error;
                    return;
                }
                selected = caster.Target;
                if (selected == null)
                {
                    failReason = SpellFailedReason.BadTargets;
                    return;
                }
            }

            var effect = targets.FirstHandler.Effect;
            var spell  = effect.Spell;

            if (selected != caster && caster != null)
            {
                if (!caster.IsInMaxRange(spell, selected))
                {
                    failReason = SpellFailedReason.OutOfRange;
                }
                else if (caster.IsPlayer && !selected.IsInFrontOf(caster))
                {
                    failReason = SpellFailedReason.UnitNotInfront;
                }
            }

            if (failReason == SpellFailedReason.Ok)
            {
                // standard checks
                failReason = targets.ValidateTarget(selected, filter);

                if (failReason == SpellFailedReason.Ok)
                {
                    // add target and look for more if we have a chain effect
                    targets.Add(selected);
                    var chainCount = effect.ChainTargets;
                    if (caster != null)
                    {
                        chainCount = caster.Auras.GetModifiedInt(SpellModifierType.ChainTargets, spell, chainCount);
                    }
                    if (chainCount > 1 && selected is Unit)
                    {
                        targets.FindChain((Unit)selected, filter, true, chainCount);
                    }
                }
            }
        }
        /// <summary>Adds the selected targets and chain-targets (if any)</summary>
        public static void AddSelection(this SpellTargetCollection targets, TargetFilter filter,
                                        ref SpellFailedReason failReason, bool harmful)
        {
            SpellCast cast = targets.Cast;

            if (cast == null)
            {
                return;
            }
            Unit        casterObject = cast.CasterObject as Unit;
            WorldObject target       = cast.SelectedTarget;

            if (target == null)
            {
                if (casterObject == null)
                {
                    DefaultTargetAdders.log.Warn(
                        "Invalid SpellCast, tried to add Selection but nothing selected and no Caster present: {0}",
                        (object)targets.Cast);
                    failReason = SpellFailedReason.Error;
                    return;
                }

                target = (WorldObject)casterObject.Target;
                if (target == null)
                {
                    failReason = SpellFailedReason.BadTargets;
                    return;
                }
            }

            SpellEffect effect = targets.FirstHandler.Effect;
            Spell       spell  = effect.Spell;

            if (target != casterObject && casterObject != null)
            {
                if (!casterObject.IsInMaxRange(spell, target))
                {
                    failReason = SpellFailedReason.OutOfRange;
                }
                else if (casterObject.IsPlayer && !target.IsInFrontOf((WorldObject)casterObject))
                {
                    failReason = SpellFailedReason.UnitNotInfront;
                }
            }

            if (failReason != SpellFailedReason.Ok)
            {
                return;
            }
            failReason = targets.ValidateTarget(target, filter);
            if (failReason != SpellFailedReason.Ok)
            {
                return;
            }
            targets.Add(target);
            int limit = effect.ChainTargets;

            if (casterObject != null)
            {
                limit = casterObject.Auras.GetModifiedInt(SpellModifierType.ChainTargets, spell, limit);
            }
            if (limit <= 1 || !(target is Unit))
            {
                return;
            }
            targets.FindChain((Unit)target, filter, true, limit);
        }