Example #1
0
        private static void ExecuteSwitcher(ISession session, EncounteredEvent encounterEV)
        {
            //if distance is very far. that is snip pokemon

            if (LocationUtils.CalculateDistanceInMeters(encounterEV.Latitude, encounterEV.Longitude, session.Client.CurrentLatitude, session.Client.CurrentLongitude) > 250)//assume that all pokemon catch from 250+m is snipe
            {
                return;
            }

            if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings) &&
                session.LogicSettings.MultipleBotConfig.OnRarePokemon &&
                (
                    session.LogicSettings.MultipleBotConfig.MinIVToSwitch < encounterEV.IV ||
                    (
                        session.LogicSettings.BotSwitchPokemonFilters.ContainsKey(encounterEV.PokemonId) &&
                        (
                            session.LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId].IV < encounterEV.IV ||
                            (session.LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId].LV > 0 && session.LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId].LV < encounterEV.Level)
                        )
                    )
                ))
            {
                var curentkey = session.Settings.AuthType == PokemonGo.RocketAPI.Enums.AuthType.Google ? session.Settings.GoogleUsername : session.Settings.PtcUsername;
                curentkey += encounterEV.EncounterId;

                session.Cache.Add(curentkey, encounterEV, DateTime.Now.AddMinutes(15));
                AuthConfig evalNextBot = null;

                foreach (var bot in session.Accounts.OrderByDescending(p => p.RuntimeTotal))
                {
                    if (bot.ReleaseBlockTime > DateTime.Now)
                    {
                        continue;
                    }
                    var key = bot.AuthType == PokemonGo.RocketAPI.Enums.AuthType.Google ? bot.GoogleUsername : bot.PtcUsername;
                    key += encounterEV.EncounterId;
                    if (session.Cache.GetCacheItem(key) == null)
                    {
                        evalNextBot = bot;
                        break;
                    }
                }

                if (evalNextBot != null)
                {
                    //cancel all running task.
                    session.CancellationTokenSource.Cancel();
                    throw new ActiveSwitchByPokemonException()
                          {
                              LastLatitude           = encounterEV.Latitude,
                              LastLongitude          = encounterEV.Longitude,
                              LastEncounterPokemonId = encounterEV.PokemonId,
                              Bot = evalNextBot
                          };
                }
            }
        }
        private static void ExecuteSwitcher(ISession session, EncounteredEvent encounterEV)
        {
            //if distance is very far. that is snip pokemon

            if (session.Stats.IsSnipping
                //assume that all pokemon catch from 250+m is snipe
                || LocationUtils.CalculateDistanceInMeters(
                    encounterEV.Latitude,
                    encounterEV.Longitude,
                    session.Client.CurrentLatitude,
                    session.Client.CurrentLongitude
                    ) > 250)
            {
                return;
            }

            if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings) &&
                session.LogicSettings.MultipleBotConfig.OnRarePokemon &&
                (
                    session.LogicSettings.MultipleBotConfig.MinIVToSwitch < encounterEV.IV ||
                    (
                        session.LogicSettings.BotSwitchPokemonFilters.ContainsKey(encounterEV.PokemonId) &&
                        (
                            session.LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId].IV < encounterEV.IV ||
                            (session.LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId].LV > 0 && session
                             .LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId]
                             .LV < encounterEV.Level)
                        )
                    )
                ))
            {
                var curentkey = session.Settings.AuthType == AuthType.Google
                    ? session.Settings.GoogleUsername
                    : session.Settings.PtcUsername;

                curentkey += encounterEV.EncounterId;
                session.Cache.Add(curentkey, encounterEV, DateTime.Now.AddMinutes(15));

                var accountManager = TinyIoCContainer.Current.Resolve <MultiAccountManager>();

                var evalNextBot = accountManager.FindAvailableAccountForPokemonSwitch(encounterEV.EncounterId);

                if (evalNextBot != null)
                {
                    //cancel all running task.
                    session.CancellationTokenSource.Cancel();
                    throw new ActiveSwitchByPokemonException()
                          {
                              LastLatitude           = encounterEV.Latitude,
                              LastLongitude          = encounterEV.Longitude,
                              LastEncounterPokemonId = encounterEV.PokemonId,
                              Bot = evalNextBot
                          };
                }
            }
        }
