Esempio n. 1
0
        async Task ExecuteCatchCommand()
        {
            var encounterPokemonResponse = await Encounter();

            if (encounterPokemonResponse.IsSuccess)
            {
                MessengerInstance.Send(new Message(Colors.Green, $"Encountered a {encounterPokemonResponse.Pokemon.Name}"));
                var pokeball = GetPokeBall();
                CatchPokemonResponse caughtPokemonResponse = null;
                do
                {
                    // returns an exception at the moment.
                    //if (settings.UseRazzBerryWhenPokemonIsAboveCP <= pokemonCP ||
                    //    settings.UseRazzBerryWhenCatchProbabilityIsBelow <= encounterPokemonResponse.CaptureProbability.CaptureProbability_.First())
                    //    await session.UseCaptureItem(pokemon.EncounterId, POGOProtos.Inventory.Item.ItemId.ItemRazzBerry, pokemon.SpawnPointId);

                    // TODO calculate pokeball based on encountered pokemon
                    if (pokeball.Count > 0)
                    {
                        MessengerInstance.Send(new Message(Colors.Green, $"Using a {pokeball.Name}"));
                        pokeball.Count--;
                        caughtPokemonResponse = await session.CatchPokemon(EncounterId, SpawnPointId, (POGOProtos.Inventory.Item.ItemId) pokeball.ItemType);
                    }
                    else
                    {
                        MessengerInstance.Send(new Message(Colors.Yellow, "No pokeballs left."));
                    }
                } while (pokeball.Count > 0 && (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape));

                if (caughtPokemonResponse != null)
                {
                    if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                    {
                        encounterPokemonResponse.PokemonData.Id = caughtPokemonResponse.CapturedPokemonId;
                        var caughtPokemon = new CaughtPokemonViewModel(encounterPokemonResponse.PokemonData, session, player.Inventory, settings);
                        var xp            = caughtPokemonResponse.CaptureAward.Xp.Sum();
                        player.Xp += xp;
                        var stardust = caughtPokemonResponse.CaptureAward.Stardust.Sum();
                        player.Stardust += stardust;
                        var candy = caughtPokemonResponse.CaptureAward.Candy.Sum();
                        player.Inventory.AddCandyForFamily(candy, caughtPokemon.FamilyId);
                        MessengerInstance.Send(new Message(Colors.Green, $"Caught a {encounterPokemonResponse.Pokemon.Name}. {xp} Xp - {candy} Candy - {stardust} Stardust."));
                        player.Inventory.Pokemon.AddOrUpdate(caughtPokemon);
                        map.CatchablePokemon.Remove(this);
                    }
                    else if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee)
                    {
                        MessengerInstance.Send(new Message(Colors.Red, $"Failed to catch a {encounterPokemonResponse.Pokemon.Name}, because it fled."));
                    }
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Because this function sometime being called inside loop, return true it mean we don't want break look, false it mean not need to call this , break a loop from caller function
        /// </summary>
        /// <param name="session"></param>
        /// <param name="cancellationToken"></param>
        /// <param name="encounter"></param>
        /// <param name="pokemon"></param>
        /// <param name="currentFortData"></param>
        /// <param name="sessionAllowTransfer"></param>
        /// <returns></returns>
        public static async Task <bool> Execute(ISession session,
                                                CancellationToken cancellationToken,
                                                dynamic encounter,
                                                MapPokemon pokemon,
                                                FortData currentFortData,
                                                bool sessionAllowTransfer)
        {
            var manager = TinyIoCContainer.Current.Resolve <MultiAccountManager>();

            manager.ThrowIfSwitchAccountRequested();
            // If the encounter is null nothing will work below, so exit now
            if (encounter == null)
            {
                return(true);
            }

            var totalBalls = (await session.Inventory.GetItems().ConfigureAwait(false)).Where(x => x.ItemId == ItemId.ItemPokeBall || x.ItemId == ItemId.ItemGreatBall || x.ItemId == ItemId.ItemUltraBall).Sum(x => x.Count);

            if (session.SaveBallForByPassCatchFlee && totalBalls < BALL_REQUIRED_TO_BYPASS_CATCHFLEE)
            {
                return(false);
            }

            // Exit if user defined max limits reached
            if (session.Stats.CatchThresholdExceeds(session))
            {
                if (manager.AllowMultipleBot() &&
                    session.LogicSettings.MultipleBotConfig.SwitchOnCatchLimit &&
                    TinyIoCContainer.Current.Resolve <MultiAccountManager>().AllowSwitch())
                {
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.CatchLimitReached,
                              ReachedValue = session.LogicSettings.CatchPokemonLimit
                          };
                }

                return(false);
            }
            using (var block = new BlockableScope(session, BotActions.Catch))
            {
                if (!await block.WaitToRun().ConfigureAwait(false))
                {
                    return(true);
                }

                AmountOfBerries = new Dictionary <ItemId, int>();

                cancellationToken.ThrowIfCancellationRequested();

                float probability = encounter.CaptureProbability?.CaptureProbability_[0];

                PokemonData encounteredPokemon;
                long        unixTimeStamp;
                ulong       _encounterId;
                string      _spawnPointId;

                // Calling from CatchNearbyPokemonTask and SnipePokemonTask
                if (encounter is EncounterResponse &&
                    (encounter?.Status == EncounterResponse.Types.Status.EncounterSuccess))
                {
                    encounteredPokemon = encounter.WildPokemon?.PokemonData;
                    unixTimeStamp      = encounter.WildPokemon?.LastModifiedTimestampMs
                                         + encounter.WildPokemon?.TimeTillHiddenMs;
                    _spawnPointId = encounter.WildPokemon?.SpawnPointId;
                    _encounterId  = encounter.WildPokemon?.EncounterId;
                }
                // Calling from CatchIncensePokemonTask
                else if (encounter is IncenseEncounterResponse &&
                         (encounter?.Result == IncenseEncounterResponse.Types.Result.IncenseEncounterSuccess))
                {
                    encounteredPokemon = encounter?.PokemonData;
                    unixTimeStamp      = pokemon.ExpirationTimestampMs;
                    _spawnPointId      = pokemon.SpawnPointId;
                    _encounterId       = pokemon.EncounterId;
                }
                // Calling from CatchLurePokemon
                else if (encounter is DiskEncounterResponse &&
                         encounter?.Result == DiskEncounterResponse.Types.Result.Success &&
                         !(currentFortData == null))
                {
                    encounteredPokemon = encounter?.PokemonData;
                    unixTimeStamp      = currentFortData.LureInfo.LureExpiresTimestampMs;
                    _spawnPointId      = currentFortData.Id;
                    _encounterId       = currentFortData.LureInfo.EncounterId;
                }
                else
                {
                    return(true); // No success to work with, exit
                }
                // Check for pokeballs before proceeding
                var pokeball = await GetBestBall(session, encounteredPokemon, probability).ConfigureAwait(false);

                if (pokeball == ItemId.ItemUnknown)
                {
                    Logger.Write(session.Translation.GetTranslation(TranslationString.ZeroPokeballInv));
                    return(false);
                }

                // Calculate CP and IV
                var pokemonCp = encounteredPokemon?.Cp;
                var pokemonIv = PokemonInfo.CalculatePokemonPerfection(encounteredPokemon);
                var lv        = PokemonInfo.GetLevel(encounteredPokemon);

                // Calculate distance away
                var latitude = encounter is EncounterResponse || encounter is IncenseEncounterResponse
                    ? pokemon.Latitude
                    : currentFortData.Latitude;
                var longitude = encounter is EncounterResponse || encounter is IncenseEncounterResponse
                    ? pokemon.Longitude
                    : currentFortData.Longitude;

                var distance = LocationUtils.CalculateDistanceInMeters(session.Client.CurrentLatitude,
                                                                       session.Client.CurrentLongitude, latitude, longitude);
                if (session.LogicSettings.ActivateMSniper)
                {
                    var newdata = new MSniperServiceTask.EncounterInfo()
                    {
                        EncounterId  = _encounterId.ToString(),
                        Iv           = Math.Round(pokemonIv, 2),
                        Latitude     = latitude.ToString("G17", CultureInfo.InvariantCulture),
                        Longitude    = longitude.ToString("G17", CultureInfo.InvariantCulture),
                        PokemonId    = (int)(encounteredPokemon?.PokemonId ?? 0),
                        PokemonName  = encounteredPokemon?.PokemonId.ToString(),
                        SpawnPointId = _spawnPointId,
                        Move1        = PokemonInfo.GetPokemonMove1(encounteredPokemon).ToString(),
                        Move2        = PokemonInfo.GetPokemonMove2(encounteredPokemon).ToString(),
                        Expiration   = unixTimeStamp
                    };
                    session.EventDispatcher.Send(newdata);
                }

                DateTime expiredDate =
                    new DateTime(1970, 1, 1, 0, 0, 0).AddMilliseconds(Convert.ToDouble(unixTimeStamp));
                var encounterEV = new EncounteredEvent()
                {
                    Latitude        = latitude,
                    Longitude       = longitude,
                    PokemonId       = encounteredPokemon.PokemonId,
                    IV              = pokemonIv,
                    Level           = (int)lv,
                    Expires         = expiredDate.ToUniversalTime(),
                    ExpireTimestamp = unixTimeStamp,
                    SpawnPointId    = _spawnPointId,
                    EncounterId     = _encounterId.ToString(),
                    Move1           = PokemonInfo.GetPokemonMove1(encounteredPokemon).ToString(),
                    Move2           = PokemonInfo.GetPokemonMove2(encounteredPokemon).ToString(),
                };

                //add catch to avoid snipe duplicate
                string uniqueCacheKey = CatchPokemonTask.GetUsernameGeoLocationCacheKey(session.Settings.Username, encounterEV.PokemonId, encounterEV.Latitude, encounterEV.Longitude);
                session.Cache.Add(uniqueCacheKey, encounterEV, DateTime.Now.AddMinutes(30));

                session.EventDispatcher.Send(encounterEV);

                if (IsNotMetWithCatchCriteria(session, encounteredPokemon, pokemonIv, lv, pokemonCp))
                {
                    session.EventDispatcher.Send(new NoticeEvent
                    {
                        Message = session.Translation.GetTranslation(TranslationString.PokemonSkipped,
                                                                     encounteredPokemon.PokemonId)
                    });
                    session.Cache.Add(CatchPokemonTask.GetEncounterCacheKey(_encounterId), encounteredPokemon, expiredDate);
                    Logger.Write(
                        $"Filter catch not met. {encounteredPokemon.PokemonId.ToString()} IV {pokemonIv} lv {lv} {pokemonCp} move1 {PokemonInfo.GetPokemonMove1(encounteredPokemon)} move 2 {PokemonInfo.GetPokemonMove2(encounteredPokemon)}");
                    return(true);
                }

                CatchPokemonResponse caughtPokemonResponse = null;
                var lastThrow      = CatchPokemonResponse.Types.CatchStatus.CatchSuccess; // Initializing lastThrow
                var attemptCounter = 1;

                // Main CatchPokemon-loop
                do
                {
                    if (session.LogicSettings.UseHumanlikeDelays)
                    {
                        await DelayingUtils.DelayAsync(session.LogicSettings.BeforeCatchDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false);
                    }

                    if ((session.LogicSettings.MaxPokeballsPerPokemon > 0 &&
                         attemptCounter > session.LogicSettings.MaxPokeballsPerPokemon))
                    {
                        break;
                    }

                    pokeball = await GetBestBall(session, encounteredPokemon, probability).ConfigureAwait(false);

                    if (pokeball == ItemId.ItemUnknown)
                    {
                        session.EventDispatcher.Send(new NoPokeballEvent
                        {
                            Id = encounter is EncounterResponse ? pokemon.PokemonId : encounter?.PokemonData.PokemonId,
                            Cp = encounteredPokemon.Cp
                        });
                        return(false);
                    }

                    // Determine whether to use berries or not
                    if (lastThrow != CatchPokemonResponse.Types.CatchStatus.CatchMissed)
                    {
                        //AmountOfBerries++;
                        //if (AmountOfBerries <= session.LogicSettings.MaxBerriesToUsePerPokemon)
                        await UseBerry(session,
                                       encounterEV.PokemonId,
                                       _encounterId,
                                       _spawnPointId,
                                       pokemonIv,
                                       pokemonCp ?? 10000, //unknown CP pokemon, want to use berry
                                       encounterEV.Level,
                                       probability,
                                       cancellationToken).ConfigureAwait(false);
                    }

                    bool hitPokemon = true;

                    //default to excellent throw
                    var normalizedRecticleSize = 1.95;

                    //default spin
                    var spinModifier = 1.0;

                    //Humanized throws
                    if (session.LogicSettings.EnableHumanizedThrows)
                    {
                        //thresholds: https://gist.github.com/anonymous/077d6dea82d58b8febde54ae9729b1bf
                        var spinTxt = "Curve";
                        var hitTxt  = "Excellent";
                        if (pokemonCp > session.LogicSettings.ForceExcellentThrowOverCp ||
                            pokemonIv > session.LogicSettings.ForceExcellentThrowOverIv)
                        {
                            normalizedRecticleSize = Random.NextDouble() * (1.95 - 1.7) + 1.7;
                        }
                        else if (pokemonCp >= session.LogicSettings.ForceGreatThrowOverCp ||
                                 pokemonIv >= session.LogicSettings.ForceGreatThrowOverIv)
                        {
                            normalizedRecticleSize = Random.NextDouble() * (1.95 - 1.3) + 1.3;
                            hitTxt = "Great";
                        }
                        else
                        {
                            var regularThrow = 100 - (session.LogicSettings.ExcellentThrowChance +
                                                      session.LogicSettings.GreatThrowChance +
                                                      session.LogicSettings.NiceThrowChance);
                            var rnd = Random.Next(1, 101);

                            if (rnd <= regularThrow)
                            {
                                normalizedRecticleSize = Random.NextDouble() * (1 - 0.1) + 0.1;
                                hitTxt = "Ordinary";
                            }
                            else if (rnd <= regularThrow + session.LogicSettings.NiceThrowChance)
                            {
                                normalizedRecticleSize = Random.NextDouble() * (1.3 - 1) + 1;
                                hitTxt = "Nice";
                            }
                            else if (rnd <=
                                     regularThrow + session.LogicSettings.NiceThrowChance +
                                     session.LogicSettings.GreatThrowChance)
                            {
                                normalizedRecticleSize = Random.NextDouble() * (1.7 - 1.3) + 1.3;
                                hitTxt = "Great";
                            }

                            if (Random.NextDouble() * 100 > session.LogicSettings.CurveThrowChance)
                            {
                                spinModifier = 0.0;
                                spinTxt      = "Straight";
                            }
                        }


                        // Round to 2 decimals
                        normalizedRecticleSize = Math.Round(normalizedRecticleSize, 2);

                        // Missed throw check
                        int missChance = Random.Next(1, 101);
                        if (missChance <= session.LogicSettings.ThrowMissPercentage &&
                            session.LogicSettings.EnableMissedThrows)
                        {
                            hitPokemon = false;
                        }

                        Logger.Write($"(Threw ball) {hitTxt} throw, {spinTxt}-ball, HitPokemon = {hitPokemon}...",
                                     LogLevel.Debug);
                    }

                    if (CatchFleeContinuouslyCount >= 3 && session.LogicSettings.ByPassCatchFlee)
                    {
                        MSniperServiceTask.BlockSnipe();

                        if (totalBalls <= BALL_REQUIRED_TO_BYPASS_CATCHFLEE)
                        {
                            Logger.Write("You don't have enough balls to bypass catchflee");
                            return(false);
                        }
                        List <ItemId> ballToByPass = new List <ItemId>();
                        var           numPokeBalls = await session.Inventory.GetItemAmountByType(ItemId.ItemPokeBall).ConfigureAwait(false);

                        for (int i = 0; i < numPokeBalls - 1; i++)
                        {
                            ballToByPass.Add(ItemId.ItemPokeBall);
                        }
                        var numGreatBalls = await session.Inventory.GetItemAmountByType(ItemId.ItemGreatBall).ConfigureAwait(false);

                        for (int i = 0; i < numGreatBalls - 1; i++)
                        {
                            ballToByPass.Add(ItemId.ItemGreatBall);
                        }
                        var numUltraBalls = await session.Inventory.GetItemAmountByType(ItemId.ItemUltraBall).ConfigureAwait(false);

                        for (int i = 0; i < numUltraBalls - 1; i++)
                        {
                            ballToByPass.Add(ItemId.ItemUltraBall);
                        }
                        bool catchMissed = true;

                        Random r = new Random();
                        for (int i = 0; i < ballToByPass.Count - 1; i++)
                        {
                            if (i > 130 && r.Next(0, 100) <= 30)
                            {
                                catchMissed = false;
                            }
                            else
                            {
                                catchMissed = true;
                            }

                            caughtPokemonResponse =
                                await session.Client.Encounter.CatchPokemon(
                                    encounter is EncounterResponse || encounter is IncenseEncounterResponse
                                    ?pokemon.EncounterId
                                    : _encounterId,
                                    encounter is EncounterResponse || encounter is IncenseEncounterResponse
                                    ?pokemon.SpawnPointId
                                    : currentFortData.Id, ballToByPass[i], 1.0, 1.0, !catchMissed).ConfigureAwait(false);

                            await session.Inventory.UpdateInventoryItem(ballToByPass[i]).ConfigureAwait(false);

                            await Task.Delay(100).ConfigureAwait(false);

                            Logger.Write($"CatchFlee By pass : {ballToByPass[i].ToString()} , Attempt {i}, result {caughtPokemonResponse.Status}");

                            if (caughtPokemonResponse.Status != CatchPokemonResponse.Types.CatchStatus.CatchMissed)
                            {
                                session.SaveBallForByPassCatchFlee = false;
                                CatchFleeContinuouslyCount         = 0;
                                break;
                            }
                        }
                    }
                    else
                    {
                        caughtPokemonResponse =
                            await session.Client.Encounter.CatchPokemon(
                                encounter is EncounterResponse || encounter is IncenseEncounterResponse
                                ?pokemon.EncounterId
                                : _encounterId,
                                encounter is EncounterResponse || encounter is IncenseEncounterResponse
                                ?pokemon.SpawnPointId
                                : currentFortData.Id, pokeball, normalizedRecticleSize, spinModifier, hitPokemon).ConfigureAwait(false);

                        await session.Inventory.UpdateInventoryItem(pokeball).ConfigureAwait(false);
                    }


                    var evt = new PokemonCaptureEvent()
                    {
                        Status        = caughtPokemonResponse.Status,
                        CaptureReason = caughtPokemonResponse.CaptureReason,
                        Latitude      = latitude,
                        Longitude     = longitude
                    };

                    lastThrow = caughtPokemonResponse.Status; // sets lastThrow status


                    if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                    {
                        evt.Shiny   = (await session.Inventory.GetPokemons().ConfigureAwait(false)).First(x => x.Id == caughtPokemonResponse.CapturedPokemonId).PokemonDisplay.Shiny ? "Yes" : "No";
                        evt.Form    = (await session.Inventory.GetPokemons().ConfigureAwait(false)).First(x => x.Id == caughtPokemonResponse.CapturedPokemonId).PokemonDisplay.Form.ToString().Replace("Unown", "").Replace("Unset", "Normal");
                        evt.Costume = (await session.Inventory.GetPokemons().ConfigureAwait(false)).First(x => x.Id == caughtPokemonResponse.CapturedPokemonId).PokemonDisplay.Costume.ToString().Replace("Unset", "Regular");
                        evt.Gender  = (await session.Inventory.GetPokemons().ConfigureAwait(false)).First(x => x.Id == caughtPokemonResponse.CapturedPokemonId).PokemonDisplay.Gender.ToString();

                        var totalExp      = 0;
                        var stardust      = caughtPokemonResponse.CaptureAward.Stardust.Sum();
                        var totalStarDust = session.Inventory.UpdateStarDust(stardust);
                        var CaptuerXP     = caughtPokemonResponse.CaptureAward.Xp.Sum();

                        if (encounteredPokemon != null)
                        {
                            encounteredPokemon.Id = caughtPokemonResponse.CapturedPokemonId;
                        }
                        foreach (var xp in caughtPokemonResponse.CaptureAward.Xp)
                        {
                            totalExp += xp;
                        }

                        //This accounts for XP for CatchFlee
                        if (totalExp < 1)
                        {
                            totalExp = 25;
                        }

                        evt.Exp      = totalExp;
                        evt.Stardust = stardust;
                        evt.UniqueId = caughtPokemonResponse.CapturedPokemonId;
                        evt.Candy    = await session.Inventory.GetCandyFamily(pokemon.PokemonId).ConfigureAwait(false);

                        evt.totalStarDust = totalStarDust;

                        if (session.LogicSettings.AutoFavoriteShinyOnCatch)
                        {
                            if (evt.Shiny == "Yes")
                            {
                                await FavoritePokemonTask.Execute(session, encounteredPokemon.Id, true);

                                Logger.Write($"You've caught a Shiny Pokemon ({encounteredPokemon.Nickname}) and it has been Favorited.");
                            }
                        }
                    }

                    if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess ||
                        caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee)
                    {
                        // Also count catch flee against the catch limit
                        if (session.LogicSettings.UseCatchLimit)
                        {
                            session.Stats.AddPokemonTimestamp(DateTime.Now.Ticks);
                            session.EventDispatcher.Send(new CatchLimitUpdate(session.Stats.GetNumPokemonsInLast24Hours(), session.LogicSettings.CatchPokemonLimit));
                        }
                    }

                    evt.CatchType = encounter is EncounterResponse
                        ? session.Translation.GetTranslation(TranslationString.CatchTypeNormal)
                        : encounter is DiskEncounterResponse
                            ? session.Translation.GetTranslation(TranslationString.CatchTypeLure)
                            : session.Translation.GetTranslation(TranslationString.CatchTypeIncense);

                    evt.CatchTypeText = encounter is EncounterResponse
                        ? "normal"
                        : encounter is DiskEncounterResponse
                            ? "lure"
                            : "incense";
                    evt.Id = encounter is EncounterResponse
                        ? pokemon.PokemonId
                        : encounter?.PokemonData.PokemonId;
                    evt.EncounterId  = _encounterId;
                    evt.Move1        = PokemonInfo.GetPokemonMove1(encounteredPokemon);
                    evt.Move2        = PokemonInfo.GetPokemonMove2(encounteredPokemon);
                    evt.Expires      = pokemon?.ExpirationTimestampMs ?? 0;
                    evt.SpawnPointId = _spawnPointId;
                    evt.Level        = PokemonInfo.GetLevel(encounteredPokemon);
                    evt.Cp           = encounteredPokemon.Cp;
                    evt.MaxCp        = PokemonInfo.CalculateMaxCp(encounteredPokemon.PokemonId);
                    evt.Perfection   = Math.Round(PokemonInfo.CalculatePokemonPerfection(encounteredPokemon), 2);
                    evt.Probability  = Math.Round(probability * 100, 2);
                    evt.Distance     = distance;
                    evt.Pokeball     = pokeball;
                    evt.Attempt      = attemptCounter;

                    //await session.Inventory.RefreshCachedInventory().ConfigureAwait(false);

                    evt.BallAmount = await session.Inventory.GetItemAmountByType(pokeball).ConfigureAwait(false);

                    evt.Rarity = PokemonGradeHelper.GetPokemonGrade(evt.Id).ToString();

                    session.EventDispatcher.Send(evt);

                    attemptCounter++;

                    // If Humanlike delays are used
                    if (session.LogicSettings.UseHumanlikeDelays)
                    {
                        switch (caughtPokemonResponse.Status)
                        {
                        case CatchPokemonResponse.Types.CatchStatus.CatchError:
                            await DelayingUtils.DelayAsync(session.LogicSettings.CatchErrorDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false);

                            break;

                        case CatchPokemonResponse.Types.CatchStatus.CatchSuccess:
                            await DelayingUtils.DelayAsync(session.LogicSettings.CatchSuccessDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false);

                            break;

                        case CatchPokemonResponse.Types.CatchStatus.CatchEscape:
                            await DelayingUtils.DelayAsync(session.LogicSettings.CatchEscapeDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false);

                            break;

                        case CatchPokemonResponse.Types.CatchStatus.CatchFlee:
                            await DelayingUtils.DelayAsync(session.LogicSettings.CatchFleeDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false);

                            break;

                        case CatchPokemonResponse.Types.CatchStatus.CatchMissed:
                            await DelayingUtils.DelayAsync(session.LogicSettings.CatchMissedDelay, 0, session.CancellationTokenSource.Token).ConfigureAwait(false);

                            break;

                        default:
                            break;
                        }
                    }
                    else
                    {
                        await DelayingUtils.DelayAsync(session.LogicSettings.DelayBetweenPlayerActions, 0, session.CancellationTokenSource.Token).ConfigureAwait(false);
                    }
                } while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed ||
                         caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);

                if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee)
                {
                    CatchFleeContinuouslyCount++;
                    if (CatchFleeContinuouslyCount >= 3 && session.LogicSettings.ByPassCatchFlee)
                    {
                        session.SaveBallForByPassCatchFlee = true;
                        Logger.Write("Seem that bot has been catch flee softban, Bot will start save 100 balls to by pass it.");
                    }
                    if (manager.AllowMultipleBot() && !session.LogicSettings.ByPassCatchFlee)
                    {
                        if (CatchFleeContinuouslyCount > session.LogicSettings.MultipleBotConfig.CatchFleeCount &&
                            TinyIoCContainer.Current.Resolve <MultiAccountManager>().AllowSwitch())
                        {
                            CatchFleeContinuouslyCount         = 0;
                            session.SaveBallForByPassCatchFlee = false;

                            throw new ActiveSwitchByRuleException()
                                  {
                                      MatchedRule  = SwitchRules.CatchFlee,
                                      ReachedValue = session.LogicSettings.MultipleBotConfig.CatchFleeCount
                                  };
                        }
                    }
                }
                else
                {
                    //reset if not catch flee.
                    if (caughtPokemonResponse.Status != CatchPokemonResponse.Types.CatchStatus.CatchMissed)
                    {
                        CatchFleeContinuouslyCount = 0;
                        MSniperServiceTask.UnblockSnipe();
                    }
                }

                session.Actions.RemoveAll(x => x == BotActions.Catch);

                if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings, manager))
                {
                    ExecuteSwitcher(session, encounterEV);
                }

                if (session.LogicSettings.TransferDuplicatePokemonOnCapture &&
                    session.LogicSettings.TransferDuplicatePokemon &&
                    sessionAllowTransfer &&
                    caughtPokemonResponse != null &&
                    caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                {
                    if (session.LogicSettings.UseNearActionRandom)
                    {
                        await HumanRandomActionTask.TransferRandom(session, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        await TransferDuplicatePokemonTask.Execute(session, cancellationToken).ConfigureAwait(false);
                    }
                }
            }
            return(true);
        }
