private static PredictionOutput GetDashingPrediction(this PredictionInput input) { var dashData = input.Unit.GetDashInfo(); var result = new PredictionOutput { Input = input }; if (!dashData.IsBlink) { var endP = dashData.Path.Last(); var dashPred = input.GetPositionOnPath( new List<Vector2> { input.Unit.ServerPosition.ToVector2(), endP }, dashData.Speed); if (dashPred.Hitchance >= HitChance.High && dashPred.UnitPosition.ToVector2().Distance(input.Unit.Position.ToVector2(), endP, true) < 200) { dashPred.CastPosition = dashPred.UnitPosition; dashPred.Hitchance = HitChance.Dashing; return dashPred; } if (dashData.Path.PathLength() > 200) { var timeToPoint = input.Delay / 2 + input.From.Distance(endP) / input.Speed - 0.25; if (timeToPoint <= input.Unit.Distance(endP) / dashData.Speed + input.RealRadius / input.Unit.MoveSpeed) { return new PredictionOutput { CastPosition = endP.ToVector3(), UnitPosition = endP.ToVector3(), Hitchance = HitChance.Dashing }; } } result.CastPosition = dashData.Path.Last().ToVector3(); result.UnitPosition = result.CastPosition; } return result; }
/// <summary> /// Returns Calculated Prediction based off given data values. /// </summary> /// <param name="input"> /// <see cref="PredictionInput" /> input /// </param> /// <param name="ft">Add Delay</param> /// <param name="checkCollision">Check Collision</param> /// <returns> /// <see cref="PredictionOutput" /> output /// </returns> internal static PredictionOutput GetPrediction(PredictionInput input, bool ft, bool checkCollision) { if (!input.Unit.LSIsValidTarget(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 (Math.Abs(input.Range - float.MaxValue) > float.Epsilon && input.Unit.LSDistanceSquared(input.RangeCheckFrom) > Math.Pow(input.Range * 1.5, 2)) { return(new PredictionOutput { Input = input }); } PredictionOutput result = null; // 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.LSDistanceSquared(input.Unit.Position) > Math.Pow(input.Range + input.RealRadius * 3 / 4, 2)) { result.Hitchance = HitChance.Medium; } if (input.RangeCheckFrom.LSDistanceSquared(result.UnitPosition) > Math.Pow(input.Range + (input.Type == SkillshotType.SkillshotCircle ? input.RealRadius : 0), 2)) { result.Hitchance = HitChance.OutOfRange; } if (input.RangeCheckFrom.LSDistanceSquared(result.CastPosition) > Math.Pow(input.Range, 2) && result.Hitchance != HitChance.OutOfRange) { result.CastPosition = input.RangeCheckFrom + input.Range * (result.UnitPosition - input.RangeCheckFrom).ToVector2() .LSNormalized() .ToVector3(); } } // Check for collision if (checkCollision && input.Collision && Math.Abs(input.Speed - float.MaxValue) > float.Epsilon) { var positions = new List <Vector3> { result.UnitPosition, input.Unit.Position }; result.CollisionObjects = Collision.GetCollision(positions, input); result.CollisionObjects.RemoveAll(x => x.Compare(input.Unit)); if (result.CollisionObjects.Count > 0) { result.Hitchance = HitChance.Collision; } } // Calc hitchance again if (result.Hitchance == HitChance.High) { result.Hitchance = GetHitChance(input); } return(result); }
/// <summary> /// Returns Immobile Prediction /// </summary> /// <param name="input"> /// <see cref="PredictionInput" /> input /// </param> /// <param name="remainingImmobileT">Remaining Immobile Time</param> /// <returns><see cref="PredictionOutput" /> output</returns> internal static PredictionOutput GetImmobilePrediction(PredictionInput input, double remainingImmobileT) { var result = new PredictionOutput { Input = input, CastPosition = input.Unit.ServerPosition, UnitPosition = input.Unit.ServerPosition, Hitchance = HitChance.High }; var timeToReachTargetPosition = input.Delay + (Math.Abs(input.Speed - float.MaxValue) > float.Epsilon ? input.Unit.Distance(input.From) / input.Speed : 0); if (timeToReachTargetPosition <= remainingImmobileT + input.RealRadius / input.Unit.MoveSpeed) { result.UnitPosition = input.Unit.Position; result.Hitchance = HitChance.Immobile; } return result; }
/// <summary> /// Returns Dashing Prediction /// </summary> /// <param name="input"> /// <see cref="PredictionInput" /> input /// </param> /// <returns><see cref="PredictionOutput" /> output</returns> internal static PredictionOutput GetDashingPrediction(PredictionInput input) { var dashData = input.Unit.GetDashInfo(); var result = new PredictionOutput { Input = input, Hitchance = HitChance.Medium }; // Normal dashes. if (!dashData.IsBlink) { var endP = dashData.EndPos.ToVector3(); // Mid air: var dashPred = GetPositionOnPath( input, new List<Vector3> { input.Unit.ServerPosition, endP }.ToVector2(), dashData.Speed); if (dashPred.Hitchance >= HitChance.High && dashPred.UnitPosition.ToVector2() .Distance(input.Unit.Position.ToVector2(), endP.ToVector2(), true) < 200) { dashPred.CastPosition = dashPred.UnitPosition; dashPred.Hitchance = HitChance.Dashing; return dashPred; } // At the end of the dash: if (dashData.Path.LSPathLength() > 200) { var timeToPoint = input.Delay / 2f + (Math.Abs(input.Speed - float.MaxValue) > float.Epsilon ? input.From.Distance(endP) / input.Speed : 0) - 0.25f; if (timeToPoint <= input.Unit.Distance(endP) / dashData.Speed + input.RealRadius / input.Unit.MoveSpeed) { return new PredictionOutput { Input = input, CastPosition = endP, UnitPosition = endP, Hitchance = HitChance.Dashing }; } } result.CastPosition = endP; result.UnitPosition = result.CastPosition; // Figure out where the unit is going. } return result; }
/// <summary> /// Returns Dashing Prediction /// </summary> /// <param name="input"> /// <see cref="PredictionInput" /> input /// </param> /// <returns><see cref="PredictionOutput" /> output</returns> internal static PredictionOutput GetDashingPrediction(PredictionInput input) { var dashData = input.Unit.GetDashInfo(); var result = new PredictionOutput { Input = input }; input.Delay += 0.1f; // Normal dashes. if (!dashData.IsBlink) { // Mid air: var dashPred = GetPositionOnPath( input, new List<Vector2> { input.Unit.ServerPosition.ToVector2(), dashData.Path.Last() }, dashData.Speed); if (dashPred.Hitchance >= HitChance.High) { dashPred.CastPosition = dashPred.UnitPosition; dashPred.Hitchance = HitChance.Dashing; return dashPred; } // At the end of the dash: if (dashData.Path.PathLength() > 200) { var endP = dashData.Path.Last(); var timeToPoint = input.Delay + (input.From.Distance(endP) / input.Speed); if (timeToPoint <= (input.Unit.Distance(endP) / dashData.Speed) + (input.RealRadius / input.Unit.MoveSpeed)) { return new PredictionOutput { CastPosition = endP.ToVector3(), UnitPosition = endP.ToVector3(), Hitchance = HitChance.Dashing }; } } result.CastPosition = dashData.Path.Last().ToVector3(); result.UnitPosition = result.CastPosition; // Figure out where the unit is going. } return result; }
private static PredictionOutput WayPointAnalysis(this PredictionInput input, PredictionOutput result) { var heroUnit = input.Unit as Obj_AI_Hero; if (heroUnit == null || input.Radius.Equals(1)) { result.Hitchance = HitChance.VeryHigh; return result; } /*if (UnitTracker.GetLastSpecialSpellTime(heroUnit) > 0 || heroUnit.IsRecalling()) { result.Hitchance = HitChance.VeryHigh; return result; } var lastWaypoint = heroUnit.GetWaypoints().Last(); var distUnitToWaypoint = heroUnit.Distance(lastWaypoint); var distFromToWaypoint = input.From.Distance(lastWaypoint); var distUnitToFrom = heroUnit.Distance(input.From); var speedDelay = distUnitToFrom / input.Speed; if (Math.Abs(input.Speed - float.MaxValue) < float.Epsilon) { speedDelay = 0; } var totalDelay = speedDelay + input.Delay; var moveArea = heroUnit.MoveSpeed * totalDelay; var fixRange = moveArea * 0.5f; var moveAngle = 30 + input.Radius / 17 - totalDelay * 2; var minPath = 900f; if (moveAngle < 31) { moveAngle = 31; } if (input.Type == SkillshotType.SkillshotCircle) { fixRange -= input.Radius / 2; } if (UnitTracker.CanCalcWaypoints(heroUnit)) { result.Hitchance = distUnitToFrom < input.Range - fixRange ? HitChance.VeryHigh : HitChance.High; return result; } if (UnitTracker.GetLastVisableTime(heroUnit) < 0.1) { result.Hitchance = HitChance.Medium; return result; } if (distUnitToFrom < 300 || distFromToWaypoint < 200) { result.Hitchance = HitChance.VeryHigh; return result; } if (distUnitToWaypoint > minPath) { result.Hitchance = HitChance.VeryHigh; return result; } if (distFromToWaypoint > fixRange && input.From.GetAngle(heroUnit) < moveAngle) { result.Hitchance = HitChance.VeryHigh; return result; } if (distFromToWaypoint <= distUnitToFrom && distUnitToFrom > input.Range - fixRange) { result.Hitchance = HitChance.Medium; return result; } if (UnitTracker.GetLastAttackTime(heroUnit) < 0.1) { if (input.Type == SkillshotType.SkillshotLine && totalDelay < 0.6 + input.Radius * 0.001) { result.Hitchance = HitChance.VeryHigh; } else if (input.Type == SkillshotType.SkillshotCircle && totalDelay < 0.7 + input.Radius * 0.001) { result.Hitchance = HitChance.VeryHigh; } else { result.Hitchance = HitChance.High; } return result; } if (heroUnit.IsWindingUp) { result.Hitchance = HitChance.High; return result; } if (heroUnit.Path.Length == 0 && !heroUnit.IsMoving) { if (distUnitToFrom > input.Range - fixRange) { result.Hitchance = HitChance.Medium; } else if (UnitTracker.GetLastStopMoveTime(heroUnit) > 0.8) { result.Hitchance = HitChance.High; } else { result.Hitchance = HitChance.VeryHigh; } return result; } if (input.Type == SkillshotType.SkillshotLine && heroUnit.Path.Length > 0 && heroUnit.IsMoving && GamePath.PathTracker.GetCurrentPath(heroUnit).Time < 0.1 && input.From.GetAngle(heroUnit) < moveAngle && distUnitToWaypoint > moveArea * 0.6) { result.Hitchance = HitChance.VeryHigh; return result; } if (input.Type == SkillshotType.SkillshotCircle && GamePath.PathTracker.GetCurrentPath(heroUnit).Time < 0.1 && distUnitToWaypoint > fixRange && distUnitToFrom < input.Range - fixRange) { result.Hitchance = HitChance.VeryHigh; return result; }*/ return result; }
private static PredictionOutput WayPointAnalysis(this PredictionInput input, PredictionOutput result) { var heroUnit = input.Unit as Obj_AI_Hero; if (heroUnit == null || input.Radius.Equals(1)) { result.Hitchance = HitChance.VeryHigh; return result; } if (UnitTracker.GetLastSpecialSpellTime(heroUnit) > 0 || heroUnit.IsRecalling()) { result.Hitchance = HitChance.VeryHigh; return result; } if (UnitTracker.GetLastVisableTime(heroUnit) < 0.1) { result.Hitchance = HitChance.Medium; return result; } result.Hitchance = HitChance.Medium; var lastWaypoint = heroUnit.GetWaypoints().Last(); var distUnitToWaypoint = heroUnit.Distance(lastWaypoint); var distFromToWaypoint = input.From.Distance(lastWaypoint); var distUnitToFrom = heroUnit.Distance(input.From); var angle = input.From.GetAngle(heroUnit); var speedDelay = distUnitToFrom / input.Speed; if (Math.Abs(input.Speed - float.MaxValue) < float.Epsilon) { speedDelay = 0; } var totalDelay = speedDelay + input.Delay; var moveArea = heroUnit.MoveSpeed * totalDelay; var fixRange = moveArea * 0.4f; var minPath = 900 + moveArea; var moveAngle = Math.Max(30 + input.Radius / 17d - totalDelay - input.Delay * 2, 31); if (GamePath.PathTracker.GetCurrentPath(heroUnit).Time < 0.1) { result.Hitchance = HitChance.High; fixRange = moveArea * 0.3f; minPath = 600 + moveArea; moveAngle += 2; } if (input.Type == SkillshotType.SkillshotCircle) { fixRange -= input.Radius / 2; } if (distFromToWaypoint <= distUnitToFrom && distUnitToFrom > input.Range - fixRange) { result.Hitchance = HitChance.Medium; return result; } if (UnitTracker.CanCalcWaypoints(heroUnit)) { result.Hitchance = HitChance.VeryHigh; return result; } if (UnitTracker.SpamSamePlace(heroUnit)) { result.Hitchance = HitChance.VeryHigh; return result; } if (distUnitToFrom < 250 || heroUnit.MoveSpeed < 200 || distFromToWaypoint < 100) { result.Hitchance = HitChance.VeryHigh; return result; } if (distUnitToWaypoint > minPath) { result.Hitchance = HitChance.VeryHigh; return result; } if (angle < moveAngle) { if (distUnitToWaypoint > fixRange && GamePath.PathTracker.GetCurrentPath(heroUnit).Time < 0.1) { result.Hitchance = HitChance.VeryHigh; return result; } if (Program.Player.IsMoving && (Program.Player.IsFacing(heroUnit) ? !heroUnit.IsFacing(Program.Player) : heroUnit.IsFacing(Program.Player))) { result.Hitchance = HitChance.VeryHigh; return result; } } if (UnitTracker.GetLastAttackTime(heroUnit) < 0.1) { if (input.Type == SkillshotType.SkillshotLine && totalDelay < 0.4 + input.Radius * 0.002) { result.Hitchance = HitChance.VeryHigh; return result; } if (input.Type == SkillshotType.SkillshotCircle && totalDelay < 0.6 + input.Radius * 0.002) { result.Hitchance = HitChance.VeryHigh; return result; } result.Hitchance = HitChance.High; } else if (heroUnit.Path.Length == 0 || !heroUnit.IsMoving) { if (heroUnit.IsWindingUp) { result.Hitchance = HitChance.High; } else if (UnitTracker.GetLastStopMoveTime(heroUnit) < 0.5) { result.Hitchance = HitChance.High; } else { result.Hitchance = HitChance.VeryHigh; } return result; } if (input.Type == SkillshotType.SkillshotCircle && GamePath.PathTracker.GetCurrentPath(heroUnit).Time < 0.1 && distUnitToWaypoint > fixRange) { result.Hitchance = HitChance.VeryHigh; } return result; }
/// <summary> /// Returns Calculated Prediction based off given data values. /// </summary> /// <param name="input"> /// <see cref="PredictionInput" /> input /// </param> /// <param name="ft">Add Delay</param> /// <param name="checkCollision">Check Collision</param> /// <returns> /// <see cref="PredictionOutput" /> output /// </returns> internal static PredictionOutput GetPrediction(PredictionInput input, bool ft, bool checkCollision) { if (!input.Unit.IsValidTarget(float.MaxValue, false)) { return(new PredictionOutput()); } if (ft) { input.Delay += Game.Ping / 2000f + 0.05f; if (input.AoE) { return(Cluster.GetAoEPrediction(input)); } } // Target too far away. if (Math.Abs(input.Range - float.MaxValue) > float.Epsilon && input.Unit.DistanceSquared(input.RangeCheckFrom) > Math.Pow(input.Range * 1.5, 2)) { return(new PredictionOutput { Input = input }); } PredictionOutput result = null; // 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); } if (!((Player.Instance).Distance(input.Unit, true) < input.Range * input.Range)) { result.Hitchance = HitChance.OutOfRange; } // Check for collision if (checkCollision && input.Collision && Math.Abs(input.Speed - float.MaxValue) > float.Epsilon) { var positions = new List <Vector3> { result.UnitPosition, input.Unit.Position }; result.CollisionObjects = Collision.GetCollision(positions, input); result.CollisionObjects.RemoveAll(x => x.Compare(input.Unit)); if (result.CollisionObjects.Count > 0) { result.Hitchance = HitChance.Collision; } } // Calc hitchance again if (result.Hitchance == HitChance.High) { result.Hitchance = GetHitChance(input); } return(result); }
public static PredictionOutput GetBadaoPrediction(this Spell spell, Obj_AI_Base target, bool collideyasuowall = true) { PredictionOutput result = null; if (!target.IsValidTarget(float.MaxValue, false)) { return new PredictionOutput(); } if (target.IsDashing()) { var dashDtata = target.GetDashInfo(); result = spell.GetBadaoStandarPrediction(target, new List<Vector2>() { target.ServerPosition.ToVector2(), dashDtata.Path.Last() }, dashDtata.Speed); if (result.Hitchance >= HitChance.High) result.Hitchance = HitChance.Dashing; } else { //Unit is immobile. var remainingImmobileT = UnitIsImmobileUntil(target); if (remainingImmobileT >= 0d) { var timeToReachTargetPosition = spell.Delay + target.Position.ToVector2().Distance(spell.From.ToVector2()) / spell.Speed; if (spell.RangeCheckFrom.ToVector2().Distance(target.Position.ToVector2()) <= spell.Range) { if (timeToReachTargetPosition <= remainingImmobileT + (target.BoundingRadius + spell.Width - 40) / target.MoveSpeed) { result = new PredictionOutput { CastPosition = target.ServerPosition, UnitPosition = target.ServerPosition, Hitchance = HitChance.Immobile }; } else result = new PredictionOutput { CastPosition = target.ServerPosition, UnitPosition = target.ServerPosition, Hitchance = HitChance.High /*timeToReachTargetPosition - remainingImmobileT + input.RealRadius / input.Unit.MoveSpeed < 0.4d ? HitChance.High : HitChance.Medium*/ }; } else { result = new PredictionOutput(); } } } //Normal prediction if (result == null) { result = spell.GetBadaoStandarPrediction(target, target.GetWaypoints()); } //Check for collision if (spell.Collision) { var positions = new List<Vector3> { result.UnitPosition, result.CastPosition, target.Position }; var originalUnit = target; result.CollisionObjects = spell.GetCollision(positions); result.CollisionObjects.RemoveAll(x => x.NetworkId == originalUnit.NetworkId); result.Hitchance = result.CollisionObjects.Count > 0 ? HitChance.Collision : result.Hitchance; } //Check yasuo wall collision else if (collideyasuowall) { var positions = new List<Vector3> { result.UnitPosition, result.CastPosition, target.Position }; var originalUnit = target; result.CollisionObjects = spell.GetCollision(positions); result.CollisionObjects.Any(x => x.NetworkId == ObjectManager.Player.NetworkId); result.Hitchance = result.CollisionObjects.Any(x => x.NetworkId == ObjectManager.Player.NetworkId) ? HitChance.Collision : result.Hitchance; } return result; }