// Check if a point is inside the hand countour box public bool isPointInsideContainerBox(PointFT p) { if (p.X < rightDownCorner.X && p.X > leftUpperCorner.X && p.Y > leftUpperCorner.Y && p.Y < rightDownCorner.Y) { return true; } else { return false; } }
public Hand() { palm = new PointFT(-1, -1); fingertips = new List<PointFT>(5); fingertips3D = new List<Vector3FT>(5); contour = new List<PointFT>(2000); inside = new List<PointFT>(6000); leftUpperCorner = new PointFT(int.MaxValue, int.MaxValue); rightDownCorner = new PointFT(int.MinValue, int.MinValue); }
public bool isCircleInsideContainerBox(PointFT p, float r) { if (leftUpperCorner.X > p.X - r) { return false; } if (rightDownCorner.X < p.X + r) { return false; } if (leftUpperCorner.Y > p.Y - r) { return false; } if (rightDownCorner.Y < p.Y + r) { return false; } return true; }
/// <summary> /// create depoly points for troops and spells /// </summary> private void CreateDeployPoints() { float getOutRedArea = 0.25f; // don't include corners in case build huts are there float maxRedPointX = (GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Max(point => point.X) + 1 ?? GameGrid.RedZoneExtents.MaxX) + getOutRedArea; float minRedPointX = (GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Min(point => point.X) - 1 ?? GameGrid.RedZoneExtents.MinX) - getOutRedArea; float maxRedPointY = (GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Max(point => point.Y) + 1 ?? GameGrid.RedZoneExtents.MaxY) + getOutRedArea; float minRedPointY = (GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Min(point => point.Y) - 1 ?? GameGrid.RedZoneExtents.MinY) - getOutRedArea; // build a box around the base PointFT left = new PointFT(minRedPointX, maxRedPointY); PointFT top = new PointFT(maxRedPointX, maxRedPointY); PointFT right = new PointFT(maxRedPointX, minRedPointY); PointFT bottom = new PointFT(minRedPointX, minRedPointY); // border around the base _border = new RectangleT((int)minRedPointX, (int)maxRedPointY, (int)(maxRedPointX - minRedPointX), (int)(minRedPointY - maxRedPointY)); // core is center of the box _core = _border.GetCenter(); PointFT[] orginPoints = new[] { new PointFT(maxRedPointX, _core.Y), new PointFT(minRedPointX, _core.Y), new PointFT(_core.X, maxRedPointY), new PointFT(_core.X, minRedPointY) }; _orgin = new Container <PointFT> { Item = orginPoints.OrderBy(point => point.DistanceSq(_target)).First() }; #region top right if (_orgin.Item.X > _core.X) { Log.Info("[Goblin Knife] Attacking from the top right"); _attackLine = new Tuple <PointFT, PointFT>(top, right); _earthQuakePoint = new PointFT(_target.X + 5.5f, _core.Y); _jumpPoint = new PointFT(_target.X + 5f, _core.Y); _healPoint = new PointFT(_orgin.Item.X - 13f, _core.Y); _ragePoint = new PointFT(_orgin.Item.X - 9f, _core.Y); } #endregion #region bottom left else if (_orgin.Item.X < _core.X) { Log.Info("[Goblin Knife] Attacking from the bottom left"); _attackLine = new Tuple <PointFT, PointFT>(bottom, left); _earthQuakePoint = new PointFT(_target.X - 5.5f, _core.Y); _jumpPoint = new PointFT(_target.X - 5f, _core.Y); _healPoint = new PointFT(_orgin.Item.X + 13f, _core.Y); _ragePoint = new PointFT(_orgin.Item.X + 9f, _core.Y); } #endregion #region top left else if (_orgin.Item.Y > _core.Y) { Log.Info("[Goblin Knife] Attacking from the top left"); _attackLine = new Tuple <PointFT, PointFT>(left, top); _earthQuakePoint = new PointFT(_core.X, _target.Y + 5.5f); _jumpPoint = new PointFT(_core.X, _target.Y + 5f); _healPoint = new PointFT(_core.X, _orgin.Item.Y - 13f); _ragePoint = new PointFT(_core.X, _orgin.Item.Y - 9f); } #endregion #region bottom right else // (orgin.Y < core.Y) { Log.Info("[Goblin Knife] Attacking from the bottom right"); _attackLine = new Tuple <PointFT, PointFT>(right, bottom); _earthQuakePoint = new PointFT(_core.X, _target.Y - 5.5f); _jumpPoint = new PointFT(_core.X, _target.Y - 5f); _healPoint = new PointFT(_core.X, _orgin.Item.Y + 13f); _ragePoint = new PointFT(_core.X, _orgin.Item.Y + 9f); } #endregion }
private List<PointFT> CalculateFrontier(ref bool[][] valid, PointFT start, ref bool[][] contour) { List<PointFT> list = new List<PointFT>(); PointFT last = new PointFT(-1, -1); PointFT current = new PointFT(start); int dir = 0; do { if (valid[current.X][current.Y]) { dir = (dir + 1) % 4; if (current != last) { list.Add(new PointFT(current.X, current.Y)); last = new PointFT(current); contour[current.X][current.Y] = false; } } else { dir = (dir + 4 - 1) % 4; } switch (dir) { case 0: current.X += 1; break; case 1: current.Y += 1; break; case 2: current.X -= 1; break; case 3: current.Y -= 1; break; } } while (current != start); return list; }
public Line(PointFT start, PointFT end) { Start = start.ToScreenAbsolute(); End = end.ToScreenAbsolute(); }
/// <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)); }
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..."); } }
private void CreateDeployPoints(bool qw) { var target = TownHall.Find()?.Location.GetCenter() ?? DarkElixirStorage.Find().FirstOrDefault()?.Location.GetCenter() ?? new PointFT(0, 0); // don't include corners in case build huts are there var maxRedPointX = GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Max(point => point.X) + 1 ?? GameGrid.RedZoneExtents.MaxX; var minRedPointX = GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Min(point => point.X) - 1 ?? GameGrid.RedZoneExtents.MinX; var maxRedPointY = GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Max(point => point.Y) + 1 ?? GameGrid.RedZoneExtents.MaxY; var minRedPointY = GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Min(point => point.Y) - 1 ?? GameGrid.RedZoneExtents.MinY; // build a box around the base var left = new PointFT(minRedPointX, maxRedPointY); var top = new PointFT(maxRedPointX, maxRedPointY); var right = new PointFT(maxRedPointX, minRedPointY); var bottom = new PointFT(minRedPointX, minRedPointY); // border around the base _border = new RectangleT((int)minRedPointX, (int)maxRedPointY, (int)(maxRedPointX - minRedPointX), (int)(minRedPointY - maxRedPointY)); // core is center of the box _core = _border.GetCenter(); var orginPoints = new[] { new PointFT(maxRedPointX, _core.Y), new PointFT(minRedPointX, _core.Y), new PointFT(_core.X, maxRedPointY), new PointFT(_core.X, minRedPointY) }; _orgin = new Container <PointFT> { Item = orginPoints.OrderBy(point => point.DistanceSq(target)).First() }; if (_orgin.Item.X > _core.X) { Log.Info("[Breakthrough] Attacking from the top right"); var redLinePoint = GameGrid.RedPoints .Where(point => point.Y > -10 && point.Y < 10)? .Max(point => point.X) ?? GameGrid.RedZoneExtents.MaxX; if (qw) { _qwPoint = right; _queenRagePoint = new PointFT(right.X - 5, right.Y + 5); _healerPoint = new PointFT(24f, -24f); _attackLine = new Tuple <PointFT, PointFT>(top, _orgin.Item.Midpoint(right)); } else { _attackLine = new Tuple <PointFT, PointFT>(top, right); _healerPoint = new PointFT(24f, _core.Y); } _healPoint = new PointFT(redLinePoint - 12f, _core.Y); _ragePoint = new PointFT(redLinePoint - 9f, _core.Y); } else if (_orgin.Item.X < _core.X) { Log.Info("[Breakthrough] Attacking from the bottom left"); var redLinePoint = GameGrid.RedPoints .Where(point => point.Y > -10 && point.Y < 10)? .Min(point => point.X) ?? GameGrid.RedZoneExtents.MinX; if (qw) { _qwPoint = left; _queenRagePoint = new PointFT(left.X + 5, left.Y - 5); _healerPoint = new PointFT(-24f, 24f); _attackLine = new Tuple <PointFT, PointFT>(bottom, _orgin.Item.Midpoint(left)); } else { _healerPoint = new PointFT(-24f, _core.Y); _attackLine = new Tuple <PointFT, PointFT>(bottom, left); } _healPoint = new PointFT(redLinePoint + 12, _core.Y); _ragePoint = new PointFT(redLinePoint + 9, _core.Y); } else if (_orgin.Item.Y > _core.Y) { Log.Info("[Breakthrough] Attacking from the top left"); var redLinePoint = GameGrid.RedPoints .Where(point => point.X > -10 && point.X < 10)? .Max(point => point.Y) ?? GameGrid.RedZoneExtents.MaxY; if (qw) { _qwPoint = left; _queenRagePoint = new PointFT(left.X + 5f, left.Y - 5f); _healerPoint = new PointFT(-24f, 24f); _attackLine = new Tuple <PointFT, PointFT>(top, _orgin.Item.Midpoint(left)); } else { _healerPoint = new PointFT(_core.X, 24f); _attackLine = new Tuple <PointFT, PointFT>(left, top); } _healPoint = new PointFT(_core.X, redLinePoint - 12f); _ragePoint = new PointFT(_core.X, redLinePoint - 9f); } else // (orgin.Y < core.Y) { Log.Info("[Breakthrough] Attacking from the bottom right"); var redLinePoint = GameGrid.RedPoints .Where(point => point.X > -10 && point.X < 10)? .Min(point => point.Y) ?? GameGrid.RedZoneExtents.MinY; if (qw) { _qwPoint = right; _queenRagePoint = new PointFT(right.X - 5, right.Y + 5); _healerPoint = new PointFT(24f, -24f); _attackLine = new Tuple <PointFT, PointFT>(bottom, _orgin.Item.Midpoint(right)); } else { _healerPoint = new PointFT(_core.X, -24f); _attackLine = new Tuple <PointFT, PointFT>(right, bottom); } _healPoint = new PointFT(_core.X, redLinePoint + 12); _ragePoint = new PointFT(_core.X, redLinePoint + 9); } }
List <PointFT> CreateLavaHoundDeployPoints(AirDefense[] airDefenses, List <VisualObject> visuals) { // don't include corners in case build huts are there var maxRedPointX = GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Max(point => point.X) + 1 ?? GameGrid.RedZoneExtents.MaxX; var minRedPointX = GameGrid.RedPoints.Where(p => - 18 < p.Y && p.Y < 18)?.Min(point => point.X) - 1 ?? GameGrid.RedZoneExtents.MinX; var maxRedPointY = GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Max(point => point.Y) + 1 ?? GameGrid.RedZoneExtents.MaxY; var minRedPointY = GameGrid.RedPoints.Where(p => - 18 < p.X && p.X < 18)?.Min(point => point.Y) - 1 ?? GameGrid.RedZoneExtents.MinY; // 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 List <PointFT> resultPoints = new List <PointFT>(); var closestAirDefenses = airDefenses.OrderBy(x => SmartAirDeployHelpers.DistanceSqToClosestDeploypoint(x.Location.GetCenter())).Take(2); if (closestAirDefenses?.Count() == 2) { var start = closestAirDefenses.First().Location.GetCenter(); var end = closestAirDefenses.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)); Log.Error($"[Smart Air] Start: ({orthLine.Start.X} , {orthLine.Start.Y}), End ({orthLine.End.X}, {orthLine.End.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 // 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 sidesToCheckForIntersections = new List <Tuple <Vector, Vector> >(); sidesToCheckForIntersections.Add(Tuple.Create(vTopPoint, vLeftPoint)); // Topleft sidesToCheckForIntersections.Add(Tuple.Create(vTopPoint, vRightPoint)); // Topright sidesToCheckForIntersections.Add(Tuple.Create(vLeftPoint, vBottomPoint)); // BottomLeft sidesToCheckForIntersections.Add(Tuple.Create(vRightPoint, vBottomPoint)); // BottomRight // 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 sidesToCheckForIntersections) { if (SmartAirDeployHelpers.LineSegementsIntersect(side.Item1, side.Item2, vOrthLineStartPoint, vOrthLineEndPoint, out vInterSectionPoint)) { break; } } var intersectionPointF = new PointF((float)vInterSectionPoint.X, (float)vInterSectionPoint.Y); var intersectionPointFt = new PointFT((int)intersectionPointF.X, (int)intersectionPointF.Y); // 5. add that point to "visuals" visuals.Add(new PointsObject("IntersectionPoint", Color.FromArgb(200, Color.Cyan), new[] { intersectionPointF })); // deployPoints = all Points within radius x var deployPoints = GameGrid.RedPoints.Where(x => x.DistanceSq(intersectionPointFt) < 220).ToList(); deployPoints = deployPoints.Select(x => x.TransformPositionAlongAxis(5)).ToList(); // FurthestDeployPoint 1 = Furthest Point to intersectionPoint which is still inside of the radius var furthestDeployPoint1 = deployPoints.OrderByDescending(x => x.DistanceSq(intersectionPointFt)).First(); // FurthestDeployPoint 2 = Furthest Point to intersectionPoint which is still inside of the radius var furthestDeployPoint2 = deployPoints.OrderByDescending(x => x.DistanceSq(furthestDeployPoint1)).First(); var lavaHoundDeployPoints = new List <PointFT>(); lavaHoundDeployPoints.Add(furthestDeployPoint1); lavaHoundDeployPoints.Add(furthestDeployPoint2); visuals.Add(new PointsObject("LavaHoundDeployPoints", Color.FromArgb(200, Color.Pink), lavaHoundDeployPoints)); visuals.Add(new PointsObject("AttackUnitDeployPoints", Color.FromArgb(110, Color.Black), deployPoints)); } return(resultPoints); }
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); } }
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"); // 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 (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; } }
// Calculate the contour box of the hand if it possible public bool calculateContainerBox(float reduction = 0) { if (contour != null && contour.Count > 0) { for (int j = 0; j < contour.Count; ++j) { if (leftUpperCorner.X > contour[j].X) leftUpperCorner.X = contour[j].X; if (rightDownCorner.X < contour[j].X) rightDownCorner.X = contour[j].X; if (leftUpperCorner.Y > contour[j].Y) leftUpperCorner.Y = contour[j].Y; if (rightDownCorner.Y < contour[j].Y) rightDownCorner.Y = contour[j].Y; } int incX = (int)((rightDownCorner.X - leftUpperCorner.X) * (reduction / 2)); int incY = (int)((rightDownCorner.Y - leftUpperCorner.Y) * (reduction / 2)); PointFT inc = new PointFT(incX, incY); leftUpperCorner = leftUpperCorner + inc; rightDownCorner = rightDownCorner + inc; return true; } else { return false; } }
// Normalize in the interval [-1, 1] the given 3D point. // The Z value is in the inverval [-1, 0], being 0 the closest distance. private Vector3FT transformTo3DCoord(PointFT p, int width, int height, int distance) { Vector3FT v = new Vector3FT(); v.X = p.Y / (width * 1.0f) * 2 - 1; v.Y = (1 - p.X / (height * 1.0f)) * 2 - 1; v.Z = (distance - 400) / -7600.0f; return v; }
/// <summary> /// Find the area of a triangle. This function uses the 1/2 determinant /// </summary> /// <param name="v1">triangle point1</param> /// <param name="v2">triangle point2</param> /// <param name="v3">triangle point3</param> /// <returns>triangle area</returns> public static float CalcTriArea(PointFT v1, PointFT v2, PointFT v3) { return(Math.Abs((v1.X * (v2.Y - v3.Y) + v2.X * (v3.Y - v1.Y) + v3.X * (v1.Y - v2.Y)) / 2f)); }
/// <summary> /// Returns the distance in tiles from the center of a building to a specific X,Y Coordiante Point. /// </summary> /// <param name="building"></param> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public static double DistanceFromPoint(this Building building, PointFT point) { return(DistanceFromPoint(building, point.X, point.Y)); }
public static PointFT GetClosestPointToLine(this Tuple <PointFT, PointFT> line, PointFT P) { PointFT a_to_p = new PointFT ( P.X - line.Item1.X, P.Y - line.Item1.Y ), a_to_b = new PointFT ( line.Item2.X - line.Item1.X, line.Item2.Y - line.Item1.Y // # Storing vector A->B ); float atb2 = a_to_b.X * a_to_b.X + a_to_b.Y * a_to_b.Y; float atp_dot_atb = a_to_p.X * a_to_b.X + a_to_p.Y * a_to_b.Y; // The dot product of a_to_p and a_to_b float t = atp_dot_atb / atb2; // # The normalized "distance" from a to the closest point return(new PointFT(line.Item1.X + a_to_b.X * t, line.Item1.Y + a_to_b.Y * t)); }
/// <summary> /// Set deploy points for troops and spells /// </summary> public static void SetDeployPoints() { // Top right side var topRight = new PointFT((float)GameGrid.DeployExtents.MaxX, (float)GameGrid.MaxY - 2); var rightTop = new PointFT((float)GameGrid.DeployExtents.MaxX, (float)GameGrid.MinY + 2); // Bottom right side var rightBottom = new PointFT((float)GameGrid.MaxX - 5, (float)GameGrid.DeployExtents.MinY); var bottomRight = new PointFT((float)GameGrid.MinX + 10, (float)GameGrid.DeployExtents.MinY); // Bottom left side // Move 8 tiles from bottom corner due to unitsbar. var bottomLeft = new PointFT((float)GameGrid.DeployExtents.MinX, (float)GameGrid.MinY + 8); var leftBottom = new PointFT((float)GameGrid.DeployExtents.MinX, (float)GameGrid.MaxY - 2); // Top Left side var leftTop = new PointFT((float)GameGrid.MinX + 2, (float)GameGrid.DeployExtents.MaxY); var topLeft = new PointFT((float)GameGrid.MaxX - 2, (float)GameGrid.DeployExtents.MaxY); var isJumpSpell = Deploy.GetTroops().ExtractOne(DeployId.Jump)?.Count > 0 ? true : false; if (AllInOnePushDeploy.Origin.X > AllInOnePushDeploy.Core.X) { Log.Info($"[{AllInOnePushDeploy.AttackName}] Attacking from the top right"); AllInOnePushDeploy.AttackLine = new Tuple <PointFT, PointFT>(topRight, rightTop); var distance = Math.Abs(AllInOnePushDeploy.Origin.X) - Math.Abs(AllInOnePushDeploy.Target.X); var target = distance >= AllInOnePushDeploy.MinDistace ? AllInOnePushDeploy.Target : AllInOnePushDeploy.Core; var firstWall = GetFirstWallForJump(AllInOnePushDeploy.Origin.Y, "Y"); AllInOnePushDeploy.FirstJumpPoint = new PointFT(firstWall.X - 2.75f, AllInOnePushDeploy.Core.Y); var maxX = isJumpSpell ? AllInOnePushDeploy.FirstJumpPoint.X - 5f : firstWall.X - 1.5f; var start = target.X + 4f; var earthQuakePoints = new List <PointFT> { new PointFT(AllInOnePushDeploy.Target.X + 6f, AllInOnePushDeploy.Core.Y) }; var jumpPoints = new List <PointFT> { new PointFT(AllInOnePushDeploy.Target.X + 5.5f, AllInOnePushDeploy.Core.Y) }; if (GetWallsInsideSpell(earthQuakePoints[0], 4f) < 8) { while (maxX > start) { earthQuakePoints.Add(new PointFT(start, AllInOnePushDeploy.Core.Y)); jumpPoints.Add(new PointFT(start - 0.5f, AllInOnePushDeploy.Core.Y)); start += 0.25f; } } AllInOnePushDeploy.EqPoint = earthQuakePoints.OrderByDescending(e => GetWallsInsideSpell(e)).FirstOrDefault(); // Prevent overlaping EQ with jump if (isJumpSpell && AllInOnePushDeploy.FirstJumpPoint.X - AllInOnePushDeploy.EqPoint.X < 7f) { AllInOnePushDeploy.EqPoint = new PointFT(AllInOnePushDeploy.FirstJumpPoint.X - 7f, AllInOnePushDeploy.FirstJumpPoint.Y); } AllInOnePushDeploy.SecondJumpPoint = new PointFT(AllInOnePushDeploy.EqPoint.X - 0.5f, AllInOnePushDeploy.EqPoint.Y); var shiftSpells = AllInOnePushDeploy.ShiftSpells; AllInOnePushDeploy.FirstRagePoint = new PointFT(AllInOnePushDeploy.Origin.X - 11f - shiftSpells, AllInOnePushDeploy.Core.Y); AllInOnePushDeploy.FirstHealPoint = new PointFT(AllInOnePushDeploy.Origin.X - 17f - shiftSpells, AllInOnePushDeploy.Core.Y); AllInOnePushDeploy.SecondRagePoint = new PointFT(AllInOnePushDeploy.Origin.X - 22f - shiftSpells, AllInOnePushDeploy.Core.Y); AllInOnePushDeploy.FirstHastePoint = new PointFT(AllInOnePushDeploy.Origin.X - 26f - shiftSpells, AllInOnePushDeploy.Core.Y); //try to find better funneling points var frac = 0.65f; AllInOnePushDeploy.FirstFunnellingPoint = new PointFT(AllInOnePushDeploy.Origin.X + frac * (AllInOnePushDeploy.AttackLine.Item1.X - AllInOnePushDeploy.Origin.X), AllInOnePushDeploy.Origin.Y + frac * (AllInOnePushDeploy.AttackLine.Item1.Y - AllInOnePushDeploy.Origin.Y)); AllInOnePushDeploy.SecondFunnellingPoint = new PointFT(AllInOnePushDeploy.Origin.X + frac * (AllInOnePushDeploy.AttackLine.Item2.X - AllInOnePushDeploy.Origin.X), AllInOnePushDeploy.Origin.Y + frac * (AllInOnePushDeploy.AttackLine.Item2.Y - AllInOnePushDeploy.Origin.Y)); AllInOnePushDeploy.FirstHasteLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X - 11f - shiftSpells, AllInOnePushDeploy.FirstFunnellingPoint.Y), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X - 11f - shiftSpells, AllInOnePushDeploy.SecondFunnellingPoint.Y) ); AllInOnePushDeploy.FirstRageLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X - 19f - shiftSpells, AllInOnePushDeploy.FirstFunnellingPoint.Y), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X - 19f - shiftSpells, AllInOnePushDeploy.SecondFunnellingPoint.Y) ); AllInOnePushDeploy.SecondHasteLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X - 24f - shiftSpells, AllInOnePushDeploy.FirstFunnellingPoint.Y), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X - 24f - shiftSpells, AllInOnePushDeploy.SecondFunnellingPoint.Y) ); AllInOnePushDeploy.SecondRageLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X - 24f - shiftSpells, AllInOnePushDeploy.FirstFunnellingPoint.Y), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X - 24f - shiftSpells, AllInOnePushDeploy.SecondFunnellingPoint.Y) ); AllInOnePushDeploy.QWHealer = new PointFT(GameGrid.DeployExtents.MaxX, AllInOnePushDeploy.FirstFunnellingPoint.Y); AllInOnePushDeploy.QWRagePoint = new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X - 2, AllInOnePushDeploy.FirstFunnellingPoint.Y); } else if (AllInOnePushDeploy.Origin.X < AllInOnePushDeploy.Core.X) { Log.Info($"[{AllInOnePushDeploy.AttackName}] Attacking from the bottom left"); AllInOnePushDeploy.AttackLine = new Tuple <PointFT, PointFT>(leftBottom, bottomLeft); var distance = Math.Abs(AllInOnePushDeploy.Origin.X) - Math.Abs(AllInOnePushDeploy.Target.X); var target = distance >= AllInOnePushDeploy.MinDistace ? AllInOnePushDeploy.Target : AllInOnePushDeploy.Core; var firstWall = GetFirstWallForJump(AllInOnePushDeploy.Origin.Y, "Y"); AllInOnePushDeploy.FirstJumpPoint = new PointFT(firstWall.X + 2.75f, AllInOnePushDeploy.Core.Y); var maxX = isJumpSpell ? AllInOnePushDeploy.FirstJumpPoint.X + 5f : firstWall.X + 1.5f; var start = target.X - 4f; var earthQuakePoints = new List <PointFT> { new PointFT(AllInOnePushDeploy.Target.X - 6f, AllInOnePushDeploy.Core.Y) }; var jumpPoints = new List <PointFT> { new PointFT(AllInOnePushDeploy.Target.X - 5.5f, AllInOnePushDeploy.Core.Y) }; if (GetWallsInsideSpell(earthQuakePoints[0], 4f) < 8) { while (maxX < start) { earthQuakePoints.Add(new PointFT(start, AllInOnePushDeploy.Core.Y)); jumpPoints.Add(new PointFT(start + 0.5f, AllInOnePushDeploy.Core.Y)); start -= 0.25f; } } AllInOnePushDeploy.EqPoint = earthQuakePoints.OrderByDescending(e => GetWallsInsideSpell(e)).FirstOrDefault(); // Prevent overlaping EQ with jump if (isJumpSpell && Math.Abs(AllInOnePushDeploy.FirstJumpPoint.X - AllInOnePushDeploy.EqPoint.X) < 7f) { AllInOnePushDeploy.EqPoint = new PointFT(AllInOnePushDeploy.FirstJumpPoint.X + 7f, AllInOnePushDeploy.FirstJumpPoint.Y); } AllInOnePushDeploy.SecondJumpPoint = new PointFT(AllInOnePushDeploy.EqPoint.X + 0.5f, AllInOnePushDeploy.EqPoint.Y); var shiftSpells = AllInOnePushDeploy.ShiftSpells; AllInOnePushDeploy.FirstRagePoint = new PointFT(AllInOnePushDeploy.Origin.X + 11f + shiftSpells, AllInOnePushDeploy.Core.Y); AllInOnePushDeploy.FirstHealPoint = new PointFT(AllInOnePushDeploy.Origin.X + 17f + shiftSpells, AllInOnePushDeploy.Core.Y); AllInOnePushDeploy.SecondRagePoint = new PointFT(AllInOnePushDeploy.Origin.X + 22f + shiftSpells, AllInOnePushDeploy.Core.Y); AllInOnePushDeploy.FirstHastePoint = new PointFT(AllInOnePushDeploy.Origin.X + 26f + shiftSpells, AllInOnePushDeploy.Core.Y); //try to find better funneling points var frac = 0.65f; AllInOnePushDeploy.FirstFunnellingPoint = new PointFT(AllInOnePushDeploy.Origin.X + frac * (AllInOnePushDeploy.AttackLine.Item1.X - AllInOnePushDeploy.Origin.X), AllInOnePushDeploy.Origin.Y + frac * (AllInOnePushDeploy.AttackLine.Item1.Y - AllInOnePushDeploy.Origin.Y)); AllInOnePushDeploy.SecondFunnellingPoint = bottomLeft; AllInOnePushDeploy.FirstHasteLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X + 11f + shiftSpells, AllInOnePushDeploy.FirstFunnellingPoint.Y), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X + 11f + shiftSpells, AllInOnePushDeploy.SecondFunnellingPoint.Y) ); AllInOnePushDeploy.FirstRageLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X + 19f + shiftSpells, AllInOnePushDeploy.FirstFunnellingPoint.Y), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X + 19f + shiftSpells, AllInOnePushDeploy.SecondFunnellingPoint.Y) ); AllInOnePushDeploy.SecondHasteLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X + 24f + shiftSpells, AllInOnePushDeploy.FirstFunnellingPoint.Y), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X + 24f + shiftSpells, AllInOnePushDeploy.SecondFunnellingPoint.Y) ); AllInOnePushDeploy.SecondRageLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X + 24f + shiftSpells, AllInOnePushDeploy.FirstFunnellingPoint.Y), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X + 24f + shiftSpells, AllInOnePushDeploy.SecondFunnellingPoint.Y) ); AllInOnePushDeploy.QWHealer = new PointFT(GameGrid.DeployExtents.MinX, AllInOnePushDeploy.FirstFunnellingPoint.Y); AllInOnePushDeploy.QWRagePoint = new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X + 2, AllInOnePushDeploy.FirstFunnellingPoint.Y); } else if (AllInOnePushDeploy.Origin.Y > AllInOnePushDeploy.Core.Y) { Log.Info($"[{AllInOnePushDeploy.AttackName}] Attacking from the top left"); AllInOnePushDeploy.AttackLine = new Tuple <PointFT, PointFT>(leftTop, topLeft); var distance = Math.Abs(AllInOnePushDeploy.Origin.Y) - Math.Abs(AllInOnePushDeploy.Target.Y); var target = distance >= AllInOnePushDeploy.MinDistace ? AllInOnePushDeploy.Target : AllInOnePushDeploy.Core; var firstWall = GetFirstWallForJump(AllInOnePushDeploy.Origin.X, "X"); AllInOnePushDeploy.FirstJumpPoint = new PointFT(AllInOnePushDeploy.Core.X, firstWall.Y - 2.75f); var maxX = isJumpSpell ? AllInOnePushDeploy.FirstJumpPoint.Y - 5f : firstWall.Y - 1.5f; var start = target.Y + 4f; var earthQuakePoints = new List <PointFT> { new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Target.Y + 6f) }; var jumpPoints = new List <PointFT> { new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Target.Y + 5.5f) }; if (GetWallsInsideSpell(earthQuakePoints[0], 4f) < 8) { while (maxX > start) { earthQuakePoints.Add(new PointFT(AllInOnePushDeploy.Core.X, start)); jumpPoints.Add(new PointFT(AllInOnePushDeploy.Core.X, start - 0.5f)); start += 0.25f; } } AllInOnePushDeploy.EqPoint = earthQuakePoints.OrderByDescending(e => GetWallsInsideSpell(e)).FirstOrDefault(); // Prevent overlaping EQ with jump if (isJumpSpell && AllInOnePushDeploy.FirstJumpPoint.Y - AllInOnePushDeploy.EqPoint.Y < 7f) { AllInOnePushDeploy.EqPoint = new PointFT(AllInOnePushDeploy.FirstJumpPoint.X, AllInOnePushDeploy.FirstJumpPoint.Y - 7f); } AllInOnePushDeploy.SecondJumpPoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.EqPoint.Y - 0.5f); var shiftSpells = AllInOnePushDeploy.ShiftSpells; AllInOnePushDeploy.FirstRagePoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Origin.Y - 11f - shiftSpells); AllInOnePushDeploy.FirstHealPoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Origin.Y - 17f - shiftSpells); AllInOnePushDeploy.SecondRagePoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Origin.Y - 22f - shiftSpells); AllInOnePushDeploy.FirstHastePoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Origin.Y - 26f - shiftSpells); //try to find better funneling points var frac = 0.65f; AllInOnePushDeploy.FirstFunnellingPoint = new PointFT(AllInOnePushDeploy.Origin.X + frac * (AllInOnePushDeploy.AttackLine.Item1.X - AllInOnePushDeploy.Origin.X), AllInOnePushDeploy.Origin.Y + frac * (AllInOnePushDeploy.AttackLine.Item1.Y - AllInOnePushDeploy.Origin.Y)); AllInOnePushDeploy.SecondFunnellingPoint = new PointFT(AllInOnePushDeploy.Origin.X + frac * (AllInOnePushDeploy.AttackLine.Item2.X - AllInOnePushDeploy.Origin.X), AllInOnePushDeploy.Origin.Y + frac * (AllInOnePushDeploy.AttackLine.Item2.Y - AllInOnePushDeploy.Origin.Y)); AllInOnePushDeploy.FirstHasteLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y - 11f - shiftSpells), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X, AllInOnePushDeploy.SecondFunnellingPoint.Y - 11f - shiftSpells) ); AllInOnePushDeploy.FirstRageLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y - 19f - shiftSpells), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X, AllInOnePushDeploy.SecondFunnellingPoint.Y - 19f - shiftSpells) ); AllInOnePushDeploy.SecondHasteLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y - 24f - shiftSpells), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X, AllInOnePushDeploy.SecondFunnellingPoint.Y - 24f - shiftSpells) ); AllInOnePushDeploy.SecondRageLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y - 24f - shiftSpells), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X, AllInOnePushDeploy.SecondFunnellingPoint.Y - 24f - shiftSpells) ); AllInOnePushDeploy.QWHealer = new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, GameGrid.DeployExtents.MaxY); AllInOnePushDeploy.QWRagePoint = new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y - 2); } else // (orgin.Y < core.Y) { Log.Info($"[{AllInOnePushDeploy.AttackName}] Attacking from the bottom right"); // Avoid bottom right side until fix zoom out on attack progress issue var avoidBottomRight = true; if (avoidBottomRight) { var originPoints = new[] { new PointFT(GameGrid.DeployExtents.MaxX, AllInOnePushDeploy.Core.Y), new PointFT(GameGrid.DeployExtents.MinX, AllInOnePushDeploy.Core.Y), new PointFT(AllInOnePushDeploy.Core.X, GameGrid.DeployExtents.MaxY), new PointFT(AllInOnePushDeploy.Core.X, GameGrid.DeployExtents.MinY) }; AllInOnePushDeploy.Origin = originPoints.OrderBy(point => point.DistanceSq(AllInOnePushDeploy.Target)).ElementAt(1); Log.Warning($"Avoid bottom right side set to true, We will attack from next closest side to the target"); SetDeployPoints(); } else { AllInOnePushDeploy.AttackLine = new Tuple <PointFT, PointFT>(rightBottom, bottomRight); var distance = Math.Abs(AllInOnePushDeploy.Origin.Y) - Math.Abs(AllInOnePushDeploy.Target.Y); var target = distance >= AllInOnePushDeploy.MinDistace ? AllInOnePushDeploy.Target : AllInOnePushDeploy.Core; var firstWall = GetFirstWallForJump(AllInOnePushDeploy.Origin.X, "X"); AllInOnePushDeploy.FirstJumpPoint = new PointFT(AllInOnePushDeploy.Core.X, firstWall.Y + 2.75f); var maxX = isJumpSpell ? AllInOnePushDeploy.FirstJumpPoint.Y + 5f : firstWall.Y + 1.5f; var start = target.Y - 4f; var earthQuakePoints = new List <PointFT> { new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Target.Y - 6f) }; var jumpPoints = new List <PointFT> { new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Target.Y - 5.5f) }; if (GetWallsInsideSpell(earthQuakePoints[0], 4f) < 8) { while (maxX < start) { earthQuakePoints.Add(new PointFT(AllInOnePushDeploy.Core.X, start)); jumpPoints.Add(new PointFT(AllInOnePushDeploy.Core.X, start + 0.5f)); start -= 0.25f; } } AllInOnePushDeploy.EqPoint = earthQuakePoints.OrderByDescending(e => GetWallsInsideSpell(e)).FirstOrDefault(); // Prevent overlaping EQ with jump if (isJumpSpell && Math.Abs(AllInOnePushDeploy.FirstJumpPoint.Y - AllInOnePushDeploy.EqPoint.Y) < 7f) { AllInOnePushDeploy.EqPoint = new PointFT(AllInOnePushDeploy.FirstJumpPoint.X, AllInOnePushDeploy.FirstJumpPoint.Y + 7f); } AllInOnePushDeploy.SecondJumpPoint = new PointFT(AllInOnePushDeploy.EqPoint.X, AllInOnePushDeploy.EqPoint.Y + 0.5f); var shiftSpells = AllInOnePushDeploy.ShiftSpells; AllInOnePushDeploy.FirstRagePoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Origin.Y + 11f + shiftSpells); AllInOnePushDeploy.FirstHealPoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Origin.Y + 17f + shiftSpells); AllInOnePushDeploy.SecondRagePoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Origin.Y + 22f + shiftSpells); AllInOnePushDeploy.FirstHastePoint = new PointFT(AllInOnePushDeploy.Core.X, AllInOnePushDeploy.Origin.Y + 26f + shiftSpells); //try to find better funneling points var frac = 0.65f; AllInOnePushDeploy.FirstFunnellingPoint = new PointFT(AllInOnePushDeploy.Origin.X + frac * (AllInOnePushDeploy.AttackLine.Item1.X - AllInOnePushDeploy.Origin.X), AllInOnePushDeploy.Origin.Y + frac * (AllInOnePushDeploy.AttackLine.Item1.Y - AllInOnePushDeploy.Origin.Y)); AllInOnePushDeploy.SecondFunnellingPoint = bottomRight; AllInOnePushDeploy.FirstHasteLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y + 11f + shiftSpells), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X, AllInOnePushDeploy.SecondFunnellingPoint.Y + 11f + shiftSpells) ); AllInOnePushDeploy.FirstRageLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y + 19f + shiftSpells), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X, AllInOnePushDeploy.SecondFunnellingPoint.Y + 19f + shiftSpells) ); AllInOnePushDeploy.SecondHasteLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y + 24f + shiftSpells), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X, AllInOnePushDeploy.SecondFunnellingPoint.Y + 24f + shiftSpells) ); AllInOnePushDeploy.SecondRageLine = new Tuple <PointFT, PointFT> ( new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y + 24f + shiftSpells), new PointFT(AllInOnePushDeploy.SecondFunnellingPoint.X, AllInOnePushDeploy.SecondFunnellingPoint.Y + 24f + shiftSpells) ); AllInOnePushDeploy.QWHealer = new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, GameGrid.DeployExtents.MinY); AllInOnePushDeploy.QWRagePoint = new PointFT(AllInOnePushDeploy.FirstFunnellingPoint.X, AllInOnePushDeploy.FirstFunnellingPoint.Y + 1); } } }