Esempio n. 3
0
        /// <summary>
        /// Because this function sometime being called inside loop, return true it mean we don't want break look, false it mean not need to call this , break a loop from caller function
        /// </summary>
        /// <param name="session"></param>
        /// <param name="cancellationToken"></param>
        /// <param name="encounter"></param>
        /// <param name="pokemon"></param>
        /// <param name="currentFortData"></param>
        /// <param name="sessionAllowTransfer"></param>
        /// <returns></returns>
        public static async Task <bool> Execute(ISession session,
                                                CancellationToken cancellationToken,
                                                dynamic encounter,
                                                MapPokemon pokemon,
                                                FortData currentFortData,
                                                bool sessionAllowTransfer)
        {
            // If the encounter is null nothing will work below, so exit now
            if (encounter == null)
            {
                return(true);
            }
            // Exit if user defined max limits reached
            if (session.Stats.CatchThresholdExceeds(session))
            {
                if (session.LogicSettings.AllowMultipleBot &&
                    session.LogicSettings.MultipleBotConfig.SwitchOnCatchLimit)
                {
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.CatchLimitReached,
                              ReachedValue = session.LogicSettings.CatchPokemonLimit
                          };
                }

                return(false);
            }
            using (var block = new BlockableScope(session, BotActions.Catch))
            {
                if (!await block.WaitToRun())
                {
                    return(true);
                }

                AmountOfBerries = 0;

                cancellationToken.ThrowIfCancellationRequested();

                float probability = encounter.CaptureProbability?.CaptureProbability_[0];

                PokemonData encounteredPokemon;
                long        unixTimeStamp;
                ulong       _encounterId;
                string      _spawnPointId;

                // Calling from CatchNearbyPokemonTask and SnipePokemonTask
                if (encounter is EncounterResponse &&
                    (encounter?.Status == EncounterResponse.Types.Status.EncounterSuccess))
                {
                    encounteredPokemon = encounter.WildPokemon?.PokemonData;
                    unixTimeStamp      = encounter.WildPokemon?.LastModifiedTimestampMs
                                         + encounter.WildPokemon?.TimeTillHiddenMs;
                    _spawnPointId = encounter.WildPokemon?.SpawnPointId;
                    _encounterId  = encounter.WildPokemon?.EncounterId;
                }
                // Calling from CatchIncensePokemonTask
                else if (encounter is IncenseEncounterResponse &&
                         (encounter?.Result == IncenseEncounterResponse.Types.Result.IncenseEncounterSuccess))
                {
                    encounteredPokemon = encounter?.PokemonData;
                    unixTimeStamp      = pokemon.ExpirationTimestampMs;
                    _spawnPointId      = pokemon.SpawnPointId;
                    _encounterId       = pokemon.EncounterId;
                }
                // Calling from CatchLurePokemon
                else if (encounter is DiskEncounterResponse &&
                         encounter?.Result == DiskEncounterResponse.Types.Result.Success &&
                         !(currentFortData == null))
                {
                    encounteredPokemon = encounter?.PokemonData;
                    unixTimeStamp      = currentFortData.LureInfo.LureExpiresTimestampMs;
                    _spawnPointId      = currentFortData.Id;
                    _encounterId       = currentFortData.LureInfo.EncounterId;
                }
                else
                {
                    return(true); // No success to work with, exit
                }
                // Check for pokeballs before proceeding
                var pokeball = await GetBestBall(session, encounteredPokemon, probability);

                if (pokeball == ItemId.ItemUnknown)
                {
                    Logger.Write(session.Translation.GetTranslation(TranslationString.ZeroPokeballInv));
                    return(false);
                }

                // Calculate CP and IV
                var pokemonCp = encounteredPokemon?.Cp;
                var pokemonIv = PokemonInfo.CalculatePokemonPerfection(encounteredPokemon);
                var lv        = PokemonInfo.GetLevel(encounteredPokemon);

                // Calculate distance away
                var latitude = encounter is EncounterResponse || encounter is IncenseEncounterResponse
                    ? pokemon.Latitude
                    : currentFortData.Latitude;
                var longitude = encounter is EncounterResponse || encounter is IncenseEncounterResponse
                    ? pokemon.Longitude
                    : currentFortData.Longitude;

                var distance = LocationUtils.CalculateDistanceInMeters(session.Client.CurrentLatitude,
                                                                       session.Client.CurrentLongitude, latitude, longitude);
                if (session.LogicSettings.ActivateMSniper)
                {
                    var newdata = new MSniperServiceTask.EncounterInfo();
                    newdata.EncounterId  = _encounterId.ToString();
                    newdata.Iv           = Math.Round(pokemonIv, 2);
                    newdata.Latitude     = latitude.ToString("G17", CultureInfo.InvariantCulture);
                    newdata.Longitude    = longitude.ToString("G17", CultureInfo.InvariantCulture);
                    newdata.PokemonId    = (int)(encounteredPokemon?.PokemonId ?? 0);
                    newdata.PokemonName  = encounteredPokemon?.PokemonId.ToString();
                    newdata.SpawnPointId = _spawnPointId;
                    newdata.Move1        = PokemonInfo.GetPokemonMove1(encounteredPokemon).ToString();
                    newdata.Move2        = PokemonInfo.GetPokemonMove2(encounteredPokemon).ToString();
                    newdata.Expiration   = unixTimeStamp;

                    session.EventDispatcher.Send(newdata);
                }

                DateTime expiredDate =
                    new DateTime(1970, 1, 1, 0, 0, 0).AddMilliseconds(Convert.ToDouble(unixTimeStamp));
                var encounterEV = new EncounteredEvent()
                {
                    Latitude        = latitude,
                    Longitude       = longitude,
                    PokemonId       = encounteredPokemon.PokemonId,
                    IV              = pokemonIv,
                    Level           = (int)lv,
                    Expires         = expiredDate.ToUniversalTime(),
                    ExpireTimestamp = unixTimeStamp,
                    SpawnPointId    = _spawnPointId,
                    EncounterId     = _encounterId.ToString(),
                    Move1           = PokemonInfo.GetPokemonMove1(encounteredPokemon).ToString(),
                    Move2           = PokemonInfo.GetPokemonMove2(encounteredPokemon).ToString(),
                };

                //add catch to avoid snipe duplicate
                string uniqueCacheKey =
                    $"{session.Settings.PtcUsername}{session.Settings.GoogleUsername}{Math.Round(encounterEV.Latitude, 6)}{encounterEV.PokemonId}{Math.Round(encounterEV.Longitude, 6)}";
                session.Cache.Add(uniqueCacheKey, encounterEV, DateTime.Now.AddMinutes(15));

                session.EventDispatcher.Send(encounterEV);

                if (IsNotMetWithCatchCriteria(session, encounteredPokemon, pokemonIv, lv, pokemonCp))
                {
                    session.EventDispatcher.Send(new NoticeEvent
                    {
                        Message = session.Translation.GetTranslation(TranslationString.PokemonSkipped,
                                                                     encounteredPokemon.PokemonId)
                    });
                    session.Cache.Add(_encounterId.ToString(), encounteredPokemon, expiredDate);
                    Logger.Write(
                        $"Filter catch not met. {encounteredPokemon.PokemonId.ToString()} IV {pokemonIv} lv {lv} {pokemonCp} move1 {PokemonInfo.GetPokemonMove1(encounteredPokemon)} move 2 {PokemonInfo.GetPokemonMove2(encounteredPokemon)}");
                    return(true);
                }

                CatchPokemonResponse caughtPokemonResponse = null;
                var lastThrow      = CatchPokemonResponse.Types.CatchStatus.CatchSuccess; // Initializing lastThrow
                var attemptCounter = 1;

                // Main CatchPokemon-loop
                do
                {
                    if ((session.LogicSettings.MaxPokeballsPerPokemon > 0 &&
                         attemptCounter > session.LogicSettings.MaxPokeballsPerPokemon))
                    {
                        break;
                    }

                    pokeball = await GetBestBall(session, encounteredPokemon, probability);

                    if (pokeball == ItemId.ItemUnknown)
                    {
                        session.EventDispatcher.Send(new NoPokeballEvent
                        {
                            Id = encounter is EncounterResponse ? pokemon.PokemonId : encounter?.PokemonData.PokemonId,
                            Cp = encounteredPokemon.Cp
                        });
                        return(false);
                    }

                    // Determine whether to use berries or not
                    if (((session.LogicSettings.UseBerriesOperator.ToLower().Equals("and") &&
                          pokemonIv >= session.LogicSettings.UseBerriesMinIv &&
                          pokemonCp >= session.LogicSettings.UseBerriesMinCp &&
                          probability < session.LogicSettings.UseBerriesBelowCatchProbability) ||
                         (session.LogicSettings.UseBerriesOperator.ToLower().Equals("or") && (
                              pokemonIv >= session.LogicSettings.UseBerriesMinIv ||
                              pokemonCp >= session.LogicSettings.UseBerriesMinCp ||
                              probability < session.LogicSettings.UseBerriesBelowCatchProbability))) &&
                        // if last throw is a miss, no double berry
                        lastThrow != CatchPokemonResponse.Types.CatchStatus.CatchMissed)
                    {
                        AmountOfBerries++;
                        if (AmountOfBerries <= session.LogicSettings.MaxBerriesToUsePerPokemon)
                        {
                            await UseBerry(session, _encounterId, _spawnPointId, cancellationToken);
                        }
                    }

                    bool hitPokemon = true;

                    //default to excellent throw
                    var normalizedRecticleSize = 1.95;

                    //default spin
                    var spinModifier = 1.0;

                    //Humanized throws
                    if (session.LogicSettings.EnableHumanizedThrows)
                    {
                        //thresholds: https://gist.github.com/anonymous/077d6dea82d58b8febde54ae9729b1bf
                        var spinTxt = "Curve";
                        var hitTxt  = "Excellent";
                        if (pokemonCp > session.LogicSettings.ForceExcellentThrowOverCp ||
                            pokemonIv > session.LogicSettings.ForceExcellentThrowOverIv)
                        {
                            normalizedRecticleSize = Random.NextDouble() * (1.95 - 1.7) + 1.7;
                        }
                        else if (pokemonCp >= session.LogicSettings.ForceGreatThrowOverCp ||
                                 pokemonIv >= session.LogicSettings.ForceGreatThrowOverIv)
                        {
                            normalizedRecticleSize = Random.NextDouble() * (1.95 - 1.3) + 1.3;
                            hitTxt = "Great";
                        }
                        else
                        {
                            var regularThrow = 100 - (session.LogicSettings.ExcellentThrowChance +
                                                      session.LogicSettings.GreatThrowChance +
                                                      session.LogicSettings.NiceThrowChance);
                            var rnd = Random.Next(1, 101);

                            if (rnd <= regularThrow)
                            {
                                normalizedRecticleSize = Random.NextDouble() * (1 - 0.1) + 0.1;
                                hitTxt = "Ordinary";
                            }
                            else if (rnd <= regularThrow + session.LogicSettings.NiceThrowChance)
                            {
                                normalizedRecticleSize = Random.NextDouble() * (1.3 - 1) + 1;
                                hitTxt = "Nice";
                            }
                            else if (rnd <=
                                     regularThrow + session.LogicSettings.NiceThrowChance +
                                     session.LogicSettings.GreatThrowChance)
                            {
                                normalizedRecticleSize = Random.NextDouble() * (1.7 - 1.3) + 1.3;
                                hitTxt = "Great";
                            }

                            if (Random.NextDouble() * 100 > session.LogicSettings.CurveThrowChance)
                            {
                                spinModifier = 0.0;
                                spinTxt      = "Straight";
                            }
                        }

                        // Round to 2 decimals
                        normalizedRecticleSize = Math.Round(normalizedRecticleSize, 2);

                        // Missed throw check
                        int missChance = Random.Next(1, 101);
                        if (missChance <= session.LogicSettings.ThrowMissPercentage &&
                            session.LogicSettings.EnableMissedThrows)
                        {
                            hitPokemon = false;
                        }

                        Logger.Write($"(Threw ball) {hitTxt} throw, {spinTxt}-ball, HitPokemon = {hitPokemon}...",
                                     LogLevel.Debug);
                    }

                    caughtPokemonResponse =
                        await session.Client.Encounter.CatchPokemon(
                            encounter is EncounterResponse || encounter is IncenseEncounterResponse
                            ?pokemon.EncounterId
                            : _encounterId,
                            encounter is EncounterResponse || encounter is IncenseEncounterResponse
                            ?pokemon.SpawnPointId
                            : currentFortData.Id, pokeball, normalizedRecticleSize, spinModifier, hitPokemon);


                    await session.Inventory.UpdateInventoryItem(pokeball, -1);

                    var evt = new PokemonCaptureEvent()
                    {
                        Status    = caughtPokemonResponse.Status,
                        Latitude  = latitude,
                        Longitude = longitude
                    };

                    lastThrow = caughtPokemonResponse.Status; // sets lastThrow status


                    if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                    {
                        var totalExp       = 0;
                        var totalStartDust = caughtPokemonResponse.CaptureAward.Stardust.Sum();
                        if (encounteredPokemon != null)
                        {
                            encounteredPokemon.Id = caughtPokemonResponse.CapturedPokemonId;
                            await session.Inventory.AddPokemonToCache(encounteredPokemon);
                        }
                        foreach (var xp in caughtPokemonResponse.CaptureAward.Xp)
                        {
                            totalExp += xp;
                        }
                        var stardust = session.Inventory.UpdateStartDust(totalStartDust);

                        evt.Exp      = totalExp;
                        evt.Stardust = stardust;
                        evt.UniqueId = caughtPokemonResponse.CapturedPokemonId;

                        var pokemonSettings = await session.Inventory.GetPokemonSettings();

                        var pokemonFamilies = await session.Inventory.GetPokemonFamilies();

                        var setting =
                            pokemonSettings.FirstOrDefault(q => pokemon != null && q.PokemonId == pokemon.PokemonId);
                        var family =
                            pokemonFamilies.FirstOrDefault(q => setting != null && q.FamilyId == setting.FamilyId);

                        if (family != null)
                        {
                            await session.Inventory.UpdateCandy(family, caughtPokemonResponse.CaptureAward.Candy.Sum());

                            family.Candy_    += caughtPokemonResponse.CaptureAward.Candy.Sum();
                            evt.FamilyCandies = family.Candy_;
                        }
                        else
                        {
                            evt.FamilyCandies = caughtPokemonResponse.CaptureAward.Candy.Sum();
                        }

                        if (session.LogicSettings.UseCatchLimit)
                        {
                            session.Stats.AddPokemonTimestamp(DateTime.Now.Ticks);
                            Logger.Write(
                                $"(CATCH LIMIT) {session.Stats.GetNumPokemonsInLast24Hours()}/{session.LogicSettings.CatchPokemonLimit}",
                                LogLevel.Info, ConsoleColor.Yellow);
                        }
                    }

                    evt.CatchType = encounter is EncounterResponse
                        ? session.Translation.GetTranslation(TranslationString.CatchTypeNormal)
                        : encounter is DiskEncounterResponse
                            ? session.Translation.GetTranslation(TranslationString.CatchTypeLure)
                            : session.Translation.GetTranslation(TranslationString.CatchTypeIncense);

                    evt.CatchTypeText = encounter is EncounterResponse
                        ? "normal"
                        : encounter is DiskEncounterResponse
                            ? "lure"
                            : "incense";
                    evt.Id = encounter is EncounterResponse
                        ? pokemon.PokemonId
                        : encounter?.PokemonData.PokemonId;
                    evt.EncounterId  = _encounterId;
                    evt.Move1        = PokemonInfo.GetPokemonMove1(encounteredPokemon);
                    evt.Move2        = PokemonInfo.GetPokemonMove2(encounteredPokemon);
                    evt.Expires      = pokemon?.ExpirationTimestampMs ?? 0;
                    evt.SpawnPointId = _spawnPointId;
                    evt.Level        = PokemonInfo.GetLevel(encounteredPokemon);
                    evt.Cp           = encounteredPokemon.Cp;
                    evt.MaxCp        = PokemonInfo.CalculateMaxCp(encounteredPokemon);
                    evt.Perfection   = Math.Round(PokemonInfo.CalculatePokemonPerfection(encounteredPokemon));
                    evt.Probability  = Math.Round(probability * 100, 2);
                    evt.Distance     = distance;
                    evt.Pokeball     = pokeball;
                    evt.Attempt      = attemptCounter;

                    //await session.Inventory.RefreshCachedInventory();

                    evt.BallAmount = await session.Inventory.GetItemAmountByType(pokeball);

                    evt.Rarity = PokemonGradeHelper.GetPokemonGrade(evt.Id).ToString();

                    session.EventDispatcher.Send(evt);

                    attemptCounter++;

                    DelayingUtils.Delay(session.LogicSettings.DelayBetweenPlayerActions, 0);
                } while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed ||
                         caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);

                if (session.LogicSettings.AllowMultipleBot)
                {
                    if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee)
                    {
                        CatchFleeContinuouslyCount++;
                        if (CatchFleeContinuouslyCount > session.LogicSettings.MultipleBotConfig.CatchFleeCount)
                        {
                            CatchFleeContinuouslyCount = 0;

                            throw new ActiveSwitchByRuleException()
                                  {
                                      MatchedRule  = SwitchRules.CatchFlee,
                                      ReachedValue = session.LogicSettings.MultipleBotConfig.CatchFleeCount
                                  };
                        }
                    }
                    else
                    {
                        //reset if not catch flee.
                        CatchFleeContinuouslyCount = 0;
                        MSniperServiceTask.UnblockSnipe();
                    }
                }

                session.Actions.RemoveAll(x => x == BotActions.Catch);

                if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings))
                {
                    ExecuteSwitcher(session, encounterEV);
                }

                if (session.LogicSettings.TransferDuplicatePokemonOnCapture &&
                    session.LogicSettings.TransferDuplicatePokemon &&
                    sessionAllowTransfer &&
                    caughtPokemonResponse != null &&
                    caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                {
                    if (session.LogicSettings.UseNearActionRandom)
                    {
                        await HumanRandomActionTask.TransferRandom(session, cancellationToken);
                    }
                    else
                    {
                        await TransferDuplicatePokemonTask.Execute(session, cancellationToken);
                    }
                }
            }
            return(true);
        }
