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 && input.Speed == float.MaxValue) { 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.Distance(b); if (d >= tDistance) { var direction = (b - a).Normalized(); 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) { path = path.CutPath(Math.Max(0, input.Delay * speed - input.RealRadius)); var tT = 0f; for (var i = 0; i < path.Count - 1; i++) { var a = path[i]; var b = path[i + 1]; var tB = a.Distance(b) / speed; var direction = (b - a).Normalized(); a = a - speed * tT * direction; var sol = Geometry.VectorMovementCollision(a, b, speed, input.From.To2D(), input.Speed, tT); var t = (float)sol[0]; var pos = (Vector2)sol[1]; if (pos.IsValid() && t >= tT && t <= tT + tB) { var p = pos + input.RealRadius * direction; if (input.Type == SkillshotType.SkillshotLine) { var alpha = (input.From.To2D() - p).AngleBetween(a - b); if (alpha > 30 && alpha < 180 - 30) { var beta = (float)Math.Asin(input.RealRadius / p.Distance(input.From)); var cp1 = input.From.To2D() + (p - input.From.To2D()).Rotated(beta); var cp2 = input.From.To2D() + (p - input.From.To2D()).Rotated(-beta); pos = cp1.Distance(pos, true) < cp2.Distance(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, }); }
internal static PredictionOutput GetStandardPrediction(PredictionInput input) { var speed = input.Unit.MoveSpeed; if (input.Unit.Distance(input.From, true) < 200 * 200) { //input.Delay /= 2; speed /= 1.5f; } var result = GetPositionOnPath(input, input.Unit.GetWaypoints(), speed); // Fill with bro science if (result.Hitchance >= HitChance.Medium && input.Unit is Obj_AI_Hero) { if (input.Unit.HasBuffOfType(BuffType.Slow) || input.Unit.Distance(input.From) < 300) { result.Hitchance = HitChance.VeryHigh; } if (input.Type == SkillshotType.SkillshotLine) { if (PathTracker.GetAngle(input.From, input.Unit) < 31 + 1) { result.Hitchance = HitChance.VeryHigh; } } else if (input.Type == SkillshotType.SkillshotCircle) { if (input.Delay < 0.35 && (PathTracker.GetCurrentPath(input.Unit).Time < 0.1d || input.Unit.IsWindingUp)) { result.Hitchance = HitChance.VeryHigh; } } var totalDelay = input.From.Distance(input.Unit.ServerPosition) / input.Speed + input.Delay; var fixRange = (input.Unit.MoveSpeed * totalDelay) / 2; var LastWaypiont = input.Unit.GetWaypoints().Last().To3D(); if (input.Unit.Path.Count() == 0 && input.Unit.Position == input.Unit.ServerPosition) { if (input.From.Distance(input.Unit.ServerPosition) < input.Range - fixRange) { result.Hitchance = HitChance.VeryHigh; } else { result.Hitchance = HitChance.High; } } else if (LastWaypiont.Distance(input.From) <= input.Unit.Distance(input.From)) { if (input.From.Distance(input.Unit.ServerPosition) < input.Range - fixRange) { result.Hitchance = HitChance.VeryHigh; } else { result.Hitchance = HitChance.High; } } if (LastWaypiont.Distance(input.Unit.ServerPosition) > 700) { if (input.From.Distance(input.Unit.ServerPosition) < input.Range - fixRange) { result.Hitchance = HitChance.VeryHigh; } } } return(result); }
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 && input.Speed == float.MaxValue) { var tDistance = input.Delay * speed - input.RealRadius; return(new PredictionOutput { Input = input, CastPosition = path.PCutPath(tDistance).Item1.To3D(), UnitPosition = path.PCutPath(tDistance + input.RealRadius).Item1.To3D(), Hitchance = PathTracker.GetCurrentPath(input.Unit).Time < 0.1d ? HitChance.VeryHigh : HitChance.High }); } //Skillshot with a delay and speed. if (pLength >= input.Delay * speed - input.RealRadius && input.Speed != float.MaxValue) { var path2 = new List <Vector2>(); path2.AddRange(path); path2[0] = path[0] + input.RealRadius * (path[0] - path[1]); var pp = CalcPositionOnPath(path, speed, input.Speed, input.From.To2D(), input.Delay, 6); var cpp = CalcPositionOnPath(path2, speed, input.Speed, input.From.To2D(), input.Delay, 6); if (cpp.Item3) { return(new PredictionOutput { Input = input, CastPosition = cpp.Item1.To3D(), UnitPosition = pp.Item1.To3D(), Hitchance = PathTracker.GetCurrentPath(input.Unit).Time < 0.1d ? HitChance.VeryHigh : HitChance.High }); } } var position = path.Last(); return(new PredictionOutput { Input = input, CastPosition = position.To3D(), UnitPosition = position.To3D(), Hitchance = HitChance.Medium }); }