public async Task <CatchPokemonResponse> CatchPokemon(ulong encounterId, string spawnPointGuid,
                                                              ItemId pokeballItemId, double normalizedRecticleSize = 1.950, double spinModifier = 1,
                                                              bool hitPokemon = true, double normalizedHitPos = 1)
        {
            var arPlusValues = new ARPlusEncounterValues();

            APIConfiguration.Logger.LogInfo("Using AR Bonus Values");
            arPlusValues.Awareness         = (float)0.000;
            arPlusValues.Proximity         = (float)0.000;
            arPlusValues.PokemonFrightened = false;

            var catchPokemonRequest = new Request
            {
                RequestType    = RequestType.CatchPokemon,
                RequestMessage = ((IMessage) new CatchPokemonMessage
                {
                    ArPlusValues = arPlusValues,
                    EncounterId = encounterId,
                    Pokeball = pokeballItemId,
                    SpawnPointId = spawnPointGuid,
                    HitPokemon = hitPokemon,
                    NormalizedReticleSize = normalizedRecticleSize,
                    SpinModifier = spinModifier,
                    NormalizedHitPosition = normalizedHitPos
                }).ToByteString()
            };

            var request = await GetRequestBuilder().GetRequestEnvelope(CommonRequest.FillRequest(catchPokemonRequest, Client)).ConfigureAwait(false);

            Tuple <CatchPokemonResponse, CheckChallengeResponse, GetHatchedEggsResponse, GetHoloInventoryResponse, CheckAwardedBadgesResponse, DownloadSettingsResponse, GetBuddyWalkedResponse> response =
                await
                PostProtoPayload
                <Request, CatchPokemonResponse, CheckChallengeResponse, GetHatchedEggsResponse, GetHoloInventoryResponse,
                 CheckAwardedBadgesResponse, DownloadSettingsResponse, GetBuddyWalkedResponse>(request).ConfigureAwait(false);

            CheckChallengeResponse checkChallengeResponse = response.Item2;

            CommonRequest.ProcessCheckChallengeResponse(Client, checkChallengeResponse);

            GetHoloInventoryResponse getHoloInventoryResponse = response.Item4;

            CommonRequest.ProcessGetHoloInventoryResponse(Client, getHoloInventoryResponse);

            DownloadSettingsResponse downloadSettingsResponse = response.Item6;

            CommonRequest.ProcessDownloadSettingsResponse(Client, downloadSettingsResponse);

            return(response.Item1);
        }
        //Catch encountered pokemon
        private async Task <MethodResult> CatchPokemon(dynamic eResponse, MapPokemon mapPokemon, bool snipped = false)
        {
            PokemonData _encounteredPokemon = null;
            long        _unixTimeStamp      = 0;
            ulong       _encounterId        = 0;
            string      _spawnPointId       = null;
            string      _pokemonType        = null;
            //Default catch success
            LoggerTypes _loggerType = LoggerTypes.Success;

            // Calling from CatchNormalPokemon
            if (eResponse is EncounterResponse &&
                (eResponse?.Status == EncounterResponse.Types.Status.EncounterSuccess))
            {
                _encounteredPokemon = eResponse.WildPokemon?.PokemonData;
                _unixTimeStamp      = eResponse.WildPokemon?.LastModifiedTimestampMs
                                      + eResponse.WildPokemon?.TimeTillHiddenMs;
                _spawnPointId = eResponse.WildPokemon?.SpawnPointId;
                _encounterId  = eResponse.WildPokemon?.EncounterId;
                _pokemonType  = "Normal";
            }
            // Calling from CatchIncensePokemon
            else if (eResponse is IncenseEncounterResponse &&
                     (eResponse?.Result == IncenseEncounterResponse.Types.Result.IncenseEncounterSuccess))
            {
                _encounteredPokemon = eResponse?.PokemonData;
                _unixTimeStamp      = mapPokemon.ExpirationTimestampMs;
                _spawnPointId       = mapPokemon.SpawnPointId;
                _encounterId        = mapPokemon.EncounterId;
                _pokemonType        = "Incense";
            }

            if (_encounterId == _lastPokeSniperId || snipped)
            {
                _pokemonType   = "Local Snipe: " + _pokemonType;
                _loggerType    = LoggerTypes.Snipe;
                AlreadySnipped = true;
            }

            CatchPokemonResponse catchPokemonResponse = null;
            int  attemptCount = 1;
            bool berryUsed    = false;

            if (_encounteredPokemon == null || _encounteredPokemon.PokemonId == PokemonId.Missingno)
            {
                return(new MethodResult());
            }

            do
            {
                if (!CatchDisabled)
                {
                    if (RemainingPokeballs() < 1)
                    {
                        LogCaller(new LoggerEventArgs("You don't have any pokeball catching pokemon will be disabled during " + UserSettings.DisableCatchDelay.ToString(CultureInfo.InvariantCulture) + " minutes.", LoggerTypes.Info));
                        CatchDisabled = true;
                        TimeAutoCatch = DateTime.Now.AddMinutes(UserSettings.DisableCatchDelay);
                        return(new MethodResult());
                    }
                }
                else
                {
                    return(new MethodResult());
                }

                //Uses lowest capture probability
                float  probability = eResponse.CaptureProbability.CaptureProbability_[0];
                ItemId pokeBall    = GetBestBall(_encounteredPokemon);

                if (UserSettings.UseBerries)
                {
                    bool isLowProbability = probability < 0.40;
                    bool isHighCp         = _encounteredPokemon.Cp > 800;
                    bool isHighPerfection = CalculateIVPerfection(_encounteredPokemon) > 95;

                    if (!berryUsed)
                    {
                        if ((isLowProbability && isHighCp) || isHighPerfection)
                        {
                            await UseBerry(mapPokemon, ItemId.ItemRazzBerry);

                            berryUsed = true;
                        }
                        else
                        {
                            bool isHighProbability = probability > 0.65;
                            var  catchSettings     = UserSettings.CatchSettings.FirstOrDefault(x => x.Id == _encounteredPokemon.PokemonId);
                            if (isHighProbability && catchSettings.UsePinap)
                            {
                                await UseBerry(mapPokemon, ItemId.ItemPinapBerry);

                                berryUsed = true;
                            }
                            else if (new Random().Next(0, 100) < 50)
                            {
                                // IF we dont use razz neither use pinap, then we will use nanab randomly the 50% of times.
                                await UseBerry(mapPokemon, ItemId.ItemNanabBerry);

                                berryUsed = true;
                            }
                        }
                        await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
                    }
                }

                await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));

                double reticuleSize      = 1.95;
                bool   hitInsideReticule = true;

                //Humanization
                if (UserSettings.EnableHumanization)
                {
                    reticuleSize      = (double)_rand.Next(10, 195) / 100;
                    hitInsideReticule = HitInsideReticle();
                }
                var arPlusValues = new ARPlusEncounterValues();
                if (UserSettings.GetArBonus)
                {
                    LogCaller(new LoggerEventArgs("Using AR Bonus Values", LoggerTypes.Debug));
                    arPlusValues.Awareness         = (float)UserSettings.ARBonusAwareness;
                    arPlusValues.Proximity         = (float)UserSettings.ARBonusProximity;
                    arPlusValues.PokemonFrightened = false;
                }

                if (!_client.LoggedIn)
                {
                    MethodResult result = await AcLogin();

                    if (!result.Success)
                    {
                        return(result);
                    }
                }

                var catchresponse = await _client.ClientSession.RpcClient.SendRemoteProcedureCallAsync(new Request
                {
                    RequestType    = RequestType.CatchPokemon,
                    RequestMessage = new CatchPokemonMessage
                    {
                        ArPlusValues          = arPlusValues,
                        EncounterId           = _encounterId,
                        HitPokemon            = hitInsideReticule,
                        NormalizedHitPosition = 1,
                        NormalizedReticleSize = reticuleSize,
                        Pokeball     = pokeBall,
                        SpawnPointId = _spawnPointId,
                        SpinModifier = 1
                    }.ToByteString()
                });

                if (catchresponse == null)
                {
                    return(new MethodResult());
                }

                catchPokemonResponse = CatchPokemonResponse.Parser.ParseFrom(catchresponse);

                string pokemon      = String.Format("Name: {0}, CP: {1}, IV: {2:0.00}%", _encounteredPokemon.PokemonId.ToString(), _encounteredPokemon.Cp, CalculateIVPerfection(_encounteredPokemon));
                string pokeBallName = pokeBall.ToString().Replace("Item", "");

                switch (catchPokemonResponse.Status)
                {
                case CatchPokemonResponse.Types.CatchStatus.CatchError:
                    LogCaller(new LoggerEventArgs(String.Format("Unknown Error. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                    continue;

                case CatchPokemonResponse.Types.CatchStatus.CatchEscape:
                    //If we get this response, means we're good
                    _fleeingPokemonResponses = 0;
                    _potentialPokemonBan     = false;

                    if (AccountState == Enums.AccountState.SoftBan)
                    {
                        AccountState = Enums.AccountState.Good;

                        LogCaller(new LoggerEventArgs("Pokemon ban was lifted", LoggerTypes.Info));
                    }

                    LogCaller(new LoggerEventArgs(String.Format("Escaped ball. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonEscape));
                    continue;

                case CatchPokemonResponse.Types.CatchStatus.CatchFlee:
                    ++_fleeingPokemonResponses;
                    LogCaller(new LoggerEventArgs(String.Format("Pokemon fled. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonFlee));
                    continue;

                case CatchPokemonResponse.Types.CatchStatus.CatchMissed:
                    LogCaller(new LoggerEventArgs(String.Format("Missed. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                    continue;

                case CatchPokemonResponse.Types.CatchStatus.CatchSuccess:
                    //Reset data
                    _fleeingPokemonResponses = 0;
                    Tracker.AddValues(1, 0);
                    _potentialPokemonBan = false;

                    int expGained   = catchPokemonResponse.CaptureAward.Xp.Sum();
                    int candyGained = catchPokemonResponse.CaptureAward.Candy.Sum();

                    ExpIncrease(expGained);

                    //_expGained += expGained;

                    LogCaller(new LoggerEventArgs(String.Format("[{0}] Pokemon Caught. {1}. Exp {2}. Candy: {3}. Attempt #{4}. Ball: {5}", _pokemonType, pokemon, expGained, candyGained, attemptCount, pokeBallName), _loggerType));

                    //Auto favorit shiny
                    if (UserSettings.AutoFavoritShiny && _encounteredPokemon.PokemonDisplay.Shiny)
                    {
                        LogCaller(new LoggerEventArgs(String.Format("[{0}] Pokemon shiny. Auto favorit this pokemon.", _encounteredPokemon.PokemonId.ToString()), LoggerTypes.Info));
                        await FavoritePokemon(new List <PokemonData> {
                            _encounteredPokemon
                        }, true);

                        await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
                    }

                    //Pokemon.Add(_encounteredPokemon);
                    UpdateInventory(InventoryRefresh.Pokemon);
                    UpdateInventory(InventoryRefresh.PokemonCandy);

                    return(new MethodResult
                    {
                        Message = "Pokemon caught",
                        Success = true
                    });
                }
                ++attemptCount;
                await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
            } while (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
            return(new MethodResult());
        }
        //Catch lured pokemon
        private async Task <MethodResult> CatchPokemon(FortData fortData)
        {
            if (!_client.LoggedIn)
            {
                MethodResult result = await AcLogin();

                if (!result.Success)
                {
                    return(result);
                }
            }

            if (!CatchDisabled)
            {
                if (RemainingPokeballs() < 1)
                {
                    LogCaller(new LoggerEventArgs("You don't have any pokeball catching (Lure) pokemon will be disabled during " + UserSettings.DisableCatchDelay.ToString(CultureInfo.InvariantCulture) + " minutes.", LoggerTypes.Info));
                    CatchDisabled = true;
                    TimeAutoCatch = DateTime.Now.AddMinutes(UserSettings.DisableCatchDelay);
                    return(new MethodResult());
                }
            }
            else
            {
                return(new MethodResult());
            }

            if (fortData.LureInfo == null || fortData.LureInfo.ActivePokemonId == PokemonId.Missingno)
            {
                return(new MethodResult());
            }

            if (LastedEncountersIds.Contains(fortData.LureInfo.EncounterId))
            {
                return(new MethodResult());
            }

            var response = await _client.ClientSession.RpcClient.SendRemoteProcedureCallAsync(new Request
            {
                RequestType    = RequestType.DiskEncounter,
                RequestMessage = new DiskEncounterMessage
                {
                    EncounterId     = fortData.LureInfo.EncounterId,
                    FortId          = fortData.Id,
                    GymLatDegrees   = fortData.Latitude,
                    GymLngDegrees   = fortData.Longitude,
                    PlayerLatitude  = _client.ClientSession.Player.Latitude,
                    PlayerLongitude = _client.ClientSession.Player.Longitude
                }.ToByteString()
            });

            if (response == null)
            {
                return(new MethodResult());
            }

            DiskEncounterResponse eResponse = DiskEncounterResponse.Parser.ParseFrom(response);

            switch (eResponse.Result)
            {
            case DiskEncounterResponse.Types.Result.Success:
                if (LastedEncountersIds.Count > 30)
                {
                    LastedEncountersIds.Clear();
                }

                LastedEncountersIds.Add(eResponse.PokemonData.Id);

                CatchPokemonResponse catchPokemonResponse = null;
                int attemptCount = 1;
                var berryUsed    = false;

                if (eResponse.PokemonData == null || eResponse.PokemonData.PokemonId == PokemonId.Missingno)
                {
                    return(new MethodResult());
                }

                do
                {
                    if (!CatchDisabled)
                    {
                        if (RemainingPokeballs() < 1)
                        {
                            LogCaller(new LoggerEventArgs("You don't have any pokeball catching (Lure) pokemon will be disabled during " + UserSettings.DisableCatchDelay.ToString(CultureInfo.InvariantCulture) + " minutes.", LoggerTypes.Info));
                            CatchDisabled = true;
                            TimeAutoCatch = DateTime.Now.AddMinutes(UserSettings.DisableCatchDelay);
                            return(new MethodResult());
                        }
                    }
                    else
                    {
                        return(new MethodResult());
                    }

                    //Uses lowest capture probability
                    float  probability = eResponse.CaptureProbability.CaptureProbability_[0];
                    ItemId pokeBall    = GetBestBall(eResponse.PokemonData);

                    if (UserSettings.UseBerries)
                    {
                        bool isLowProbability = probability < 0.35;
                        bool isHighCp         = eResponse.PokemonData.Cp > 700;
                        bool isHighPerfection = CalculateIVPerfection(eResponse.PokemonData) > 90;

                        if (!berryUsed)
                        {
                            if ((isLowProbability && isHighCp) || isHighPerfection)
                            {
                                await UseBerry(fortData.LureInfo.EncounterId, fortData.Id, ItemId.ItemRazzBerry);

                                berryUsed = true;
                            }
                            else
                            {
                                bool isHighProbability = probability > 0.65;
                                var  catchSettings     = UserSettings.CatchSettings.FirstOrDefault(x => x.Id == eResponse.PokemonData.PokemonId);
                                if (isHighProbability && catchSettings.UsePinap)
                                {
                                    await UseBerry(fortData.LureInfo.EncounterId, fortData.Id, ItemId.ItemPinapBerry);

                                    berryUsed = true;
                                }
                                else if (new Random().Next(0, 100) < 50)
                                {
                                    // IF we dont use razz neither use pinap, then we will use nanab randomly the 50% of times.
                                    await UseBerry(fortData.LureInfo.EncounterId, fortData.Id, ItemId.ItemNanabBerry);

                                    berryUsed = true;
                                }
                            }
                        }
                    }

                    double reticuleSize      = 1.95;
                    bool   hitInsideReticule = true;

                    //Humanization
                    if (UserSettings.EnableHumanization)
                    {
                        reticuleSize      = (double)_rand.Next(10, 195) / 100;
                        hitInsideReticule = HitInsideReticle();
                    }

                    //End humanization
                    var arPlusValues = new ARPlusEncounterValues();
                    if (UserSettings.GetArBonus)
                    {
                        LogCaller(new LoggerEventArgs("Using AR Bonus Values", LoggerTypes.Debug));
                        arPlusValues.Awareness         = (float)UserSettings.ARBonusAwareness;
                        arPlusValues.Proximity         = (float)UserSettings.ARBonusProximity;
                        arPlusValues.PokemonFrightened = false;
                    }

                    if (!_client.LoggedIn)
                    {
                        MethodResult result = await AcLogin();

                        if (!result.Success)
                        {
                            return(result);
                        }
                    }

                    var catchresponse = await _client.ClientSession.RpcClient.SendRemoteProcedureCallAsync(new Request
                    {
                        RequestType    = RequestType.CatchPokemon,
                        RequestMessage = new CatchPokemonMessage
                        {
                            ArPlusValues          = arPlusValues,
                            EncounterId           = fortData.LureInfo.EncounterId,
                            HitPokemon            = hitInsideReticule,
                            NormalizedHitPosition = 1,
                            NormalizedReticleSize = reticuleSize,
                            Pokeball     = pokeBall,
                            SpawnPointId = fortData.Id,
                            SpinModifier = 1
                        }.ToByteString()
                    });

                    if (catchresponse == null)
                    {
                        return(new MethodResult());
                    }

                    catchPokemonResponse = CatchPokemonResponse.Parser.ParseFrom(catchresponse);
                    string pokemon      = String.Format("Name: {0}, CP: {1}, IV: {2:0.00}%", fortData.LureInfo.ActivePokemonId, eResponse.PokemonData.Cp, CalculateIVPerfection(eResponse.PokemonData));
                    string pokeBallName = pokeBall.ToString().Replace("Item", "");

                    switch (catchPokemonResponse.Status)
                    {
                    case CatchPokemonResponse.Types.CatchStatus.CatchError:
                        LogCaller(new LoggerEventArgs(String.Format("Unknown Error. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                        continue;

                    case CatchPokemonResponse.Types.CatchStatus.CatchEscape:
                        //If we get this response, means we're good
                        _fleeingPokemonResponses = 0;
                        _potentialPokemonBan     = false;

                        if (AccountState == AccountState.SoftBan || AccountState == AccountState.HashIssues)
                        {
                            AccountState = AccountState.Good;

                            LogCaller(new LoggerEventArgs("Pokemon ban was lifted", LoggerTypes.Info));
                        }

                        LogCaller(new LoggerEventArgs(String.Format("Escaped ball. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonEscape));
                        continue;

                    case CatchPokemonResponse.Types.CatchStatus.CatchFlee:
                        ++_fleeingPokemonResponses;
                        LogCaller(new LoggerEventArgs(String.Format("Pokemon fled. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonFlee));
                        continue;

                    case CatchPokemonResponse.Types.CatchStatus.CatchMissed:
                        LogCaller(new LoggerEventArgs(String.Format("Missed. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                        continue;

                    case CatchPokemonResponse.Types.CatchStatus.CatchSuccess:
                        int expGained   = catchPokemonResponse.CaptureAward.Xp.Sum();
                        int candyGained = catchPokemonResponse.CaptureAward.Candy.Sum();

                        Tracker.AddValues(1, 0);

                        ExpIncrease(expGained);

                        //_expGained += expGained;

                        fortData.LureInfo = null;

                        LogCaller(new LoggerEventArgs(String.Format("[Lured] Pokemon Caught. {0}. Exp {1}. Candy {2}. Attempt #{3}. Ball: {4}", pokemon, expGained, candyGained, attemptCount, pokeBallName), LoggerTypes.Success));

                        //Auto favorit shiny
                        if (UserSettings.AutoFavoritShiny && eResponse.PokemonData.PokemonDisplay.Shiny)
                        {
                            LogCaller(new LoggerEventArgs(String.Format("[{0}] Pokemon shiny. Auto favorit this pokemon.", eResponse.PokemonData.PokemonId.ToString()), LoggerTypes.Info));
                            await FavoritePokemon(new List <PokemonData> {
                                eResponse.PokemonData
                            }, true);

                            await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
                        }

                        //Pokemon.Add(eResponse.PokemonData);
                        UpdateInventory(InventoryRefresh.Pokemon);

                        return(new MethodResult
                        {
                            Message = "Pokemon caught",
                            Success = true
                        });
                    }
                    ++attemptCount;

                    await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
                } while (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
                return(new MethodResult());

            case DiskEncounterResponse.Types.Result.EncounterAlreadyFinished:
                break;

            case DiskEncounterResponse.Types.Result.NotAvailable:
                break;

            case DiskEncounterResponse.Types.Result.NotInRange:
                break;

            case DiskEncounterResponse.Types.Result.PokemonInventoryFull:
                break;

            case DiskEncounterResponse.Types.Result.Unknown:
                break;
            }

            if (LastedEncountersIds.Count > 30)
            {
                LastedEncountersIds.Clear();
            }

            LastedEncountersIds.Add(fortData.LureInfo.EncounterId);

            LogCaller(new LoggerEventArgs(String.Format("Faill cath lure on pokestop {0}. {1}.", fortData.Id, eResponse.Result), LoggerTypes.Warning));
            return(new MethodResult());
        }
        //Catch encountered pokemon
        private async Task <MethodResult> CatchPokemon(dynamic eResponse, MapPokemon mapPokemon)
        {
            PokemonData _encounteredPokemon = null;
            long        _unixTimeStamp      = 0;
            ulong       _encounterId        = 0;
            string      _spawnPointId       = null;
            string      _pokemonType        = null;

            // Calling from CatchNormalPokemon
            if (eResponse is EncounterResponse &&
                (eResponse?.Status == EncounterResponse.Types.Status.EncounterSuccess))
            {
                _encounteredPokemon = eResponse.WildPokemon?.PokemonData;
                _unixTimeStamp      = eResponse.WildPokemon?.LastModifiedTimestampMs
                                      + eResponse.WildPokemon?.TimeTillHiddenMs;
                _spawnPointId = eResponse.WildPokemon?.SpawnPointId;
                _encounterId  = eResponse.WildPokemon?.EncounterId;
                _pokemonType  = "Normal";
            }
            // Calling from CatchIncensePokemon
            else if (eResponse is IncenseEncounterResponse &&
                     (eResponse?.Result == IncenseEncounterResponse.Types.Result.IncenseEncounterSuccess))
            {
                _encounteredPokemon = eResponse?.PokemonData;
                _unixTimeStamp      = mapPokemon.ExpirationTimestampMs;
                _spawnPointId       = mapPokemon.SpawnPointId;
                _encounterId        = mapPokemon.EncounterId;
                _pokemonType        = "Incense";
            }

            CatchPokemonResponse catchPokemonResponse = null;
            int attemptCount = 1;

            do
            {
                if (mapPokemon == null)
                {
                    return(new MethodResult());
                }

                //Uses lowest capture probability
                float  probability = eResponse.CaptureProbability.CaptureProbability_[0];
                ItemId pokeBall    = GetBestBall(_encounteredPokemon);

                if (pokeBall == ItemId.ItemUnknown)
                {
                    LogCaller(new LoggerEventArgs("No pokeballs remaining (encounter)", LoggerTypes.Warning));

                    return(new MethodResult
                    {
                        Message = "No pokeballs remaining"
                    });
                }

                bool isLowProbability = probability < 0.40;
                bool isHighCp         = _encounteredPokemon.Cp > 800;
                bool isHighPerfection = CalculateIVPerfection(_encounteredPokemon) > 95;

                if (UserSettings.UseBerries)
                {
                    if ((isLowProbability && isHighCp) || isHighPerfection)
                    {
                        await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));

                        await UseBerry(mapPokemon, ItemId.ItemRazzBerry);
                    }
                    else
                    {
                        bool isHighProbability = probability > 0.65;
                        if (isHighProbability)
                        {
                            await UseBerry(mapPokemon, ItemId.ItemPinapBerry);
                        }
                        else if (new Random().Next(0, 100) < 50)
                        {
                            // IF we dont use razz neither use pinap, then we will use nanab randomly the 50% of times.
                            await UseBerry(mapPokemon, ItemId.ItemNanabBerry);
                        }
                    }
                }

                await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));

                double reticuleSize      = 1.95;
                bool   hitInsideReticule = true;

                //Humanization
                if (UserSettings.EnableHumanization)
                {
                    reticuleSize      = (double)_rand.Next(10, 195) / 100;
                    hitInsideReticule = HitInsideReticle();
                }
                var arPlusValues = new ARPlusEncounterValues();
                if (UserSettings.GetArBonus)
                {
                    LogCaller(new LoggerEventArgs("Using AR Bonus Values", LoggerTypes.Debug));
                    arPlusValues.Awareness         = (float)UserSettings.ARBonusAwareness;
                    arPlusValues.Proximity         = (float)UserSettings.ARBonusProximity;
                    arPlusValues.PokemonFrightened = false;
                }

                var catchresponse = await _client.ClientSession.RpcClient.SendRemoteProcedureCallAsync(new Request
                {
                    RequestType    = RequestType.CatchPokemon,
                    RequestMessage = new CatchPokemonMessage
                    {
                        ArPlusValues          = arPlusValues,
                        EncounterId           = _encounterId,
                        HitPokemon            = hitInsideReticule,
                        NormalizedHitPosition = 1,
                        NormalizedReticleSize = reticuleSize,
                        Pokeball     = pokeBall,
                        SpawnPointId = _spawnPointId,
                        SpinModifier = 1
                    }.ToByteString()
                });

                if (catchresponse == null)
                {
                    return(new MethodResult());
                }

                catchPokemonResponse = CatchPokemonResponse.Parser.ParseFrom(catchresponse);

                string pokemon      = String.Format("Name: {0}, CP: {1}, IV: {2:0.00}%", mapPokemon.PokemonId, _encounteredPokemon.Cp, CalculateIVPerfection(_encounteredPokemon));
                string pokeBallName = pokeBall.ToString().Replace("Item", "");

                switch (catchPokemonResponse.Status)
                {
                case CatchPokemonResponse.Types.CatchStatus.CatchError:
                    LogCaller(new LoggerEventArgs(String.Format("Unknown Error. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                    continue;

                case CatchPokemonResponse.Types.CatchStatus.CatchEscape:
                    //If we get this response, means we're good
                    _fleeingPokemonResponses = 0;
                    _potentialPokemonBan     = false;

                    if (AccountState == Enums.AccountState.SoftBan)
                    {
                        AccountState = Enums.AccountState.Good;

                        LogCaller(new LoggerEventArgs("Pokemon ban was lifted", LoggerTypes.Info));
                    }

                    LogCaller(new LoggerEventArgs(String.Format("Escaped ball. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonEscape));
                    continue;

                case CatchPokemonResponse.Types.CatchStatus.CatchFlee:
                    ++_fleeingPokemonResponses;
                    LogCaller(new LoggerEventArgs(String.Format("Pokemon fled. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonFlee));
                    continue;

                case CatchPokemonResponse.Types.CatchStatus.CatchMissed:
                    LogCaller(new LoggerEventArgs(String.Format("Missed. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                    continue;

                case CatchPokemonResponse.Types.CatchStatus.CatchSuccess:
                    //Reset data
                    _fleeingPokemonResponses = 0;
                    Tracker.AddValues(1, 0);
                    _potentialPokemonBan = false;

                    int expGained   = catchPokemonResponse.CaptureAward.Xp.Sum();
                    int candyGained = catchPokemonResponse.CaptureAward.Candy.Sum();

                    ExpIncrease(expGained);

                    //_expGained += expGained;

                    //NOTE: To be sure that we don't repeat this encounter, we will delete it from the cell
                    var cell = _client.ClientSession.Map.Cells.FirstOrDefault(x => x.CatchablePokemons.FirstOrDefault(y => y.EncounterId == mapPokemon.EncounterId) != null);
                    if (cell != null)
                    {
                        var mapPokemonFound = cell.CatchablePokemons.FirstOrDefault(y => y.EncounterId == mapPokemon.EncounterId);
                        if (mapPokemonFound != null)
                        {
                            cell.CatchablePokemons.Remove(mapPokemonFound);
                        }
                    }

                    LogCaller(new LoggerEventArgs(String.Format("[{0}] Pokemon Caught. {1}. Exp {2}. Candy: {3}. Attempt #{4}. Ball: {5}", _pokemonType, pokemon, expGained, candyGained, attemptCount, pokeBallName), LoggerTypes.Success));

                    //Pokemon.Add(_encounteredPokemon);
                    UpdateInventory(InventoryRefresh.Pokemon);

                    return(new MethodResult
                    {
                        Message = "Pokemon caught",
                        Success = true
                    });
                }

                ++attemptCount;

                await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
            } while (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
            return(new MethodResult());
        }
        //Catch lured pokemon
        private async Task <MethodResult> CatchPokemon(FortData fortData)
        {
            var response = await _client.ClientSession.RpcClient.SendRemoteProcedureCallAsync(new Request
            {
                RequestType    = RequestType.DiskEncounter,
                RequestMessage = new DiskEncounterMessage
                {
                    EncounterId     = fortData.LureInfo.EncounterId,
                    FortId          = fortData.Id,
                    GymLatDegrees   = fortData.Latitude,
                    GymLngDegrees   = fortData.Longitude,
                    PlayerLatitude  = _client.ClientSession.Player.Latitude,
                    PlayerLongitude = _client.ClientSession.Player.Longitude
                }.ToByteString()
            });

            if (response == null)
            {
                return(new MethodResult());
            }

            DiskEncounterResponse eResponse = DiskEncounterResponse.Parser.ParseFrom(response);

            switch (eResponse.Result)
            {
            case DiskEncounterResponse.Types.Result.Success:
                CatchPokemonResponse catchPokemonResponse = null;
                int attemptCount = 1;
                var berryUsed    = false;

                do
                {
                    //Uses lowest capture probability
                    float  probability = eResponse.CaptureProbability.CaptureProbability_[0];
                    ItemId pokeBall    = GetBestBall(eResponse.PokemonData);

                    if (pokeBall == ItemId.ItemUnknown)
                    {
                        LogCaller(new LoggerEventArgs("No pokeballs remaining (lure)", LoggerTypes.Warning));

                        return(new MethodResult
                        {
                            Message = "No pokeballs remaining"
                        });
                    }

                    if (UserSettings.UseBerries)
                    {
                        bool isLowProbability = probability < 0.35;
                        bool isHighCp         = eResponse.PokemonData.Cp > 700;
                        bool isHighPerfection = CalculateIVPerfection(eResponse.PokemonData) > 90;

                        if (!berryUsed)
                        {
                            if ((isLowProbability && isHighCp) || isHighPerfection)
                            {
                                await UseBerry(fortData.LureInfo.EncounterId, fortData.Id, ItemId.ItemRazzBerry);

                                berryUsed = true;
                            }
                            else
                            {
                                bool isHighProbability = probability > 0.65;
                                var  catchSettings     = UserSettings.CatchSettings.FirstOrDefault(x => x.Id == eResponse.PokemonData.PokemonId);
                                var  usePinap          = catchSettings != null && catchSettings.UsePinap;
                                if (isHighProbability && usePinap)
                                {
                                    await UseBerry(fortData.LureInfo.EncounterId, fortData.Id, ItemId.ItemPinapBerry);

                                    berryUsed = true;
                                }
                                else if (new Random().Next(0, 100) < 50)
                                {
                                    // IF we dont use razz neither use pinap, then we will use nanab randomly the 50% of times.
                                    await UseBerry(fortData.LureInfo.EncounterId, fortData.Id, ItemId.ItemNanabBerry);

                                    berryUsed = true;
                                }
                            }
                        }
                    }

                    double reticuleSize      = 1.95;
                    bool   hitInsideReticule = true;

                    //Humanization
                    if (UserSettings.EnableHumanization)
                    {
                        reticuleSize      = (double)_rand.Next(10, 195) / 100;
                        hitInsideReticule = HitInsideReticle();
                    }

                    //End humanization
                    var arPlusValues = new ARPlusEncounterValues();
                    if (UserSettings.GetArBonus)
                    {
                        LogCaller(new LoggerEventArgs("Using AR Bonus Values", LoggerTypes.Debug));
                        arPlusValues.Awareness         = (float)UserSettings.ARBonusAwareness;
                        arPlusValues.Proximity         = (float)UserSettings.ARBonusProximity;
                        arPlusValues.PokemonFrightened = false;
                    }

                    var catchresponse = await _client.ClientSession.RpcClient.SendRemoteProcedureCallAsync(new Request
                    {
                        RequestType    = RequestType.CatchPokemon,
                        RequestMessage = new CatchPokemonMessage
                        {
                            ArPlusValues          = arPlusValues,
                            EncounterId           = fortData.LureInfo.EncounterId,
                            HitPokemon            = hitInsideReticule,
                            NormalizedHitPosition = 1,
                            NormalizedReticleSize = reticuleSize,
                            Pokeball     = pokeBall,
                            SpawnPointId = fortData.Id,
                            SpinModifier = 1
                        }.ToByteString()
                    });

                    if (catchresponse == null)
                    {
                        return(new MethodResult());
                    }

                    catchPokemonResponse = CatchPokemonResponse.Parser.ParseFrom(catchresponse);
                    string pokemon      = String.Format("Name: {0}, CP: {1}, IV: {2:0.00}%", fortData.LureInfo.ActivePokemonId, eResponse.PokemonData.Cp, CalculateIVPerfection(eResponse.PokemonData));
                    string pokeBallName = pokeBall.ToString().Replace("Item", "");

                    switch (catchPokemonResponse.Status)
                    {
                    case CatchPokemonResponse.Types.CatchStatus.CatchError:
                        LogCaller(new LoggerEventArgs(String.Format("Unknown Error. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                        continue;

                    case CatchPokemonResponse.Types.CatchStatus.CatchEscape:
                        LogCaller(new LoggerEventArgs(String.Format("Escaped ball. {0}. Attempt #{1}.", pokemon, attemptCount), LoggerTypes.PokemonEscape));
                        berryUsed = false;
                        continue;

                    case CatchPokemonResponse.Types.CatchStatus.CatchFlee:
                        LogCaller(new LoggerEventArgs(String.Format("Pokemon fled. {0}. Attempt #{1}", pokemon, attemptCount), LoggerTypes.PokemonFlee));
                        continue;

                    case CatchPokemonResponse.Types.CatchStatus.CatchMissed:
                        LogCaller(new LoggerEventArgs(String.Format("Missed. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                        continue;

                    case CatchPokemonResponse.Types.CatchStatus.CatchSuccess:
                        int expGained   = catchPokemonResponse.CaptureAward.Xp.Sum();
                        int candyGained = catchPokemonResponse.CaptureAward.Candy.Sum();

                        Tracker.AddValues(1, 0);

                        ExpIncrease(expGained);

                        //_expGained += expGained;

                        fortData.LureInfo = null;

                        LogCaller(new LoggerEventArgs(String.Format("[Lured] Pokemon Caught. {0}. Exp {1}. Candy {2}. Attempt #{3}. Ball: {4}", pokemon, expGained, candyGained, attemptCount, pokeBallName), LoggerTypes.Success));

                        //Pokemon.Add(eResponse.PokemonData);
                        UpdateInventory(InventoryRefresh.Pokemon);

                        return(new MethodResult
                        {
                            Message = "Pokemon caught",
                            Success = true
                        });
                    }
                    ++attemptCount;

                    await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
                } while (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
                break;

            case DiskEncounterResponse.Types.Result.EncounterAlreadyFinished:
                return(new MethodResult
                {
                    Message = "Encounter not available"
                });

            case DiskEncounterResponse.Types.Result.NotAvailable:
                return(new MethodResult
                {
                    Message = "Encounter not available"
                });

            case DiskEncounterResponse.Types.Result.NotInRange:
                LogCaller(new LoggerEventArgs(String.Format("Lured encounter failed with response {0}", eResponse.Result), LoggerTypes.Warning));
                return(new MethodResult
                {
                    Message = "Encounter failed"
                });

            case DiskEncounterResponse.Types.Result.PokemonInventoryFull:
                LogCaller(new LoggerEventArgs("Encounter failed. Pokemon inventory full", LoggerTypes.Warning));

                return(new MethodResult
                {
                    Message = "Encounter failed. Pokemon inventory full"
                });

            case DiskEncounterResponse.Types.Result.Unknown:
                LogCaller(new LoggerEventArgs(String.Format("Lured encounter failed with response {0}", eResponse.Result), LoggerTypes.Warning));

                return(new MethodResult
                {
                    Message = "Encounter failed"
                });
            }
            return(new MethodResult());
        }