Esempio n. 4
0
        public static ulong CatchPokemon(ulong encounterId, string spawnpointId, PokemonId pokeid, double pokeLong = 0, double pokeLat = 0, bool goBack = false, double returnLatitude = -1, double returnLongitude = -1, int luredPoke = 0)
        {
            ulong             ret = 0;
            EncounterResponse encounterPokemonResponse;

            //Offset Miss count here to account for user setting.
            var missCount = 0;

            if (GlobalVars.Max_Missed_throws <= 1)
            {
                missCount = 2;
            }

            if (GlobalVars.Max_Missed_throws == 2)
            {
                missCount = 1;
            }

            var forceHit = false;

            try
            {
                if (luredPoke == 0)
                {
                    encounterPokemonResponse = client.Encounter.EncounterPokemon(encounterId, spawnpointId).Result;
                }
                else if (luredPoke == 1)
                {
                    var DiscEncounterPokemonResponse = client.Encounter.EncounterLurePokemon(encounterId, spawnpointId);
                    encounterPokemonResponse        = new EncounterResponse();
                    encounterPokemonResponse.Status = DiskEncounterResultToEncounterStatus(DiscEncounterPokemonResponse.Result);

                    if (DiscEncounterPokemonResponse.Result == DiskEncounterResponse.Types.Result.Success)
                    {
                        encounterPokemonResponse.WildPokemon             = new WildPokemon();
                        encounterPokemonResponse.WildPokemon.EncounterId = encounterId;
                        encounterPokemonResponse.WildPokemon.PokemonData = DiscEncounterPokemonResponse.PokemonData;
                        encounterPokemonResponse.CaptureProbability      = new POGOProtos.Data.Capture.CaptureProbability();
                        encounterPokemonResponse.CaptureProbability.CaptureProbability_.Add(1.0F);
                    }
                }
                else
                {
                    var IncenseEncounterPokemonResponse = client.Encounter.EncounterIncensePokemon(encounterId, spawnpointId);
                    encounterPokemonResponse        = new EncounterResponse();
                    encounterPokemonResponse.Status = IncenseEncounterResultToEncounterStatus(IncenseEncounterPokemonResponse.Result);

                    if (IncenseEncounterPokemonResponse.Result == IncenseEncounterResponse.Types.Result.IncenseEncounterSuccess)
                    {
                        encounterPokemonResponse.WildPokemon             = new WildPokemon();
                        encounterPokemonResponse.WildPokemon.EncounterId = encounterId;
                        encounterPokemonResponse.WildPokemon.PokemonData = IncenseEncounterPokemonResponse.PokemonData;
                        encounterPokemonResponse.CaptureProbability      = IncenseEncounterPokemonResponse.CaptureProbability;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.ColoredConsoleWrite(ConsoleColor.Red, $"Error: Logic.cs - CatchPokemon - encounter: {ex.Message}");
                if (goBack)
                {
                    Logger.ColoredConsoleWrite(ConsoleColor.Cyan, $"(SNIPING) Go to {returnLatitude} / {returnLongitude} before starting the capture.");
                    Logger.ColoredConsoleWrite(ConsoleColor.Cyan, LocationUtils.FindAddress(returnLatitude, returnLongitude));
                    LocationUtils.updatePlayerLocation(client, returnLatitude, returnLongitude, GlobalVars.altitude);
                    var tmpMap = client.Map.GetMapObjects(true);
                }
                return(ret);
            }

            if (goBack)
            {
                Logger.ColoredConsoleWrite(ConsoleColor.Cyan, $"(SNIPING) Go to {returnLatitude} / {returnLongitude} before starting the capture.");
                Logger.ColoredConsoleWrite(ConsoleColor.Cyan, LocationUtils.FindAddress(returnLatitude, returnLongitude));
                LocationUtils.updatePlayerLocation(client, returnLatitude, returnLongitude, GlobalVars.altitude);
                var tmpMap = client.Map.GetMapObjects(true);
            }

            if (encounterPokemonResponse.Status == EncounterResponse.Types.Status.EncounterSuccess)
            {
                if (SkippedPokemon.Contains(encounterPokemonResponse.WildPokemon.EncounterId))
                {
                    Logger.ColoredConsoleWrite(ConsoleColor.Cyan, "Previously Skipped this Pokemon - Skipping Again!");
                    return(0);
                }

                var bestPokeball = GetBestBall(encounterPokemonResponse?.WildPokemon, false);

                var iv = PokemonGo.RocketAPI.PokemonInfo.CalculatePokemonPerfection(encounterPokemonResponse.WildPokemon.PokemonData);
                var strIVPerfection = iv.ToString("0.00");
                if (bestPokeball == ItemId.ItemUnknown)
                {
                    Logger.ColoredConsoleWrite(ConsoleColor.Red, $"No Pokeballs! - missed {pokeid} CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} IV {strIVPerfection}%");
                    Logger.ColoredConsoleWrite(ConsoleColor.Red, "Detected all balls out of stock - disabling pokemon catch until restock of at least 1 ball type occurs");

                    Logic.Instance.pokeballoutofstock = true;
                    AllowCatchPokemon = false;

                    return(0);
                }

                var inventoryBerries = client.Inventory.GetItems();
                var probability      = encounterPokemonResponse?.CaptureProbability?.CaptureProbability_?.FirstOrDefault();
                var probability100   = Math.Round(probability.Value * 100);

                Logger.ColoredConsoleWrite(ConsoleColor.Magenta, $"Encountered {pokeid} CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} IV {strIVPerfection}% Probability {probability100}%");
                if (encounterPokemonResponse.WildPokemon.PokemonData != null)
                {
                    SaveLocations(encounterPokemonResponse.WildPokemon, iv, probability100);
                }

                if (encounterPokemonResponse.WildPokemon.PokemonData != null &&
                    encounterPokemonResponse.WildPokemon.PokemonData.Cp >= GlobalVars.MinCPtoCatch &&
                    probability100 >= GlobalVars.MinProbToCatch &&
                    iv >= GlobalVars.MinIVtoCatch)
                {
                    var usedBerry = false;
                    var escaped   = false;
                    CatchPokemonResponse caughtPokemonResponse;
                    var inventory = client.Inventory.GetItems();
                    var razz      = inventory.FirstOrDefault(p => p.ItemId == ItemId.ItemRazzBerry);
                    var pinap     = inventory.FirstOrDefault(p => p.ItemId == ItemId.ItemPinapBerry);
                    var nanab     = inventory.FirstOrDefault(p => p.ItemId == ItemId.ItemNanabBerry);

                    do
                    {
                        // Check if the best ball is still valid
                        if (bestPokeball == ItemId.ItemUnknown)
                        {
                            Logger.ColoredConsoleWrite(ConsoleColor.Red, $"No Pokeballs! - missed {pokeid} CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} IV {strIVPerfection}%");
                            Logger.ColoredConsoleWrite(ConsoleColor.Red, "Detected all balls out of stock - disabling pokemon catch until restock of at least 1 ball type occurs");

                            Logic.Instance.pokeballoutofstock = true;
                            AllowCatchPokemon = false;

                            return(0);
                        }


                        if (GlobalVars.UseRazzBerry && !usedBerry && (probability.Value < GlobalVars.razzberry_chance))
                        {
                            if (razz != null && razz.Count > 0)
                            {
                                //Throw berry
                                var useRazzberry = client.Encounter.UseItemEncounter(encounterId, ItemId.ItemRazzBerry, spawnpointId);
                                if (useRazzberry.Status == UseItemEncounterResponse.Types.Status.Success)
                                {
                                    razz.Count = razz.Count - 1;
                                    Logger.Info($"We used a Razz Berry. Remaining: {razz.Count}.");
                                    usedBerry = true;
                                }
                                else
                                {
                                    Logger.Info("RazzBerry Status: " + useRazzberry.Status);
                                }

                                RandomHelper.RandomSleep(250);
                            }
                            if (!client.Player.PlayerResponse.PlayerData.TutorialState.Contains(TutorialState.PokemonBerry))
                            {
                                Logic.Instance.Tutorial.MarkTutorialAsDone(TutorialState.PokemonBerry, client);
                            }
                        }

                        if (GlobalVars.PokemonPinap.Contains(pokeid) && !usedBerry)
                        {
                            try {
                                if (pinap != null && pinap.Count > 0)
                                {
                                    // Use a pinap
                                    var res = client.Encounter.UseItemEncounter(encounterId, ItemId.ItemPinapBerry, spawnpointId);
                                    if (res.Status == UseItemEncounterResponse.Types.Status.Success)
                                    {
                                        pinap.Count = pinap.Count - 1;
                                        Logger.Info($"We used a Pinap Berry. Remaining: {pinap.Count}.");
                                        usedBerry = true;
                                    }
                                    else
                                    {
                                        Logger.Info("PinapBerry Status: " + res.Status);
                                    }
                                    RandomHelper.RandomSleep(250);
                                }
                            } catch (Exception ex1) {
                                Logger.Debug("" + ex1);
                            }
                        }

                        var r = new Random();

                        if (GlobalVars.UseNanabBerry && !usedBerry)
                        {
                            try {
                                var reallyUseIt = (r.Next(0, 100) <= GlobalVars.NanabPercent);
                                if (GlobalVars.NanabPercent == 100 || reallyUseIt)
                                {
                                    if (nanab != null && nanab.Count > 0)
                                    {
                                        var res = client.Encounter.UseItemEncounter(encounterId, ItemId.ItemNanabBerry, spawnpointId);
                                        if (res.Status == UseItemEncounterResponse.Types.Status.Success)
                                        {
                                            nanab.Count = nanab.Count - 1;
                                            Logger.Info($"We used a Nabab Berry. Remaining: {nanab.Count}.");
                                            usedBerry = true;
                                        }
                                        else
                                        {
                                            Logger.Info("Status: " + res.Status);
                                        }
                                        RandomHelper.RandomSleep(250);
                                    }
                                }
                            } catch (Exception ex1) {
                                Logger.Debug("" + ex1);
                            }
                        }
                        // limit number of balls wasted by misses and log for UX because fools be tripin
                        switch (missCount)
                        {
                        case 0:
                            if (bestPokeball == ItemId.ItemMasterBall)
                            {
                                Logger.ColoredConsoleWrite(ConsoleColor.Magenta, "No messing around with your Master Balls! Forcing a hit on target.");
                                forceHit = true;
                            }
                            break;

                        case 1:
                            if (bestPokeball == ItemId.ItemUltraBall)
                            {
                                Logger.ColoredConsoleWrite(ConsoleColor.Magenta, "Not wasting more of your Ultra Balls! Forcing a hit on target.");
                                forceHit = true;
                            }
                            break;

                        case 2:
                            //adding another chance of forcing hit here to improve overall odds after 2 misses
                            var rInt = r.Next(0, 2);
                            forceHit |= rInt == 1;
                            break;

                        default:
                            // default to force hit after 3 wasted balls of any kind.
                            Logger.ColoredConsoleWrite(ConsoleColor.Magenta, "Enough misses! Forcing a hit on target.");
                            forceHit = true;
                            break;
                        }
                        if (missCount > 0)
                        {
                            //adding another chance of forcing hit here to improve overall odds after 1st miss
                            var rInt = r.Next(0, 3);
                            if (rInt == 1)
                            {
                                // lets hit
                                forceHit = true;
                            }
                        }

                        caughtPokemonResponse = CatchPokemonWithRandomVariables(encounterId, spawnpointId, bestPokeball, forceHit);
                        if (caughtPokemonResponse == null)
                        {
                            caughtPokemonResponse = new CatchPokemonResponse();
                        }

                        if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed)
                        {
                            Logger.ColoredConsoleWrite(ConsoleColor.Magenta, $"Missed { pokeid} while using {bestPokeball}");
                            missCount++;
                            RandomHelper.RandomSleep(1500, 3000);
                        }
                        else if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape)
                        {
                            Logger.ColoredConsoleWrite(ConsoleColor.Magenta, $"{pokeid} escaped while using {bestPokeball}");
                            usedBerry = false;
                            escaped   = true;
                            //reset forceHit in case we randomly triggered on last throw.
                            forceHit = false;
                            RandomHelper.RandomSleep(1500, 3000);
                        }
                        // Update the best ball to ensure we can still throw
                        bestPokeball = GetBestBall(encounterPokemonResponse?.WildPokemon, escaped);
                    } while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);

                    if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                    {
                        ret = caughtPokemonResponse.CapturedPokemonId;

                        if (GlobalVars.ShowPokemons)
                        {
                            Logic.Instance.DeletePokemonFromMap(encounterPokemonResponse.WildPokemon.SpawnPointId);
                        }

                        var curDate = DateTime.Now;
                        Task.Factory.StartNew(() => infoObservable.PushNewHuntStats($"{pokeLat}/{pokeLong};{pokeid};{curDate.Ticks};{curDate}" + Environment.NewLine));

                        var date = DateTime.Now;
                        if (caughtPokemonResponse.CaptureAward.Xp.Sum() >= 500)
                        {
                            if (GlobalVars.LogPokemons)
                            {
                                File.AppendAllText(GlobalVars.FileForPokemonsCaught, $"[{date}] Caught new {pokeid} (CP: {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} | IV: {strIVPerfection}% | Pokeball used: {bestPokeball} | XP: {caughtPokemonResponse.CaptureAward.Xp.Sum()}) " + Environment.NewLine);
                            }
                            Logger.ColoredConsoleWrite(ConsoleColor.Gray, $"Caught {pokeid} CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} IV {strIVPerfection}% got {caughtPokemonResponse.CaptureAward.Xp.Sum()} XP | {caughtPokemonResponse.CaptureAward.Candy.Sum()} Candies | {caughtPokemonResponse.CaptureAward.Stardust.Sum()} Stardust");
                            Setout.pokemonCatchCount++;
                            Setout.SaveSession();
                            // Wrong: TutorialState.PokemonCapture is not for the first wild pokemon caught.
                            // if (!client.Player.PlayerResponse.PlayerData.TutorialState.Contains(TutorialState.PokemonCapture)) Logic.Instance.Tutorial.MarkTutorialAsDone(TutorialState.PokemonCapture, client, pokeid);
                        }
                        else
                        {
                            if (GlobalVars.LogPokemons)
                            {
                                File.AppendAllText(GlobalVars.FileForPokemonsCaught, $"[{date}] Caught {pokeid} (CP: {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} | IV: {strIVPerfection}% | Pokeball used: {bestPokeball} | XP: {caughtPokemonResponse.CaptureAward.Xp.Sum()}) " + Environment.NewLine);
                            }
                            Logger.ColoredConsoleWrite(ConsoleColor.Gray, $"Caught {pokeid} CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} IV {strIVPerfection}% got {caughtPokemonResponse.CaptureAward.Xp.Sum()} XP | {caughtPokemonResponse.CaptureAward.Candy.Sum()} Candies | {caughtPokemonResponse.CaptureAward.Stardust.Sum()} Stardust");
                            Setout.pokemonCatchCount++;
                            Setout.SaveSession();

                            if (Logic.Instance.Telegram != null)
                            {
                                Logic.Instance.Telegram.sendInformationText(TelegramUtil.TelegramUtilInformationTopics.Catch, pokeid, encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp, strIVPerfection, bestPokeball, caughtPokemonResponse.CaptureAward.Xp.Sum());
                            }
                        }
                        Logic.Instance.BotStats.AddPokemon(1);
                        Logic.Instance.BotStats.AddExperience(caughtPokemonResponse.CaptureAward.Xp.Sum());
                        Logic.Instance.BotStats.AddStardust(caughtPokemonResponse.CaptureAward.Stardust.Sum());
                        Setout.RefreshConsoleTitle(client);
                        RandomHelper.RandomSleep(1500, 2000);
                    }
                    else
                    {
                        Logger.ColoredConsoleWrite(ConsoleColor.DarkYellow, $"{pokeid} CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} IV {strIVPerfection}% got away while using {bestPokeball}..");
                        Logic.FailedSoftban++;
                        if (Logic.FailedSoftban > 10)
                        {
                            Logger.ColoredConsoleWrite(ConsoleColor.Red, $"Soft Ban Detected - Stopping Bot to prevent perma-ban. Try again in 4-24 hours and be more careful next time!");
                            Setout.LimitReached("");
                        }
                    }
                }
                else
                {
                    Logger.ColoredConsoleWrite(ConsoleColor.Magenta, "Pokemon CP or IV or Prob lower than Configured Min to Catch - Skipping Pokemon");
                    SkippedPokemon.Add(encounterPokemonResponse.WildPokemon.EncounterId);
                }
            }
            else if (encounterPokemonResponse.Status == EncounterResponse.Types.Status.PokemonInventoryFull)
            {
                Logger.Warning("You have no free space for new pokemons...transfer some as soon as possible.");
            }
            else
            {
                Logger.Debug(encounterPokemonResponse.Status.ToString());
            }
            return(ret);
        }
        //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());
        }
