Update to the latest changes from: https://github.com/eslindsey/Pokemon-Go-Rocket-API

Spegeli [2016-07-22 23:46:34]
Update to the latest changes from: https://github.com/eslindsey/Pokemon-Go-Rocket-API
Filename
PokemonGo.RocketAPI.Console/App.config
PokemonGo.RocketAPI.Console/PokemonGo.RocketAPI.Console.csproj
PokemonGo.RocketAPI.Console/Settings.cs
PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
PokemonGo.RocketAPI.Console/UserSettings.cs
PokemonGo.RocketAPI.Console/UserSettings.settings
PokemonGo.RocketAPI.Logic/Inventory.cs
PokemonGo.RocketAPI.Logic/Logic.cs
PokemonGo.RocketAPI.Logic/Navigation.cs
PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj
PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs
PokemonGo.RocketAPI/Client.cs
PokemonGo.RocketAPI/ISettings.cs
PokemonGo.RocketAPI/Login/GoogleLogin.cs
PokemonGo.RocketAPI/Login/PtcLogin.cs
diff --git a/PokemonGo.RocketAPI.Console/App.config b/PokemonGo.RocketAPI.Console/App.config
index f10befb..111e210 100644
--- a/PokemonGo.RocketAPI.Console/App.config
+++ b/PokemonGo.RocketAPI.Console/App.config
@@ -17,29 +17,38 @@
       </dependentAssembly>
     </assemblyBinding>
   </runtime>
-  <userSettings>
+  <userSettings>
     <PokemonGo.RocketAPI.Console.UserSettings>
       <setting name="AuthType" serializeAs="String">
-        <value>Google</value>
+        <value>Ptc</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="GoogleRefreshToken" serializeAs="String">
+        <value />
+      </setting>
       <setting name="DefaultLatitude" serializeAs="String">
         <value>0</value>
       </setting>
       <setting name="DefaultLongitude" serializeAs="String">
         <value>0</value>
       </setting>
-    </PokemonGo.RocketAPI.Console.UserSettings>
+      <setting name="DefaultAltitude" serializeAs="String">
+        <value>10</value>
+      </setting>
+      <setting name="KeepMinIVPercentage" serializeAs="String">
+        <value>85</value>
+      </setting>
+      <setting name="KeepMinCP" serializeAs="String">
+        <value>1000</value>
+      </setting>
+      <setting name="WalkingSpeedInKilometerPerHour" serializeAs="String">
+        <value>50</value>
+      </setting>
+    </PokemonGo.RocketAPI.Console.UserSettings>
   </userSettings>
 </configuration>
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Console/PokemonGo.RocketAPI.Console.csproj b/PokemonGo.RocketAPI.Console/PokemonGo.RocketAPI.Console.csproj
index bbe1764..982972b 100644
--- a/PokemonGo.RocketAPI.Console/PokemonGo.RocketAPI.Console.csproj
+++ b/PokemonGo.RocketAPI.Console/PokemonGo.RocketAPI.Console.csproj
@@ -1,87 +1,88 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{1FEA147E-F704-497B-A538-00B053B5F672}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>PokemonGo.RocketAPI.Console</RootNamespace>
-    <AssemblyName>PokemonGo.RocketAPI.Console</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
-      <HintPath>..\packages\Google.Protobuf.3.0.0-beta3\lib\dotnet\Google.Protobuf.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Configuration" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Settings.cs" />
-    <Compile Include="UserSettings.Designer.cs">
-      <AutoGen>True</AutoGen>
-      <DesignTimeSharedInput>True</DesignTimeSharedInput>
-      <DependentUpon>UserSettings.settings</DependentUpon>
-    </Compile>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="App.config">
-      <SubType>Designer</SubType>
-    </None>
-    <None Include="packages.config" />
-    <None Include="UserSettings.settings">
-      <Generator>SettingsSingleFileGenerator</Generator>
-      <LastGenOutput>UserSettings.Designer.cs</LastGenOutput>
-    </None>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\PokemonGo.RocketAPI.Logic\PokemonGo.RocketAPI.Logic.csproj">
-      <Project>{0739E40D-C589-4AEB-93E5-EE8CD6773C60}</Project>
-      <Name>PokemonGo.RocketAPI.Logic</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\PokemonGo.RocketAPI\PokemonGo.RocketAPI.csproj">
-      <Project>{05D2DA44-1B8E-4CF7-94ED-4D52451CD095}</Project>
-      <Name>PokemonGo.RocketAPI</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{1FEA147E-F704-497B-A538-00B053B5F672}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>PokemonGo.RocketAPI.Console</RootNamespace>
+    <AssemblyName>PokemonGo.RocketAPI.Console</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Protobuf.3.0.0-beta3\lib\dotnet\Google.Protobuf.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Settings.cs" />
+    <Compile Include="UserSettings.cs" />
+    <Compile Include="UserSettings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+      <DependentUpon>UserSettings.settings</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config">
+      <SubType>Designer</SubType>
+    </None>
+    <None Include="packages.config" />
+    <None Include="UserSettings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>UserSettings.Designer.cs</LastGenOutput>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\PokemonGo.RocketAPI.Logic\PokemonGo.RocketAPI.Logic.csproj">
+      <Project>{0739E40D-C589-4AEB-93E5-EE8CD6773C60}</Project>
+      <Name>PokemonGo.RocketAPI.Logic</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\PokemonGo.RocketAPI\PokemonGo.RocketAPI.csproj">
+      <Project>{05D2DA44-1B8E-4CF7-94ED-4D52451CD095}</Project>
+      <Name>PokemonGo.RocketAPI</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   </Target>
   <Target Name="AfterBuild">
   </Target>
