Move more logic from MainForm to RocketBot.Logic

Brian [2016-08-23 13:56:18]
Move more logic from MainForm to RocketBot.Logic
Filename
PokemonGo.RocketBot.Logic/Common/Translations.cs
PokemonGo.RocketBot.Logic/PokemonGo.RocketBot.Logic.csproj
PokemonGo.RocketBot.Logic/Tasks/LevelUpSpecificPokemonTask.cs
PokemonGo.RocketBot.Logic/Tasks/RecycleSpecificItemTask.cs
PokemonGo.RocketBot.Logic/Tasks/RenameSpecificPokemonTask.cs
PokemonGo.RocketBot.Logic/Tasks/TransferPokemonTask.cs
PokemonGo.RocketBot.Logic/Tasks/UseIncenseTask.cs
PokemonGo.RocketBot.Logic/Tasks/UseLuckyEggTask.cs
PokemonGo.RocketBot.Window/ConsoleLogger.cs
PokemonGo.RocketBot.Window/Forms/MainForm.cs
PokemonGo.RocketBot.Window/Helpers/ResourceHelper.cs
PokemonGo.RocketBot.Window/Models/LoggingStrings.cs
PokemonGo.RocketBot.Window/PokemonGo.RocketBot.Window.csproj
PokemonGo.RocketBot.Window/WebSocketHandler/ActionCommands/TransferPokemonHandler.cs
diff --git a/PokemonGo.RocketBot.Logic/Common/Translations.cs b/PokemonGo.RocketBot.Logic/Common/Translations.cs
index d4d1fc8..2db460f 100644
--- a/PokemonGo.RocketBot.Logic/Common/Translations.cs
+++ b/PokemonGo.RocketBot.Logic/Common/Translations.cs
@@ -78,6 +78,7 @@ namespace PokemonGo.RocketBot.Logic.Common
         LogEntryPkmn,
         LogEntryTransfered,
         LogEntryEvolved,
+        LogEntryLevelUp,
         LogEntryBerry,
         LogEntryEgg,
         LogEntryDebug,
@@ -205,7 +206,8 @@ namespace PokemonGo.RocketBot.Logic.Common
             ItemTypeNameHandling = TypeNameHandling.Arrays,
             ItemConverterType = typeof(KeyValuePairConverter),
             ObjectCreationHandling = ObjectCreationHandling.Replace,
