Major Updated from Sen66

Detective Squirrel [2016-07-23 11:53:47]
Major Updated from Sen66

Updates in README
Filename
PokemonGo/RocketAPI/Client.cs
PokemonGo/RocketAPI/Console/App.config
PokemonGo/RocketAPI/Console/Program.cs
PokemonGo/RocketAPI/Console/Settings.cs
PokemonGo/RocketAPI/ISettings.cs
PokemonGo/RocketAPI/Login/GoogleLogin.cs
README.md
screenshot.jpg
diff --git a/PokemonGo/RocketAPI/Client.cs b/PokemonGo/RocketAPI/Client.cs
index d5312a5..8cd5b80 100644
--- a/PokemonGo/RocketAPI/Client.cs
+++ b/PokemonGo/RocketAPI/Client.cs
@@ -29,7 +29,7 @@ namespace PokemonGo.RocketAPI
         private double _currentLat;
         private double _currentLng;
         private Request.Types.UnknownAuth _unknownAuth;
-        static string accestoken = string.Empty;
+        public static string AccessToken { get; set; } = string.Empty;

         public Client(ISettings settings)
         {
@@ -58,7 +58,7 @@ namespace PokemonGo.RocketAPI
             var customRequest = new Request.Types.CatchPokemonRequest
             {
                 EncounterId = encounterId,
-                Pokeball = (int) GetBestBall(pokemonCP).Result,
+                Pokeball = (int)GetBestBall(pokemonCP).Result,
                 SpawnPointGuid = spawnPointGuid,
                 HitPokemon = 1,
                 NormalizedReticleSize = Utils.FloatAsUlong(1.950),
@@ -69,7 +69,7 @@ namespace PokemonGo.RocketAPI
             var catchPokemonRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.CATCH_POKEMON,
+                    Type = (int)RequestType.CATCH_POKEMON,
                     Message = customRequest.ToByteString()
                 });
             return
@@ -80,29 +80,37 @@ namespace PokemonGo.RocketAPI

         public async Task DoGoogleLogin()
         {
-            if (_settings.GoogleRefreshToken == string.Empty && accestoken == string.Empty)
+            _authType = AuthType.Google;
+            GoogleLogin.TokenResponseModel tokenResponse = null;
+
+            if (_settings.GoogleRefreshToken == string.Empty && AccessToken == string.Empty)
             {
-                var tokenResponse = await GoogleLogin.GetAccessToken();
+                var deviceCode = await GoogleLogin.GetDeviceCode();
+                tokenResponse = await GoogleLogin.GetAccessToken(deviceCode);
                 _accessToken = tokenResponse.id_token;
-                Console.WriteLine($"Put RefreshToken in settings for direct login: {tokenResponse.access_token}");
-                accestoken = tokenResponse.access_token;
+                Console.WriteLine($"Put RefreshToken in settings for direct login: {tokenResponse.refresh_token}");
+                _settings.GoogleRefreshToken = tokenResponse.refresh_token;
+                AccessToken = tokenResponse.refresh_token;
             }
             else
             {
-                GoogleLogin.TokenResponseModel tokenResponse;
-                if (_settings.GoogleRefreshToken != string.Empty)
+                if (_settings.GoogleRefreshToken != null)
                     tokenResponse = await GoogleLogin.GetAccessToken(_settings.GoogleRefreshToken);
                 else
-                    tokenResponse = await GoogleLogin.GetAccessToken(accestoken);
+                    tokenResponse = await GoogleLogin.GetAccessToken(AccessToken);
                 _accessToken = tokenResponse.id_token;
-                _authType = AuthType.Google;
             }
         }

         public async Task DoPtcLogin(string username, string password)
         {
-            _accessToken = await PtcLogin.GetAccessToken(username, password);
-            _authType = AuthType.Ptc;
+            try
+            {
+                _accessToken = await PtcLogin.GetAccessToken(username, password);
+                _authType = AuthType.Ptc;
+            }
+            catch (Newtonsoft.Json.JsonReaderException) { ColoredConsoleWrite(ConsoleColor.White, "Json Reader Exception - Server down? - Restarting"); DoPtcLogin(username, password); }
+            catch (Exception ex) { ColoredConsoleWrite(ConsoleColor.White, ex.ToString() + "Exception - Please report - Restarting"); DoPtcLogin(username, password); }
         }

         public async Task<EncounterResponse> EncounterPokemon(ulong encounterId, string spawnPointGuid)
@@ -118,7 +126,7 @@ namespace PokemonGo.RocketAPI
             var encounterResponse = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.ENCOUNTER,
+                    Type = (int)RequestType.ENCOUNTER,
                     Message = customRequest.ToByteString()
                 });
             return
@@ -136,7 +144,7 @@ namespace PokemonGo.RocketAPI
             var releasePokemonRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.EVOLVE_POKEMON,
+                    Type = (int)RequestType.EVOLVE_POKEMON,
                     Message = customRequest.ToByteString()
                 });
             return
@@ -151,21 +159,21 @@ namespace PokemonGo.RocketAPI

             var ballCollection = inventory.InventoryDelta.InventoryItems.Select(i => i.InventoryItemData?.Item)
                 .Where(p => p != null)
-                .GroupBy(i => (MiscEnums.Item) i.Item_)
-                .Select(kvp => new {ItemId = kvp.Key, Amount = kvp.Sum(x => x.Count)})
+                .GroupBy(i => (MiscEnums.Item)i.Item_)
+                .Select(kvp => new { ItemId = kvp.Key, Amount = kvp.Sum(x => x.Count) })
                 .Where(y => y.ItemId == MiscEnums.Item.ITEM_POKE_BALL
                             || y.ItemId == MiscEnums.Item.ITEM_GREAT_BALL
                             || y.ItemId == MiscEnums.Item.ITEM_ULTRA_BALL
                             || y.ItemId == MiscEnums.Item.ITEM_MASTER_BALL);

             var pokeBallsCount = ballCollection.Where(p => p.ItemId == MiscEnums.Item.ITEM_POKE_BALL).
