Exemple #1
0
        /// <summary>
        /// Searching for target according to user input
        /// </summary>
        /// <param name="settingsTarget">Advanced Settings target select</param>
        /// <returns></returns>
        public static IEnumerable <int> SeTarget(int settingsTarget)
        {
            if (settingsTarget == 2)
            {
                // Eagle Artillerty search
                foreach (var f in SearchTarget(EagleArtillery.Find(CacheBehavior.ForceScan)))
                {
                    yield return(f);
                }

                // If not found switch to thownhall
                if (targetIsSet == false)
                {
                    foreach (var f in SearchTarget(TownHall.Find(CacheBehavior.ForceScan)))
                    {
                        yield return(f);
                    }
                }
            }
            else if (settingsTarget == 0)
            {
                // Townhall search
                foreach (var f in SearchTarget(TownHall.Find(CacheBehavior.ForceScan)))
                {
                    yield return(f);
                }

                // If not found switch to the core of the base
                if (targetIsSet == false)
                {
                    AllInOnePushDeploy.Target = AllInOnePushDeploy.Core;
                    targetIsSet = true;
                }
            }
            else if (settingsTarget == 1)
            {
                // Dark Elixir Storage search
                foreach (var f in SearchTarget(DarkElixirStorage.Find(CacheBehavior.ForceScan)?.FirstOrDefault()))
                {
                    yield return(f);
                }

                // If not found switch to townhall
                if (targetIsSet == false)
                {
                    foreach (var f in SearchTarget(TownHall.Find(CacheBehavior.ForceScan)))
                    {
                        yield return(f);
                    }
                }
            }

            // If not found both switch to the core of the base
            if (targetIsSet == false)
            {
                AllInOnePushDeploy.Target = AllInOnePushDeploy.Core;
            }
        }
Exemple #2
0
        /// <summary>
        /// get where to deploy hereos according to user defined
        /// </summary>
        /// <param name="deployHeroesAt">user defined location 1 is TwonHall , 2 is Dark Elixir Storage</param>
        /// <returns></returns>
        public static PointFT GetHeroesTarget(int deployHeroesAt)
        {
            var target = new PointFT(0f, 0f);

            switch (deployHeroesAt)
            {
            case 1:
                target = (PointFT)TownHall.Find()?.Location.GetCenter();
                break;

            case 2:
                target = (PointFT)DarkElixirStorage.Find()?.FirstOrDefault()?.Location.GetCenter();
                break;
            }
            return(target);
        }
        public static Target[] GenerateTargets(float minimumDistance, bool ignoreGold, bool ignoreElixir, CacheBehavior behavior = CacheBehavior.Default)
        {
            // Find all Collectors & storages just sitting around...
            List <Building> buildings = new List <Building>();

            if (!ignoreGold)
            {
                //User has Gold min set to ZERO - which means Dont include Gold Targets
                buildings.AddRange(GoldMine.Find(behavior));
                buildings.AddRange(GoldStorage.Find(behavior));
            }

            if (!ignoreElixir)
            {
                //User has Elixir min set to ZERO - which means Dont include Elixir Targets
                buildings.AddRange(ElixirCollector.Find(behavior));
                buildings.AddRange(ElixirStorage.Find(behavior));
            }

            //We always includ DarkElixir - Because who doesnt love dark Elixir?
            buildings.AddRange(DarkElixirDrill.Find(behavior));
            buildings.AddRange(DarkElixirStorage.Find(behavior));

            List <Target> targetList = new List <Target>();

            foreach (Building building in buildings)
            {
                Target current = new Target();

                current.TargetBuilding  = building;
                current.Center          = building.Location.GetCenter();
                current.NearestRedLine  = GameGrid.RedPoints.OrderBy(p => p.DistanceSq(current.Center)).First();
                current.CenterToRedline = current.Center.DistanceSq(current.NearestRedLine);
                Log.Debug($"[Berts Algorithms] DistanceSq from {current.Name} to red point: {current.CenterToRedline.ToString("F1")}");
                if (current.CenterToRedline < minimumDistance)                                                                              //Compare distance to Redline to the Minimum acceptable distance Passed in
                {
                    current.DeployGrunts = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _gruntDeployDistanceFromRedline);  //Barbs & Goblins
                    current.DeployRanged = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _rangedDeployDistanceFromRedline); //Archers & Minions

                    targetList.Add(current);
                }
            }

            Log.Debug($"[Berts Algorithms] Found {targetList.Count} deploy points");

            return(targetList.ToArray());
        }
        /// <summary>
        /// get where to deploy hereos according to user defined
        /// </summary>
        /// <param name="deployHeroesAt">user defined location 1 is TwonHall , 2 is Dark Elixir Storage</param>
        /// <returns></returns>
        public static PointFT GetHeroesTarget(int deployHeroesAt)
        {
            var target = new PointFT(0f, 0f);

            switch (deployHeroesAt)
            {
            case 1:
                var th = TownHall.Find()?.Location.GetCenter();
                target = th != null ? (PointFT)th : target;
                break;

            case 2:
                var de = DarkElixirStorage.Find()?.FirstOrDefault()?.Location.GetCenter();
                target = de != null ? (PointFT)de : target;
                break;
            }
            return(target);
        }
 public override double ShouldAccept()
 {
     if (Opponent.MeetsRequirements(BaseRequirements.All))
     {
         Log.Debug("[Goblin Knife] searching for DE Storage ....");
         var DE = DarkElixirStorage.Find()?.FirstOrDefault()?.Location.GetCenter();
         if (DE == null)
         {
             Log.Debug("Couldn't found DE Storage .. we will skip this base");
             Log.Error("Counld not locate DE Storage .. skipping this base");
             return(0);
         }
         else
         {
             Log.Debug("[Goblin Knife] Found DE storage .. move to CreateDeployPoints Method");
             return(1);
         }
     }
     return(0);
 }
        public static Target TargetDarkElixirStorage(CacheBehavior behavior = CacheBehavior.Default)
        {
            var target = new Target();

            var des = DarkElixirStorage.Find(behavior);

            target.ValidTarget = false;

            if (des.Length > 0)
            {
                target.ValidTarget    = true;
                target.TargetBuilding = des[0];
                target.Center         = des[0].Location.GetCenter();

                target.Edge           = Origin.PointOnLineAwayFromEnd(target.Center, _DEStorageCenterToOuterEdgeDistance);
                target.NearestRedLine = GameGrid.RedPoints.OrderBy(p => p.DistanceSq(target.Edge)).First();
                target.EdgeToRedline  = target.Edge.DistanceSq(target.NearestRedLine);

                //Fill the DeployGrunts Property with where out main dragon force should go.
                target.DeployGrunts = Origin.PointOnLineAwayFromEnd(target.NearestRedLine, 0.2f); //TODO Move to Constants..
            }

            return(target);
        }