-            DefaultValueHandling = DefaultValueHandling.Populate)] private readonly
+            DefaultValueHandling = DefaultValueHandling.Populate)]
+        private readonly
             List<KeyValuePair<PokemonMove, string>> _pokemonMovesetTranslationStrings =
                 new List<KeyValuePair<PokemonMove, string>>
                 {
@@ -395,7 +397,8 @@ namespace PokemonGo.RocketBot.Logic.Common
             ItemTypeNameHandling = TypeNameHandling.Arrays,
             ItemConverterType = typeof(KeyValuePairConverter),
             ObjectCreationHandling = ObjectCreationHandling.Replace,
-            DefaultValueHandling = DefaultValueHandling.Populate)] private readonly
+            DefaultValueHandling = DefaultValueHandling.Populate)]
+        private readonly
             List<KeyValuePair<PokemonId, string>> _pokemonTranslationStrings = new List<KeyValuePair<PokemonId, string>>
             {
                 new KeyValuePair<PokemonId, string>((PokemonId) 001, "Bulbasaur"),
@@ -640,6 +643,7 @@ namespace PokemonGo.RocketBot.Logic.Common
             new KeyValuePair<TranslationString, string>(TranslationString.LogEntryPkmn, "PKMN"),
             new KeyValuePair<TranslationString, string>(TranslationString.LogEntryTransfered, "TRANSFERRED"),
             new KeyValuePair<TranslationString, string>(TranslationString.LogEntryEvolved, "EVOLVED"),
+            new KeyValuePair<TranslationString, string>(TranslationString.LogEntryLevelUp, "LEVELUP"),
             new KeyValuePair<TranslationString, string>(TranslationString.LogEntryBerry, "BERRY"),
             new KeyValuePair<TranslationString, string>(TranslationString.LogEntryEgg, "EGG"),
             new KeyValuePair<TranslationString, string>(TranslationString.LogEntryDebug, "DEBUG"),
@@ -886,7 +890,7 @@ namespace PokemonGo.RocketBot.Logic.Common
                 var input = File.ReadAllText(fullPath);

                 var jsonSettings = new JsonSerializerSettings();
-                jsonSettings.Converters.Add(new StringEnumConverter {CamelCaseText = true});
+                jsonSettings.Converters.Add(new StringEnumConverter { CamelCaseText = true });
                 jsonSettings.ObjectCreationHandling = ObjectCreationHandling.Replace;
                 jsonSettings.DefaultValueHandling = DefaultValueHandling.Populate;

@@ -937,7 +941,7 @@ namespace PokemonGo.RocketBot.Logic.Common
         public void Save(string fullPath)
         {
             var output = JsonConvert.SerializeObject(this, Formatting.Indented,
-                new StringEnumConverter {CamelCaseText = true});
+                new StringEnumConverter { CamelCaseText = true });

             var folder = Path.GetDirectoryName(fullPath);
             if (folder != null && !Directory.Exists(folder))
diff --git a/PokemonGo.RocketBot.Logic/PokemonGo.RocketBot.Logic.csproj b/PokemonGo.RocketBot.Logic/PokemonGo.RocketBot.Logic.csproj
index 43977d9..cca00ed 100644
--- a/PokemonGo.RocketBot.Logic/PokemonGo.RocketBot.Logic.csproj
+++ b/PokemonGo.RocketBot.Logic/PokemonGo.RocketBot.Logic.csproj
@@ -158,6 +158,7 @@
     <Compile Include="Tasks\GetPokeDexCount.cs" />
     <Compile Include="Tasks\InventoryListTask.cs" />
     <Compile Include="Tasks\LevelUpPokemonTask.cs" />
+    <Compile Include="Tasks\LevelUpSpecificPokemonTask.cs" />
     <Compile Include="Tasks\PokemonListTask.cs" />
     <Compile Include="Tasks\Farm.cs" />
     <Compile Include="Settings.cs" />
@@ -184,12 +185,13 @@
     <Compile Include="Tasks\Login.cs" />
     <Compile Include="Tasks\RecycleItemsTask.cs" />
     <Compile Include="Tasks\RenamePokemonTask.cs" />
+    <Compile Include="Tasks\RenameSpecificPokemonTask.cs" />
     <Compile Include="Tasks\SnipePokemonTask.cs" />
     <Compile Include="Tasks\TransferDuplicatePokemonTask.cs" />
     <Compile Include="Event\UseLuckyEggEvent.cs" />
     <Compile Include="State\VersionCheckState.cs" />
     <Compile Include="Event\WarnEvent.cs" />
-    <Compile Include="Tasks\TransferPokemonTask.cs" />
+    <Compile Include="Tasks\TransferSpecificPokemonTask.cs" />
     <Compile Include="Tasks\TransferWeakPokemonTask.cs" />
     <Compile Include="Tasks\UseIncenseConstantlyTask.cs" />
     <Compile Include="Tasks\UseIncubatorsTask.cs" />
diff --git a/PokemonGo.RocketBot.Logic/Tasks/LevelUpSpecificPokemonTask.cs b/PokemonGo.RocketBot.Logic/Tasks/LevelUpSpecificPokemonTask.cs
new file mode 100644
index 0000000..6442e8f
--- /dev/null
+++ b/PokemonGo.RocketBot.Logic/Tasks/LevelUpSpecificPokemonTask.cs
@@ -0,0 +1,33 @@
+using POGOProtos.Networking.Responses;
+using PokemonGo.RocketBot.Logic.Logging;
+using PokemonGo.RocketBot.Logic.State;
+using PokemonGo.RocketBot.Logic.Utils;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PokemonGo.RocketBot.Logic.Tasks
+{
+    public class LevelUpSpecificPokemonTask
+    {
+        public static async Task Execute(ISession session, ulong pokemonId)
+        {
+            var upgradeResult = await session.Inventory.UpgradePokemon(pokemonId);
+            if (upgradeResult.Result == UpgradePokemonResponse.Types.Result.Success)
+            {
+                Logger.Write("Pokemon Upgraded: " +
+                             session.Translation.GetPokemonTranslation(
+                                 upgradeResult.UpgradedPokemon.PokemonId) + ": " +
+                             upgradeResult.UpgradedPokemon.Cp, LogLevel.LevelUp);
+            }
+            else
+            {
+                Logger.Write("Pokemon Upgrade Failed.", LogLevel.Warning);
+            }
+
+            DelayingUtils.Delay(session.LogicSettings.DelayBetweenPlayerActions, 0);
+        }
+    }
+}
diff --git a/PokemonGo.RocketBot.Logic/Tasks/RecycleSpecificItemTask.cs b/PokemonGo.RocketBot.Logic/Tasks/RecycleSpecificItemTask.cs
new file mode 100644
index 0000000..3b6d753
--- /dev/null
+++ b/PokemonGo.RocketBot.Logic/Tasks/RecycleSpecificItemTask.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PokemonGo.RocketBot.Logic.Logging;
+using PokemonGo.RocketBot.Logic.State;
+using POGOProtos.Inventory.Item;
+using POGOProtos.Networking.Responses;
+
+namespace PokemonGo.RocketBot.Logic.Tasks
+{
+    public class RecycleSpecificItemTask
+    {
+        public static async Task Execute(Session session, ItemId itemId, int count)
+        {
+            var response = await session.Client.Inventory.RecycleItem(itemId, count);
+            if (response.Result == RecycleInventoryItemResponse.Types.Result.Success)
+            {
+                Logger.Write(
+                    $"Recycled {count}x {itemId.ToString().Substring(4)}",
+                    LogLevel.Recycling);
+            }
+            else
+            {
+                Logger.Write(
+                    $"Unable to recycle {count}x {itemId.ToString().Substring(4)}",
+                    LogLevel.Error);
+            }
+        }
+    }
+}
diff --git a/PokemonGo.RocketBot.Logic/Tasks/RenameSpecificPokemonTask.cs b/PokemonGo.RocketBot.Logic/Tasks/RenameSpecificPokemonTask.cs
new file mode 100644
index 0000000..27ea0a0
--- /dev/null
+++ b/PokemonGo.RocketBot.Logic/Tasks/RenameSpecificPokemonTask.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PokemonGo.RocketBot.Logic.State;
+using PokemonGo.RocketBot.Logic.Event;
+using PokemonGo.RocketBot.Logic.Common;
+using POGOProtos.Data;
+using POGOProtos.Networking.Responses;
+using PokemonGo.RocketBot.Logic.Logging;
+using PokemonGo.RocketBot.Logic.Utils;
+
+namespace PokemonGo.RocketBot.Logic.Tasks
+{
+    public class RenameSpecificPokemonTask
+    {
+        public static async Task Execute(Session session, PokemonData pokemon, string newNickname)
+        {
+            //var pkm = pokemon;
+            var response = await session.Client.Inventory.NicknamePokemon(pokemon.Id, newNickname);
+            Logger.Write(response.Result == NicknamePokemonResponse.Types.Result.Success
+                ? $"Successfully renamed {pokemon.PokemonId} to \"{newNickname}\""
+                : $"Failed renaming {pokemon.PokemonId} to \"{newNickname}\"");
+            DelayingUtils.Delay(session.LogicSettings.DelayBetweenPlayerActions, 0);
+            //session.EventDispatcher.Send(new NoticeEvent
+            //{
+            //    Message =
+            //        session.Translation.GetTranslation(TranslationString.PokemonRename,
+            //            session.Translation.GetPokemonTranslation(pokemon.PokemonId),
+            //            pokemon.PokemonId, pkm.Nickname, newNickname)
+            //});
+        }
+    }
+}
diff --git a/PokemonGo.RocketBot.Logic/Tasks/TransferPokemonTask.cs b/PokemonGo.RocketBot.Logic/Tasks/TransferSpecificPokemonTask.cs
similarity index 97%
rename from PokemonGo.RocketBot.Logic/Tasks/TransferPokemonTask.cs
rename to PokemonGo.RocketBot.Logic/Tasks/TransferSpecificPokemonTask.cs
index 0a3e8b0..0480845 100644
--- a/PokemonGo.RocketBot.Logic/Tasks/TransferPokemonTask.cs
+++ b/PokemonGo.RocketBot.Logic/Tasks/TransferSpecificPokemonTask.cs
@@ -11,7 +11,7 @@ using PokemonGo.RocketBot.Logic.Utils;

 namespace PokemonGo.RocketBot.Logic.Tasks
 {
-    public class TransferPokemonTask
+    public class TransferSpecificPokemonTask
     {
         public static async Task Execute(ISession session, ulong pokemonId)
         {
diff --git a/PokemonGo.RocketBot.Logic/Tasks/UseIncenseTask.cs b/PokemonGo.RocketBot.Logic/Tasks/UseIncenseTask.cs
new file mode 100644
index 0000000..d38c9da
--- /dev/null
+++ b/PokemonGo.RocketBot.Logic/Tasks/UseIncenseTask.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PokemonGo.RocketBot.Logic.State;
+using POGOProtos.Networking.Responses;
+using PokemonGo.RocketBot.Logic.Logging;
+using POGOProtos.Inventory.Item;
+
+namespace PokemonGo.RocketBot.Logic.Tasks
+{
+    public class UseIncenseTask
+    {
+        public static async Task Execute(Session session)
+        {
+            var response = await session.Client.Inventory.UseIncense(ItemId.ItemIncenseOrdinary);
+            switch (response.Result)
+            {
+                case UseIncenseResponse.Types.Result.Success:
+                    Logger.Write($"Incense valid until: {DateTime.Now.AddMinutes(30)}");
+                    break;
+                case UseIncenseResponse.Types.Result.IncenseAlreadyActive:
+                    Logger.Write($"An incense is already active!", LogLevel.Warning);
+                    break;
+                case UseIncenseResponse.Types.Result.LocationUnset:
+                    Logger.Write($"Bot must be running first!", LogLevel.Error);
+                    break;
+                case UseIncenseResponse.Types.Result.Unknown:
+                    break;
+                case UseIncenseResponse.Types.Result.NoneInInventory:
+                    break;
+                default:
+                    Logger.Write($"Failed using an incense!", LogLevel.Error);
+                    break;
+            }
+        }
+    }
+}
diff --git a/PokemonGo.RocketBot.Logic/Tasks/UseLuckyEggTask.cs b/PokemonGo.RocketBot.Logic/Tasks/UseLuckyEggTask.cs
new file mode 100644
index 0000000..bd579df
--- /dev/null
+++ b/PokemonGo.RocketBot.Logic/Tasks/UseLuckyEggTask.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PokemonGo.RocketBot.Logic.State;
+using POGOProtos.Networking.Responses;
+using PokemonGo.RocketBot.Logic.Logging;
+
+namespace PokemonGo.RocketBot.Logic.Tasks
+{
+    public class UseLuckyEggTask
+    {
+        public static async Task Execute(Session session)
+        {
+            var response = await session.Client.Inventory.UseItemXpBoost();
+            switch (response.Result)
+            {
+                case UseItemXpBoostResponse.Types.Result.Success:
+                    Logger.Write($"Using a Lucky Egg");
+                    Logger.Write($"Lucky Egg valid until: {DateTime.Now.AddMinutes(30)}");
+                    break;
+                case UseItemXpBoostResponse.Types.Result.ErrorXpBoostAlreadyActive:
+                    Logger.Write($"A Lucky Egg is already active!", LogLevel.Warning);
+                    break;
+                case UseItemXpBoostResponse.Types.Result.ErrorLocationUnset:
+                    Logger.Write($"Bot must be running first!", LogLevel.Error);
+                    break;
+                case UseItemXpBoostResponse.Types.Result.Unset:
+                    break;
+                case UseItemXpBoostResponse.Types.Result.ErrorInvalidItemType:
+                    break;
+                case UseItemXpBoostResponse.Types.Result.ErrorNoItemsRemaining:
+                    break;
+                default:
+                    Logger.Write($"Failed using a Lucky Egg!", LogLevel.Error);
+                    break;
+            }
+        }
+    }
+}
diff --git a/PokemonGo.RocketBot.Window/ConsoleLogger.cs b/PokemonGo.RocketBot.Window/ConsoleLogger.cs
index bbc62e3..c478151 100644
--- a/PokemonGo.RocketBot.Window/ConsoleLogger.cs
+++ b/PokemonGo.RocketBot.Window/ConsoleLogger.cs
@@ -96,6 +96,10 @@ namespace PokemonGo.RocketBot.Window
                     MainForm.ColoredConsoleWrite(Color.Yellow,
                         $"[{DateTime.Now.ToString("HH:mm:ss")}] ({LoggingStrings.Evolved}) {message}");
                     break;
+                case LogLevel.LevelUp:
+                    MainForm.ColoredConsoleWrite(Color.Yellow,
+                        $"[{DateTime.Now.ToString("HH:mm:ss")}] ({LoggingStrings.LevelUp}) {message}");
+                    break;
                 case LogLevel.Berry:
                     MainForm.ColoredConsoleWrite(Color.DarkGoldenrod,
                         $"[{DateTime.Now.ToString("HH:mm:ss")}] ({LoggingStrings.Berry}) {message}");
diff --git a/PokemonGo.RocketBot.Window/Forms/MainForm.cs b/PokemonGo.RocketBot.Window/Forms/MainForm.cs
index 948aa8b..12a43de 100644
--- a/PokemonGo.RocketBot.Window/Forms/MainForm.cs
+++ b/PokemonGo.RocketBot.Window/Forms/MainForm.cs
@@ -602,7 +602,7 @@ namespace PokemonGo.RocketBot.Window.Forms
                 var key = pokemon.PokemonId.ToString();
                 if (!olvPokemonList.SmallImageList.Images.ContainsKey(key))
                 {
-                    var img = GetPokemonImage((int)pokemon.PokemonId);
+                    var img = ResourceHelper.GetPokemonImage((int)pokemon.PokemonId);
                     olvPokemonList.SmallImageList.Images.Add(key, img);
                 }
                 return key;
@@ -731,17 +731,7 @@ namespace PokemonGo.RocketBot.Window.Forms
             SetState(false);
             foreach (var pokemon in pokemons)
             {
-                var transferPokemonResponse = await _session.Client.Inventory.TransferPokemon(pokemon.Id);
-                if (transferPokemonResponse.Result == ReleasePokemonResponse.Types.Result.Success)
-                {
-                    Logger.Write(
-                        $"{pokemon.PokemonId} was transferred. {transferPokemonResponse.CandyAwarded} candy awarded",
-                        LogLevel.Transfer);
-                }
-                else
-                {
-                    Logger.Write($"{pokemon.PokemonId} could not be transferred", LogLevel.Error);
-                }
+                await TransferSpecificPokemonTask.Execute(_session, pokemon.Id);
             }
             await ReloadPokemonList();
         }
@@ -751,15 +741,7 @@ namespace PokemonGo.RocketBot.Window.Forms
             SetState(false);
             foreach (var pokemon in pokemons)
             {
-                var evolvePokemonResponse = await _session.Client.Inventory.UpgradePokemon(pokemon.Id);
-                if (evolvePokemonResponse.Result == UpgradePokemonResponse.Types.Result.Success)
-                {
-                    Logger.Write($"{pokemon.PokemonId} successfully upgraded.");
-                }
-                else
-                {
-                    Logger.Write($"{pokemon.PokemonId} could not be upgraded");
-                }
+                await LevelUpSpecificPokemonTask.Execute(_session, pokemon.Id);
             }
             await ReloadPokemonList();
         }
@@ -769,16 +751,7 @@ namespace PokemonGo.RocketBot.Window.Forms
             SetState(false);
             foreach (var pokemon in pokemons)
             {
-                var evolvePokemonResponse = await _session.Client.Inventory.EvolvePokemon(pokemon.Id);
-                if (evolvePokemonResponse.Result == EvolvePokemonResponse.Types.Result.Success)
-                {
-                    Logger.Write(
-                        $"{pokemon.PokemonId} successfully evolved into {evolvePokemonResponse.EvolvedPokemonData.PokemonId}\n{evolvePokemonResponse.ExperienceAwarded} experience awarded\n{evolvePokemonResponse.CandyAwarded} candy awarded");
-                }
-                else
-                {
-                    Logger.Write($"{pokemon.PokemonId} could not be evolved");
-                }
+                await EvolveSpecificPokemonTask.Execute(_session, pokemon.Id);
             }
             await ReloadPokemonList();
         }
@@ -886,25 +859,11 @@ namespace PokemonGo.RocketBot.Window.Forms
                     }
                     continue;
                 }