-  -->
+  -->
 </Project>
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Console/Settings.cs b/PokemonGo.RocketAPI.Console/Settings.cs
index d139ba9..1478c95 100644
--- a/PokemonGo.RocketAPI.Console/Settings.cs
+++ b/PokemonGo.RocketAPI.Console/Settings.cs
@@ -11,14 +11,29 @@ namespace PokemonGo.RocketAPI.Console
 {
     public class Settings : ISettings
     {
-        public AuthType AuthType => (AuthType)Enum.Parse(typeof(AuthType), UserSettings.Default.AuthType);
+        //public AuthType AuthType => (AuthType)Enum.Parse(typeof(AuthType), UserSettings.Default.AuthType);
+        public AuthType AuthType => (AuthType)Enum.Parse(typeof(AuthType), UserSettings.Default.AuthType, true);
         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
+        public float KeepMinIVPercentage => UserSettings.Default.KeepMinIVPercentage;
+        public int KeepMinCP => UserSettings.Default.KeepMinCP;
+        public double WalkingSpeedInKilometerPerHour => UserSettings.Default.WalkingSpeedInKilometerPerHour;
+
+        public string GoogleRefreshToken
+        {
+            get { return UserSettings.Default.GoogleRefreshToken; }
+            set
+            {
+                UserSettings.Default.GoogleRefreshToken = value;
+                UserSettings.Default.Save();
+            }
+        }
+
+        ICollection<KeyValuePair<ItemId, int>> ISettings.ItemRecycleFilter
         {
             get
             {
@@ -64,21 +79,63 @@ namespace PokemonGo.RocketAPI.Console
                      new KeyValuePair<ItemId, int>(ItemId.ItemItemStorageUpgrade, 100),
                 };
             }
-
             set
             {
                 throw new NotImplementedException();
             }
         }

-        public string GoogleRefreshToken
+        public ICollection<PokemonId> PokemonsToEvolve
         {
-            get { return UserSettings.Default.GoogleRefreshToken; }
+            get
+            {
+                //Type of pokemons to evolve
+                return new[]
+                {
+                    PokemonId.Rattata,
+                    PokemonId.Spearow,
+                    PokemonId.Ekans,
+                    PokemonId.Pikachu,
+                    PokemonId.Sandshrew,
+                    PokemonId.Clefable,
+                    PokemonId.Vulpix,
+                    PokemonId.Jigglypuff,
+                    PokemonId.Zubat,
+                    PokemonId.Paras,
+                    PokemonId.Venonat,
+                    PokemonId.Diglett,
+                    PokemonId.Meowth,
+                    PokemonId.Psyduck,
+                    PokemonId.Mankey,
+                    PokemonId.Growlithe,
+                    PokemonId.Tentacool,
+                    PokemonId.Ponyta,
+                    PokemonId.Slowpoke,
+                    PokemonId.Magnemite,
+                    PokemonId.Doduo,
+                    PokemonId.Seel,
+                    PokemonId.Grimer,
+                    PokemonId.Shellder,
+                    PokemonId.Drowzee,
+                    PokemonId.Krabby,
+                    PokemonId.Voltorb,
+                    PokemonId.Exeggcute,
+                    PokemonId.Cubone,
+                    PokemonId.Koffing,
+                    PokemonId.Rhyhorn,
+                    PokemonId.Horsea,
+                    PokemonId.Goldeen,
+                    PokemonId.Staryu,
+                    PokemonId.Omanyte,
+                    PokemonId.Kabuto,
+                    PokemonId.Dratini
+                };
+            }
             set
             {
-                UserSettings.Default.GoogleRefreshToken = value;
-                UserSettings.Default.Save();
+                throw new NotImplementedException();
             }
         }
+
     }
 }
diff --git a/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs b/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
index 14a6bc4..96d7083 100644
--- a/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
+++ b/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
@@ -1,110 +1,180 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
-//     Dieser Code wurde von einem Tool generiert.
-//     Laufzeitversion:4.0.30319.42000
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
 //
-//     Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
-//     der Code erneut generiert wird.
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
 // </auto-generated>
 //------------------------------------------------------------------------------

