/// <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 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); } } } }
/// <summary> /// Attempts to get the best setting for this target. Also sets CurrentSettingIndex. Returns null if unsuccessful. /// </summary> /// <param name="creaturesOnScreen">A collection of creatures visible on screen.</param> /// <param name="playersOnScreen">A collection of players visible on screen.</param> /// <param name="tileCollection">A collection of tiles visible on screen.</param> /// <param name="setCreature">Whether to set this target's Creature.</param> /// <returns></returns> public Target.Setting GetBestSetting(IEnumerable <Objects.Creature> creaturesOnScreen, IEnumerable <Objects.Creature> playersOnScreen, Map.TileCollection tileCollection, bool setCreature) { // check if there are any settings to use bool found = false; foreach (Target.Setting s in this.GetSettings()) { if (s.UseThisSetting) { found = true; break; } } if (!found) { return(null); } // set up the player's tile and other variables Map.Tile playerTile = tileCollection.GetTile(count: this.Parent.Client.Player.ID); if (playerTile == null) { return(null); } List <Objects.Creature> creatures = new List <Objects.Creature>(), players = new List <Objects.Creature>(); foreach (Objects.Creature c in creaturesOnScreen) { if (c.Name.ToLower() == this.Name.ToLower()) { creatures.Add(c); } } foreach (Objects.Creature p in playersOnScreen.ToArray()) { if (p.ID != this.Parent.Client.Player.ID) { players.Add(p); } } // calculate best setting int bestCount = 0, bestIndex = 0, index = 0; Target.Setting bestSetting = null; Objects.Creature bestCreature = null; foreach (Target.Setting setting in this.GetSettings()) { if (!setting.UseThisSetting) { continue; } int count = 0, bestCreatureDistance = setting.Range + 1; Objects.Creature tempCreature = null; foreach (Objects.Creature c in creatures) { if (!c.IsVisible) { continue; } Map.Tile creatureTile = tileCollection.GetTile(count: c.ID); if (creatureTile == null) { continue; } if (!playerTile.WorldLocation.IsOnScreen(creatureTile.WorldLocation)) { continue; } if (this.Parent.CurrentSettings.FriendlyMode && players.Count > 0 && !c.HasAttackedMeRecently(4000)) { continue; } if (setting.MustBeShootable && !c.IsShootable(tileCollection)) { continue; } var pfNodes = c.GetTilesToCreature(tileCollection, this.Parent.PathFinder) .ToList <Objects.PathFinder.Node>(); if (setting.MustBeReachable && pfNodes.Count == 0) { continue; } if ((pfNodes.Count > 0 ? pfNodes.Count : playerTile.WorldLocation.DistanceTo(creatureTile.WorldLocation)) > setting.Range) { continue; } count++; if (setCreature) { int distance = pfNodes.Count > 0 ? pfNodes.Count : (int)playerTile.WorldLocation.DistanceTo(creatureTile.WorldLocation); if (distance < bestCreatureDistance) { bestCreatureDistance = distance; tempCreature = c; } } } if (count == 0 || count < setting.Count) { continue; } if (count > bestCount) { bestCount = count; bestSetting = setting; bestIndex = index; bestCreature = tempCreature; } index++; } this.CurrentSettingIndex = bestSetting != null ? bestIndex : -1; if (bestSetting != null && bestCreature != null) { this.Creature = bestCreature; } return(bestSetting); }
/// <summary> /// Loads data (waypoints, loot, targets, settings) from a binary file loaded into a Objects.Packet object. /// </summary> /// <param name="version">The version of LibreBot which created the file.</param> /// <param name="p">The Objects.Packet object.</param> /// <returns></returns> private bool Load(ushort version, Objects.Packet p) { while (p.GetPosition < p.Length) { Enums.CavebotDatType type = (Enums.CavebotDatType)p.GetByte(); ushort count = 0; switch (type) { case Enums.CavebotDatType.Settings: switch (version) { case 212: case 213: this.CurrentSettings.EatFood = p.GetBool(); this.CurrentSettings.Exhaust = p.GetUInt16(); this.CurrentSettings.MinimumHealthToShoot = p.GetUInt16(); this.CurrentSettings.NodeRadius = p.GetByte(); this.CurrentSettings.NodeSkipRange = p.GetByte(); this.CurrentSettings.OpenContainers = p.GetBool(); this.CurrentSettings.PrioritizeDanger = p.GetBool(); this.CurrentSettings.StickToCreature = p.GetBool(); this.CurrentSettings.StopAttackingWhenOutOfRange = p.GetBool(); this.CurrentSettings.UseGoldStacks = p.GetBool(); this.CurrentSettings.CanUseMagicRope = p.GetBool(); this.CurrentSettings.UseAlternateNodeFinder = p.GetBool(); this.CurrentSettings.KillBeforeLooting = p.GetBool(); break; default: this.CurrentSettings.EatFood = p.GetBool(); this.CurrentSettings.Exhaust = p.GetUInt16(); this.CurrentSettings.MinimumHealthToShoot = p.GetUInt16(); this.CurrentSettings.NodeRadius = p.GetByte(); this.CurrentSettings.NodeSkipRange = p.GetByte(); this.CurrentSettings.OpenContainers = p.GetBool(); this.CurrentSettings.PrioritizeDanger = p.GetBool(); this.CurrentSettings.StickToCreature = p.GetBool(); this.CurrentSettings.StopAttackingWhenOutOfRange = p.GetBool(); this.CurrentSettings.UseGoldStacks = p.GetBool(); this.CurrentSettings.CanUseMagicRope = p.GetBool(); break; } break; case Enums.CavebotDatType.Loot: count = p.GetUInt16(); for (int i = 0; i < count; i++) { switch (version) { default: Loot l = new Loot(); l.ID = p.GetUInt16(); l.Name = p.GetString(); l.Cap = p.GetUInt16(); string destination = p.GetString(); switch (destination.ToLower()) { case "ground": l.Destination = Loot.Destinations.Ground; break; default: l.Destination = Loot.Destinations.EmptyContainer; l.Index = byte.Parse(destination[1].ToString()); break; } this.AddLoot(l); break; case 213: this.AddLoot(new Loot(p.GetUInt16(), p.GetString(), p.GetUInt16(), (Loot.Destinations)p.GetByte(), p.GetByte())); break; } } break; case Enums.CavebotDatType.Targetting: count = p.GetUInt16(); for (int i = 0; i < count; i++) { Target t = new Target(this); t.Name = p.GetString(); if (version < 212) // load old settings (single setting environment) { Target.Setting setting = new Target.Setting(t); setting.Count = p.GetByte(); setting.Range = p.GetByte(); setting.DistanceRange = 3; setting.FightMode = (Enums.FightMode)p.GetByte(); setting.FightStance = (Enums.FightStance)p.GetByte(); p.GetString(); // ring p.GetString(); // rune setting.Spell = p.GetString(); setting.DangerLevel = p.GetByte(); p.GetBool(); // friendly mode setting.MustBeReachable = p.GetBool(); setting.MustBeShootable = p.GetBool(); t.DoLoot = p.GetBool(); setting.UseThisSetting = true; p.GetBool(); // alarm, deprecated t.SetSettings(new List<Target.Setting>() { setting }); } else // load new settings (multiple setting environment) { ushort settingsCount = p.GetUInt16(); List<Target.Setting> settings = new List<Target.Setting>(); for (int j = 0; j < settingsCount; j++) { Target.Setting setting = new Target.Setting(t); setting.Count = p.GetByte(); setting.Range = p.GetByte(); setting.DistanceRange = 3; setting.FightMode = (Enums.FightMode)p.GetByte(); setting.FightStance = (Enums.FightStance)p.GetByte(); p.GetString(); // ring p.GetString(); // rune setting.Spell = p.GetString(); setting.DangerLevel = p.GetByte(); p.GetBool(); // friendly mode setting.MustBeReachable = p.GetBool(); setting.MustBeShootable = p.GetBool(); t.DoLoot = p.GetBool(); setting.UseThisSetting = true; settings.Add(setting); } t.SetSettings(settings); } this.AddTarget(t); } break; case Enums.CavebotDatType.Waypoints: count = p.GetUInt16(); for (int i = 0; i < count; i++) { Modules.Cavebot.Waypoint.Types wpType = (Modules.Cavebot.Waypoint.Types)p.GetByte(); Objects.Location wpLocation = new Objects.Location(p.GetUInt16(), p.GetUInt16(), p.GetByte()); string wpLabel = p.GetString(); List<Objects.Location> wpNodes = new List<Objects.Location>(); string wpScript = string.Empty; switch (wpType) { case Modules.Cavebot.Waypoint.Types.Node: switch (version) { case 200: this.AddWaypoint(new Waypoint(this, wpLocation, wpType)); break; case 201: default: ushort nodeCount = p.GetUInt16(); for (int j = 0; j < nodeCount; j++) wpNodes.Add(new Objects.Location(p.GetUInt16(), p.GetUInt16(), p.GetByte())); this.AddWaypoint(new Waypoint(this, wpLocation, wpNodes)); break; } break; case Modules.Cavebot.Waypoint.Types.Script: if (version == 211) { ushort scriptCount = p.GetUInt16(); List<Objects.Script> scripts = new List<Objects.Script>(); string filePath = p.GetString(); string contents = System.IO.File.Exists(filePath) ? System.IO.File.ReadAllText(filePath) : string.Empty; /*for (int j = 0; j < scriptCount; j++) { string fileName = p.GetString(); if (!System.IO.File.Exists(fileName)) continue; Objects.Script script = new Objects.Script(this.Client, fileName, wpLocation); scripts.Add(script); }*/ this.AddWaypoint(new Waypoint(this, wpLocation, contents)); } else { wpScript = p.GetString(); this.AddWaypoint(new Waypoint(this, wpLocation, wpScript)); } break; default: this.AddWaypoint(new Waypoint(this, wpLocation, wpType)); break; } } break; default: return false; } } return true; }