-                DefaultIfEmpty(new {ItemId = MiscEnums.Item.ITEM_POKE_BALL, Amount = 0}).FirstOrDefault().Amount;
+                DefaultIfEmpty(new { ItemId = MiscEnums.Item.ITEM_POKE_BALL, Amount = 0 }).FirstOrDefault().Amount;
             var greatBallsCount = ballCollection.Where(p => p.ItemId == MiscEnums.Item.ITEM_GREAT_BALL).
-                DefaultIfEmpty(new {ItemId = MiscEnums.Item.ITEM_GREAT_BALL, Amount = 0}).FirstOrDefault().Amount;
+                DefaultIfEmpty(new { ItemId = MiscEnums.Item.ITEM_GREAT_BALL, Amount = 0 }).FirstOrDefault().Amount;
             var ultraBallsCount = ballCollection.Where(p => p.ItemId == MiscEnums.Item.ITEM_ULTRA_BALL).
-                DefaultIfEmpty(new {ItemId = MiscEnums.Item.ITEM_ULTRA_BALL, Amount = 0}).FirstOrDefault().Amount;
+                DefaultIfEmpty(new { ItemId = MiscEnums.Item.ITEM_ULTRA_BALL, Amount = 0 }).FirstOrDefault().Amount;
             var masterBallsCount = ballCollection.Where(p => p.ItemId == MiscEnums.Item.ITEM_MASTER_BALL).
-                DefaultIfEmpty(new {ItemId = MiscEnums.Item.ITEM_MASTER_BALL, Amount = 0}).FirstOrDefault().Amount;
+                DefaultIfEmpty(new { ItemId = MiscEnums.Item.ITEM_MASTER_BALL, Amount = 0 }).FirstOrDefault().Amount;

             // Use better balls for high CP pokemon
             if (masterBallsCount > 0 && pokemonCP >= 1000)
@@ -193,12 +201,12 @@ namespace PokemonGo.RocketAPI
                 return MiscEnums.Item.ITEM_POKE_BALL;
             }
             else if ((greatBallsCount < 40 && pokemonCP >= 200) || greatBallsCount >= 40)
-                {
-                    ColoredConsoleWrite(ConsoleColor.Green, $"[{DateTime.Now.ToString("HH:mm:ss")}] Great Ball is being used");
+            {
+                ColoredConsoleWrite(ConsoleColor.Green, $"[{DateTime.Now.ToString("HH:mm:ss")}] Great Ball is being used");
                 return MiscEnums.Item.ITEM_GREAT_BALL;
             }
             else if (ultraBallsCount > 0 && pokemonCP >= 500)
-                {
+            {
                 ColoredConsoleWrite(ConsoleColor.Green, $"[{DateTime.Now.ToString("HH:mm:ss")}] Ultra Ball is being used");
                 return MiscEnums.Item.ITEM_ULTRA_BALL;
             }
@@ -231,7 +239,7 @@ namespace PokemonGo.RocketAPI
             var fortDetailRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 10,
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.FORT_DETAILS,
+                    Type = (int)RequestType.FORT_DETAILS,
                     Message = customRequest.ToByteString()
                 });
             return
@@ -266,19 +274,19 @@ namespace PokemonGo.RocketAPI
             var mapRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 10,
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.GET_MAP_OBJECTS,
+                    Type = (int)RequestType.GET_MAP_OBJECTS,
                     Message = customRequest.ToByteString()
                 },
-                new Request.Types.Requests {Type = (int) RequestType.GET_HATCHED_OBJECTS},
+                new Request.Types.Requests { Type = (int)RequestType.GET_HATCHED_OBJECTS },
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.GET_INVENTORY,
-                    Message = new Request.Types.Time {Time_ = DateTime.UtcNow.ToUnixTime()}.ToByteString()
+                    Type = (int)RequestType.GET_INVENTORY,
+                    Message = new Request.Types.Time { Time_ = DateTime.UtcNow.ToUnixTime() }.ToByteString()
                 },
-                new Request.Types.Requests {Type = (int) RequestType.CHECK_AWARDED_BADGES},
+                new Request.Types.Requests { Type = (int)RequestType.CHECK_AWARDED_BADGES },
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.DOWNLOAD_SETTINGS,
+                    Type = (int)RequestType.DOWNLOAD_SETTINGS,
                     Message =
                         new Request.Types.SettingsGuid
                         {
@@ -293,7 +301,7 @@ namespace PokemonGo.RocketAPI
         public async Task<GetPlayerResponse> GetProfile()
         {
             var profileRequest = RequestBuilder.GetInitialRequest(_accessToken, _authType, _currentLat, _currentLng, 10,
-                new Request.Types.Requests {Type = (int) RequestType.GET_PLAYER});
+                new Request.Types.Requests { Type = (int)RequestType.GET_PLAYER });
             return
                 await _httpClient.PostProtoPayload<Request, GetPlayerResponse>($"https://{_apiUrl}/rpc", profileRequest);
         }
@@ -330,7 +338,7 @@ namespace PokemonGo.RocketAPI
             var fortDetailRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.FORT_SEARCH,
+                    Type = (int)RequestType.FORT_SEARCH,
                     Message = customRequest.ToByteString()
                 });
             return
@@ -343,6 +351,8 @@ namespace PokemonGo.RocketAPI
         {
             _currentLat = lat;
             _currentLng = lng;
+//            _settings.DefaultLatitude = lat;
+//            _settings.DefaultLongitude = lng;
         }

         public async Task SetServer()
@@ -371,7 +381,7 @@ namespace PokemonGo.RocketAPI
             var releasePokemonRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.RELEASE_POKEMON,
+                    Type = (int)RequestType.RELEASE_POKEMON,
                     Message = customRequest.ToByteString()
                 });
             return