Exemple #7
0
        public static Target[] GenerateTargets(string algorithmName, float minimumDistance, bool ignoreGold, bool ignoreElixir, string AttackId, out double avgFillstate, out double avgCollectorLvl, CacheBehavior behavior = CacheBehavior.Default, bool outputDebugImage = false, bool activeBase = false)
        {
            // Find all Collectors & storages just sitting around...
            List <Building> buildings = new List <Building>();

            //Get a list of Gold Mines.
            List <GoldMine> goldMines = new List <GoldMine>();

            goldMines.AddRange(GoldMine.Find(behavior));

            //Get a list of Elixir Collectors.
            List <ElixirCollector> elixirCollectors = new List <ElixirCollector>();

            elixirCollectors.AddRange(ElixirCollector.Find(behavior));
            avgFillstate = 0;

            //Get the Average Fill State of all the Elixir Collectors - From this we can tell what percentage of the loot is in Collectors.
            if (elixirCollectors.Count > 1)
            {
                avgFillstate = elixirCollectors.Average(c => c.FillState);
            }

            //Log the Average Fill State of aLL elixir Collectors...
            Log.Debug($"[Berts Algorithms] - Fill State Average of ALL Elixir Collectors: {(avgFillstate * 10).ToString("F1")}");

            if (!ignoreGold)
            {
                buildings.AddRange(goldMines);
                if (activeBase)
                {
                    buildings.AddRange(GoldStorage.Find(behavior));
                }
            }
            if (!ignoreElixir)
            {
                buildings.AddRange(elixirCollectors);
                if (activeBase)
                {
                    buildings.AddRange(ElixirStorage.Find(behavior));
                }
            }

            //Determine the Average Collector Level.
            avgCollectorLvl = 0;

            if (ignoreGold && !ignoreElixir)
            {
                if (elixirCollectors.Count(c => c.Level.HasValue) > 1)
                {
                    avgCollectorLvl = elixirCollectors.Where(c => c.Level.HasValue).Average(c => (int)c.Level);
                }
            }
            else if (ignoreElixir && !ignoreGold)
            {
                if (goldMines.Count(c => c.Level.HasValue) > 1)
                {
                    avgCollectorLvl = goldMines.Where(c => c.Level.HasValue).Average(c => (int)c.Level);
                }
            }
            else if (!ignoreElixir && !ignoreGold)
            {
                if (buildings.Count(c => c.Level.HasValue) > 1)
                {
                    avgCollectorLvl = buildings.Where(c => c.Level.HasValue).Average(c => (int)c.Level);
                }
            }

            //We always includ DarkElixir - Because who doesnt love dark Elixir?
            buildings.AddRange(DarkElixirDrill.Find(behavior));
            if (activeBase)
            {
                buildings.AddRange(DarkElixirStorage.Find(behavior));
            }

            List <Target> targetList = new List <Target>();

            foreach (Building building in buildings)
            {
                Target current = new Target();

                current.TargetBuilding  = building;
                current.Center          = building.Location.GetCenter();
                current.Edge            = Origin.PointOnLineAwayFromEnd(current.Center, 1.0f);
                current.NearestRedLine  = AllPoints.OrderBy(p => p.DistanceSq(current.Edge)).First();
                current.CenterToRedline = current.Center.DistanceSq(current.NearestRedLine);
                if (current.CenterToRedline < minimumDistance)  //Compare distance to Redline to the Minimum acceptable distance Passed in
                {
                    Log.Debug($"[Berts Algorithms] Distance from {current.Name} to red point: {Math.Sqrt(current.CenterToRedline).ToString("F1")}, Min Distance: {Math.Sqrt(minimumDistance).ToString("F1")} - GO!");
                    current.DeployGrunts = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _gruntDeployDistanceFromRedline);  //Barbs & Goblins
                    current.DeployRanged = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _rangedDeployDistanceFromRedline); //Archers & Minions

                    targetList.Add(current);
                }
                else
                {
                    Log.Debug($"[Berts Algorithms] Distance from {current.Name} to red point: {Math.Sqrt(current.CenterToRedline).ToString("F1")}, Min Distance: {Math.Sqrt(minimumDistance).ToString("F1")} - TOO FAR!");
                }
            }

            if (outputDebugImage)
            {
                OutputDebugImage(algorithmName, buildings, targetList, AttackId);
            }

            return(targetList.ToArray());
        }
        public override IEnumerable <int> AttackRoutine()
        {
            var DE = DarkElixirStorage.Find()?.FirstOrDefault()?.Location.GetCenter();

            //set the target
            if (DE == null)
            {
                for (var i = 1; i <= 3; i++)
                {
                    Log.Warning($"bot didn't found the DE Storage .. we will attemp search NO. {i + 1}");
                    yield return(1000);

                    DE = DarkElixirStorage.Find()?.FirstOrDefault()?.Location.GetCenter();
                    if (DE != null)
                    {
                        Log.Warning($"DE Storage found after {i + 1} retries");
                        break;
                    }
                }
            }

            if (DE != null)
            {
                _target = (PointFT)DE;
            }
            else
            {
                Log.Debug("[Goblin Knife] coundn't locate the target after aligning the base");
                Log.Error("Couldn't find DE Storage we will return home");
                Surrender();

                yield break;
            }
            CreateDeployPoints();
            Log.Info($"[Goblin Knife] V{Version} Deploy start");

            //get troops
            var deployElements = Deploy.GetTroops();

            var clanCastle = deployElements.ExtractOne(u => u.ElementType == DeployElementType.ClanTroops && UserSettings.UseClanTroops);

            var earthQuakeSpell = deployElements.Extract(u => u.Id == DeployId.Earthquake);
            var jumpSpell       = deployElements.ExtractOne(DeployId.Jump);
            var giant           = deployElements.ExtractOne(DeployId.Giant);
            var goblin          = deployElements.ExtractOne(DeployId.Goblin);
            var wizard          = deployElements.ExtractOne(DeployId.Wizard);
            var barbarian       = deployElements.ExtractOne(DeployId.Barbarian);
            var archer          = deployElements.ExtractOne(DeployId.Archer);
            var wallbreaker     = deployElements.ExtractOne(DeployId.WallBreaker);
            var ragespell       = deployElements.ExtractOne(DeployId.Rage);
            var healspell       = deployElements.ExtractOne(DeployId.Heal);

            _freezeSpell = deployElements.ExtractOne(DeployId.Freeze);

            var heroes = deployElements
                         .Extract(u => (UserSettings.UseKing && u.ElementType == DeployElementType.HeroKing) ||
                                  (UserSettings.UseQueen && u.ElementType == DeployElementType.HeroQueen) ||
                                  (UserSettings.UseWarden && u.ElementType == DeployElementType.HeroWarden))
                         .ToList();

            //open near to dark elixer with 4 earthquakes
            if (earthQuakeSpell?.Sum(u => u.Count) >= 4)
            {
                foreach (var unit in earthQuakeSpell)
                {
                    foreach (int t in Deploy.AtPoint(unit, _earthQuakePoint, unit.Count))
                    {
                        yield return(t);
                    }
                }
            }
            else
            {
                _useJump = true;
            }
            yield return(1000);

            if (giant?.Count > 0)
            {
                foreach (int t in Deploy.AlongLine(giant, _attackLine.Item1, _attackLine.Item2, 6, 6))
                {
                    yield return(t);
                }
            }

            yield return(1000);

            if (wizard?.Count > 0)
            {
                foreach (int t in Deploy.AlongLine(wizard, _attackLine.Item1, _attackLine.Item2, 8, 4))
                {
                    yield return(t);
                }
            }

            if (barbarian?.Count > 0)
            {
                while (barbarian.Count > 0)
                {
                    int count = barbarian.Count;

                    Log.Info($"[Goblin Knife] Deploying {barbarian.PrettyName}");
                    foreach (int t in Deploy.AlongLine(barbarian, _attackLine.Item1, _attackLine.Item2, count, 4))
                    {
                        yield return(t);
                    }

                    // prevent infinite loop if deploy point is on red
                    if (barbarian.Count != count)
                    {
                        continue;
                    }

                    Log.Warning($"[Goblin Knife] Couldn't deploy {barbarian.PrettyName}");
                    break;
                }
            }

            if (archer?.Count > 0)
            {
                int archerCount = (int)(archer.Count / 2);
                Log.Info($"[Goblin Knife] Deploying {archer.PrettyName} ");
                foreach (int t in Deploy.AlongLine(archer, _attackLine.Item1, _attackLine.Item2, archerCount, 4))
                {
                    yield return(t);
                }
            }

            yield return(3000);

            if (ragespell?.Count >= 2)
            {
                foreach (int t in Deploy.AtPoint(ragespell, _ragePoint))
                {
                    yield return(t);
                }
            }
            if (wallbreaker?.Count > 0)
            {
                Log.Info($"[Goblin Knife] send test {wallbreaker.PrettyName} to check for bombs");
                foreach (int t in Deploy.AtPoint(wallbreaker, _orgin, 1))
                {
                    yield return(t);
                }
            }

            yield return(1000);

            while (wallbreaker?.Count > 0)
            {
                int count = wallbreaker.Count;
                Log.Info("[Goblin Knife] send wall breakers in groups");
                foreach (int t in Deploy.AtPoint(wallbreaker, _orgin, 3))
                {
                    yield return(t);
                }

                // prevent infinite loop if deploy point is on red
                if (wallbreaker.Count != count)
                {
                    continue;
                }

                Log.Warning($"[Goblin Knife] Couldn't deploy {wallbreaker.PrettyName}");
                break;
            }

            while (giant?.Count > 0)
            {
                int count = giant.Count;

                Log.Info($"[Goblin Knife] Deploying {giant.PrettyName} x{count}");
                foreach (int t in Deploy.AtPoint(giant, _orgin, count))
                {
                    yield return(t);
                }

                // prevent infinite loop if deploy point is on red
                if (giant.Count != count)
                {
                    continue;
                }

                Log.Warning($"[Goblin Knife] Couldn't deploy {giant.PrettyName}");
                break;
            }

            yield return(1000);

            while (wizard?.Count > 0)
            {
                int count = wizard.Count;

                Log.Info($"[Goblin Knife] Deploying {wizard}");
                foreach (int t in Deploy.AlongLine(wizard, _attackLine.Item1, _attackLine.Item2, 4, 2))
                {
                    yield return(t);
                }

                // prevent infinite loop if deploy point is on red
                if (wizard.Count != count)
                {
                    continue;
                }

                Log.Warning($"[Goblin Knife] Couldn't deploy {wizard.PrettyName}");
                break;
            }
            if (archer?.Count > 0)
            {
                Log.Info($"[Goblin Knife] Deploying {archer.PrettyName} ");
                foreach (int t in Deploy.AlongLine(archer, _attackLine.Item1, _attackLine.Item2, archer.Count, 4))
                {
                    yield return(t);
                }
            }

            yield return(1500);

            if (_useJump == true && jumpSpell?.Count > 0)
            {
                foreach (int t in Deploy.AtPoint(jumpSpell, _jumpPoint))
                {
                    yield return(t);
                }
            }

            if (healspell?.Count > 0)
            {
                foreach (int t in Deploy.AtPoint(healspell, _healPoint))
                {
                    yield return(t);
                }
            }

            if (clanCastle?.Count > 0)
            {
                Log.Info($"[Goblin Knife] Deploying {clanCastle.PrettyName}");
                foreach (int t in Deploy.AtPoint(clanCastle, _orgin))
                {
                    yield return(t);
                }
            }

            if (heroes.Any())
            {
                _delay = 1000;
                foreach (DeployElement hero in heroes.Where(u => u.Count > 0))
                {
                    foreach (int t in Deploy.AtPoint(hero, _orgin))
                    {
                        yield return(t);
                    }
                }
                watchHeroes = true;
            }
            yield return(_delay);

            while (goblin?.Count > 0)
            {
                int testGoblins = (int)(goblin.Count / 3);
                Log.Info($"[Goblin Knife] Deploying {goblin.PrettyName} x{testGoblins}");

                foreach (int t in Deploy.AtPoint(goblin, _orgin, testGoblins))
                {
                    yield return(t);
                }

                yield return(2000);

                int count = goblin.Count;

                Log.Info($"[Goblin Knife] Deploying {goblin.PrettyName} x{count}");
                foreach (int t in Deploy.AtPoint(goblin, _orgin, count))
                {
                    yield return(t);
                }

                // prevent infinite loop if deploy point is on red
                if (goblin.Count != count)
                {
                    continue;
                }

                Log.Warning($"[Goblin Knife] Couldn't deploy {goblin.PrettyName}");
                break;
            }
            //use freeze if inferno is found
            if (_freezeSpell?.Count > 0)
            {
                var infernos = InfernoTower.Find();
                // find and watch inferno towers
                if (infernos != null)
                {
                    foreach (var inferno in infernos)
                    {
                        inferno.FirstActivated += DropFreeze;

                        inferno.StartWatching();
                    }
                }
            }
            yield return(200);

            foreach (int t in Deploy.AtPoint(healspell, _target))
            {
                yield return(t);
            }

            foreach (int t in Deploy.AtPoint(ragespell, _target))
            {
                yield return(t);
            }
            if (watchHeroes == true)
            {
                Deploy.WatchHeroes(heroes, 7000);
            }
        }
        private void CreateDeployPoints(bool qw)
        {
            var target = TownHall.Find()?.Location.GetCenter() ??
                         DarkElixirStorage.Find().FirstOrDefault()?.Location.GetCenter() ??
                         new PointFT(0, 0);

            // don't include corners in case build huts are there
            var maxRedPointX = GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Max(point => point.X) + 1 ?? GameGrid.RedZoneExtents.MaxX;
            var minRedPointX = GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Min(point => point.X) - 1 ?? GameGrid.RedZoneExtents.MinX;
            var maxRedPointY = GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Max(point => point.Y) + 1 ?? GameGrid.RedZoneExtents.MaxY;
            var minRedPointY = GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Min(point => point.Y) - 1 ?? GameGrid.RedZoneExtents.MinY;

            // build a box around the base
            var left   = new PointFT(minRedPointX, maxRedPointY);
            var top    = new PointFT(maxRedPointX, maxRedPointY);
            var right  = new PointFT(maxRedPointX, minRedPointY);
            var bottom = new PointFT(minRedPointX, minRedPointY);

            // border around the base
            _border = new RectangleT((int)minRedPointX, (int)maxRedPointY, (int)(maxRedPointX - minRedPointX), (int)(minRedPointY - maxRedPointY));

            // core is center of the box
            _core = _border.GetCenter();

            var orginPoints = new[]
            {
                new PointFT(maxRedPointX, _core.Y),
                new PointFT(minRedPointX, _core.Y),
                new PointFT(_core.X, maxRedPointY),
                new PointFT(_core.X, minRedPointY)
            };

            _orgin = new Container <PointFT> {
                Item = orginPoints.OrderBy(point => point.DistanceSq(target)).First()
            };

            if (_orgin.Item.X > _core.X)
            {
                Log.Info("[Breakthrough] Attacking from the top right");

                var redLinePoint = GameGrid.RedPoints
                                   .Where(point => point.Y > -10 && point.Y < 10)?
                                   .Max(point => point.X) ?? GameGrid.RedZoneExtents.MaxX;

                if (qw)
                {
                    _qwPoint        = right;
                    _queenRagePoint = new PointFT(right.X - 5, right.Y + 5);
                    _healerPoint    = new PointFT(24f, -24f);
                    _attackLine     = new Tuple <PointFT, PointFT>(top, _orgin.Item.Midpoint(right));
                }
                else
                {
                    _attackLine  = new Tuple <PointFT, PointFT>(top, right);
                    _healerPoint = new PointFT(24f, _core.Y);
                }
                _healPoint = new PointFT(redLinePoint - 12f, _core.Y);
                _ragePoint = new PointFT(redLinePoint - 9f, _core.Y);
            }
            else if (_orgin.Item.X < _core.X)
            {
                Log.Info("[Breakthrough] Attacking from the bottom left");

                var redLinePoint = GameGrid.RedPoints
                                   .Where(point => point.Y > -10 && point.Y < 10)?
                                   .Min(point => point.X) ?? GameGrid.RedZoneExtents.MinX;

                if (qw)
                {
                    _qwPoint        = left;
                    _queenRagePoint = new PointFT(left.X + 5, left.Y - 5);
                    _healerPoint    = new PointFT(-24f, 24f);
                    _attackLine     = new Tuple <PointFT, PointFT>(bottom, _orgin.Item.Midpoint(left));
                }
                else
                {
                    _healerPoint = new PointFT(-24f, _core.Y);
                    _attackLine  = new Tuple <PointFT, PointFT>(bottom, left);
                }
                _healPoint = new PointFT(redLinePoint + 12, _core.Y);
                _ragePoint = new PointFT(redLinePoint + 9, _core.Y);
            }
            else if (_orgin.Item.Y > _core.Y)
            {
                Log.Info("[Breakthrough] Attacking from the top left");

                var redLinePoint = GameGrid.RedPoints
                                   .Where(point => point.X > -10 && point.X < 10)?
                                   .Max(point => point.Y) ?? GameGrid.RedZoneExtents.MaxY;

                if (qw)
                {
                    _qwPoint        = left;
                    _queenRagePoint = new PointFT(left.X + 5f, left.Y - 5f);
                    _healerPoint    = new PointFT(-24f, 24f);
                    _attackLine     = new Tuple <PointFT, PointFT>(top, _orgin.Item.Midpoint(left));
                }
                else
                {
                    _healerPoint = new PointFT(_core.X, 24f);
                    _attackLine  = new Tuple <PointFT, PointFT>(left, top);
                }
                _healPoint = new PointFT(_core.X, redLinePoint - 12f);
                _ragePoint = new PointFT(_core.X, redLinePoint - 9f);
            }
            else // (orgin.Y < core.Y)
            {
                Log.Info("[Breakthrough] Attacking from the bottom right");

                var redLinePoint = GameGrid.RedPoints
                                   .Where(point => point.X > -10 && point.X < 10)?
                                   .Min(point => point.Y) ?? GameGrid.RedZoneExtents.MinY;

                if (qw)
                {
                    _qwPoint        = right;
                    _queenRagePoint = new PointFT(right.X - 5, right.Y + 5);
                    _healerPoint    = new PointFT(24f, -24f);
                    _attackLine     = new Tuple <PointFT, PointFT>(bottom, _orgin.Item.Midpoint(right));
                }
                else
                {
                    _healerPoint = new PointFT(_core.X, -24f);
                    _attackLine  = new Tuple <PointFT, PointFT>(right, bottom);
                }
                _healPoint = new PointFT(_core.X, redLinePoint + 12);
                _ragePoint = new PointFT(_core.X, redLinePoint + 9);
            }
        }
        public static Target[] GenerateTargets(float minimumDistance, bool ignoreGold, bool ignoreElixir, CacheBehavior behavior = CacheBehavior.Default, bool outputDebugImage = false)
        {
            // Find all Collectors & storages just sitting around...
            List <Building> buildings = new List <Building>();

            if (!ignoreGold)
            {
                //User has Gold min set to ZERO - which means Dont include Gold Targets
                buildings.AddRange(GoldMine.Find(behavior));
                buildings.AddRange(GoldStorage.Find(behavior));
            }

            if (!ignoreElixir)
            {
                //User has Elixir min set to ZERO - which means Dont include Elixir Targets
                buildings.AddRange(ElixirCollector.Find(behavior));
                buildings.AddRange(ElixirStorage.Find(behavior));
            }

            //We always includ DarkElixir - Because who doesnt love dark Elixir?
            buildings.AddRange(DarkElixirDrill.Find(behavior));
            buildings.AddRange(DarkElixirStorage.Find(behavior));

            List <Target> targetList = new List <Target>();

            foreach (Building building in buildings)
            {
                Target current = new Target();

                current.TargetBuilding  = building;
                current.Center          = building.Location.GetCenter();
                current.NearestRedLine  = GameGrid.RedPoints.OrderBy(p => p.DistanceSq(current.Center)).First();
                current.CenterToRedline = current.Center.DistanceSq(current.NearestRedLine);
                Log.Debug($"[Berts Algorithms] DistanceSq from {current.Name} to red point: {current.CenterToRedline.ToString("F1")}");
                if (current.CenterToRedline < minimumDistance)                                                                              //Compare distance to Redline to the Minimum acceptable distance Passed in
                {
                    current.DeployGrunts = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _gruntDeployDistanceFromRedline);  //Barbs & Goblins
                    current.DeployRanged = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _rangedDeployDistanceFromRedline); //Archers & Minions

                    targetList.Add(current);
                }
            }

            if (outputDebugImage)
            {
                var d             = DateTime.UtcNow;
                var debugFileName = $"Human Barch {d.Year}-{d.Month}-{d.Day} {d.Hour}-{d.Minute}-{d.Second}-{d.Millisecond}";
                //Get a screen Capture of all targets we found...
                using (Bitmap canvas = Screenshot.Capture())
                {
                    Screenshot.Save(canvas, $"{debugFileName}_1");

                    foreach (var building in buildings)
                    {
                        var color = Color.White;
                        if (building.GetType() == typeof(ElixirCollector) || building.GetType() == typeof(ElixirStorage))
                        {
                            color = Color.Violet;
                        }
                        if (building.GetType() == typeof(GoldMine) || building.GetType() == typeof(GoldStorage))
                        {
                            color = Color.Gold;
                        }
                        if (building.GetType() == typeof(DarkElixirDrill) || building.GetType() == typeof(DarkElixirStorage))
                        {
                            color = Color.Brown;
                        }

                        //Draw a target on each building.
                        Visualize.Target(canvas, building.Location.GetCenter(), 40, color);
                    }
                    //Save the Image to the Debug Folder...
                    Screenshot.Save(canvas, $"{debugFileName}_2");
                }

                //Get a screen Capture of all targets we found...
                using (Bitmap canvas = Screenshot.Capture())
                {
                    foreach (var target in targetList)
                    {
                        var color = Color.White;
                        if (target.TargetBuilding.GetType() == typeof(ElixirCollector) || target.TargetBuilding.GetType() == typeof(ElixirStorage))
                        {
                            color = Color.Violet;
                        }
                        if (target.TargetBuilding.GetType() == typeof(GoldMine) || target.TargetBuilding.GetType() == typeof(GoldStorage))
                        {
                            color = Color.Gold;
                        }
                        if (target.TargetBuilding.GetType() == typeof(DarkElixirDrill) || target.TargetBuilding.GetType() == typeof(DarkElixirStorage))
                        {
                            color = Color.Brown;
                        }

                        //Draw a target on each building.
                        Visualize.Target(canvas, target.TargetBuilding.Location.GetCenter(), 40, color);
                        Visualize.Target(canvas, target.DeployGrunts, 20, color);
                        Visualize.Target(canvas, target.DeployRanged, 20, color);
                    }
                    //Save the Image to the Debug Folder...
                    Screenshot.Save(canvas, $"{debugFileName}_3");
                }

                Log.Debug("[Berts Algorithms] Collector/Storage & Target Debug Images Saved!");
            }

            Log.Debug($"[Berts Algorithms] Found {targetList.Count} deploy points");

            return(targetList.ToArray());
        }