Esempio n. 7
0
        private async Task <MethodResult> CatchPokemon(EncounterResponse eResponse, MapPokemon mapPokemon)
        {
            try
            {
                CatchPokemonResponse catchPokemonResponse = null;
                int attemptCount = 1;

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

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

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

                    bool isLowProbability = probability < 0.40;
                    bool isHighCp         = eResponse.WildPokemon.PokemonData.Cp > 800;
                    bool isHighPerfection = CalculateIVPerfection(eResponse.WildPokemon.PokemonData).Data > 95;

                    if ((isLowProbability && isHighCp) || isHighPerfection)
                    {
                        await Task.Delay(200);

                        await UseBerry(mapPokemon);
                    }

                    await Task.Delay(200);

                    catchPokemonResponse = await _client.Encounter.CatchPokemon(mapPokemon.EncounterId, mapPokemon.SpawnPointId, pokeBall);

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

                    if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                    {
                        int expGained = catchPokemonResponse.CaptureAward.Xp.Sum();

                        ExpIncrease(expGained);

                        //_expGained += expGained;

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

                        return(new MethodResult
                        {
                            Message = "Pokemon caught",
                            Success = true
                        });
                    }
                    else if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee)
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Pokemon fled. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonFlee));
                    }
                    else if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape)
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Escaped ball. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonEscape));
                    }
                    else
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Unknown Error. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                    }

                    ++attemptCount;

                    await Task.Delay(500);
                } while (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
            }
            catch (Exception ex)
            {
                LogCaller(new LoggerEventArgs("Failed to catch pokemon due to error", LoggerTypes.Exception, ex));

                return(new MethodResult
                {
                    Message = "Failed to catch pokemon"
                });
            }

            return(new MethodResult
            {
                Message = "Failed to catch pokemon",
                Success = true
            });
        }
