/// <summary> /// Drop EQ spells on drills to get DE beacuse max EQ will gain 320 DE from max drill /// </summary> /// <param name="drillLevel">minmum drill level</param> /// <param name="spells">available spells in unitsbar</param> /// <returns>Drop EQ spells on drills</returns> public static IEnumerable <int> UseEQOnDrills(int drillLevel, List <DeployElement> spells) { var EQSpell = spells.Extract(u => u.Id == DeployId.Earthquake); var EQCount = EQSpell.Sum(u => u.Count); if (EQCount > 0) { Log.Info($"{SmartFourFingersDeploy.AttackName} start use EQ on drills"); var drills = DarkElixirDrill.Find(CacheBehavior.ForceScan, drillLevel); if (drills.Any()) { foreach (var d in drills) { var eq = EQSpell.FirstOrDefault()?.Count > 0 ? EQSpell.FirstOrDefault() : EQSpell.LastOrDefault(); if (eq.Count > 0) { foreach (var t in Deploy.AtPoint(eq, d.Location.GetCenter())) { yield return(t); } } } } else { Log.Warning($"{SmartFourFingersDeploy.AttackName} no Drills found to use EQ on !!"); } } else { Log.Warning($"{SmartFourFingersDeploy.AttackName} no EarthQuake spells found to use on drills"); } }
public static void CalculateTargets() { collectors = ElixirCollector.Find(); mines = GoldMine.Find(); drills = DarkElixirDrill.Find(); int collectorsCount = collectors != null?collectors.Count() : 0; int minesCount = mines != null?mines.Count() : 0; int drillsCount = drills != null?drills.Count() : 0; // Set total count of targets SmartFourFingersDeploy.TotalTargetsCount = collectorsCount + minesCount + drillsCount; // four corners var top = new PointFT((float)GameGrid.DeployExtents.MaxX + 1, GameGrid.DeployExtents.MaxY + 4); var right = new PointFT((float)GameGrid.DeployExtents.MaxX + 1, GameGrid.DeployExtents.MinY - 4); var bottom = new PointFT((float)GameGrid.DeployExtents.MinX - 1, GameGrid.DeployExtents.MinY - 4); var left = new PointFT((float)GameGrid.DeployExtents.MinX - 1, GameGrid.DeployExtents.MaxY + 4); SetCore(); var corners = new List <Tuple <PointFT, PointFT> > { new Tuple <PointFT, PointFT>(top, right), new Tuple <PointFT, PointFT>(bottom, right), new Tuple <PointFT, PointFT>(bottom, left), new Tuple <PointFT, PointFT>(top, left) }; // loop throw the 4 sides and count targets on each side var targetsAtLine = new List <int>(); foreach (var l in corners) { var colCount = collectors.Where(t => t.Location.GetCenter(). IsInTri(SmartFourFingersDeploy.Core, l.Item1, l.Item2))?.Count() ?? 0; var minCount = mines.Where(t => t.Location.GetCenter(). IsInTri(SmartFourFingersDeploy.Core, l.Item1, l.Item2))?.Count() ?? 0; var drillCount = drills.Where(t => t.Location.GetCenter(). IsInTri(SmartFourFingersDeploy.Core, l.Item1, l.Item2))?.Count() ?? 0; var total = colCount + minCount + drillCount; targetsAtLine.Add(total); } SmartFourFingersDeploy.TargetsAtLine = targetsAtLine; }
public static Target[] GenerateTargets(float minimumDistance, bool ignoreGold, bool ignoreElixir, CacheBehavior behavior = CacheBehavior.Default) { // Find all Collectors & storages just sitting around... List <Building> buildings = new List <Building>(); if (!ignoreGold) { //User has Gold min set to ZERO - which means Dont include Gold Targets buildings.AddRange(GoldMine.Find(behavior)); buildings.AddRange(GoldStorage.Find(behavior)); } if (!ignoreElixir) { //User has Elixir min set to ZERO - which means Dont include Elixir Targets buildings.AddRange(ElixirCollector.Find(behavior)); buildings.AddRange(ElixirStorage.Find(behavior)); } //We always includ DarkElixir - Because who doesnt love dark Elixir? buildings.AddRange(DarkElixirDrill.Find(behavior)); buildings.AddRange(DarkElixirStorage.Find(behavior)); List <Target> targetList = new List <Target>(); foreach (Building building in buildings) { Target current = new Target(); current.TargetBuilding = building; current.Center = building.Location.GetCenter(); current.NearestRedLine = GameGrid.RedPoints.OrderBy(p => p.DistanceSq(current.Center)).First(); current.CenterToRedline = current.Center.DistanceSq(current.NearestRedLine); Log.Debug($"[Berts Algorithms] DistanceSq from {current.Name} to red point: {current.CenterToRedline.ToString("F1")}"); if (current.CenterToRedline < minimumDistance) //Compare distance to Redline to the Minimum acceptable distance Passed in { current.DeployGrunts = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _gruntDeployDistanceFromRedline); //Barbs & Goblins current.DeployRanged = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _rangedDeployDistanceFromRedline); //Archers & Minions targetList.Add(current); } } Log.Debug($"[Berts Algorithms] Found {targetList.Count} deploy points"); return(targetList.ToArray()); }
/// <summary> /// Search for drills and store the heighest amount of drills /// </summary> /// <param name="drillLevel">minimum drill level</param> /// <returns></returns> static IEnumerable <int> GetDrills(int drillLevel) { Log.Info($"[Smart Zap] looking for dark elixir drills ..."); availableDrills = DarkElixirDrill.Find(CacheBehavior.ForceScan, drillLevel); for (var i = 1; i <= 5; i++) { yield return(1000); var reCountDrills = DarkElixirDrill.Find(CacheBehavior.ForceScan, drillLevel); if (reCountDrills.Count() > availableDrills.Count()) { availableDrills = reCountDrills; } } Log.Info($"[Smart Zap] found {availableDrills.Count()} drills"); }
private void GenerateDeployPointsFromMinesToMilk(CacheBehavior behavior = CacheBehavior.Default) { // Find all mines List <Building> mines = new List <Building>(); TownHall th = TownHall.Find(); if (th != null) { mines.Add(th); } if (!resourcesFull.HasFlag(ResourcesFull.Gold)) { mines.AddRange(GoldMine.Find(behavior)); } if (!resourcesFull.HasFlag(ResourcesFull.Elixir)) { mines.AddRange(ElixirCollector.Find(behavior)); } if (!resourcesFull.HasFlag(ResourcesFull.Delixir)) { mines.AddRange(DarkElixirDrill.Find(behavior)); } List <PointFT> resultPoints = new List <PointFT>(); foreach (Building mine in mines) { PointFT center = mine.Location.GetCenter(); PointFT closest = GameGrid.RedPoints.OrderBy(p => p.DistanceSq(center)).First(); float distanceSq = center.DistanceSq(closest); Log.Debug("DistanceSq from " + mine.GetType().Name + " to red point: " + distanceSq.ToString("F1")); if (distanceSq < 9) // 3 tiles (squared = 9) means there is no wall or building between us and the collector { Log.Debug("Adding deploy point"); PointFT awayFromRedLine = closest.AwayFrom(center, 0.5f); resultPoints.Add(awayFromRedLine); } } Log.Debug("Found " + resultPoints.Count + " deploy points"); deployPoints = resultPoints.ToArray(); }
static IEnumerable <int> GetDestroyedDrills(PointFT point) { isDestroyed = false; Log.Info($"[Smart Zap] Check if this drill is destroyed ..."); var drills = DarkElixirDrill.Find(CacheBehavior.ForceScan).Where(d => d.Location.GetCenter().DistanceSq(point) <= 1); for (var i = 1; i <= 4; i++) { yield return(1000); var reCountDrills = DarkElixirDrill.Find(CacheBehavior.ForceScan).Where(d => d.Location.GetCenter().DistanceSq(point) <= 1); if (reCountDrills.Count() > drills.Count()) { drills = reCountDrills; } } if (drills.Count() == 0) { isDestroyed = true; Log.Info($"[Smart Zap] the drill was destroyed !!"); } }
/// <summary> /// Check to see how many collector and mine near to the redline by user defined distance /// </summary> /// <param name="userDistance">Minimum distance for exposed colloctors and mines</param> /// <param name="minCollectors">minimum exposed collectors</param> /// <param name="minMines">minimum exposed mines</param> /// <param name="AttackName">Attack name for logs and debugging</param> /// <param name="debug">debug mode in advanced settings</param> /// <returns>true if matches user defined min collectores and mines</returns> public static bool IsBaseMinCollectorsAndMinesOutside(int userDistance, int minCollectors, int minMines, string AttackName, int debug) { var distance = userDistance * userDistance; var redPoints = GameGrid.RedPoints.Where( point => !(point.X > 18 && point.Y > 18 || point.X > 18 && point.Y < -18 || point.X < -18 && point.Y > 18 || point.X < -18 && point.Y < -18)); collectors = ElixirCollector.Find().Where(c => c.Location.GetCenter() .DistanceSq(redPoints.OrderBy(p => p.DistanceSq(c.Location.GetCenter())) .FirstOrDefault()) <= distance); mines = GoldMine.Find().Where(c => c.Location.GetCenter() .DistanceSq(redPoints.OrderBy(p => p.DistanceSq(c.Location.GetCenter())) .FirstOrDefault()) <= distance); drills = DarkElixirDrill.Find().Where(c => c.Location.GetCenter() .DistanceSq(redPoints.OrderBy(p => p.DistanceSq(c.Location.GetCenter())) .FirstOrDefault()) <= distance); int collectorsCount = collectors != null?collectors.Count() : 0; int minesCount = mines != null?mines.Count() : 0; int drillsCount = drills != null?drills.Count() : 0; // Set total count of targets SmartFourFingersDeploy.TotalTargetsCount = collectorsCount + minesCount + drillsCount; // four corners var top = new PointFT((float)GameGrid.DeployExtents.MaxX + 1, GameGrid.DeployExtents.MaxY + 4); var right = new PointFT((float)GameGrid.DeployExtents.MaxX + 1, GameGrid.DeployExtents.MinY - 4); var bottom = new PointFT((float)GameGrid.DeployExtents.MinX - 1, GameGrid.DeployExtents.MinY - 4); var left = new PointFT((float)GameGrid.DeployExtents.MinX - 1, GameGrid.DeployExtents.MaxY + 4); SetCore(); var corners = new List <Tuple <PointFT, PointFT> > { new Tuple <PointFT, PointFT>(top, right), new Tuple <PointFT, PointFT>(bottom, right), new Tuple <PointFT, PointFT>(bottom, left), new Tuple <PointFT, PointFT>(top, left) }; // loop throw the 4 sides and count targets on each side var targetsAtLine = new List <int>(); foreach (var l in corners) { var colCount = collectors.Where(t => t.Location.GetCenter(). IsInTri(SmartFourFingersDeploy.Core, l.Item1, l.Item2))?.Count() ?? 0; var minCount = mines.Where(t => t.Location.GetCenter(). IsInTri(SmartFourFingersDeploy.Core, l.Item1, l.Item2))?.Count() ?? 0; var drillCount = drills.Where(t => t.Location.GetCenter(). IsInTri(SmartFourFingersDeploy.Core, l.Item1, l.Item2))?.Count() ?? 0; var total = colCount + minCount + drillCount; targetsAtLine.Add(total); } SmartFourFingersDeploy.TargetsAtLine = targetsAtLine; var op = new Opponent(0); //if (!op.IsForcedAttack ) { Log.Info($"{AttackName} NO. of Colloctors & mines near from red line:"); Log.Info($"elixir colloctors is {collectorsCount}"); Log.Info($"gold mines is {minesCount}"); Log.Info($"----------------------------"); Log.Info($"sum of all is {collectorsCount + minesCount}"); if (debug == 1) { using (Bitmap bmp = Screenshot.Capture()) { using (Graphics g = Graphics.FromImage(bmp)) { foreach (var c in collectors) { var point = c.Location.GetCenter(); Visualize.Target(bmp, point, 30, Color.Purple); } foreach (var c in mines) { var point = c.Location.GetCenter(); Visualize.Target(bmp, point, 30, Color.Gold); } foreach (var c in drills) { var point = c.Location.GetCenter(); Visualize.Target(bmp, point, 30, Color.Black); } DrawLine(bmp, Color.Red, SmartFourFingersDeploy.Core, top); DrawLine(bmp, Color.Red, SmartFourFingersDeploy.Core, right); DrawLine(bmp, Color.Red, SmartFourFingersDeploy.Core, bottom); DrawLine(bmp, Color.Red, SmartFourFingersDeploy.Core, left); } var d = DateTime.UtcNow; Screenshot.Save(bmp, "Collectors and Mines {d.Year}-{d.Month}-{d.Day} {d.Hour}-{d.Minute}-{d.Second}-{d.Millisecond}"); } } } if (collectorsCount >= minCollectors && minesCount >= minMines) { return(true); } else { Log.Warning($"{AttackName} this base doesn't meets Collocetors & Mines requirements"); return(false); } }
IEnumerable <int> DeployLeftoverSpells() { var lightningSpells = deployElements.FirstOrDefault(u => u.ElementType == DeployElementType.Spell && u.Id == DeployId.Lightning); List <DeployElement> earthquakeSpells = deployElements.Where(u => u.ElementType == DeployElementType.Spell && u.Id == DeployId.Earthquake).ToList(); List <DeployElement> skeletonSpells = deployElements.Where(u => u.ElementType == DeployElementType.Spell && u.Id == DeployId.Skeleton).ToList(); List <DeployElement> leftoverSpells = new List <DeployElement>(); //To Prevent errors, perform a recount on all these. leftoverSpells.RecountAndAddIfAny(skeletonSpells); leftoverSpells.RecountAndAddIfAny(earthquakeSpells); leftoverSpells.RecountAndAddIfAny(lightningSpells); //Now if any Skeleton Spells exist, drop them ALL on the last air-D to Distract/Destroy. if (leftoverSpells.Count > 0) { yield return(Rand.Int(4000, 6000)); // pause a while longer... Dragons should be getting close to this one now... var adToDistract = 0; if (zapped1) { adToDistract = 1; } if (zapped2) { adToDistract = 2; } PointFT dropPoint = new PointFT(); string locationDesc = string.Empty; if (airDefenses.Length < adToDistract + 1) { //Only two Air Defenses were found? No Third to use spells on... drop them on A DE Collector. //Put them on any Elixir Collector still up. var deDrill = DarkElixirDrill.Find(CacheBehavior.ForceScan); if (deDrill.Any()) { dropPoint = deDrill[0].Location.GetCenter(); locationDesc = "Dark Elixir Drill"; } else { //Give up and just drop them in the middle of the map to get rid of them. dropPoint = HumanLikeAlgorithms.Origin; locationDesc = "Center of map - (no other air Defenses or DE Drills Could be found)"; } } else { //There were aditional air defenses found... drop them on the next one. dropPoint = airDefenses[adToDistract].Location.GetCenter(); locationDesc = $"Air Defense #{adToDistract + 1}"; } foreach (var spell in leftoverSpells) { Log.Info($"{Tag} Deploying {spell.Count} left over {spell.PrettyName} Spell(s) to {locationDesc}..."); foreach (var t in Deploy.AtPoint(spell, dropPoint, spell.Count)) { yield return(t); } } } else { Log.Info($"{Tag} All Spells Successfully Deployed..."); } }
public static Target[] GenerateTargets(string algorithmName, float minimumDistance, bool ignoreGold, bool ignoreElixir, string AttackId, out double avgFillstate, out double avgCollectorLvl, CacheBehavior behavior = CacheBehavior.Default, bool outputDebugImage = false, bool activeBase = false) { // Find all Collectors & storages just sitting around... List <Building> buildings = new List <Building>(); //Get a list of Gold Mines. List <GoldMine> goldMines = new List <GoldMine>(); goldMines.AddRange(GoldMine.Find(behavior)); //Get a list of Elixir Collectors. List <ElixirCollector> elixirCollectors = new List <ElixirCollector>(); elixirCollectors.AddRange(ElixirCollector.Find(behavior)); avgFillstate = 0; //Get the Average Fill State of all the Elixir Collectors - From this we can tell what percentage of the loot is in Collectors. if (elixirCollectors.Count > 1) { avgFillstate = elixirCollectors.Average(c => c.FillState); } //Log the Average Fill State of aLL elixir Collectors... Log.Debug($"[Berts Algorithms] - Fill State Average of ALL Elixir Collectors: {(avgFillstate * 10).ToString("F1")}"); if (!ignoreGold) { buildings.AddRange(goldMines); if (activeBase) { buildings.AddRange(GoldStorage.Find(behavior)); } } if (!ignoreElixir) { buildings.AddRange(elixirCollectors); if (activeBase) { buildings.AddRange(ElixirStorage.Find(behavior)); } } //Determine the Average Collector Level. avgCollectorLvl = 0; if (ignoreGold && !ignoreElixir) { if (elixirCollectors.Count(c => c.Level.HasValue) > 1) { avgCollectorLvl = elixirCollectors.Where(c => c.Level.HasValue).Average(c => (int)c.Level); } } else if (ignoreElixir && !ignoreGold) { if (goldMines.Count(c => c.Level.HasValue) > 1) { avgCollectorLvl = goldMines.Where(c => c.Level.HasValue).Average(c => (int)c.Level); } } else if (!ignoreElixir && !ignoreGold) { if (buildings.Count(c => c.Level.HasValue) > 1) { avgCollectorLvl = buildings.Where(c => c.Level.HasValue).Average(c => (int)c.Level); } } //We always includ DarkElixir - Because who doesnt love dark Elixir? buildings.AddRange(DarkElixirDrill.Find(behavior)); if (activeBase) { buildings.AddRange(DarkElixirStorage.Find(behavior)); } List <Target> targetList = new List <Target>(); foreach (Building building in buildings) { Target current = new Target(); current.TargetBuilding = building; current.Center = building.Location.GetCenter(); current.Edge = Origin.PointOnLineAwayFromEnd(current.Center, 1.0f); current.NearestRedLine = AllPoints.OrderBy(p => p.DistanceSq(current.Edge)).First(); current.CenterToRedline = current.Center.DistanceSq(current.NearestRedLine); if (current.CenterToRedline < minimumDistance) //Compare distance to Redline to the Minimum acceptable distance Passed in { Log.Debug($"[Berts Algorithms] Distance from {current.Name} to red point: {Math.Sqrt(current.CenterToRedline).ToString("F1")}, Min Distance: {Math.Sqrt(minimumDistance).ToString("F1")} - GO!"); current.DeployGrunts = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _gruntDeployDistanceFromRedline); //Barbs & Goblins current.DeployRanged = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _rangedDeployDistanceFromRedline); //Archers & Minions targetList.Add(current); } else { Log.Debug($"[Berts Algorithms] Distance from {current.Name} to red point: {Math.Sqrt(current.CenterToRedline).ToString("F1")}, Min Distance: {Math.Sqrt(minimumDistance).ToString("F1")} - TOO FAR!"); } } if (outputDebugImage) { OutputDebugImage(algorithmName, buildings, targetList, AttackId); } return(targetList.ToArray()); }
public override IEnumerable <int> AttackRoutine() { Log.Info("[Deploy] Deploy start"); // Get all the units available Log.Debug("Scanning troops"); var deployElements = Deploy.GetTroops(); var spells = deployElements.Extract(DeployElementType.Spell); var tankUnits = deployElements.Extract(AttackType.Tank).ToArray(); var attackUnits = deployElements.Extract(AttackType.Damage).ToArray(); var healUnits = deployElements.Extract(AttackType.Heal).ToArray(); var waveCounter = 1; // Get starting resources LootResources preLoot = Opponent.GetAvailableLoot(); if (preLoot == null) { Log.Error("[Deploy] Milking deploy could not read available starting loot"); Attack.Surrender(); yield break; } Log.Debug($"[Deploy] Pre-attack resources - G: {preLoot.Gold}, E: {preLoot.Elixir}, DE: {preLoot.DarkElixir}"); // Make sure we wait at least 15 seconds in this attack, in case we snipe TH // Loop until surrender conditions are met while (true) { // Get deploy points for each mine that is on the outside of the base //resourcesFull = GetResourcesState(); GenerateDeployPointsFromMinesToMilk(CacheBehavior.CheckForDestroyed); if (deployPoints == null || deployPoints.Length < 1) { Log.Debug("Surrendering because deployPoints = " + deployPoints?.Length); break; } if (tankUnits.Any()) { foreach (var t in Deploy.AtPoints(tankUnits, deployPoints)) { yield return(t); } yield return(1000); } if (attackUnits.Any()) { foreach (var t in Deploy.AtPoints(attackUnits, deployPoints, 6)) { yield return(t); } yield return(1000); } if (healUnits.Any()) { foreach (var t in Deploy.AtPoints(healUnits, deployPoints)) { yield return(t); } yield return(1000); } // Wait for the wave to finish Log.Info($"[Deploy] Wave {waveCounter} Deployed. Waiting to finish..."); foreach (var t in Attack.WaitForNoResourceChange()) { yield return(t); } // Get starting resources, cache needs to be false to force a new check LootResources postLoot = Opponent.GetAvailableLoot(false); if (postLoot == null) { Log.Warning("[Deploy] Milking Deploy could not read available loot this wave"); } else { Log.Debug($"[Deploy] Wave {waveCounter} resources - G: {postLoot.Gold}, E: {postLoot.Elixir}, DE: {postLoot.DarkElixir}"); int newGold = preLoot.Gold - postLoot.Gold; int newElixir = preLoot.Elixir - postLoot.Elixir; int newDark = preLoot.DarkElixir - postLoot.DarkElixir; Log.Debug($"[Deploy] Wave {waveCounter} resource diff - G: {newGold}, E: {newElixir}, DE: {newDark}, points: {deployPoints.Length}"); if (newGold + newElixir < 5000 * deployPoints.Length) { Log.Debug("Surrendering because gained resources isn't enough"); break; } preLoot = postLoot; } waveCounter++; } // Wait for the wave to finish Log.Info("[Deploy] Deploy done. Waiting to finish..."); foreach (var t in Attack.WaitForNoResourceChange(10)) { yield return(t); } if (spells.Any(u => u.Id == DeployId.Lightning) && DarkElixirDrill.Find(CacheBehavior.ForceScan, 4).Length > 0) { Log.Debug("Level 4 or greater drills found, waiting for attack to finish."); foreach (var t in Attack.WaitForNoResourceChange(5)) { yield return(t); } foreach (var t in ZapDarkElixirDrills()) { yield return(t); } } Attack.Surrender(); }
/// <summary> /// use lighting on drill in smart way to save elixir usage /// </summary> /// <param name="deAmount">minimum dark elixir to gain per zap (user defined)</param> /// <param name="drillLevel">minimum drill level to zap (user defined)</param> /// <param name="spells">available spells in unitsbar</param> /// <returns>deploy lighting on drills</returns> public static IEnumerable <int> SmartZap(int deAmount, int drillLevel, List <DeployElement> spells) { Log.Info($"{SmartFourFingersDeploy.AttackName} Smart Zap Drills module"); bool zapDrill = true; var zap = spells.Extract(u => u.Id == DeployId.Lightning); var zapCount = zap?.Sum(u => u.Count); if (zapCount <= 0) { Log.Warning($"{SmartFourFingersDeploy.AttackName} Smart Zap Drills No lighting Spells found for Smart Zap"); zapDrill = false; } var drills = DarkElixirDrill.Find(CacheBehavior.ForceScan, drillLevel); if (drills == null) { Log.Warning("{SmartFourFingersDeploy.AttackName} Smart Zap Drills didn't found Dark Drills matches the requirements"); zapDrill = false; } var opponent = new Opponent(0); var availableDE = opponent.GetAvailableLoot(false).DarkElixir; var availableDEAfterZap = 0; if (availableDE < deAmount) { Log.Warning($"{SmartFourFingersDeploy.AttackName} Smart Zap Drills this base only has {availableDE} DE .. it doesn't match the requirements ({deAmount})"); zapDrill = false; } if (zapDrill) { Log.Info($"{SmartFourFingersDeploy.AttackName} Smart Zap Drills found {zap.Sum(u => u.Count)} Lighting Spell(s)"); Log.Info($"{SmartFourFingersDeploy.AttackName} Smart Zap Drills found {drills.Count()} Dark drill(s)"); // Zap each drill only twice beacuse (level 4 lighting will got 90% DE from max drill level) for (var j = 1; j <= 2; j++) { for (var i = 0; i < drills.Count(); i++) { if (drills[i] != null && zapCount > 0) { // Get location of each drill var DP = drills[i].Location.GetCenter(); // If we have our own lighting we will drop it first .. if we don't, use CC "beacuse IsClanSpell not working if only CC spell" var zp = zap.FirstOrDefault().Count > 0 ? zap.FirstOrDefault() : zap.LastOrDefault(); foreach (var t in Deploy.AtPoint(zp, DP, 1)) { yield return(t); } yield return(7000); zapCount--; if (zapCount > 0) { availableDEAfterZap = opponent.GetAvailableLoot(false).DarkElixir; if (availableDE - availableDEAfterZap < deAmount) { Log.Warning($"{SmartFourFingersDeploy.AttackName} Smart Zap Drills only {availableDE - availableDEAfterZap} DE from this drill .. you set it to {deAmount} .. will not zap it again "); drills[i] = null; } else { Log.Info($"{SmartFourFingersDeploy.AttackName} Smart Zap Drills gain {availableDE - availableDEAfterZap} DE from this drill"); availableDE = availableDEAfterZap; } } var remDrills = DarkElixirDrill.Find(CacheBehavior.ForceScan, drillLevel); if (!remDrills.Any()) { break; } } if (zapCount <= 0) { break; } } yield return(7000); var standingDrills = DarkElixirDrill.Find(CacheBehavior.ForceScan, drillLevel); if (!standingDrills.Any()) { Log.Warning($"{SmartFourFingersDeploy.AttackName} no drills to zap"); break; } } } }
public static Target[] GenerateTargets(float minimumDistance, bool ignoreGold, bool ignoreElixir, CacheBehavior behavior = CacheBehavior.Default, bool outputDebugImage = false) { // Find all Collectors & storages just sitting around... List <Building> buildings = new List <Building>(); if (!ignoreGold) { //User has Gold min set to ZERO - which means Dont include Gold Targets buildings.AddRange(GoldMine.Find(behavior)); buildings.AddRange(GoldStorage.Find(behavior)); } if (!ignoreElixir) { //User has Elixir min set to ZERO - which means Dont include Elixir Targets buildings.AddRange(ElixirCollector.Find(behavior)); buildings.AddRange(ElixirStorage.Find(behavior)); } //We always includ DarkElixir - Because who doesnt love dark Elixir? buildings.AddRange(DarkElixirDrill.Find(behavior)); buildings.AddRange(DarkElixirStorage.Find(behavior)); List <Target> targetList = new List <Target>(); foreach (Building building in buildings) { Target current = new Target(); current.TargetBuilding = building; current.Center = building.Location.GetCenter(); current.NearestRedLine = GameGrid.RedPoints.OrderBy(p => p.DistanceSq(current.Center)).First(); current.CenterToRedline = current.Center.DistanceSq(current.NearestRedLine); Log.Debug($"[Berts Algorithms] DistanceSq from {current.Name} to red point: {current.CenterToRedline.ToString("F1")}"); if (current.CenterToRedline < minimumDistance) //Compare distance to Redline to the Minimum acceptable distance Passed in { current.DeployGrunts = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _gruntDeployDistanceFromRedline); //Barbs & Goblins current.DeployRanged = current.Center.PointOnLineAwayFromEnd(current.NearestRedLine, _rangedDeployDistanceFromRedline); //Archers & Minions targetList.Add(current); } } if (outputDebugImage) { var d = DateTime.UtcNow; var debugFileName = $"Human Barch {d.Year}-{d.Month}-{d.Day} {d.Hour}-{d.Minute}-{d.Second}-{d.Millisecond}"; //Get a screen Capture of all targets we found... using (Bitmap canvas = Screenshot.Capture()) { Screenshot.Save(canvas, $"{debugFileName}_1"); foreach (var building in buildings) { var color = Color.White; if (building.GetType() == typeof(ElixirCollector) || building.GetType() == typeof(ElixirStorage)) { color = Color.Violet; } if (building.GetType() == typeof(GoldMine) || building.GetType() == typeof(GoldStorage)) { color = Color.Gold; } if (building.GetType() == typeof(DarkElixirDrill) || building.GetType() == typeof(DarkElixirStorage)) { color = Color.Brown; } //Draw a target on each building. Visualize.Target(canvas, building.Location.GetCenter(), 40, color); } //Save the Image to the Debug Folder... Screenshot.Save(canvas, $"{debugFileName}_2"); } //Get a screen Capture of all targets we found... using (Bitmap canvas = Screenshot.Capture()) { foreach (var target in targetList) { var color = Color.White; if (target.TargetBuilding.GetType() == typeof(ElixirCollector) || target.TargetBuilding.GetType() == typeof(ElixirStorage)) { color = Color.Violet; } if (target.TargetBuilding.GetType() == typeof(GoldMine) || target.TargetBuilding.GetType() == typeof(GoldStorage)) { color = Color.Gold; } if (target.TargetBuilding.GetType() == typeof(DarkElixirDrill) || target.TargetBuilding.GetType() == typeof(DarkElixirStorage)) { color = Color.Brown; } //Draw a target on each building. Visualize.Target(canvas, target.TargetBuilding.Location.GetCenter(), 40, color); Visualize.Target(canvas, target.DeployGrunts, 20, color); Visualize.Target(canvas, target.DeployRanged, 20, color); } //Save the Image to the Debug Folder... Screenshot.Save(canvas, $"{debugFileName}_3"); } Log.Debug("[Berts Algorithms] Collector/Storage & Target Debug Images Saved!"); } Log.Debug($"[Berts Algorithms] Found {targetList.Count} deploy points"); return(targetList.ToArray()); }