예제 #1
0
파일: Cavebot.cs 프로젝트: KyLuaa/bot
        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;
        }