/// <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; }
private void LootItems(Objects.Container lootContainer, IEnumerable<Loot> loots, Map.TileCollection tiles) { Random rand = new Random(); if (!this.Parent.StopwatchFoodEater.IsRunning) this.Parent.StopwatchFoodEater.Start(); int index = lootContainer.ItemsAmount - 1, retryCount = 0; while (index >= 0 && !this.Cancel) { // sanity checks if (lootContainer.ItemsAmount == 0 || !lootContainer.IsOpen) break; if (retryCount >= 3) { retryCount = 0; index--; continue; } // get item Objects.Item item = lootContainer.GetItemInSlot((byte)index); if (item == null) { index--; retryCount = 0; continue; } // check if it's food, eat it if so if (this.Parent.CurrentSettings.EatFood && this.Parent.StopwatchFoodEater.Elapsed.TotalSeconds > 20 && this.Parent.Client.ItemList.Food.All.Contains(item.ID)) { if (item.Count <= 1) item.Use(); else { for (int i = 0; i < Math.Min(item.Count, (ushort)3); i++) { item.Use(); Thread.Sleep(rand.Next(200, 325)); } } this.Parent.StopwatchFoodEater.Restart(); Thread.Sleep(rand.Next(200, 350)); index--; continue; } // check if we want to loot this item Loot loot = null; foreach (Loot l in loots) { if (l.ID == item.ID) { loot = l; break; } } if (loot == null) { index--; continue; } // loot this item bool successful = false; switch (loot.Destination) { case Loot.Destinations.Ground: Objects.Map.Tile playerTile = tiles.GetTile(count: this.Parent.Client.Player.ID); if (playerTile == null) break; List<Map.Tile> adjacentTiles = tiles.GetAdjacentTileCollection(playerTile).GetTiles().ToList(); adjacentTiles.Shuffle(); foreach (Objects.Map.Tile tile in adjacentTiles) { if (!tile.IsWalkable()) continue; item.Move(new Objects.ItemLocation(tile.WorldLocation)); successful = true; break; } break; case Loot.Destinations.EmptyContainer: Objects.ItemLocation toItem = this.Parent.Client.Inventory.GetFirstSuitableSlot(item, loot.Index); if (toItem == null) break; item.Move(toItem); successful = true; break; } // if successful, check if it's looted // if it wasn't looted, try again if (successful) { if (!item.WaitForInteraction(800)) { retryCount++; continue; } if (this.Parent.ItemLooted != null) this.Parent.ItemLooted(item); if (!this.Parent.CurrentSettings.FastLooting) Thread.Sleep(rand.Next(400, 700)); } retryCount = 0; index--; } if (this.Parent.CurrentSettings.OpenContainers && !this.Cancel && lootContainer.IsOpen && lootContainer.ItemsAmount > 0) { bool found = false; foreach (Objects.Item item in lootContainer.GetItems().Reverse()) { if (item.HasFlag(Enums.ObjectPropertiesFlags.IsContainer)) { for (int i = 0; i < 3; i++) { item.Use(); if (item.WaitForInteraction(800)) break; } found = true; break; } } if (found) this.LootItems(lootContainer, loots, this.CachedTiles); } }