-                var response = await _session.Client.Inventory.NicknamePokemon(pokemon.Id, newName.ToString());
-                if (response.Result == NicknamePokemonResponse.Types.Result.Success)
-                {
-                    Logger.Write($"Successfully renamed {pokemon.PokemonId} to \"{newName}\"");
-                }
-                else
-                {
-                    Logger.Write($"Failed renaming {pokemon.PokemonId} to \"{newName}\"");
-                }
-                await Task.Delay(1500);
+                await RenameSpecificPokemonTask.Execute(_session, pokemon, nickname);
             }
             await ReloadPokemonList();
         }

-        private Image GetPokemonImage(int pokemonId)
-        {
-            return ResourceHelper.GetImage("Pokemon_" + pokemonId);
-        }
-
         private async Task ReloadPokemonList()
         {
             SetState(false);
@@ -1016,29 +975,7 @@ namespace PokemonGo.RocketBot.Window.Forms
                                 SetState(true);
                                 return;
                             }
-                            var response = await _session.Client.Inventory.UseItemXpBoost();
-                            switch (response.Result)
-                            {
-                                case UseItemXpBoostResponse.Types.Result.Success:
-                                    Logger.Write($"Using a Lucky Egg");
-                                    Logger.Write($"Lucky Egg valid until: {DateTime.Now.AddMinutes(30)}");
-                                    break;
-                                case UseItemXpBoostResponse.Types.Result.ErrorXpBoostAlreadyActive:
-                                    Logger.Write($"A Lucky Egg is already active!", LogLevel.Warning);
-                                    break;
-                                case UseItemXpBoostResponse.Types.Result.ErrorLocationUnset:
-                                    Logger.Write($"Bot must be running first!", LogLevel.Error);
-                                    break;
-                                case UseItemXpBoostResponse.Types.Result.Unset:
-                                    break;
-                                case UseItemXpBoostResponse.Types.Result.ErrorInvalidItemType:
-                                    break;
-                                case UseItemXpBoostResponse.Types.Result.ErrorNoItemsRemaining:
-                                    break;
-                                default:
-                                    Logger.Write($"Failed using a Lucky Egg!", LogLevel.Error);
-                                    break;
-                            }
+                            await UseLuckyEggTask.Execute(_session);
                         }
                         break;
                     case ItemId.ItemIncenseOrdinary:
@@ -1049,101 +986,12 @@ namespace PokemonGo.RocketBot.Window.Forms
                                 SetState(true);
                                 return;
                             }
-                            var response = await _session.Client.Inventory.UseIncense(ItemId.ItemIncenseOrdinary);
-                            switch (response.Result)
-                            {
-                                case UseIncenseResponse.Types.Result.Success:
-                                    Logger.Write($"Incense valid until: {DateTime.Now.AddMinutes(30)}");
-                                    break;
-                                case UseIncenseResponse.Types.Result.IncenseAlreadyActive:
-                                    Logger.Write($"An incense is already active!", LogLevel.Warning);
-                                    break;
-                                case UseIncenseResponse.Types.Result.LocationUnset:
-                                    Logger.Write($"Bot must be running first!", LogLevel.Error);
-                                    break;
-                                case UseIncenseResponse.Types.Result.Unknown:
-                                    break;
-                                case UseIncenseResponse.Types.Result.NoneInInventory:
-                                    break;
-                                default:
-                                    Logger.Write($"Failed using an incense!", LogLevel.Error);
-                                    break;
-                            }
+                            await UseIncenseTask.Execute(_session);
                         }
                         break;
-                    case ItemId.ItemUnknown:
-                        break;
-                    case ItemId.ItemPokeBall:
-                        break;
-                    case ItemId.ItemGreatBall:
-                        break;
-                    case ItemId.ItemUltraBall:
-                        break;
-                    case ItemId.ItemMasterBall:
-                        break;
-                    case ItemId.ItemPotion:
-                        break;
-                    case ItemId.ItemSuperPotion:
-                        break;
-                    case ItemId.ItemHyperPotion:
-                        break;
-                    case ItemId.ItemMaxPotion:
-                        break;
-                    case ItemId.ItemRevive:
-                        break;
-                    case ItemId.ItemMaxRevive:
-                        break;
-                    case ItemId.ItemIncenseSpicy:
-                        break;
-                    case ItemId.ItemIncenseCool:
-                        break;
-                    case ItemId.ItemIncenseFloral:
-                        break;
-                    case ItemId.ItemTroyDisk:
-                        break;
-                    case ItemId.ItemXAttack:
-                        break;
-                    case ItemId.ItemXDefense:
-                        break;
-                    case ItemId.ItemXMiracle:
-                        break;
-                    case ItemId.ItemRazzBerry:
-                        break;
-                    case ItemId.ItemBlukBerry:
-                        break;
-                    case ItemId.ItemNanabBerry:
-                        break;
-                    case ItemId.ItemWeparBerry:
-                        break;
-                    case ItemId.ItemPinapBerry:
-                        break;
-                    case ItemId.ItemSpecialCamera:
-                        break;
-                    case ItemId.ItemIncubatorBasicUnlimited:
-                        break;
-                    case ItemId.ItemIncubatorBasic:
-                        break;
-                    case ItemId.ItemPokemonStorageUpgrade:
-                        break;
-                    case ItemId.ItemItemStorageUpgrade:
-                        break;
                     default:
                         {
-                            var response =
-                                await
-                                    _session.Client.Inventory.RecycleItem(item.ItemId, decimal.ToInt32(form.numCount.Value));
-                            if (response.Result == RecycleInventoryItemResponse.Types.Result.Success)
-                            {
-                                Logger.Write(
-                                    $"Recycled {decimal.ToInt32(form.numCount.Value)}x {item.ItemId.ToString().Substring(4)}",
-                                    LogLevel.Recycling);
-                            }
-                            else
-                            {
-                                Logger.Write(
-                                    $"Unable to recycle {decimal.ToInt32(form.numCount.Value)}x {item.ItemId.ToString().Substring(4)}",
-                                    LogLevel.Error);
-                            }
+                            await RecycleSpecificItemTask.Execute(_session, item.ItemId, decimal.ToInt32(form.numCount.Value));
                         }
                         break;
                 }
