Update to the last commits from https://github.com/FeroxRev/Pokemon-Go-Rocket-API

Spegeli [2016-07-22 06:51:39]
Update to the last commits from https://github.com/FeroxRev/Pokemon-Go-Rocket-API
Filename
PokemonGo.RocketAPI.Console/App.config
PokemonGo.RocketAPI.Console/Program.cs
PokemonGo.RocketAPI.Console/Settings.cs
PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
PokemonGo.RocketAPI.Console/UserSettings.settings
PokemonGo.RocketAPI.Logic/Inventory.cs
PokemonGo.RocketAPI.Logic/Logic.cs
PokemonGo.RocketAPI.Logic/Navigation.cs
PokemonGo.RocketAPI/Client.cs
PokemonGo.RocketAPI/ISettings.cs
PokemonGo.RocketAPI/Login/GoogleLogin.cs
PokemonGo.RocketAPI/Login/PtcLogin.cs
PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj
diff --git a/PokemonGo.RocketAPI.Console/App.config b/PokemonGo.RocketAPI.Console/App.config
index 1b3985e..f10befb 100644
--- a/PokemonGo.RocketAPI.Console/App.config
+++ b/PokemonGo.RocketAPI.Console/App.config
@@ -19,21 +19,27 @@
   </runtime>
   <userSettings>
     <PokemonGo.RocketAPI.Console.UserSettings>
-        <setting name="AuthType" serializeAs="String">
-            <value>Google</value>
-        </setting>
-        <setting name="PtcUsername" serializeAs="String">
-            <value>username</value>
-        </setting>
-        <setting name="PtcPassword" serializeAs="String">
-            <value>password</value>
-        </setting>
-        <setting name="DefaultLatitude" serializeAs="String">
-            <value>0</value>
-        </setting>
-        <setting name="DefaultLongitude" serializeAs="String">
-            <value>0</value>
-        </setting>
+      <setting name="AuthType" serializeAs="String">
+        <value>Google</value>
+      </setting>
+      <setting name="PtcUsername" serializeAs="String">
+        <value>username</value>
+      </setting>
+      <setting name="GoogleRefreshToken" serializeAs="String">
+        <value />
+      </setting>
+      <setting name="DefaultAltitude" serializeAs="String">
+        <value>10</value>
+      </setting>
+      <setting name="PtcPassword" serializeAs="String">
+        <value>password</value>
+      </setting>
+      <setting name="DefaultLatitude" serializeAs="String">
+        <value>0</value>
+      </setting>
+      <setting name="DefaultLongitude" serializeAs="String">
+        <value>0</value>
+      </setting>
     </PokemonGo.RocketAPI.Console.UserSettings>
   </userSettings>
 </configuration>
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Console/Program.cs b/PokemonGo.RocketAPI.Console/Program.cs
index 50d7711..2d8bf93 100644
--- a/PokemonGo.RocketAPI.Console/Program.cs
+++ b/PokemonGo.RocketAPI.Console/Program.cs
@@ -30,7 +30,7 @@ namespace PokemonGo.RocketAPI.Console
             {
                 try
                 {
-                    new Logic.Logic(new Settings()).Execute();
+                    new Logic.Logic(new Settings()).Execute().Wait();
                 }
                 catch (PtcOfflineException)
                 {
diff --git a/PokemonGo.RocketAPI.Console/Settings.cs b/PokemonGo.RocketAPI.Console/Settings.cs
index 236daa4..d139ba9 100644
--- a/PokemonGo.RocketAPI.Console/Settings.cs
+++ b/PokemonGo.RocketAPI.Console/Settings.cs
@@ -1,54 +1,84 @@
-using System.Configuration;
-using PokemonGo.RocketAPI.Enums;
-using PokemonGo.RocketAPI.GeneratedCode;
-using System;
-using System.Globalization;
-using System.Runtime.CompilerServices;
-using System.Collections.Generic;
-using AllEnum;
-
-namespace PokemonGo.RocketAPI.Console
-{
-    public class Settings : ISettings
-    {
-        public AuthType AuthType => (AuthType)Enum.Parse(typeof(AuthType), UserSettings.Default.AuthType);
-        public string PtcUsername => UserSettings.Default.PtcUsername;
-        public string PtcPassword => UserSettings.Default.PtcPassword;
-        public double DefaultLatitude => UserSettings.Default.DefaultLatitude;
-        public double DefaultLongitude => UserSettings.Default.DefaultLongitude;
-
-        ICollection<KeyValuePair<ItemId, int>> ISettings.itemRecycleFilter
-        {
-            get
-            {
-                //Items to Recylce but keep X amount
-                return new[]
-                {
-                    new KeyValuePair<ItemId, int>(ItemId.ItemPokeBall, 150),
-                    new KeyValuePair<ItemId, int>(ItemId.ItemPotion, 5),
-                    new KeyValuePair<ItemId, int>(ItemId.ItemSuperPotion, 5),
-                    new KeyValuePair<ItemId, int>(ItemId.ItemHyperPotion, 5),
-                    new KeyValuePair<ItemId, int>(ItemId.ItemMaxPotion, 5),
-                    new KeyValuePair<ItemId, int>(ItemId.ItemRevive, 5),
-                    new KeyValuePair<ItemId, int>(ItemId.ItemMaxRevive, 5),
-                    new KeyValuePair<ItemId, int>(ItemId.ItemRazzBerry, 5)
-                };
-            }
-
-            set
-            {
-                throw new NotImplementedException();
-            }
-        }
-
-        public string GoogleRefreshToken
-        {
-            get { return UserSettings.Default.GoogleRefreshToken; }
-            set
-            {
-                UserSettings.Default.GoogleRefreshToken = value;
-                UserSettings.Default.Save();
-            }
-        }
-    }
-}
+using System.Configuration;
+using PokemonGo.RocketAPI.Enums;
+using PokemonGo.RocketAPI.GeneratedCode;
+using System;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+using AllEnum;
+
+namespace PokemonGo.RocketAPI.Console
+{
+    public class Settings : ISettings
+    {
+        public AuthType AuthType => (AuthType)Enum.Parse(typeof(AuthType), UserSettings.Default.AuthType);
+        public string PtcUsername => UserSettings.Default.PtcUsername;
+        public string PtcPassword => UserSettings.Default.PtcPassword;
+        public double DefaultLatitude => UserSettings.Default.DefaultLatitude;
+        public double DefaultLongitude => UserSettings.Default.DefaultLongitude;
+        public double DefaultAltitude => UserSettings.Default.DefaultAltitude;
+
+        ICollection<KeyValuePair<ItemId, int>> ISettings.itemRecycleFilter
+        {
+            get
+            {
+                //Items to Recylce but keep X amount
+                return new[]
+                {
+                    new KeyValuePair<ItemId, int>(ItemId.ItemUnknown, 0),
+                    new KeyValuePair<ItemId, int>(ItemId.ItemPokeBall, 20),
+                    new KeyValuePair<ItemId, int>(ItemId.ItemGreatBall, 20),
+                    new KeyValuePair<ItemId, int>(ItemId.ItemUltraBall, 50),
+                    new KeyValuePair<ItemId, int>(ItemId.ItemMasterBall, 100),
+
+                    new KeyValuePair<ItemId, int>(ItemId.ItemPotion, 0),
+                    new KeyValuePair<ItemId, int>(ItemId.ItemSuperPotion, 0),
+                    new KeyValuePair<ItemId, int>(ItemId.ItemHyperPotion, 20),
+                    new KeyValuePair<ItemId, int>(ItemId.ItemMaxPotion, 50),
+
+                    new KeyValuePair<ItemId, int>(ItemId.ItemRevive, 10),
+                    new KeyValuePair<ItemId, int>(ItemId.ItemMaxRevive, 50),
+
+                     new KeyValuePair<ItemId, int>(ItemId.ItemLuckyEgg, 200),
+
+                     new KeyValuePair<ItemId, int>(ItemId.ItemIncenseOrdinary, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemIncenseSpicy, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemIncenseCool, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemIncenseFloral, 100),
+
+                     new KeyValuePair<ItemId, int>(ItemId.ItemTroyDisk, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemXAttack, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemXDefense, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemXMiracle, 100),
+
+                     new KeyValuePair<ItemId, int>(ItemId.ItemRazzBerry, 20),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemBlukBerry, 10),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemNanabBerry, 10),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemWeparBerry, 30),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemPinapBerry, 30),
+
+                     new KeyValuePair<ItemId, int>(ItemId.ItemSpecialCamera, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemIncubatorBasicUnlimited, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemIncubatorBasic, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemPokemonStorageUpgrade, 100),
+                     new KeyValuePair<ItemId, int>(ItemId.ItemItemStorageUpgrade, 100),
+                };
+            }
+
+            set
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        public string GoogleRefreshToken
+        {
+            get { return UserSettings.Default.GoogleRefreshToken; }
+            set
+            {
+                UserSettings.Default.GoogleRefreshToken = value;
+                UserSettings.Default.Save();
+            }
+        }
+    }
+}
diff --git a/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs b/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
index edbe42a..14a6bc4 100644
--- a/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
+++ b/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
@@ -25,43 +25,55 @@ namespace PokemonGo.RocketAPI.Console {

         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("")]
