/// <summary>
 /// Attempts to use an item on a world location.
 /// </summary>
 /// <param name="itemid">The item's ID.</param>
 /// <param name="loc">The world location to use the item on.</param>
 public void HotkeyUseItemOnLocation(ushort itemid, Objects.Location loc)
 {
     if (itemid == 0 || !loc.IsValid())
     {
         return;
     }
 }
 /// <summary>
 /// Attempts to use an item on a world location.
 /// If possible, use UseItemOnTile instead, as it provides better performance.
 /// </summary>
 /// <param name="itemLocation">The item's location.</param>
 /// <param name="loc">The world location to use the item on.</param>
 public void UseItemOnLocation(Objects.ItemLocation itemLocation, Objects.Location loc)
 {
     if (itemLocation == null || !loc.IsValid())
     {
         return;
     }
     this.UseItemOnTile(itemLocation, this.Client.Map.GetTile(loc, null));
 }
Exemple #3
0
        /// <summary>
        /// Gets a memory location based on a world location.
        /// </summary>
        /// <param name="memoryLocation">The memory location to use as reference.</param>
        /// <param name="playerTile">The player's tile to use as reference.</param>
        /// <returns></returns>
        private Objects.Location MemoryLocationToWorldLocation(Objects.Location memoryLocation, Map.Tile playerTile)
        {
            if (playerTile == null || !memoryLocation.IsValid())
            {
                return(Objects.Location.Invalid);
            }

            Objects.Location playerMemLoc = playerTile.MemoryLocation;
            return(playerTile.WorldLocation.Offset(memoryLocation.X - playerMemLoc.X,
                                                   memoryLocation.Y - playerMemLoc.Y,
                                                   memoryLocation.Z - playerMemLoc.Z));

            /*Objects.Location loc = Objects.Location.Invalid;
             * if (playerTile == null) return loc;
             *
             * // get the center of a "screen"
             * // keep in mind that memory locations are zero-based
             * int centerX = Constants.Map.MaxX / 2 - 1,
             *  centerY = Constants.Map.MaxY / 2 - 1;
             *
             * loc = new Objects.Location(memoryLocation.X, memoryLocation.Y, memoryLocation.Z);
             * Objects.Location playerMemLoc = playerTile.MemoryLocation;
             *
             * // get and apply diffs
             * int diffX = centerX - playerMemLoc.X;
             * int diffY = centerY - playerMemLoc.Y;
             * loc.X += diffX;
             * loc.Y += diffY;
             *
             * // re-align values if they are out of range
             * int maxX = Constants.Map.MaxX - 1;
             * int maxY = Constants.Map.MaxY - 1;
             * if (loc.X > maxX) loc.X -= Constants.Map.MaxX;
             * else if (loc.X < 0) loc.X += Constants.Map.MaxX;
             * if (loc.Y > maxY) loc.Y -= Constants.Map.MaxY;
             * else if (loc.Y < 0) loc.Y += Constants.Map.MaxY;
             *
             * // finally align to the player's world location
             * Objects.Location playerLoc = playerTile.WorldLocation;
             * return playerLoc.Offset(loc.X - centerX, loc.Y - centerY, loc.Z - playerMemLoc.Z);*/
        }