@@ -392,7 +402,7 @@ namespace PokemonGo.RocketAPI
             var updateRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 10,
                 new Request.Types.Requests
                 {
-                    Type = (int) RequestType.PLAYER_UPDATE,
+                    Type = (int)RequestType.PLAYER_UPDATE,
                     Message = customRequest.ToByteString()
                 });
             var updateResponse =
@@ -420,7 +430,7 @@ namespace PokemonGo.RocketAPI
             foreach (var item in items)
             {
                 var transfer = await RecycleItem((AllEnum.ItemId)item.Item_, item.Count);
-                ColoredConsoleWrite(ConsoleColor.DarkCyan, $"[{DateTime.Now.ToString("HH:mm:ss")}] Recycled {item.Count}x {(AllEnum.ItemId)item.Item_}");
+                ColoredConsoleWrite(ConsoleColor.DarkCyan, $"[{DateTime.Now.ToString("HH:mm:ss")}] Recycled {item.Count}x {((AllEnum.ItemId)item.Item_).ToString().Substring(4)}");
                 await Task.Delay(500);
             }
             await Task.Delay(_settings.RecycleItemsInterval * 1000);
@@ -451,5 +461,36 @@ namespace PokemonGo.RocketAPI
                 .Select(i => i.InventoryItemData?.Item)
                 .Where(p => p != null);
         }
+
+        public async Task<UseItemCaptureRequest> UseCaptureItem(ulong encounterId, AllEnum.ItemId itemId, string spawnPointGuid)
+        {
+            var customRequest = new UseItemCaptureRequest
+            {
+                EncounterId = encounterId,
+                ItemId = itemId,
+                SpawnPointGuid = spawnPointGuid
+            };
+
+            var useItemRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
+                new Request.Types.Requests()
+                {
+                    Type = (int)RequestType.USE_ITEM_CAPTURE,
+                    Message = customRequest.ToByteString()
+                });
+            return await _httpClient.PostProtoPayload<Request, UseItemCaptureRequest>($"https://{_apiUrl}/rpc", useItemRequest);
+        }
+
+        public async Task UseRazzBerry(Client client, ulong encounterId, string spawnPointGuid)
+        {
+            IEnumerable<Item> myItems = await GetItems(client);
+            IEnumerable<Item> RazzBerries = myItems.Where(i => (ItemId)i.Item_ == ItemId.ItemRazzBerry);
+            Item RazzBerry = RazzBerries.FirstOrDefault();
+            if (RazzBerry != null)
+            {
+                UseItemCaptureRequest useRazzBerry = await client.UseCaptureItem(encounterId, AllEnum.ItemId.ItemRazzBerry, spawnPointGuid);
+                ColoredConsoleWrite(ConsoleColor.Green, $"[{DateTime.Now.ToString("HH:mm:ss")}] Used Rasperry. Remaining: {RazzBerry.Count}");
+                await Task.Delay(2000);
+            }
+        }
     }
 }
diff --git a/PokemonGo/RocketAPI/Console/App.config b/PokemonGo/RocketAPI/Console/App.config
index 0884bc8..1ad5872 100644
--- a/PokemonGo/RocketAPI/Console/App.config
+++ b/PokemonGo/RocketAPI/Console/App.config
@@ -20,8 +20,11 @@
     <add key="DefaultLongitude" value="174.766365" /> <!--Default Viaduct Harbour, Auckland, New Zealand-->
     <add key="LevelOutput" value="levelup" /> <!--2 Modes: "time": Every XXX seconds and "levelup" every levelup-->
     <add key="LevelTimeInterval" value="1" /> <!--Pick 1 if levelup and time in seconds if "time"-->
-    <add key="RecycleItemsInterval" value="60" /> <!--Recycle Time in seconds-->
+    <add key="Recycler" value="true" /> <!--Recycler master switch-->
+    <add key="RecycleItemsInterval" value="60" /> <!--Recycle Interval in seconds-->
     <add key="Language" value="english" /> <!--Languages english/german-->
+    <add key="RazzBerryMode" value="probability" /> <!--When to use RazzBerry cp/probability-->
+    <add key="RazzBerrySetting" value="0.4" /> <!--Cp Mode: Use RazzBerry when Pokemon is over this value; pobability Mode: Use Razzberry when % between 0 and 1 of catching is under this value-->
     <add key="TransferType" value="duplicate" /> <!--none/cp/leaveStrongest/duplicate/all Whitelists/blackslists for each type is in Program.cs-->
     <add key="TransferCPThreshold" value="0" /> <!--transfer pokemon with CP less than this value if cp transfer type is selected. Whitelist in Program.cs-->
     <add key="EvolveAllGivenPokemons" value="false" />
