/// <summary> /// Returns the list of the units that the skillshot will hit before reaching the set positions. /// </summary> public static List <Obj_AI_Base> GetCollision(List <Vector3> positions, PredictionInput input) { var result = new List <Obj_AI_Base>(); foreach (var position in positions) { foreach (var objectType in input.CollisionObjects) { switch (objectType) { case CollisionableObjects.Minions: foreach (var minion in ObjectManager.Get <Obj_AI_Minion>() .Where( minion => minion.IsValidTarget( Math.Min(input.Range + input.Radius + 100, 2000), true, input.RangeCheckFrom))) { input.Unit = minion; var minionPrediction = Prediction.GetPrediction(input, false, false); if ( minionPrediction.UnitPosition.To2D() .Distance(input.From.To2D(), position.To2D(), true, true) <= Math.Pow((input.Radius + 15 + minion.BoundingRadius), 2)) { result.Add(minion); } } break; case CollisionableObjects.Heroes: foreach (var hero in HeroManager.Enemies.FindAll( hero => hero.IsValidTarget( Math.Min(input.Range + input.Radius + 100, 2000), true, input.RangeCheckFrom)) ) { input.Unit = hero; var prediction = Prediction.GetPrediction(input, false, false); if ( prediction.UnitPosition.To2D() .Distance(input.From.To2D(), position.To2D(), true, true) <= Math.Pow((input.Radius + 50 + hero.BoundingRadius), 2)) { result.Add(hero); } } break; case CollisionableObjects.Walls: var step = position.Distance(input.From) / 20; for (var i = 0; i < 20; i++) { var p = input.From.To2D().Extend(position.To2D(), step * i); if (NavMesh.GetCollisionFlags(p.X, p.Y).HasFlag(CollisionFlags.Wall)) { result.Add(ObjectManager.Player); } } break; case CollisionableObjects.YasuoWall: if (Utils.TickCount - _wallCastT > 4000) { break; } GameObject wall = null; foreach (var gameObject in ObjectManager.Get <GameObject>() .Where( gameObject => gameObject.IsValid && Regex.IsMatch( gameObject.Name, "_w_windwall_enemy_0.\\.troy", RegexOptions.IgnoreCase)) ) { wall = gameObject; } if (wall == null) { break; } var level = wall.Name.Substring(wall.Name.Length - 6, 1); var wallWidth = (300 + 50 * Convert.ToInt32(level)); var wallDirection = (wall.Position.To2D() - _yasuoWallCastedPos).Normalized().Perpendicular(); var wallStart = wall.Position.To2D() + wallWidth / 2f * wallDirection; var wallEnd = wallStart - wallWidth * wallDirection; if (wallStart.Intersection(wallEnd, position.To2D(), input.From.To2D()).Intersects) { var t = Utils.TickCount + (wallStart.Intersection(wallEnd, position.To2D(), input.From.To2D()) .Point.Distance(input.From) / input.Speed + input.Delay) * 1000; if (t < _wallCastT + 4000) { result.Add(ObjectManager.Player); } } break; } } } return(result.Distinct().ToList()); }
public static PredictionOutput GetPrediction(PredictionInput input) { var mainTargetPrediction = Prediction.GetPrediction(input, false, true); var posibleTargets = new List <PossibleTarget> { new PossibleTarget { Position = mainTargetPrediction.UnitPosition.To2D(), Unit = input.Unit } }; if (mainTargetPrediction.Hitchance >= HitChance.Medium) { //Add the posible targets in range: posibleTargets.AddRange(GetPossibleTargets(input)); } if (posibleTargets.Count > 1) { var candidates = new List <Vector2>(); foreach (var target in posibleTargets) { var targetCandidates = GetCandidates( input.From.To2D(), target.Position, (input.Radius), input.Range); candidates.AddRange(targetCandidates); } var bestCandidateHits = -1; var bestCandidate = new Vector2(); var bestCandidateHitPoints = new List <Vector2>(); var positionsList = posibleTargets.Select(t => t.Position).ToList(); foreach (var candidate in candidates) { if ( GetHits( input.From.To2D(), candidate, (input.Radius + input.Unit.BoundingRadius / 3 - 10), new List <Vector2> { posibleTargets[0].Position }).Count() == 1) { var hits = GetHits(input.From.To2D(), candidate, input.Radius, positionsList).ToList(); var hitsCount = hits.Count; if (hitsCount >= bestCandidateHits) { bestCandidateHits = hitsCount; bestCandidate = candidate; bestCandidateHitPoints = hits.ToList(); } } } if (bestCandidateHits > 1) { float maxDistance = -1; Vector2 p1 = new Vector2(), p2 = new Vector2(); //Center the position for (var i = 0; i < bestCandidateHitPoints.Count; i++) { for (var j = 0; j < bestCandidateHitPoints.Count; j++) { var startP = input.From.To2D(); var endP = bestCandidate; var proj1 = positionsList[i].ProjectOn(startP, endP); var proj2 = positionsList[j].ProjectOn(startP, endP); var dist = Vector2.DistanceSquared(bestCandidateHitPoints[i], proj1.LinePoint) + Vector2.DistanceSquared(bestCandidateHitPoints[j], proj2.LinePoint); if (dist >= maxDistance && (proj1.LinePoint - positionsList[i]).AngleBetween( proj2.LinePoint - positionsList[j]) > 90) { maxDistance = dist; p1 = positionsList[i]; p2 = positionsList[j]; } } } return(new PredictionOutput { Hitchance = mainTargetPrediction.Hitchance, _aoeTargetsHitCount = bestCandidateHits, UnitPosition = mainTargetPrediction.UnitPosition, CastPosition = ((p1 + p2) * 0.5f).To3D(), Input = input }); } } return(mainTargetPrediction); }
public static PredictionOutput GetPrediction(PredictionInput input) { var mainTargetPrediction = Prediction.GetStandardPrediction(input);//Prediction.GetPrediction(input, false, true); var posibleTargets = new List <PossibleTarget> { new PossibleTarget { Position = mainTargetPrediction.UnitPosition.To2D(), Unit = input.Unit } }; // Console.WriteLine(posibleTargets.First().Unit.Name); if (mainTargetPrediction.Hitchance >= HitChance.Medium) { //Add the posible targets in range: posibleTargets.AddRange(GetPossibleTargets(input)); } if (posibleTargets.Count > 1) { var candidates = new List <Vector2>(); foreach (var target in posibleTargets) { target.Position = target.Position - input.From.To2D(); } for (var i = 0; i < posibleTargets.Count; i++) { for (var j = 0; j < posibleTargets.Count; j++) { if (i != j) { var p = (posibleTargets[i].Position + posibleTargets[j].Position) * 0.5f; if (!candidates.Contains(p)) { candidates.Add(p); } } } } var bestCandidateHits = -1; var bestCandidate = new Vector2(); var positionsList = posibleTargets.Select(t => t.Position).ToList(); foreach (var candidate in candidates) { var hits = GetHits(candidate, input.Range, input.Radius, positionsList); if (hits > bestCandidateHits) { bestCandidate = candidate; bestCandidateHits = hits; } } if (bestCandidateHits > 1 && input.From.To2D().Distance(bestCandidate, true) > 50 * 50) { return(new PredictionOutput { Hitchance = mainTargetPrediction.Hitchance, _aoeTargetsHitCount = bestCandidateHits, UnitPosition = mainTargetPrediction.UnitPosition, CastPosition = (bestCandidate + input.From.To2D()).To3D(), Input = input }); } } return(mainTargetPrediction); }
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.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 && false) { 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 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); }
public static PredictionOutput GetPrediction(PredictionInput input) { return(GetPrediction(input, true, true)); }