-namespace PokemonGo.RocketAPI.Console {
-
-
+namespace PokemonGo.RocketAPI.Console
+{
+
+
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
     [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
-    internal sealed partial class UserSettings : global::System.Configuration.ApplicationSettingsBase {
-
+    internal sealed partial class UserSettings : global::System.Configuration.ApplicationSettingsBase
+    {
+
         private static UserSettings defaultInstance = ((UserSettings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new UserSettings())));
-
-        public static UserSettings Default {
-            get {
+
+        public static UserSettings Default
+        {
+            get
+            {
                 return defaultInstance;
             }
         }
-
+
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Configuration.DefaultSettingValueAttribute("Google")]
-        public string AuthType {
-            get {
+        public string AuthType
+        {
+            get
+            {
                 return ((string)(this["AuthType"]));
             }
-            set {
+            set
+            {
                 this["AuthType"] = value;
             }
         }
-
+
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("username")]
-        public string PtcUsername {
-            get {
+        [global::System.Configuration.DefaultSettingValueAttribute("username2")]
+        public string PtcUsername
+        {
+            get
+            {
                 return ((string)(this["PtcUsername"]));
             }
-            set {
+            set
+            {
                 this["PtcUsername"] = value;
             }
         }
-
+
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("pw")]
+        public string PtcPassword
+        {
+            get
+            {
+                return ((string)(this["PtcPassword"]));
+            }
+            set
+            {
+                this["PtcPassword"] = value;
+            }
+        }
+
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Configuration.DefaultSettingValueAttribute("")]
-        public string GoogleRefreshToken {
-            get {
+        public string GoogleRefreshToken
+        {
+            get
+            {
                 return ((string)(this["GoogleRefreshToken"]));
             }
-            set {
+            set
+            {
                 this["GoogleRefreshToken"] = value;
             }
         }
-
+
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("52.379189")]
+        public double DefaultLatitude
+        {
+            get
+            {
+                return ((double)(this["DefaultLatitude"]));
+            }
+            set
+            {
+                this["DefaultLatitude"] = value;
+            }
+        }
+
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("4.899431")]
+        public double DefaultLongitude
+        {
+            get
+            {
+                return ((double)(this["DefaultLongitude"]));
+            }
+            set
+            {
+                this["DefaultLongitude"] = value;
+            }
+        }
+
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Configuration.DefaultSettingValueAttribute("10")]
-        public double DefaultAltitude {
-            get {
+        public double DefaultAltitude
+        {
+            get
+            {
                 return ((double)(this["DefaultAltitude"]));
             }
-            set {
+            set
+            {
                 this["DefaultAltitude"] = value;
             }
         }
-
+
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("password")]
-        public string PtcPassword {
-            get {
-                return ((string)(this["PtcPassword"]));
+        [global::System.Configuration.DefaultSettingValueAttribute("85")]
+        public float KeepMinIVPercentage
+        {
+            get
+            {
+                return ((float)(this["KeepMinIVPercentage"]));
             }
-            set {
-                this["PtcPassword"] = value;
+            set
+            {
+                this["KeepMinIVPercentage"] = value;
             }
         }
-
+
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("0")]
-        public double DefaultLatitude {
-            get {
-                return ((double)(this["DefaultLatitude"]));
+        [global::System.Configuration.DefaultSettingValueAttribute("1000")]
+        public int KeepMinCP
+        {
+            get
+            {
+                return ((int)(this["KeepMinCP"]));
             }
-            set {
-                this["DefaultLatitude"] = value;
+            set
+            {
+                this["KeepMinCP"] = value;
             }
         }
-
+
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("0")]
-        public double DefaultLongitude {
-            get {
-                return ((double)(this["DefaultLongitude"]));
+        [global::System.Configuration.DefaultSettingValueAttribute("50")]
+        public double WalkingSpeedInKilometerPerHour
+        {
+            get
+            {
+                return ((double)(this["WalkingSpeedInKilometerPerHour"]));
             }
-            set {
-                this["DefaultLongitude"] = value;
+            set
+            {
+                this["WalkingSpeedInKilometerPerHour"] = value;
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Console/UserSettings.cs b/PokemonGo.RocketAPI.Console/UserSettings.cs
new file mode 100644
index 0000000..b83c870
--- /dev/null
+++ b/PokemonGo.RocketAPI.Console/UserSettings.cs
@@ -0,0 +1,33 @@
+namespace PokemonGo.RocketAPI.Console
+{
+
+
+    // This class allows you to handle specific events on the settings class:
+    //  The SettingChanging event is raised before a setting's value is changed.
+    //  The PropertyChanged event is raised after a setting's value is changed.
+    //  The SettingsLoaded event is raised after the setting values are loaded.
+    //  The SettingsSaving event is raised before the setting values are saved.
+    internal sealed partial class UserSettings
+    {
+
+        public UserSettings()
+        {
+            // // To add event handlers for saving and changing settings, uncomment the lines below:
+            //
+            // this.SettingChanging += this.SettingChangingEventHandler;
+            //
+            // this.SettingsSaving += this.SettingsSavingEventHandler;
+            //
+        }
+
+        private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e)
+        {
+            // Add code to handle the SettingChangingEvent event here.
+        }
+
+        private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e)
+        {
+            // Add code to handle the SettingsSaving event here.
+        }
+    }
+}
diff --git a/PokemonGo.RocketAPI.Console/UserSettings.settings b/PokemonGo.RocketAPI.Console/UserSettings.settings
index 7beb694..29496ad 100644
--- a/PokemonGo.RocketAPI.Console/UserSettings.settings
+++ b/PokemonGo.RocketAPI.Console/UserSettings.settings
@@ -23,5 +23,14 @@
     <Setting Name="DefaultLongitude" Type="System.Double" Scope="User">
       <Value Profile="(Default)">0</Value>
     </Setting>
+    <Setting Name="KeepMinIVPercentage" Type="System.Single" Scope="User">
+      <Value Profile="(Default)">85</Value>
+    </Setting>
+    <Setting Name="KeepMinCP" Type="System.Int32" Scope="User">
+      <Value Profile="(Default)">1000</Value>
+    </Setting>
+    <Setting Name="WalkingSpeedInKilometerPerHour" Type="System.Double" Scope="User">
+      <Value Profile="(Default)">50</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 a0dcffa..6e17432 100644
--- a/PokemonGo.RocketAPI.Logic/Inventory.cs
+++ b/PokemonGo.RocketAPI.Logic/Inventory.cs
@@ -92,10 +92,15 @@ namespace PokemonGo.RocketAPI.Logic
                 .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()
+        public async Task<IEnumerable<PokemonData>> GetPokemonToEvolve(IEnumerable<PokemonId> filter = null)
         {
             var myPokemons = await GetPokemons();
-            var pokemons = myPokemons.Where(p => p.DeployedFortId == 0).ToList(); //Don't evolve pokemon in gyms
+            myPokemons = myPokemons.Where(p => p.DeployedFortId == 0).OrderBy(p => p.Cp); //Don't evolve pokemon in gyms
+            if (filter != null)
+            {
+                myPokemons = myPokemons.Where(p => filter.Contains(p.PokemonId));
+            }
+            var pokemons = myPokemons.ToList();

             var myPokemonSettings = await GetPokemonSettings();
             var pokemonSettings = myPokemonSettings.ToList();
@@ -148,8 +153,8 @@ namespace PokemonGo.RocketAPI.Logic
             var myItems = await GetItems();

             return myItems
-                .Where(x => settings.itemRecycleFilter.Any(f => f.Key == ((ItemId)x.Item_) && x.Count > f.Value))
-                .Select(x => new Item { Item_ = x.Item_, Count = x.Count - settings.itemRecycleFilter.Single(f => f.Key == (AllEnum.ItemId)x.Item_).Value, Unseen = x.Unseen });
+                .Where(x => settings.ItemRecycleFilter.Any(f => f.Key == ((ItemId)x.Item_) && x.Count > f.Value))
+                .Select(x => new Item { Item_ = x.Item_, Count = x.Count - settings.ItemRecycleFilter.Single(f => f.Key == (AllEnum.ItemId)x.Item_).Value, Unseen = x.Unseen });
         }
     }
 }
diff --git a/PokemonGo.RocketAPI.Logic/Logic.cs b/PokemonGo.RocketAPI.Logic/Logic.cs
index 81963d1..08af05e 100644
--- a/PokemonGo.RocketAPI.Logic/Logic.cs
+++ b/PokemonGo.RocketAPI.Logic/Logic.cs
@@ -20,6 +20,7 @@ namespace PokemonGo.RocketAPI.Logic
         private readonly ISettings _clientSettings;
         private readonly Inventory _inventory;
         private readonly Statistics _stats;
+        private readonly Navigation _navigation;

         public Logic(ISettings clientSettings)
         {
@@ -27,6 +28,7 @@ namespace PokemonGo.RocketAPI.Logic
             _client = new Client(_clientSettings);
             _inventory = new Inventory(_client);
             _stats = new Statistics();
+            _navigation = new Navigation(_client);
         }

         public async Task Execute()
@@ -51,6 +53,8 @@ namespace PokemonGo.RocketAPI.Logic
                     else if (_clientSettings.AuthType == AuthType.Google)
                         await _client.DoGoogleLogin();

+                    await _client.SetServer();
+
                     await PostLoginExecute();
                 }
                 catch (AccessTokenExpiredException)
@@ -69,16 +73,11 @@ namespace PokemonGo.RocketAPI.Logic
             {
                 try
                 {
-                    await _client.SetServer();
-
-                    //var inventory = await _client.GetInventory();
-                    //var playerStats = inventory.InventoryDelta.InventoryItems.Select(i => i.InventoryItemData).FirstOrDefault(i => i.PlayerStats != null);
+                    _stats.updateConsoleTitle(_inventory);

                     var profile = await _client.GetProfile();
                     var _currentLevelInfos = await Statistics._getcurrentLevelInfos(_inventory);

-                    _stats.updateConsoleTitle(_inventory);
-
                     Logger.Normal(ConsoleColor.Yellow, "----------------------------");
                     if (_clientSettings.AuthType == AuthType.Ptc)
                         Logger.Normal(ConsoleColor.Cyan, $"PTC Account: {_clientSettings.PtcUsername}\n");
@@ -93,7 +92,7 @@ namespace PokemonGo.RocketAPI.Logic
                     Logger.Normal(ConsoleColor.DarkGray, $"Stardust: {profile.Profile.Currency.ToArray()[1].Amount}");
                     Logger.Normal(ConsoleColor.Yellow, "----------------------------");

-                    //await EvolveAllPokemonWithEnoughCandy();
+                    await EvolveAllPokemonWithEnoughCandy(_clientSettings.PokemonsToEvolve);
                     await TransferDuplicatePokemon();
                     await RecycleItems();
                     await ExecuteFarmingPokestopsAndPokemons();
@@ -121,6 +120,11 @@ namespace PokemonGo.RocketAPI.Logic
             }
         }

+        public static float CalculatePokemonPerfection(PokemonData poke)
+        {
+            return ((float)(poke.IndividualAttack * 2 + poke.IndividualDefense + poke.IndividualStamina) / (4.0f * 15.0f)) * 100.0f;
+        }
+
         public async Task RepeatAction(int repeat, Func<Task> action)
         {
             for (int i = 0; i < repeat; i++)
@@ -130,7 +134,7 @@ namespace PokemonGo.RocketAPI.Logic
         private async Task ExecuteFarmingPokestopsAndPokemons()
         {
             var mapObjects = await _client.GetMapObjects();
-            var pokeStops = mapObjects.MapCells.SelectMany(i => i.Forts).Where(i => i.Type == FortType.Checkpoint && i.CooldownCompleteTimestampMs < DateTime.UtcNow.ToUnixTime());
+            var pokeStops = mapObjects.MapCells.SelectMany(i => i.Forts).Where(i => i.Type == FortType.Checkpoint && i.CooldownCompleteTimestampMs < DateTime.UtcNow.ToUnixTime()).OrderBy(i => LocationUtils.CalculateDistanceInMeters(new Navigation.Location(_client.CurrentLat, _client.CurrentLng), new Navigation.Location(i.Latitude, i.Longitude)));
             Logger.Normal(ConsoleColor.Green, $"Found {pokeStops.Count()} pokestops");

             foreach (var pokeStop in pokeStops)
@@ -139,7 +143,7 @@ namespace PokemonGo.RocketAPI.Logic
                 await TransferDuplicatePokemon();

                 var distance = Navigation.DistanceBetween2Coordinates(_client.CurrentLat, _client.CurrentLng, pokeStop.Latitude, pokeStop.Longitude);
-                var update = await _client.UpdatePlayerLocation(pokeStop.Latitude, pokeStop.Longitude, _clientSettings.DefaultAltitude);
+                var update = await _navigation.HumanLikeWalking(new Navigation.Location(pokeStop.Latitude, pokeStop.Longitude), _clientSettings.WalkingSpeedInKilometerPerHour);
                 var fortInfo = await _client.GetFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);
                 var fortSearch = await _client.SearchFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);

@@ -157,7 +161,7 @@ namespace PokemonGo.RocketAPI.Logic
         private async Task ExecuteCatchAllNearbyPokemons()
         {
             var mapObjects = await _client.GetMapObjects();
-            var pokemons = mapObjects.MapCells.SelectMany(i => i.CatchablePokemons);
+            var pokemons = mapObjects.MapCells.SelectMany(i => i.CatchablePokemons).OrderBy(i => LocationUtils.CalculateDistanceInMeters(new Navigation.Location(_client.CurrentLat, _client.CurrentLng), new Navigation.Location(i.Latitude, i.Longitude)));
             if (pokemons != null && pokemons.Any())
                 Logger.Normal(ConsoleColor.Green, $"Found {pokemons.Count()} catchable Pokemon");

@@ -166,10 +170,12 @@ namespace PokemonGo.RocketAPI.Logic
                 var distance = Navigation.DistanceBetween2Coordinates(_client.CurrentLat, _client.CurrentLng, pokemon.Latitude, pokemon.Longitude);
                 await Task.Delay(distance > 100 ? 15000 : 500);

-                await _client.UpdatePlayerLocation(pokemon.Latitude, pokemon.Longitude, _clientSettings.DefaultAltitude);
-
                 var encounter = await _client.EncounterPokemon(pokemon.EncounterId, pokemon.SpawnpointId);
-                await CatchEncounter(encounter, pokemon);
+
+                if (encounter.Status == EncounterResponse.Types.Status.EncounterSuccess)
+                    await CatchEncounter(encounter, pokemon);
+                else
+                    Logger.Normal($"Encounter problem: {encounter?.Status}");
             }
             await RandomHelper.RandomDelay(8000, 9000);
         }
@@ -180,7 +186,8 @@ namespace PokemonGo.RocketAPI.Logic
             do
             {
                 var bestBerry = await GetBestBerry(encounter?.WildPokemon);
-                if (bestBerry != AllEnum.ItemId.ItemUnknown && encounter?.CaptureProbability.CaptureProbability_.First() < 0.35)
+                var probability = encounter?.CaptureProbability?.CaptureProbability_?.FirstOrDefault();
+                if (bestBerry != AllEnum.ItemId.ItemUnknown && probability.HasValue && probability.Value < 0.35)
                 {
                     var useRaspberry = await _client.UseCaptureItem(pokemon.EncounterId, bestBerry, pokemon.SpawnpointId);
                     Logger.Normal($"Use Rasperry {bestBerry}");
@@ -208,7 +215,7 @@ namespace PokemonGo.RocketAPI.Logic
                 _stats.updateConsoleTitle(_inventory);
                 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 {bestPokeball} and received XP {caughtPokemonResponse.Scores.Xp.Sum()}"
+                    ? $"We caught a {pokemon.PokemonId} with CP {encounter?.WildPokemon?.PokemonData?.Cp} ({CalculatePokemonPerfection(encounter?.WildPokemon?.PokemonData).ToString("0.00")}% perfect) and CaptureProbability: {encounter?.CaptureProbability.CaptureProbability_.First()}, used {bestPokeball} and received XP {caughtPokemonResponse.Scores.Xp.Sum()}"
                     : $"{pokemon.PokemonId} with CP {encounter?.WildPokemon?.PokemonData?.Cp} CaptureProbability: {encounter?.CaptureProbability.CaptureProbability_.First()} {caughtPokemonResponse.Status} while using a {bestPokeball}.."
                     );
                 await RandomHelper.RandomDelay(1750, 2250);
@@ -216,18 +223,13 @@ namespace PokemonGo.RocketAPI.Logic
             while (caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchMissed || caughtPokemonResponse.Status == CatchPokemonResponse.Types.CatchStatus.CatchEscape);
         }

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

-                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}");
-
                 Logger.Normal(
                     evolvePokemonOutProto.Result == EvolvePokemonOut.Types.EvolvePokemonStatus.PokemonEvolvedSuccess
                         ? $"Evolved {pokemon.PokemonId} successfully for {evolvePokemonOutProto.ExpAwarded} xp"
@@ -246,6 +248,9 @@ namespace PokemonGo.RocketAPI.Logic

             foreach (var duplicatePokemon in duplicatePokemons)
             {
+                if (CalculatePokemonPerfection(duplicatePokemon) >= _clientSettings.KeepMinIVPercentage || duplicatePokemon.Cp > _clientSettings.KeepMinCP)
+                    continue;
+
                 var bestPokemonOfType = await _inventory.GetHighestCPofType(duplicatePokemon);
                 var transfer = await _client.TransferPokemon(duplicatePokemon.Id);

@@ -349,5 +354,18 @@ namespace PokemonGo.RocketAPI.Logic

             return berries.OrderBy(g => g.Key).First().Key;
         }
+
+        private async Task DisplayPlayerLevelInTitle()
+        {
+            var playerStats = await _inventory.GetPlayerStats();
+            var playerStat = playerStats.FirstOrDefault();
+            if (playerStat != null)
+            {
+                var message = $"Player level {playerStat.Level:0} - ({(playerStat.Experience - playerStat.PrevLevelXp):0} / {(playerStat.NextLevelXp - playerStat.PrevLevelXp):0})";
+                System.Console.Title = message;
+                Logger.Normal(message);
+            }
+            await Task.Delay(5000);
+        }
     }
 }
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Logic/Navigation.cs b/PokemonGo.RocketAPI.Logic/Navigation.cs
index d31e2ae..6d1e590 100644
--- a/PokemonGo.RocketAPI.Logic/Navigation.cs
+++ b/PokemonGo.RocketAPI.Logic/Navigation.cs
@@ -1,13 +1,86 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Runtime.InteropServices;
 using System.Threading.Tasks;
+using PokemonGo.RocketAPI.GeneratedCode;
+using PokemonGo.RocketAPI.Logic.Utils;

 namespace PokemonGo.RocketAPI.Logic
 {
-    public static class Navigation
+    public class Navigation
     {
+
+        private static readonly double speedDownTo = 10 / 3.6;
+        private readonly Client _client;
+
+        public Navigation(Client client)
+        {
+            _client = client;
+        }
+
+        public async Task<PlayerUpdateResponse> HumanLikeWalking(Location targetLocation, double walkingSpeedInKilometersPerHour)
+        {
+            double speedInMetersPerSecond = walkingSpeedInKilometersPerHour / 3.6;
+
+            Location sourceLocation = new Location(_client.CurrentLat, _client.CurrentLng);
+            var distanceToTarget = LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation);
+            Logger.Normal($"Distance to target location: {distanceToTarget:0.##} meters. Will take {distanceToTarget / speedInMetersPerSecond:0.##} seconds!");
+
+            double nextWaypointBearing = LocationUtils.DegreeBearing(sourceLocation, targetLocation);
+            double nextWaypointDistance = speedInMetersPerSecond;
+            Location waypoint = LocationUtils.CreateWaypoint(sourceLocation, nextWaypointDistance, nextWaypointBearing);
+
+            //Initial walking
+            DateTime requestSendDateTime = DateTime.Now;
+            var result = await _client.UpdatePlayerLocation(waypoint.Latitude, waypoint.Longitude, _client.Settings.DefaultAltitude);
+
+            do
+            {
+                double millisecondsUntilGetUpdatePlayerLocationResponse = (DateTime.Now - requestSendDateTime).TotalMilliseconds;
+
+                sourceLocation = new Location(_client.CurrentLat, _client.CurrentLng);
+                var currentDistanceToTarget = LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation);
+
+                if (currentDistanceToTarget < 40)
+                {
+                    if (speedInMetersPerSecond > speedDownTo)
+                    {
+                        Logger.Normal("We are within 40 meters of the target. Speeding down to 10 km/h to not pass the target.");
+                        speedInMetersPerSecond = speedDownTo;
+                    }
+                    else
+                    {
+                        Logger.Normal("We are within 40 meters of the target, attempting to interact.");
+                    }
+                }
+                else
+                {
+                    Logger.Normal($"Distance to target location: {LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation):0.##} meters.");
+                }
+
+                nextWaypointDistance = Math.Min(currentDistanceToTarget, millisecondsUntilGetUpdatePlayerLocationResponse / 1000 * speedInMetersPerSecond);
+                nextWaypointBearing = LocationUtils.DegreeBearing(sourceLocation, targetLocation);
+                waypoint = LocationUtils.CreateWaypoint(sourceLocation, nextWaypointDistance, nextWaypointBearing);
+
+                requestSendDateTime = DateTime.Now;
+                result = await _client.UpdatePlayerLocation(waypoint.Latitude, waypoint.Longitude, _client.Settings.DefaultAltitude);
+                await Task.Delay(Math.Min((int)(distanceToTarget / speedInMetersPerSecond * 1000), 3000));
+            } while (LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation) >= 30);
+
+            return result;
+        }
+
+        public class Location
+        {
+            public double Latitude { get; set; }
+            public double Longitude { get; set; }
+
+            public Location(double latitude, double longitude)
+            {
+                Latitude = latitude;
+                Longitude = longitude;
+            }
+        }
+
         public static double DistanceBetween2Coordinates(double Lat1, double Lng1, double Lat2, double Lng2)
         {
             double r_earth = 6378137;
@@ -20,4 +93,4 @@ namespace PokemonGo.RocketAPI.Logic
             return d;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj b/PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj
index 8a0cf1b..8346c44 100644
--- a/PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj
+++ b/PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj
@@ -49,6 +49,7 @@
     <Compile Include="Navigation.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Utils\CheckAndDownloadVersion.cs" />
+    <Compile Include="Utils\LocationUtils.cs" />
     <Compile Include="Utils\Statistics.cs" />
     <Compile Include="Utils\StringUtils.cs" />
   </ItemGroup>
diff --git a/PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs b/PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs
new file mode 100644
index 0000000..4ff42f7
--- /dev/null
+++ b/PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static PokemonGo.RocketAPI.Logic.Navigation;
+
+namespace PokemonGo.RocketAPI.Logic.Utils
+{
+    public static class LocationUtils
+    {
+        public static Location CreateWaypoint(Location sourceLocation, double distanceInMeters, double bearingDegrees) //from http://stackoverflow.com/a/17545955
+        {
+            double distanceKm = distanceInMeters / 1000.0;
+            double distanceRadians = distanceKm / 6371; //6371 = Earth's radius in km
+
+            double bearingRadians = ToRad(bearingDegrees);
+            double sourceLatitudeRadians = ToRad(sourceLocation.Latitude);
+            double sourceLongitudeRadians = ToRad(sourceLocation.Longitude);
+
+            double targetLatitudeRadians = Math.Asin(Math.Sin(sourceLatitudeRadians) * Math.Cos(distanceRadians)
+                    + Math.Cos(sourceLatitudeRadians) * Math.Sin(distanceRadians) * Math.Cos(bearingRadians));
+
+            double targetLongitudeRadians = sourceLongitudeRadians + Math.Atan2(Math.Sin(bearingRadians)
+                    * Math.Sin(distanceRadians) * Math.Cos(sourceLatitudeRadians), Math.Cos(distanceRadians)
+                    - Math.Sin(sourceLatitudeRadians) * Math.Sin(targetLatitudeRadians));
+
+            // adjust toLonRadians to be in the range -180 to +180...
+            targetLongitudeRadians = ((targetLongitudeRadians + 3 * Math.PI) % (2 * Math.PI)) - Math.PI;
+
+            return new Location(ToDegrees(targetLatitudeRadians), ToDegrees(targetLongitudeRadians));
+        }
+
+        public static double CalculateDistanceInMeters(Location sourceLocation, Location targetLocation) // from http://stackoverflow.com/questions/6366408/calculating-distance-between-two-latitude-and-longitude-geocoordinates
+        {
+            var baseRad = Math.PI * sourceLocation.Latitude / 180;
+            var targetRad = Math.PI * targetLocation.Latitude / 180;
+            var theta = sourceLocation.Longitude - targetLocation.Longitude;
+            var thetaRad = Math.PI * theta / 180;
+
+            double dist =
+                Math.Sin(baseRad) * Math.Sin(targetRad) + Math.Cos(baseRad) *
+                Math.Cos(targetRad) * Math.Cos(thetaRad);
+            dist = Math.Acos(dist);
+
+            dist = dist * 180 / Math.PI;
+            dist = dist * 60 * 1.1515 * 1.609344 * 1000;
+
+            return dist;
+        }
+
+        public static double DegreeBearing(Location sourceLocation, Location targetLocation) // from http://stackoverflow.com/questions/2042599/direction-between-2-latitude-longitude-points-in-c-sharp
+        {
+            var dLon = ToRad(targetLocation.Longitude - sourceLocation.Longitude);
+            var dPhi = Math.Log(
+                Math.Tan(ToRad(targetLocation.Latitude) / 2 + Math.PI / 4) / Math.Tan(ToRad(sourceLocation.Latitude) / 2 + Math.PI / 4));
+            if (Math.Abs(dLon) > Math.PI)
+                dLon = dLon > 0 ? -(2 * Math.PI - dLon) : (2 * Math.PI + dLon);
+            return ToBearing(Math.Atan2(dLon, dPhi));
+        }
+
+        public static double ToRad(double degrees)
+        {
+            return degrees * (Math.PI / 180);
+        }
+
+        public static double ToDegrees(double radians)
+        {
+            return radians * 180 / Math.PI;
+        }
+
+        public static double ToBearing(double radians)
+        {
+            // convert radians to degrees (as bearing: 0...360)
+            return (ToDegrees(radians) + 360) % 360;
+        }
+    }
+}
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI/Client.cs b/PokemonGo.RocketAPI/Client.cs
index 8c637a8..507c525 100644
--- a/PokemonGo.RocketAPI/Client.cs
+++ b/PokemonGo.RocketAPI/Client.cs
@@ -17,7 +17,8 @@ namespace PokemonGo.RocketAPI
 {
     public class Client
     {
-        private readonly ISettings _settings;
+        //private readonly ISettings _settings;
+        public ISettings Settings { get; }
         private readonly HttpClient _httpClient;
         private AuthType _authType = AuthType.Google;
         public string AccessToken { get; set; }
@@ -30,8 +31,8 @@ namespace PokemonGo.RocketAPI

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

             //Setup HttpClient and create default headers
             HttpClientHandler handler = new HttpClientHandler()
@@ -61,9 +62,9 @@ namespace PokemonGo.RocketAPI
             _authType = AuthType.Google;

             GoogleLogin.TokenResponseModel tokenResponse = null;
-            if (_settings.GoogleRefreshToken != string.Empty)
+            if (Settings.GoogleRefreshToken != string.Empty)
             {
-                tokenResponse = await GoogleLogin.GetAccessToken(_settings.GoogleRefreshToken);
+                tokenResponse = await GoogleLogin.GetAccessToken(Settings.GoogleRefreshToken);
                 AccessToken = tokenResponse?.id_token;
             }

@@ -71,7 +72,7 @@ namespace PokemonGo.RocketAPI
             {
                 var deviceCode = await GoogleLogin.GetDeviceCode();
                 tokenResponse = await GoogleLogin.GetAccessToken(deviceCode);
-                _settings.GoogleRefreshToken = tokenResponse?.refresh_token;
+                Settings.GoogleRefreshToken = tokenResponse?.refresh_token;
                 AccessToken = tokenResponse?.id_token;
             }

diff --git a/PokemonGo.RocketAPI/ISettings.cs b/PokemonGo.RocketAPI/ISettings.cs
index 1ee22df..cb1684e 100644
--- a/PokemonGo.RocketAPI/ISettings.cs
+++ b/PokemonGo.RocketAPI/ISettings.cs
@@ -13,7 +13,12 @@ namespace PokemonGo.RocketAPI
         string GoogleRefreshToken { get; set; }
         string PtcPassword { get; }
         string PtcUsername { get; }
+        float KeepMinIVPercentage { get; }
+        int KeepMinCP { get; }
+        double WalkingSpeedInKilometerPerHour { get; }

-        ICollection<KeyValuePair<AllEnum.ItemId, int>> itemRecycleFilter { get; set; }
+        ICollection<KeyValuePair<AllEnum.ItemId, int>> ItemRecycleFilter { get; set; }
+
+        ICollection<AllEnum.PokemonId> PokemonsToEvolve { get; }
     }
 }
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI/Login/GoogleLogin.cs b/PokemonGo.RocketAPI/Login/GoogleLogin.cs
index 4097831..77eb633 100644
--- a/PokemonGo.RocketAPI/Login/GoogleLogin.cs
+++ b/PokemonGo.RocketAPI/Login/GoogleLogin.cs
@@ -21,7 +21,7 @@ namespace PokemonGo.RocketAPI.Login
         private const string ClientId = "848232511240-73ri3t7plvk96pj4f85uj8otdat2alem.apps.googleusercontent.com";
         private const string ClientSecret = "NCjF1TLi2CcY6t5mt0ZveuL7";

-        internal static async Task<TokenResponseModel> GetAccessToken(DeviceCodeModel deviceCode)
+        public static async Task<TokenResponseModel> GetAccessToken(DeviceCodeModel deviceCode)
         {
             //Poll until user submitted code..
             TokenResponseModel tokenResponse;
diff --git a/PokemonGo.RocketAPI/Login/PtcLogin.cs b/PokemonGo.RocketAPI/Login/PtcLogin.cs
index 15782d3..63c4fbf 100644
--- a/PokemonGo.RocketAPI/Login/PtcLogin.cs
+++ b/PokemonGo.RocketAPI/Login/PtcLogin.cs
@@ -1,70 +1,70 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using System.Web;
-using PokemonGo.RocketAPI.Exceptions;
-using PokemonGo.RocketAPI.Helpers;
-
-namespace PokemonGo.RocketAPI.Login
-{
-    internal static class PtcLogin
-    {
-        public static async Task<string> GetAccessToken(string username, string password)
-        {
-            var handler = new HttpClientHandler()
-            {
-                AutomaticDecompression = DecompressionMethods.GZip,
-                AllowAutoRedirect = false
-            };
-
-            using (var tempHttpClient = new HttpClient(handler))
-            {
-                //Get session cookie
-                var sessionResp = await tempHttpClient.GetAsync(Resources.PtcLoginUrl);
-                var data = await sessionResp.Content.ReadAsStringAsync();
-                var lt = JsonHelper.GetValue(data, "lt");
-                var executionId = JsonHelper.GetValue(data, "execution");
-
-                //Login
-                var loginResp = await tempHttpClient.PostAsync(Resources.PtcLoginUrl,
-                    new FormUrlEncodedContent(
-                        new[]
-                        {
-                            new KeyValuePair<string, string>("lt", lt),
-                            new KeyValuePair<string, string>("execution", executionId),
-                            new KeyValuePair<string, string>("_eventId", "submit"),
-                            new KeyValuePair<string, string>("username", username),
-                            new KeyValuePair<string, string>("password", password),
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+using PokemonGo.RocketAPI.Exceptions;
+using PokemonGo.RocketAPI.Helpers;
+
+namespace PokemonGo.RocketAPI.Login
+{
+    internal static class PtcLogin
+    {
+        public static async Task<string> GetAccessToken(string username, string password)
+        {
+            var handler = new HttpClientHandler()
+            {
+                AutomaticDecompression = DecompressionMethods.GZip,
+                AllowAutoRedirect = false
+            };
+
+            using (var tempHttpClient = new HttpClient(handler))
+            {
+                //Get session cookie
+                var sessionResp = await tempHttpClient.GetAsync(Resources.PtcLoginUrl);
+                var data = await sessionResp.Content.ReadAsStringAsync();
+                var lt = JsonHelper.GetValue(data, "lt");
+                var executionId = JsonHelper.GetValue(data, "execution");
+
+                //Login
+                var loginResp = await tempHttpClient.PostAsync(Resources.PtcLoginUrl,
+                    new FormUrlEncodedContent(
+                        new[]
+                        {
+                            new KeyValuePair<string, string>("lt", lt),
+                            new KeyValuePair<string, string>("execution", executionId),
+                            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)
-                    throw new PtcOfflineException();
-
-                //Get tokenvar
-                var tokenResp = await tempHttpClient.PostAsync(Resources.PtcLoginOauth,
-                    new FormUrlEncodedContent(
-                        new[]
-                        {
-                            new KeyValuePair<string, string>("client_id", "mobile-app_pokemon-go"),
-                            new KeyValuePair<string, string>("redirect_uri",
-                                "https://www.nianticlabs.com/pokemongo/error"),
-                            new KeyValuePair<string, string>("client_secret",
-                                "w8ScCUXJQc6kXKw8FiOhd8Fixzht18Dq3PEVkUCP5ZPxtgyWsbTvWHFLm2wNY0JR"),
-                            new KeyValuePair<string, string>("grant_type", "refresh_token"),
-                            new KeyValuePair<string, string>("code", ticketId),
-                        }));
-
-                var tokenData = await tokenResp.Content.ReadAsStringAsync();
-                return HttpUtility.ParseQueryString(tokenData)["access_token"];
-            }
-        }
-    }
-}
+                    throw new PtcOfflineException();
+
+                var ticketId = HttpUtility.ParseQueryString(loginResp.Headers.Location.Query)["ticket"];
+                if (ticketId == null)
+                    throw new PtcOfflineException();
+
+                //Get tokenvar
+                var tokenResp = await tempHttpClient.PostAsync(Resources.PtcLoginOauth,
+                    new FormUrlEncodedContent(
+                        new[]
+                        {
+                            new KeyValuePair<string, string>("client_id", "mobile-app_pokemon-go"),
+                            new KeyValuePair<string, string>("redirect_uri",
+                                "https://www.nianticlabs.com/pokemongo/error"),
+                            new KeyValuePair<string, string>("client_secret",
+                                "w8ScCUXJQc6kXKw8FiOhd8Fixzht18Dq3PEVkUCP5ZPxtgyWsbTvWHFLm2wNY0JR"),
+                            new KeyValuePair<string, string>("grant_type", "refresh_token"),
+                            new KeyValuePair<string, string>("code", ticketId),
+                        }));
+
+                var tokenData = await tokenResp.Content.ReadAsStringAsync();
+                return HttpUtility.ParseQueryString(tokenData)["access_token"];
+            }
+        }
+    }
+}
You may download the files in Public Git.