diff --git a/PokemonGo/RocketAPI/Console/Program.cs b/PokemonGo/RocketAPI/Console/Program.cs
index 688b741..00727b2 100644
--- a/PokemonGo/RocketAPI/Console/Program.cs
+++ b/PokemonGo/RocketAPI/Console/Program.cs
@@ -26,11 +26,19 @@ namespace PokemonGo.RocketAPI.Console
 {
     internal class Program
     {
-        private static readonly ISettings ClientSettings = new Settings();
-        static int Currentlevel = -1;
+        private static ISettings ClientSettings = new Settings();
+        private static int Currentlevel = -1;
+        private static int TotalExperience = 0;
+        private static int TotalPokemon = 0;
+        private static DateTime TimeStarted = DateTime.Now;
+
+        public static double GetRuntime()
+        {
+            return ((DateTime.Now - TimeStarted).TotalSeconds) / 3600;
+        }

         public static void CheckVersion()
-        {
+        {
             try
             {
                 var match =
@@ -52,11 +60,8 @@ namespace PokemonGo.RocketAPI.Console
                     ColoredConsoleWrite(ConsoleColor.Yellow, "Awesome! You have already got the newest version! " + Assembly.GetExecutingAssembly().GetName().Version);
                     return;
                 }
-                ;

-                ColoredConsoleWrite(ConsoleColor.White, "There is a new Version available: " + gitVersion + " downloading.. ");
-                Thread.Sleep(1000);
-                Process.Start("");
+                ColoredConsoleWrite(ConsoleColor.White, "There is a new Version available: " + gitVersion);
             }
             catch (Exception)
             {
@@ -69,7 +74,7 @@ namespace PokemonGo.RocketAPI.Console
             using (var wC = new WebClient())
                 return
                     wC.DownloadString(
-                        "");
+                        "https://raw.githubusercontent.com/DetectiveSquirrel/PokemonGo-Bot/master/PokemonGo/RocketAPI/Console/Properties/AssemblyInfo.cs");
         }

         public static void ColoredConsoleWrite(ConsoleColor color, string text)
@@ -151,17 +156,16 @@ namespace PokemonGo.RocketAPI.Console
                         .Where(p => p != null && p?.PokemonId > 0);

                 ColoredConsoleWrite(ConsoleColor.Yellow, "----------------------------");
-                ColoredConsoleWrite(ConsoleColor.Cyan, "Account: " + ClientSettings.PtcUsername);
-                ColoredConsoleWrite(ConsoleColor.Cyan, "Password: " + ClientSettings.PtcPassword + "\n");
-                ColoredConsoleWrite(ConsoleColor.DarkGray, "Latitude: " + ClientSettings.DefaultLatitude);
-                ColoredConsoleWrite(ConsoleColor.DarkGray, "Longitude: " + ClientSettings.DefaultLongitude);
-                ColoredConsoleWrite(ConsoleColor.Yellow, "----------------------------");
-                ColoredConsoleWrite(ConsoleColor.DarkGray, "Your Account:\n");
+                if (ClientSettings.AuthType == AuthType.Ptc)
+                {
+                    ColoredConsoleWrite(ConsoleColor.Cyan, "Account: " + ClientSettings.PtcUsername);
+                    ColoredConsoleWrite(ConsoleColor.Cyan, "Password: " + ClientSettings.PtcPassword + "\n");
+                }
                 ColoredConsoleWrite(ConsoleColor.DarkGray, "Name: " + profile.Profile.Username);
                 ColoredConsoleWrite(ConsoleColor.DarkGray, "Team: " + profile.Profile.Team);
                 ColoredConsoleWrite(ConsoleColor.DarkGray, "Stardust: " + profile.Profile.Currency.ToArray()[1].Amount);
-
-                ColoredConsoleWrite(ConsoleColor.Cyan, "\nFarming Started");
+                ColoredConsoleWrite(ConsoleColor.DarkGray, "\nLatitude: " + ClientSettings.DefaultLatitude);
+                ColoredConsoleWrite(ConsoleColor.DarkGray, "Longitude: " + ClientSettings.DefaultLongitude);
                 ColoredConsoleWrite(ConsoleColor.Yellow, "----------------------------");
                 if (ClientSettings.TransferType == "leaveStrongest")
                     await TransferAllButStrongestUnwantedPokemon(client);
@@ -175,8 +179,8 @@ namespace PokemonGo.RocketAPI.Console
                     ColoredConsoleWrite(ConsoleColor.DarkGray, $"[{DateTime.Now.ToString("HH:mm:ss")}] Transfering pokemon disabled");
                 if (ClientSettings.EvolveAllGivenPokemons)
                     await EvolveAllGivenPokemons(client, pokemons);
-
-                client.RecycleItems(client);
+                if (ClientSettings.Recycler)
+                    client.RecycleItems(client);

                 await Task.Delay(5000);
                 PrintLevel(client);
@@ -186,12 +190,12 @@ namespace PokemonGo.RocketAPI.Console
                 await Task.Delay(10000);
                 Execute();
             }
-            catch (TaskCanceledException tce) { ColoredConsoleWrite(ConsoleColor.White, "Task Canceled Exception - Restarting"); Execute(); }
-            catch (UriFormatException ufe) { ColoredConsoleWrite(ConsoleColor.White, "System URI Format Exception - Restarting"); Execute(); }
-            catch (ArgumentOutOfRangeException aore) { ColoredConsoleWrite(ConsoleColor.White, "ArgumentOutOfRangeException - Restarting"); Execute(); }
-            catch (ArgumentNullException ane) { ColoredConsoleWrite(ConsoleColor.White, "Argument Null Refference - Restarting"); Execute(); }
-            catch (NullReferenceException nre) { ColoredConsoleWrite(ConsoleColor.White, "Null Refference - Restarting"); Execute(); }
-            //await ExecuteCatchAllNearbyPokemons(client);
+            catch (TaskCanceledException) { ColoredConsoleWrite(ConsoleColor.White, "Task Canceled Exception - Restarting"); Execute(); }
+            catch (UriFormatException) { ColoredConsoleWrite(ConsoleColor.White, "System URI Format Exception - Restarting"); Execute(); }
+            catch (ArgumentOutOfRangeException) { ColoredConsoleWrite(ConsoleColor.White, "ArgumentOutOfRangeException - Restarting"); Execute(); }
+            catch (ArgumentNullException) { ColoredConsoleWrite(ConsoleColor.White, "Argument Null Refference - Restarting"); Execute(); }
+            catch (NullReferenceException) { ColoredConsoleWrite(ConsoleColor.White, "Null Refference - Restarting"); Execute(); }
+            catch (Exception ex) { ColoredConsoleWrite(ConsoleColor.White, ex.ToString()); Execute(); }
         }

         private static async Task ExecuteCatchAllNearbyPokemons(Client client)