diff --git a/PokemonGo.RocketBot.Window/Helpers/ResourceHelper.cs b/PokemonGo.RocketBot.Window/Helpers/ResourceHelper.cs
index 9ea7874..6d7cc4b 100644
--- a/PokemonGo.RocketBot.Window/Helpers/ResourceHelper.cs
+++ b/PokemonGo.RocketBot.Window/Helpers/ResourceHelper.cs
@@ -7,18 +7,18 @@ namespace PokemonGo.RocketBot.Window.Helpers
     {
         public static Image GetImage(string name)
         {
-            return (Image) Properties.Resources.ResourceManager.GetObject(name);
+            return (Image)Properties.Resources.ResourceManager.GetObject(name);
         }

         public static Image GetImage(string name, int maxHeight, int maxWidth)
         {
             var image = GetImage(name);
-            var ratioX = (double) maxWidth/image.Width;
-            var ratioY = (double) maxHeight/image.Height;
+            var ratioX = (double)maxWidth / image.Width;
+            var ratioY = (double)maxHeight / image.Height;
             var ratio = Math.Min(ratioX, ratioY);

-            var newWidth = (int) (image.Width*ratio);
-            var newHeight = (int) (image.Height*ratio);
+            var newWidth = (int)(image.Width * ratio);
+            var newHeight = (int)(image.Height * ratio);

             var newImage = new Bitmap(newWidth, newHeight);

@@ -27,5 +27,10 @@ namespace PokemonGo.RocketBot.Window.Helpers

             return newImage;
         }
+
+        public static Image GetPokemonImage(int pokemonId)
+        {
+            return GetImage("Pokemon_" + pokemonId);
+        }
     }
 }
