private async Task <bool> RepairItems(Game game, MovementMode movementMode)
        {
            if (NPCHelpers.ShouldGoToRepairNPC(game))
            {
                var repairNPC = NPCHelpers.GetRepairNPC(game.Act);
                Log.Information($"Client {game.Me.Name} moving to {repairNPC} for repair/arrows");
                var pathRepairNPC = repairNPC == NPCCode.Hratli ? await _pathingService.GetPathToObject(game, EntityCode.Hratli, movementMode)
                 : await _pathingService.GetPathToNPC(game.MapId, Difficulty.Normal, WayPointHelpers.MapTownArea(game.Act), game.Me.Location, repairNPC, movementMode);

                if (pathRepairNPC.Count > 0 && await MovementHelpers.TakePathOfLocations(game, pathRepairNPC, movementMode))
                {
                    var uniqueNPC = NPCHelpers.GetUniqueNPC(game, repairNPC);
                    if (uniqueNPC == null)
                    {
                        Log.Warning($"Client {game.Me.Name} Did not find {repairNPC} at {game.Me.Location}");
                        return(false);
                    }

                    if (!NPCHelpers.RepairItemsAndBuyArrows(game, uniqueNPC))
                    {
                        Log.Warning($"Client {game.Me.Name} Selling items and refreshing potions to {repairNPC} failed at {game.Me.Location}");
                    }
                }
                else
                {
                    Log.Warning($"Client {game.Me.Name} {movementMode} to {repairNPC} failed at {game.Me.Location}");
                }
            }

            return(true);
        }
        private async Task <bool> IdentifyItems(Game game, MovementMode movementMode)
        {
            var unidentifiedItemCount = game.Inventory.Items.Count(i => !i.IsIdentified) +
                                        game.Cube.Items.Count(i => !i.IsIdentified);

            if (unidentifiedItemCount > 6)
            {
                Log.Information($"Visiting Deckard Cain with {unidentifiedItemCount} unidentified items");
                var deckhardCainCode = NPCHelpers.GetDeckardCainForAct(game.Act);

                var deckardCain     = NPCHelpers.GetUniqueNPC(game, deckhardCainCode);
                var pathDeckardCain = new List <Point>();
                if (deckardCain != null)
                {
                    pathDeckardCain = await _pathingService.GetPathToLocation(game.MapId, Difficulty.Normal, WayPointHelpers.MapTownArea(game.Act), game.Me.Location, deckardCain.Location, movementMode);
                }
                else
                {
                    pathDeckardCain = await _pathingService.GetPathToNPC(game.MapId, Difficulty.Normal, WayPointHelpers.MapTownArea(game.Act), game.Me.Location, deckhardCainCode, movementMode);
                }

                if (!await MovementHelpers.TakePathOfLocations(game, pathDeckardCain, movementMode))
                {
                    Log.Warning($"Client {game.Me.Name} {movementMode} to deckard cain failed at {game.Me.Location}");
                    return(false);
                }

                return(NPCHelpers.IdentifyItemsAtDeckardCain(game));
            }

            return(true);
        }
        private async Task <bool> RefreshAndSellItems(Game game, MovementMode movementMode, TownManagementOptions options)
        {
            var sellItemCount = game.Inventory.Items.Count(i => !Pickit.Pickit.ShouldKeepItem(game, i)) + game.Cube.Items.Count(i => !Pickit.Pickit.ShouldKeepItem(game, i));

            if (NPCHelpers.ShouldRefreshCharacterAtNPC(game) || sellItemCount > 5 || options.ItemsToBuy?.Count > 0)
            {
                var sellNpc = NPCHelpers.GetSellNPC(game.Act);
                Log.Information($"Client {game.Me.Name} moving to {sellNpc} for refresh and selling {sellItemCount} items");
                var pathSellNPC = await _pathingService.GetPathToNPC(game.MapId, Difficulty.Normal, WayPointHelpers.MapTownArea(game.Act), game.Me.Location, sellNpc, movementMode);

                if (pathSellNPC.Count > 0 && await MovementHelpers.TakePathOfLocations(game, pathSellNPC, movementMode))
                {
                    var uniqueNPC = NPCHelpers.GetUniqueNPC(game, sellNpc);
                    if (uniqueNPC == null)
                    {
                        Log.Warning($"Client {game.Me.Name} Did not find {sellNpc} at {game.Me.Location}");
                        return(false);
                    }

                    if (!NPCHelpers.SellItemsAndRefreshPotionsAtNPC(game, uniqueNPC, options.ItemsToBuy))
                    {
                        Log.Warning($"Client {game.Me.Name} Selling items and refreshing potions failed at {game.Me.Location}");
                        return(false);
                    }
                }
                else
                {
                    Log.Warning($"Client {game.Me.Name} {movementMode} to {sellNpc} failed at {game.Me.Location}");
                    return(false);
                }
            }

            return(true);
        }
        public async Task <bool> PerformTownTasks(Client client, TownManagementOptions options)
        {
            var game         = client.Game;
            var movementMode = GetMovementMode(game);

            game.CleanupCursorItem();
            InventoryHelpers.CleanupPotionsInBelt(game);

            if (client.Game.Me.Class == CharacterClass.Paladin && client.Game.Me.HasSkill(Skill.Vigor))
            {
                client.Game.ChangeSkill(Skill.Vigor, Hand.Right);
            }

            if (!await GeneralHelpers.PickupCorpseIfExists(client, _pathingService))
            {
                Log.Error($"{client.Game.Me.Name} failed to pickup corpse");
                return(false);
            }

            if (client.Game.Act != options.Act)
            {
                var targetTownArea     = WayPointHelpers.MapTownArea(options.Act);
                var pathToTownWayPoint = await _pathingService.ToTownWayPoint(client.Game, movementMode);

                if (!await MovementHelpers.TakePathOfLocations(client.Game, pathToTownWayPoint, movementMode))
                {
                    Log.Warning($"Teleporting to {client.Game.Act} waypoint failed");
                    return(false);
                }

                var townWaypoint = client.Game.GetEntityByCode(client.Game.Act.MapTownWayPointCode()).Single();
                Log.Information($"Taking waypoint to {targetTownArea}");
                if (!GeneralHelpers.TryWithTimeout((_) =>
                {
                    client.Game.TakeWaypoint(townWaypoint, options.Act.MapTownWayPoint());
                    return(GeneralHelpers.TryWithTimeout((_) => client.Game.Area == targetTownArea, TimeSpan.FromSeconds(2)));
                }, TimeSpan.FromSeconds(5)))
                {
                    Log.Information($"Moving to {options.Act} failed");
                    return(false);
                }
            }

            var townArea = WayPointHelpers.MapTownArea(game.Act);

            if (!await IdentifyItems(game, movementMode))
            {
                return(false);
            }

            if (!await RefreshAndSellItems(game, movementMode, options))
            {
                return(false);
            }

            if (!await RepairItems(game, movementMode))
            {
                return(false);
            }

            if (InventoryHelpers.HasAnyItemsToStash(client.Game))
            {
                var pathStash = await _pathingService.GetPathToObject(game.MapId, Difficulty.Normal, townArea, game.Me.Location, EntityCode.Stash, movementMode);

                if (!await MovementHelpers.TakePathOfLocations(game, pathStash, movementMode))
                {
                    Log.Warning($"{movementMode} failed at location {game.Me.Location}");
                }

                var stashItemsResult = InventoryHelpers.StashItemsToKeep(game, _externalMessagingClient);
                if (stashItemsResult != Enums.MoveItemResult.Succes)
                {
                    Log.Warning($"Stashing items failed with result {stashItemsResult}");
                }
            }

            if (CubeHelpers.AnyGemsToTransmuteInStash(client.Game))
            {
                var pathStash = await _pathingService.GetPathToObject(game.MapId, Difficulty.Normal, townArea, game.Me.Location, EntityCode.Stash, movementMode);

                if (!await MovementHelpers.TakePathOfLocations(game, pathStash, movementMode))
                {
                    Log.Warning($"{movementMode} failed at location {game.Me.Location}");
                }
                CubeHelpers.TransmuteGems(client.Game);
            }

            if (!await GambleItems(client, movementMode))
            {
                return(false);
            }

            return(true);
        }