@@ -214,12 +218,15 @@ namespace PokemonGo.RocketAPI.Console
                 CatchPokemonResponse caughtPokemonResponse;
                 do
                 {
-                    caughtPokemonResponse =
-                        await
-                            client.CatchPokemon(pokemon.EncounterId, pokemon.SpawnpointId, pokemon.Latitude,
-                                pokemon.Longitude, MiscEnums.Item.ITEM_POKE_BALL, pokemonCP);
-                    ; //note: reverted from settings because this should not be part of settings but part of logic
-                } while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed);
+                    if (ClientSettings.RazzBerryMode == "cp")
+                        if (pokemonCP > ClientSettings.RazzBerrySetting)
+                            await client.UseRazzBerry(client, pokemon.EncounterId, pokemon.SpawnpointId);
+                    if (ClientSettings.RazzBerryMode == "probability")
+                        if (encounterPokemonResponse.CaptureProbability.CaptureProbability_.First() < ClientSettings.RazzBerrySetting)
+                            await client.UseRazzBerry(client, pokemon.EncounterId, pokemon.SpawnpointId);
+                    caughtPokemonResponse = await client.CatchPokemon(pokemon.EncounterId, pokemon.SpawnpointId, pokemon.Latitude, pokemon.Longitude, MiscEnums.Item.ITEM_POKE_BALL, pokemonCP); ; //note: reverted from settings because this should not be part of settings but part of logic
+                } while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
+
                 string pokemonName;
                 if (ClientSettings.Language == "german")
                 {
@@ -233,6 +240,9 @@ namespace PokemonGo.RocketAPI.Console
                 if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                 {
                     ColoredConsoleWrite(ConsoleColor.Green, $"[{DateTime.Now.ToString("HH:mm:ss")}] We caught a {pokemonName} with {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} CP");
+                    foreach (int xp in caughtPokemonResponse.Scores.Xp)
+                        TotalExperience += xp;
+                    TotalPokemon += 1;
                 }
                 else
                     ColoredConsoleWrite(ConsoleColor.Red, $"[{DateTime.Now.ToString("HH:mm:ss")}] {pokemonName} with {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} CP got away..");
@@ -262,9 +272,22 @@ namespace PokemonGo.RocketAPI.Console
                 var fortInfo = await client.GetFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);
                 var fortSearch = await client.SearchFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);

-                ColoredConsoleWrite(ConsoleColor.Cyan,
-                    $"[{DateTime.Now.ToString("HH:mm:ss")}] PokeStop XP: {fortSearch.ExperienceAwarded}, Gems: {fortSearch.GemsAwarded}, Eggs: {fortSearch.PokemonDataEgg} Items: {GetFriendlyItemsString(fortSearch.ItemsAwarded)}");
-
+                StringWriter PokeStopOutput = new StringWriter();
+                PokeStopOutput.Write($"[{DateTime.Now.ToString("HH:mm:ss")}] ");
+                if (fortInfo.Name != string.Empty)
+                    PokeStopOutput.Write("PokeStop: " + fortInfo.Name);
+                if (fortSearch.ExperienceAwarded != 0)
+                    PokeStopOutput.Write($", XP: {fortSearch.ExperienceAwarded}");
+                if (fortSearch.GemsAwarded != 0)
+                    PokeStopOutput.Write($", Gems: {fortSearch.GemsAwarded}");
+                if (fortSearch.PokemonDataEgg != null)
+                    PokeStopOutput.Write($", Eggs: {fortSearch.PokemonDataEgg}");
+                if (GetFriendlyItemsString(fortSearch.ItemsAwarded) != string.Empty)
+                    PokeStopOutput.Write($", Items: {GetFriendlyItemsString(fortSearch.ItemsAwarded)} ");
+                ColoredConsoleWrite(ConsoleColor.Cyan, PokeStopOutput.ToString());
+
+                if (fortSearch.ExperienceAwarded != 0)
+                    TotalExperience += (fortSearch.ExperienceAwarded);
                 await Task.Delay(15000);
                 await ExecuteCatchAllNearbyPokemons(client);
             }
@@ -277,10 +300,9 @@ namespace PokemonGo.RocketAPI.Console
             if (!enumerable.Any())
                 return string.Empty;

-            return
-                enumerable.GroupBy(i => i.ItemId)
-                    .Select(kvp => new { ItemName = kvp.Key.ToString(), Amount = kvp.Sum(x => x.ItemCount) })
-                    .Select(y => $"{y.Amount} x {y.ItemName}")
+            return enumerable.GroupBy(i => i.ItemId)
+                    .Select(kvp => new { ItemName = kvp.Key.ToString().Substring(4), Amount = kvp.Sum(x => x.ItemCount) })
+                    .Select(y => $"{y.Amount}x {y.ItemName}")
                     .Aggregate((a, b) => $"{a}, {b}");
         }

@@ -291,7 +313,7 @@ namespace PokemonGo.RocketAPI.Console
                 try
                 {
                     //ColoredConsoleWrite(ConsoleColor.White, "Coded by Ferox - edited by NecronomiconCoding");
-                    //CheckVersion();
+                    CheckVersion();
                     Execute();
                 }
                 catch (PtcOfflineException)
@@ -305,7 +327,7 @@ namespace PokemonGo.RocketAPI.Console
             });
             System.Console.ReadLine();
         }
-
+
         private static async Task TransferAllButStrongestUnwantedPokemon(Client client)
         {
             //ColoredConsoleWrite(ConsoleColor.White, $"[{DateTime.Now.ToString("HH:mm:ss")}] Firing up the meat grinder");
@@ -388,16 +410,26 @@ namespace PokemonGo.RocketAPI.Console
                         FAILED = 3;
                         ERROR_POKEMON_IS_EGG = 4;
                     }*/