Example #3
0
        public void OnStatisticChanged(ISession session)
        {
            if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings))
            {
                var config = session.LogicSettings.MultipleBotConfig;

                if (config.PokestopSwitch > 0 && config.PokestopSwitch <= this.TotalPokestops)
                {
                    session.CancellationTokenSource.Cancel();

                    //Activate switcher by pokestop
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.Pokestop,
                              ReachedValue = this.TotalPokestops
                          };
                }

                if (config.PokemonSwitch > 0 && config.PokemonSwitch <= this.TotalPokemons)
                {
                    session.CancellationTokenSource.Cancel();
                    //Activate switcher by pokestop
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.Pokemon,
                              ReachedValue = this.TotalPokemons
                          };
                }

                if (config.EXPSwitch > 0 && config.EXPSwitch <= this.TotalExperience)
                {
                    session.CancellationTokenSource.Cancel();
                    //Activate switcher by pokestop
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.EXP,
                              ReachedValue = this.TotalExperience
                          };
                }

                var totalMin = (DateTime.Now - _initSessionDateTime).TotalMinutes;
                if (config.RuntimeSwitch > 0 && config.RuntimeSwitch <= totalMin)
                {
                    session.CancellationTokenSource.Cancel();
                    //Activate switcher by pokestop
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.Runtime,
                              ReachedValue = Math.Round(totalMin, 1)
                          };
                }
            }
        }
Example #4
0
        public void OnStatisticChanged(ISession session)
        {
            if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings) && TinyIoCContainer.Current.Resolve <MultiAccountManager>().AllowSwitch())
            {
                var config = session.LogicSettings.MultipleBotConfig;

                if (config.PokestopSwitch > 0 && config.PokestopSwitch <= this.TotalPokestops)
                {
                    session.CancellationTokenSource.Cancel();

                    //Activate switcher by pokestop
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.Pokestop,
                              ReachedValue = this.TotalPokestops
                          };
                }

                if (config.PokemonSwitch > 0 && config.PokemonSwitch <= this.TotalPokemons)
                {
                    session.CancellationTokenSource.Cancel();
                    //Activate switcher by pokestop
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.Pokemon,
                              ReachedValue = this.TotalPokemons
                          };
                }

                if (config.EXPSwitch > 0 && config.EXPSwitch <= this.TotalExperience)
                {
                    session.CancellationTokenSource.Cancel();
                    //Activate switcher by pokestop
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.EXP,
                              ReachedValue = this.TotalExperience
                          };
                }

                // When bot starts OR did the account switch by time, random time for Runtime has not been set. So we need to set it
                if (!isRandomTimeSet)
                {
                    Random random = new Random();
                    newRandomSwitchTime = config.RuntimeSwitch + random.Next((config.RuntimeSwitchRandomTime * -1), config.RuntimeSwitchRandomTime);
                    isRandomTimeSet     = true;
                }

                var totalMin = (DateTime.Now - _initSessionDateTime).TotalMinutes;
                if (newRandomSwitchTime > 0 && newRandomSwitchTime <= totalMin)
                {
                    // Setup random time to false, so that next account generates new random runtime
                    isRandomTimeSet = false;

                    session.CancellationTokenSource.Cancel();
                    //Activate switcher by pokestop
                    throw new ActiveSwitchByRuleException()
                          {
                              MatchedRule  = SwitchRules.Runtime,
                              ReachedValue = Math.Round(totalMin, 1)
                          };
                }
            }
        }
Example #5
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);
        }
