internal static PredictionOutput WayPointAnalysis(PredictionOutput result, PredictionInput input) { if (!(input.Unit is AIHeroClient && input.Unit.IsValid) || input.Radius == 1) { result.Hitchance = HitChance.VeryHigh; return result; } //Program.debug("PRED: FOR CHAMPION " + input.Unit.BaseSkinName); // CAN'T MOVE SPELLS /////////////////////////////////////////////////////////////////////////////////// if (UnitTracker.GetSpecialSpellEndTime(input.Unit) > 0 || input.Unit.HasBuff("Recall")) { result.Hitchance = HitChance.VeryHigh; return result; } // PREPARE MATH /////////////////////////////////////////////////////////////////////////////////// result.Hitchance = HitChance.High; var lastWaypiont = input.Unit.GetWaypoints().Last(); var distanceUnitToWaypoint = lastWaypiont.Distance(input.Unit.ServerPosition); var distanceFromToUnit = input.From.Distance(input.Unit.ServerPosition); var distanceFromToWaypoint = lastWaypiont.Distance(input.From); float speedDelay = distanceFromToUnit / input.Speed; if (Math.Abs(input.Speed - float.MaxValue) < float.Epsilon) speedDelay = 0; else speedDelay = distanceFromToUnit / input.Speed; float totalDelay = speedDelay + input.Delay; float moveArea = input.Unit.MoveSpeed * totalDelay; float fixRange = moveArea * 0.5f; double angleMove = 30 + (input.Radius / 17) - (totalDelay * 2); float backToFront = moveArea * 1.5f; float pathMinLen = 900f; if (angleMove < 31) angleMove = 31; if (UnitTracker.GetLastNewPathTime(input.Unit) < 0.1d) { pathMinLen = 600f + backToFront; result.Hitchance = HitChance.High; } if (input.Type == SkillshotType.SkillshotCircle) { fixRange -= input.Radius / 2; } // SPAM CLICK /////////////////////////////////////////////////////////////////////////////////// if (UnitTracker.PathCalc(input.Unit)) { Console.WriteLine("PRED: SPAM CLICK"); if (distanceFromToUnit < input.Range - fixRange) { result.Hitchance = HitChance.VeryHigh; return result; } result.Hitchance = HitChance.High; return result; } // NEW VISABLE /////////////////////////////////////////////////////////////////////////////////// if (UnitTracker.GetLastVisableTime(input.Unit) < 0.1d) { Console.WriteLine("PRED: NEW VISABLE"); result.Hitchance = HitChance.Medium; return result; } // SPECIAL CASES /////////////////////////////////////////////////////////////////////////////////// if (distanceFromToUnit < 300 || distanceFromToWaypoint < 200) { Console.WriteLine("PRED: SPECIAL CASES"); result.Hitchance = HitChance.VeryHigh; return result; } // LONG CLICK DETECTION /////////////////////////////////////////////////////////////////////////////////// if (distanceUnitToWaypoint > pathMinLen) { Console.WriteLine("PRED: LONG CLICK DETECTION"); result.Hitchance = HitChance.VeryHigh; return result; } // RUN IN LANE DETECTION /////////////////////////////////////////////////////////////////////////////////// if (distanceFromToWaypoint > fixRange && GetAngle(input.From, input.Unit) < angleMove) { Console.WriteLine(GetAngle(input.From, input.Unit) + " PRED: RUN IN LANE DETECTION " + angleMove); result.Hitchance = HitChance.VeryHigh; return result; } // FIX RANGE /////////////////////////////////////////////////////////////////////////////////// if (distanceFromToWaypoint <= input.Unit.Distance(input.From) && distanceFromToUnit > input.Range - fixRange) { //debug("PRED: FIX RANGE"); result.Hitchance = HitChance.Medium; return result; } // AUTO ATTACK LOGIC /////////////////////////////////////////////////////////////////////////////////// if (UnitTracker.GetLastAutoAttackTime(input.Unit) < 0.1d) { 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; Console.WriteLine("PRED: AUTO ATTACK DETECTION"); return result; } // STOP LOGIC /////////////////////////////////////////////////////////////////////////////////// else { if (input.Unit.Spellbook.IsAutoAttacking || input.Unit.Spellbook.IsChanneling || input.Unit.Spellbook.IsCharging) { result.Hitchance = HitChance.High; return result; } else if (input.Unit.Path.Count() == 0 && !input.Unit.IsMoving) { if (distanceFromToUnit > input.Range - fixRange) result.Hitchance = HitChance.Medium; else if (UnitTracker.GetLastStopMoveTime(input.Unit) < 0.8d) result.Hitchance = HitChance.High; else result.Hitchance = HitChance.VeryHigh; Console.WriteLine("PRED: STOP LOGIC"); return result; } } // ANGLE HIT CHANCE /////////////////////////////////////////////////////////////////////////////////// if (input.Type == SkillshotType.SkillshotLine && input.Unit.Path.Count() > 0 && input.Unit.IsMoving) { if (UnitTracker.GetLastNewPathTime(input.Unit) < 0.1d && GetAngle(input.From, input.Unit) < angleMove && distanceUnitToWaypoint > moveArea * 0.6) { Console.WriteLine("PRED: ANGLE HIT CHANCE " + angleMove + " > " + GetAngle(input.From, input.Unit)); result.Hitchance = HitChance.VeryHigh; return result; } } // CIRCLE NEW PATH /////////////////////////////////////////////////////////////////////////////////// if (input.Type == SkillshotType.SkillshotCircle) { if (UnitTracker.GetLastNewPathTime(input.Unit) < 0.1d && distanceUnitToWaypoint > fixRange && distanceFromToUnit < input.Range - fixRange && distanceUnitToWaypoint > fixRange) { Console.WriteLine("PRED: CIRCLE NEW PATH"); result.Hitchance = HitChance.VeryHigh; return result; } } //Program.debug("PRED: NO DETECTION"); return result; }
internal static PredictionOutput GetDashingPrediction(PredictionInput input) { var dashData = Dash.GetDashInfo(input.Unit); 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.GetPathLength() > 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; }