private IObject SearchNearestObject(GravityGun gun)
        {
            var holdPosition = gun.GetHoldPosition(false);
            var filterArea   = ScriptHelper.GrowFromCenter(
                holdPosition + Vector2.UnitX * Player.FacingDirection * GravityGun.Range / 2, GravityGun.Range);
            IObject nearestObject = null;

            foreach (var obj in Game.GetObjectsByArea(filterArea))
            {
                var rangeLimit  = GetRangeLimit();
                var objPosition = obj.GetWorldPosition();

                if (ScriptHelper.IsDynamicObject(obj) &&
                    !GravityGun.Blacklist.Contains(obj.Name) &&
                    ScriptHelper.IntersectCircle(obj.GetAABB(), holdPosition, GravityGun.Range, rangeLimit[0], rangeLimit[1]) &&
                    !GetMimimumRange().Intersects(obj.GetAABB()) &&
                    (nearestObject == null || Rank(nearestObject, obj) == 1))
                {
                    var rcInput = new RayCastInput()
                    {
                        ClosestHitOnly   = true,
                        FilterOnMaskBits = true,
                        MaskBits         = CategoryBits.StaticGround,
                    };
                    var results = Game.RayCast(holdPosition, objPosition, rcInput);

                    if (results.Count() > 0 && results.First().HitObject != null)
                    {
                        var result = results.First();
                        var closestStaticObjPosition = result.Position;

                        if (Vector2.DistanceSquared(holdPosition, objPosition) <
                            Vector2.DistanceSquared(holdPosition, closestStaticObjPosition))
                        {
                            nearestObject = obj;
                        }
                    }
                    else
                    {
                        nearestObject = obj;
                    }
                }
            }

            return(nearestObject);
        }
        private bool IsObjectInRange(GravityGun gun, IObject obj)
        {
            var holdPosition = gun.GetHoldPosition(false);
            var rcInput      = new RayCastInput()
            {
                MaskBits         = (ushort)(gun.IsSupercharged ? CategoryBits.Dynamic + CategoryBits.Player : CategoryBits.Dynamic),
                FilterOnMaskBits = true,
            };
            var results = Game.RayCast(holdPosition, holdPosition + Player.AimVector * GravityGun.Range, rcInput);

            Game.DrawLine(holdPosition, holdPosition + Player.AimVector * GravityGun.Range);

            foreach (var result in results)
            {
                if (result.ObjectID == obj.UniqueID)
                {
                    return(true);
                }
            }
            return(false);
        }
        private bool IsPlayerInRange(GravityGun gun, IPlayer player)
        {
            if (player == null)
            {
                return(false);
            }

            var holdPosition = gun.GetHoldPosition(false);
            var rcInput      = new RayCastInput()
            {
                MaskBits         = CategoryBits.Player,
                FilterOnMaskBits = true,
            };
            var results = Game.RayCast(Bot.Position, Bot.Position + Player.AimVector * GravityGun.Range * 4, rcInput);

            foreach (var result in results)
            {
                if (result.ObjectID == player.UniqueID)
                {
                    return(true);
                }
            }
            return(false);
        }
        public void Update(float elapsed, GravityGun gun)
        {
            if (Constants.IS_ME_ALONE)
            {
                m_debugText.SetWorldPosition(Player.GetWorldPosition());
                m_debugText.SetText(ScriptHelper.ToDisplayString(m_state + "\n", Player.IsInputEnabled + "\n",
                                                                 Player.GetBotBehaviorSet().RangedWeaponUsage + "\n", GetNeareastObject(gun) == null));
            }
            else
            {
                Bot.LogDebug(m_state, Player.IsInputEnabled, Player.GetBotBehaviorSet().RangedWeaponUsage);
            }

            if (m_state == State.Normal || m_state == State.Cooldown)
            {
                // Trick the bot to use this weapon only when there are objects around
                // and stop using it when there is nothing to shoot with
                UpdateWeaponUsage(gun);
            }
            else
            {
                m_timeout += elapsed;

                if (m_timeout >= 3000f)
                {
                    Stop("State timeout");
                }
                if (Player.IsStaggering || Player.IsStunned || !Player.IsOnGround || Player.IsBurningInferno)
                {
                    Stop("Player is stunned");
                }
            }

            if (Game.IsEditorTest)
            {
                var o = GetNeareastObject(gun);
                if (o != null)
                {
                    Game.DrawArea(o.GetAABB(), Color.Red);
                }
                if (NearestObject != null)
                {
                    Game.DrawArea(NearestObject.GetAABB(), Color.Magenta);
                }
                foreach (var p in SearchedEnemies)
                {
                    Game.DrawArea(p.GetAABB(), Color.Cyan);
                }
                if (m_targetEnemy != null)
                {
                    Game.DrawArea(m_targetEnemy.GetAABB(), Color.Green);
                }
                Game.DrawArea(DangerArea, Color.Red);
                Game.DrawCircle(gun.GetHoldPosition(false), GravityGun.Range);
                Game.DrawArea(GetMimimumRange(), Color.Cyan);
            }

            //ScriptHelper.Stopwatch(() =>
            //{
            switch (m_state)
            {
            case State.Normal:
            {
                if (!ScriptHelper.IsElapsed(m_stateDelay, 30))
                {
                    break;
                }

                m_stateDelay = Game.TotalElapsedGameTime;
                if (EnemiesNearby())
                {
                    if (!Player.IsInputEnabled)
                    {
                        Player.SetInputEnabled(true);
                    }
                    break;
                }

                var enemies = SearchedEnemies;
                if (enemies.Count() > 0 && NearestObject == null)
                {
                    NearestObject = gun.IsSupercharged ? enemies.First() : GetNeareastObject(gun);
                }

                if (NearestObject != null && !m_executeOnce && Player.IsOnGround &&
                    !Player.IsStaggering && !Player.IsStunned && !Player.IsHoldingPlayerInGrab)
                {
                    Player.SetInputEnabled(false);

                    if (Player.CurrentWeaponDrawn != gun.Type)
                    {
                        if (gun.Type == WeaponItemType.Rifle)
                        {
                            Player.AddCommand(new PlayerCommand(PlayerCommandType.DrawRifle));
                        }
                        if (gun.Type == WeaponItemType.Handgun)
                        {
                            Player.AddCommand(new PlayerCommand(PlayerCommandType.DrawHandgun));
                        }
                        ChangeState(State.Drawing);
                        break;
                    }

                    if (GetCurrentAmmo(gun) == 0)
                    {
                        Player.AddCommand(new PlayerCommand(PlayerCommandType.Reload));
                        ChangeState(State.Reloading);
                        break;
                    }

                    Player.AddCommand(new PlayerCommand(PlayerCommandType.StartAimAtPrecise, NearestObject.UniqueID));
                    m_executeOnce = true;
                }

                if (NearestObject != null && Player.CurrentWeaponDrawn == gun.Type && GetCurrentAmmo(gun) > 0)
                {
                    ChangeState(State.AimingTargetedObject);
                }
                break;
            }

            case State.Drawing:
            {
                if (!Player.IsDrawingWeapon)
                {
                    ChangeState(State.Normal);
                }
                break;
            }

            case State.Reloading:
            {
                if (!Player.IsReloading)
                {
                    ChangeState(State.Normal);
                }
                break;
            }

            case State.AimingTargetedObject:
            {
                var rangeLimit   = GetRangeLimit();
                var holdPosition = gun.GetHoldPosition(false);

                if (NearestObject.IsRemoved ||
                    !ScriptHelper.IntersectCircle(NearestObject.GetAABB(), holdPosition, GravityGun.Range,
                                                  rangeLimit[0], rangeLimit[1]))
                {
                    Stop("NearestObject not in range");
                    break;
                }

                if (Player.IsManualAiming && MaybeLockTarget(gun, NearestObject) && IsObjectInRange(gun, NearestObject))
                {
                    gun.PickupObject();
                    ChangeState(State.Retrieving);
                }
                break;
            }

            case State.Retrieving:
            {
                if (gun.TargetedObject == null || IsObjectStuck(gun.TargetedObject))
                {
                    Stop(gun.TargetedObject == null ? "TargetedObject = null" : "TargetedObject is stuck");
                    break;
                }
                if (gun.IsTargetedObjectStabilized && gun.TargetedObject.GetLinearVelocity().Length() < 1)
                {
                    var enemies = SearchedEnemies;
                    if (enemies.Count() > 0 || m_nearestObjectIsPlayer)
                    {
                        if (enemies.Count() > 1 && m_nearestObjectIsPlayer)
                        {
                            foreach (var enemy in enemies)
                            {
                                if (enemy.UniqueID != NearestObject.UniqueID)
                                {
                                    m_targetEnemy = enemy; break;
                                }
                            }
                        }
                        else if (enemies.Count() > 0)
                        {
                            m_targetEnemy = enemies.First();
                        }

                        if (m_targetEnemy != null)
                        {
                            Player.AddCommand(new PlayerCommand(PlayerCommandType.StartAimAtPrecise, m_targetEnemy.UniqueID));
                        }
                        ChangeState(State.AimingEnemy);
                        var botBehaviorSet = Player.GetBotBehaviorSet();
                        m_shootDelayTimeThisTurn = RandomHelper.Between(
                            botBehaviorSet.RangedWeaponPrecisionAimShootDelayMin,
                            botBehaviorSet.RangedWeaponPrecisionAimShootDelayMax);
                    }
                    else
                    {
                        Stop("No enemies to shoot");
                    }
                }
                break;
            }

            case State.AimingEnemy:
            {
                if (gun.TargetedObject == null || m_targetEnemy != null && (m_targetEnemy.IsDead || m_targetEnemy.IsRemoved))
                {
                    Stop(gun.TargetedObject == null ? "Already Shot" : "Enemy already dead");
                    break;
                }
                if (IsPlayerInRange(gun, m_targetEnemy) || m_nearestObjectIsPlayer)
                {
                    m_shootDelayTime += elapsed;

                    if (m_shootDelayTime >= m_shootDelayTimeThisTurn)
                    {
                        if (!m_nearestObjectIsPlayer && NearestObject.GetLinearVelocity().Length() < 1 ||
                            m_nearestObjectIsPlayer)
                        {
                            Player.AddCommand(new PlayerCommand(PlayerCommandType.AttackOnce));
                            m_shootDelayTime = 0f;
                        }
                    }
                }
                break;
            }

            case State.Cooldown:
            {
                if (ScriptHelper.IsElapsed(m_cooldownTime, CooldownTime))
                {
                    ChangeState(State.Normal);
                }
                break;
            }
            }

            //    return m_state.ToString();
            //});
        }