/// <summary> /// Gets Prediction result /// </summary> /// <param name="target">Target for spell</param> /// <param name="width">Spell width</param> /// <param name="delay">Spell delay</param> /// <param name="missileSpeed">Spell missile speed</param> /// <param name="range">Spell range</param> /// <param name="collisionable">Spell collisionable</param> /// <param name="type">Spell skillshot type</param> /// <param name="path">Waypoints of target</param> /// <param name="avgt">Average reaction time (in ms)</param> /// <param name="movt">Passed time from last movement change (in ms)</param> /// <param name="avgp">Average Path Lenght</param> /// <param name="from">Spell casted position</param> /// <param name="rangeCheckFrom"></param> /// <returns>Prediction result as <see cref="Prediction.Result"/></returns> public static Prediction.Result GetPrediction(Obj_AI_Base target, float width, float delay, float missileSpeed, float range, bool collisionable, List <Vector2> path, float avgt, float movt, float avgp, Vector2 from, Vector2 rangeCheckFrom) { return(Prediction.GetPrediction(target, width, delay, missileSpeed, range, collisionable, SkillshotType.SkillshotLine, path, avgt, movt, avgp, from, rangeCheckFrom)); }
/// <summary> /// Gets Prediction result /// </summary> /// <param name="target">Target for spell</param> /// <param name="width">Spell width</param> /// <param name="delay">Spell delay</param> /// <param name="missileSpeed">Spell missile speed</param> /// <param name="range">Spell range</param> /// <param name="collisionable">Spell collisionable</param> /// <param name="type">Spell skillshot type</param> /// <param name="path">Waypoints of target</param> /// <param name="avgt">Average reaction time (in ms)</param> /// <param name="movt">Passed time from last movement change (in ms)</param> /// <param name="avgp">Average Path Lenght</param> /// <param name="from">Spell casted position</param> /// <param name="rangeCheckFrom"></param> /// <returns>Prediction result as <see cref="Prediction.Result"/></returns> internal static Result GetPrediction(Obj_AI_Base target, float width, float delay, float missileSpeed, float range, bool collisionable, SkillshotType type, List <Vector2> path, float avgt, float movt, float avgp, Vector2 from, Vector2 rangeCheckFrom) { Prediction.AssertInitializationMode(); Result result = new Result(); try { if (type == SkillshotType.SkillshotCircle) { range += width; } //to do: hook logic ? by storing average movement direction etc if (path.Count <= 1 && movt > 100 && (Environment.TickCount - PathTracker.EnemyInfo[target.NetworkId].LastAATick > 300 || !predMenu.Item("SPREDWINDUP").GetValue <bool>())) //if target is not moving, easy to hit (and not aaing) { result.HitChance = HitChance.VeryHigh; result.CastPosition = target.ServerPosition.To2D(); result.UnitPosition = result.CastPosition; result.CollisionResult = Collision.GetCollisions(from, result.CastPosition, width, delay, missileSpeed); if (collisionable && (result.CollisionResult.Objects.HasFlag(Collision.Flags.Minions) || result.CollisionResult.Objects.HasFlag(Collision.Flags.YasuoWall))) { result.HitChance = HitChance.Collision; } if (from.Distance(result.CastPosition) > range - GetArrivalTime(from.Distance(result.CastPosition), delay, missileSpeed) * target.MoveSpeed * (100 - predMenu.Item("SPREDMAXRANGEIGNORE").GetValue <Slider>().Value) / 100f) { result.HitChance = HitChance.OutOfRange; } return(result); } if (target is AIHeroClient) { if (((AIHeroClient)target).IsChannelingImportantSpell()) { result.HitChance = HitChance.VeryHigh; result.CastPosition = target.ServerPosition.To2D(); result.UnitPosition = result.CastPosition; result.CollisionResult = Collision.GetCollisions(from, result.CastPosition, width, delay, missileSpeed); //check collisions if (collisionable && (result.CollisionResult.Objects.HasFlag(Collision.Flags.Minions) || result.CollisionResult.Objects.HasFlag(Collision.Flags.YasuoWall))) { result.HitChance = HitChance.Collision; } //check if target can dodge with moving backward if (from.Distance(result.CastPosition) > range - GetArrivalTime(from.Distance(result.CastPosition), delay, missileSpeed) * target.MoveSpeed * (100 - predMenu.Item("SPREDMAXRANGEIGNORE").GetValue <Slider>().Value) / 100f) { result.HitChance = HitChance.OutOfRange; } return(result); } if (Environment.TickCount - PathTracker.EnemyInfo[target.NetworkId].LastAATick < 300 && predMenu.Item("SPREDWINDUP").GetValue <bool>()) { if (target.AttackCastDelay * 1000 + PathTracker.EnemyInfo[target.NetworkId].AvgOrbwalkTime + avgt - width / 2f / target.MoveSpeed >= GetArrivalTime(target.ServerPosition.To2D().Distance(from), delay, missileSpeed)) { result.HitChance = HitChance.High; result.CastPosition = target.ServerPosition.To2D(); result.UnitPosition = result.CastPosition; result.CollisionResult = Collision.GetCollisions(from, result.CastPosition, width, delay, missileSpeed); //check collisions if (collisionable && (result.CollisionResult.Objects.HasFlag(Collision.Flags.Minions) || result.CollisionResult.Objects.HasFlag(Collision.Flags.YasuoWall))) { result.HitChance = HitChance.Collision; } return(result); } } //to do: find a fuking logic if (avgp < 400 && movt < 100 && path.PathLength() <= avgp) { result.HitChance = HitChance.High; result.CastPosition = path.Last(); result.UnitPosition = result.CastPosition; result.CollisionResult = Collision.GetCollisions(from, result.CastPosition, width, delay, missileSpeed); //check collisions if (collisionable && (result.CollisionResult.Objects.HasFlag(Collision.Flags.Minions) || result.CollisionResult.Objects.HasFlag(Collision.Flags.YasuoWall))) { result.HitChance = HitChance.Collision; } //check if target can dodge with moving backward if (from.Distance(result.CastPosition) > range - GetArrivalTime(from.Distance(result.CastPosition), delay, missileSpeed) * target.MoveSpeed * (100 - predMenu.Item("SPREDMAXRANGEIGNORE").GetValue <Slider>().Value) / 100f) { result.HitChance = HitChance.OutOfRange; } return(result); } } if (target.IsDashing()) //if unit is dashing { return(GetDashingPrediction(target, width, delay, missileSpeed, range, collisionable, type, from)); } if (Utility.IsImmobileTarget(target)) //if unit is immobile { return(GetImmobilePrediction(target, width, delay, missileSpeed, range, collisionable, type, from)); } result = WaypointAnlysis(target, width, delay, missileSpeed, range, collisionable, type, path, avgt, movt, avgp, from); //check collisions if (collisionable && (result.CollisionResult.Objects.HasFlag(Collision.Flags.Minions) || result.CollisionResult.Objects.HasFlag(Collision.Flags.YasuoWall))) { result.HitChance = HitChance.Collision; } //check if target can dodge with moving backward if (from.Distance(result.CastPosition) > range - GetArrivalTime(from.Distance(result.CastPosition), delay, missileSpeed) * target.MoveSpeed * (100 - predMenu.Item("SPREDMAXRANGEIGNORE").GetValue <Slider>().Value) / 100f) { result.HitChance = HitChance.OutOfRange; } return(result); } finally { //check if movement changed while prediction calculations if (!target.GetWaypoints().SequenceEqual(path)) { result.HitChance = HitChance.Medium; } } }
/// <summary> /// Gets prediction result /// </summary> /// <param name="target">Target</param> /// <param name="width">Vector width</param> /// <param name="delay">Spell delay</param> /// <param name="vectorSpeed">Vector speed</param> /// <param name="range">Spell range</param> /// <param name="vectorLenght">Vector lenght</param> /// <param name="path">Waypoints of target</param> /// <param name="avgt">Average reaction time (in ms)</param> /// <param name="movt">Passed time from last movement change (in ms)</param> /// <param name="avgp">Average Path Lenght</param> /// <param name="rangeCheckFrom"></param> /// <returns>Prediction result as <see cref="Prediction.Vector.Result"/></returns> public static Result GetPrediction(Obj_AI_Base target, float width, float delay, float vectorSpeed, float range, float vectorLenght, List <Vector2> path, float avgt, float movt, float avgp, Vector2 rangeCheckFrom) { Prediction.AssertInitializationMode(); Result result = new Result(); Vector2 immobileFrom = rangeCheckFrom + (target.ServerPosition.To2D() - rangeCheckFrom).Normalized() * range; if (path.Count <= 1) //if target is not moving, easy to hit { result.HitChance = HitChance.VeryHigh; result.CastTargetPosition = target.ServerPosition.To2D(); result.UnitPosition = result.CastTargetPosition; result.CollisionResult = Collision.GetCollisions(immobileFrom, result.CastTargetPosition, width, delay, vectorSpeed); if (immobileFrom.Distance(result.CastTargetPosition) > vectorLenght - Prediction.GetArrivalTime(immobileFrom.Distance(result.CastTargetPosition), delay, vectorSpeed) * target.MoveSpeed) { result.HitChance = HitChance.OutOfRange; } return(result); } if (target is AIHeroClient) { if (((AIHeroClient)target).IsChannelingImportantSpell()) { result.HitChance = HitChance.VeryHigh; result.CastTargetPosition = target.ServerPosition.To2D(); result.UnitPosition = result.CastTargetPosition; result.CollisionResult = Collision.GetCollisions(immobileFrom, result.CastTargetPosition, width, delay, vectorSpeed); //check if target can dodge with moving backward if (immobileFrom.Distance(result.CastTargetPosition) > range - Prediction.GetArrivalTime(immobileFrom.Distance(result.CastTargetPosition), delay, vectorSpeed) * target.MoveSpeed) { result.HitChance = HitChance.OutOfRange; } return(result); } //to do: find a fuking logic if (avgp < 400 && movt < 100) { result.HitChance = HitChance.High; result.CastTargetPosition = target.ServerPosition.To2D(); result.UnitPosition = result.CastTargetPosition; result.CollisionResult = Collision.GetCollisions(immobileFrom, result.CastTargetPosition, width, delay, vectorSpeed); //check if target can dodge with moving backward if (immobileFrom.Distance(result.CastTargetPosition) > range - Prediction.GetArrivalTime(immobileFrom.Distance(result.CastTargetPosition), delay, vectorSpeed) * target.MoveSpeed) { result.HitChance = HitChance.OutOfRange; } return(result); } } if (target.IsDashing()) { return(Prediction.GetDashingPrediction(target, width, delay, vectorSpeed, range, false, SkillshotType.SkillshotLine, immobileFrom).AsVectorResult(immobileFrom)); } if (SPrediction.Utility.IsImmobileTarget(target)) { return(Prediction.GetImmobilePrediction(target, width, delay, vectorSpeed, range, false, SkillshotType.SkillshotLine, immobileFrom).AsVectorResult(immobileFrom)); } for (int i = 0; i < path.Count - 1; i++) { Vector2 point = Geometry.ClosestCirclePoint(rangeCheckFrom, range, path[i], path[i + 1]); Prediction.Result res = Prediction.WaypointAnlysis(target, width, delay, vectorSpeed, vectorLenght, false, SkillshotType.SkillshotLine, path, avgt, movt, avgp, point); if (res.HitChance >= HitChance.Low) { return(res.AsVectorResult(point)); } } result.CastSourcePosition = immobileFrom; result.CastTargetPosition = target.ServerPosition.To2D(); result.HitChance = HitChance.Impossible; return(result); }
/// <summary> /// Gets Aoe Prediction result /// </summary> /// <param name="width">Spell width</param> /// <param name="delay">Spell delay</param> /// <param name="vectorSpeed">Vector speed</param> /// <param name="range">Spell range</param> /// <param name="vectorLenght">Vector lenght</param> /// <param name="rangeCheckFrom"></param> /// <returns>Prediction result as <see cref="Prediction.AoeResult"/></returns> public static AoeResult GetAoePrediction(float width, float delay, float vectorSpeed, float range, float vectorLenght, Vector2 rangeCheckFrom) { AoeResult result = new AoeResult(); var enemies = HeroManager.Enemies.Where(p => p.IsValidTarget() && Prediction.GetFastUnitPosition(p, delay, 0, rangeCheckFrom).Distance(rangeCheckFrom) < range); foreach (AIHeroClient enemy in enemies) { List <Vector2> path = enemy.GetWaypoints(); if (path.Count <= 1) { Vector2 from = rangeCheckFrom + (enemy.ServerPosition.To2D() - rangeCheckFrom).Normalized() * range; Vector2 to = from + (enemy.ServerPosition.To2D() - from).Normalized() * vectorLenght; Collision.Result colResult = Collision.GetCollisions(from, to, width, delay, vectorSpeed); if (colResult.Objects.HasFlag(Collision.Flags.EnemyChampions)) { int collisionCount = colResult.Units.Count(p => p.IsEnemy && p.IsChampion()); if (collisionCount > result.HitCount) { result = new AoeResult { CastSourcePosition = from, CastTargetPosition = enemy.ServerPosition.To2D(), HitCount = collisionCount, CollisionResult = colResult }; } } } else { if (!enemy.IsDashing()) { for (int i = 0; i < path.Count - 1; i++) { Vector2 point = Geometry.ClosestCirclePoint(rangeCheckFrom, range, path[i], path[i + 1]); Prediction.Result prediction = Prediction.GetPrediction(enemy, width, delay, vectorSpeed, vectorLenght, false, SkillshotType.SkillshotLine, path, enemy.AvgMovChangeTime(), enemy.LastMovChangeTime(), enemy.AvgPathLenght(), point, rangeCheckFrom); if (prediction.HitChance > HitChance.Medium) { Vector2 to = point + (prediction.CastPosition - point).Normalized() * vectorLenght; Collision.Result colResult = Collision.GetCollisions(point, to, width, delay, vectorSpeed, false); if (colResult.Objects.HasFlag(Collision.Flags.EnemyChampions)) { int collisionCount = colResult.Units.Count(p => p.IsEnemy && p.IsChampion()); if (collisionCount > result.HitCount) { result = new AoeResult { CastSourcePosition = point, CastTargetPosition = prediction.CastPosition, HitCount = collisionCount, CollisionResult = colResult }; } } } } } } } return(result); }
public static float AvgMovChangeTime(this AIHeroClient t) { Prediction.AssertInitializationMode(); return(PathTracker.EnemyInfo[t.NetworkId].AvgTick + Prediction.IgnoreReactionDelay); }
public static float AvgPathLenght(this AIHeroClient t) { Prediction.AssertInitializationMode(); return(PathTracker.EnemyInfo[t.NetworkId].AvgPathLenght); }
public static int LastMovChangeTime(this AIHeroClient t) { Prediction.AssertInitializationMode(); return(Environment.TickCount - PathTracker.EnemyInfo[t.NetworkId].LastWaypointTick); }
public static int MovImmobileTime(this AIHeroClient t) { Prediction.AssertInitializationMode(); return(PathTracker.EnemyInfo[t.NetworkId].IsStopped ? Environment.TickCount - PathTracker.EnemyInfo[t.NetworkId].StopTick : 0); }
/// <summary> /// Gets collided units & flags /// </summary> /// <param name="from">Start position</param> /// <param name="to">End position</param> /// <param name="width">Rectangle scale</param> /// <param name="delay">Spell delay</param> /// <param name="missileSpeed">Spell missile speed</param> /// <returns>Collision result as <see cref="Collision.Result"/></returns> public static Result GetCollisions(Vector2 from, Vector2 to, float width, float delay, float missileSpeed = 0, bool isArc = false) { List <Obj_AI_Base> collidedUnits = new List <Obj_AI_Base>(); var spellHitBox = ClipperWrapper.MakePaths(ClipperWrapper.DefineRectangle(from, to, width)); if (isArc) { spellHitBox = ClipperWrapper.MakePaths(new MidlaneSharp.Geometry.Polygon( ClipperWrapper.DefineArc(from - new Vector2(875 / 2f, 20), to, (float)Math.PI * (to.Distance(from) / 875f), 410, 200 * (to.Distance(from) / 875f)), ClipperWrapper.DefineArc(from - new Vector2(875 / 2f, 20), to, (float)Math.PI * (to.Distance(from) / 875f), 410, 320 * (to.Distance(from) / 875f)))); } Flags _colFlags = Flags.None; var collidedMinions = MinionManager.GetMinions(from.Distance(to) + 250, MinionTypes.All, MinionTeam.NotAlly, MinionOrderTypes.None).AsParallel().Where(p => ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(ClipperWrapper.DefineCircle(Prediction.GetFastUnitPosition(p, delay, missileSpeed), p.BoundingRadius + 10)), spellHitBox)); var collidedEnemies = HeroManager.Enemies.AsParallel().Where(p => ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(ClipperWrapper.DefineCircle(Prediction.GetFastUnitPosition(p, delay, missileSpeed), p.BoundingRadius)), spellHitBox)); var collidedAllies = HeroManager.Allies.AsParallel().Where(p => ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(ClipperWrapper.DefineCircle(Prediction.GetFastUnitPosition(p, delay, missileSpeed), p.BoundingRadius)), spellHitBox)); if (collidedMinions != null && collidedMinions.Count() != 0) { collidedUnits.AddRange(collidedMinions); _colFlags |= Flags.Minions; } if (collidedEnemies != null && collidedEnemies.Count() != 0) { collidedUnits.AddRange(collidedEnemies); _colFlags |= Flags.EnemyChampions; } if (collidedAllies != null && collidedAllies.Count() != 0) { collidedUnits.AddRange(collidedAllies); _colFlags |= Flags.AllyChampions; } if (CheckWallCollision(from, to)) { _colFlags |= Flags.Wall; } if (CheckYasuoWallCollision(from, to, width)) { _colFlags |= Flags.YasuoWall; } return(new Result(collidedUnits, _colFlags)); }
/// <summary> /// Checks enemy hero collisions /// </summary> /// <param name="from">Start position</param> /// <param name="to">End position</param> /// <param name="width">Rectangle scale</param> /// <param name="delay">Spell delay</param> /// <param name="missileSpeed">Spell missile speed</param> /// <param name="isArc">Checks collision for arc spell</param> /// <returns>true if collision found</returns> public static bool CheckAllyHeroCollision(Vector2 from, Vector2 to, float width, float delay, float missileSpeed = 0, bool isArc = false) { var spellHitBox = ClipperWrapper.MakePaths(ClipperWrapper.DefineRectangle(from, to, width)); if (isArc) { spellHitBox = ClipperWrapper.MakePaths(new MidlaneSharp.Geometry.Polygon( ClipperWrapper.DefineArc(from - new Vector2(875 / 2f, 20), to, (float)Math.PI * (to.Distance(from) / 875f), 410, 200 * (to.Distance(from) / 875f)), ClipperWrapper.DefineArc(from - new Vector2(875 / 2f, 20), to, (float)Math.PI * (to.Distance(from) / 875f), 410, 320 * (to.Distance(from) / 875f)))); } return(HeroManager.Allies.AsParallel().Any(p => ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(ClipperWrapper.DefineCircle(Prediction.GetFastUnitPosition(p, delay, missileSpeed), p.BoundingRadius)), spellHitBox))); }
/// <summary> /// Gets Aoe Prediction result /// </summary> /// <param name="width">Spell width</param> /// <param name="delay">Spell delay</param> /// <param name="missileSpeed">Spell missile speed</param> /// <param name="range">Spell range</param> /// <param name="from">Spell casted position</param> /// <param name="rangeCheckFrom"></param> /// <returns>Prediction result as <see cref="Prediction.AoeResult"/></returns> public static Prediction.AoeResult GetAoePrediction(float width, float delay, float missileSpeed, float range, Vector2 from, Vector2 rangeCheckFrom) { Prediction.AoeResult result = new Prediction.AoeResult(); result.HitCount = 0; var enemies = HeroManager.Enemies.Where(p => p.IsValidTarget() && Prediction.GetFastUnitPosition(p, delay, 0, from).Distance(rangeCheckFrom) < range); foreach (AIHeroClient enemy in enemies) { Prediction.Result prediction = GetPrediction(enemy, width, delay, missileSpeed, range, false, enemy.GetWaypoints(), enemy.AvgMovChangeTime(), enemy.LastMovChangeTime(), enemy.AvgPathLenght(), from, rangeCheckFrom); if (prediction.HitChance > HitChance.Medium) { Vector2 to = from + (prediction.CastPosition - from).Normalized() * range; var spellHitBox = ClipperWrapper.DefineSector(from, to, width, range); var collidedEnemies = HeroManager.Enemies.AsParallel().Where(p => !ClipperWrapper.IsOutside(spellHitBox, Prediction.GetFastUnitPosition(p, delay, missileSpeed, from))); int collisionCount = collidedEnemies.Count(); if (collisionCount > result.HitCount) { result = prediction.ToAoeResult(collisionCount, new Collision.Result(collidedEnemies.ToList <Obj_AI_Base>(), Collision.Flags.EnemyChampions)); } } } return(result); }