Esempio n. 1
0
        /// <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);
        }
Esempio n. 2
0
        /// <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)));
        }
Esempio n. 3
0
        /// <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);
        }
Esempio n. 4
0
        /// <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);
        }
Esempio n. 5
0
        /// <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));
        }
Esempio n. 6
0
        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;
                    }
                }
            }
        }
Esempio n. 7
0
        /// <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);
            }
        }
Esempio n. 8
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 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));
        }
Esempio n. 9
0
        /// <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)));
        }
Esempio n. 10
0
        /// <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)));
        }
Esempio n. 11
0
        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;
                }
            }
        }