-
+                    string pokemonName;
+                    if (ClientSettings.Language == "german")
+                    {
+                        ColoredConsoleWrite(ConsoleColor.DarkCyan, "german");
+                        string name_english = Convert.ToString(pokemon.PokemonId);
+                        var request = (HttpWebRequest)WebRequest.Create("http://boosting-service.de/pokemon/index.php?pokeName=" + name_english);
+                        var response = (HttpWebResponse)request.GetResponse();
+                        pokemonName = new StreamReader(response.GetResponseStream()).ReadToEnd();
+                    }
+                    else
+                        pokemonName = Convert.ToString(pokemon.PokemonId);
                     if (transferPokemonResponse.Status == 1)
                     {
-                        ColoredConsoleWrite(ConsoleColor.Magenta, $"[{DateTime.Now.ToString("HH:mm:ss")}] Transferred {pokemon.PokemonId} with {pokemon.Cp} CP");
+                        ColoredConsoleWrite(ConsoleColor.Magenta, $"[{DateTime.Now.ToString("HH:mm:ss")}] Transferred {pokemonName} with {pokemon.Cp} CP");
                     }
                     else
                     {
                         var status = transferPokemonResponse.Status;

-                        ColoredConsoleWrite(ConsoleColor.Red, $"[{DateTime.Now.ToString("HH:mm:ss")}] Somehow failed to transfer {pokemon.PokemonId} with {pokemon.Cp} CP. " +
+                        ColoredConsoleWrite(ConsoleColor.Red, $"[{DateTime.Now.ToString("HH:mm:ss")}] Somehow failed to transfer {pokemonName} with {pokemon.Cp} CP. " +
                                                  $"ReleasePokemonOutProto.Status was {status}");
                     }

@@ -427,8 +459,18 @@ namespace PokemonGo.RocketAPI.Console
                     if (dubpokemon.Favorite == 0)
                     {
                         var transfer = await client.TransferPokemon(dubpokemon.Id);
+                        string pokemonName;
+                        if (ClientSettings.Language == "german")
+                        {
+                            string name_english = Convert.ToString(dubpokemon.PokemonId);
+                            var request = (HttpWebRequest)WebRequest.Create("http://boosting-service.de/pokemon/index.php?pokeName=" + name_english);
+                            var response = (HttpWebResponse)request.GetResponse();
+                            pokemonName = new StreamReader(response.GetResponseStream()).ReadToEnd();
+                        }
+                        else
+                            pokemonName = Convert.ToString(dubpokemon.PokemonId);
                         ColoredConsoleWrite(ConsoleColor.DarkGreen,
-                            $"[{DateTime.Now.ToString("HH:mm:ss")}] Transferred {dubpokemon.PokemonId} with {dubpokemon.Cp} CP (Highest is {dupes.ElementAt(i).Last().value.Cp})");
+                            $"[{DateTime.Now.ToString("HH:mm:ss")}] Transferred {pokemonName} with {dubpokemon.Cp} CP (Highest is {dupes.ElementAt(i).Last().value.Cp})");

                     }
                 }
@@ -439,8 +481,8 @@ namespace PokemonGo.RocketAPI.Console
         {
             //ColoredConsoleWrite(ConsoleColor.White, $"[{DateTime.Now.ToString("HH:mm:ss")}] Firing up the meat grinder");

-            var doNotTransfer = new[] //these will not be transferred even when below the CP threshold
-            {
+            PokemonId[] doNotTransfer = new[] //these will not be transferred even when below the CP threshold
+            { // DO NOT EMPTY THIS ARRAY
                 //PokemonId.Pidgey,
                 //PokemonId.Rattata,
                 //PokemonId.Weedle,
@@ -470,9 +512,12 @@ namespace PokemonGo.RocketAPI.Console

             //foreach (var unwantedPokemonType in unwantedPokemonTypes)
             {
-                var pokemonToDiscard = pokemons.Where(p => !doNotTransfer.Contains(p.PokemonId) && p.Cp < cpThreshold)
-                                                   .OrderByDescending(p => p.Cp)
-                                                   .ToList();
+                List<PokemonData> pokemonToDiscard;
+                if (doNotTransfer.Count() != 0)
+                    pokemonToDiscard = pokemons.Where(p => !doNotTransfer.Contains(p.PokemonId) && p.Cp < cpThreshold).OrderByDescending(p => p.Cp).ToList();
+                else
+                    pokemonToDiscard = pokemons.Where(p => p.Cp < cpThreshold).OrderByDescending(p => p.Cp).ToList();
+

                 //var unwantedPokemon = pokemonOfDesiredType.Skip(1) // keep the strongest one for potential battle-evolving
                 //                                          .ToList();
@@ -501,8 +546,10 @@ namespace PokemonGo.RocketAPI.Console
                             ColoredConsoleWrite(ConsoleColor.Magenta, $"[{DateTime.Now.ToString("HH:mm:ss")}] Current Level: " + v.Level + ". XP needed for next Level: " + (v.NextLevelXp - v.Experience));
                         }
                 }
-
-            await Task.Delay(ClientSettings.LevelTimeInterval * 1000);
+            if (ClientSettings.LevelOutput == "levelup")
+                await Task.Delay(1000);
+            else
+                await Task.Delay(ClientSettings.LevelTimeInterval * 1000);
             PrintLevel(client);
         }

@@ -515,7 +562,7 @@ namespace PokemonGo.RocketAPI.Console
                 if (v != null)
                 {
                     int XpDiff = GetXpDiff(client, v.Level);
-                    System.Console.Title = string.Format(Username + " | Level {0:0} - ({1:0} / {2:0}) | Stardust {3:0}", v.Level, (v.Experience - v.PrevLevelXp - XpDiff), (v.NextLevelXp - v.PrevLevelXp - XpDiff), profile.Profile.Currency.ToArray()[1].Amount);
+                    System.Console.Title = string.Format(Username + " | Level: {0:0} - ({1:0} / {2:0}) | Stardust: {3:0}", v.Level, (v.Experience - v.PrevLevelXp - XpDiff), (v.NextLevelXp - v.PrevLevelXp - XpDiff), profile.Profile.Currency.ToArray()[1].Amount) + " | XP/Hour: " + Math.Round(TotalExperience / GetRuntime()) + " | Pokemon/Hour: " + Math.Round(TotalPokemon / GetRuntime());
                 }
             await Task.Delay(1000);
             ConsoleLevelTitle(Username, client);
diff --git a/PokemonGo/RocketAPI/Console/Settings.cs b/PokemonGo/RocketAPI/Console/Settings.cs
index e540c7b..25f86b8 100644
--- a/PokemonGo/RocketAPI/Console/Settings.cs
+++ b/PokemonGo/RocketAPI/Console/Settings.cs
@@ -26,19 +26,26 @@ namespace PokemonGo.RocketAPI.Console
         public string PtcUsername => GetSetting() != string.Empty ? GetSetting() : "username";
         public string PtcPassword => GetSetting() != string.Empty ? GetSetting() : "password";

-        public double DefaultLatitude => GetSetting() != string.Empty ? double.Parse(GetSetting(), CultureInfo.InvariantCulture) : 51.22640;
+        public double DefaultLatitude
+        {
+            get { return GetSetting() != string.Empty ? double.Parse(GetSetting(), CultureInfo.InvariantCulture) : 51.22640; }
+            set { SetSetting(value); }
+        }

-        //Default Amsterdam Central Station if another location is not specified
-        public double DefaultLongitude => GetSetting() != string.Empty ? double.Parse(GetSetting(), CultureInfo.InvariantCulture) : 6.77874;

-        //Default Amsterdam Central Station if another location is not specified
+        public double DefaultLongitude
+        {
+            get { return GetSetting() != string.Empty ? double.Parse(GetSetting(), CultureInfo.InvariantCulture) : 6.77874; }
+            set { SetSetting(value); }
+        }

-        // LEAVE EVERYTHING ALONE

         public string LevelOutput => GetSetting() != string.Empty ? GetSetting() : "time";

         public int LevelTimeInterval => GetSetting() != string.Empty ? System.Convert.ToInt16(GetSetting()) : 600;

+        public bool Recycler => GetSetting() != string.Empty ? System.Convert.ToBoolean(GetSetting(), CultureInfo.InvariantCulture) : false;
+
         ICollection<KeyValuePair<ItemId, int>> ISettings.ItemRecycleFilter
         {
             get
@@ -57,17 +64,16 @@ namespace PokemonGo.RocketAPI.Console
                     new KeyValuePair<ItemId, int>(ItemId.ItemHyperPotion, 50)
                 };
             }
