/// <summary> /// Returns Calculated Prediction based off given data values. /// </summary> /// <param name="input"> /// <see cref="PredictionInput" /> /// </param> /// <param name="ft">Add Delay</param> /// <param name="checkCollision">Check Collision</param> /// <returns> /// <see cref="PredictionOutput" /> /// </returns> 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(Cluster.GetAoEPrediction(input)); } } //Target too far away. if (System.Math.Abs(input.Range - float.MaxValue) > float.Epsilon && input.Unit.DistanceSquared(input.RangeCheckFrom) > System.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 (System.Math.Abs(input.Range - float.MaxValue) > float.Epsilon) { if (result.Hitchance >= HitChance.High && input.RangeCheckFrom.DistanceSquared(input.Unit.Position) > System.Math.Pow(input.Range + input.RealRadius * 3 / 4, 2)) { result.Hitchance = HitChance.Medium; } if (input.RangeCheckFrom.DistanceSquared(result.UnitPosition) > System.Math.Pow( input.Range + (input.Type == SkillshotType.SkillshotCircle ? input.RealRadius : 0), 2)) { result.Hitchance = HitChance.OutOfRange; } if (input.RangeCheckFrom.DistanceSquared(result.CastPosition) > System.Math.Pow(input.Range, 2)) { if (result.Hitchance != HitChance.OutOfRange) { result.CastPosition = input.RangeCheckFrom + input.Range * (result.UnitPosition - input.RangeCheckFrom).Normalized().SetZ(); } 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); }