Exemple #4
0
            /// <summary>
            /// Attempts to get the best location to move to. Returns Objects.Location.Invalid if unsuccessful.
            /// </summary>
            /// <param name="setting">The setting to use.</param>
            /// <param name="tileCollection">The tiles that are visible on screen.</param>
            /// <param name="creaturesOnScreen">The creatures that are visible on screen.</param>
            /// <returns></returns>
            public Objects.Location GetBestLocation(Target.Setting setting, Map.TileCollection tileCollection,
                                                    IEnumerable <Objects.Creature> creaturesOnScreen, Stack <Objects.Location> backtrackedLocations = null)
            {
                if (this.Creature == null)
                {
                    return(null);
                }
                Map.Tile playerTile = tileCollection.GetTile(count: this.Parent.Client.Player.ID),
                         targetTile = tileCollection.GetTile(count: this.Creature.ID);
                if (playerTile == null || targetTile == null)
                {
                    return(null);
                }
                Map.TileCollection             adjacentTiles = tileCollection.GetAdjacentTileCollection(targetTile);
                List <Objects.PathFinder.Node> pfNodes       = null;
                int closest = 15;

                Objects.Location bestLocation = Objects.Location.Invalid;
                switch (setting.FightStance)
                {
                case Enums.FightStance.FollowDiagonalOnly:
                    if (playerTile.WorldLocation.IsAdjacentDiagonalOnly(targetTile.WorldLocation))
                    {
                        break;
                    }
                    int closestNonDiagonal = 15;
                    Objects.Location bestNonDiagonalLocation = Objects.Location.Invalid;
                    foreach (Map.Tile tile in adjacentTiles.GetTiles())
                    {
                        if (!tile.IsWalkable())
                        {
                            continue;
                        }
                        //if (!tile.WorldLocation.IsAdjacentDiagonalOnly(targetTile.WorldLocation)) continue;
                        pfNodes = playerTile.WorldLocation.GetTilesToLocation(this.Parent.Client,
                                                                              tile.WorldLocation, tileCollection, this.Parent.PathFinder, true).ToList <Objects.PathFinder.Node>();
                        if (pfNodes.Count > 0)
                        {
                            if (this.Parent.CurrentSettings.AllowDiagonalMovement &&
                                playerTile.WorldLocation.IsAdjacentDiagonalOnly(targetTile.WorldLocation))
                            {
                                continue;
                            }

                            if (pfNodes.Count - 1 < closest &&
                                tile.WorldLocation.IsAdjacentDiagonalOnly(targetTile.WorldLocation))
                            {
                                closest      = pfNodes.Count - 1;
                                bestLocation = tile.WorldLocation;
                            }
                            else if (pfNodes.Count - 1 < closestNonDiagonal &&
                                     tile.WorldLocation.IsAdjacentNonDiagonalOnly(targetTile.WorldLocation))
                            {
                                closestNonDiagonal      = pfNodes.Count - 1;
                                bestNonDiagonalLocation = tile.WorldLocation;
                            }
                        }
                    }
                    if (!bestLocation.IsValid())
                    {
                        bestLocation = bestNonDiagonalLocation;
                    }
                    break;

                case Enums.FightStance.FollowStrike:
                    if (playerTile.WorldLocation.IsAdjacentNonDiagonalOnly(targetTile.WorldLocation))
                    {
                        break;
                    }
                    foreach (Map.Tile tile in adjacentTiles.GetTiles())
                    {
                        if (!tile.WorldLocation.IsAdjacentNonDiagonalOnly(targetTile.WorldLocation))
                        {
                            continue;
                        }
                        pfNodes = playerTile.WorldLocation.GetTilesToLocation(this.Parent.Client,
                                                                              tile.WorldLocation, tileCollection, this.Parent.PathFinder, true).ToList <Objects.PathFinder.Node>();
                        if (pfNodes.Count > 0 && pfNodes.Count - 1 < closest &&
                            (!this.Parent.CurrentSettings.AllowDiagonalMovement ||
                             playerTile.WorldLocation.IsAdjacentDiagonalOnly(targetTile.WorldLocation)))
                        {
                            closest      = pfNodes.Count - 1;
                            bestLocation = tile.WorldLocation;
                        }
                    }
                    break;

                case Enums.FightStance.DistanceFollow:
                case Enums.FightStance.DistanceWait:
                    // map creature tiles and the path nodes to them from the player
                    Dictionary <Map.Tile, List <Objects.PathFinder.Node> > creatureTiles =
                        new Dictionary <Map.Tile, List <Objects.PathFinder.Node> >();
                    // add the current target
                    creatureTiles.Add(targetTile,
                                      this.Creature.GetTilesToCreature(tileCollection, this.Parent.PathFinder).ToList <Objects.PathFinder.Node>());
                    // check whether to add other monsters as well
                    if (this.Parent.CurrentSettings.ConsiderAllMonstersWhenKeepingAway)
                    {
                        foreach (Objects.Creature c in creaturesOnScreen)
                        {
                            Map.Tile t = tileCollection.GetTile(count: c.ID);
                            if (t != null && !creatureTiles.ContainsKey(t))
                            {
                                creatureTiles.Add(t,
                                                  c.GetTilesToCreature(tileCollection, this.Parent.PathFinder).ToList <Objects.PathFinder.Node>());
                            }
                        }
                    }

                    // check if the player needs to move
                    // also set the player's location as default location to return
                    bool needToMove = false;
                    bestLocation = playerTile.WorldLocation;
                    foreach (var keypair in creatureTiles)
                    {
                        // check if creature can reach the player
                        if (keypair.Value.Count == 0)
                        {
                            continue;
                        }

                        if (keypair.Value.Count < setting.DistanceRange ||
                            (setting.FightStance == Enums.FightStance.DistanceFollow && keypair.Value.Count > setting.DistanceRange))
                        {
                            needToMove = true;
                        }
                    }
                    if (!needToMove)
                    {
                        break;
                    }

                    int      bestRange = 1;
                    Map.Tile bestTile  = playerTile;
                    // calculate distance to the player's tile
                    foreach (var keypair in creatureTiles)
                    {
                        pfNodes = keypair.Value;
                        if (pfNodes.Count == 0)
                        {
                            continue;
                        }
                        int count = pfNodes.Count;
                        bestRange += Math.Abs(setting.DistanceRange - count) * (count < setting.DistanceRange ? 2 : 1);
                    }

                    if (backtrackedLocations != null && backtrackedLocations.Count > 0)
                    {
                        Objects.Location peekLoc = backtrackedLocations.Peek();
                        if (peekLoc.IsOnScreen(playerTile.WorldLocation))
                        {
                            bestLocation = peekLoc;
                            break;
                        }
                    }
                    // calculate and set
                    foreach (Map.Tile t in tileCollection.GetAdjacentTileCollection(playerTile).GetTiles())
                    {
                        if (t == null || !t.IsWalkable())
                        {
                            continue;
                        }
                        if (this.Parent.CurrentSettings.AllowDiagonalMovement &&
                            playerTile.WorldLocation.IsAdjacentDiagonalOnly(t.WorldLocation))
                        {
                            continue;
                        }

                        // calculate distance for creatures
                        int distance = 0;
                        foreach (var keypair in creatureTiles)
                        {
                            pfNodes = keypair.Key.WorldLocation.GetTilesToLocation(this.Parent.Client, t.WorldLocation,
                                                                                   tileCollection, this.Parent.PathFinder, true).ToList <Objects.PathFinder.Node>();
                            if (pfNodes.Count == 0)
                            {
                                continue;
                            }
                            int count = pfNodes.Count - 1;
                            distance += Math.Abs(setting.DistanceRange - count) * (count < setting.DistanceRange ? 2 : 1);
                        }

                        // get next tile in same general direction
                        bool good       = false;
                        int  directionX = playerTile.WorldLocation.X - t.WorldLocation.X,
                             directionY = playerTile.WorldLocation.Y - t.WorldLocation.Y;
                        foreach (Map.Tile nextTile in tileCollection.GetAdjacentTileCollection(t).GetTiles())
                        {
                            if (nextTile == null || !nextTile.IsWalkable())
                            {
                                continue;
                            }
                            if (t.WorldLocation.X - nextTile.WorldLocation.X != directionX &&
                                t.WorldLocation.Y - nextTile.WorldLocation.Y != directionY)
                            {
                                continue;
                            }
                            if (nextTile == playerTile)
                            {
                                continue;
                            }

                            good = true;
                            break;
                        }
                        if (!good)
                        {
                            continue;
                        }

                        // check of tile is better than previous tile
                        if (bestRange > distance)
                        {
                            bestRange    = distance;
                            bestLocation = t.WorldLocation;
                        }
                    }
                    break;

                case Enums.FightStance.FollowEconomic:
                    break;
                }
                return(bestLocation);
            }