-        public string GoogleRefreshToken {
+        [global::System.Configuration.DefaultSettingValueAttribute("Google")]
+        public string AuthType {
             get {
-                return ((string)(this["GoogleRefreshToken"]));
+                return ((string)(this["AuthType"]));
             }
             set {
-                this["GoogleRefreshToken"] = value;
+                this["AuthType"] = value;
             }
         }

         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("Ptc")]
-        public string AuthType {
+        [global::System.Configuration.DefaultSettingValueAttribute("username")]
+        public string PtcUsername {
             get {
-                return ((string)(this["AuthType"]));
+                return ((string)(this["PtcUsername"]));
             }
             set {
-                this["AuthType"] = value;
+                this["PtcUsername"] = value;
             }
         }

         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("Jarolon")]
-        public string PtcUsername {
+        [global::System.Configuration.DefaultSettingValueAttribute("")]
+        public string GoogleRefreshToken {
             get {
-                return ((string)(this["PtcUsername"]));
+                return ((string)(this["GoogleRefreshToken"]));
             }
             set {
-                this["PtcUsername"] = value;
+                this["GoogleRefreshToken"] = value;
+            }
+        }
+
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("10")]
+        public double DefaultAltitude {
+            get {
+                return ((double)(this["DefaultAltitude"]));
+            }
+            set {
+                this["DefaultAltitude"] = value;
             }
         }

         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("5dfM56Rh")]
