private void Run() { #region local variables Walker walker = new Walker(this); Targeting targeting = new Targeting(this); Looter looter = new Looter(this); List<Objects.Location> corpseLocations = new List<Objects.Location>(); Objects.Location currentCorpseLocation = Objects.Location.Invalid; Waypoint currentWaypoint = null; bool cleanupCalled = false; Map.TileCollection tileCollection = null; #region events // create anonymous methods and reference them // because we want to unsub them later TargetHandler anonTargetKilled = delegate(Target t) { if (t == null || t.Creature == null) return; if (!t.DoLoot) return; if (!this.Client.Player.Location.IsOnScreen(t.Creature.Location)) return; if (!corpseLocations.Contains(t.Creature.Location)) corpseLocations.Add(t.Creature.Location); }; Targeting.CreatureDiedHandler anonCreatureDied = delegate(Objects.Creature c) { string name = c.Name.ToLower(); foreach (Target t in this.GetTargets()) { if (t.Name.ToLower() == name) { if (!t.DoLoot) break; if (!corpseLocations.Contains(c.Location)) corpseLocations.Add(c.Location); break; } } }; Walker.WaypointHandler anonWaypointExecutedEnd = delegate(Waypoint waypoint, bool success) { if (this.Waypoints.Count == 0) return; this.CurrentWaypointIndex++; }; Looter.CorpseOpenedHandler anonCorpseOpened = delegate(Objects.Container container) { looter.LootItems(container, this.GetLoot(), true); }; Looter.LootingFinishedHandler anonLootingFinished = delegate(Objects.Container container) { if (this.Waypoints.Count == 0) return; if (container.IsOpen) container.Close(); corpseLocations.Remove(currentCorpseLocation); currentCorpseLocation = Objects.Location.Invalid; }; Targeting.ErrorHandler anonTargetingError = delegate(Exception ex) { DateTime dt = DateTime.Now; string dtString = dt.Year + "-" + dt.Month + "-" + dt.Day + " " + dt.Hour + ":" + dt.Minute + ":" + dt.Second; File.AppendAllText("cavebot-debug.txt", "[" + dtString + "] Targeting:\n" + ex.Message + "\n" + ex.StackTrace + "\n"); }; Walker.ErrorHandler anonWalkerError = delegate(Exception ex) { DateTime dt = DateTime.Now; string dtString = dt.Year + "-" + dt.Month + "-" + dt.Day + " " + dt.Hour + ":" + dt.Minute + ":" + dt.Second; File.AppendAllText("cavebot-debug.txt", "[" + dtString + "] Waypoints:\n" + ex.Message + "\n" + ex.StackTrace + "\n"); }; Looter.ErrorOccurredHandler anonLooterError = delegate(Exception ex) { DateTime dt = DateTime.Now; string dtString = dt.Year + "-" + dt.Month + "-" + dt.Day + " " + dt.Hour + ":" + dt.Minute + ":" + dt.Second; File.AppendAllText("cavebot-debug.txt", "[" + dtString + "] Looter:\n" + ex.Message + "\n" + ex.StackTrace + "\n"); }; CleanupHandler anonCleanup = delegate() { this.TargetKilled -= anonTargetKilled; walker.WaypointExecutedEnd -= anonWaypointExecutedEnd; looter.CorpseOpened -= anonCorpseOpened; looter.LootingFinished -= anonLootingFinished; targeting.CreatureDied -= anonCreatureDied; targeting.ErrorOccurred -= anonTargetingError; walker.ErrorOccurred -= anonWalkerError; looter.ErrorOccurred -= anonLooterError; cleanupCalled = true; }; // subscribe to events this.TargetKilled += anonTargetKilled; walker.WaypointExecutedEnd += anonWaypointExecutedEnd; looter.CorpseOpened += anonCorpseOpened; looter.LootingFinished += anonLootingFinished; targeting.CreatureDied += anonCreatureDied; targeting.ErrorOccurred += anonTargetingError; walker.ErrorOccurred += anonWalkerError; looter.ErrorOccurred += anonLooterError; // subscribe to cleanup, as we need to unsub before exiting this.CleanupCalled += anonCleanup; #endregion #endregion while (this.IsRunning) { try { Thread.Sleep(500); // check if IsRunning changed or cleanup called while thread was sleeping if (!this.IsRunning || cleanupCalled) break; if (!this.Client.Player.Connected) continue; // check if a script waypoint is currently running if (walker.IsRunning && currentWaypoint != null && currentWaypoint.Type == Waypoint.Types.Script) { continue; } Objects.Location playerLoc = this.Client.Player.Location; IEnumerable<Objects.Creature> creatures = this.Client.BattleList.GetCreatures(false, true), visiblePlayers = this.Client.BattleList.GetPlayers(true, true); List<Objects.Creature> visibleCreatures = new List<Objects.Creature>(); foreach (Objects.Creature c in creatures) { if (c.IsVisible) visibleCreatures.Add(c); } foreach (Objects.Creature c in targeting.GetKilledCreatures(creatures)) { string name = c.Name.ToLower(); foreach (Target t in this.GetTargets()) { if (t.Name.ToLower() != name) continue; if (!corpseLocations.Contains(c.Location)) corpseLocations.Add(c.Location); break; } } #region targeting if (targeting.IsRunning) { targeting.UpdateCache(tileCollection, visibleCreatures, visiblePlayers); continue; } else if (this.CurrentSettings.KillBeforeLooting || corpseLocations.Count == 0) { Target t = this.GetBestTarget(tileCollection, creatures, this.Client.BattleList.GetPlayers(true, true), true); if (t != null) { if (this.CurrentSettings.KillBeforeLooting && looter.IsRunning) looter.CancelExecution(); if (this.Client.TibiaVersion < 810) this.StopwatchExhaust.Restart(); // restart to avoid instant attack->spell/rune targeting.ExecuteTarget(t, tileCollection, visibleCreatures, visiblePlayers); continue; } } #endregion #region looting if (looter.IsRunning) { looter.UpdateCache(tileCollection); continue; } // loot always if there are no waypoints if (this.Waypoints.Count == 0) { List<ushort> ids = new List<ushort>(); foreach (Loot loot in this.GetLoot()) { ids.Add(loot.ID); } foreach (Objects.Container c in this.Client.Inventory.GetContainers(1)) { if (c.Name.Contains("Backpack")) continue; if (c.GetItems(ids).ToArray().Length == 0) continue; looter.LootItems(c, this.GetLoot(), false); } } // check loot locations else if (corpseLocations.Count > 0) { if (this.Client.Player.IsWalking) continue; // find new corpse location if (!currentCorpseLocation.IsValid() || !playerLoc.IsInRange(currentCorpseLocation)) { int distance = int.MaxValue; Objects.Location bestLoc = Objects.Location.Invalid; foreach (Objects.Location loc in corpseLocations) { if (!playerLoc.IsInRange(loc)) continue; int corpseDistance = 0; if (playerLoc.IsOnScreen(loc)) { Map.Tile tile = tileCollection.GetTile(loc); if (tile == null) continue; Map.TileObject topItem = tile.GetTopUseItem(false); if (!topItem.HasFlag(Enums.ObjectPropertiesFlags.IsContainer)) continue; var tilesToLoc = playerLoc.GetTilesToLocation(this.Client, loc, tileCollection, this.PathFinder, true, true).ToArray(); if (tilesToLoc.Length == 0) continue; corpseDistance = tilesToLoc.Length - 1; } else corpseDistance = (int)playerLoc.DistanceTo(loc) + 20; if (corpseDistance < distance) { distance = corpseDistance; bestLoc = loc; } } if (bestLoc.IsValid()) currentCorpseLocation = bestLoc; } // move to loot location if (currentCorpseLocation.IsValid() && playerLoc.IsInRange(currentCorpseLocation)) { if (this.Client.Window.StatusBar.GetText() == Enums.StatusBar.ThereIsNoWay) { corpseLocations.Remove(currentCorpseLocation); currentCorpseLocation = Objects.Location.Invalid; this.Client.Window.StatusBar.SetText(string.Empty); continue; } if (playerLoc.IsOnScreen(currentCorpseLocation)) { Map.Tile tile = tileCollection.GetTile(currentCorpseLocation); if (tile == null) { corpseLocations.Remove(currentCorpseLocation); currentCorpseLocation = Objects.Location.Invalid; continue; } Map.TileObject topItem = tile.GetTopUseItem(false); if (!topItem.HasFlag(Enums.ObjectPropertiesFlags.IsContainer)) { corpseLocations.Remove(currentCorpseLocation); currentCorpseLocation = Objects.Location.Invalid; continue; } if (playerLoc.DistanceTo(currentCorpseLocation) >= 2) { Map.TileCollection adjTiles = tileCollection.GetAdjacentTileCollection(tile); int adjDistance = playerLoc.GetTilesToLocation(this.Client, tile.WorldLocation, tileCollection, this.PathFinder, true).ToArray().Length; Objects.Location adjLoc = Objects.Location.Invalid; foreach (Map.Tile adjTile in adjTiles.GetTiles()) { if (!adjTile.IsWalkable()) continue; var tilesToCorpse = playerLoc.GetTilesToLocation(this.Client, adjTile.WorldLocation, tileCollection, this.PathFinder, true).ToArray(); if (tilesToCorpse.Length == 0) continue; int dist = tilesToCorpse.Length - 1; if (dist < adjDistance) { adjDistance = dist; adjLoc = adjTile.WorldLocation; } } if (adjLoc.IsValid()) { this.Client.Player.GoTo = adjLoc; continue; } corpseLocations.Remove(currentCorpseLocation); currentCorpseLocation = Objects.Location.Invalid; continue; } // we're in range to open the corpse, so let's open it looter.OpenCorpse(tileCollection, tile); continue; } else { this.Client.Player.GoTo = currentCorpseLocation; continue; } } else currentCorpseLocation = Objects.Location.Invalid; } #endregion #region waypoints if (walker.IsRunning) { walker.UpdateCache(tileCollection); continue; } else if (this.Waypoints.Count > 0) { // check if this is the first time we're running the walker // and if waypoint index wasn't set by user // if so, find the closest waypoint if (currentWaypoint == null && this.CurrentWaypointIndex == 0) { int distance = 200; Waypoint closestWaypoint = null; foreach (Waypoint wp in this.GetWaypoints()) { if (!playerLoc.IsInRange(wp.Location)) continue; int wpDist = (int)playerLoc.DistanceTo(wp.Location); if (distance > wpDist) { distance = wpDist; closestWaypoint = wp; } } if (closestWaypoint == null) continue; currentWaypoint = closestWaypoint; } else currentWaypoint = this.Waypoints[this.CurrentWaypointIndex]; walker.ExecuteWaypoint(currentWaypoint, tileCollection); } #endregion } catch (Exception ex) { } } this.CleanupCalled -= anonCleanup; }