Exemple #5
0
            private void Run()
            {
                while (true)
                {
                    try
                    {
                        this.ResetEvent.Wait();
                        if (this.TargetExecutedBegin != null)
                        {
                            this.TargetExecutedBegin(this.CurrentTarget);
                        }

                        Objects.Client   client      = this.Parent.Client;
                        Objects.Creature oldCreature = null;

                        while (!this.Cancel)
                        {
                            this.ResetEventCacheUpdated.WaitOne();

                            if (this.Cancel)
                            {
                                break;
                            }

                            // get best setting
                            Target.Setting setting = this.CurrentTarget.GetBestSetting(this.CachedCreatures,
                                                                                       this.CachedPlayers, this.CachedTiles, true);
                            if (setting == null)
                            {
                                break;
                            }

                            // check if we should revert to older creature if sticky is on
                            // or if new creature is in no better position
                            if (oldCreature != null &&
                                oldCreature != this.CurrentTarget.Creature &&
                                oldCreature.IsVisible &&
                                client.Player.Location.IsOnScreen(oldCreature.Location))
                            {
                                if (this.Parent.CurrentSettings.StickToCreature)
                                {
                                    this.CurrentTarget.Creature = oldCreature;
                                }
                                else
                                {
                                    int oldDist = (int)client.Player.Location.DistanceTo(oldCreature.Location),
                                        newDist = this.CurrentTarget.Creature != null ?
                                                  (int)client.Player.Location.DistanceTo(this.CurrentTarget.Creature.Location) :
                                                  100;
                                    if (oldDist < newDist + 2)
                                    {
                                        this.CurrentTarget.Creature = oldCreature;
                                    }
                                }
                            }
                            oldCreature = this.CurrentTarget.Creature;

                            Objects.Location playerLoc = client.Player.Location,
                                             targetLoc = this.CurrentTarget.Creature.Location;

                            #region targeting checks and whatnot
                            // check if the creature is dead
                            if (this.CurrentTarget.Creature.IsDead)
                            {
                                break;
                            }

                            // check if creature is about to become a corpse
                            if (this.CurrentTarget.Creature.IsVisible &&
                                this.CurrentTarget.Creature.HealthPercent == 0)
                            {
                                continue;
                            }

                            // check if creature is still on screen, stop attacking and looping if so
                            if (!playerLoc.IsOnScreen(targetLoc))
                            {
                                this.CancelAttack();
                                break;
                            }

                            // check if creature if reachable and/or shootable
                            // stop attacking and break if settings says they must be
                            if ((setting.MustBeReachable && !this.CurrentTarget.Creature.IsReachable(this.CachedTiles, this.Parent.PathFinder)) ||
                                (setting.MustBeShootable && !this.CurrentTarget.Creature.IsShootable(this.CachedTiles)))
                            {
                                this.CancelAttack();
                                break;
                            }

                            // check if player is attacking the wrong target
                            if (client.Player.Target != this.CurrentTarget.Creature.ID)
                            {
                                this.CurrentTarget.Creature.Attack();
                                Thread.Sleep(100);
                            }

                            // set fight stance+mode and move accordingly
                            Map.Tile playerTile   = this.CachedTiles.GetTile(count: client.Player.ID),
                                     creatureTile = this.CachedTiles.GetTile(count: this.CurrentTarget.Creature.ID);
                            if (playerTile == null || creatureTile == null)
                            {
                                this.CancelAttack();
                                break;
                            }
                            switch (setting.FightStance)
                            {
                            case Enums.FightStance.Stand:
                                if (client.Player.FightStance != Enums.FightStance.Stand)
                                {
                                    client.Player.FightStance = Enums.FightStance.Stand;
                                }
                                break;

                            case Enums.FightStance.Follow:
                                if (client.Player.FightStance != Enums.FightStance.Follow)
                                {
                                    client.Player.FightStance = Enums.FightStance.Follow;
                                }
                                break;

                            case Enums.FightStance.FollowDiagonalOnly:
                            case Enums.FightStance.DistanceFollow:
                            case Enums.FightStance.DistanceWait:
                            case Enums.FightStance.FollowStrike:
                                if (client.Player.FightStance != Enums.FightStance.Stand)
                                {
                                    client.Player.FightStance = Enums.FightStance.Stand;
                                }
                                if (client.Player.IsWalking)
                                {
                                    break;
                                }
                                Objects.Location bestLoc = this.CurrentTarget.GetBestLocation(setting, this.CachedTiles, this.CachedCreatures);
                                if (bestLoc.IsValid() && client.Player.GoTo != bestLoc)
                                {
                                    client.Player.GoTo = bestLoc;
                                }
                                break;
                            }

                            // shoot rune or spell
                            if (client.Player.HealthPercent >= this.Parent.CurrentSettings.MinimumHealthToShoot &&
                                this.CurrentTarget.Creature.HealthPercent > 0)
                            {
                                ushort runeID = 0;
                                if ((runeID = setting.GetRuneID()) != 0)
                                {
                                    Objects.Item rune = client.Inventory.GetItem(runeID);
                                    if (rune != null)
                                    {
                                        if (!this.StopwatchExhaust.IsRunning ||
                                            this.StopwatchExhaust.ElapsedMilliseconds >= this.Parent.CurrentSettings.Exhaust)
                                        {
                                            if (setting.RuneIsAoE()) // todo: test this
                                            {
                                                Map.Tile aoeTile = this.Parent.GetAreaEffectTile(setting.GetAreaEffect(),
                                                                                                 this.CachedTiles, this.CurrentTarget.Creature);
                                                if (aoeTile != null)
                                                {
                                                    rune.UseOnTile(aoeTile);
                                                    this.StopwatchExhaust.Restart();
                                                }
                                            }
                                            else if (this.CurrentTarget.Creature.IsShootable(this.CachedTiles))
                                            {
                                                rune.UseOnBattleList(this.CurrentTarget.Creature);
                                                this.StopwatchExhaust.Restart();
                                            }
                                        }
                                    }
                                }
                                else if (!string.IsNullOrEmpty(setting.Spell))
                                {
                                    // todo: add aoe spells
                                    if (playerLoc.IsAdjacentNonDiagonalOnly(targetLoc))
                                    {
                                        Enums.Direction direction = Enums.Direction.Down;
                                        int             diffX     = playerLoc.X - targetLoc.X,
                                                        diffY = playerLoc.Y - targetLoc.Y;
                                        if (diffX > 0)
                                        {
                                            direction = Enums.Direction.Left;
                                        }
                                        else if (diffX < 0)
                                        {
                                            direction = Enums.Direction.Right;
                                        }
                                        else if (diffY > 0)
                                        {
                                            direction = Enums.Direction.Up;
                                        }
                                        else if (diffY < 0)
                                        {
                                            direction = Enums.Direction.Down;
                                        }
                                        if (client.Player.Direction != direction)
                                        {
                                            client.Packets.Turn(direction);
                                            for (int i = 0; i < 6; i++)
                                            {
                                                Thread.Sleep(50);
                                                if ((Enums.Direction)client.Player.Direction == direction)
                                                {
                                                    break;
                                                }
                                            }
                                        }
                                        if (client.Player.Direction == direction &&
                                            (!this.StopwatchExhaust.IsRunning || this.StopwatchExhaust.ElapsedMilliseconds > this.Parent.CurrentSettings.Exhaust))
                                        {
                                            client.Packets.Say(setting.Spell);
                                            this.StopwatchExhaust.Restart();
                                        }
                                    }
                                }
                            }
                            #endregion
                        }

                        if (this.TargetExecutedEnd != null)
                        {
                            this.TargetExecutedEnd(this.CurrentTarget);
                        }
                        this.ResetEvent.Reset();
                        this.Cancel = false;
                    }
                    catch (Exception ex)
                    {
                        if (this.ErrorOccurred != null)
                        {
                            this.ErrorOccurred(ex);
                        }
                    }
                }
            }