+        [global::System.Configuration.DefaultSettingValueAttribute("password")]
         public string PtcPassword {
             get {
                 return ((string)(this["PtcPassword"]));
@@ -73,7 +85,7 @@ namespace PokemonGo.RocketAPI.Console {

         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("48.78")]
+        [global::System.Configuration.DefaultSettingValueAttribute("0")]
         public double DefaultLatitude {
             get {
                 return ((double)(this["DefaultLatitude"]));
@@ -85,7 +97,7 @@ namespace PokemonGo.RocketAPI.Console {

         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("9.18274")]
+        [global::System.Configuration.DefaultSettingValueAttribute("0")]
         public double DefaultLongitude {
             get {
                 return ((double)(this["DefaultLongitude"]));
diff --git a/PokemonGo.RocketAPI.Console/UserSettings.settings b/PokemonGo.RocketAPI.Console/UserSettings.settings
index c7066da..7beb694 100644
--- a/PokemonGo.RocketAPI.Console/UserSettings.settings
+++ b/PokemonGo.RocketAPI.Console/UserSettings.settings
@@ -2,23 +2,26 @@
 <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="PokemonGo.RocketAPI.Console" GeneratedClassName="UserSettings">
   <Profiles />
   <Settings>
-    <Setting Name="GoogleRefreshToken" Type="System.String" Scope="User">
-      <Value Profile="(Default)" />
-    </Setting>
     <Setting Name="AuthType" Type="System.String" Scope="User">
-      <Value Profile="(Default)">Ptc</Value>
+      <Value Profile="(Default)">Google</Value>
     </Setting>
     <Setting Name="PtcUsername" Type="System.String" Scope="User">
-      <Value Profile="(Default)">Jarolon</Value>
+      <Value Profile="(Default)">username</Value>
+    </Setting>
+    <Setting Name="GoogleRefreshToken" Type="System.String" Scope="User">
+      <Value Profile="(Default)" />
+    </Setting>
+    <Setting Name="DefaultAltitude" Type="System.Double" Scope="User">
+      <Value Profile="(Default)">10</Value>
     </Setting>
     <Setting Name="PtcPassword" Type="System.String" Scope="User">
-      <Value Profile="(Default)">5dfM56Rh</Value>
+      <Value Profile="(Default)">password</Value>
     </Setting>
     <Setting Name="DefaultLatitude" Type="System.Double" Scope="User">
-      <Value Profile="(Default)">48.78</Value>
+      <Value Profile="(Default)">0</Value>
     </Setting>
     <Setting Name="DefaultLongitude" Type="System.Double" Scope="User">
-      <Value Profile="(Default)">9.18274</Value>
+      <Value Profile="(Default)">0</Value>
     </Setting>
   </Settings>
 </SettingsFile>
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Logic/Inventory.cs b/PokemonGo.RocketAPI.Logic/Inventory.cs
index a8cbf1f..93cf8b9 100644
--- a/PokemonGo.RocketAPI.Logic/Inventory.cs
+++ b/PokemonGo.RocketAPI.Logic/Inventory.cs
@@ -37,35 +37,34 @@ namespace PokemonGo.RocketAPI.Logic
             return
                 templates.ItemTemplates.Select(i => i.PokemonSettings)
                     .Where(p => p != null && p?.FamilyId != PokemonFamilyId.FamilyUnset);
-        }
-
+        }

         public async Task<IEnumerable<PokemonData>> GetDuplicatePokemonToTransfer(bool keepPokemonsThatCanEvolve = false)
         {
             var myPokemon = await GetPokemons();

-            var pokemonList = myPokemon as IList<PokemonData> ?? myPokemon.ToList();
+            var pokemonList = myPokemon.Where(p => p.DeployedFortId == 0).ToList(); //Don't evolve pokemon in gyms
             if (keepPokemonsThatCanEvolve)
             {
                 var results = new List<PokemonData>();
                 var pokemonsThatCanBeTransfered = pokemonList.GroupBy(p => p.PokemonId)
-                    .Where(x => x.Count() > 1).ToList();
+                    .Where(x => x.Count() > 2).ToList();

                 var myPokemonSettings = await GetPokemonSettings();
-                var pokemonSettings = myPokemonSettings as IList<PokemonSettings> ?? myPokemonSettings.ToList();
+                var pokemonSettings = myPokemonSettings.ToList();

                 var myPokemonFamilies = await GetPokemonFamilies();
-                var pokemonFamilies = myPokemonFamilies as PokemonFamily[] ?? myPokemonFamilies.ToArray();
+                var pokemonFamilies = myPokemonFamilies.ToArray();

                 foreach (var pokemon in pokemonsThatCanBeTransfered)
                 {
                     var settings = pokemonSettings.Single(x => x.PokemonId == pokemon.Key);
                     var familyCandy = pokemonFamilies.Single(x => settings.FamilyId == x.FamilyId);
-                    var amountToSkip = (familyCandy.Candy + settings.CandyToEvolve - 1)/settings.CandyToEvolve;
-
-                    if (settings.EvolutionIds.Count == 0)
+                    if (settings.CandyToEvolve == 0)
                         continue;

+                    var amountToSkip = (familyCandy.Candy + settings.CandyToEvolve - 1) / settings.CandyToEvolve + 2;
+
                     results.AddRange(pokemonList.Where(x => x.PokemonId == pokemon.Key && x.Favorite == 0)
                         .OrderByDescending(x => x.Cp)
                         .ThenBy(n => n.StaminaMax)
@@ -76,13 +75,42 @@ namespace PokemonGo.RocketAPI.Logic

                 return results;
             }
-
+
             return pokemonList
                 .GroupBy(p => p.PokemonId)
                 .Where(x => x.Count() > 1)
                 .SelectMany(p => p.Where(x => x.Favorite == 0).OrderByDescending(x => x.Cp).ThenBy(n => n.StaminaMax).Skip(1).ToList());
         }

+        public async Task<IEnumerable<PokemonData>> GetPokemonToEvolve()
+        {
+            var myPokemons = await GetPokemons();
+            var pokemons = myPokemons.Where(p => p.DeployedFortId == 0).ToList(); //Don't evolve pokemon in gyms
+
+            var myPokemonSettings = await GetPokemonSettings();
+            var pokemonSettings = myPokemonSettings.ToList();
+
+            var myPokemonFamilies = await GetPokemonFamilies();
+            var pokemonFamilies = myPokemonFamilies.ToArray();
+
+            var pokemonToEvolve = new List<PokemonData>();
+            foreach (var pokemon in pokemons)
+            {
+                var settings = pokemonSettings.Single(x => x.PokemonId == pokemon.PokemonId);
+                var familyCandy = pokemonFamilies.Single(x => settings.FamilyId == x.FamilyId);
+
+                //Don't evolve if we can't evolve it
+                if (settings.EvolutionIds.Count == 0)
+                    continue;
+
+                var pokemonCandyNeededAlready = pokemonToEvolve.Count(p => pokemonSettings.Single(x => x.PokemonId == p.PokemonId).FamilyId == settings.FamilyId) * settings.CandyToEvolve;
+                if (familyCandy.Candy - pokemonCandyNeededAlready > settings.CandyToEvolve)
+                    pokemonToEvolve.Add(pokemon);
+            }
+
+            return pokemonToEvolve;
+        }
+
         public async Task<IEnumerable<Item>> GetItems()
         {
             var inventory = await _client.GetInventory();
diff --git a/PokemonGo.RocketAPI.Logic/Logic.cs b/PokemonGo.RocketAPI.Logic/Logic.cs
index 71f0afe..50dc64e 100644
--- a/PokemonGo.RocketAPI.Logic/Logic.cs
+++ b/PokemonGo.RocketAPI.Logic/Logic.cs
@@ -1,10 +1,12 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Reflection.Emit;
 using System.Text;
 using System.Threading.Tasks;
 using AllEnum;
 using PokemonGo.RocketAPI.Enums;
+using PokemonGo.RocketAPI.Exceptions;
 using PokemonGo.RocketAPI.Extensions;
 using PokemonGo.RocketAPI.GeneratedCode;
 using PokemonGo.RocketAPI.Logic.Utils;
@@ -27,7 +29,7 @@ namespace PokemonGo.RocketAPI.Logic
             _stats = new Statistics();
         }

-        public async void Execute()
+        public async Task Execute()
         {
             CheckAndDownloadVersion.CheckVersion();

@@ -40,11 +42,27 @@ namespace PokemonGo.RocketAPI.Logic
             }

             Logger.Normal(ConsoleColor.DarkGreen, $"Starting Execute on login server: {_clientSettings.AuthType}");
+            while (true)
+            {
+                try
+                {
+                    if (_clientSettings.AuthType == AuthType.Ptc)
+                        await _client.DoPtcLogin(_clientSettings.PtcUsername, _clientSettings.PtcPassword);
+                    else if (_clientSettings.AuthType == AuthType.Google)
+                        await _client.DoGoogleLogin();
+
+                    await PostLoginExecute();
+                }
+                catch (AccessTokenExpiredException)
+                {
+                    Logger.Error($"Access token expired");
+                }
+                await Task.Delay(10000);
+            }
+        }

-            if (_clientSettings.AuthType == AuthType.Ptc)
-                await _client.DoPtcLogin(_clientSettings.PtcUsername, _clientSettings.PtcPassword);
-            else if (_clientSettings.AuthType == AuthType.Google)
-                await _client.DoGoogleLogin();
+        public async Task PostLoginExecute()
+        {
             Logger.Normal(ConsoleColor.DarkGreen, $"Client logged in");

             while (true)
@@ -52,8 +70,10 @@ namespace PokemonGo.RocketAPI.Logic
                 try
                 {
                     await _client.SetServer();
-                    var profile = await _client.GetProfile();
+
                     var inventory = await _client.GetInventory();
+                    var playerStats = inventory.InventoryDelta.InventoryItems.Select(i => i.InventoryItemData).FirstOrDefault(i => i.PlayerStats != null);
+                    var profile = await _client.GetProfile();
                     var _currentLevelInfos = await Statistics._getcurrentLevelInfos(_client);

                     Logger.Normal(ConsoleColor.Yellow, "----------------------------");
@@ -70,9 +90,10 @@ namespace PokemonGo.RocketAPI.Logic
                     Logger.Normal(ConsoleColor.DarkGray, $"Stardust: {profile.Profile.Currency.ToArray()[1].Amount}");
                     Logger.Normal(ConsoleColor.Yellow, "----------------------------");

-                    await TransferDuplicatePokemon(false);
+                    //await EvolveAllPokemonWithEnoughCandy();
+                    await TransferDuplicatePokemon();
                     await RecycleItems();
-                    await RepeatAction(10, async () => await ExecuteFarmingPokestopsAndPokemons(_client));
+                    await ExecuteFarmingPokestopsAndPokemons();

                     /*
                 * Example calls below
@@ -84,6 +105,10 @@ namespace PokemonGo.RocketAPI.Logic
                 var pokemons = inventory.InventoryDelta.InventoryItems.Select(i => i.InventoryItemData?.Pokemon).Where(p => p != null && p?.PokemonId > 0);
                 */
                 }
+                catch (AccessTokenExpiredException)
+                {
+                    throw;
+                }
                 catch (Exception ex)
                 {
                     Logger.Error($"Exception: {ex}");
@@ -99,68 +124,77 @@ namespace PokemonGo.RocketAPI.Logic
                 await action();
         }

-        private async Task ExecuteFarmingPokestopsAndPokemons(Client client)
+        private async Task ExecuteFarmingPokestopsAndPokemons()
         {
-            var mapObjects = await client.GetMapObjects();
+            var mapObjects = await _client.GetMapObjects();
             var pokeStops = mapObjects.MapCells.SelectMany(i => i.Forts).Where(i => i.Type == FortType.Checkpoint && i.CooldownCompleteTimestampMs < DateTime.UtcNow.ToUnixTime());
             Logger.Normal(ConsoleColor.Green, $"Found {pokeStops.Count()} pokestops");

             foreach (var pokeStop in pokeStops)
             {
-                await ExecuteCatchAllNearbyPokemons(client);
-
-                var update = await client.UpdatePlayerLocation(pokeStop.Latitude, pokeStop.Longitude);
-                var fortInfo = await client.GetFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);
-                var fortSearch = await client.SearchFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);
+                await ExecuteCatchAllNearbyPokemons();
+
+                var distance = Navigation.DistanceBetween2Coordinates(_client.CurrentLat, _client.CurrentLng, pokeStop.Latitude, pokeStop.Longitude);
+                var update = await _client.UpdatePlayerLocation(pokeStop.Latitude, pokeStop.Longitude, _clientSettings.DefaultAltitude);
+                var fortInfo = await _client.GetFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);
+                var fortSearch = await _client.SearchFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);

                 _stats.addExperience(fortSearch.ExperienceAwarded);
                 _stats.updateConsoleTitle(_client);

-                Logger.Normal(ConsoleColor.Cyan, $"Using Pokestop: {fortInfo.Name}");
+                Logger.Normal(ConsoleColor.Cyan, $"Using Pokestop: {fortInfo.Name} in {Math.Round(distance)}m distance");
                 Logger.Normal(ConsoleColor.Cyan, $"Received XP: {fortSearch.ExperienceAwarded}, Gems: { fortSearch.GemsAwarded}, Eggs: {fortSearch.PokemonDataEgg} Items: {StringUtils.GetSummedFriendlyNameOfItemAwardList(fortSearch.ItemsAwarded)}");

-                await RandomHelper.RandomDelay(500, 1000);
+                await RandomHelper.RandomDelay(750,1000);
                 await RecycleItems();
-
-                await RandomHelper.RandomDelay(7500,8500);
             }
         }

-        private async Task ExecuteCatchAllNearbyPokemons(Client client)
+        private async Task ExecuteCatchAllNearbyPokemons()
         {
-            var mapObjects = await client.GetMapObjects();
+            var mapObjects = await _client.GetMapObjects();
             var pokemons = mapObjects.MapCells.SelectMany(i => i.CatchablePokemons);
             if (pokemons != null && pokemons.Any())
                 Logger.Normal(ConsoleColor.Green, $"Found {pokemons.Count()} catchable Pokemon");

             foreach (var pokemon in pokemons)
             {
-                var update = await client.UpdatePlayerLocation(pokemon.Latitude, pokemon.Longitude);
-                var encounterPokemonResponse = await client.EncounterPokemon(pokemon.EncounterId, pokemon.SpawnpointId);
-                var pokemonCP = encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp;
-                var berry = await GetBestBerry(pokemonCP);
-                var pokeball = await GetBestBall(pokemonCP);
-                if (pokeball == MiscEnums.Item.ITEM_UNKNOWN)
+                var distance = Navigation.DistanceBetween2Coordinates(_client.CurrentLat, _client.CurrentLng, pokemon.Latitude, pokemon.Longitude);
+                if (distance > 100)
+                    await Task.Delay(15000);
+                else
+                    await Task.Delay(500);
+
+                await _client.UpdatePlayerLocation(pokemon.Latitude, pokemon.Longitude, _clientSettings.DefaultAltitude);
+
+                var encounter = await _client.EncounterPokemon(pokemon.EncounterId, pokemon.SpawnpointId);
+                await CatchEncounter(encounter, pokemon);
+            }
+            await Task.Delay(15000);
+        }
+
+        private async Task CatchEncounter(EncounterResponse encounter, MapPokemon pokemon)
+        {
+            CatchPokemonResponse caughtPokemonResponse;
+            do
+            {
+                var berry = await GetBestBerry(encounter?.WildPokemon);
+                if (berry != AllEnum.ItemId.ItemUnknown && encounter?.CaptureProbability.CaptureProbability_.First() < 0.35)
                 {
-                    Logger.Normal($"You don't own any Pokeballs :( - We missed a {pokemon.PokemonId} with CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp}");
-                    return;
+                    var useRaspberry = await _client.UseCaptureItem(pokemon.EncounterId, pokemon.SpawnpointId, berry);
+                    Logger.Normal($"Use Rasperry {berry}");
+                    await RandomHelper.RandomDelay(500, 1000);
                 }
-                var balls_used = 0;

-                CatchPokemonResponse caughtPokemonResponse;
-                do
+                var pokeball = await GetBestBall(encounter?.WildPokemon);
+                if (pokeball == MiscEnums.Item.ITEM_UNKNOWN)
                 {
-                    if (berry != AllEnum.ItemId.ItemUnknown && encounterPokemonResponse?.CaptureProbability.CaptureProbability_.First() < 0.4)
-                    {
-                        var useRaspberry = await _client.UseCaptureItem(pokemon.EncounterId, pokemon.SpawnpointId, berry);
-                        Logger.Normal($"Use Rasperry {berry}");
-                        await RandomHelper.RandomDelay(500, 1000);
-                    }
-
-                    caughtPokemonResponse = await client.CatchPokemon(pokemon.EncounterId, pokemon.SpawnpointId, pokemon.Latitude, pokemon.Longitude, pokeball);
-                    balls_used++;
+                    Logger.Normal($"You don't own any Pokeballs :( - We missed a {pokemon.PokemonId} with CP {encounter?.WildPokemon?.PokemonData?.Cp}");
+                    return;
                 }
-                while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed);
+
+                var distance = Navigation.DistanceBetween2Coordinates(_client.CurrentLat, _client.CurrentLng, pokemon.Latitude, pokemon.Longitude);
+                caughtPokemonResponse = await _client.CatchPokemon(pokemon.EncounterId, pokemon.SpawnpointId, pokemon.Latitude, pokemon.Longitude, pokeball);

                 if (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess)
                 {
@@ -170,38 +204,26 @@ namespace PokemonGo.RocketAPI.Logic
                     var profile = await _client.GetProfile();
                     _stats.getStardust(profile.Profile.Currency.ToArray()[1].Amount);
                 }
-
                 _stats.updateConsoleTitle(_client);
+                Logger.Normal(ConsoleColor.Yellow, caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess ? $"We caught a {pokemon.PokemonId} with CP {encounter?.WildPokemon?.PokemonData?.Cp} and CaptureProbability: {encounter?.CaptureProbability.CaptureProbability_.First()}, used {pokeball} in {Math.Round(distance)}m distance and received XP {caughtPokemonResponse.Scores.Xp.Sum()}" : $"{pokemon.PokemonId} with CP {encounter?.WildPokemon?.PokemonData?.Cp} CaptureProbability: {encounter?.CaptureProbability.CaptureProbability_.First()} in {Math.Round(distance)}m distance {caughtPokemonResponse.Status} while using a {pokeball}..");

-                Logger.Normal(ConsoleColor.Yellow, caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchSuccess ? $"We caught a {pokemon.PokemonId} with CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp}, used {balls_used} x {pokeball} and received XP {caughtPokemonResponse.Scores.Xp.Sum()}" : $"{pokemon.PokemonId} with CP {encounterPokemonResponse?.WildPokemon?.PokemonData?.Cp} got away while using a {pokeball}..");
-
-                await RandomHelper.RandomDelay(500, 1000);
-                await TransferDuplicatePokemon(false);
-
-                await RandomHelper.RandomDelay(2500, 5000);
+                await Task.Delay(2000);
             }
+            while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
         }

-        private async Task EvolveAllGivenPokemons(IEnumerable<Pokemon> pokemonToEvolve)
+        private async Task EvolveAllPokemonWithEnoughCandy()
         {
+            var pokemonToEvolve = await _inventory.GetPokemonToEvolve();
             foreach (var pokemon in pokemonToEvolve)
             {
-                EvolvePokemonOut evolvePokemonOutProto;
-                do
-                {
-                    evolvePokemonOutProto = await _client.EvolvePokemon((ulong)pokemon.Id);
+                var evolvePokemonOutProto = await _client.EvolvePokemon((ulong)pokemon.Id);

-                    if (evolvePokemonOutProto.Result == EvolvePokemonOut.Types.EvolvePokemonStatus.PokemonEvolvedSuccess)
-                        Logger.Normal($"Evolved {pokemon.PokemonType} successfully for {evolvePokemonOutProto.ExpAwarded}xp");
-                    else
-                        Logger.Normal($"Failed to evolve {pokemon.PokemonType}. EvolvePokemonOutProto.Result was {evolvePokemonOutProto.Result}, stopping evolving {pokemon.PokemonType}");
+                if (evolvePokemonOutProto.Result == EvolvePokemonOut.Types.EvolvePokemonStatus.PokemonEvolvedSuccess)
+                    Logger.Normal($"Evolved {pokemon.PokemonId} successfully for {evolvePokemonOutProto.ExpAwarded}xp");
+                else
+                    Logger.Normal($"Failed to evolve {pokemon.PokemonId}. EvolvePokemonOutProto.Result was {evolvePokemonOutProto.Result}, stopping evolving {pokemon.PokemonId}");

-                    await Task.Delay(3000);
-                }
-                while (evolvePokemonOutProto.Result == EvolvePokemonOut.Types.EvolvePokemonStatus.PokemonEvolvedSuccess);
-
-                _stats.increasePokemonsTransfered();
-                _stats.updateConsoleTitle(_client);

                 await Task.Delay(3000);
             }
@@ -237,8 +259,10 @@ namespace PokemonGo.RocketAPI.Logic
             }
         }

