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 static IEnumerable <int> GroundAttack(int customOrder)
        {
            DeploymentMethods.clanCastle  = AllInOnePushDeploy.deployElements.ExtractOne(u => u.ElementType == DeployElementType.ClanTroops);
            DeploymentMethods.eq          = AllInOnePushDeploy.deployElements.Extract(u => u.Id == DeployId.Earthquake);
            DeploymentMethods.rageSpell   = AllInOnePushDeploy.deployElements.Extract(u => u.Id == DeployId.Rage);
            DeploymentMethods.healSpell   = AllInOnePushDeploy.deployElements.Extract(u => u.Id == DeployId.Heal);
            DeploymentMethods.freezeSpell = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Freeze);
            DeploymentMethods.jumpSpell   = AllInOnePushDeploy.deployElements.Extract(u => u.Id == DeployId.Jump);
            DeploymentMethods.hasteSpell  = AllInOnePushDeploy.deployElements.Extract(u => u.Id == DeployId.Haste);
            DeploymentMethods.poison      = AllInOnePushDeploy.deployElements.Extract(u => u.Id == DeployId.Poison);
            //tanks
            DeploymentMethods.giant = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Giant);
            DeploymentMethods.golem = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Golem);
            //main troops
            DeploymentMethods.wallbreaker = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.WallBreaker);
            DeploymentMethods.bowler      = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Bowler);
            DeploymentMethods.witch       = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Witch);
            DeploymentMethods.healer      = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Healer);
            DeploymentMethods.wizard      = AllInOnePushDeploy.deployElements.ExtractOne(DeployId.Wizard);

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

            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);

            // Drop earthquake
            foreach (var t in DeploymentMethods.DropEQ())
            {
                yield return(t);
            }

            if (customOrder == 1)
            {
                foreach (var t in DeploymentMethods.DeployInCustomOrder(AllInOnePushDeploy.CustomOrderList))
                {
                    yield return(t);
                }
            }
            else
            {
                // Check if queen walk is active
                var QW = AllInOnePushDeploy.QWSettings == 1 && DeploymentMethods.queen?.Count > 0 && DeploymentMethods.healer?.Count >= AllInOnePushDeploy.HealerOnQWSettings ? true : false;
                if (QW)
                {
                    foreach (var s in DeploymentMethods.DeployFunnlling())
                    {
                        yield return(s);
                    }
                    foreach (var s in DeploymentMethods.DeployGolems())
                    {
                        yield return(s);
                    }
                }
                else
                {
                    foreach (var s in DeploymentMethods.DeployGolems())
                    {
                        yield return(s);
                    }
                    foreach (var s in DeploymentMethods.DeployFunnlling())
                    {
                        yield return(s);
                    }
                }
                foreach (var s in DeploymentMethods.DeployGiants())
                {
                    yield return(s);
                }
                foreach (var s in DeploymentMethods.DeployHeroes())
                {
                    yield return(s);
                }
                foreach (var s in DeploymentMethods.DeployWB())
                {
                    yield return(s);
                }
                foreach (var s in DeploymentMethods.DeployNormalTroops())
                {
                    yield return(s);
                }
            }

            // Screen Shots for spells if debug mode is on
            if (AllInOnePushDeploy.Debug)
            {
                AllInOnePushHelper.DebugEQpells();
                AllInOnePushHelper.DebugSpells();
            }

            // Deploy spells
            foreach (var s in DeploymentMethods.DeployJump())
            {
                yield return(s);
            }

            foreach (var s in DeploymentMethods.DeploySpell(DeploymentMethods.rageSpell, AllInOnePushDeploy.FirstRagePoint))
            {
                yield return(s);
            }

            yield return(2000);

            if (DeploymentMethods.hasteSpell.Sum(u => u.Count) > 0)
            {
                foreach (var s in DeploymentMethods.DeploySpell(DeploymentMethods.hasteSpell, AllInOnePushDeploy.FirstHealPoint))
                {
                    yield return(s);
                }
            }
            else
            {
                foreach (var s in DeploymentMethods.DeploySpell(DeploymentMethods.healSpell, AllInOnePushDeploy.FirstHealPoint))
                {
                    yield return(s);
                }
            }

            if (DeploymentMethods.poison?.Count > 0)
            {
                foreach (var s in DeploymentMethods.DeploySpell(DeploymentMethods.poison, AllInOnePushDeploy.FirstHealPoint))
                {
                    yield return(s);
                }
            }

            // 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();
                    }
                }
            }

            yield return(4000);

            // activate Grand Warden apility
            if (DeploymentMethods.isWarden)
            {
                DeploymentMethods.warden.Select();
                DeploymentMethods.warden.Select();
            }

            foreach (var s in DeploymentMethods.DeploySpell(DeploymentMethods.rageSpell, AllInOnePushDeploy.SecondRagePoint))
            {
                yield return(s);
            }

            foreach (var s in DeploymentMethods.DeploySpell(DeploymentMethods.healSpell, AllInOnePushDeploy.SecondRagePoint))
            {
                yield return(s);
            }

            yield return(1000);

            foreach (var s in DeploymentMethods.DeploySpell(DeploymentMethods.rageSpell, AllInOnePushDeploy.FirstHastePoint))
            {
                yield return(s);
            }

            foreach (var s in DeploymentMethods.DeploySpell(DeploymentMethods.hasteSpell, AllInOnePushDeploy.FirstHastePoint))
            {
                yield return(s);
            }



            // Start watching heroes
            if (DeploymentMethods.watchHeroes == true)
            {
                Deploy.WatchHeroes(DeploymentMethods.heroes);
            }

            if (DeploymentMethods.watchQueen == true)
            {
                Deploy.WatchHeroes(new List <DeployElement> {
                    DeploymentMethods.queen
                });
            }
        }
        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);
            }
        }
        void CreateDebugImages()
        {
            List <InfernoTower>  infernos       = InfernoTower.Find(CacheBehavior.Default).ToList();
            List <WizardTower>   wizTowers      = WizardTower.Find(CacheBehavior.Default).ToList();
            List <ArcherTower>   archerTowers   = ArcherTower.Find(CacheBehavior.Default).ToList();
            List <ElixirStorage> elixirStorages = ElixirStorage.Find(CacheBehavior.Default).ToList();
            EagleArtillery       eagle          = EagleArtillery.Find(CacheBehavior.Default);

            var d             = DateTime.UtcNow;
            var debugFileName = $"Dragon Deploy {d.Year}-{d.Month}-{d.Day} {d.Hour}-{d.Minute}-{d.Second}-{d.Millisecond}";

            using (Bitmap canvas = Screenshot.Capture())
            {
                Screenshot.Save(canvas, $"{debugFileName}_1");

                //Draw some stuff on it.
                Visualize.Axes(canvas);
                Visualize.Grid(canvas, redZone: true);
                Visualize.Target(canvas, mainTarget.Center, 40, Color.Red);
                Visualize.Target(canvas, deFunnelPoints[0], 40, Color.White);
                Visualize.Target(canvas, deFunnelPoints[1], 40, Color.White);
                Visualize.Target(canvas, balloonFunnelPoints[0], 40, Color.Pink);
                Visualize.Target(canvas, balloonFunnelPoints[1], 40, Color.Pink);

                for (int i = 0; i < infernos.Count(); i++)
                {
                    Visualize.Target(canvas, infernos.ElementAt(i).Location.GetCenter(), 30, Color.Orange);
                }

                for (int i = 0; i < airDefenses.Count(); i++)
                {
                    Visualize.Target(canvas, airDefenses.ElementAt(i).Location.GetCenter(), 30, Color.Cyan);
                }

                for (int i = 0; i < wizTowers.Count(); i++)
                {
                    Visualize.Target(canvas, wizTowers.ElementAt(i).Location.GetCenter(), 30, Color.Purple);
                }

                for (int i = 0; i < archerTowers.Count(); i++)
                {
                    Visualize.Target(canvas, archerTowers.ElementAt(i).Location.GetCenter(), 30, Color.RosyBrown);
                }

                if (eagle != null)
                {
                    Visualize.Target(canvas, eagle.Location.GetCenter(), 30, Color.YellowGreen);
                }

                Visualize.Target(canvas, mainTarget.DeployGrunts, 40, Color.Beige);

                Screenshot.Save(canvas, $"{debugFileName}_2");
            }

            //Write a text file that goes with all images that shows what is in the image.
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < airDefenses.Count(); i++)
            {
                sb.AppendLine($"Air Defense {i + 1} - Level:{airDefenses.ElementAt(i).Level}");
            }

            for (int i = 0; i < infernos.Count(); i++)
            {
                sb.AppendLine($"Inferno Tower {i + 1} - Level:{infernos.ElementAt(i).Level}");
            }

            for (int i = 0; i < wizTowers.Count(); i++)
            {
                sb.AppendLine($"Wizard Tower {i + 1} - Level:{wizTowers.ElementAt(i).Level}");
            }

            for (int i = 0; i < archerTowers.Count(); i++)
            {
                sb.AppendLine($"Archer Tower {i + 1} - Level:{archerTowers.ElementAt(i).Level}");
            }

            if (eagle != null)
            {
                sb.AppendLine($"Eagle Artillery 1 - Level:{eagle.Level}");
            }

            //System.IO.File.WriteAllText($@"C:\RaccoonBot\Debug Screenshots\{debugFileName}_3.txt", sb.ToString());

            Log.Info($"{Tag} Deploy Debug Image Saved!");
        }
        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();
            }
        }