Esempio n. 8
0
        private async Task <MethodResult> CatchPokemon(FortData fortData)
        {
            try
            {
                DiskEncounterResponse eResponse = await _client.Encounter.EncounterLurePokemon(fortData.LureInfo.EncounterId, fortData.Id);

                if (eResponse.Result == DiskEncounterResponse.Types.Result.PokemonInventoryFull)
                {
                    LogCaller(new LoggerEventArgs("Encounter failed. Pokemon inventory full", LoggerTypes.Warning));

                    return(new MethodResult
                    {
                        Message = "Encounter failed. Pokemon inventory full"
                    });
                }
                else if (eResponse.Result != DiskEncounterResponse.Types.Result.Success)
                {
                    if (eResponse.Result == DiskEncounterResponse.Types.Result.NotAvailable)
                    {
                        //Ignore
                        return(new MethodResult
                        {
                            Message = "Encounter not available"
                        });
                    }

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

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

                CatchPokemonResponse catchPokemonResponse = null;
                int attemptCount = 1;

                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", LoggerTypes.Warning));

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

                    bool isLowProbability = probability < 0.35;
                    bool isHighCp         = eResponse.PokemonData.Cp > 700;
                    bool isHighPerfection = CalculateIVPerfection(eResponse.PokemonData).Data > 90;

                    if ((isLowProbability && isHighCp) || isHighPerfection)
                    {
                        await UseBerry(fortData.LureInfo.EncounterId, fortData.Id);
                    }

                    catchPokemonResponse = await _client.Encounter.CatchPokemon(fortData.LureInfo.EncounterId, fortData.Id, pokeBall);

                    string pokemon = String.Format("Name: {0}, CP: {1}, IV: {2:0.00}%", fortData.LureInfo.ActivePokemonId, eResponse.PokemonData.Cp, CalculateIVPerfection(eResponse.PokemonData).Data);

                    if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                    {
                        int expGained = catchPokemonResponse.CaptureAward.Xp.Sum();

                        ExpIncrease(expGained);

                        //_expGained += expGained;

                        LogCaller(new LoggerEventArgs(String.Format("Lured Pokemon Caught. {0}. Exp {1}. Attempt #{2}", pokemon, expGained, attemptCount), LoggerTypes.Success));

                        return(new MethodResult
                        {
                            Message = "Pokemon caught",
                            Success = true
                        });
                    }
                    else if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee)
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Pokemon fled. {0}. Attempt #{1}", pokemon, attemptCount), LoggerTypes.PokemonFlee));
                    }
                    else if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape)
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Escaped ball. {0}. Attempt #{1}.", pokemon, attemptCount), LoggerTypes.PokemonEscape));
                    }
                    else
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Unknown Error. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                    }

                    ++attemptCount;

                    await Task.Delay(1000);
                } while (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
            }
            catch (Exception ex)
            {
                LogCaller(new LoggerEventArgs("Failed to catch lured pokemon due to error", LoggerTypes.Exception, ex));

                return(new MethodResult
                {
                    Message = "Failed to catch lured pokemon"
                });
            }

            return(new MethodResult
            {
                Message = "Failed to catch lured pokemon",
                Success = true
            });
        }