\ No newline at end of file
diff --git a/PokemonGo.RocketBot.Window/Models/LoggingStrings.cs b/PokemonGo.RocketBot.Window/Models/LoggingStrings.cs
index 38e166d..8388572 100644
--- a/PokemonGo.RocketBot.Window/Models/LoggingStrings.cs
+++ b/PokemonGo.RocketBot.Window/Models/LoggingStrings.cs
@@ -17,6 +17,8 @@ namespace PokemonGo.RocketBot.Window.Models

         internal static string Evolved;

+        internal static string LevelUp;
+
         internal static string Farming;

         internal static string Info;
@@ -63,6 +65,10 @@ namespace PokemonGo.RocketBot.Window.Models
                 session?.Translation.GetTranslation(
                     TranslationString.LogEntryEvolved) ?? "EVOLVED";

+            LevelUp =
+                 session?.Translation.GetTranslation(
+                    TranslationString.LogEntryLevelUp) ?? "LEVELUP";
+
             Farming =
                 session?.Translation.GetTranslation(
                     TranslationString.LogEntryFarming) ?? "FARMING";
diff --git a/PokemonGo.RocketBot.Window/PokemonGo.RocketBot.Window.csproj b/PokemonGo.RocketBot.Window/PokemonGo.RocketBot.Window.csproj
index 4ce519b..4dfaafe 100644
--- a/PokemonGo.RocketBot.Window/PokemonGo.RocketBot.Window.csproj
+++ b/PokemonGo.RocketBot.Window/PokemonGo.RocketBot.Window.csproj
@@ -103,10 +103,42 @@
       <HintPath>..\packages\GMap.NET.WindowsForms.1.7.1\lib\net40\GMap.NET.WindowsForms.dll</HintPath>
       <Private>True</Private>
     </Reference>