-
-            set
-            {
-                throw new NotImplementedException();
-            }
         }

         public int RecycleItemsInterval => GetSetting() != string.Empty ? Convert.ToInt16(GetSetting()) : 60;

         public string Language => GetSetting() != string.Empty ? GetSetting() : "english";

+        public string RazzBerryMode => GetSetting() != string.Empty ? GetSetting() : "cp";
+
+        public double RazzBerrySetting => GetSetting() != string.Empty ? double.Parse(GetSetting(), CultureInfo.InvariantCulture) : 500;
+
         public string GoogleRefreshToken
         {
             get { return GetSetting() != string.Empty ? GetSetting() : string.Empty; }
@@ -85,5 +91,15 @@ namespace PokemonGo.RocketAPI.Console
             if (key != null) configFile.AppSettings.Settings[key].Value = value;
             configFile.Save();
         }
+
+        private void SetSetting(double value, [CallerMemberName] string key = null)
+        {
+            CultureInfo customCulture = (CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
+            customCulture.NumberFormat.NumberDecimalSeparator = ".";
+            System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;
+            var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+            if (key != null) configFile.AppSettings.Settings[key].Value = value.ToString();
+            configFile.Save();
+        }
     }
 }
diff --git a/PokemonGo/RocketAPI/ISettings.cs b/PokemonGo/RocketAPI/ISettings.cs
index d6a58e9..20d4692 100644
--- a/PokemonGo/RocketAPI/ISettings.cs
+++ b/PokemonGo/RocketAPI/ISettings.cs
@@ -10,8 +10,8 @@ namespace PokemonGo.RocketAPI
     public interface ISettings
     {
         AuthType AuthType { get; }
-        double DefaultLatitude { get; }
-        double DefaultLongitude { get; }
+        double DefaultLatitude { get; set; }
+        double DefaultLongitude { get; set; }
         string LevelOutput { get; }
         int LevelTimeInterval { get; }
         string GoogleRefreshToken { get; set; }
@@ -20,8 +20,11 @@ namespace PokemonGo.RocketAPI
         bool EvolveAllGivenPokemons { get; }
         string TransferType { get; }
         int TransferCPThreshold { get; }
-        ICollection<KeyValuePair<AllEnum.ItemId, int>> ItemRecycleFilter { get; set; }
+        bool Recycler { get; }
+        ICollection<KeyValuePair<AllEnum.ItemId, int>> ItemRecycleFilter { get; }
         int RecycleItemsInterval { get; }
         string Language { get; }
+        string RazzBerryMode { get; }
+        double RazzBerrySetting { get; }
     }
 }
diff --git a/PokemonGo/RocketAPI/Login/GoogleLogin.cs b/PokemonGo/RocketAPI/Login/GoogleLogin.cs
index 17dbb0c..aba7fe5 100644
--- a/PokemonGo/RocketAPI/Login/GoogleLogin.cs
+++ b/PokemonGo/RocketAPI/Login/GoogleLogin.cs
@@ -16,9 +16,8 @@ namespace PokemonGo.RocketAPI.Login
         private const string ClientId = "848232511240-73ri3t7plvk96pj4f85uj8otdat2alem.apps.googleusercontent.com";
         private const string ClientSecret = "NCjF1TLi2CcY6t5mt0ZveuL7";

-        internal static async Task<TokenResponseModel> GetAccessToken()
+        internal static async Task<TokenResponseModel> GetAccessToken(DeviceCodeModel deviceCodeResponse)
         {
-            var deviceCodeResponse = await GetDeviceCode();
             Console.WriteLine("Please visit " + deviceCodeResponse.verification_url + " and enter " +
                               deviceCodeResponse.user_code);

@@ -43,11 +42,24 @@ namespace PokemonGo.RocketAPI.Login
                 new KeyValuePair<string, string>("scope", "openid email https://www.googleapis.com/auth/userinfo.email"));
         }