Example #6
0
        private static void ExecuteSwitcher(ISession session, EncounteredEvent encounterEV)
        {
            //if distance is very far. that is snip pokemon
            var accountManager = TinyIoCContainer.Current.Resolve <MultiAccountManager>();

            session.Cache.Add(CatchPokemonTask.GetUsernameEncounterCacheKey(session.Settings.Username, encounterEV.EncounterId), encounterEV, DateTime.Now.AddMinutes(15));

            var evalNextBot = accountManager.FindAvailableAccountForPokemonSwitch(encounterEV.EncounterId);

            if (evalNextBot == null)
            {
                return;
            }

            if (session.Stats.IsSnipping
                //assume that all pokemon catch from 250+m is snipe
                || LocationUtils.CalculateDistanceInMeters(
                    encounterEV.Latitude,
                    encounterEV.Longitude,
                    session.Client.CurrentLatitude,
                    session.Client.CurrentLongitude
                    ) > 1000)
            {
                var snipePokemonFiler = session.LogicSettings.PokemonSnipeFilters.GetFilter <SnipeFilter>(encounterEV.PokemonId);

                if (session.LogicSettings.PokemonSnipeFilters.ContainsKey(encounterEV.PokemonId))
                {
                    var filter = session.LogicSettings.PokemonSnipeFilters[encounterEV.PokemonId];
                    if (accountManager.AllowMultipleBot() &&
                        filter.AllowMultiAccountSnipe &&
                        filter.IsMatch(encounterEV.IV,
                                       (PokemonMove)Enum.Parse(typeof(PokemonMove), encounterEV.Move1),
                                       (PokemonMove)Enum.Parse(typeof(PokemonMove), encounterEV.Move2),
                                       encounterEV.Level, true))
                    {
                        //throw
                        throw new ActiveSwitchByPokemonException()
                              {
                                  EncounterData          = encounterEV,
                                  LastLatitude           = encounterEV.Latitude,
                                  LastLongitude          = encounterEV.Longitude,
                                  LastEncounterPokemonId = encounterEV.PokemonId,
                                  Snipe = true,
                                  Bot   = evalNextBot
                              };
                    }
                }

                return;
            }

            if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings, accountManager) &&
                session.LogicSettings.MultipleBotConfig.OnRarePokemon &&
                (
                    session.LogicSettings.MultipleBotConfig.MinIVToSwitch < encounterEV.IV ||
                    (
                        session.LogicSettings.BotSwitchPokemonFilters.ContainsKey(encounterEV.PokemonId) &&
                        (
                            session.LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId].IV < encounterEV.IV ||
                            (session.LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId].LV > 0 && session
                             .LogicSettings.BotSwitchPokemonFilters[encounterEV.PokemonId]
                             .LV < encounterEV.Level)
                        )
                    )
                ))
            {
                if (evalNextBot != null)
                {
                    //cancel all running task.
                    session.CancellationTokenSource.Cancel();
                    throw new ActiveSwitchByPokemonException()
                          {
                              LastLatitude           = encounterEV.Latitude,
                              LastLongitude          = encounterEV.Longitude,
                              LastEncounterPokemonId = encounterEV.PokemonId,
                              Bot = evalNextBot
                          };
                }
            }
        }
