public SafePathResult(bool isSafe, FoundIntersection intersection) { Intersection = intersection; IsSafe = isSafe; }
/// <summary> /// Returns if the skillshot will hit the Caster if the Caster follows the path. /// </summary> public SafePathResult IsSafePath(List <Vector2> path, int timeOffset, int speed = -1, int delay = 0) { var distance = 0f; timeOffset += Game.Ping / 2; speed = (speed == -1) ? (int)ObjectManager.Player.MoveSpeed : speed; 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.LSDistance(from), (int)((distance + intersection.Point.LSDistance(from)) * 1000 / speed), intersection.Point, from)); } } var sortedList = segmentIntersections.OrderBy(o => o.Distance).ToList(); allIntersections.AddRange(sortedList); distance += from.LSDistance(to); } //Skillshot with missile. if (SpellData.Type == SkillShotType.SkillshotMissileLine || SpellData.Type == SkillShotType.SkillshotMissileCone) { //Outside the skillshot if (IsSafe(ObjectManager.Player.ServerPosition.To2D())) { //No intersections -> Safe if (allIntersections.Count == 0) { return(new SafePathResult(true, new FoundIntersection())); } for (var i = 0; i <= allIntersections.Count - 1; i = i + 2) { var enterIntersection = allIntersections[i]; var enterIntersectionProjection = enterIntersection.PointVector2.ProjectOn(Start, End).SegmentPoint; //Intersection with no exit point. if (i == allIntersections.Count - 1) { var missilePositionOnIntersection = GetMissilePosition(enterIntersection.Time - timeOffset); return (new SafePathResult( (End.LSDistance(missilePositionOnIntersection) + 50 <= End.LSDistance(enterIntersectionProjection)) && ObjectManager.Player.MoveSpeed < SpellData.MissileSpeed, allIntersections[0])); } var exitIntersection = allIntersections[i + 1]; var exitIntersectionProjection = exitIntersection.PointVector2.ProjectOn(Start, End).SegmentPoint; var missilePosOnEnter = GetMissilePosition(enterIntersection.Time - timeOffset); var missilePosOnExit = GetMissilePosition(exitIntersection.Time + timeOffset); //Missile didnt pass. if (missilePosOnEnter.LSDistance(End) + 50 > enterIntersectionProjection.LSDistance(End)) { if (missilePosOnExit.LSDistance(End) <= exitIntersectionProjection.LSDistance(End)) { return(new SafePathResult(false, allIntersections[0])); } } } return(new SafePathResult(true, allIntersections[0])); } //Inside the skillshot. if (allIntersections.Count == 0) { return(new SafePathResult(false, new FoundIntersection())); } if (allIntersections.Count > 0) { //Check only for the exit point FoundIntersection exitIntersection = allIntersections[0]; Vector2 exitIntersectionProjection = exitIntersection.PointVector2.ProjectOn(Start, End).SegmentPoint; Vector2 missilePosOnExit = GetMissilePosition(exitIntersection.Time + timeOffset); if (missilePosOnExit.LSDistance(End) <= exitIntersectionProjection.LSDistance(End)) { return(new SafePathResult(false, allIntersections[0])); } } } if (IsSafe(ObjectManager.Player.ServerPosition.To2D())) { 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.LSDistance(End) / SpellData.MissileSpeed) - (Environment.TickCount - StartTick); Vector2 myPositionWhenExplodes = path.PositionAfter(timeToExplode, speed, delay); if (!IsSafe(myPositionWhenExplodes)) { return(new SafePathResult(false, allIntersections[0])); } Vector2 myPositionWhenExplodesWithOffset = path.PositionAfter(timeToExplode, speed, timeOffset); return(new SafePathResult(IsSafe(myPositionWhenExplodesWithOffset), allIntersections[0])); }