+    <Reference Include="Google.Apis, Version=1.16.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Apis.1.16.0\lib\net45\Google.Apis.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Google.Apis.Auth, Version=1.16.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Apis.Auth.1.16.0\lib\net45\Google.Apis.Auth.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.16.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Apis.Auth.1.16.0\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Google.Apis.Core, Version=1.16.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Apis.Core.1.16.0\lib\net45\Google.Apis.Core.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Google.Apis.PlatformServices, Version=1.16.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Apis.1.16.0\lib\net45\Google.Apis.PlatformServices.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
     <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
       <HintPath>..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll</HintPath>
       <Private>True</Private>
     </Reference>
+    <Reference Include="MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a, processorArchitecture=MSIL">
+      <HintPath>..\packages\MetroModernUI.1.4.0.0\lib\net\MetroFramework.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="MetroFramework.Design, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a, processorArchitecture=MSIL">
+      <HintPath>..\packages\MetroModernUI.1.4.0.0\lib\net\MetroFramework.Design.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="MetroFramework.Fonts, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a, processorArchitecture=MSIL">
+      <HintPath>..\packages\MetroModernUI.1.4.0.0\lib\net\MetroFramework.Fonts.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
     <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
       <HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
       <Private>True</Private>
diff --git a/PokemonGo.RocketBot.Window/WebSocketHandler/ActionCommands/TransferPokemonHandler.cs b/PokemonGo.RocketBot.Window/WebSocketHandler/ActionCommands/TransferPokemonHandler.cs
index 70ded15..9a5d172 100644
--- a/PokemonGo.RocketBot.Window/WebSocketHandler/ActionCommands/TransferPokemonHandler.cs
+++ b/PokemonGo.RocketBot.Window/WebSocketHandler/ActionCommands/TransferPokemonHandler.cs
@@ -16,7 +16,7 @@ namespace PokemonGo.RocketBot.Window.WebSocketHandler.ActionCommands

         public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message)
         {
-            await TransferPokemonTask.Execute(session, (ulong) message.PokemonId);
+            await TransferSpecificPokemonTask.Execute(session, (ulong) message.PokemonId);
         }
     }
 }
\ No newline at end of file
You may download the files in Public Git.