internal static Vector2[] GetCandidates(Vector2 from, Vector2 to, float radius, float range) { var middlePoint = (from + to) / 2; var intersections = Geometry2.CircleCircleIntersection( from, middlePoint, radius, from.Distance7(middlePoint)); if (intersections.Length > 1) { var c1 = intersections[0]; var c2 = intersections[1]; c1 = from + range * (to - c1).Normalized2(); c2 = from + range * (to - c2).Normalized2(); return(new[] { c1, c2 }); } return(new Vector2[] { }); }
internal static PredictionOutput GetPositionOnPath(PredictionInput input, List <Vector2> path, float speed = -1) { speed = (Math.Abs(speed - (-1)) < float.Epsilon) ? input.Unit.MoveSpeed : speed; if (path.Count <= 1) { return(new PredictionOutput { Input = input, UnitPosition = input.Unit.ServerPosition, CastPosition = input.Unit.ServerPosition, Hitchance = HitChance.VeryHigh }); } var pLength = path.PathLength(); //Skillshots with only a delay if (pLength >= input.Delay * speed - input.RealRadius && Math.Abs(input.Speed - float.MaxValue) < float.Epsilon) { var tDistance = input.Delay * speed - input.RealRadius; for (var i = 0; i < path.Count - 1; i++) { var a = path[i]; var b = path[i + 1]; var d = a.Distance7(b); if (d >= tDistance) { var direction = (b - a).Normalized2(); var cp = a + direction * tDistance; var p = a + direction * ((i == path.Count - 2) ? Math.Min(tDistance + input.RealRadius, d) : (tDistance + input.RealRadius)); return(new PredictionOutput { Input = input, CastPosition = cp.To3D(), UnitPosition = p.To3D(), Hitchance = PathTracker.GetCurrentPath(input.Unit).Time < 0.1d ? HitChance.VeryHigh : HitChance.High }); } tDistance -= d; } } //Skillshot with a delay and speed. if (pLength >= input.Delay * speed - input.RealRadius && Math.Abs(input.Speed - float.MaxValue) > float.Epsilon) { var d = input.Delay * speed - input.RealRadius; if (input.Type == SkillshotType.SkillshotLine || input.Type == SkillshotType.SkillshotCone) { if (input.From.Distance6(input.Unit.ServerPosition, true) < 200 * 200) { d = input.Delay * speed; } } path = path.CutPath(d); var tT = 0f; for (var i = 0; i < path.Count - 1; i++) { var a = path[i]; var b = path[i + 1]; var tB = a.Distance7(b) / speed; var direction = (b - a).Normalized2(); a = a - speed * tT * direction; var sol = Geometry2.VectorMovementCollision(a, b, speed, input.From.To2D2(), input.Speed, tT); var t = (float)sol[0]; var pos = (Vector2)sol[1]; if (pos.IsValid() && t >= tT && t <= tT + tB) { if (pos.Distance7(b, true) < 20) { break; } var p = pos + input.RealRadius * direction; if (input.Type == SkillshotType.SkillshotLine && false) { var alpha = (input.From.To2D2() - p).AngleBetween2(a - b); if (alpha > 30 && alpha < 180 - 30) { var beta = (float)Math.Asin(input.RealRadius / p.Distance8(input.From)); var cp1 = input.From.To2D2() + (p - input.From.To2D2()).Rotated2(beta); var cp2 = input.From.To2D2() + (p - input.From.To2D2()).Rotated2(-beta); pos = cp1.Distance7(pos, true) < cp2.Distance7(pos, true) ? cp1 : cp2; } } return(new PredictionOutput { Input = input, CastPosition = pos.To3D(), UnitPosition = p.To3D(), Hitchance = PathTracker.GetCurrentPath(input.Unit).Time < 0.1d ? HitChance.VeryHigh : HitChance.High }); } tT += tB; } } var position = path.Last(); return(new PredictionOutput { Input = input, CastPosition = position.To3D(), UnitPosition = position.To3D(), Hitchance = HitChance.Medium }); }