Example #7
0
        public static async Task FarmPokestop(ISession session, FortData pokeStop, FortDetailsResponse fortInfo, CancellationToken cancellationToken, bool doNotRetry = false)
        {
            var manager = TinyIoC.TinyIoCContainer.Current.Resolve <MultiAccountManager>();

            // If the cooldown is in the future than don't farm the pokestop.
            if (pokeStop.CooldownCompleteTimestampMs > DateTime.UtcNow.ToUnixTime())
            {
                return;
            }

            if (session.Stats.SearchThresholdExceeds(session, true))
            {
                if (manager.AllowMultipleBot() && session.LogicSettings.MultipleBotConfig.SwitchOnPokestopLimit)
                {
                    throw new Exceptions.ActiveSwitchByRuleException(SwitchRules.SpinPokestopReached, session.LogicSettings.PokeStopLimit);
                }
                return;
            }

            //await session.Client.Map.GetMapObjects().ConfigureAwait(false);
            FortSearchResponse fortSearch;
            var timesZeroXPawarded = 0;
            var fortTry            = 0;                                     //Current check
            int retryNumber        = session.LogicSettings.ByPassSpinCount; //How many times it needs to check to clear softban
            int zeroCheck          = Math.Min(5, retryNumber);              //How many times it checks fort before it thinks it's softban

            var distance = LocationUtils.CalculateDistanceInMeters(pokeStop.Latitude, pokeStop.Longitude, session.Client.CurrentLatitude, session.Client.CurrentLongitude);

            //This should be < ## not > ##. > makes bot jump to pokestop if < then when in range will just spin.
            if (distance < 50) //if (distance > 30)
            {
                await LocationUtils.UpdatePlayerLocationWithAltitude(session, new GeoCoordinate(pokeStop.Latitude, pokeStop.Longitude), 0).ConfigureAwait(false);

                await session.Client.Misc.RandomAPICall().ConfigureAwait(false);
            }

            do
            {
                cancellationToken.ThrowIfCancellationRequested();
                TinyIoC.TinyIoCContainer.Current.Resolve <MultiAccountManager>().ThrowIfSwitchAccountRequested();
                int    retry     = 3;
                double latitude  = pokeStop.Latitude;
                double longitude = pokeStop.Longitude;
                do
                {
                    fortSearch = await session.Client.Fort.SearchFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude).ConfigureAwait(false);

                    if (fortSearch.Result == FortSearchResponse.Types.Result.OutOfRange)
                    {
                        if (retry > 2)
                        {
                            await Task.Delay(500).ConfigureAwait(false);
                        }
                        else
                        {
                            await session.Client.Map.GetMapObjects(true).ConfigureAwait(false);
                        }

                        Logger.Debug($"Loot pokestop result: {fortSearch.Result}, distance to pokestop:[{pokeStop.Latitude}, {pokeStop.Longitude}] {distance:0.00}m, retry: #{4 - retry}");

                        latitude  += 0.000003;
                        longitude += 0.000005;
                        await LocationUtils.UpdatePlayerLocationWithAltitude(session, new GeoCoordinate(latitude, longitude), 0).ConfigureAwait(false);

                        retry--;
                    }
                }while (fortSearch.Result == FortSearchResponse.Types.Result.OutOfRange && retry > 0);
                Logger.Debug($"Loot pokestop result: {fortSearch.Result}");
                if (fortSearch.ExperienceAwarded > 0 && timesZeroXPawarded > 0)
                {
                    timesZeroXPawarded = 0;
                }
                if (fortSearch.ExperienceAwarded == 0 && fortSearch.Result != FortSearchResponse.Types.Result.InventoryFull)
                {
                    timesZeroXPawarded++;

                    if (timesZeroXPawarded > zeroCheck)
                    {
                        if ((int)fortSearch.CooldownCompleteTimestampMs != 0)
                        {
                            break; // Check if successfully looted, if so program can continue as this was "false alarm".
                        }

                        fortTry += 1;

                        session.EventDispatcher.Send(new FortFailedEvent
                        {
                            Name   = fortInfo.Name,
                            Try    = fortTry,
                            Max    = retryNumber - zeroCheck,
                            Looted = false
                        });
                        if (doNotRetry)
                        {
                            break;
                        }
                        if (!session.LogicSettings.FastSoftBanBypass)
                        {
                            await DelayingUtils.DelayAsync(session.LogicSettings.DelayBetweenPlayerActions, 0, session.CancellationTokenSource.Token).ConfigureAwait(false);
                        }
                    }
                }
                else
                {
                    softbanCount = 0;
                    if (fortTry != 0)
                    {
                        session.EventDispatcher.Send(new FortFailedEvent
                        {
                            Name   = fortInfo.Name,
                            Try    = fortTry + 1,
                            Max    = retryNumber - zeroCheck,
                            Looted = true
                        });
                    }

                    session.EventDispatcher.Send(new FortUsedEvent
                    {
                        Id             = pokeStop.Id,
                        Name           = fortInfo.Name,
                        Exp            = fortSearch.ExperienceAwarded,
                        Gems           = fortSearch.GemsAwarded > 0 ? $"Yes {fortSearch.GemsAwarded}" : "No",
                        Items          = StringUtils.GetSummedFriendlyNameOfItemAwardList(fortSearch.ItemsAwarded),
                        Badges         = fortSearch.AwardedGymBadge != null ? fortSearch.AwardedGymBadge.GymBadgeType.ToString() : "No",
                        BonusLoot      = fortSearch.BonusLoot != null ? StringUtils.GetSummedFriendlyNameOfGetLootList(fortSearch.BonusLoot.LootItem) : "No",
                        RaidTickets    = fortSearch.RaidTickets > 0 ? $"{fortSearch.RaidTickets} tickets" : "No",
                        TeamBonusLoot  = fortSearch.TeamBonusLoot != null ? StringUtils.GetSummedFriendlyNameOfGetLootList(fortSearch.TeamBonusLoot.LootItem) : "No",
                        PokemonDataEgg = fortSearch.PokemonDataEgg != null ? fortSearch.PokemonDataEgg : null,
                        Latitude       = pokeStop.Latitude,
                        Longitude      = pokeStop.Longitude,
                        Altitude       = session.Client.CurrentAltitude,
                        InventoryFull  = fortSearch.Result == FortSearchResponse.Types.Result.InventoryFull,
                        Fort           = pokeStop
                    });

                    if (fortSearch.Result == FortSearchResponse.Types.Result.Success)
                    {
                        mapEmptyCount = 0;
                        foreach (var item in fortSearch.ItemsAwarded)
                        {
                            await session.Inventory.UpdateInventoryItem(item.ItemId).ConfigureAwait(false);
                        }
                        if (fortSearch.PokemonDataEgg != null)
                        {
                            fortSearch.PokemonDataEgg.IsEgg = true;
                        }

                        // Update the cache
                        var fortFromCache = session.Client.Map.LastGetMapObjectResponse.MapCells.SelectMany(x => x.Forts).FirstOrDefault(f => f.Id == pokeStop.Id);

                        long newCooldown = TimeUtil.GetCurrentTimestampInMilliseconds() + (5 * 60 * 1000); /* 5 min */
                        fortFromCache.CooldownCompleteTimestampMs = newCooldown;
                        pokeStop.CooldownCompleteTimestampMs      = newCooldown;

                        if (session.SaveBallForByPassCatchFlee)
                        {
                            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);
                            Logger.Write($"Ball requires for by pass catch flee {totalBalls}/{CatchPokemonTask.BALL_REQUIRED_TO_BYPASS_CATCHFLEE}");
                        }
                        else
                        {
                            MSniperServiceTask.UnblockSnipe(false);
                        }
                    }
                    if (fortSearch.Result == FortSearchResponse.Types.Result.InventoryFull)
                    {
                        await RecycleItemsTask.Execute(session, cancellationToken).ConfigureAwait(false);

                        _storeRi = 1;
                    }

                    if (session.LogicSettings.UsePokeStopLimit)
                    {
                        session.Stats.AddPokestopTimestamp(DateTime.Now.Ticks);
                        session.EventDispatcher.Send(new PokestopLimitUpdate(session.Stats.GetNumPokestopsInLast24Hours(), session.LogicSettings.PokeStopLimit));
                    }
                    //add pokeStops to Map
                    OnLootPokestopEvent(pokeStop);
                    //end pokeStop to Map

                    break; //Continue with program as loot was succesfull.
                }
            } while (fortTry < retryNumber - zeroCheck);
            //Stop trying if softban is cleaned earlier or if 40 times fort looting failed.

            if (manager.AllowMultipleBot())
            {
                if (fortTry >= retryNumber - zeroCheck)
                {
                    softbanCount++;

                    //only check if PokestopSoftbanCount > 0
                    if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings, manager) &&
                        session.LogicSettings.MultipleBotConfig.PokestopSoftbanCount > 0 &&
                        session.LogicSettings.MultipleBotConfig.PokestopSoftbanCount <= softbanCount &&
                        TinyIoCContainer.Current.Resolve <MultiAccountManager>().AllowSwitch())
                    {
                        softbanCount = 0;

                        //Activate switcher by pokestop
                        throw new ActiveSwitchByRuleException()
                              {
                                  MatchedRule  = SwitchRules.PokestopSoftban,
                                  ReachedValue = session.LogicSettings.MultipleBotConfig.PokestopSoftbanCount
                              };
                    }
                }
            }
            else
            {
                softbanCount = 0; //reset softban count
            }

            if (session.LogicSettings.RandomlyPauseAtStops && !doNotRetry)
            {
                if (++_randomStop >= _randomNumber)
                {
                    _randomNumber = _rc.Next(4, 11);
                    _randomStop   = 0;
                    int randomWaitTime = _rc.Next(30, 120);
                    await Task.Delay(randomWaitTime, cancellationToken).ConfigureAwait(false);
                }
            }
        }
        private static async Task FarmPokestop(ISession session, FortData pokeStop, FortDetailsResponse fortInfo, CancellationToken cancellationToken, bool doNotRetry = false)
        {
            // If the cooldown is in the future than don't farm the pokestop.
            if (pokeStop.CooldownCompleteTimestampMs > DateTime.UtcNow.ToUnixTime())
            {
                return;
            }

            FortSearchResponse fortSearch;
            var       timesZeroXPawarded = 0;
            var       fortTry            = 0;  //Current check
            const int retryNumber        = 50; //How many times it needs to check to clear softban
            const int zeroCheck          = 5;  //How many times it checks fort before it thinks it's softban

            do
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (SearchThresholdExceeds(session))
                {
                    break;
                }

                fortSearch =
                    await session.Client.Fort.SearchFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);

                if (fortSearch.ExperienceAwarded > 0 && timesZeroXPawarded > 0)
                {
                    timesZeroXPawarded = 0;
                }
                if (fortSearch.ExperienceAwarded == 0 && fortSearch.Result != FortSearchResponse.Types.Result.InventoryFull)
                {
                    timesZeroXPawarded++;

                    if (timesZeroXPawarded > zeroCheck)
                    {
                        if ((int)fortSearch.CooldownCompleteTimestampMs != 0)
                        {
                            break; // Check if successfully looted, if so program can continue as this was "false alarm".
                        }

                        fortTry += 1;

                        session.EventDispatcher.Send(new FortFailedEvent
                        {
                            Name   = fortInfo.Name,
                            Try    = fortTry,
                            Max    = retryNumber - zeroCheck,
                            Looted = false
                        });
                        if (doNotRetry)
                        {
                            break;
                        }
                        if (!session.LogicSettings.FastSoftBanBypass)
                        {
                            DelayingUtils.Delay(session.LogicSettings.DelayBetweenPlayerActions, 0);
                        }
                    }
                }
                else
                {
                    if (fortTry != 0)
                    {
                        session.EventDispatcher.Send(new FortFailedEvent
                        {
                            Name   = fortInfo.Name,
                            Try    = fortTry + 1,
                            Max    = retryNumber - zeroCheck,
                            Looted = true
                        });
                    }

                    session.EventDispatcher.Send(new FortUsedEvent
                    {
                        Id            = pokeStop.Id,
                        Name          = fortInfo.Name,
                        Exp           = fortSearch.ExperienceAwarded,
                        Gems          = fortSearch.GemsAwarded,
                        Items         = StringUtils.GetSummedFriendlyNameOfItemAwardList(fortSearch.ItemsAwarded),
                        Latitude      = pokeStop.Latitude,
                        Longitude     = pokeStop.Longitude,
                        Altitude      = session.Client.CurrentAltitude,
                        InventoryFull = fortSearch.Result == FortSearchResponse.Types.Result.InventoryFull
                    });
                    if (fortSearch.Result == FortSearchResponse.Types.Result.InventoryFull)
                    {
                        await RecycleItemsTask.Execute(session, cancellationToken);

                        _storeRi = 1;
                    }

                    if (session.LogicSettings.UsePokeStopLimit)
                    {
                        session.Stats.AddPokestopTimestamp(DateTime.Now.Ticks);
                        Logger.Write($"(POKESTOP LIMIT) {session.Stats.GetNumPokestopsInLast24Hours()}/{session.LogicSettings.PokeStopLimit}",
                                     LogLevel.Info, ConsoleColor.Yellow);
                    }
                    break; //Continue with program as loot was succesfull.
                }
            } while (fortTry < retryNumber - zeroCheck);
            //Stop trying if softban is cleaned earlier or if 40 times fort looting failed.

            if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings))
            {
                if (fortTry >= retryNumber - zeroCheck)
                {
                    softbanCount++;

                    //only check if PokestopSoftbanCount > 0
                    if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings) &&
                        session.LogicSettings.MultipleBotConfig.PokestopSoftbanCount > 0 &&
                        session.LogicSettings.MultipleBotConfig.PokestopSoftbanCount <= softbanCount)
                    {
                        softbanCount = 0;
                        session.CancellationTokenSource.Cancel();

                        //Activate switcher by pokestop
                        throw new ActiveSwitchByRuleException()
                              {
                                  MatchedRule  = SwitchRules.PokestopSoftban,
                                  ReachedValue = softbanCount
                              };
                    }
                }
            }
            else
            {
                softbanCount = 0; //reset softban count
            }

            if (session.LogicSettings.RandomlyPauseAtStops && !doNotRetry)
            {
                if (++_randomStop >= _randomNumber)
                {
                    _randomNumber = _rc.Next(4, 11);
                    _randomStop   = 0;
                    int randomWaitTime = _rc.Next(30, 120);
                    await Task.Delay(randomWaitTime, cancellationToken);
                }
            }
        }
        /// <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);
        }
