public override double ShouldAccept() { if (Opponent.MeetsRequirements(BaseRequirements.All)) { if (!SmartAirDeployHelpers.AllAirDefensesFound(TownHall.Find() == null ? TownHallLimits.Limits.Length - 1 : TownHall.Find().Level)) { return(0); } return(1); } return(0); }
PointFT[] CalculateRageDeployPoints(DeployElement rageSpell, PointFT[] potentialDeployPoints, List <VisualObject> visuals) { if (rageSpell == null) { return(null); } // PotentialdeployPoints[] is already ordered by angle ascending var minAnglePoint = potentialDeployPoints.First(); var maxAnglePoint = potentialDeployPoints.Last(); var line = new Line(minAnglePoint, maxAnglePoint); visuals.Add(new LinesObject("RageSpellDeployPointLine", Color.FromArgb(200, Color.White), new[] { line })); // rageSpell.Count +1 because chopLine would start on the very first point of the line otherwise var spellDeployPoints = SmartAirDeployHelpers.ChopLine(line.Start, line.End, rageSpell.Count + 1); //visuals.Add(new PointsObject("BabyDragon DeployPoints", Color.FromArgb(250, Color.Tomato), spellDeployPoints, 3)); var rageSpellDeployPoints = spellDeployPoints.Skip(1).Select(x => new PointFT((int)x.X, (int)x.Y)).ToArray(); visuals.Add(new PointsObject("BabyDragon DeployPoints", Color.FromArgb(140, Color.Purple), rageSpellDeployPoints, 10)); return(rageSpellDeployPoints); }
/// <summary> /// Finds AirDefenses which can and should be ZapQuaked. /// The length of the list is dependent on the available spells (2 lightnings, 1 earthquake = 1 AirDefense target) /// </summary> /// <param name="earthQuakeSpells">The available earthquake spells</param> /// <param name="lightningSpells">The available lightning spells</param> /// <returns>A list of AirDefenses which can and should be ZapQuaked</returns> List <AirDefense> FindAirDefenseTargets(DeployElement earthQuakeSpells, DeployElement lightningSpells, List <VisualObject> visuals) { var lightningsToDestroyAirDefenses = (int)Math.Floor((double)lightningSpells.Count / 2); var destroyableAirDefenses = Math.Min(lightningsToDestroyAirDefenses, earthQuakeSpells.Count); Log.Info($"[LavaLoon] We've got {lightningSpells.Count} Lightning Spells and {earthQuakeSpells.Count}, which is enough to destroy {destroyableAirDefenses} AirDefenses."); var allAirDefenses = AirDefense.Find(); try { var targetsToFindCount = Math.Min(destroyableAirDefenses, allAirDefenses.Count()); if (targetsToFindCount == 0) { Log.Error("[LavaLoon] FindAirDefenseTargets has been called even though it shouldn't have been called!"); return(null); } // If we need to find 2 or more AirDefense targets we want to find the closest AirDefenses if (targetsToFindCount > 1) { var airDefensesOrderedByDeployPointDistance = allAirDefenses.OrderByDescending(x => SmartAirDeployHelpers.DistanceSqToClosestDeploypoint(x.Location.GetCenter())); // furthestAirDefense = The airdefense which is the furthest away from deployzone var furthestAirDefense = airDefensesOrderedByDeployPointDistance.First(); var remainingAirDefenses = airDefensesOrderedByDeployPointDistance.Skip(1).ToList(); var orderedList = OrderByDistance(furthestAirDefense, remainingAirDefenses).Take(targetsToFindCount).ToList(); // Add visuals var orderedListCenters = orderedList.Select(x => x.Location.GetCenter()); visuals.Add(new PointsObject("AirDefenseTargets", Color.FromArgb(200, Color.CornflowerBlue), orderedListCenters)); return(orderedList); } var targetList = allAirDefenses.Take(1).ToList(); // Add visuals var targetListCenters = targetList.Select(x => x.Location.GetCenter()); visuals.Add(new PointsObject("AirDefenseTargets", Color.FromArgb(200, Color.CornflowerBlue), targetListCenters)); return(targetList); } catch (Exception ex) { Log.Error("[LavaLoon] Exception occured during 'ZapQuakeAirDefenses'. More information can be found inside of the debug log."); Log.Debug("[LavaLoon] Exception details: " + ex); return(null); } }
/// <summary> /// Prepares some stuff (baseBorder, orth from AirDefenses, intersectionPoint) which helps to calculate the actual deploypoints. /// </summary> /// <param name="airDefenses">Found AirDefenses after possible ZapQuake</param> /// <param name="visuals">VisualObjects for drawing information (deploypoints, orth and so on) into bmp</param> /// <returns></returns> DeployCalculationInformation PrepareDeployCalculation(AirDefense[] airDefenses, List <VisualObject> visuals) { var maxRedPointX = GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Max(point => point.X) + 1 ?? GameGrid.RedZoneExtents.MaxX; var minRedPointX = GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Min(point => point.X) - 1 ?? GameGrid.RedZoneExtents.MinX; var maxRedPointY = GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Max(point => point.Y) + 1 ?? GameGrid.RedZoneExtents.MaxY; var minRedPointY = GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Min(point => point.Y) - 1 ?? GameGrid.RedZoneExtents.MinY; // border around the base var baseBorder = new List <RectangleT>(); baseBorder.Add(new RectangleT((int)minRedPointX, (int)maxRedPointY, (int)(maxRedPointX - minRedPointX), (int)(minRedPointY - maxRedPointY))); // Add baseborder as visual visuals.Add(new RectangleObject("BaseBorder", Color.FromArgb(100, Color.Maroon), baseBorder, new Pen(Color.Maroon))); // Find nearest deploy points for two airdefenses var airDefensesOrderedByDeployPointDistance = airDefenses.OrderByDescending(x => SmartAirDeployHelpers.DistanceSqToClosestDeploypoint(x.Location.GetCenter())); var closestAirDefense = airDefensesOrderedByDeployPointDistance.FirstOrDefault(); var remainingAirDefenses = airDefensesOrderedByDeployPointDistance.Skip(1).ToList(); var orderedList = OrderByDistance(closestAirDefense, remainingAirDefenses).Take(2).ToList(); PointF intersectionPointF; PointFT intersectionPointFt; // 1. convert all corners into vectors var left = new PointFT(minRedPointX, maxRedPointY).ToScreenAbsolute(); var top = new PointFT(maxRedPointX, maxRedPointY).ToScreenAbsolute(); var right = new PointFT(maxRedPointX, minRedPointY).ToScreenAbsolute(); var bottom = new PointFT(minRedPointX, minRedPointY).ToScreenAbsolute(); Vector vLeftPoint = new Vector(left.X, left.Y); Vector vTopPoint = new Vector(top.X, top.Y); Vector vRightPoint = new Vector(right.X, right.Y); Vector vBottomPoint = new Vector(bottom.X, bottom.Y); // 2. create the 4 combinations of the 4 points to get all 4 edges (topleft, topright, ...) var baseBorderSides = new List <Tuple <Vector, Vector> >(); baseBorderSides.Add(Tuple.Create(vTopPoint, vLeftPoint)); // Topleft baseBorderSides.Add(Tuple.Create(vTopPoint, vRightPoint)); // Topright baseBorderSides.Add(Tuple.Create(vLeftPoint, vBottomPoint)); // BottomLeft baseBorderSides.Add(Tuple.Create(vRightPoint, vBottomPoint)); // BottomRight if (orderedList?.Count() == 2) { var start = orderedList.First().Location.GetCenter(); var end = orderedList.Last().Location.GetCenter(); var airDefenseConnection = new Line(start, end); visuals.Add(new LinesObject("AirDefenseConnection", Color.FromArgb(180, Color.OrangeRed), new[] { airDefenseConnection })); Point screenStart = start.ToScreenAbsolute(); Point screenEnd = end.ToScreenAbsolute(); Vector vStart = new Vector(screenStart.X, screenStart.Y); Vector vEnd = new Vector(screenEnd.X, screenEnd.Y); Vector vStartEnd = vEnd - vStart; Vector vDir = vStartEnd; vDir.Normalize(); Vector vOrthDir = new Vector(vDir.Y, -vDir.X); Vector vOrthMidPoint = vStart + vStartEnd * 0.5; Point midPoint = new Point((int)vOrthMidPoint.X, (int)vOrthMidPoint.Y); // We have two lines (mid -> airDef1) and (mid -> airDef2) // We want to know what line points "away" from the townhall (center of the map) var mapCenterAbsolute = new PointFT(0f, 0f).ToScreenAbsolute(); Vector vMapCenter = new Vector(mapCenterAbsolute.X, mapCenterAbsolute.Y); Vector dirTest1 = vOrthMidPoint + vOrthDir * +0.1; Vector dirTest2 = vOrthMidPoint + vOrthDir * -0.1; Vector dirAwayFromCenter = (vMapCenter - dirTest1).LengthSquared < (vMapCenter - dirTest2).LengthSquared ? -vOrthDir : vOrthDir; Vector vAirDefOrthLineEnd = vOrthMidPoint + dirAwayFromCenter * 3000; Point airDefLineEndCorrect = new Point((int)vAirDefOrthLineEnd.X, (int)vAirDefOrthLineEnd.Y); var orthLine = new Line(new PointF((float)vOrthMidPoint.X, (float)vOrthMidPoint.Y), new PointF(airDefLineEndCorrect.X, airDefLineEndCorrect.Y)); visuals.Add(new LinesObject("AirDefenseOrth", new Pen(Color.OrangeRed, 3), new[] { orthLine })); // Now we want to find the intersection of our line, with the outer rectangle. // We know that our line starts inside the rect, and ends outside of it, that means there must be exactly one intersection point // 3. use those for the following intersection calculation: Vector vOrthLineStartPoint = vOrthMidPoint; Vector vOrthLineEndPoint = vAirDefOrthLineEnd; Vector vOrth = vOrthLineStartPoint + vOrthLineEndPoint; // 4. test this line for intersections against all 4 sides, only (and exactly) one of them will have an intersection Vector vInterSectionPoint = default(Vector); foreach (var side in baseBorderSides) { if (SmartAirDeployHelpers.LineSegementsIntersect(side.Item1, side.Item2, vOrthLineStartPoint, vOrthLineEndPoint, out vInterSectionPoint)) { break; } } intersectionPointF = new PointF((float)vInterSectionPoint.X, (float)vInterSectionPoint.Y); intersectionPointFt = new PointFT((int)intersectionPointF.X, (int)intersectionPointF.Y); } else if (orderedList?.Count == 1) { // It's not necessary to build an orth between two AirDefenses in that case, so just find the closest deploy point to the only left AirDefense var start = orderedList.First().Location.GetCenter(); var deployPointsOrderedByDistance = GameGrid.RedPoints.OrderBy(x => x.DistanceSq(start)); intersectionPointFt = deployPointsOrderedByDistance.First(); intersectionPointF = intersectionPointFt.ToScreenAbsolute(); } else { // No Airdefense left anymore? Then just use a random Redpoint intersectionPointFt = GameGrid.RedPoints.First(); intersectionPointF = intersectionPointFt.ToScreenAbsolute(); } // 5. add that point to "visuals" visuals.Add(new PointsObject("IntersectionPoint", Color.FromArgb(200, Color.Cyan), new[] { intersectionPointF })); // 6. Chop baseborder line into points so we can determine proper deploypoints var baseBorderPoints = new List <PointFT>(); foreach (var side in baseBorderSides) { baseBorderPoints.AddRange(SmartAirDeployHelpers.ChopLine(side.Item1, side.Item2)); } // deployPoints = all Points within radius x var deployPoints = baseBorderPoints.Where(x => x.DistanceSq(intersectionPointFt) < 450).ToList(); deployPoints = deployPoints.Select(x => x.TransformPositionAlongAxis(1)).ToList(); deployPoints = deployPoints.Select(x => x.Constrain()).ToList(); return(new DeployCalculationInformation(intersectionPointFt, intersectionPointF, deployPoints)); }