-        private async Task<MiscEnums.Item> GetBestBall(int? pokemonCp)
+        private async Task<MiscEnums.Item> GetBestBall(WildPokemon pokemon)
         {
+            var pokemonCp = pokemon?.PokemonData?.Cp;
+
             var pokeBallsCount = await _inventory.GetItemAmountByType(MiscEnums.Item.ITEM_POKE_BALL);
             var greatBallsCount = await _inventory.GetItemAmountByType(MiscEnums.Item.ITEM_GREAT_BALL);
             var ultraBallsCount = await _inventory.GetItemAmountByType(MiscEnums.Item.ITEM_ULTRA_BALL);
@@ -271,8 +295,10 @@ namespace PokemonGo.RocketAPI.Logic
             return MiscEnums.Item.ITEM_UNKNOWN;
         }

-        private async Task<AllEnum.ItemId> GetBestBerry(int? pokemonCp)
+        private async Task<AllEnum.ItemId> GetBestBerry(WildPokemon pokemon)
         {
+            var pokemonCp = pokemon?.PokemonData?.Cp;
+
             var razzBerryCount = await _inventory.GetItemAmountByType(MiscEnums.Item.ITEM_RAZZ_BERRY);
             var blukBerryCount = await _inventory.GetItemAmountByType(MiscEnums.Item.ITEM_BLUK_BERRY);
             var nanabBerryCount = await _inventory.GetItemAmountByType(MiscEnums.Item.ITEM_NANAB_BERRY);
diff --git a/PokemonGo.RocketAPI.Logic/Navigation.cs b/PokemonGo.RocketAPI.Logic/Navigation.cs
index e0665b6..d31e2ae 100644
--- a/PokemonGo.RocketAPI.Logic/Navigation.cs
+++ b/PokemonGo.RocketAPI.Logic/Navigation.cs
@@ -1,12 +1,23 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace PokemonGo.RocketAPI.Logic
-{
-    class Navigation
-    {
-    }
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PokemonGo.RocketAPI.Logic
+{
+    public static class Navigation
+    {
+        public static double DistanceBetween2Coordinates(double Lat1, double Lng1, double Lat2, double Lng2)
+        {
+            double r_earth = 6378137;
+            double d_lat = (Lat2 - Lat1) * Math.PI / 180;
+            double d_lon = (Lng2 - Lng1) * Math.PI / 180;
+            double alpha = Math.Sin(d_lat / 2) * Math.Sin(d_lat / 2)
+                + Math.Cos(Lat1 * Math.PI / 180) * Math.Cos(Lat2 * Math.PI / 180)
+                * Math.Sin(d_lon / 2) * Math.Sin(d_lon / 2);
+            double d = 2 * r_earth * Math.Atan2(Math.Sqrt(alpha), Math.Sqrt(1 - alpha));
+            return d;
+        }
+    }
 }
diff --git a/PokemonGo.RocketAPI/Client.cs b/PokemonGo.RocketAPI/Client.cs
index 1199977..7dfdef4 100644
--- a/PokemonGo.RocketAPI/Client.cs
+++ b/PokemonGo.RocketAPI/Client.cs
@@ -4,6 +4,7 @@ using System.Net.Http;
 using System.Threading.Tasks;
 using Google.Protobuf;
 using PokemonGo.RocketAPI.Enums;
+using PokemonGo.RocketAPI.Exceptions;
 using PokemonGo.RocketAPI.GeneratedCode;
 using PokemonGo.RocketAPI.Helpers;
 using PokemonGo.RocketAPI.Extensions;
@@ -19,17 +20,18 @@ namespace PokemonGo.RocketAPI
         private readonly ISettings _settings;
         private readonly HttpClient _httpClient;
         private AuthType _authType = AuthType.Google;
-        private string _accessToken;
+        public string AccessToken { get; set; }
         private string _apiUrl;
         private Request.Types.UnknownAuth _unknownAuth;

-        private double _currentLat;
-        private double _currentLng;
+        public double CurrentLat { get; private set; }
+        public double CurrentLng { get; private set; }
+        public double CurrentAltitude { get; private set; }

         public Client(ISettings settings)
         {
             _settings = settings;
-            SetCoordinates(_settings.DefaultLatitude, _settings.DefaultLongitude);
+            SetCoordinates(_settings.DefaultLatitude, _settings.DefaultLongitude, _settings.DefaultAltitude);

             //Setup HttpClient and create default headers
             HttpClientHandler handler = new HttpClientHandler()
@@ -47,10 +49,11 @@ namespace PokemonGo.RocketAPI
                 "application/x-www-form-urlencoded");
         }

-        private void SetCoordinates(double lat, double lng)
+        private void SetCoordinates(double lat, double lng, double altitude)
         {
-            _currentLat = lat;
-            _currentLng = lng;
+            CurrentLat = lat;
+            CurrentLng = lng;
+            CurrentAltitude = altitude;
         }

         public async Task DoGoogleLogin()
@@ -59,39 +62,43 @@ namespace PokemonGo.RocketAPI
             if (_settings.GoogleRefreshToken != string.Empty)
             {
                 var tokenResponse = await GoogleLogin.GetAccessToken(_settings.GoogleRefreshToken);
-                _accessToken = tokenResponse.id_token;
+                AccessToken = tokenResponse.id_token;
             }
-
-            if (_accessToken == null)
+
+            if (AccessToken == null)
             {
-                var tokenResponse = await GoogleLogin.GetAccessToken();
-                _accessToken = tokenResponse.id_token;
+                var deviceCode = await GoogleLogin.GetDeviceCode();
+                var tokenResponse = await GoogleLogin.GetAccessToken(deviceCode);
+                AccessToken = tokenResponse.id_token;
                 _settings.GoogleRefreshToken = tokenResponse.access_token;
-                Logger.Normal($"Put RefreshToken in settings for direct login: {tokenResponse.access_token}");
-                Thread thread = new Thread(() => Clipboard.SetText(tokenResponse.access_token));
-                thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
-                thread.Start();
-                thread.Join();
-                Logger.Normal("The RefreshToken is in your Clipboard!");
             }
         }