Esempio n. 9
0
        //Catch encountered pokemon
        private async Task <MethodResult> CatchPokemon(EncounterResponse eResponse, MapPokemon mapPokemon)
        {
            try
            {
                CatchPokemonResponse catchPokemonResponse = null;
                int attemptCount = 1;

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

                    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         = eResponse.WildPokemon.PokemonData.Cp > 800;
                    bool isHighPerfection = CalculateIVPerfection(eResponse.WildPokemon.PokemonData).Data > 95;

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

                        await UseBerry(mapPokemon);
                    }

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


                    double reticuleSize      = 1.95;
                    int    hitInsideReticule = 1;

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

                    catchPokemonResponse = await _client.Encounter.CatchPokemon(mapPokemon.EncounterId, mapPokemon.SpawnPointId, pokeBall, reticuleSize, 1, hitInsideReticule);

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

                    if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                    {
                        //Reset data
                        _fleeingPokemonResponses = 0;
                        ++PokemonCaught;
                        _potentialPokemonBan = false;

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

                        ExpIncrease(expGained);

                        //_expGained += expGained;

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

                        return(new MethodResult
                        {
                            Message = "Pokemon caught",
                            Success = true
                        });
                    }
                    else if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee)
                    {
                        ++_fleeingPokemonResponses;

                        LogCaller(new LoggerEventArgs(String.Format("Pokemon fled. {0}. Attempt #{1}. Ball: {2}", pokemon, attemptCount, pokeBallName), LoggerTypes.PokemonFlee));
                    }
                    else if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape)
                    {
                        //If we get this response, means we're good
                        _fleeingPokemonResponses = 0;
                        _potentialPokemonBan     = false;

                        if (AccountState == Enums.AccountState.PokemonBanAndPokestopBanTemp || AccountState == Enums.AccountState.PokemonBanTemp)
                        {
                            if (AccountState == Enums.AccountState.PokemonBanAndPokestopBanTemp)
                            {
                                AccountState = Enums.AccountState.PokestopBanTemp;
                            }
                            else
                            {
                                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));
                    }
                    else
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Unknown Error. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                    }

                    ++attemptCount;

                    await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
                } while (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
            }
            catch (Exception ex)
            {
                LogCaller(new LoggerEventArgs("Failed to catch pokemon due to error", LoggerTypes.Exception, ex));

                return(new MethodResult
                {
                    Message = "Failed to catch pokemon"
                });
            }

            return(new MethodResult
            {
                Message = "Failed to catch pokemon",
                Success = true
            });
        }
 /// <summary>
 /// Provides a safe way to invoke the <see cref="CatchPokemonReceived" /> event.
 /// </summary>
 /// <param name="value"></param>
 public void RaiseCatchPokemonReceived(CatchPokemonResponse value) => CatchPokemonReceived?.Invoke(this, value);
