public static IEnumerable <int> DeployBalloons()
        {
            yield return(dragonAttack ? 2000 : (babyLoon ? 500 : 0));

            if (balloon?.Count > 0)
            {
                if (!dragonAttack || balloon.Count > 10)
                {
                    foreach (var t in Deploy.AlongLine(balloon, AllInOnePushDeploy.AttackLine.Item1, AllInOnePushDeploy.AttackLine.Item2, balloon.Count, 2))
                    {
                        yield return(t);
                    }
                }
                else
                {
                    var count = balloon.Count / 2;
                    foreach (var t in Deploy.AtPoint(balloon, AllInOnePushDeploy.FirstFunnellingPoint, count))
                    {
                        yield return(t);
                    }

                    foreach (var t in Deploy.AtPoint(balloon, AllInOnePushDeploy.SecondFunnellingPoint, count))
                    {
                        yield return(t);
                    }
                }
            }
        }
        public static IEnumerable <int> DeployGiants()
        {
            var jumpSpellCount = jumpSpell?.Sum(u => u.Count);

            if ((useJump && jumpSpellCount >= 2) || (!useJump && jumpSpellCount >= 1))
            {
                foreach (var unit in jumpSpell)
                {
                    foreach (var t in Deploy.AtPoint(unit, AllInOnePushDeploy.FirstJumpPoint))
                    {
                        yield return(t);
                    }
                }
            }

            if (giant?.Count > 0)
            {
                Log.Info($"[{AllInOnePushDeploy.AttackName}] deploy Giants ...");
                foreach (var t in Deploy.AlongLine(giant, AllInOnePushDeploy.FirstFunnellingPoint, AllInOnePushDeploy.SecondFunnellingPoint, 8, 4))
                {
                    yield return(t);
                }

                var waves = wizard?.Count >= 8 ? 2 : 1;
                foreach (var f in DeployWizard(waves))
                {
                    yield return(f);
                }

                foreach (var f in DeployWB())
                {
                    yield return(f);
                }

                foreach (var t in Deploy.AtPoint(giant, AllInOnePushDeploy.Origin, giant.Count))
                {
                    yield return(t);
                }
            }

            if (clanCastle?.Count > 0 && AllInOnePushDeploy.ClanCastleSettings == 2)
            {
                foreach (var t in Deploy.AtPoint(clanCastle, AllInOnePushDeploy.Origin))
                {
                    yield return(t);
                }
            }

            //if one golem deploy after funnlling
            if (golem?.Count > 0)
            {
                Log.Info($"[{AllInOnePushDeploy.AttackName}] deploy Golem ...");
                foreach (var t in Deploy.AlongLine(golem, AllInOnePushDeploy.AttackLine.Item1, AllInOnePushDeploy.AttackLine.Item2, golem.Count, golem.Count))
                {
                    yield return(t);
                }
            }
        }
 public static IEnumerable <int> DeployMinions()
 {
     if (minion?.Count > 0)
     {
         foreach (var t in Deploy.AlongLine(minion, AllInOnePushDeploy.AttackLine.Item1, AllInOnePushDeploy.AttackLine.Item2, minion.Count, 4))
         {
             yield return(t);
         }
     }
 }
 public static IEnumerable <int> DeployBabyDragons()
 {
     if (babyDragon?.Count > 0)
     {
         foreach (var t in Deploy.AlongLine(babyDragon, AllInOnePushDeploy.FirstFunnellingPoint, AllInOnePushDeploy.SecondFunnellingPoint, babyDragon.Count, 4, 50))
         {
             yield return(t);
         }
     }
 }
 public static IEnumerable <int> DeployWizard(int waves = 1)
 {
     if (wizard?.Count > 0)
     {
         var count = wizard.Count / waves;
         foreach (var t in Deploy.AlongLine(wizard, AllInOnePushDeploy.FirstFunnellingPoint, AllInOnePushDeploy.SecondFunnellingPoint, count, 4))
         {
             yield return(t);
         }
     }
 }
        public static IEnumerable <int> DeployUnusedTroops()
        {
            // Check unit bar for unused troops
            Log.Warning($"{AllInOnePushDeploy.AttackName} search for unused troops !!");
            var unusedTroops = Deploy.GetTroops();
            var spell        = unusedTroops.Extract(DeployElementType.Spell);

            if (unusedTroops.Sum(u => u.Count) > 0)
            {
                unusedTroops.OrderForDeploy();
                foreach (var u in unusedTroops)
                {
                    if (u?.Count > 0)
                    {
                        Log.Warning($"we found {u.Count}x {u.PrettyName}");
                    }
                }

                Log.Info($"[{AllInOnePushDeploy.AttackName}] deploy unused troops");
                foreach (var unit in unusedTroops)
                {
                    if (unit?.Count > 0)
                    {
                        if (unit.IsRanged)
                        {
                            foreach (var t in Deploy.AlongLine(unit, AllInOnePushDeploy.FirstFunnellingPoint, AllInOnePushDeploy.SecondFunnellingPoint, unit.Count, 4))
                            {
                                yield return(t);
                            }
                        }
                        else
                        {
                            foreach (var t in Deploy.AtPoint(unit, AllInOnePushDeploy.Origin, unit.Count))
                            {
                                yield return(t);
                            }
                        }
                    }
                }
            }
            else
            {
                Log.Info($"[{AllInOnePushDeploy.AttackName}] all Troops have been deployed");
            }
        }
        public static IEnumerable <int> AirAttack(int customOrder)
        {
            Log.Info($"[{AllInOnePushDeploy.AttackName}] 'Air Attack' has been activated");

            DeploymentMethods.wallbreaker = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.WallBreaker);
            DeploymentMethods.balloon     = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Balloon);
            DeploymentMethods.minion      = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Minion);
            DeploymentMethods.babyDragon  = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.BabyDragon);
            DeploymentMethods.dragon      = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Dragon);
            DeploymentMethods.lava        = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.LavaHound);

            DeploymentMethods.spells = AllInOnePushDeploy.deployElements.Extract(DeployElementType.Spell);

            DeploymentMethods.lightingSpell = DeploymentMethods.spells.ExtractOne(DeployId.Lightning);
            DeploymentMethods.eq            = DeploymentMethods.spells.Extract(u => u.Id == DeployId.Earthquake);
            DeploymentMethods.hasteSpell    = DeploymentMethods.spells.Extract(u => u.Id == DeployId.Haste);
            DeploymentMethods.rageSpell     = DeploymentMethods.spells.Extract(u => u.Id == DeployId.Rage);
            DeploymentMethods.freezeSpell   = DeploymentMethods.spells.ExtractOne(DeployId.Freeze);

            DeploymentMethods.clanCastle = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.ClanCastle);

            DeploymentMethods.heroes = AllInOnePushDeploy.deployElements.Extract(x => x.IsHero);

            DeploymentMethods.warden = DeploymentMethods.heroes.ExtractOne(u => u.ElementType == DeployElementType.HeroWarden);
            DeploymentMethods.queen  = DeploymentMethods.heroes.ExtractOne(DeployId.Queen);

            DeploymentMethods.dragonAttack = DeploymentMethods.dragon?.Count >= 5 ? true : false;
            DeploymentMethods.babyLoon     = DeploymentMethods.babyDragon?.Count >= 7 ? true : false;
            DeploymentMethods.lavaloonion  = DeploymentMethods.balloon?.Count >= 15 ? true : false;

            if (DeploymentMethods.lightingSpell?.Count >= 2)
            {
                foreach (var t in DeploymentMethods.ZapAirDefense())
                {
                    yield return(t);
                }
            }

            if (DeploymentMethods.lightingSpell?.Count >= 2)
            {
                foreach (var t in DeploymentMethods.ZapAirDefense())
                {
                    yield return(t);
                }
            }

            if (customOrder == 1)
            {
                foreach (var t in DeploymentMethods.DeployInCustomOrderAir(AllInOnePushDeploy.CustomOrderList))
                {
                    yield return(t);
                }
            }
            else
            {
                if (DeploymentMethods.babyLoon)
                {
                    foreach (var t in DeploymentMethods.AirFunnelling())
                    {
                        yield return(t);
                    }

                    foreach (var t in DeploymentMethods.DeployBabyDragons())
                    {
                        yield return(t);
                    }

                    foreach (var t in DeploymentMethods.DeployBalloons())
                    {
                        yield return(t);
                    }

                    foreach (var t in DeploymentMethods.DeployLava())
                    {
                        yield return(t);
                    }
                }
                else if (DeploymentMethods.dragonAttack)
                {
                    foreach (var t in DeploymentMethods.AirFunnelling())
                    {
                        yield return(t);
                    }

                    foreach (var t in DeploymentMethods.DeployLava())
                    {
                        yield return(t);
                    }

                    foreach (var t in DeploymentMethods.DeployDragons())
                    {
                        yield return(t);
                    }

                    foreach (var t in DeploymentMethods.DeployBalloons())
                    {
                        yield return(t);
                    }
                }
                else if (DeploymentMethods.lavaloonion)
                {
                    foreach (var t in DeploymentMethods.DeployBalloons())
                    {
                        yield return(t);
                    }

                    foreach (var t in DeploymentMethods.DeployLava())
                    {
                        yield return(t);
                    }

                    if (DeploymentMethods.clanCastle?.Count > 0)
                    {
                        foreach (var t in Deploy.AtPoint(DeploymentMethods.clanCastle, AllInOnePushDeploy.Origin))
                        {
                            yield return(t);
                        }
                    }

                    foreach (var t in DeploymentMethods.DeployDragons())
                    {
                        yield return(t);
                    }

                    foreach (var t in DeploymentMethods.DeployBabyDragons())
                    {
                        yield return(t);
                    }
                }
            }

            if (DeploymentMethods.clanCastle?.Count > 0)
            {
                foreach (var t in Deploy.AtPoint(DeploymentMethods.clanCastle, AllInOnePushDeploy.Origin))
                {
                    yield return(t);
                }
            }

            if (DeploymentMethods.warden?.Count > 0)
            {
                foreach (var t in Deploy.AtPoint(DeploymentMethods.warden, AllInOnePushDeploy.Origin))
                {
                    yield return(t);
                }


                DeploymentMethods.isWarden = true;
            }
            else
            {
                DeploymentMethods.isWarden = false;
            }

            // Start with haste <IF> it's more than or equal rages count <ELSE> start with rages.
            var firstSpell  = DeploymentMethods.hasteSpell?.Sum(u => u.Count) >= DeploymentMethods.rageSpell?.Sum(u => u.Count) ? DeploymentMethods.hasteSpell : DeploymentMethods.rageSpell;
            var secondSpell = firstSpell == DeploymentMethods.hasteSpell ? DeploymentMethods.rageSpell : DeploymentMethods.hasteSpell;

            var firstSpellUnit  = firstSpell.FirstOrDefault()?.Count > 0 ? firstSpell.FirstOrDefault() : firstSpell.LastOrDefault();
            var secondSpellUnit = secondSpell.FirstOrDefault()?.Count > 0 ? secondSpell.FirstOrDefault() : secondSpell.LastOrDefault();

            var line = AllInOnePushDeploy.FirstHasteLine;

            // Todo: deploy rages for TH8, 2 on the first line then 1 on the second line.

            if (firstSpellUnit?.Count > 0)
            {
                var count = firstSpellUnit.Count >= 3 ? 3 : firstSpellUnit.Count;
                foreach (var t in Deploy.AlongLine(firstSpellUnit, line.Item1, line.Item2, count, count, 250))
                {
                    yield return(t);
                }

                line = AllInOnePushDeploy.FirstRageLine;
            }

            foreach (var t in DeploymentMethods.DeployMinions())
            {
                yield return(t);
            }

            yield return(4500);

            if (secondSpellUnit?.Count > 0)
            {
                var count = secondSpellUnit.Count >= 3 ? 3 : secondSpellUnit.Count;
                foreach (var t in Deploy.AlongLine(secondSpellUnit, line.Item1, line.Item2, count, count, 250))
                {
                    yield return(t);
                }

                line = AllInOnePushDeploy.SecondHasteLine;
            }
            else
            {
                if (firstSpell?.Sum(u => u.Count) > 0)
                {
                    firstSpellUnit = firstSpell.FirstOrDefault().Count > 0 ? firstSpell.FirstOrDefault() : firstSpell.LastOrDefault();
                    var count = firstSpellUnit.Count >= 3 ? 3 : firstSpellUnit.Count;
                    foreach (var t in Deploy.AlongLine(firstSpellUnit, line.Item1, line.Item2, count, count, 250))
                    {
                        yield return(t);
                    }

                    line = AllInOnePushDeploy.SecondHasteLine;
                }
            }

            // Use freeze if inferno is found
            if (DeploymentMethods.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();
                    }
                }
            }

            if (DeploymentMethods.isWarden)
            {
                DeploymentMethods.warden.Select();
                DeploymentMethods.warden.Select();
            }

            yield return(4000);

            if (firstSpell?.Sum(u => u.Count) > 0)
            {
                foreach (var unit in firstSpell)
                {
                    var count = unit.Count >= 3 ? 3 : unit.Count;
                    foreach (var t in Deploy.AlongLine(unit, line.Item1, line.Item2, count, count, 250))
                    {
                        yield return(t);
                    }
                }

                line = AllInOnePushDeploy.SecondRageLine;
            }

            if (secondSpell?.Sum(u => u.Count) > 0)
            {
                secondSpellUnit = secondSpell.FirstOrDefault().Count > 0 ? secondSpell.FirstOrDefault() : secondSpell.LastOrDefault();
                foreach (var unit in secondSpell)
                {
                    var count = unit.Count >= 3 ? 3 : unit.Count;
                    foreach (var t in Deploy.AlongLine(unit, line.Item1, line.Item2, count, count, 250))
                    {
                        yield return(t);
                    }
                }
            }

            foreach (var t in DeploymentMethods.DeployWB())
            {
                yield return(t);
            }

            yield return(4000);

            if (DeploymentMethods.heroes.Any())
            {
                foreach (var hero in DeploymentMethods.heroes.Where(u => u.Count > 0))
                {
                    foreach (var t in Deploy.AtPoint(hero, AllInOnePushDeploy.Origin))
                    {
                        yield return(t);
                    }
                }
                Deploy.WatchHeroes(DeploymentMethods.heroes);
            }


            if (DeploymentMethods.queen?.Count > 0)
            {
                foreach (var t in Deploy.AtPoint(DeploymentMethods.queen, AllInOnePushDeploy.Origin))
                {
                    yield return(t);
                }
                Deploy.WatchHeroes(new List <DeployElement> {
                    DeploymentMethods.queen
                });
            }

            foreach (var w in DeploymentMethods.DeployUnusedTroops())
            {
                yield return(w);
            }
        }
        public override IEnumerable <int> AttackRoutine()
        {
            // Set start battle time.
            startTime = DateTime.Now;

            int waveLimit   = UserSettings.WaveSize;
            int waveDelay   = (int)(UserSettings.WaveDelay * 1000);
            int heroesIndex = -1;

            // Set the core point of the base
            SmartFourFingersHelper.SetCore();

            if (!IsTargetsCalculated)
            {
                SmartFourFingersHelper.CalculateTargets();
            }


            // Points to draw lines in deploy extends area.
            var topLeft  = new PointFT((float)GameGrid.MaxX - 2, (float)GameGrid.DeployExtents.MaxY);
            var topRight = new PointFT((float)GameGrid.DeployExtents.MaxX, (float)GameGrid.MaxY - 2);

            var rightTop    = new PointFT((float)GameGrid.DeployExtents.MaxX, (float)GameGrid.MinY + 2);
            var rightBottom = new PointFT((float)GameGrid.MaxX - 2, (float)GameGrid.DeployExtents.MinY);

            // Move 8 tiles from bottom corner due to unitsbar.
            var bottomLeft  = new PointFT((float)GameGrid.DeployExtents.MinX, (float)GameGrid.MinY + 8);
            var bottomRight = new PointFT((float)GameGrid.MinX + 8, (float)GameGrid.DeployExtents.MinY);

            var leftTop    = new PointFT((float)GameGrid.MinX + 2, (float)GameGrid.DeployExtents.MaxY);
            var leftBottom = new PointFT((float)GameGrid.DeployExtents.MinX, (float)GameGrid.MaxY - 2);

            var linesPointsList = new List <PointFT>
            {
                topLeft, topRight,
                rightTop, rightBottom,
                bottomLeft, bottomRight,
                leftBottom, leftTop
            };

            // Main four lines of attack.
            var topRightLine    = new Tuple <PointFT, PointFT>(topRight, rightTop);
            var bottomRightLine = new Tuple <PointFT, PointFT>(bottomRight, rightBottom);
            var bottomLeftLine  = new Tuple <PointFT, PointFT>(bottomLeft, leftBottom);
            var topLeftLine     = new Tuple <PointFT, PointFT>(topLeft, leftTop);

            // List of the four attack lines in clocwise order
            AttackLines = new List <Tuple <PointFT, PointFT> >
            {
                topRightLine,
                bottomRightLine,
                bottomLeftLine,
                topLeftLine
            };



            var deployHeroesAt = GetCurrentSetting("Deploy Heroes At");

            var target = SmartFourFingersHelper.GetHeroesTarget(deployHeroesAt);

            // Search for target if not found for 3 more times
            if (target.X == 0f && target.Y == 0f)
            {
                for (var i = 1; i <= 3; i++)
                {
                    yield return(1000);

                    target = SmartFourFingersHelper.GetHeroesTarget(deployHeroesAt);
                    if (target.X != 0f || target.Y != 0f)
                    {
                        break;
                    }
                }
            }

            var nearestRedPointToTarget = GameGrid.RedPoints.OrderBy(p => p.DistanceSq(target)).FirstOrDefault();
            var nearestLinePoint        = linesPointsList.OrderBy(p => p.DistanceSq(nearestRedPointToTarget)).FirstOrDefault();

            heroesIndex = AttackLines.FindIndex(u => (u.Item1.X == nearestLinePoint.X && u.Item1.Y == nearestLinePoint.Y) || (u.Item2.X == nearestLinePoint.X && u.Item2.Y == nearestLinePoint.Y));

            var units  = Deploy.GetTroops();
            var heroes = units.Extract(x => x.IsHero);
            var cc     = units.ExtractOne(u => u.ElementType == DeployElementType.ClanTroops);
            var spells = units.Extract(u => u.ElementType == DeployElementType.Spell);

            units.OrderForDeploy();

            // Set first attack line
            // Start from the next line to user defined to end with user defined line
            var line  = AttackLines.NextOf(AttackLines[heroesIndex]);
            var index = AttackLines.FindIndex(u => u.Item1.X == line.Item1.X && u.Item1.Y == line.Item1.Y);

            var deploymentMode = GetCurrentSetting("Set Troops Deployment");

            if (deploymentMode == 2)
            {
                AddFakeTargets();
            }

            var targetsCount = TargetsAtLine[index];

            Log.Info($"{AttackName} {Version} starts");

            var deployCC = GetCurrentSetting("CC Deployment");

            if (deployCC == 0 && cc?.Count > 0)
            {
                Log.Info($"{AttackName} Deploy Clan Castle troops first");
                foreach (var t in Deploy.AlongLine(cc, line.Item1, line.Item2, 1, 1, 0, waveDelay))
                {
                    yield return(t);
                }
            }

            // Start troops deployment on four sides.
            for (var i = 4; i >= 1; i--)
            {
                Log.Info($"Targets at this side = {targetsCount} targets from total {TotalTargetsCount} targets");
                foreach (var unit in units)
                {
                    if (unit?.Count > 0)
                    {
                        var count   = deploymentMode == 0 ? unit.Count / i : (TotalTargetsCount > 0 ? unit.Count * targetsCount / TotalTargetsCount : 0);
                        var housing = unit.UnitData.HousingSpace;
                        var fingers = housing < 4 ? (count < 8 ? count : 4) : 1;

                        Log.Info($"{AttackName} Deploy {count}x {unit.PrettyName}");
                        foreach (var t in Deploy.AlongLine(unit, line.Item1, line.Item2, count, fingers, 0, waveDelay))
                        {
                            yield return(t);
                        }
                    }
                }

                if (i != 1)
                {
                    line  = AttackLines.NextOf(AttackLines[index]);
                    index = AttackLines.FindIndex(u => u.Item1.X == line.Item1.X && u.Item1.Y == line.Item1.Y);

                    TotalTargetsCount -= targetsCount;
                    targetsCount       = TargetsAtLine[index];
                }
            }

            if (deployCC == 1 && cc?.Count > 0)
            {
                Log.Info($"{AttackName} Deploy Clan Castle troops");
                foreach (var t in Deploy.AlongLine(cc, line.Item1, line.Item2, 1, 1, 0, waveDelay))
                {
                    yield return(t);
                }
            }

            if (heroes.Any())
            {
                Log.Info($"{AttackName} Deploy Heroes");
                foreach (var hero in heroes.Where(u => u.Count > 0))
                {
                    foreach (var t in Deploy.AlongLine(hero, line.Item1, line.Item2, 1, 1, 0, waveDelay))
                    {
                        yield return(t);
                    }
                }
                Deploy.WatchHeroes(heroes, 5000);
            }

            // Call FinalizeAttack and ForceZap at the same time
            var zapSpells = Deploy.GetTroops().Extract(u => u.ElementType == DeployElementType.Spell);

            if (spells.Extract(u => u.Id == DeployId.Lightning).Sum(u => u.Count) > 0 ||
                spells.Extract(u => u.Id == DeployId.Earthquake).Sum(u => u.Count) > 0)
            {
                var finalize = this.FinalizeAttack(units).GetEnumerator();
                var force    = ForceZap().GetEnumerator();

                var firstEnumMoreItems  = finalize.MoveNext();
                var secondEnumMoreItems = force.MoveNext();

                // Start both FinalizeAttack and ForceZap
                while (firstEnumMoreItems && secondEnumMoreItems)
                {
                    firstEnumMoreItems  = finalize.MoveNext();
                    secondEnumMoreItems = force.MoveNext();
                    yield return(200);
                }
                // Complete ForceZap if FinalizeAttack finished
                while (!firstEnumMoreItems && secondEnumMoreItems)
                {
                    secondEnumMoreItems = force.MoveNext();
                    yield return(200);
                }
                // Complete FinalizeAttack if ForceZap finished
                while (!secondEnumMoreItems && firstEnumMoreItems)
                {
                    firstEnumMoreItems = finalize.MoveNext();
                    yield return(200);
                }
            }
            else
            {
                yield break;
            }
        }
        public static IEnumerable <int> DeployGolems()
        {
            if (golem?.Count >= 2)
            {
                Log.Info($"[{AllInOnePushDeploy.AttackName}] deploy Golems troops .. ");

                foreach (var t in Deploy.AlongLine(golem, AllInOnePushDeploy.AttackLine.Item1, AllInOnePushDeploy.AttackLine.Item2, golem.Count, golem.Count))
                {
                    yield return(t);
                }

                if (AllInOnePushDeploy.ClanCastleSettings == 1)
                {
                    if (clanCastle?.Count > 0)
                    {
                        foreach (var t in Deploy.AtPoint(clanCastle, AllInOnePushDeploy.Origin))
                        {
                            yield return(t);
                        }
                    }
                }

                yield return(new Random().Next(800, 1500));

                var waves = wizard?.Count >= 12 ? 2 : 1;
                foreach (var f in DeployWizard(waves))
                {
                    yield return(f);
                }
            }
            else if (golem?.Count == 1 && AllInOnePushDeploy.ClanCastleSettings == 1)
            {
                if (clanCastle?.Count > 0)
                {
                    foreach (var t in Deploy.AtPoint(golem, AllInOnePushDeploy.FirstFunnellingPoint, golem.Count))
                    {
                        yield return(t);
                    }

                    foreach (var t in Deploy.AtPoint(clanCastle, AllInOnePushDeploy.SecondFunnellingPoint))
                    {
                        yield return(t);
                    }

                    yield return(1000);
                }
            }
            else
            {
                if (golem?.Count > 0 && healer?.Count == null)
                {
                    foreach (var t in Deploy.AtPoint(golem, AllInOnePushDeploy.Origin))
                    {
                        yield return(t);
                    }
                }
                if (AllInOnePushDeploy.ClanCastleSettings == 1)
                {
                    if (clanCastle?.Count > 0)
                    {
                        foreach (var t in Deploy.AtPoint(clanCastle, AllInOnePushDeploy.Origin))
                        {
                            yield return(t);
                        }
                    }
                }
            }
        }
        public static IEnumerable <int> DeployNormalTroops()
        {
            Log.Info($"[{AllInOnePushDeploy.AttackName}] deploy rest of troops");

            if (witch?.Count > 4)
            {
                if (bowler?.Count > 0)
                {
                    foreach (var t in Deploy.AlongLine(bowler, AllInOnePushDeploy.FirstFunnellingPoint, AllInOnePushDeploy.SecondFunnellingPoint, bowlerFunnelCount, 4))
                    {
                        yield return(t);
                    }
                }
            }


            if (bowler?.Count > 0)
            {
                foreach (var t in Deploy.AtPoint(bowler, AllInOnePushDeploy.Origin, bowler.Count))
                {
                    yield return(t);
                }
            }
            if (witch?.Count > 0)
            {
                foreach (var t in Deploy.AtPoint(witch, AllInOnePushDeploy.Origin, witch.Count))
                {
                    yield return(t);
                }
            }
            if (clanCastle?.Count > 0)
            {
                Log.Info($"[{AllInOnePushDeploy.AttackName}] Deploying {clanCastle.PrettyName}");
                foreach (var t in Deploy.AtPoint(clanCastle, AllInOnePushDeploy.Origin))
                {
                    yield return(t);
                }
            }

            if (healer?.Count > 0)
            {
                foreach (var t in Deploy.AtPoint(healer, AllInOnePushDeploy.Origin, healer.Count))
                {
                    yield return(t);
                }
            }

            AllInOnePushDeploy.deployElements.OrderForDeploy();
            foreach (var unit in AllInOnePushDeploy.deployElements)
            {
                Log.Info($"[{AllInOnePushDeploy.AttackName}] deploy any remaining troops");
                if (unit?.Count > 0)
                {
                    if (unit.IsRanged)
                    {
                        foreach (var t in Deploy.AlongLine(unit, AllInOnePushDeploy.FirstFunnellingPoint, AllInOnePushDeploy.SecondFunnellingPoint, unit.Count, 4))
                        {
                            yield return(t);
                        }
                    }
                    else
                    {
                        foreach (var t in Deploy.AtPoint(unit, AllInOnePushDeploy.Origin, unit.Count))
                        {
                            yield return(t);
                        }
                    }
                }
            }

            foreach (var w in DeployWizard())
            {
                yield return(w);
            }

            foreach (var w in DeployUnusedTroops())
            {
                yield return(w);
            }
        }
        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);
            }
        }
        public override IEnumerable <int> AttackRoutine()
        {
            Log.Info("[Breakthrough] Deploy start");

            var funnelIds  = new[] { DeployId.Archer, DeployId.Barbarian, DeployId.Minion, DeployId.Wizard };
            var byLineIds  = new[] { DeployId.Archer, DeployId.Barbarian, DeployId.Minion, DeployId.Wizard, DeployId.Balloon, DeployId.Dragon, DeployId.BabyDragon, DeployId.Miner };
            var byPointIds = new[] { DeployId.Valkyrie, DeployId.Pekka, DeployId.Witch, DeployId.Goblin, DeployId.Bowler };

            // get a list of all deployable units
            var deployElements = Deploy.GetTroops();

            // extract spells into their own list
            var spells = deployElements.Extract(DeployElementType.Spell);

            // extract heores into their own list
            var heroes = deployElements.Extract(u => u.IsHero);

            // extract clanCastle into its own list
            var clanCastle = deployElements.ExtractOne(u => u.ElementType == DeployElementType.ClanTroops);

            // get tanks
            var tanks = deployElements.Extract(AttackType.Tank).ToArray();

            // get wallbreakers
            var wallBreakers = deployElements.ExtractOne(DeployId.WallBreaker);

            // get healers
            var healers = deployElements.ExtractOne(DeployId.Healer);

            // get funnel troops
            var funnel = funnelIds.Select(id => deployElements.FirstOrDefault(u => u.Id == id)).Where(u => u != null).ToArray();

            // get deploy all in a line
            var byLine = deployElements.Extract(byLineIds).ToArray();

            // get deploy all by point
            var byPoint = deployElements.Extract(byPointIds).ToArray();

            // get hogs
            var hogs = deployElements.ExtractOne(u => u.Id == DeployId.HogRider);

            // get heal spells
            var healSpells = spells.ExtractOne(u => u.Id == DeployId.Heal);

            // get rage spells
            var rageSpells = spells.ExtractOne(u => u.Id == DeployId.Rage);

            // user's wave delay setting
            var waveDelay = (int)(UserSettings.WaveDelay * 1000);

            // check if queen walk is an option
            if (heroes.Any(u => u.Id == DeployId.Queen) && healers?.Count >= 4)
            {
                var queen = heroes.ExtractOne(u => u.Id == DeployId.Queen);

                // get deploy points with queen walk
                CreateDeployPoints(true);

                // deploy queen walk
                Log.Info("[Breakthrough] Queen walk available.");
                Log.Info($"[Breakthrough] Deploying {queen.PrettyName}");
                foreach (var t in Deploy.AtPoint(queen, _qwPoint, waveDelay: waveDelay))
                {
                    yield return(t);
                }

                var healerCount = Math.Min(healers.Count, 4);
                Log.Info($"[Breakthrough] Deploying {healers.PrettyName} x{healerCount}");
                foreach (var t in Deploy.AtPoint(healers, _healerPoint, healerCount, waveDelay: waveDelay))
                {
                    yield return(t);
                }

                // watch queen
                Deploy.WatchHeroes(new List <DeployElement> {
                    queen
                });

                if (rageSpells?.Count > 1)
                {
                    Log.Info($"[Breakthrough] Deploying {rageSpells.PrettyName} x1");
                    foreach (var t in Deploy.AtPoint(rageSpells, _queenRagePoint, waveDelay: waveDelay))
                    {
                        yield return(t);
                    }
                }

                // wait 15 seconds
                yield return(15000);
            }
            else
            {
                // get deploy points without queen walk
                CreateDeployPoints(false);
            }

            var funnelTank = tanks.FirstOrDefault(u => u.Id == DeployId.Giant) ?? tanks.FirstOrDefault();

            // deploy four tanks if available
            if (funnelTank != null)
            {
                var deployCount = Math.Min(funnelTank.Count, 4);

                Log.Info($"[Breakthrough] Deploying {funnelTank.PrettyName} x{deployCount}");
                foreach (var t in Deploy.AlongLine(funnelTank, _attackLine.Item1, _attackLine.Item2, deployCount,
                                                   deployCount, waveDelay: waveDelay))
                {
                    yield return(t);
                }
            }

            // deploy funnel
            foreach (var unit in funnel.Where(u => u.Count > 0))
            {
                var deployElementCount = Math.Min(unit.Count, UserSettings.WaveSize / unit.UnitData.HousingSpace);

                Log.Info($"[Breakthrough] Deploying {unit.PrettyName} x{deployElementCount}");
                foreach (
                    var t in
                    Deploy.AlongLine(unit, _attackLine.Item1, _attackLine.Item2, deployElementCount, 4,
                                     waveDelay: waveDelay))
                {
                    yield return(t);
                }
            }

            // deploy Wallbreakers
            while (wallBreakers?.Count > 0)
            {
                var count = wallBreakers.Count;

                Log.Info($"[Breakthrough] Deploying {wallBreakers.PrettyName} x3");
                foreach (var t in Deploy.AtPoint(wallBreakers, _orgin, 3))
                {
                    yield return(t);
                }

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

                Log.Warning($"[Breakthrough] Couldn't deploy {wallBreakers.PrettyName}");
                break;
            }


            // deploy the rest of the tanks
            while (tanks.Any(u => u.Count > 0))
            {
                var deployError = false;

                foreach (var unit in tanks.Where(u => u.Count > 0))
                {
                    var count = unit.Count;

                    Log.Info($"[Breakthrough] Deploying {unit.PrettyName} x{unit.Count}");
                    foreach (var t in Deploy.AtPoint(unit, _orgin, unit.Count, waveDelay: waveDelay))
                    {
                        yield return(t);
                    }

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

                    Log.Warning($"[Breakthrough] Couldn't deploy {unit.PrettyName}");
                    deployError = true;
                    break;
                }
                if (deployError)
                {
                    break;
                }
            }

            if (rageSpells?.Count > 0)
            {
                Log.Info($"[Breakthrough] Deploying {rageSpells.PrettyName} x1");
                foreach (var t in Deploy.AtPoint(rageSpells, _ragePoint, waveDelay: waveDelay))
                {
                    yield return(t);
                }
            }

            if (healSpells?.Count > 0)
            {
                Log.Info($"[Breakthrough] Deploying {healSpells.PrettyName} x1");
                foreach (var t in Deploy.AtPoint(healSpells, _healPoint, waveDelay: waveDelay))
                {
                    yield return(t);
                }
            }

            while (byLine.Any(u => u.Count > 0))
            {
                foreach (var unit in byLine.Where(u => u.Count > 0))
                {
                    Log.Info($"[Breakthrough] Deploying {unit.PrettyName} x{unit.Count}");
                    foreach (
                        var t in
                        Deploy.AlongLine(unit, _attackLine.Item1, _attackLine.Item2, unit.Count, 4,
                                         waveDelay: waveDelay))
                    {
                        yield return(t);
                    }
                }
            }

            while (byPoint.Any(u => u.Count > 0))
            {
                var deployError = false;

                foreach (var unit in byPoint.Where(u => u.Count > 0))
                {
                    var count = unit.Count;

                    Log.Info($"[Breakthrough] Deploying {unit.PrettyName} x{unit.Count}");
                    foreach (var t in Deploy.AtPoint(unit, _orgin, unit.Count, waveDelay: waveDelay))
                    {
                        yield return(t);
                    }

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

                    Log.Warning($"[Breakthrough] Couldn't deploy {unit.PrettyName}");
                    deployError = true;
                    break;
                }
                if (deployError)
                {
                    break;
                }
            }

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

            if (heroes.Any())
            {
                foreach (var hero in heroes.Where(u => u.Count > 0))
                {
                    Log.Info($"[Breakthrough] Deploying {hero.PrettyName}");
                    foreach (var t in Deploy.AtPoint(hero, _orgin, waveDelay: waveDelay))
                    {
                        yield return(t);
                    }
                }
            }

            if (healers?.Count > 0)
            {
                Log.Info($"[Breakthrough] Deploying {healers.PrettyName} x{healers.Count}");
                foreach (var t in Deploy.AtPoint(healers, _healerPoint, healers.Count, waveDelay: waveDelay))
                {
                    yield return(t);
                }
            }

            if (hogs?.Count > 0)
            {
                Log.Info($"[Breakthrough] Deploying {hogs.PrettyName} x{hogs.Count}");
                foreach (var t in Deploy.AtPoint(hogs, _orgin, hogs.Count, waveDelay: waveDelay))
                {
                    yield return(t);
                }
            }

            Deploy.WatchHeroes(heroes);

            // get freeze spells
            _freezeSpell = spells.ExtractOne(u => u.Id == DeployId.Freeze);

            // no freeze spells so end deployment
            if (!(_freezeSpell?.Count > 0))
            {
                yield break;
            }

            // find and watch inferno towers
            var infernos = InfernoTower.Find();

            foreach (var inferno in infernos)
            {
                inferno.FirstActivated += DropFreeze;

                inferno.StartWatching();
            }
        }
