internal static PredictionOutput GetDashingPrediction(PredictionInput input) { var dashData = input.Unit.GetDashInfo(); var result = new PredictionOutput { Input = input }; //Normal dashes. if (!dashData.IsBlink) { //Mid air: var endP = dashData.Path.Last(); var dashPred = GetPositionOnPath( input, new List<Vector2> { input.Unit.ServerPosition.To2D(), endP }, dashData.Speed); if (dashPred.Hitchance >= HitChance.High && dashPred.UnitPosition.To2D().Distance(input.Unit.Position.To2D(), endP, true) < 200) { dashPred.CastPosition = dashPred.UnitPosition; dashPred.Hitchance = HitChance.Dashing; return dashPred; } //At the end of the dash: if (dashData.Path.PathLength() > 200) { var timeToPoint = input.Delay / 2f + input.From.To2D().Distance(endP) / input.Speed - 0.25f; if (timeToPoint <= input.Unit.Distance(endP) / dashData.Speed + input.RealRadius / input.Unit.MoveSpeed) { return new PredictionOutput { CastPosition = endP.To3D(), UnitPosition = endP.To3D(), Hitchance = HitChance.Dashing }; } } result.CastPosition = dashData.Path.Last().To3D(); result.UnitPosition = result.CastPosition; //Figure out where the unit is going. } return result; }
internal static PredictionOutput WayPointAnalysis(PredictionOutput result, PredictionInput input) { if (!input.Unit.IsValid() || input.Radius == 1) { result.Hitchance = HitChance.VeryHigh; return result; } // CAN'T MOVE SPELLS /////////////////////////////////////////////////////////////////////////////////// if (UnitTracker.GetSpecialSpellEndTime(input.Unit) > 100 || input.Unit.HasBuff("Recall") || (UnitTracker.GetLastStopMoveTime(input.Unit) < 100 && input.Unit.IsRooted)) { debug("CAN'T MOVE SPELLS"); result.Hitchance = HitChance.VeryHigh; result.CastPosition = input.Unit.Position; return result; } // NEW VISABLE /////////////////////////////////////////////////////////////////////////////////// if (UnitTracker.GetLastVisableTime(input.Unit) < 100) { debug("PRED: NEW VISABLE"); result.Hitchance = HitChance.Medium; return result; } // PREPARE MATH /////////////////////////////////////////////////////////////////////////////////// result.Hitchance = HitChance.Medium; var lastWaypiont = input.Unit.GetWaypoints().Last().To3D(); var distanceUnitToWaypoint = lastWaypiont.Distance(input.Unit.ServerPosition); var distanceFromToUnit = input.From.Distance(input.Unit.ServerPosition); var distanceFromToWaypoint = lastWaypiont.Distance(input.From); var getAngle = GetAngle(input.From, input.Unit); float speedDelay = distanceFromToUnit / input.Speed; if (Math.Abs(input.Speed - float.MaxValue) < float.Epsilon) speedDelay = 0; float totalDelay = speedDelay + input.Delay; float moveArea = input.Unit.MoveSpeed * totalDelay; float fixRange = moveArea * 0.35f; float pathMinLen = 800 + moveArea; double angleMove = 32; if (input.Type == SkillshotType.SkillshotCircle) { fixRange -= input.Radius / 2; } // FIX RANGE /////////////////////////////////////////////////////////////////////////////////// if (distanceFromToWaypoint <= distanceFromToUnit) { if (distanceFromToUnit > input.Range - fixRange) { result.Hitchance = HitChance.Medium; return result; } } var points = CirclePoints(15, 450, input.Unit.Position).Where(x => x.IsWall()); if (points.Count() > 2) { var runOutWall = true; foreach (var point in points) { if (input.Unit.Position.Distance(point) > lastWaypiont.Distance(point)) { runOutWall = false; } } if (runOutWall) { debug("PRED: RUN OUT WALL"); result.Hitchance = HitChance.VeryHigh; return result; } } if (input.Unit.GetWaypoints().Count == 1) { if (UnitTracker.GetLastStopMoveTime(input.Unit) < 600) { //OktwCommon.debug("PRED: STOP HIGH"); result.Hitchance = HitChance.High; return result; } else { debug("PRED: STOP LOGIC"); result.Hitchance = HitChance.VeryHigh; } } // SPAM POSITION /////////////////////////////////////////////////////////////////////////////////// if (UnitTracker.SpamSamePlace(input.Unit)) { debug("PRED: SPAM POSITION"); result.Hitchance = HitChance.VeryHigh; return result; } // SPECIAL CASES /////////////////////////////////////////////////////////////////////////////////// if (distanceFromToUnit < 250) { debug("PRED: SPECIAL CASES NEAR"); result.Hitchance = HitChance.VeryHigh; return result; } else if (input.Unit.MoveSpeed < 250) { debug("PRED: SPECIAL CASES SLOW"); result.Hitchance = HitChance.VeryHigh; return result; } else if (distanceFromToWaypoint < 250) { debug("PRED: SPECIAL CASES ON WAY"); result.Hitchance = HitChance.VeryHigh; return result; } // LONG CLICK DETECTION /////////////////////////////////////////////////////////////////////////////////// if (distanceUnitToWaypoint > pathMinLen) { debug("PRED: LONG CLICK DETECTION"); result.Hitchance = HitChance.VeryHigh; return result; } // LOW HP DETECTION /////////////////////////////////////////////////////////////////////////////////// if (input.Unit.HealthPercent < 20 || ObjectManager.Player.HealthPercent < 20) { result.Hitchance = HitChance.VeryHigh; return result; } // RUN IN LANE DETECTION /////////////////////////////////////////////////////////////////////////////////// if (getAngle < angleMove && UnitTracker.GetLastNewPathTime(input.Unit) < 100) { debug(GetAngle(input.From, input.Unit) + " PRED: ANGLE " + angleMove + " DIS " + distanceUnitToWaypoint); result.Hitchance = HitChance.VeryHigh; return result; } // CIRCLE NEW PATH /////////////////////////////////////////////////////////////////////////////////// if (input.Type == SkillshotType.SkillshotCircle) { if (UnitTracker.GetLastNewPathTime(input.Unit) < 100 && distanceUnitToWaypoint > fixRange) { debug("PRED: CIRCLE NEW PATH"); result.Hitchance = HitChance.VeryHigh; return result; } } //Program.debug("PRED: NO DETECTION"); return result; }