+        /// <summary>
+        /// For GUI clients only. GUI clients don't use the DoGoogleLogin, but call the GoogleLogin class directly
+        /// </summary>
+        /// <param name="type"></param>
+        public void SetAuthType(AuthType type)
+        {
+            _authType = type;
+        }
+
         public async Task DoPtcLogin(string username, string password)
         {
-            _accessToken = await PtcLogin.GetAccessToken(username, password);
+            AccessToken = await PtcLogin.GetAccessToken(username, password);
             _authType = AuthType.Ptc;
         }

-        public async Task<PlayerUpdateResponse> UpdatePlayerLocation(double lat, double lng)
+        public async Task<PlayerUpdateResponse> UpdatePlayerLocation(double lat, double lng, double alt)
         {
-            this.SetCoordinates(lat, lng);
+            this.SetCoordinates(lat, lng, alt);
             var customRequest = new Request.Types.PlayerUpdateProto()
             {
-                Lat = Utils.FloatAsUlong(_currentLat),
-                Lng = Utils.FloatAsUlong(_currentLng)
+                Lat = Utils.FloatAsUlong(CurrentLat),
+                Lng = Utils.FloatAsUlong(CurrentLng)
             };

-            var updateRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 10,
+            var updateRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.PLAYER_UPDATE,
@@ -105,10 +112,14 @@ namespace PokemonGo.RocketAPI

         public async Task SetServer()
         {
-            var serverRequest = RequestBuilder.GetInitialRequest(_accessToken, _authType, _currentLat, _currentLng, 10,
+            var serverRequest = RequestBuilder.GetInitialRequest(AccessToken, _authType, CurrentLat, CurrentLng, CurrentAltitude,
                 RequestType.GET_PLAYER, RequestType.GET_HATCHED_OBJECTS, RequestType.GET_INVENTORY,
                 RequestType.CHECK_AWARDED_BADGES, RequestType.DOWNLOAD_SETTINGS);
             var serverResponse = await _httpClient.PostProto<Request>(Resources.RpcUrl, serverRequest);
+
+            if (serverResponse.Auth == null)
+                throw new AccessTokenExpiredException();
+
             _unknownAuth = new Request.Types.UnknownAuth()
             {
                 Unknown71 = serverResponse.Auth.Unknown71,
@@ -121,21 +132,21 @@ namespace PokemonGo.RocketAPI

         public async Task<GetPlayerResponse> GetProfile()
         {
-            var profileRequest = RequestBuilder.GetInitialRequest(_accessToken, _authType, _currentLat, _currentLng, 10,
+            var profileRequest = RequestBuilder.GetInitialRequest(AccessToken, _authType, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests() { Type = (int)RequestType.GET_PLAYER });
             return await _httpClient.PostProtoPayload<Request, GetPlayerResponse>($"https://{_apiUrl}/rpc", profileRequest);
         }

         public async Task<DownloadSettingsResponse> GetSettings()
         {
-            var settingsRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 10,
+            var settingsRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 RequestType.DOWNLOAD_SETTINGS);
             return await _httpClient.PostProtoPayload<Request, DownloadSettingsResponse>($"https://{_apiUrl}/rpc", settingsRequest);
         }

         public async Task<DownloadItemTemplatesResponse> GetItemTemplates()
         {
-            var settingsRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 10,
+            var settingsRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 RequestType.DOWNLOAD_ITEM_TEMPLATES);
             return
                 await
@@ -151,14 +162,14 @@ namespace PokemonGo.RocketAPI
             {
                 CellIds =
                     ByteString.CopyFrom(
-                        ProtoHelper.EncodeUlongList(S2Helper.GetNearbyCellIds(_currentLng,
-                            _currentLat))),
-                Latitude = Utils.FloatAsUlong(_currentLat),
-                Longitude = Utils.FloatAsUlong(_currentLng),
+                        ProtoHelper.EncodeUlongList(S2Helper.GetNearbyCellIds(CurrentLng,
+                            CurrentLat))),
+                Latitude = Utils.FloatAsUlong(CurrentLat),
+                Longitude = Utils.FloatAsUlong(CurrentLng),
                 Unknown14 = ByteString.CopyFromUtf8("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
             };

-            var mapRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 10,
+            var mapRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.GET_MAP_OBJECTS,
@@ -193,7 +204,7 @@ namespace PokemonGo.RocketAPI
                 Longitude = Utils.FloatAsUlong(fortLng),
             };

-            var fortDetailRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 10,
+            var fortDetailRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.FORT_DETAILS,
@@ -209,11 +220,11 @@ namespace PokemonGo.RocketAPI
                 Id = ByteString.CopyFromUtf8(fortId),
                 FortLatDegrees = Utils.FloatAsUlong(fortLat),
                 FortLngDegrees = Utils.FloatAsUlong(fortLng),
-                PlayerLatDegrees = Utils.FloatAsUlong(_currentLat),
-                PlayerLngDegrees = Utils.FloatAsUlong(_currentLng)
+                PlayerLatDegrees = Utils.FloatAsUlong(CurrentLat),
+                PlayerLngDegrees = Utils.FloatAsUlong(CurrentLng)
             };

-            var fortDetailRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
+            var fortDetailRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.FORT_SEARCH,
@@ -228,11 +239,11 @@ namespace PokemonGo.RocketAPI
             {
                 EncounterId = encounterId,
                 SpawnpointId = spawnPointGuid,
-                PlayerLatDegrees = Utils.FloatAsUlong(_currentLat),
-                PlayerLngDegrees = Utils.FloatAsUlong(_currentLng)
+                PlayerLatDegrees = Utils.FloatAsUlong(CurrentLat),
+                PlayerLngDegrees = Utils.FloatAsUlong(CurrentLng)
             };

-            var encounterResponse = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
+            var encounterResponse = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.ENCOUNTER,
@@ -250,7 +261,7 @@ namespace PokemonGo.RocketAPI
                 SpawnPointGuid = spawnPointGuid
             };

-            var useItemRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
+            var useItemRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.USE_ITEM_CAPTURE,
@@ -274,7 +285,7 @@ namespace PokemonGo.RocketAPI
                 NormalizedHitPosition = Utils.FloatAsUlong(1)
             };