Ejemplo n.º 13
0
        public override IEnumerable <int> AttackRoutine()
        {
            int waveLimit   = UserSettings.WaveSize;
            int waveDelay   = (int)(UserSettings.WaveDelay * 1000);
            int heroesIndex = -1;

            var core = new PointFT(-0.01f, 0.01f);

            // Points to draw lines in deploy extends area.
            var topLeft  = new PointFT((float)GameGrid.MaxX - 2, (float)GameGrid.DeployExtents.MaxY);
            var topRight = new PointFT((float)GameGrid.DeployExtents.MaxX, (float)GameGrid.MaxY - 2);

            var rightTop    = new PointFT((float)GameGrid.DeployExtents.MaxX, (float)GameGrid.MinY + 2);
            var rightBottom = new PointFT((float)GameGrid.MaxX - 2, (float)GameGrid.DeployExtents.MinY);

            // Move 8 tiles from bottom corner due to unitsbar.
            var bottomLeft  = new PointFT((float)GameGrid.DeployExtents.MinX, (float)GameGrid.MinY + 8);
            var bottomRight = new PointFT((float)GameGrid.MinX + 8, (float)GameGrid.DeployExtents.MinY);

            var leftTop    = new PointFT((float)GameGrid.MinX + 2, (float)GameGrid.DeployExtents.MaxY);
            var leftBottom = new PointFT((float)GameGrid.DeployExtents.MinX, (float)GameGrid.MaxY - 2);

            var linesPointsList = new List <PointFT>
            {
                topLeft, topRight,
                rightTop, rightBottom,
                bottomLeft, bottomRight,
                leftBottom, leftTop
            };

            // Main four lines of attack.
            var topRightLine    = new Tuple <PointFT, PointFT>(topRight, rightTop);
            var bottomRightLine = new Tuple <PointFT, PointFT>(bottomRight, rightBottom);
            var bottomLeftLine  = new Tuple <PointFT, PointFT>(bottomLeft, leftBottom);
            var topLeftLine     = new Tuple <PointFT, PointFT>(topLeft, leftTop);

            // List of the four attack lines in clocwise order
            var attackLines = new List <Tuple <PointFT, PointFT> >
            {
                topLeftLine,
                topRightLine,
                bottomRightLine,
                bottomLeftLine
            };

            var deployHeroesAt = GetCurrentSetting("Deploy Heroes At");


            var target = SmartFourFingersHelper.GetHeroesTarget(deployHeroesAt);

            var nearestRedPointToTarget = GameGrid.RedPoints.OrderBy(p => p.DistanceSq(target)).FirstOrDefault();
            var nearestLinePoint        = linesPointsList.OrderBy(p => p.DistanceSq(nearestRedPointToTarget)).FirstOrDefault();

            heroesIndex = attackLines.FindIndex(u => (u.Item1.X == nearestLinePoint.X && u.Item1.Y == nearestLinePoint.Y) || (u.Item2.X == nearestLinePoint.X && u.Item2.Y == nearestLinePoint.Y));

            var units  = Deploy.GetTroops();
            var heroes = units.Extract(x => x.IsHero);
            var cc     = units.ExtractOne(u => u.ElementType == DeployElementType.ClanTroops);
            var spells = units.Extract(u => u.ElementType == DeployElementType.Spell);

            units.OrderForDeploy();

            // Set first attack line
            // Start from the next line to user defined to end with user defined line
            var line  = attackLines.NextOf(attackLines[heroesIndex]);
            var index = attackLines.FindIndex(u => u.Item1.X == line.Item1.X && u.Item1.Y == line.Item1.Y);

            Log.Info($"{AttackName} {Version} starts");
            // Start troops deployment on four sides.
            for (var i = 4; i >= 1; i--)
            {
                foreach (var unit in units)
                {
                    if (unit?.Count > 0)
                    {
                        var count   = unit.Count / i;
                        var fingers = count % 4 <= 1 ? count : 4;
                        foreach (var t in Deploy.AlongLine(unit, line.Item1, line.Item2, count, fingers, 0, waveDelay))
                        {
                            yield return(t);
                        }
                    }
                }
                if (i != 1)
                {
                    line  = attackLines.NextOf(attackLines[index]);
                    index = attackLines.FindIndex(u => u.Item1.X == line.Item1.X && u.Item1.Y == line.Item1.Y);
                }
            }

            if (cc?.Count > 0)
            {
                Log.Info($"{AttackName} Deploy Clan Castle troops");
                foreach (var t in Deploy.AlongLine(cc, line.Item1, line.Item2, 1, 1, 0, waveDelay))
                {
                    yield return(t);
                }
            }

            if (heroes.Any())
            {
                Log.Info($"{AttackName} Deploy Heroes");
                foreach (var hero in heroes.Where(u => u.Count > 0))
                {
                    foreach (var t in Deploy.AlongLine(hero, line.Item1, line.Item2, 1, 1, 0, waveDelay))
                    {
                        yield return(t);
                    }
                }
                Deploy.WatchHeroes(heroes, 5000);
            }


            var minDEDrillLevel = GetCurrentSetting("Min Drill Level");

            // start smart zap
            if (GetCurrentSetting("Smart Zap Drills") == 1)
            {
                var waitBeforeSmartZap = GetCurrentSetting("Start Zap Drills After ?(sec)") * 1000;
                var minDEAmount        = GetCurrentSetting("Min Dark Elixir per Zap");


                yield return(waitBeforeSmartZap);

                foreach (var t in SmartZapping.SmartZap(minDEAmount, minDEDrillLevel, spells))
                {
                    yield return(t);
                }
            }

            // start Use EarthQuake spell on drills
            if (GetCurrentSetting("Use EarthQuake spell on drills") == 1)
            {
                foreach (var t in SmartZapping.UseEQOnDrills(minDEDrillLevel, spells))
                {
                    yield return(t);
                }
            }

            // end battle
            var endBattleTime = GetCurrentSetting("End Battle after zap ?(sec)");

            foreach (var t in SmartZapping.EndBattle(endBattleTime))
            {
                yield return(t);
            }
        }