/// <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(), enemy.LastAngleDiff(), 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); }
/// <summary> /// Checks Yasuo wall collisions /// </summary> /// <param name="poly">Polygon to check collision</param> /// <returns>true if collision found</returns> public static bool CheckYasuoWallCollision(Geometry.Polygon spellHitBox) { if (Utils.TickCount - yasuoWallCastedTick > 4000) { return(false); } GameObject yasuoWall = ObjectManager.Get <GameObject>().Where(p => p.IsValid && Regex.IsMatch(p.Name, "_w_windwall_enemy_0.\\.troy", RegexOptions.IgnoreCase)).FirstOrDefault(); if (yasuoWall == null) { return(false); } Vector2 yasuoWallDirection = (yasuoWall.Position.To2D() - yasuoWallCastedPos).Normalized().Perpendicular(); float yasuoWallWidth = 300 + 50 * yasuoWallLevel; Vector2 yasuoWallStart = yasuoWall.Position.To2D() + yasuoWallWidth / 2f * yasuoWallDirection; Vector2 yasuoWallEnd = yasuoWallStart - yasuoWallWidth * yasuoWallDirection; Geometry.Polygon yasuoWallPoly = ClipperWrapper.DefineRectangle(yasuoWallStart, yasuoWallEnd, 5); return(ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(yasuoWallPoly), ClipperWrapper.MakePaths(spellHitBox))); }
/// <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) { Prediction.AssertInitializationMode(); Prediction.Result result = Prediction.GetPrediction(target, width, delay, missileSpeed, range, collisionable, SkillshotType.SkillshotCircle, path, avgt, movt, avgp, from, rangeCheckFrom); if (result.HitChance >= HitChance.Low && result.HitChance < HitChance.VeryHigh) { if (result.CastPosition.Distance(from) < 875.0f) { Vector2 direction = (result.CastPosition - from).Normalized(); result.CastPosition = from + direction * (875f + width / 2f); var targetHitBox = ClipperWrapper.DefineCircle(Prediction.GetFastUnitPosition(target, delay, missileSpeed, from), target.BoundingRadius); float multp = (result.CastPosition.Distance(from) / 875.0f); var arcHitBox = new SCommon.Maths.Geometry.Polygon( ClipperWrapper.DefineArc(from - new Vector2(875 / 2f, 20), result.CastPosition, (float)Math.PI * multp, 410, 200 * multp), ClipperWrapper.DefineArc(from - new Vector2(875 / 2f, 20), result.CastPosition, (float)Math.PI * multp, 410, 320 * multp)); if (ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(targetHitBox), ClipperWrapper.MakePaths(arcHitBox))) { result.HitChance = (HitChance)(result.HitChance + 1); } } } return(result); }
/// <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(); var enemies = HeroManager.Enemies.Where(p => p.IsValidTarget() && Prediction.GetFastUnitPosition(p, delay, 0, from).Distance(rangeCheckFrom) < range); foreach (Obj_AI_Hero 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) { float multp = (result.CastPosition.Distance(from) / 875.0f); var spellHitBox = new SCommon.Maths.Geometry.Polygon( ClipperWrapper.DefineArc(from - new Vector2(875 / 2f, 20), result.CastPosition, (float)Math.PI * multp, 410, 200 * multp), ClipperWrapper.DefineArc(from - new Vector2(875 / 2f, 20), result.CastPosition, (float)Math.PI * multp, 410, 320 * multp)); var collidedEnemies = HeroManager.Enemies.AsParallel().Where(p => ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(ClipperWrapper.DefineCircle(Prediction.GetFastUnitPosition(p, delay, missileSpeed), p.BoundingRadius)), ClipperWrapper.MakePaths(spellHitBox))); 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); }
/// <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, float anglediff, Vector2 from, Vector2 rangeCheckFrom) { Prediction.AssertInitializationMode(); Prediction.Result result = new Prediction.Result(); if (path.Count <= 1) //if target is not moving, easy to hit { result.HitChance = LeagueSharp.Common.HitChance.Immobile; result.CastPosition = target.ServerPosition.To2D(); result.UnitPosition = result.CastPosition; return(result); } if (target is AIHeroClient && ((AIHeroClient)target).IsChannelingImportantSpell()) { result.HitChance = LeagueSharp.Common.HitChance.Immobile; result.CastPosition = target.ServerPosition.To2D(); result.UnitPosition = result.CastPosition; return(result); } if (Utility.IsImmobileTarget(target)) { return(Prediction.GetImmobilePrediction(target, width, delay, missileSpeed, range, collisionable, SkillshotType.SkillshotCircle, from)); } if (target.IsDashing()) { return(Prediction.GetDashingPrediction(target, width, delay, missileSpeed, range, collisionable, SkillshotType.SkillshotCircle, from)); } float targetDistance = rangeCheckFrom.Distance(target.ServerPosition); float flyTime = 0f; if (missileSpeed != 0) { Vector2 Vt = (path[path.Count - 1] - path[0]).Normalized() * target.MoveSpeed; Vector2 Vs = (target.ServerPosition.To2D() - rangeCheckFrom).Normalized() * missileSpeed; Vector2 Vr = Vs - Vt; flyTime = targetDistance / Vr.Length(); if (path.Count > 5) { flyTime = targetDistance / missileSpeed; } } float t = flyTime + delay + Game.Ping / 2000f + Prediction.SpellDelay / 1000f; result.HitChance = Prediction.GetHitChance(t * 1000f, avgt, movt, avgp, anglediff); #region arc collision test if (result.HitChance > LeagueSharp.Common.HitChance.Low) { for (int i = 1; i < path.Count; i++) { Vector2 senderPos = rangeCheckFrom; Vector2 testPos = path[i]; float multp = (testPos.Distance(senderPos) / 875.0f); var dianaArc = new SCommon.Maths.Geometry.Polygon( ClipperWrapper.DefineArc(senderPos - new Vector2(875 / 2f, 20), testPos, (float)Math.PI * multp, 410, 200 * multp), ClipperWrapper.DefineArc(senderPos - new Vector2(875 / 2f, 20), testPos, (float)Math.PI * multp, 410, 320 * multp)); if (!ClipperWrapper.IsOutside(dianaArc, target.ServerPosition.To2D())) { result.HitChance = LeagueSharp.Common.HitChance.VeryHigh; result.CastPosition = testPos; result.UnitPosition = testPos; return(result); } } } #endregion return(CirclePrediction.GetPrediction(target, width, delay, missileSpeed, range, collisionable, path, avgt, movt, avgp, anglediff, from, rangeCheckFrom)); }
public void ExtendedQ() { var t = TargetSelector.GetTarget(1200f, TargetSelector.DamageType.Physical); if (t != null) { var enemyHitBox = ClipperWrapper.DefineCircle(LeagueSharp.Common.Geometry.PositionAfter(t.GetWaypoints(), 300, (int)t.MoveSpeed), t.BoundingRadius); var minions = MinionManager.GetMinions(Spells[Q].Range, MinionTypes.All, MinionTeam.NotAlly); foreach (var minion in minions) { var spellHitBox = ClipperWrapper.DefineRectangle(ObjectManager.Player.ServerPosition.To2D(), ObjectManager.Player.ServerPosition.To2D() + (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized() * 1200f, 60f); if (ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(enemyHitBox), ClipperWrapper.MakePaths(spellHitBox))) { Spells[Q].CastOnUnit(minion); return; } } } }
/// <summary> /// The thread which detects spell hits /// </summary> public void EvadeThread() { //TO DO: evade with targetted spells (jax, irelia, master etc..) DetectedSpellData dcspell; while (true) { try { if (m_spell_queue.TryDequeue(out dcspell)) { Vector2 my_pos = ObjectManager.Player.ServerPosition.To2D(); Vector2 sender_pos = dcspell.StartPosition; Vector2 end_pos = dcspell.EndPosition; Vector2 direction = (end_pos - sender_pos).Normalized(); if (sender_pos.Distance(end_pos) > dcspell.Spell.Range) { end_pos = sender_pos + direction * dcspell.Spell.Range; } Geometry.Polygon my_hitbox = ClipperWrapper.DefineRectangle(my_pos - 60, my_pos + 60, 60); Geometry.Polygon spell_hitbox = null; if (dcspell.Spell.IsSkillshot) { if (dcspell.Spell.Type == SkillshotType.SkillshotLine) { spell_hitbox = ClipperWrapper.DefineRectangle(sender_pos, end_pos, dcspell.Spell.Radius); } else if (dcspell.Spell.Type == SkillshotType.SkillshotCircle) { spell_hitbox = ClipperWrapper.DefineCircle(end_pos, dcspell.Spell.Radius); } else if (dcspell.Spell.Type == SkillshotType.SkillshotCone) { spell_hitbox = ClipperWrapper.DefineSector(sender_pos, end_pos - sender_pos, dcspell.Spell.Radius * (float)Math.PI / 180, dcspell.Spell.Range); } } //spells with arc if (dcspell.Spell.IsArc) { float mul = (end_pos.Distance(sender_pos) / (dcspell.Spell.Range - 20.0f)); spell_hitbox = new Geometry.Polygon( ClipperWrapper.DefineArc(sender_pos - dcspell.Spell.ArcData.Pos, end_pos, dcspell.Spell.ArcData.Angle * mul, dcspell.Spell.ArcData.Width, dcspell.Spell.ArcData.Height * mul), ClipperWrapper.DefineArc(sender_pos - dcspell.Spell.ArcData.Pos, end_pos, dcspell.Spell.ArcData.Angle * mul, dcspell.Spell.ArcData.Width, (dcspell.Spell.ArcData.Height + dcspell.Spell.ArcData.Radius) * mul), spell_hitbox); } if (spell_hitbox != null) { if (ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(my_hitbox), ClipperWrapper.MakePaths(spell_hitbox))) { OnSpellHitDetected(direction, ObjectManager.Player); } else { if (ObjectManager.Player.CharData.BaseSkinName == "Morgana" && shieldAlly != null && shieldAlly.Item("SHIELDENABLED").GetValue <bool>()) { var allies = ObjectManager.Player.GetAlliesInRange(EvadeSpell.Range).Where(p => !p.IsMe && shieldAlly.Item("shield" + p.ChampionName).GetValue <bool>()); if (allies != null) { foreach (Obj_AI_Base ally in allies) { Vector2 ally_pos = ally.ServerPosition.To2D(); Geometry.Polygon ally_hitbox = ClipperWrapper.DefineRectangle(ally_pos, ally_pos + 60, 60); if (ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(ally_hitbox), ClipperWrapper.MakePaths(spell_hitbox))) { OnSpellHitDetected(direction, ally); break; } } } } } } m_spell_pool.PutObject(dcspell); } } catch { } Thread.Sleep(1); } }
/// <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 SCommon.Maths.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 + 15)), 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> /// Check Yasuo wall collisions /// </summary> /// <param name="from">Start position</param> /// <param name="to">End position</param> /// <param name="width">Rectangle scale</param> /// <param name="isArc">Check collision for arc spell</param> /// <returns>true if collision found</returns> public static bool CheckYasuoWallCollision(Vector2 from, Vector2 to, float width, bool isArc = false) { if (Utils.TickCount - yasuoWallCastedTick > 4000) { return(false); } GameObject yasuoWall = ObjectManager.Get <GameObject>().Where(p => p.IsValid && Regex.IsMatch(p.Name, "_w_windwall_enemy_0.\\.troy", RegexOptions.IgnoreCase)).FirstOrDefault(); if (yasuoWall == null) { return(false); } Vector2 yasuoWallDirection = (yasuoWall.Position.To2D() - yasuoWallCastedPos).Normalized().Perpendicular(); float yasuoWallWidth = 300 + 50 * yasuoWallLevel; Vector2 yasuoWallStart = yasuoWall.Position.To2D() + yasuoWallWidth / 2f * yasuoWallDirection; Vector2 yasuoWallEnd = yasuoWallStart - yasuoWallWidth * yasuoWallDirection; Geometry.Polygon yasuoWallPoly = ClipperWrapper.DefineRectangle(yasuoWallStart, yasuoWallEnd, 5); Geometry.Polygon spellHitBox = ClipperWrapper.DefineRectangle(from, to, width); if (isArc) { spellHitBox = new SCommon.Maths.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(ClipperWrapper.IsIntersects(ClipperWrapper.MakePaths(yasuoWallPoly), ClipperWrapper.MakePaths(spellHitBox))); }
/// <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 SCommon.Maths.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))); }
private void BounceQ() { var minions = MinionManager.GetMinions(Spells[Q].Range, MinionTypes.All, MinionTeam.NotAlly).Where(p => !p.IsMoving); List <Obj_AI_Base> nonKillableMinions = new List <Obj_AI_Base>(); foreach (var minion in minions) { if (Spells[Q].IsKillable(minion)) //prio killable minions to deal more dmg { var hitbox1 = ClipperWrapper.DefineSector(minion.ServerPosition.To2D(), (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized(), 40, 500f); var hitbox2 = ClipperWrapper.DefineSector(minion.ServerPosition.To2D(), (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized(), 20, 500f); //var hitbox3 = ClipperWrapper.DefineSector(minion.ServerPosition.To2D(), (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized(), 110, 300f); //var hitbox4 = ClipperWrapper.DefineSector(minion.ServerPosition.To2D(), (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized(), 160, 150f); if (HeroManager.Enemies.Any(p => minion.Distance(ObjectManager.Player.ServerPosition.To2D()) < 500f && p.NetworkId == m_lastTarget.NetworkId && !hitbox1.IsOutside(SCommon.Prediction.Prediction.GetFastUnitPosition(p, 0.3f)))) { Spells[Q].CastOnUnit(minion); return; } else if (!ObjectManager.Get <Obj_AI_Base>().Any(p => p.IsValidTarget(1200f) && p.IsEnemy && !p.IsChampion() && !hitbox2.IsOutside(p.ServerPosition.To2D())) && HeroManager.Enemies.Any(p => minion.Distance(ObjectManager.Player.ServerPosition.To2D()) < 500f && (TargetSelector.SelectedTarget == null || TargetSelector.SelectedTarget.NetworkId == p.NetworkId) && !hitbox2.IsOutside(SCommon.Prediction.Prediction.GetFastUnitPosition(p, 0.3f)))) { Spells[Q].CastOnUnit(minion); return; } else if (!ObjectManager.Get <Obj_AI_Base>().Any(p => p.IsValidTarget(1200f) && p.IsEnemy && !p.IsChampion() && !hitbox1.IsOutside(p.ServerPosition.To2D())) && HeroManager.Enemies.Any(p => minion.Distance(ObjectManager.Player.ServerPosition.To2D()) < 500f && (TargetSelector.SelectedTarget == null || TargetSelector.SelectedTarget.NetworkId == p.NetworkId) && !hitbox1.IsOutside(SCommon.Prediction.Prediction.GetFastUnitPosition(p, 0.3f)))) { Spells[Q].CastOnUnit(minion); return; } } else { nonKillableMinions.Add(minion); } } foreach (var minion in nonKillableMinions) { var hitbox1 = ClipperWrapper.DefineSector(minion.ServerPosition.To2D(), (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized(), 40, 500f); var hitbox2 = ClipperWrapper.DefineSector(minion.ServerPosition.To2D(), (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized(), 20, 500f); //var hitbox3 = ClipperWrapper.DefineSector(minion.ServerPosition.To2D(), (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized(), 110, 300f); //var hitbox4 = ClipperWrapper.DefineSector(minion.ServerPosition.To2D(), (minion.ServerPosition.To2D() - ObjectManager.Player.ServerPosition.To2D()).Normalized(), 160, 150f); if (HeroManager.Enemies.Any(p => minion.Distance(ObjectManager.Player.ServerPosition.To2D()) < 300 && p.NetworkId == m_lastTarget.NetworkId && !hitbox1.IsOutside(SCommon.Prediction.Prediction.GetFastUnitPosition(p, 0.3f)))) { Spells[Q].CastOnUnit(minion); return; } else if (!ObjectManager.Get <Obj_AI_Base>().Any(p => p.IsValidTarget(1200f) && p.IsEnemy && !p.IsChampion() && !hitbox2.IsOutside(p.ServerPosition.To2D())) && HeroManager.Enemies.Any(p => minion.Distance(ObjectManager.Player.ServerPosition.To2D()) < 500f && (TargetSelector.SelectedTarget == null || TargetSelector.SelectedTarget.NetworkId == p.NetworkId) && !hitbox2.IsOutside(SCommon.Prediction.Prediction.GetFastUnitPosition(p, 0.3f)))) { Spells[Q].CastOnUnit(minion); return; } else if (!ObjectManager.Get <Obj_AI_Base>().Any(p => p.IsValidTarget(1200f) && p.IsEnemy && !p.IsChampion() && !hitbox1.IsOutside(p.ServerPosition.To2D())) && HeroManager.Enemies.Any(p => minion.Distance(ObjectManager.Player.ServerPosition.To2D()) < 500f && (TargetSelector.SelectedTarget == null || TargetSelector.SelectedTarget.NetworkId == p.NetworkId) && !hitbox1.IsOutside(SCommon.Prediction.Prediction.GetFastUnitPosition(p, 0.3f)))) { Spells[Q].CastOnUnit(minion); return; } } }