-            var catchPokemonRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
+            var catchPokemonRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.CATCH_POKEMON,
@@ -292,7 +303,7 @@ namespace PokemonGo.RocketAPI
                 PokemonId = pokemonId
             };

-            var releasePokemonRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
+            var releasePokemonRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.RELEASE_POKEMON,
@@ -308,7 +319,7 @@ namespace PokemonGo.RocketAPI
                 PokemonId = pokemonId
             };

-            var releasePokemonRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
+            var releasePokemonRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.EVOLVE_POKEMON,
@@ -321,7 +332,7 @@ namespace PokemonGo.RocketAPI

         public async Task<GetInventoryResponse> GetInventory()
         {
-            var inventoryRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30, RequestType.GET_INVENTORY);
+            var inventoryRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude, RequestType.GET_INVENTORY);
             return await _httpClient.PostProtoPayload<Request, GetInventoryResponse>($"https://{_apiUrl}/rpc", inventoryRequest);
         }

@@ -333,7 +344,7 @@ namespace PokemonGo.RocketAPI
                 Count = amount
             };

-            var releasePokemonRequest = RequestBuilder.GetRequest(_unknownAuth, _currentLat, _currentLng, 30,
+            var releasePokemonRequest = RequestBuilder.GetRequest(_unknownAuth, CurrentLat, CurrentLng, CurrentAltitude,
                 new Request.Types.Requests()
                 {
                     Type = (int)RequestType.RECYCLE_INVENTORY_ITEM,
diff --git a/PokemonGo.RocketAPI/ISettings.cs b/PokemonGo.RocketAPI/ISettings.cs
index 9d7631e..1ee22df 100644
--- a/PokemonGo.RocketAPI/ISettings.cs
+++ b/PokemonGo.RocketAPI/ISettings.cs
@@ -1,18 +1,19 @@
-using PokemonGo.RocketAPI.Enums;
-using PokemonGo.RocketAPI.GeneratedCode;
-using System.Collections.Generic;
-
-namespace PokemonGo.RocketAPI
-{
-    public interface ISettings
-    {
-        AuthType AuthType { get; }
-        double DefaultLatitude { get; }
-        double DefaultLongitude { get; }
-        string GoogleRefreshToken { get; set; }
-        string PtcPassword { get; }
-        string PtcUsername { get; }
-
-        ICollection<KeyValuePair<AllEnum.ItemId, int>> itemRecycleFilter { get; set; }
-    }
+using PokemonGo.RocketAPI.Enums;
+using PokemonGo.RocketAPI.GeneratedCode;
+using System.Collections.Generic;
+
+namespace PokemonGo.RocketAPI
+{
+    public interface ISettings
+    {
+        AuthType AuthType { get; }
+        double DefaultLatitude { get; }
+        double DefaultLongitude { get; }
+        double DefaultAltitude { get; }
+        string GoogleRefreshToken { get; set; }
+        string PtcPassword { get; }
+        string PtcUsername { get; }
+
+        ICollection<KeyValuePair<AllEnum.ItemId, int>> itemRecycleFilter { get; set; }
+    }
 }
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI/Login/GoogleLogin.cs b/PokemonGo.RocketAPI/Login/GoogleLogin.cs
index 85925c7..4097831 100644
--- a/PokemonGo.RocketAPI/Login/GoogleLogin.cs
+++ b/PokemonGo.RocketAPI/Login/GoogleLogin.cs
@@ -14,40 +14,41 @@ using System.Diagnostics;

 namespace PokemonGo.RocketAPI.Login
 {
-    internal static class GoogleLogin
+    public static class GoogleLogin
     {
         private const string OauthTokenEndpoint = "https://www.googleapis.com/oauth2/v4/token";
         private const string OauthEndpoint = "https://accounts.google.com/o/oauth2/device/code";
         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 deviceCode)
         {
-            var deviceCodeResponse = await GetDeviceCode();
-            Logger.Normal("Please visit " + deviceCodeResponse.verification_url + " and enter " + deviceCodeResponse.user_code);
-            Thread thread = new Thread(() => Clipboard.SetText(deviceCodeResponse.user_code));
-            thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
-            thread.Start();
-            thread.Join();
-            Logger.Normal("The Token is in your Clipboard!");
-            Process.Start("https://google.com/device");
-
             //Poll until user submitted code..
             TokenResponseModel tokenResponse;
             do
             {
                 await Task.Delay(2000);
-                tokenResponse = await PollSubmittedToken(deviceCodeResponse.device_code);
+                tokenResponse = await PollSubmittedToken(deviceCode.device_code);
             } while (tokenResponse.access_token == null || tokenResponse.refresh_token == null);

             return tokenResponse;
         }

-        private static async Task<DeviceCodeModel> GetDeviceCode()
+        public static async Task<DeviceCodeModel> GetDeviceCode()
         {
-            return await HttpClientHelper.PostFormEncodedAsync<DeviceCodeModel>(OauthEndpoint,
+            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"));
+
+            Logger.Normal($"Please visit {deviceCode.verification_url} and enter {deviceCode.user_code}");
+            Thread thread = new Thread(() => Clipboard.SetText(deviceCode.user_code));
+            thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
+            thread.Start();
+            thread.Join();
+            Logger.Normal("The Token is in your Clipboard!");
+            Process.Start("https://google.com/device");
+
+            return deviceCode;
         }

         private static async Task<TokenResponseModel> PollSubmittedToken(string deviceCode)
@@ -78,7 +79,7 @@ namespace PokemonGo.RocketAPI.Login
             public string error_description { get; set; }
         }

-        internal class TokenResponseModel
+        public class TokenResponseModel
         {
             public string access_token { get; set; }
             public string token_type { get; set; }
diff --git a/PokemonGo.RocketAPI/Login/PtcLogin.cs b/PokemonGo.RocketAPI/Login/PtcLogin.cs
index f34f7bb..15782d3 100644
--- a/PokemonGo.RocketAPI/Login/PtcLogin.cs
+++ b/PokemonGo.RocketAPI/Login/PtcLogin.cs
@@ -39,7 +39,10 @@ namespace PokemonGo.RocketAPI.Login
                             new KeyValuePair<string, string>("_eventId", "submit"),
                             new KeyValuePair<string, string>("username", username),
                             new KeyValuePair<string, string>("password", password),
-                        }));
+                        }));
+
+                if (loginResp.Headers.Location == null)
+                    throw new PtcOfflineException();

                 var ticketId = HttpUtility.ParseQueryString(loginResp.Headers.Location.Query)["ticket"];
                 if (ticketId == null)
diff --git a/PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj b/PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj
index f9dde93..67a05ea 100644
--- a/PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj
+++ b/PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj
@@ -78,6 +78,7 @@
     <Compile Include="Enums\AuthType.cs" />
     <Compile Include="Enums\MiscEnums.cs" />
     <Compile Include="Enums\RequestType.cs" />
+    <Compile Include="Exceptions\AccessTokenExpiredException.cs" />
     <Compile Include="Exceptions\InvalidResponseException.cs" />
     <Compile Include="Exceptions\PtcOfflineException.cs" />
     <Compile Include="Extensions\DateTimeExtensions.cs" />
You may download the files in Public Git.