public SafePathResult IsSafePath(GamePath path, int timeOffset, int speed = -1, int delay = 0, Obj_AI_Base unit = null) { var Distance = 0f; timeOffset += Game.Ping / 2; speed = (speed == -1) ? (int)GameObjects.Player.MoveSpeed : speed; if (unit == null) { unit = GameObjects.Player; } var allIntersections = new List <FoundIntersection>(); for (var i = 0; i <= path.Count - 2; i++) { var from = path[i]; var to = path[i + 1]; var segmentIntersections = new List <FoundIntersection>(); for (var j = 0; j <= Polygon.Points.Count - 1; j++) { var sideStart = Polygon.Points[j]; var sideEnd = Polygon.Points[j == (Polygon.Points.Count - 1) ? 0 : j + 1]; var intersection = from.Intersection(to, sideStart, sideEnd); if (intersection.Intersects) { segmentIntersections.Add(new FoundIntersection(Distance + intersection.Point.Distance(from), (int)((Distance + intersection.Point.Distance(from)) * 1000 / speed), intersection.Point, from)); } } var sortedList = segmentIntersections.OrderBy(o => o.Distance).ToList(); allIntersections.AddRange(sortedList); Distance += from.Distance(to); } if (SpellData.Type == SkillShotType.SkillshotMissileLine || SpellData.Type == SkillShotType.SkillshotMissileCone || SpellData.Type == SkillShotType.SkillshotArc) { if (IsSafe(Common.Evade.Evade.PlayerPosition)) { if (allIntersections.Count == 0) { return(new SafePathResult(true, new FoundIntersection())); } if (SpellData.DontCross) { return(new SafePathResult(false, allIntersections[0])); } for (var i = 0; i <= allIntersections.Count - 1; i = i + 2) { var enterIntersection = allIntersections[i]; var enterIntersectionProjection = enterIntersection.Point.ProjectOn(Start, End).SegmentPoint; if (i == allIntersections.Count - 1) { var missilePositionOnIntersection = GetMissilePosition(enterIntersection.Time - timeOffset); return(new SafePathResult((End.Distance(missilePositionOnIntersection) + 50 <= End.Distance(enterIntersectionProjection)) && GameObjects.Player.MoveSpeed < SpellData.MissileSpeed, allIntersections[0])); } var exitIntersection = allIntersections[i + 1]; var exitIntersectionProjection = exitIntersection.Point.ProjectOn(Start, End).SegmentPoint; var missilePosOnEnter = GetMissilePosition(enterIntersection.Time - timeOffset); var missilePosOnExit = GetMissilePosition(exitIntersection.Time + timeOffset); if (missilePosOnEnter.Distance(End) + 50 > enterIntersectionProjection.Distance(End)) { if (missilePosOnExit.Distance(End) <= exitIntersectionProjection.Distance(End)) { return(new SafePathResult(false, allIntersections[0])); } } } return(new SafePathResult(true, allIntersections[0])); } if (allIntersections.Count == 0) { return(new SafePathResult(false, new FoundIntersection())); } if (allIntersections.Count > 0) { var exitIntersection = allIntersections[0]; var exitIntersectionProjection = exitIntersection.Point.ProjectOn(Start, End).SegmentPoint; var missilePosOnExit = GetMissilePosition(exitIntersection.Time + timeOffset); if (missilePosOnExit.Distance(End) <= exitIntersectionProjection.Distance(End)) { return(new SafePathResult(false, allIntersections[0])); } } } if (IsSafe(Common.Evade.Evade.PlayerPosition)) { if (allIntersections.Count == 0) { return(new SafePathResult(true, new FoundIntersection())); } if (SpellData.DontCross) { return(new SafePathResult(false, allIntersections[0])); } } else { if (allIntersections.Count == 0) { return(new SafePathResult(false, new FoundIntersection())); } } var timeToExplode = (SpellData.DontAddExtraDuration ? 0 : SpellData.ExtraDuration) + SpellData.Delay + (int)(1000 * Start.Distance(End) / SpellData.MissileSpeed) - (Utils.TickCount - StartTick); var myPositionWhenExplodes = path.PositionAfter(timeToExplode, speed, delay); if (!IsSafe(myPositionWhenExplodes)) { return(new SafePathResult(false, allIntersections[0])); } var myPositionWhenExplodesWithOffset = path.PositionAfter(timeToExplode, speed, timeOffset); return(new SafePathResult(IsSafe(myPositionWhenExplodesWithOffset), allIntersections[0])); }