-        private static async Task<DeviceCodeModel> GetDeviceCode()
+        /*public static async Task<TokenResponseModel> GetAccessToken(DeviceCodeModel deviceCode)
         {
-            return await HttpClientHelper.PostFormEncodedAsync<DeviceCodeModel>(OauthEndpoint,
+            TokenResponseModel tokenResponse;
+            do
+            {
+                await Task.Delay(2000);
+                tokenResponse = await PollSubmittedToken(deviceCode.device_code);
+            } while (tokenResponse.access_token == null || tokenResponse.refresh_token == null);
+
+            return tokenResponse;
+        }*/
+
+        public static async Task<DeviceCodeModel> GetDeviceCode()
+        {
+            var deviceCode = await HttpClientHelper.PostFormEncodedAsync<DeviceCodeModel>(OauthEndpoint,
                 new KeyValuePair<string, string>("client_id", ClientId),
                 new KeyValuePair<string, string>("scope", "openid email https://www.googleapis.com/auth/userinfo.email"));
+            return deviceCode;
         }

         private static async Task<TokenResponseModel> PollSubmittedToken(string deviceCode)
diff --git a/README.md b/README.md
index e73aff9..1fab250 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,80 @@
 # Pokemon-Go-Rocket-API
-![alt tag](https://github.com/DetectiveSquirrel/Pokemon-Go-Rocket-API/blob/master/screenshot.jpg)
+![alt tag](https://github.com/DetectiveSquirrel/PokemonGo-Bot/blob/master/screenshot.jpg)

 A Pokemon Go bot in C#

 ## Features
-* PTC Login / Google
+* PTC / Google Login
 * Get Map Objects and Inventory
-* Search for gyms/pokestops/spawns
-* Farm pokestops
-* Farm all pokemons in neighbourhood
-* Evolve pokemons
-* Transfer pokemons
-* Auto recycle not needed items
+* Search for Gyms / Pokéstops / Spawns
+* Farm Pokéstops
+* Farm all Pokémon in the neighbourhood
+* Evolve Pokémon
+* Transfer Pokémon
+* Auto-Recycle uneeded items
 * Output level and needed XP for levelup
+* Output Username, Level, Stardust, XP/hour, Pokemon/hour in Console Title
+* German/English pokemon names
+* Automatic use of Razzberries
+* Automatic Update checker

 ## Getting Started

 Go to PokemonGo\RocketAPI\Console\App.config -> Edit the Settings you like -> Build and Run (CTRL+F5)

-## Transfer Types
+# Settings
+## AuthType
+* *Google* - Google login via oauth2
+* *Ptc* - Pokemon Trainer Club login with username/password combination

-The most popular option is probably the duplicate type that removes all duplicates and leaves you one pokemon of each type with the highest CP.
+## PtcUsername
+* *username* for PTC account. No need for when using Google.
+* *password* for PTC account. No need for when using Google.

-* none - disables transferring
-* cp - transfers all pokemon below the CP threshold in the app.config, EXCEPT for those types specified in program.cs in TransferAllWeakPokemon
-* leaveStrongest - transfers all but the highest CP pokemon of each type SPECIFIED IN program.cs in TransferAllButStrongestUnwantedPokemon (those that aren't specified are untouched)
-* duplicate - same as above but for all pokemon (no need to specify type), (will not transfer favorited pokemon)
-* all - transfers all pokemon
+## GoogleRefreshToken
+* *GoogleRefreshToken* - You get this code when you connect the application with your Google account. You do not need to enter it.
+
+## DefaultLatitude
+* *12.345678* - Latitude of your location you want to use the bot in. Number between -90 and +90. Doesn't matter how many numbers stand after the comma.
+
+## DefaultLongitude
+* *123.456789* - Longitude of your location you want to use the bot in. Number between -180 and +180. Doesn't matter how many numbers stand after the comma.
+
+## LevelOutput
+* *time* - Every X amount of time it prints the current level and experience needed for the next level.
+* *levelup* - Only outputs the level and needed experience for next level on levelup.
+
+## LevelTimeInterval
+* *seconds* - After X seconds it will print the current level and experience needed for levelup when using *time* mode.
+
+## Recycler
+* *false* Recycler not active.
+* *true* Recycler active.
+
+## RecycleItemsInterval
+* *seconds* After X seconds it recycles items from the filter in *Settings.cs*.
+
+## Language
+* *english* Outputs caught pokemons in english name.
+* *german*  Outputs caught pokemons in german name.
+
+## RazzBerryMode
+* *cp* - Use RazzBerry when Pokemon is over specific CP.
+* *probability* - Use RazzBerry when Pokemon catch chance is under a specific percentage.
+
+## RazzBerrySetting
+* *value* CP: Use RazzBerry when Pokemon is over this value | Probability Mode: Use Razzberry when % of catching is under this value
+
+## TransferType
+* *none* - disables transferring
+* *cp* - transfers all pokemon below the CP threshold in the app.config, EXCEPT for those types specified in program.cs in TransferAllWeakPokemon
+* *leaveStrongest* - transfers all but the highest CP pokemon of each type SPECIFIED IN program.cs in TransferAllButStrongestUnwantedPokemon (those that aren't specified are untouched)
+* *duplicate* - same as above but for all pokemon (no need to specify type), (will not transfer favorited pokemon)
+* *all* - transfers all pokemon
+
+## TransferCPThreshold
+* *CP* transfers all pokemons with less CP than this value.
+
+## EvolveAllGivenPokemons
+* *false* Evolves no pokemons.
+* *true* Evolves all pokemoms.
diff --git a/screenshot.jpg b/screenshot.jpg
index a11f343..b4d0a44 100644
Binary files a/screenshot.jpg and b/screenshot.jpg differ
You may download the files in Public Git.