internal static PredictionOutput GetPrediction(PredictionInput input, bool ft, bool checkCollision) { PredictionOutput result = null; if (!input.Unit.IsValidTarget(float.MaxValue, false)) { return(new PredictionOutput()); } if (ft) { //Increase the delay due to the latency and server tick: input.Delay += Game.Ping / 2000f + 0.06f; if (input.Aoe) { return(AoePrediction.GetPrediction(input)); } } //Target too far away. if (Math.Abs(input.Range - float.MaxValue) > float.Epsilon && input.Unit.Distance(input.RangeCheckFrom, true) > Math.Pow(input.Range * 1.5, 2)) { return(new PredictionOutput { Input = input }); } //Unit is dashing. if (input.Unit.IsDashing()) { result = GetDashingPrediction(input); } else { //Unit is immobile. var remainingImmobileT = UnitIsImmobileUntil(input.Unit); if (remainingImmobileT >= 0d) { result = GetImmobilePrediction(input, remainingImmobileT); } } //Normal prediction if (result == null) { result = GetStandardPrediction(input); } //Check if the unit position is in range if (Math.Abs(input.Range - float.MaxValue) > float.Epsilon) { if (result.Hitchance >= HitChance.High && input.RangeCheckFrom.Distance(input.Unit.Position, true) > Math.Pow(input.Range + input.RealRadius * 3 / 4, 2)) { result.Hitchance = HitChance.Medium; } if (input.RangeCheckFrom.Distance(result.UnitPosition, true) > Math.Pow(input.Range + (input.Type == SkillshotType.SkillshotCircle ? input.RealRadius : 0), 2)) { result.Hitchance = HitChance.OutOfRange; } if (input.RangeCheckFrom.Distance(result.CastPosition, true) > Math.Pow(input.Range, 2)) { if (result.Hitchance != HitChance.OutOfRange) { result.CastPosition = input.RangeCheckFrom + input.Range * (result.UnitPosition - input.RangeCheckFrom).To2D().Normalized().To3D(); } else { result.Hitchance = HitChance.OutOfRange; } } } //Check for collision if (checkCollision && input.Collision) { var positions = new List <Vector3> { result.UnitPosition, result.CastPosition, input.Unit.Position }; var originalUnit = input.Unit; result.CollisionObjects = Collision.GetCollision(positions, input); result.CollisionObjects.RemoveAll(x => x.NetworkId == originalUnit.NetworkId); result.Hitchance = result.CollisionObjects.Count > 0 ? HitChance.Collision : result.Hitchance; } return(result); }