Esempio n. 11
0
        public static async Task Execute(ISession session, CancellationToken cancellationToken, dynamic encounter, MapPokemon pokemon,
                                         FortData currentFortData = null, ulong encounterId = 0, bool sessionAllowTransfer = true)
        {
            AmountOfBerries = 0;

            cancellationToken.ThrowIfCancellationRequested();

            // If the encounter is null nothing will work below, so exit now
            if (encounter == null)
            {
                return;
            }

            // Exit if user defined max limits reached
            if (CatchThresholdExceeds(session, cancellationToken))
            {
                return;
            }

            float probability = encounter.CaptureProbability?.CaptureProbability_[0];

            // Check for pokeballs before proceeding
            var pokeball = await GetBestBall(session, encounter, probability);

            if (pokeball == ItemId.ItemUnknown)
            {
                return;
            }

            //Calculate CP and IV
            var pokemonCp = (encounter is EncounterResponse
                               ? encounter.WildPokemon?.PokemonData?.Cp
                               : encounter.PokemonData?.Cp);
            var pokemonIv = PokemonInfo.CalculatePokemonPerfection(encounter is EncounterResponse
                    ? encounter.WildPokemon?.PokemonData
                    : encounter?.PokemonData);

            // Calculate distance away
            var distance = LocationUtils.CalculateDistanceInMeters(session.Client.CurrentLatitude,
                                                                   session.Client.CurrentLongitude,
                                                                   encounter is EncounterResponse || encounter is IncenseEncounterResponse
                    ? pokemon.Latitude
                    : currentFortData.Latitude,
                                                                   encounter is EncounterResponse || encounter is IncenseEncounterResponse
                    ? pokemon.Longitude
                    : currentFortData.Longitude);

            CatchPokemonResponse caughtPokemonResponse = null;
            var lastThrow      = CatchPokemonResponse.Types.CatchStatus.CatchSuccess; // Initializing lastThrow
            var attemptCounter = 1;

            do
            {
                if ((session.LogicSettings.MaxPokeballsPerPokemon > 0 &&
                     attemptCounter > session.LogicSettings.MaxPokeballsPerPokemon))
                {
                    break;
                }

                pokeball = await GetBestBall(session, encounter, probability);

                if (pokeball == ItemId.ItemUnknown)
                {
                    session.EventDispatcher.Send(new NoPokeballEvent
                    {
                        Id = encounter is EncounterResponse ? pokemon.PokemonId : encounter?.PokemonData.PokemonId,
                        Cp =
                            (encounter is EncounterResponse
                                ? encounter.WildPokemon?.PokemonData?.Cp
                                : encounter?.PokemonData?.Cp) ?? 0
                    });
                    return;
                }

                // Determine whether to use berries or not
                if (((session.LogicSettings.UseBerriesOperator.ToLower().Equals("and") &&
                      pokemonIv >= session.LogicSettings.UseBerriesMinIv &&
                      pokemonCp >= session.LogicSettings.UseBerriesMinCp &&
                      probability < session.LogicSettings.UseBerriesBelowCatchProbability) ||
                     (session.LogicSettings.UseBerriesOperator.ToLower().Equals("or") && (
                          pokemonIv >= session.LogicSettings.UseBerriesMinIv ||
                          pokemonCp >= session.LogicSettings.UseBerriesMinCp ||
                          probability < session.LogicSettings.UseBerriesBelowCatchProbability))) &&
                    lastThrow != CatchPokemonResponse.Types.CatchStatus.CatchMissed) // if last throw is a miss, no double berry
                {
                    AmountOfBerries++;
                    if (AmountOfBerries <= session.LogicSettings.MaxBerriesToUsePerPokemon)
                    {
                        await UseBerry(session,
                                       encounter is EncounterResponse || encounter is IncenseEncounterResponse
                                       ?pokemon.EncounterId
                                       : encounterId,
                                       encounter is EncounterResponse || encounter is IncenseEncounterResponse
                                       ?pokemon.SpawnPointId
                                       : currentFortData?.Id);
                    }
                }

                bool hitPokemon = true;

                //default to excellent throw
                var normalizedRecticleSize = 1.95;
                //default spin
                var spinModifier = 1.0;

                //Humanized throws
                if (session.LogicSettings.EnableHumanizedThrows)
                {
                    //thresholds: https://gist.github.com/anonymous/077d6dea82d58b8febde54ae9729b1bf
                    var spinTxt = "Curve";
                    var hitTxt  = "Excellent";
                    if (pokemonCp > session.LogicSettings.ForceExcellentThrowOverCp ||
                        pokemonIv > session.LogicSettings.ForceExcellentThrowOverIv)
                    {
                        normalizedRecticleSize = Random.NextDouble() * (1.95 - 1.7) + 1.7;
                    }
                    else if (pokemonCp >= session.LogicSettings.ForceGreatThrowOverCp ||
                             pokemonIv >= session.LogicSettings.ForceGreatThrowOverIv)
                    {
                        normalizedRecticleSize = Random.NextDouble() * (1.95 - 1.3) + 1.3;
                        hitTxt = "Great";
                    }
                    else
                    {
                        var regularThrow = 100 - (session.LogicSettings.ExcellentThrowChance +
                                                  session.LogicSettings.GreatThrowChance +
                                                  session.LogicSettings.NiceThrowChance);
                        var rnd = Random.Next(1, 101);

                        if (rnd <= regularThrow)
                        {
                            normalizedRecticleSize = Random.NextDouble() * (1 - 0.1) + 0.1;
                            hitTxt = "Ordinary";
                        }
                        else if (rnd <= regularThrow + session.LogicSettings.NiceThrowChance)
                        {
                            normalizedRecticleSize = Random.NextDouble() * (1.3 - 1) + 1;
                            hitTxt = "Nice";
                        }
                        else if (rnd <=
                                 regularThrow + session.LogicSettings.NiceThrowChance +
                                 session.LogicSettings.GreatThrowChance)
                        {
                            normalizedRecticleSize = Random.NextDouble() * (1.7 - 1.3) + 1.3;
                            hitTxt = "Great";
                        }

                        if (Random.NextDouble() * 100 > session.LogicSettings.CurveThrowChance)
                        {
                            spinModifier = 0.0;
                            spinTxt      = "Straight";
                        }
                    }

                    //round to 2 decimals
                    normalizedRecticleSize = Math.Round(normalizedRecticleSize, 2);

                    // Missed throw check
                    int missChance = Random.Next(1, 101);
                    if (missChance <= session.LogicSettings.ThrowMissPercentage && session.LogicSettings.EnableMissedThrows)
                    {
                        hitPokemon = false;
                    }

                    Logger.Write($"(Threw ball) {hitTxt} throw, {spinTxt}-ball, HitPokemon = {hitPokemon}...", LogLevel.Debug);
                }

                caughtPokemonResponse =
                    await session.Client.Encounter.CatchPokemon(
                        encounter is EncounterResponse || encounter is IncenseEncounterResponse
                        ?pokemon.EncounterId
                        : encounterId,
                        encounter is EncounterResponse || encounter is IncenseEncounterResponse
                        ?pokemon.SpawnPointId
                        : currentFortData.Id, pokeball, normalizedRecticleSize, spinModifier, hitPokemon);

                var lat = encounter is EncounterResponse || encounter is IncenseEncounterResponse
                             ? pokemon.Latitude : currentFortData.Latitude;
                var lng = encounter is EncounterResponse || encounter is IncenseEncounterResponse
                            ? pokemon.Longitude : currentFortData.Longitude;
                var evt = new PokemonCaptureEvent()
                {
                    Status    = caughtPokemonResponse.Status,
                    Latitude  = lat,
                    Longitude = lng
                };

                lastThrow = caughtPokemonResponse.Status; // sets lastThrow status

                if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                {
                    var totalExp = 0;

                    foreach (var xp in caughtPokemonResponse.CaptureAward.Xp)
                    {
                        totalExp += xp;
                    }
                    var profile = await session.Client.Player.GetPlayer();

                    evt.Exp      = totalExp;
                    evt.Stardust = profile.PlayerData.Currencies.ToArray()[1].Amount;
                    evt.UniqueId = caughtPokemonResponse.CapturedPokemonId;

                    var pokemonSettings = await session.Inventory.GetPokemonSettings();

                    var pokemonFamilies = await session.Inventory.GetPokemonFamilies();

                    var setting =
                        pokemonSettings.FirstOrDefault(q => pokemon != null && q.PokemonId == pokemon.PokemonId);
                    var family = pokemonFamilies.FirstOrDefault(q => setting != null && q.FamilyId == setting.FamilyId);

                    if (family != null)
                    {
                        family.Candy_    += caughtPokemonResponse.CaptureAward.Candy.Sum();
                        evt.FamilyCandies = family.Candy_;
                    }
                    else
                    {
                        evt.FamilyCandies = caughtPokemonResponse.CaptureAward.Candy.Sum();
                    }

                    if (session.LogicSettings.UseCatchLimit)
                    {
                        session.Stats.PokemonTimestamps.Add(DateTime.Now.Ticks);
                        UpdateTimeStampsPokemon?.Invoke();
                        Logger.Write($"(CATCH LIMIT) {session.Stats.PokemonTimestamps.Count}/{session.LogicSettings.CatchPokemonLimit}",
                                     LogLevel.Info, ConsoleColor.Yellow);
                    }
                }

                evt.CatchType = encounter is EncounterResponse
                    ? session.Translation.GetTranslation(TranslationString.CatchTypeNormal)
                    : encounter is DiskEncounterResponse
                        ? session.Translation.GetTranslation(TranslationString.CatchTypeLure)
                        : session.Translation.GetTranslation(TranslationString.CatchTypeIncense);

                evt.CatchTypeText = encounter is EncounterResponse
                    ? "normal"
                    : encounter is DiskEncounterResponse
                        ? "lure"
                        : "incense";
                evt.Id = encounter is EncounterResponse
                    ? pokemon.PokemonId : encounter?.PokemonData.PokemonId;
                evt.EncounterId = encounter is EncounterResponse || encounter is IncenseEncounterResponse
                    ? pokemon.EncounterId
                    : encounterId;
                evt.Move1 = PokemonInfo.GetPokemonMove1(encounter is EncounterResponse
                    ? encounter.WildPokemon?.PokemonData
                    : encounter?.PokemonData);
                evt.Move2 = PokemonInfo.GetPokemonMove2(encounter is EncounterResponse
                    ? encounter.WildPokemon?.PokemonData
                    : encounter?.PokemonData);
                evt.Expires      = pokemon?.ExpirationTimestampMs ?? 0;
                evt.SpawnPointId = encounter is EncounterResponse || encounter is IncenseEncounterResponse
                    ? pokemon.SpawnPointId
                    : currentFortData?.Id;
                evt.Level =
                    PokemonInfo.GetLevel(encounter is EncounterResponse
                        ? encounter.WildPokemon?.PokemonData
                        : encounter?.PokemonData);
                evt.Cp = encounter is EncounterResponse
                    ? encounter.WildPokemon?.PokemonData?.Cp
                    : encounter?.PokemonData?.Cp ?? 0;
                evt.MaxCp =
                    PokemonInfo.CalculateMaxCp(encounter is EncounterResponse
                        ? encounter.WildPokemon?.PokemonData
                        : encounter?.PokemonData);
                evt.Perfection =
                    Math.Round(
                        PokemonInfo.CalculatePokemonPerfection(encounter is EncounterResponse
                            ? encounter.WildPokemon?.PokemonData
                            : encounter?.PokemonData));
                evt.Probability =
                    Math.Round(probability * 100, 2);
                evt.Distance = distance;
                evt.Pokeball = pokeball;
                evt.Attempt  = attemptCounter;
                await session.Inventory.RefreshCachedInventory();

                evt.BallAmount = await session.Inventory.GetItemAmountByType(pokeball);

                evt.Rarity = PokemonGradeHelper.GetPokemonGrade(evt.Id).ToString();
                session.EventDispatcher.Send(evt);

                attemptCounter++;

                DelayingUtils.Delay(session.LogicSettings.DelayBetweenPlayerActions, 0);
            } while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed ||
                     caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);

            if (session.LogicSettings.TransferDuplicatePokemonOnCapture &&
                session.LogicSettings.TransferDuplicatePokemon &&
                sessionAllowTransfer &&
                caughtPokemonResponse != null &&
                caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
            {
                if (session.LogicSettings.UseNearActionRandom)
                {
                    await HumanRandomActionTask.TransferRandom(session, cancellationToken);
                }
                else
                {
                    await TransferDuplicatePokemonTask.Execute(session, cancellationToken);
                }
            }
        }
        //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());
        }
        //Catch lured pokemon
        private async Task <MethodResult> CatchPokemon(FortData fortData)
        {
            try
            {
                var response = await 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  = ClientSession.Player.Latitude,
                        PlayerLongitude = ClientSession.Player.Longitude
                    }.ToByteString()
                });

                DiskEncounterResponse eResponse = null;

                eResponse = DiskEncounterResponse.Parser.ParseFrom(response);

                if (eResponse.Result == DiskEncounterResponse.Types.Result.PokemonInventoryFull)
                {
                    LogCaller(new LoggerEventArgs("Encounter failed. Pokemon inventory full", LoggerTypes.Warning));

                    return(new MethodResult
                    {
                        Message = "Encounter failed. Pokemon inventory full"
                    });
                }
                else if (eResponse.Result != DiskEncounterResponse.Types.Result.Success)
                {
                    if (eResponse.Result == DiskEncounterResponse.Types.Result.NotAvailable)
                    {
                        //Ignore
                        return(new MethodResult
                        {
                            Message = "Encounter not available"
                        });
                    }

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

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

                CatchPokemonResponse catchPokemonResponse = null;
                int attemptCount = 1;

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

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

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

                    bool isLowProbability = probability < 0.35;
                    bool isHighCp         = eResponse.PokemonData.Cp > 700;
                    bool isHighPerfection = CalculateIVPerfection(eResponse.PokemonData).Data > 90;

                    if ((isLowProbability && isHighCp) || isHighPerfection)
                    {
                        await UseBerry(fortData.LureInfo.EncounterId, fortData.Id);
                    }

                    double reticuleSize      = 1.95;
                    bool   hitInsideReticule = true;

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

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

                    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).Data);

                    if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                    {
                        int expGained = catchPokemonResponse.CaptureAward.Xp.Sum();

                        Tracker.AddValues(1, 0);

                        ExpIncrease(expGained);

                        //_expGained += expGained;

                        LogCaller(new LoggerEventArgs(String.Format("Lured Pokemon Caught. {0}. Exp {1}. Attempt #{2}", pokemon, expGained, attemptCount), LoggerTypes.Success));

                        return(new MethodResult
                        {
                            Message = "Pokemon caught",
                            Success = true
                        });
                    }
                    else if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchFlee)
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Pokemon fled. {0}. Attempt #{1}", pokemon, attemptCount), LoggerTypes.PokemonFlee));
                    }
                    else if (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape)
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Escaped ball. {0}. Attempt #{1}.", pokemon, attemptCount), LoggerTypes.PokemonEscape));
                    }
                    else
                    {
                        LogCaller(new LoggerEventArgs(String.Format("Unknown Error. {0}. Attempt #{1}. Status: {2}", pokemon, attemptCount, catchPokemonResponse.Status), LoggerTypes.Warning));
                    }

                    ++attemptCount;

                    await Task.Delay(CalculateDelay(UserSettings.DelayBetweenPlayerActions, UserSettings.PlayerActionDelayRandom));
                } while (catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || catchPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
            }
            catch (Exception ex)
            {
                LogCaller(new LoggerEventArgs("Failed to catch lured pokemon due to error", LoggerTypes.Exception, ex));

                return(new MethodResult
                {
                    Message = "Failed to catch lured pokemon"
                });
            }

            return(new MethodResult
            {
                Message = "Failed to catch lured pokemon",
                Success = true
            });
        }