Example #10
0
        private static async Task FarmPokestop(ISession session, FortData pokeStop, FortDetailsResponse fortInfo, CancellationToken cancellationToken, bool doNotRetry = false)
        {
            // If the cooldown is in the future than don't farm the pokestop.
            if (pokeStop.CooldownCompleteTimestampMs > DateTime.UtcNow.ToUnixTime())
            {
                return;
            }

            if (session.Stats.SearchThresholdExceeds(session, true))
            {
                if (session.LogicSettings.AllowMultipleBot && session.LogicSettings.MultipleBotConfig.SwitchOnPokestopLimit)
                {
                    throw new Exceptions.ActiveSwitchByRuleException(SwitchRules.SpinPokestopReached, session.LogicSettings.PokeStopLimit);
                }
                return;
            }

            //await session.Client.Map.GetMapObjects();
            FortSearchResponse fortSearch;
            var timesZeroXPawarded = 0;
            var fortTry            = 0;                                     //Current check
            int retryNumber        = session.LogicSettings.ByPassSpinCount; //How many times it needs to check to clear softban
            int zeroCheck          = Math.Min(5, retryNumber);              //How many times it checks fort before it thinks it's softban

            do
            {
                cancellationToken.ThrowIfCancellationRequested();
                TinyIoC.TinyIoCContainer.Current.Resolve <MultiAccountManager>().ThrowIfSwitchAccountRequested();
                int retry = 3;
                do
                {
                    fortSearch =
                        await session.Client.Fort.SearchFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);

                    if (fortSearch.Result == FortSearchResponse.Types.Result.OutOfRange)
                    {
                        if (retry < 2)
                        {
                            await session.Client.Map.GetMapObjects(true);
                        }
                        var distance = LocationUtils.CalculateDistanceInMeters(pokeStop.Latitude, pokeStop.Longitude, session.Client.CurrentLatitude, session.Client.CurrentLongitude);
#if DEBUG
                        Logger.Write($"Loot pokestop result :{fortSearch.Result} , distance to pokestop : {distance:0.00}m");
#endif
                        if (distance > 30)
                        {
                            await LocationUtils.UpdatePlayerLocationWithAltitude(session, new GeoCoordinatePortable.GeoCoordinate(pokeStop.Latitude, pokeStop.Longitude), 0);
                        }
                        retry--;
                        //await session.Client.Map.GetMapObjects(true);
                    }
                }while (fortSearch.Result == FortSearchResponse.Types.Result.OutOfRange && retry > 0);

                if (fortSearch.ExperienceAwarded > 0 && timesZeroXPawarded > 0)
                {
                    timesZeroXPawarded = 0;
                }
                if (fortSearch.ExperienceAwarded == 0 && fortSearch.Result != FortSearchResponse.Types.Result.InventoryFull)
                {
                    timesZeroXPawarded++;

                    if (timesZeroXPawarded > zeroCheck)
                    {
                        if ((int)fortSearch.CooldownCompleteTimestampMs != 0)
                        {
                            break; // Check if successfully looted, if so program can continue as this was "false alarm".
                        }

                        fortTry += 1;

                        session.EventDispatcher.Send(new FortFailedEvent
                        {
                            Name   = fortInfo.Name,
                            Try    = fortTry,
                            Max    = retryNumber - zeroCheck,
                            Looted = false
                        });
                        if (doNotRetry)
                        {
                            break;
                        }
                        if (!session.LogicSettings.FastSoftBanBypass)
                        {
                            DelayingUtils.Delay(session.LogicSettings.DelayBetweenPlayerActions, 0);
                        }
                    }
                }
                else
                {
                    softbanCount = 0;
                    if (fortTry != 0)
                    {
                        session.EventDispatcher.Send(new FortFailedEvent
                        {
                            Name   = fortInfo.Name,
                            Try    = fortTry + 1,
                            Max    = retryNumber - zeroCheck,
                            Looted = true
                        });
                    }

                    session.EventDispatcher.Send(new FortUsedEvent
                    {
                        Id            = pokeStop.Id,
                        Name          = fortInfo.Name,
                        Exp           = fortSearch.ExperienceAwarded,
                        Gems          = fortSearch.GemsAwarded,
                        Items         = StringUtils.GetSummedFriendlyNameOfItemAwardList(fortSearch.ItemsAwarded),
                        Latitude      = pokeStop.Latitude,
                        Longitude     = pokeStop.Longitude,
                        Altitude      = session.Client.CurrentAltitude,
                        InventoryFull = fortSearch.Result == FortSearchResponse.Types.Result.InventoryFull,
                        Fort          = pokeStop
                    });
                    if (fortSearch.Result == FortSearchResponse.Types.Result.Success)
                    {
                        mapEmptyCount = 0;
                        foreach (var item in fortSearch.ItemsAwarded)
                        {
                            await session.Inventory.UpdateInventoryItem(item.ItemId);
                        }
                        if (fortSearch.PokemonDataEgg != null)
                        {
                            fortSearch.PokemonDataEgg.IsEgg = true;
                        }

                        // Update the cache
                        var fortFromCache = session.Client.Map.LastGetMapObjectResponse.MapCells.SelectMany(x => x.Forts).FirstOrDefault(f => f.Id == pokeStop.Id);

                        long newCooldown = TimeUtil.GetCurrentTimestampInMilliseconds() + (5 * 60 * 1000); /* 5 min */
                        fortFromCache.CooldownCompleteTimestampMs = newCooldown;
                        pokeStop.CooldownCompleteTimestampMs      = newCooldown;
                    }
                    MSniperServiceTask.UnblockSnipe(false);
                    if (fortSearch.Result == FortSearchResponse.Types.Result.InventoryFull)
                    {
                        await RecycleItemsTask.Execute(session, cancellationToken);

                        _storeRi = 1;
                    }

                    if (session.LogicSettings.UsePokeStopLimit)
                    {
                        session.Stats.AddPokestopTimestamp(DateTime.Now.Ticks);
                        session.EventDispatcher.Send(new PokestopLimitUpdate(session.Stats.GetNumPokestopsInLast24Hours(), session.LogicSettings.PokeStopLimit));
                    }
                    break; //Continue with program as loot was succesfull.
                }
            } while (fortTry < retryNumber - zeroCheck);
            //Stop trying if softban is cleaned earlier or if 40 times fort looting failed.

            if (session.LogicSettings.AllowMultipleBot)
            {
                if (fortTry >= retryNumber - zeroCheck)
                {
                    softbanCount++;

                    //only check if PokestopSoftbanCount > 0
                    if (MultipleBotConfig.IsMultiBotActive(session.LogicSettings) &&
                        session.LogicSettings.MultipleBotConfig.PokestopSoftbanCount > 0 &&
                        session.LogicSettings.MultipleBotConfig.PokestopSoftbanCount <= softbanCount &&
                        TinyIoCContainer.Current.Resolve <MultiAccountManager>().AllowSwitch())
                    {
                        softbanCount = 0;

                        //Activate switcher by pokestop
                        throw new ActiveSwitchByRuleException()
                              {
                                  MatchedRule  = SwitchRules.PokestopSoftban,
                                  ReachedValue = session.LogicSettings.MultipleBotConfig.PokestopSoftbanCount
                              };
                    }
                }
            }
            else
            {
                softbanCount = 0; //reset softban count
            }

            if (session.LogicSettings.RandomlyPauseAtStops && !doNotRetry)
            {
                if (++_randomStop >= _randomNumber)
                {
                    _randomNumber = _rc.Next(4, 11);
                    _randomStop   = 0;
                    int randomWaitTime = _rc.Next(30, 120);
                    await Task.Delay(randomWaitTime, cancellationToken);
                }
            }
        }