Exemple #6
0
            private void Run()
            {
                while (true)
                {
                    try
                    {
                        this.ResetEvent.Wait();
                        if (this.WaypointExecutedBegin != null)
                        {
                            this.WaypointExecutedBegin(this.CurrentWaypoint);
                        }

                        bool success  = false,
                             firstRun = true;
                        Objects.Location currentSubNode = Objects.Location.Invalid;

                        while (!this.Cancel)
                        {
                            this.ResetEventTilesUpdated.WaitOne();

                            if (this.Cancel)
                            {
                                break;
                            }

                            Objects.Player   player    = this.Parent.Client.Player;
                            Objects.Location playerLoc = player.Location;

                            if (player.Z != this.CurrentWaypoint.Location.Z)
                            {
                                break;
                            }

                            if (firstRun)
                            {
                                firstRun = false;
                            }
                            else
                            {
                                if (this.Parent.Client.Window.StatusBar.GetText() == Enums.StatusBar.ThereIsNoWay)
                                {
                                    this.Parent.Client.Window.StatusBar.SetText(string.Empty);
                                    success = false;
                                    break;
                                }
                            }

                            bool isOnScreen     = playerLoc.IsOnScreen(this.CurrentWaypoint.Location),
                                 doBreak        = false;
                            var tilesToLocation = isOnScreen ?
                                                  playerLoc.GetTilesToLocation(this.Parent.Client,
                                                                               this.CurrentWaypoint.Location, this.CachedTiles, this.Parent.PathFinder)
                                                  .ToList <Objects.PathFinder.Node>() :
                                                  new List <Objects.PathFinder.Node>();

                            switch (this.CurrentWaypoint.Type)
                            {
                            case Waypoint.Types.Walk:
                                #region walk
                                if (playerLoc == this.CurrentWaypoint.Location)
                                {
                                    doBreak = true;
                                    success = true;
                                    break;
                                }
                                if (isOnScreen && tilesToLocation.Count == 0)
                                {
                                    doBreak = true;
                                    success = false;
                                    break;
                                }
                                if (!player.IsWalking || player.GoTo != this.CurrentWaypoint.Location)
                                {
                                    player.GoTo = this.CurrentWaypoint.Location;
                                }
                                #endregion
                                break;

                            case Waypoint.Types.Node:
                                #region node
                                if (playerLoc == this.CurrentWaypoint.Location)
                                {
                                    doBreak = true;
                                    success = true;
                                    break;
                                }
                                if (isOnScreen && tilesToLocation.Count == 0)
                                {
                                    doBreak = true;
                                    success = false;
                                    break;
                                }

                                // check if the player is already walking to a node
                                if (player.IsWalking)
                                {
                                    int range = this.Parent.CurrentSettings.NodeRadius;
                                    Objects.Location currentGoTo = player.GoTo;
                                    bool             found       = false;
                                    for (int x = -range; x <= range; x++)
                                    {
                                        for (int y = -range; y <= range; y++)
                                        {
                                            Objects.Location subNode = this.CurrentWaypoint.Location.Offset(x, y);
                                            if (currentGoTo != subNode)
                                            {
                                                continue;
                                            }
                                            // check distance to node
                                            if (isOnScreen)
                                            {
                                                var tilesToSubNode = playerLoc.GetTilesToLocation(this.Parent.Client,
                                                                                                  subNode, this.CachedTiles, this.Parent.PathFinder, true).ToArray();
                                                if (tilesToSubNode.Length <= this.Parent.CurrentSettings.NodeSkipRange)
                                                {
                                                    success = true;
                                                    doBreak = true;
                                                    break;
                                                }
                                            }
                                            found = true;
                                            break;
                                        }
                                        if (found)
                                        {
                                            break;
                                        }
                                    }
                                    if (found)
                                    {
                                        break;
                                    }
                                }
                                else if (playerLoc.DistanceTo(this.CurrentWaypoint.Location) <= this.Parent.CurrentSettings.NodeSkipRange)
                                {
                                    success = true;
                                    doBreak = true;
                                    break;
                                }

                                // find new node to walk to
                                if (isOnScreen)
                                {
                                    Map.Tile tile = this.CachedTiles.GetTile(this.CurrentWaypoint.Location);
                                    if (tile == null)
                                    {
                                        doBreak = true;
                                        success = false;
                                        break;
                                    }
                                    Map.TileCollection nearbyTiles = this.CachedTiles.GetNearbyTileCollection(tile,
                                                                                                              this.Parent.CurrentSettings.NodeRadius);
                                    Objects.Location loc = tilesToLocation.Count != 0 ?
                                                           tile.WorldLocation :
                                                           Objects.Location.Invalid;
                                    List <Map.Tile> goodTiles = new List <Map.Tile>();
                                    foreach (Map.Tile nearbyTile in nearbyTiles.GetTiles())
                                    {
                                        bool isReachable = playerLoc.CanReachLocation(this.Parent.Client,
                                                                                      nearbyTile.WorldLocation, this.CachedTiles, this.Parent.PathFinder);
                                        if (isReachable)
                                        {
                                            goodTiles.Add(nearbyTile);
                                        }
                                    }
                                    if (goodTiles.Count > 0)
                                    {
                                        loc = goodTiles[new Random().Next(goodTiles.Count)].WorldLocation;
                                    }

                                    if (loc.IsValid())
                                    {
                                        player.GoTo = loc;
                                    }
                                    else
                                    {
                                        doBreak = true;
                                        success = false;
                                        break;
                                    }
                                }
                                else if (this.Parent.CurrentSettings.UseAlternateNodeFinder)
                                {
                                    int              range = this.Parent.CurrentSettings.NodeRadius;
                                    Random           rand  = new Random();
                                    Objects.Location loc   = this.CurrentWaypoint.Location;
                                    for (int x = -range; x <= range; x++)
                                    {
                                        for (int y = -range; y <= range; y++)
                                        {
                                            Objects.Location subNode = this.CurrentWaypoint.Location.Offset(
                                                rand.Next(-range, range + 1), rand.Next(-range, range + 1));
                                            if (!this.Parent.Client.Modules.MapViewer.IsWalkable(subNode))
                                            {
                                                continue;
                                            }
                                            loc = subNode;
                                            break;
                                        }
                                        if (loc != this.CurrentWaypoint.Location)
                                        {
                                            break;
                                        }
                                    }
                                    player.GoTo = loc;
                                }
                                else     // use stored subnodes
                                {
                                    Objects.Location loc = this.CurrentWaypoint.Location;
                                    if (this.CurrentWaypoint.NodeLocations.Count > 0)
                                    {
                                        int index = -1, newIndex = new Random().Next(-1, this.CurrentWaypoint.NodeLocations.Count);
                                        if (newIndex != index)
                                        {
                                            loc = this.CurrentWaypoint.NodeLocations[newIndex];
                                        }
                                    }
                                    player.GoTo = loc;
                                }
                                #endregion
                                break;

                            case Waypoint.Types.Machete:
                            case Waypoint.Types.Pick:
                            case Waypoint.Types.Rope:
                            case Waypoint.Types.Shovel:
                                #region tools
                                // check if we're adjacent to the waypoint
                                if (playerLoc.IsAdjacentTo(this.CurrentWaypoint.Location))
                                {
                                    Objects.Item tool = null;
                                    switch (this.CurrentWaypoint.Type)
                                    {
                                    case Waypoint.Types.Machete:
                                        tool = this.Parent.Client.Inventory.GetItem(this.Parent.Client.ItemList.Tools.Machete);
                                        break;

                                    case Waypoint.Types.Pick:
                                        tool = this.Parent.Client.Inventory.GetItem(this.Parent.Client.ItemList.Tools.Pick);
                                        break;

                                    case Waypoint.Types.Rope:
                                        tool = this.Parent.Client.Inventory.GetItem(this.Parent.Client.ItemList.Tools.Rope);
                                        break;

                                    case Waypoint.Types.Shovel:
                                        tool = this.Parent.Client.Inventory.GetItem(this.Parent.Client.ItemList.Tools.Shovel);
                                        break;
                                    }
                                    if (tool == null)
                                    {
                                        doBreak = true;
                                        success = false;
                                        break;
                                    }
                                    Map.Tile tile = this.CachedTiles.GetTile(this.CurrentWaypoint.Location);
                                    if (tile == null)
                                    {
                                        success = false;
                                        doBreak = true;
                                        break;
                                    }
                                    Map.TileObject topItem = tile.GetTopUseItem(true);
                                    if (this.CurrentWaypoint.Type != Waypoint.Types.Rope)
                                    {
                                        tool.UseOnTileObject(topItem);
                                        success = true;
                                        doBreak = true;
                                    }
                                    else
                                    {
                                        if (topItem.StackIndex != 0)
                                        {
                                            // find a non-blocking adjacent tile
                                            var adjacentTiles = this.CachedTiles.GetAdjacentTileCollection(tile).GetTiles()
                                                                .ToList <Map.Tile>();
                                            Map.Tile bestTile = tile;
                                            foreach (Map.Tile t in adjacentTiles.ToArray())
                                            {
                                                if (!t.IsWalkable())
                                                {
                                                    adjacentTiles.Remove(t);
                                                }
                                            }
                                            if (adjacentTiles.Count > 0)
                                            {
                                                bestTile = adjacentTiles[new Random().Next(adjacentTiles.Count)];
                                            }
                                            topItem.Move(bestTile.ToItemLocation());
                                        }
                                        else
                                        {
                                            tool.UseOnTileObject(topItem);
                                            for (int i = 0; i < 3; i++)
                                            {
                                                Thread.Sleep(100);
                                                if (player.Z != this.CurrentWaypoint.Location.Z)
                                                {
                                                    doBreak = true;
                                                    success = true;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                    break;
                                }
                                else if (isOnScreen)
                                {
                                    Map.Tile tile = this.CachedTiles.GetTile(this.CurrentWaypoint.Location);
                                    if (tile == null)
                                    {
                                        success = false;
                                        doBreak = true;
                                        break;
                                    }
                                    Map.TileCollection adjacentTiles = this.CachedTiles.GetAdjacentTileCollection(tile);
                                    Objects.Location   bestLoc       = Objects.Location.Invalid;
                                    int distance = int.MaxValue;
                                    foreach (Map.Tile adjTile in adjacentTiles.GetTiles())
                                    {
                                        if (!adjTile.IsWalkable())
                                        {
                                            continue;
                                        }

                                        var tilesToAdjTile = playerLoc.GetTilesToLocation(this.Parent.Client,
                                                                                          adjTile.WorldLocation, this.CachedTiles, this.Parent.PathFinder, true)
                                                             .ToArray <Objects.PathFinder.Node>();

                                        if (tilesToAdjTile.Length == 0)
                                        {
                                            continue;
                                        }
                                        if (tilesToAdjTile.Length < distance)
                                        {
                                            bestLoc  = adjTile.WorldLocation;
                                            distance = tilesToAdjTile.Length;
                                        }
                                    }
                                    if (bestLoc.IsValid())
                                    {
                                        player.GoTo = bestLoc;
                                    }
                                    else
                                    {
                                        doBreak = true;
                                        success = false;
                                        break;
                                    }
                                }
                                else if (!player.IsWalking)
                                {
                                    player.GoTo = this.CurrentWaypoint.Location;
                                }
                                #endregion
                                break;

                            case Waypoint.Types.Ladder:
                                #region ladder
                                if (player.IsWalking)
                                {
                                    break;
                                }

                                if (isOnScreen)
                                {
                                    Map.Tile tile = this.CachedTiles.GetTile(this.CurrentWaypoint.Location);
                                    if (tile == null)
                                    {
                                        doBreak = true;
                                        success = false;
                                        break;
                                    }

                                    if (playerLoc.DistanceTo(this.CurrentWaypoint.Location) < 2)
                                    {
                                        Map.TileObject topItem = tile.GetTopUseItem(false);
                                        if (topItem == null)
                                        {
                                            doBreak = true;
                                            success = false;
                                            break;
                                        }
                                        for (int i = 0; i < 3; i++)
                                        {
                                            topItem.Use();
                                            Thread.Sleep(300);
                                            if (player.Z != this.CurrentWaypoint.Location.Z)
                                            {
                                                doBreak = true;
                                                success = true;
                                                break;
                                            }
                                        }
                                        break;
                                    }
                                    // find suitable loc to walk to
                                    int distance             = int.MaxValue;
                                    Objects.Location bestLoc = Objects.Location.Invalid;
                                    foreach (Map.Tile adjTile in this.CachedTiles.GetAdjacentTileCollection(tile).GetTiles())
                                    {
                                        if (!adjTile.IsWalkable())
                                        {
                                            continue;
                                        }
                                        var tilesToAdjTile = playerLoc.GetTilesToLocation(this.Parent.Client,
                                                                                          adjTile.WorldLocation, this.CachedTiles, this.Parent.PathFinder, true)
                                                             .ToArray <Objects.PathFinder.Node>();
                                        if (tilesToAdjTile.Length == 0)
                                        {
                                            continue;
                                        }
                                        if (tilesToAdjTile.Length < distance)
                                        {
                                            distance = tilesToAdjTile.Length;
                                            bestLoc  = adjTile.WorldLocation;
                                        }
                                    }
                                    if (bestLoc.IsValid())
                                    {
                                        player.GoTo = bestLoc;
                                    }
                                    else
                                    {
                                        doBreak = true;
                                        success = false;
                                    }
                                    break;
                                }
                                else
                                {
                                    player.GoTo = this.CurrentWaypoint.Location;
                                }
                                #endregion
                                break;
                            }

                            if (doBreak)
                            {
                                break;
                            }
                        }

                        if (this.WaypointExecutedEnd != null)
                        {
                            this.WaypointExecutedEnd(this.CurrentWaypoint, success);
                        }
                        this.ResetEvent.Reset();
                    }
                    catch (Exception ex)
                    {
                        if (this.ErrorOccurred != null)
                        {
                            this.ErrorOccurred(ex);
                        }
                    }
                }
            }