/// <summary> /// Loot any wrecks & cargo containers close by /// </summary> private void LootWrecks() { var cargo = Cache.Instance.DirectEve.GetShipsCargo(); if (cargo.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenCargoHoldOfActiveShip); return; } // Ship's cargo is not ready yet if (!cargo.IsReady) { return; } var shipsCargo = cargo.Items.Select(i => new ItemCache(i)).ToList(); var freeCargoCapacity = cargo.Capacity - cargo.UsedCapacity; var lootWindows = Cache.Instance.DirectEve.Windows.OfType <DirectContainerWindow>().Where(w => w.Type == "form.LootCargoView"); foreach (var window in lootWindows) { // The window is not ready, then continue if (!window.IsReady) { continue; } // Get the container var containerEntity = Cache.Instance.EntityById(window.ItemId); // Does it no longer exist or is it out of transfer range or its looted if (containerEntity == null || containerEntity.Distance > (int)Distance.SafeScoopRange || Cache.Instance.LootedContainers.Contains(containerEntity.Id)) { Logging.Log("Salvage: Closing loot window [" + window.ItemId + "]"); window.Close(); continue; } // Get the container that is associated with the cargo container var container = Cache.Instance.DirectEve.GetContainer(window.ItemId); // List its items var items = container.Items.Select(i => new ItemCache(i)); // Build a list of items to loot var lootItems = new List <ItemCache>(); if (Settings.Instance.WreckLootStatistics) { // Log all items found in the wreck File.AppendAllText(Settings.Instance.WreckLootStatisticsFile, "TIME: " + string.Format("{0:dd/MM/yyyy HH:mm:ss}", DateTime.Now) + "\n"); File.AppendAllText(Settings.Instance.WreckLootStatisticsFile, "NAME: " + containerEntity.Name + "\n"); File.AppendAllText(Settings.Instance.WreckLootStatisticsFile, "ITEMS:" + "\n"); foreach (var item in items.OrderBy(i => i.TypeId)) { File.AppendAllText(Settings.Instance.WreckLootStatisticsFile, "TypeID: " + item.TypeId.ToString() + "\n"); File.AppendAllText(Settings.Instance.WreckLootStatisticsFile, "Name: " + item.Name + "\n"); File.AppendAllText(Settings.Instance.WreckLootStatisticsFile, "Quantity: " + item.Quantity.ToString() + "\n"); File.AppendAllText(Settings.Instance.WreckLootStatisticsFile, "=\n"); } File.AppendAllText(Settings.Instance.WreckLootStatisticsFile, ";" + "\n"); } //if (freeCargoCapacity < 1000) //this should allow BSs to dump scrapmetal but haulers and noctus' to hold onto it //{ // // Dump scrap metal if we have any // if (containerEntity.Name == "Cargo Container" && shipsCargo.Any(i => i.IsScrapMetal)) // { // foreach (var item in shipsCargo.Where(i => i.IsScrapMetal)) // { // container.Add(item.DirectItem); // freeCargoCapacity += item.TotalVolume; // } // // shipsCargo.RemoveAll(i => i.IsScrapMetal); // } //} // Walk through the list of items ordered by highest value item first foreach (var item in items.OrderByDescending(i => i.IskPerM3)) { if (freeCargoCapacity < 1000) //this should allow BSs to not pickup large low value items but haulers and noctus' to scoop everything { // We never want to pick up a cap booster if (item.GroupID == (int)Group.CapacitorGroupCharge) { continue; } // We never want to pick up metal scraps //if (item.IsScrapMetal) // continue; } // We pick up loot depending on isk per m3 var isMissionItem = Cache.Instance.MissionItems.Contains((item.Name ?? string.Empty).ToLower()); // Never pick up contraband (unless its the mission item) if (!isMissionItem && item.IsContraband) { continue; } // Do we want to loot other items? if (!isMissionItem && !LootEverything) { continue; } // Do not pick up items that cannot enter in a freighter container (unless its the mission item) // Note: some mission items that are alive have been allowed to be // scooped because unloadlootstate.MoveCommonMissionCompletionitems // will move them into the hangar floor not the loot location if (!isMissionItem && item.IsAliveandWontFitInContainers) { continue; } // We are at our max, either make room or skip the item if ((freeCargoCapacity - item.TotalVolume) <= (isMissionItem ? 0 : ReserveCargoCapacity)) { // We can't drop items in this container anyway, well get it after its salvaged if (!isMissionItem && containerEntity.GroupId != (int)Group.CargoContainer) { continue; } // Make a list of items which are worth less List <ItemCache> worthLess; if (isMissionItem) { worthLess = shipsCargo; } else if (item.IskPerM3.HasValue) { worthLess = shipsCargo.Where(sc => sc.IskPerM3.HasValue && sc.IskPerM3 < item.IskPerM3).ToList(); } else { worthLess = shipsCargo.Where(sc => sc.IskPerM3.HasValue).ToList(); } // Remove mission item from this list worthLess.RemoveAll(wl => Cache.Instance.MissionItems.Contains((wl.Name ?? string.Empty).ToLower())); worthLess.RemoveAll(wl => (wl.Name ?? string.Empty).ToLower() == Cache.Instance.BringMissionItem); // Consider dropping ammo if it concerns the mission item! if (!isMissionItem) { worthLess.RemoveAll(wl => Ammo.Any(a => a.TypeId == wl.TypeId)); } // Nothing is worth less then the current item if (worthLess.Count() == 0) { continue; } // Not enough space even if we dumped the crap if ((freeCargoCapacity + worthLess.Sum(wl => wl.TotalVolume)) < item.TotalVolume) { if (isMissionItem) { Logging.Log("Salvage: Not enough space for mission item! Need [" + item.TotalVolume + "] maximum available [" + (freeCargoCapacity + worthLess.Sum(wl => wl.TotalVolume)) + "]"); } continue; } // Start clearing out items that are worth less var moveTheseItems = new List <DirectItem>(); foreach (var wl in worthLess.OrderBy(wl => wl.IskPerM3.HasValue ? wl.IskPerM3.Value : double.MaxValue).ThenByDescending(wl => wl.TotalVolume)) { // Mark this item as moved moveTheseItems.Add(wl.DirectItem); // Substract (now) free volume freeCargoCapacity += wl.TotalVolume; // We freed up enough space? if ((freeCargoCapacity - item.TotalVolume) >= ReserveCargoCapacity) { break; } } if (moveTheseItems.Count > 0) { // If this is not a cargo container, then jettison loot if (containerEntity.GroupId != (int)Group.CargoContainer || isMissionItem) { if (DateTime.Now.Subtract(_lastJettison).TotalSeconds < (int)Time.DelayBetweenJetcans_seconds) { return; } Logging.Log("Salvage: Jettisoning [" + moveTheseItems.Count + "] items to make room for the more valuable loot"); // Note: This could (in theory) f**k up with the bot jettison an item and // then picking it up again :/ (granted it should never happen unless // mission item volume > reserved volume cargo.Jettison(moveTheseItems.Select(i => i.ItemId)); _lastJettison = DateTime.Now; return; } // Move items to the cargo container container.Add(moveTheseItems); // Remove it from the ships cargo list shipsCargo.RemoveAll(i => moveTheseItems.Any(wl => wl.ItemId == i.Id)); Logging.Log("Salvage: Moving [" + moveTheseItems.Count + "] items into the cargo container to make room for the more valuable loot"); } } // Update free space freeCargoCapacity -= item.TotalVolume; lootItems.Add(item); } // Mark container as looted Cache.Instance.LootedContainers.Add(containerEntity.Id); // Loot actual items if (lootItems.Count != 0) { Logging.Log("Salvage: Looting container [" + containerEntity.Name + "][" + containerEntity.Id + "], [" + lootItems.Count + "] valuable items"); cargo.Add(lootItems.Select(i => i.DirectItem)); } else { Logging.Log("Salvage: Container [" + containerEntity.Name + "][" + containerEntity.Id + "] contained no valuable items"); } } // Open a container in range foreach (var containerEntity in Cache.Instance.Containers.Where(e => e.Distance <= (int)Distance.SafeScoopRange)) { // Emptry wreck, ignore if (containerEntity.GroupId == (int)Group.Wreck && containerEntity.IsWreckEmpty) { continue; } // We looted this container if (Cache.Instance.LootedContainers.Contains(containerEntity.Id)) { continue; } // We already opened the loot window var window = lootWindows.FirstOrDefault(w => w.ItemId == containerEntity.Id); if (window != null) { continue; } // Ignore open request within 10 seconds if (_openedContainers.ContainsKey(containerEntity.Id) && DateTime.Now.Subtract(_openedContainers[containerEntity.Id]).TotalSeconds < 10) { continue; } // Don't even try to open a wreck if you are speed tanking and you aren't processing a loot action //if (Settings.Instance.SpeedTank == true && Cache.Instance.OpenWrecks == false) // continue; // Don't even try to open a wreck if you are specified LootEverything as false and you aren't processing a loot action // this is currently commented out as it would keep golems and other non-speed tanked ships from looting the field as they cleared // missions, but NOT stick around after killing things to clear it ALL. Looteverything==false does NOT mean loot nothing //if (Settings.Instance.LootEverything == false && Cache.Instance.OpenWrecks == false) // continue; // Open the container Logging.Log("Salvage: Opening container [" + containerEntity.Name + "][" + containerEntity.Id + "]"); containerEntity.OpenCargo(); _openedContainers[containerEntity.Id] = DateTime.Now; break; } }
public void ProcessState() { var cargo = Cache.Instance.DirectEve.GetShipsCargo(); var itemshangar = Cache.Instance.DirectEve.GetItemHangar(); DirectContainer corpAmmoHangar = null; if (!string.IsNullOrEmpty(Settings.Instance.AmmoHangar)) { corpAmmoHangar = Cache.Instance.DirectEve.GetCorporationHangar(Settings.Instance.AmmoHangar); } DirectContainer corpLootHangar = null; if (!string.IsNullOrEmpty(Settings.Instance.LootHangar)) { corpLootHangar = Cache.Instance.DirectEve.GetCorporationHangar(Settings.Instance.LootHangar); } DirectContainer lootContainer = null; if (!string.IsNullOrEmpty(Settings.Instance.LootContainer)) { long lootContainerID = itemshangar.Items.FirstOrDefault(i => i.GivenName != null && i.GivenName.ToLower() == Settings.Instance.LootContainer.ToLower()).ItemId; lootContainer = Cache.Instance.DirectEve.GetContainer(lootContainerID); } DirectContainer corpBookmarkHangar = null; if (!string.IsNullOrEmpty(Settings.Instance.BookmarkHangar)) { corpBookmarkHangar = Cache.Instance.DirectEve.GetCorporationHangar(Settings.Instance.BookmarkHangar); } switch (State) { case UnloadLootState.Idle: case UnloadLootState.Done: break; case UnloadLootState.Begin: if (cargo.Items.Count == 0) { State = UnloadLootState.Done; } Logging.Log("UnloadLoot: Opening station hangar"); State = UnloadLootState.OpenItemHangar; break; case UnloadLootState.OpenItemHangar: // Is the hangar open? if (itemshangar.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenHangarFloor); break; } // Not ready yet if (!itemshangar.IsReady) { break; } Logging.Log("UnloadLoot: Opening ship's cargo"); State = UnloadLootState.OpenShipsCargo; break; case UnloadLootState.OpenShipsCargo: // Is cargo open? if (cargo.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenCargoHoldOfActiveShip); break; } if (!cargo.IsReady) { break; } if (corpAmmoHangar != null || corpLootHangar != null) { //Logging.Log("UnloadLoot: Opening corporation hangar"); State = UnloadLootState.OpenCorpHangar; } else { //Logging.Log("UnloadLoot: CommonMissionCompletionitems"); State = UnloadLootState.MoveCommonMissionCompletionitems; } break; case UnloadLootState.OpenCorpHangar: // Is cargo open? var corpHangar = corpAmmoHangar ?? corpLootHangar; if (corpHangar != null) { if (corpHangar.Window == null) { // No, command it to open Logging.Log("UnloadLoot: Opening corporation hangar"); Cache.Instance.DirectEve.OpenCorporationHangar(); break; } if (!corpHangar.IsReady) { break; } } Logging.Log("UnloadLoot: Moving Common Mission Completion items"); State = UnloadLootState.MoveCommonMissionCompletionitems; break; case UnloadLootState.MoveCommonMissionCompletionitems: var CommonMissionCompletionItemHangar = itemshangar; // // how do we get IsMissionItem to work for us here? (see ItemCache) // Zbikoki's Hacker Card 28260, Reports 3814, Gate Key 2076, Militants 25373, Marines 3810, i.groupid == 314 (Misc Mission Items, mainly for storylines) and i.GroupId == 283 (Misc Mission Items, mainly for storylines) // var ItemsToMove = cargo.Items.Where(i => i.TypeId == 17192 || i.TypeId == 2076 || i.TypeId == 3814 || i.TypeId == 17206 || i.TypeId == 28260 || i.GroupId == 283 || i.GroupId == 314); CommonMissionCompletionItemHangar.Add(ItemsToMove); _lastAction = DateTime.Now; Logging.Log("UnloadLoot: Moving Common Mission Completion Items to Local hangar"); State = UnloadLootState.MoveLoot; break; case UnloadLootState.MoveLoot: var lootHangar = corpLootHangar ?? lootContainer ?? itemshangar; var lootToMove = cargo.Items.Where(i => (i.TypeName ?? string.Empty).ToLower() != Cache.Instance.BringMissionItem && !Settings.Instance.Ammo.Any(a => a.TypeId == i.TypeId)); LootValue = 0; foreach (var item in lootToMove) { if (!Cache.Instance.InvTypesById.ContainsKey(item.TypeId)) { continue; } var invType = Cache.Instance.InvTypesById[item.TypeId]; LootValue += (invType.MedianBuy ?? 0) * Math.Max(item.Quantity, 1); } // Move loot to the loot hangar lootHangar.Add(lootToMove); _lastAction = DateTime.Now; Logging.Log("UnloadLoot: Loot was worth an estimated [" + LootValue.ToString("#,##0") + "] isk in buy-orders"); //Move bookmarks to the bookmarks hangar if (!string.IsNullOrEmpty(Settings.Instance.BookmarkHangar) && Settings.Instance.CreateSalvageBookmarks == true) { Logging.Log("UnloadLoot: Creating salvage bookmarks in hangar"); var bookmarks = Cache.Instance.BookmarksByLabel(Settings.Instance.BookmarkPrefix + " "); List <long> salvageBMs = new List <long>(); foreach (DirectBookmark bookmark in bookmarks) { salvageBMs.Add((long)bookmark.BookmarkId); if (salvageBMs.Count == 5) { itemshangar.AddBookmarks(salvageBMs); salvageBMs.Clear(); } } if (salvageBMs.Count > 0) { itemshangar.AddBookmarks(salvageBMs); salvageBMs.Clear(); } } Logging.Log("UnloadLoot: Moving ammo"); State = UnloadLootState.MoveAmmo; break; case UnloadLootState.MoveAmmo: // Wait 5 seconds after moving if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 5) { break; } var ammoHangar = corpAmmoHangar ?? itemshangar; // Move the mission item & ammo to the ammo hangar ammoHangar.Add(cargo.Items.Where(i => ((i.TypeName ?? string.Empty).ToLower() == Cache.Instance.BringMissionItem || Settings.Instance.Ammo.Any(a => a.TypeId == i.TypeId)))); _lastAction = DateTime.Now; Logging.Log("UnloadLoot: Waiting for items to move"); State = UnloadLootState.WaitForMove; break; case UnloadLootState.WaitForMove: if (cargo.Items.Count != 0) { _lastAction = DateTime.Now; break; } // Wait x seconds after moving if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 2) { break; } if (Cache.Instance.DirectEve.GetLockedItems().Count == 0) { if (corpBookmarkHangar != null && Settings.Instance.CreateSalvageBookmarks) { Logging.Log("UnloadLoot: Moving salvage bookmarks to corp hangar"); corpBookmarkHangar.Add(itemshangar.Items.Where(i => i.TypeId == 51)); } Logging.Log("UnloadLoot: Stacking items"); State = UnloadLootState.StackItemsHangar; break; } if (DateTime.Now.Subtract(_lastAction).TotalSeconds > 120) { Logging.Log("UnloadLoot: Moving items timed out, clearing item locks"); Cache.Instance.DirectEve.UnlockItems(); Logging.Log("UnloadLoot: Stacking items"); State = UnloadLootState.StackItemsHangar; break; } break; case UnloadLootState.StackItemsHangar: // Don't stack until 5 seconds after the cargo has cleared if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 5) { break; } // Stack everything if (corpAmmoHangar == null || corpLootHangar == null || lootContainer == null) // Only stack if we moved something { itemshangar.StackAll(); _lastAction = DateTime.Now; } State = UnloadLootState.StackItemsCorpAmmo; break; case UnloadLootState.StackItemsCorpAmmo: if (Settings.Instance.AmmoHangar != string.Empty) { // Don't stack until 5 seconds after the cargo has cleared if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 5) { break; } // Stack everything if (corpAmmoHangar != null) { corpAmmoHangar.StackAll(); _lastAction = DateTime.Now; } } State = UnloadLootState.StackItemsCorpLoot; break; case UnloadLootState.StackItemsCorpLoot: if (Settings.Instance.LootHangar != string.Empty) { // Don't stack until 5 seconds after the cargo has cleared if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 5) { break; } // Stack everything if (corpLootHangar != null) { corpLootHangar.StackAll(); _lastAction = DateTime.Now; } } State = UnloadLootState.StackItemsLootContainer; break; case UnloadLootState.StackItemsLootContainer: if (Settings.Instance.LootContainer != string.Empty) { // Don't stack until 5 seconds after the cargo has cleared if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 5) { break; } // Stack everything if (lootContainer != null) { lootContainer.StackAll(); _lastAction = DateTime.Now; } } State = UnloadLootState.WaitForStacking; break; case UnloadLootState.WaitForStacking: // Wait 5 seconds after stacking if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 5) { break; } if (Cache.Instance.DirectEve.GetLockedItems().Count == 0) { Logging.Log("UnloadLoot: Done"); State = UnloadLootState.Done; break; } if (DateTime.Now.Subtract(_lastAction).TotalSeconds > 120) { Logging.Log("UnloadLoot: Stacking items timed out, clearing item locks"); Cache.Instance.DirectEve.UnlockItems(); Logging.Log("UnloadLoot: Done"); State = UnloadLootState.Done; break; } break; } }
/// <summary> /// Refresh the mission items /// </summary> public void RefreshMissionItems(long agentId) { // Clear out old items MissionItems.Clear(); BringMissionItem = string.Empty; var mission = GetAgentMission(agentId); if (mission == null) { return; } if (factionName == null || factionName == "") { factionName = "Default"; } if (Settings.Instance.FittingsDefined) { //Set fitting to default DefaultFitting = (string)Settings.Instance.DefaultFitting.Fitting; Fitting = DefaultFitting; MissionShip = ""; ChangeMissionShipFittings = false; if (Settings.Instance.MissionFitting.Any(m => m.Mission.ToLower() == mission.Name.ToLower())) //priority goes to mission-specific fittings { string _missionFit; string _missionShip; MissionFitting _missionFitting; // if we've got multiple copies of the same mission, find the one with the matching faction if (Settings.Instance.MissionFitting.Any(m => m.Faction.ToLower() == factionName.ToLower() && (m.Mission.ToLower() == mission.Name.ToLower()))) { _missionFitting = Settings.Instance.MissionFitting.FirstOrDefault(m => m.Faction.ToLower() == factionName.ToLower() && (m.Mission.ToLower() == mission.Name.ToLower())); } else //otherwise just use the first copy of that mission { _missionFitting = Settings.Instance.MissionFitting.FirstOrDefault(m => m.Mission.ToLower() == mission.Name.ToLower()); } _missionFit = (string)_missionFitting.Fitting; _missionShip = (string)_missionFitting.Ship; if (!(_missionFit == "" && !(_missionShip == ""))) // if we've both specified a mission specific ship and a fitting, then apply that fitting to the ship { ChangeMissionShipFittings = true; Fitting = _missionFit; } else if (!((factionFit == null) || (factionFit == ""))) { Fitting = factionFit; } Logging.Log("Cache: Mission: " + _missionFitting.Mission + " - Faction: " + factionName + " - Fitting: " + _missionFit + " - Ship: " + _missionShip + " - ChangeMissionShipFittings: " + ChangeMissionShipFittings); MissionShip = _missionShip; } else if (!((factionFit == null) || (factionFit == ""))) // if no mission fittings defined, try to match by faction { Fitting = factionFit; } if (Fitting == "") // otherwise use the default { Fitting = DefaultFitting; } } var missionName = FilterPath(mission.Name); var missionXmlPath = Path.Combine(Settings.Instance.MissionsPath, missionName + ".xml"); if (!File.Exists(missionXmlPath)) { return; } try { var xdoc = XDocument.Load(missionXmlPath); var items = ((IEnumerable)xdoc.XPathEvaluate("//action[(translate(@name, 'LOT', 'lot')='loot') or (translate(@name, 'LOTIEM', 'lotiem')='lootitem')]/parameter[translate(@name, 'TIEM', 'tiem')='item']/@value")).Cast <XAttribute>().Select(a => ((string)a ?? string.Empty).ToLower()); MissionItems.AddRange(items); BringMissionItem = (string)xdoc.Root.Element("bring") ?? string.Empty; BringMissionItem = BringMissionItem.ToLower(); //load fitting setting from the mission file //Fitting = (string)xdoc.Root.Element("fitting") ?? "default"; } catch (Exception ex) { Logging.Log("Error loading mission XML file [" + ex.Message + "]"); } }
internal static bool PerformFinalDestinationTask(DirectBookmark bookmark, int warpDistance, ref DateTime nextAction) { // The bookmark no longer exists, assume we aren't there if (bookmark == null) { return(false); } if (Cache.Instance.DirectEve.Session.IsInStation) { // We have arived if (bookmark.ItemId.HasValue && bookmark.ItemId == Cache.Instance.DirectEve.Session.StationId) { return(true); } // We are apparently in a station that is incorrect Logging.Log("Traveler.BookmarkDestination: We're docked in the wrong station, undocking"); Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdExitStation); nextAction = DateTime.Now.AddSeconds(30); return(false); } // Is this a station bookmark? if (bookmark.Entity != null && bookmark.Entity.GroupId == (int)Group.Station) { var arrived = StationDestination.PerformFinalDestinationTask(bookmark.Entity.Id, bookmark.Entity.Name, ref nextAction); if (arrived) { Logging.Log("Traveler.BookmarkDestination: Arrived at bookmark [" + bookmark.Title + "]"); } return(arrived); } // Its not a station bookmark, make sure we are in space if (Cache.Instance.DirectEve.Session.IsInStation) { // We are in a station, but not the correct station! if (nextAction < DateTime.Now) { Logging.Log("Traveler.BookmarkDestination: We're docked but our destination is in space, undocking"); Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdExitStation); nextAction = DateTime.Now.AddSeconds(30); } // We are not there yet return(false); } if (!Cache.Instance.InSpace) { // We are not in space and not in a station, wait a bit return(false); } // This bookmark has no x / y / z, assume we are there. if (bookmark.X == -1 || bookmark.Y == -1 || bookmark.Z == -1) { Logging.Log("Traveler.BookmarkDestination: Arrived at the bookmark [" + bookmark.Title + "][No XYZ]"); return(true); } var distance = Cache.Instance.DistanceFromMe(bookmark.X ?? 0, bookmark.Y ?? 0, bookmark.Z ?? 0); if (distance < warpDistance) { Logging.Log("Traveler.BookmarkDestination: Arrived at the bookmark [" + bookmark.Title + "]"); return(true); } if (nextAction > DateTime.Now) { return(false); } Logging.Log("Traveler.BookmarkDestination: Warping to bookmark [" + bookmark.Title + "]"); bookmark.WarpTo(); nextAction = DateTime.Now.AddSeconds(30); return(false); }
public void LoadSettings() { var repairstopwatch = new Stopwatch(); Settings.Instance.characterName = Cache.Instance.DirectEve.Me.Name; Settings.Instance.settingsPath = Path.Combine(Settings.Instance.path, Cache.Instance.FilterPath(Settings.Instance.characterName) + ".xml"); var reloadSettings = Settings.Instance.characterName != Cache.Instance.DirectEve.Me.Name; if (File.Exists(Settings.Instance.settingsPath)) { reloadSettings = _lastModifiedDate != File.GetLastWriteTime(Settings.Instance.settingsPath); } if (!reloadSettings) { return; } _lastModifiedDate = File.GetLastWriteTime(settingsPath); if (!File.Exists(Settings.Instance.settingsPath)) //if the settings file does not exist initialize these values. Should we not halt when missing the settings XML? { // Clear settings //AgentName = string.Empty; CharacterMode = "dps"; AutoStart = false; SaveConsoleLog = true; maxLineConsole = 1000; waitDecline = false; Disable3D = false; RandomDelay = 0; minStandings = 10; MinimumDelay = 0; minStandings = 10; WindowXPosition = null; WindowYPosition = null; LootHangar = string.Empty; AmmoHangar = string.Empty; BookmarkHangar = string.Empty; LootContainer = string.Empty; MissionsPath = Path.Combine(path, "Missions"); bookmarkWarpOut = string.Empty; MaximumHighValueTargets = 0; MaximumLowValueTargets = 0; Ammo.Clear(); ItemsBlackList.Clear(); WreckBlackList.Clear(); FactionFitting.Clear(); AgentsList.Clear(); MissionFitting.Clear(); MinimumAmmoCharges = 0; WeaponGroupId = 0; ReserveCargoCapacity = 0; MaximumWreckTargets = 0; SpeedTank = false; OrbitDistance = 0; OptimalRange = 0; NosDistance = 38000; MinimumPropulsionModuleDistance = 3000; MinimumPropulsionModuleCapacitor = 35; ActivateRepairModules = 0; DeactivateRepairModules = 0; MinimumShieldPct = 0; MinimumArmorPct = 0; MinimumCapacitorPct = 0; SafeShieldPct = 0; SafeArmorPct = 0; SafeCapacitorPct = 0; UseDrones = false; DroneTypeId = 0; DroneControlRange = 0; DroneMinimumShieldPct = 0; DroneMinimumArmorPct = 0; DroneMinimumCapacitorPct = 0; DroneRecallCapacitorPct = 0; LongRangeDroneRecallCapacitorPct = 0; UseGatesInSalvage = false; Blacklist.Clear(); FactionBlacklist.Clear(); missionName = null; //missionbookmarktoagentloops = 0; return; } var xml = XDocument.Load(Settings.Instance.settingsPath).Root; // // these are listed by feature and should likely be re-ordered to reflect that // DebugStates = (bool?)xml.Element("debugStates") ?? false; //enables more console logging having to do with the sub-states within each state DebugPerformance = (bool?)xml.Element("debugPerformance") ?? false; //enabled more console logging having to do with the time it takes to execute each state CharacterMode = (string)xml.Element("characterMode") ?? "dps"; //other option is "salvage" AutoStart = (bool?)xml.Element("autoStart") ?? false; // auto Start enabled or disabled by default? SaveConsoleLog = (bool?)xml.Element("saveLog") ?? true; // save the console log to file maxLineConsole = (int?)xml.Element("maxLineConsole") ?? 1000; // maximum console log lines to show in the GUI Disable3D = (bool?)xml.Element("disable3D") ?? false; // Disable3d graphics while in space RandomDelay = (int?)xml.Element("randomDelay") ?? 0; MinimumDelay = (int?)xml.Element("minimumDelay") ?? 0; minStandings = (float?)xml.Element("minStandings") ?? 10; waitDecline = (bool?)xml.Element("waitDecline") ?? false; UseGatesInSalvage = (bool?)xml.Element("useGatesInSalvage") ?? false; // if our mission does not despawn (likely someone in the mission looting our stuff?) use the gates when salvaging to get to our bookmarks UseLocalWatch = (bool?)xml.Element("UseLocalWatch") ?? true; LocalBadStandingPilotsToTolerate = (int?)xml.Element("LocalBadStandingPilotsToTolerate") ?? 1; LocalBadStandingLevelToConsiderBad = (double?)xml.Element("LocalBadStandingLevelToConsiderBad") ?? -0.1; BattleshipInvasionLimit = (int?)xml.Element("battleshipInvasionLimit") ?? 0; // if this number of battleships lands on grid while in a mission we will enter panic BattlecruiserInvasionLimit = (int?)xml.Element("battlecruiserInvasionLimit") ?? 0; // if this number of battlecruisers lands on grid while in a mission we will enter panic CruiserInvasionLimit = (int?)xml.Element("cruiserInvasionLimit") ?? 0; // if this number of cruisers lands on grid while in a mission we will enter panic FrigateInvasionLimit = (int?)xml.Element("frigateInvasionLimit") ?? 0; // if this number of frigates lands on grid while in a mission we will enter panic InvasionRandomDelay = (int?)xml.Element("invasionRandomDelay") ?? 0; // random relay to stay docked InvasionMinimumDelay = (int?)xml.Element("invasionMinimumDelay") ?? 0; // minimum delay to stay docked EnableStorylines = (bool?)xml.Element("enableStorylines") ?? false; IskPerLP = (double?)xml.Element("IskPerLP") ?? 600; //used in value calculations UndockDelay = (int?)xml.Element("undockdelay") ?? 10; //Delay when undocking - not in use UndockPrefix = (string)xml.Element("undockprefix") ?? "Insta"; //Undock bookmark prefix - used by traveler - not in use WindowXPosition = (int?)xml.Element("windowXPosition") ?? 1600; //windows position (needs to be changed, default is off screen) WindowYPosition = (int?)xml.Element("windowYPosition") ?? 1050; //windows position (needs to be changed, default is off screen) CombatShipName = (string)xml.Element("combatShipName") ?? ""; SalvageShipName = (string)xml.Element("salvageShipName") ?? ""; TransportShipName = (string)xml.Element("transportShipName") ?? ""; LootHangar = (string)xml.Element("lootHangar"); AmmoHangar = (string)xml.Element("ammoHangar"); BookmarkHangar = (string)xml.Element("bookmarkHangar"); LootContainer = (string)xml.Element("lootContainer"); CreateSalvageBookmarks = (bool?)xml.Element("createSalvageBookmarks") ?? false; BookmarkPrefix = (string)xml.Element("bookmarkPrefix") ?? "Salvage:"; MinimumWreckCount = (int?)xml.Element("minimumWreckCount") ?? 1; AfterMissionSalvaging = (bool?)xml.Element("afterMissionSalvaging") ?? false; SalvageMultpleMissionsinOnePass = (bool?)xml.Element("salvageMultpleMissionsinOnePass") ?? false; UnloadLootAtStation = (bool?)xml.Element("unloadLootAtStation") ?? false; //AgentName = (string) xml.Element("agentName"); bookmarkWarpOut = (string)xml.Element("bookmarkWarpOut") ?? ""; EVEProcessMemoryCeiling = (int?)xml.Element("EVEProcessMemoryCeiling") ?? 900; EVEProcessMemoryCeilingLogofforExit = (string)xml.Element("EVEProcessMemoryCeilingLogofforExit") ?? "exit"; DontShootFrigatesWithSiegeorAutoCannons = (bool?)xml.Element("DontShootFrigatesWithSiegeorAutoCannons") ?? false; //Assume InnerspaceProfile CloseQuestorCMDUplinkInnerspaceProfile = (bool?)xml.Element("CloseQuestorCMDUplinkInnerspaceProfile") ?? true; CloseQuestorCMDUplinkIsboxerCharacterSet = (bool?)xml.Element("CloseQuestorCMDUplinkIsboxerCharacterSet") ?? false; walletbalancechangelogoffdelay = (int?)xml.Element("walletbalancechangelogoffdelay") ?? 30; walletbalancechangelogoffdelayLogofforExit = (string)xml.Element("walletbalancechangelogoffdelayLogofforExit") ?? "exit"; SessionsLog = (bool?)xml.Element("SessionsLog") ?? true; DroneStatsLog = (bool?)xml.Element("DroneStatsLog") ?? true; WreckLootStatistics = (bool?)xml.Element("WreckLootStatistics") ?? true; MissionStats1Log = (bool?)xml.Element("MissionStats1Log") ?? true; MissionStats2Log = (bool?)xml.Element("MissionStats2Log") ?? true; MissionStats3Log = (bool?)xml.Element("MissionStats3Log") ?? true; PocketStatistics = (bool?)xml.Element("PocketStatistics") ?? true; PocketStatsUseIndividualFilesPerPocket = (bool?)xml.Element("PocketStatsUseIndividualFilesPerPocket") ?? true; var missionsPath = (string)xml.Element("missionsPath"); MissionsPath = !string.IsNullOrEmpty(missionsPath) ? Path.Combine(path, missionsPath) : Path.Combine(path, "Missions"); LowSecMissions = (bool?)xml.Element("LowSecMissions") ?? false; MaximumHighValueTargets = (int?)xml.Element("maximumHighValueTargets") ?? 2; MaximumLowValueTargets = (int?)xml.Element("maximumLowValueTargets") ?? 2; Ammo.Clear(); var ammoTypes = xml.Element("ammoTypes"); if (ammoTypes != null) { foreach (var ammo in ammoTypes.Elements("ammoType")) { Ammo.Add(new Ammo(ammo)); } } MinimumAmmoCharges = (int?)xml.Element("minimumAmmoCharges") ?? 0; UseFittingManager = (bool?)xml.Element("UseFittingManager") ?? true; //agent list AgentsList.Clear(); var agentList = xml.Element("agentsList"); if (agentList != null) { if (agentList.HasElements) { int i = 0; foreach (var agent in agentList.Elements("agentList")) { AgentsList.Add(new AgentsList(agent)); i++; } if (i >= 2) { MultiAgentSupport = true; Logging.Log("Settings: Found more than one agent in your character XML: MultiAgentSupport is true"); } else { MultiAgentSupport = false; Logging.Log("Settings: Found only one agent in your character XML: MultiAgentSupport is false"); } } else { Logging.Log("Settings: agentList exists in your characters config but no agents were listed."); } } else { Logging.Log("Settings: Error! No Agents List specified."); } FactionFitting.Clear(); var factionFittings = xml.Element("factionfittings"); if (UseFittingManager) { if (factionFittings != null) { foreach (var factionfitting in factionFittings.Elements("factionfitting")) { FactionFitting.Add(new FactionFitting(factionfitting)); } if (FactionFitting.Exists(m => m.Faction.ToLower() == "default")) { DefaultFitting = FactionFitting.Find(m => m.Faction.ToLower() == "default"); if ((DefaultFitting.Fitting == "") || (DefaultFitting.Fitting == null)) { UseFittingManager = false; Logging.Log("Settings: Error! No default fitting specified or fitting is incorrect. Fitting manager will not be used."); } Logging.Log("Settings: Faction Fittings defined. Fitting manager will be used when appropriate."); } else { UseFittingManager = false; Logging.Log("Settings: Error! No default fitting specified or fitting is incorrect. Fitting manager will not be used."); } } else { UseFittingManager = false; Logging.Log("Settings: No faction fittings specified. Fitting manager will not be used."); } } MissionFitting.Clear(); var missionFittings = xml.Element("missionfittings"); if (UseFittingManager) { if (missionFittings != null) { foreach (var missionfitting in missionFittings.Elements("missionfitting")) { MissionFitting.Add(new MissionFitting(missionfitting)); } } } WeaponGroupId = (int?)xml.Element("weaponGroupId") ?? 0; ReserveCargoCapacity = (int?)xml.Element("reserveCargoCapacity") ?? 0; MaximumWreckTargets = (int?)xml.Element("maximumWreckTargets") ?? 0; SpeedTank = (bool?)xml.Element("speedTank") ?? false; OrbitDistance = (int?)xml.Element("orbitDistance") ?? 0; OptimalRange = (int?)xml.Element("optimalRange") ?? 0; NosDistance = (int?)xml.Element("NosDistance") ?? 38000; MinimumPropulsionModuleDistance = (int?)xml.Element("minimumPropulsionModuleDistance") ?? 5000; MinimumPropulsionModuleCapacitor = (int?)xml.Element("minimumPropulsionModuleCapacitor") ?? 0; ActivateRepairModules = (int?)xml.Element("activateRepairModules") ?? 65; DeactivateRepairModules = (int?)xml.Element("deactivateRepairModules") ?? 95; MinimumShieldPct = (int?)xml.Element("minimumShieldPct") ?? 100; MinimumArmorPct = (int?)xml.Element("minimumArmorPct") ?? 100; MinimumCapacitorPct = (int?)xml.Element("minimumCapacitorPct") ?? 50; SafeShieldPct = (int?)xml.Element("safeShieldPct") ?? 0; SafeArmorPct = (int?)xml.Element("safeArmorPct") ?? 0; SafeCapacitorPct = (int?)xml.Element("safeCapacitorPct") ?? 0; LootEverything = (bool?)xml.Element("lootEverything") ?? true; UseDrones = (bool?)xml.Element("useDrones") ?? true; DroneTypeId = (int?)xml.Element("droneTypeId") ?? 0; DroneControlRange = (int?)xml.Element("droneControlRange") ?? 0; DroneMinimumShieldPct = (int?)xml.Element("droneMinimumShieldPct") ?? 50; DroneMinimumArmorPct = (int?)xml.Element("droneMinimumArmorPct") ?? 50; DroneMinimumCapacitorPct = (int?)xml.Element("droneMinimumCapacitorPct") ?? 0; DroneRecallShieldPct = (int?)xml.Element("droneRecallShieldPct") ?? 0; DroneRecallArmorPct = (int?)xml.Element("droneRecallArmorPct") ?? 0; DroneRecallCapacitorPct = (int?)xml.Element("droneRecallCapacitorPct") ?? 0; LongRangeDroneRecallShieldPct = (int?)xml.Element("longRangeDroneRecallShieldPct") ?? 0; LongRangeDroneRecallArmorPct = (int?)xml.Element("longRangeDroneRecallArmorPct") ?? 0; LongRangeDroneRecallCapacitorPct = (int?)xml.Element("longRangeDroneRecallCapacitorPct") ?? 0; MaterialsForWarOreID = (int?)xml.Element("MaterialsForWarOreID") ?? 20; MaterialsForWarOreQty = (int?)xml.Element("MaterialsForWarOreQty") ?? 8000; Blacklist.Clear(); var blacklist = xml.Element("blacklist"); if (blacklist != null) { foreach (var mission in blacklist.Elements("mission")) { Blacklist.Add((string)mission); } } FactionBlacklist.Clear(); var factionblacklist = xml.Element("factionblacklist"); if (factionblacklist != null) { foreach (var faction in factionblacklist.Elements("faction")) { FactionBlacklist.Add((string)faction); } } WreckBlackListSmallWrecks = (bool?)xml.Element("WreckBlackListSmallWrecks") ?? false; WreckBlackListMediumWrecks = (bool?)xml.Element("WreckBlackListMediumWrecks") ?? false; // // if enabled the following would keep you from looting (or salvaging?) small wrecks // //list of small wreck if (WreckBlackListSmallWrecks) { WreckBlackList.Add(26557); WreckBlackList.Add(26561); WreckBlackList.Add(26564); WreckBlackList.Add(26567); WreckBlackList.Add(26570); WreckBlackList.Add(26573); WreckBlackList.Add(26576); WreckBlackList.Add(26579); WreckBlackList.Add(26582); WreckBlackList.Add(26585); WreckBlackList.Add(26588); WreckBlackList.Add(26591); WreckBlackList.Add(26594); WreckBlackList.Add(26935); } // // if enabled the following would keep you from looting (or salvaging?) medium wrecks // //list of medium wreck if (WreckBlackListMediumWrecks) { WreckBlackList.Add(26558); WreckBlackList.Add(26562); WreckBlackList.Add(26568); WreckBlackList.Add(26574); WreckBlackList.Add(26580); WreckBlackList.Add(26586); WreckBlackList.Add(26592); WreckBlackList.Add(26934); } logpath = (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\log\\" + Cache.Instance.DirectEve.Me.Name + "\\"); //logpath_s = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\log\\"; ConsoleLogPath = Path.Combine(logpath + "Console\\"); ConsoleLogFile = Path.Combine(ConsoleLogPath + string.Format("{0:MM-dd-yyyy}", DateTime.Today) + "-" + Cache.Instance.DirectEve.Me.Name + "-" + "console" + ".log"); SessionsLogPath = Path.Combine(logpath); SessionsLogFile = Path.Combine(SessionsLogPath + Cache.Instance.DirectEve.Me.Name + ".Sessions.log"); DroneStatsLogPath = Path.Combine(logpath); DroneStatslogFile = Path.Combine(DroneStatsLogPath + Cache.Instance.DirectEve.Me.Name + ".DroneStats.log"); WreckLootStatisticsPath = Path.Combine(logpath); WreckLootStatisticsFile = Path.Combine(WreckLootStatisticsPath + Cache.Instance.DirectEve.Me.Name + ".WreckLootStatisticsDump.log"); MissionStats1LogPath = Path.Combine(logpath, "missionstats\\"); MissionStats1LogFile = Path.Combine(MissionStats1LogPath + Cache.Instance.DirectEve.Me.Name + ".Statistics.log"); MissionStats2LogPath = Path.Combine(logpath, "missionstats\\"); MissionStats2LogFile = Path.Combine(MissionStats2LogPath + Cache.Instance.DirectEve.Me.Name + ".DatedStatistics.log"); MissionStats3LogPath = Path.Combine(logpath, "missionstats\\"); MissionStats3LogFile = Path.Combine(MissionStats3LogPath + Cache.Instance.DirectEve.Me.Name + ".CustomDatedStatistics.csv"); PocketStatisticsPath = Path.Combine(logpath, "pocketstats\\"); PocketStatisticsFile = Path.Combine(PocketStatisticsPath + Cache.Instance.DirectEve.Me.Name + "pocketstats-combined.csv"); //create all the logging directories even if they aren't configured to be used - we can adjust this later if it really bugs people to have some potentially empty directories. Directory.CreateDirectory(logpath); Directory.CreateDirectory(ConsoleLogPath); Directory.CreateDirectory(SessionsLogPath); Directory.CreateDirectory(DroneStatsLogPath); Directory.CreateDirectory(WreckLootStatisticsPath); Directory.CreateDirectory(MissionStats1LogPath); Directory.CreateDirectory(MissionStats2LogPath); Directory.CreateDirectory(MissionStats3LogPath); Directory.CreateDirectory(PocketStatisticsPath); if (SettingsLoaded != null) { SettingsLoaded(this, new EventArgs()); } }
private void ReplyToAgent() { var agentWindow = Agent.Window; if (agentWindow == null || !agentWindow.IsReady) { return; } var responses = agentWindow.AgentResponses; if (responses == null || responses.Count == 0) { return; } var request = responses.FirstOrDefault(r => r.Text.Contains(RequestMission)); var complete = responses.FirstOrDefault(r => r.Text.Contains(CompleteMission)); var view = responses.FirstOrDefault(r => r.Text.Contains(ViewMission)); var accept = responses.FirstOrDefault(r => r.Text.Contains(Accept)); var decline = responses.FirstOrDefault(r => r.Text.Contains(Decline)); if (complete != null) { if (Purpose == AgentInteractionPurpose.CompleteMission) { // Complete the mission, close convo Logging.Log("AgentInteraction: Saying [Complete Mission]"); complete.Say(); Logging.Log("AgentInteraction: Closing conversation"); State = AgentInteractionState.CloseConversation; _nextAction = DateTime.Now.AddSeconds(7); } else { Logging.Log("AgentInteraction: Waiting for mission"); // Apparently someone clicked "accept" already State = AgentInteractionState.WaitForMission; _nextAction = DateTime.Now.AddSeconds(7); } } else if (request != null) { if (Purpose == AgentInteractionPurpose.StartMission) { // Request a mission and wait for it Logging.Log("AgentInteraction: Saying [Request Mission]"); request.Say(); Logging.Log("AgentInteraction: Waiting for mission"); State = AgentInteractionState.WaitForMission; _nextAction = DateTime.Now.AddSeconds(7); } else { Logging.Log("AgentInteraction: Unexpected dialog options"); State = AgentInteractionState.UnexpectedDialogOptions; } } else if (view != null) { // View current mission Logging.Log("AgentInteraction: Saying [View Mission]"); view.Say(); _nextAction = DateTime.Now.AddSeconds(7); // No state change } else if (accept != null || decline != null) { if (Purpose == AgentInteractionPurpose.StartMission) { Logging.Log("AgentInteraction: Waiting for mission"); State = AgentInteractionState.WaitForMission; // Dont say anything, wait for the mission _nextAction = DateTime.Now.AddSeconds(7); } else { Logging.Log("AgentInteraction: Unexpected dialog options"); State = AgentInteractionState.UnexpectedDialogOptions; } } }
private void KillAction(Action action) { bool ignoreAttackers; if (!bool.TryParse(action.GetParameterValue("ignoreattackers"), out ignoreAttackers)) { ignoreAttackers = false; } bool breakOnAttackers; if (!bool.TryParse(action.GetParameterValue("breakonattackers"), out breakOnAttackers)) { breakOnAttackers = false; } var targetNames = action.GetParameterValues("target"); // No parameter? Ignore kill action if (targetNames.Count == 0) { Logging.Log("MissionController.Kill: No targets defined!"); _currentAction++; return; } var targets = Cache.Instance.Entities.Where(e => targetNames.Contains(e.Name)); if (targets.Count() == 0) { Logging.Log("MissionController.Kill: All targets killed " + targetNames.Aggregate((current, next) => current + "[" + next + "]")); // We killed it/them !?!?!? :) _currentAction++; return; } if (breakOnAttackers && Cache.Instance.TargetedBy.Any(t => !t.IsSentry && t.Distance < Cache.Instance.WeaponRange)) { // We are being attacked, break the kill order if (Cache.Instance.RemovePriorityTargets(targets)) { Logging.Log("MissionController.Kill: Breaking off kill order, new spawn has arived!"); } foreach (var target in Cache.Instance.Targets.Where(e => targets.Any(t => t.Id == e.Id))) { Logging.Log("MissionController.Kill: Unlocking [" + target.Name + "][" + target.Id + "] due to kill order being put on hold"); target.UnlockTarget(); } return; } if (!ignoreAttackers || breakOnAttackers) { // Apparently we are busy, wait for combat to clear attackers first var targetedBy = Cache.Instance.TargetedBy; if (targetedBy != null && targetedBy.Count(t => !t.IsSentry && t.Distance < Cache.Instance.WeaponRange) > 0) { return; } } var closest = targets.OrderBy(t => t.Distance).First(); if (closest.Distance < Cache.Instance.WeaponRange) { if (!Cache.Instance.PriorityTargets.Any(pt => pt.Id == closest.Id)) { Logging.Log("MissionController.Kill: Adding [" + closest.Name + "][" + closest.Id + "] as a priority target"); Cache.Instance.AddPriorityTargets(new[] { closest }, Priority.PriorityKillTarget); } if (Cache.Instance.Approaching != null && !Settings.Instance.SpeedTank) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdStopShip); Cache.Instance.Approaching = null; } } else { // Move within 80% max distance if (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != closest.Id) { Logging.Log("MissionController.Kill: Approaching target [" + closest.Name + "][" + closest.Id + "]"); if (Settings.Instance.SpeedTank) { closest.Orbit(Settings.Instance.OrbitDistance); } else { closest.Approach((int)(Cache.Instance.WeaponRange * 0.8d)); } } } }
public void ProcessState() { switch (State) { case PanicState.Normal: if (!Cache.Instance.InSpace) { _lastDockedorJumping = DateTime.Now; } if (DateTime.Now.AddSeconds(3) > _lastDockedorJumping) { if (Cache.Instance.DirectEve.ActiveShip.Entity != null) { _lastNormalX = Cache.Instance.DirectEve.ActiveShip.Entity.X; _lastNormalY = Cache.Instance.DirectEve.ActiveShip.Entity.Y; _lastNormalZ = Cache.Instance.DirectEve.ActiveShip.Entity.Z; } if (Cache.Instance.DirectEve.ActiveShip.GroupId == (int)Group.Capsule) { Logging.Log("Panic: You are in a Capsule, you must have died :("); State = PanicState.StartPanicking; } else if (InMission && Cache.Instance.InSpace && Cache.Instance.DirectEve.ActiveShip.CapacitorPercentage < Settings.Instance.MinimumCapacitorPct && Cache.Instance.DirectEve.ActiveShip.GroupId != 31) { // Only check for cap-panic while in a mission, not while doing anything else Logging.Log("Panic: Start panicking, capacitor [" + Cache.Instance.DirectEve.ActiveShip.CapacitorPercentage + "%] below [" + Settings.Instance.MinimumCapacitorPct + "%]"); //Questor.panic_attempts_this_mission; Cache.Instance.panic_attempts_this_mission = (Cache.Instance.panic_attempts_this_mission + 1); Cache.Instance.panic_attempts_this_pocket = (Cache.Instance.panic_attempts_this_pocket + 1); State = PanicState.StartPanicking; } else if (Cache.Instance.InSpace && Cache.Instance.DirectEve.ActiveShip.ShieldPercentage < Settings.Instance.MinimumShieldPct) { Logging.Log("Panic: Start panicking, shield [" + Cache.Instance.DirectEve.ActiveShip.ShieldPercentage + "%] below [" + Settings.Instance.MinimumShieldPct + "%]"); Cache.Instance.panic_attempts_this_mission = (Cache.Instance.panic_attempts_this_mission + 1); Cache.Instance.panic_attempts_this_pocket = (Cache.Instance.panic_attempts_this_pocket + 1); State = PanicState.StartPanicking; } else if (Cache.Instance.InSpace && Cache.Instance.DirectEve.ActiveShip.ArmorPercentage < Settings.Instance.MinimumArmorPct) { Logging.Log("Panic: Start panicking, armor [" + Cache.Instance.DirectEve.ActiveShip.ArmorPercentage + "%] below [" + Settings.Instance.MinimumArmorPct + "%]"); Cache.Instance.panic_attempts_this_mission = (Cache.Instance.panic_attempts_this_mission + 1); Cache.Instance.panic_attempts_this_pocket = (Cache.Instance.panic_attempts_this_pocket + 1); State = PanicState.StartPanicking; } _delayedResume = false; if (InMission) { var frigates = Cache.Instance.Entities.Count(e => e.IsFrigate && e.IsPlayer); var cruisers = Cache.Instance.Entities.Count(e => e.IsCruiser && e.IsPlayer); var battlecruisers = Cache.Instance.Entities.Count(e => e.IsBattlecruiser && e.IsPlayer); var battleships = Cache.Instance.Entities.Count(e => e.IsBattleship && e.IsPlayer); if (Settings.Instance.FrigateInvasionLimit > 0 && frigates >= Settings.Instance.FrigateInvasionLimit) { _delayedResume = true; Cache.Instance.panic_attempts_this_mission = (Cache.Instance.panic_attempts_this_mission + 1); Cache.Instance.panic_attempts_this_pocket = (Cache.Instance.panic_attempts_this_pocket + 1); State = PanicState.StartPanicking; Logging.Log("Panic: Start panicking, mission invaded by [" + frigates + "] frigates"); } if (Settings.Instance.CruiserInvasionLimit > 0 && cruisers >= Settings.Instance.CruiserInvasionLimit) { _delayedResume = true; Cache.Instance.panic_attempts_this_mission = (Cache.Instance.panic_attempts_this_mission + 1); Cache.Instance.panic_attempts_this_pocket = (Cache.Instance.panic_attempts_this_pocket + 1); State = PanicState.StartPanicking; Logging.Log("Panic: Start panicking, mission invaded by [" + cruisers + "] cruisers"); } if (Settings.Instance.BattlecruiserInvasionLimit > 0 && battlecruisers >= Settings.Instance.BattlecruiserInvasionLimit) { _delayedResume = true; Cache.Instance.panic_attempts_this_mission = (Cache.Instance.panic_attempts_this_mission + 1); Cache.Instance.panic_attempts_this_pocket = (Cache.Instance.panic_attempts_this_pocket + 1); State = PanicState.StartPanicking; Logging.Log("Panic: Start panicking, mission invaded by [" + battlecruisers + "] battlecruisers"); } if (Settings.Instance.BattleshipInvasionLimit > 0 && battleships >= Settings.Instance.BattleshipInvasionLimit) { _delayedResume = true; Cache.Instance.panic_attempts_this_mission = (Cache.Instance.panic_attempts_this_mission + 1); Cache.Instance.panic_attempts_this_pocket = (Cache.Instance.panic_attempts_this_pocket + 1); State = PanicState.StartPanicking; Logging.Log("Panic: Start panicking, mission invaded by [" + battleships + "] battleships"); } if (_delayedResume) { _randomDelay = (Settings.Instance.InvasionRandomDelay > 0 ? _random.Next(Settings.Instance.InvasionRandomDelay) : 0); _randomDelay += Settings.Instance.InvasionMinimumDelay; } } Cache.Instance.AddPriorityTargets(Cache.Instance.TargetedBy.Where(t => t.IsWarpScramblingMe), Priority.WarpScrambler); if (Settings.Instance.SpeedTank) { Cache.Instance.AddPriorityTargets(Cache.Instance.TargetedBy.Where(t => t.IsWebbingMe), Priority.Webbing); Cache.Instance.AddPriorityTargets(Cache.Instance.TargetedBy.Where(t => t.IsTargetPaintingMe), Priority.TargetPainting); } Cache.Instance.AddPriorityTargets(Cache.Instance.TargetedBy.Where(t => t.IsNeutralizingMe), Priority.Neutralizing); Cache.Instance.AddPriorityTargets(Cache.Instance.TargetedBy.Where(t => t.IsJammingMe), Priority.Jamming); Cache.Instance.AddPriorityTargets(Cache.Instance.TargetedBy.Where(t => t.IsSensorDampeningMe), Priority.Dampening); if (Cache.Instance.Modules.Any(m => m.IsTurret)) { Cache.Instance.AddPriorityTargets(Cache.Instance.TargetedBy.Where(t => t.IsTrackingDisruptingMe), Priority.TrackingDisrupting); } } break; // NOTE: The difference between Panicking and StartPanicking is that the bot will move to "Panic" state once in warp & Panicking // and the bot wont go into Panic mode while still "StartPanicking" case PanicState.StartPanicking: case PanicState.Panicking: // Add any warp scramblers to the priority list Cache.Instance.AddPriorityTargets(Cache.Instance.TargetedBy.Where(t => t.IsWarpScramblingMe), Priority.WarpScrambler); // Failsafe, in theory would/should never happen if (State == PanicState.Panicking && Cache.Instance.TargetedBy.Any(t => t.IsWarpScramblingMe)) { // Resume is the only state that will make Questor revert to combat mode State = PanicState.Resume; return; } if (Cache.Instance.InStation) { Logging.Log("Panic: Entered a station, lower panic mode"); State = PanicState.Panic; } // Once we have warped off 500km, assume we are "safer" if (State == PanicState.StartPanicking && Cache.Instance.DistanceFromMe(_lastNormalX, _lastNormalY, _lastNormalZ) > (int)Distance.PanicDistanceToConsiderSafelyWarpedOff) { Logging.Log("Panic: We've warped off"); State = PanicState.Panicking; } // We leave the panicking state once we actually start warping off var station = Cache.Instance.Stations.FirstOrDefault(); if (station != null) { if (Cache.Instance.InWarp) { break; } if (station.Distance > (int)Distance.WarptoDistance) { if (DateTime.Now.Subtract(_lastWarpTo).TotalSeconds > 5) { Logging.Log("Panic: Warping to [" + station.Name + "] which is [" + Math.Round(station.Distance / 1000, 0) + "k away]"); station.WarpTo(); _lastWarpTo = DateTime.Now; } } else if (DateTime.Now.Subtract(_lastDock).TotalSeconds > 5) { station.Dock(); _lastDock = DateTime.Now; } break; } // What is this you say? No star? if (Cache.Instance.Star == null) { break; } if (Cache.Instance.Star.Distance > (int)Distance.WeCanWarpToStarFromHere) { if (Cache.Instance.InWarp) { break; } if (Cache.Instance.TargetedBy.Where(t => t.IsWarpScramblingMe).Count() > 0) { Logging.Log("Panic: We are still warp scrambled!"); //This runs every 'tick' so we should see it every 1.5 seconds or so _lastWarpScrambled = DateTime.Now; } else if (DateTime.Now.Subtract(_lastWarpTo).TotalSeconds > 5 | DateTime.Now.Subtract(_lastWarpScrambled).TotalSeconds < 10) //this will effectively spam warpto as soon as you are free of warp disruption if you were warp disrupted in the past 10 seconds { Logging.Log("Panic: Warping to [" + Cache.Instance.Star.Name + "] which is [" + Math.Round(Cache.Instance.Star.Distance / 1000, 0) + "k away]"); Cache.Instance.Star.WarpTo(); _lastWarpTo = DateTime.Now; } } else { Logging.Log("Panic: At the star, lower panic mode"); State = PanicState.Panic; } break; case PanicState.Panic: // Do not resume until you're no longer in a capsule if (Cache.Instance.DirectEve.ActiveShip.GroupId == (int)Group.Capsule) { break; } if (Cache.Instance.InStation) { Logging.Log("Panic: We're in a station, resume mission"); State = _delayedResume ? PanicState.DelayedResume : PanicState.Resume; } var isSafe = Cache.Instance.DirectEve.ActiveShip.CapacitorPercentage > Settings.Instance.SafeCapacitorPct; isSafe &= Cache.Instance.DirectEve.ActiveShip.ShieldPercentage > Settings.Instance.SafeShieldPct; isSafe &= Cache.Instance.DirectEve.ActiveShip.ArmorPercentage > Settings.Instance.SafeArmorPct; if (isSafe) { Logging.Log("Panic: We've recovered, resume mission"); State = _delayedResume ? PanicState.DelayedResume : PanicState.Resume; } if (State == PanicState.DelayedResume) { Logging.Log("Panic: Delaying resume for " + _randomDelay + " seconds"); _resumeTime = DateTime.Now.AddSeconds(_randomDelay); } break; case PanicState.DelayedResume: if (DateTime.Now > _resumeTime) { State = PanicState.Resume; } break; case PanicState.Resume: // Don't do anything here break; } }
private void ActivateAction(Action action) { var target = action.GetParameterValue("target"); // No parameter? Although we shouldnt really allow it, assume its the acceleration gate :) if (string.IsNullOrEmpty(target)) { target = "Acceleration Gate"; } var targets = Cache.Instance.EntitiesByName(target); if (targets == null || targets.Count() == 0) { Logging.Log("AnomalyController.Activate: Can't find [" + target + "] to activate! Stopping Questor!"); State = AnomalyControllerState.Error; return; } var closest = targets.OrderBy(t => t.Distance).First(); if (closest.Distance < (int)Distance.GateActivationRange) { // Tell the drones module to retract drones Cache.Instance.IsMissionPocketDone = true; // We cant activate if we have drones out if (Cache.Instance.ActiveDrones.Count() > 0) { return; } if (closest.Distance < (int)Distance.WayTooClose) { if ((DateTime.Now.Subtract(_lastOrbit).TotalSeconds > 15)) { closest.Orbit((int)Distance.GateActivationRange); Logging.Log("AnomolyController: Activate: initiating Orbit of [" + closest.Name + "] orbiting at [" + Cache.Instance.OrbitDistance + "]"); _lastOrbit = DateTime.Now; } } Logging.Log(" dist " + closest.Distance); if (closest.Distance >= (int)Distance.WayTooClose) { // Add bookmark (before we activate) if (Settings.Instance.CreateSalvageBookmarks) { BookmarkPocketForSalvaging(); } // Reload weapons and activate gate to move to the next pocket ReloadAll(); closest.Activate(); // Do not change actions, if NextPocket gets a timeout (>2 mins) then it reverts to the last action Logging.Log("AnomalyController.Activate: Activate [" + closest.Name + "] and change state to 'NextPocket'"); _lastActivateAction = DateTime.Now; State = AnomalyControllerState.NextPocket; } } else if (closest.Distance < (int)Distance.WarptoDistance) { // Move to the target if (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != closest.Id) { Logging.Log("AnomalyController.Activate: Approaching target [" + closest.Name + "][ID: " + closest.Id + "]"); closest.Approach(); } } else { // We cant warp if we have drones out if (Cache.Instance.ActiveDrones.Count() > 0) { return; } if (DateTime.Now.Subtract(_lastAlign).TotalMinutes > 2) { // Probably never happens closest.AlignTo(); _lastAlign = DateTime.Now; } } }
/// <summary> /// Activates tractorbeam on targeted wrecks /// </summary> private void ActivateTractorBeams() { // We are not in space yet, wait... if (!Cache.Instance.InSpace) { return; } var tractorBeams = Cache.Instance.Modules.Where(m => TractorBeams.Contains(m.TypeId)).ToList(); if (tractorBeams.Count == 0) { return; } var tractorBeamRange = tractorBeams.Min(t => t.OptimalRange); var wrecks = Cache.Instance.Targets.Where(t => (t.GroupId == (int)Group.Wreck || t.GroupId == (int)Group.CargoContainer) && t.Distance < tractorBeamRange).ToList(); for (var i = tractorBeams.Count - 1; i >= 0; i--) { var tractorBeam = tractorBeams[i]; if (!tractorBeam.IsActive && !tractorBeam.IsDeactivating) { continue; } var wreck = wrecks.FirstOrDefault(w => w.Id == tractorBeam.TargetId); // If the wreck no longer exists, or its within loot range then disable the tractor beam if (tractorBeam.IsActive && (wreck == null || wreck.Distance <= 2500)) { tractorBeam.Deactivate(); } // Remove the tractor beam as a possible beam to activate tractorBeams.RemoveAt(i); wrecks.RemoveAll(w => w.Id == tractorBeam.TargetId); } foreach (var wreck in wrecks) { // This velocity check solves some bugs where velocity showed up as 150000000m/s if (wreck.Velocity != 0 && wreck.Velocity < 2500) { continue; } // Is this wreck within range? if (wreck.Distance <= 2500) { continue; } if (tractorBeams.Count == 0) { return; } var tractorBeam = tractorBeams[0]; tractorBeams.RemoveAt(0); tractorBeam.Activate(wreck.Id); Logging.Log("Salvage: Activating tractorbeam [" + tractorBeam.ItemId + "] on [" + wreck.Name + "][" + wreck.Id + "]"); } }
public void ProcessState() { if (!Settings.Instance.UseDrones) { return; } switch (State) { case DroneState.WaitingForTargets: // Are we in the right state ? if (Cache.Instance.ActiveDrones.Count() > 0) { // Apparently not, we have drones out, go into fight mode State = DroneState.Fighting; break; } // Should we launch drones? var launch = true; // Always launch if we're scrambled if (!Cache.Instance.PriorityTargets.Any(pt => pt.IsWarpScramblingMe)) { launch &= Cache.Instance.UseDrones; // Are we done with this mission pocket? launch &= !Cache.Instance.IsMissionPocketDone; // If above minimums launch &= Cache.Instance.DirectEve.ActiveShip.ShieldPercentage >= Settings.Instance.DroneMinimumShieldPct; launch &= Cache.Instance.DirectEve.ActiveShip.ArmorPercentage >= Settings.Instance.DroneMinimumArmorPct; launch &= Cache.Instance.DirectEve.ActiveShip.CapacitorPercentage >= Settings.Instance.DroneMinimumCapacitorPct; // yes if there are targets to kill launch &= Cache.Instance.TargetedBy.Count(e => !e.IsSentry && e.CategoryId == (int)CategoryID.Entity && e.IsNpc && !e.IsContainer && e.GroupId != (int)Group.LargeCollidableStructure && e.Distance < Settings.Instance.DroneControlRange) > 0; // If drones get agro'd within 30 seconds, then wait (5 * _recallCount + 5) seconds since the last recall if (_lastLaunch < _lastRecall && _lastRecall.Subtract(_lastLaunch).TotalSeconds < 30) { if (_lastRecall.AddSeconds(5 * _recallCount + 5) < DateTime.Now) { // Increase recall count and allow the launch _recallCount++; // Never let _recallCount go above 5 if (_recallCount > 5) { _recallCount = 5; } } else { // Do not launch the drones until the delay has passed launch = false; } } else // Drones have been out for more then 30s { _recallCount = 0; } } if (launch) { // Reset launch tries _launchTries = 0; _lastLaunch = DateTime.Now; State = DroneState.Launch; } break; case DroneState.Launch: // Launch all drones _launchTimeout = DateTime.Now; Cache.Instance.DirectEve.ActiveShip.LaunchAllDrones(); State = DroneState.Launching; break; case DroneState.Launching: // We haven't launched anything yet, keep waiting if (Cache.Instance.ActiveDrones.Count() == 0) { if (DateTime.Now.Subtract(_launchTimeout).TotalSeconds > 10) { // Relaunch if tries < 10 if (_launchTries < 10) { _launchTries++; State = DroneState.Launch; break; } else { State = DroneState.OutOfDrones; } } break; } // Are we done launching? if (_lastDroneCount == Cache.Instance.ActiveDrones.Count()) { State = DroneState.Fighting; } break; case DroneState.OutOfDrones: //if (DateTime.Now.Subtract(_launchTimeout).TotalSeconds > 1000) //{ // State = DroneState.WaitingForTargets; //} break; case DroneState.Fighting: // Should we recall our drones? This is a possible list of reasons why we should var recall = false; // Are we done (for now) ? if (Cache.Instance.TargetedBy.Count(e => !e.IsSentry && e.IsNpc && e.Distance < Settings.Instance.DroneControlRange) == 0) { Logging.Log("Drones: Recalling drones because no NPC is targeting us within dronerange"); recall = true; } if (Cache.Instance.IsMissionPocketDone) { Logging.Log("Drones: Recalling drones because we are done with this pocket."); recall = true; } else if (_shieldPctTotal > GetShieldPctTotal()) { Logging.Log("Drones: Recalling drones because we have lost shields! [Old: " + _shieldPctTotal.ToString("N2") + "][New: " + GetShieldPctTotal().ToString("N2") + "]"); recall = true; } else if (_armorPctTotal > GetArmorPctTotal()) { Logging.Log("Drones: Recalling drones because we have lost armor! [Old:" + _armorPctTotal.ToString("N2") + "][New: " + GetArmorPctTotal().ToString("N2") + "]"); recall = true; } else if (_structurePctTotal > GetStructurePctTotal()) { Logging.Log("Drones: Recalling drones because we have lost structure! [Old:" + _structurePctTotal.ToString("N2") + "][New: " + GetStructurePctTotal().ToString("N2") + "]"); recall = true; } else if (Cache.Instance.ActiveDrones.Count() < _lastDroneCount) { // Did we lose a drone? (this should be covered by total's as well though) Logging.Log("Drones: Recalling drones because we have lost a drone! [Old:" + _lastDroneCount + "][New: " + Cache.Instance.ActiveDrones.Count() + "]"); recall = true; } else { // Default to long range recall var lowShieldWarning = Settings.Instance.LongRangeDroneRecallShieldPct; var lowArmorWarning = Settings.Instance.LongRangeDroneRecallArmorPct; var lowCapWarning = Settings.Instance.LongRangeDroneRecallCapacitorPct; if (Cache.Instance.ActiveDrones.Average(d => d.Distance) < (Settings.Instance.DroneControlRange / 2d)) { lowShieldWarning = Settings.Instance.DroneRecallShieldPct; lowArmorWarning = Settings.Instance.DroneRecallArmorPct; lowCapWarning = Settings.Instance.DroneRecallCapacitorPct; } if (Cache.Instance.DirectEve.ActiveShip.ShieldPercentage < lowShieldWarning) { Logging.Log("Drones: Recalling drones due to shield [" + Cache.Instance.DirectEve.ActiveShip.ShieldPercentage + "%] below [" + lowShieldWarning + "%] minimum"); recall = true; } else if (Cache.Instance.DirectEve.ActiveShip.ArmorPercentage < lowArmorWarning) { Logging.Log("Drones: Recalling drones due to armor [" + Cache.Instance.DirectEve.ActiveShip.ArmorPercentage + "%] below [" + lowArmorWarning + "%] minimum"); recall = true; } else if (Cache.Instance.DirectEve.ActiveShip.CapacitorPercentage < lowCapWarning) { Logging.Log("Drones: Recalling drones due to capacitor [" + Cache.Instance.DirectEve.ActiveShip.CapacitorPercentage + "%] below [" + lowCapWarning + "%] minimum"); recall = true; } } if (Cache.Instance.ActiveDrones.Count() == 0) { Logging.Log("Drones: Apparently we have lost all our drones"); recall = true; } else { var isPanicking = false; isPanicking |= Cache.Instance.DirectEve.ActiveShip.ShieldPercentage < Settings.Instance.MinimumShieldPct; isPanicking |= Cache.Instance.DirectEve.ActiveShip.ArmorPercentage < Settings.Instance.MinimumArmorPct; isPanicking |= Cache.Instance.DirectEve.ActiveShip.CapacitorPercentage < Settings.Instance.MinimumCapacitorPct; if (Cache.Instance.PriorityTargets.Any(pt => pt.IsWarpScramblingMe) && recall) { Logging.Log("Drones: Overriding drone recall, we are scrambled!"); recall = false; } } // Recall or engage if (recall) { State = DroneState.Recalling; } else { EngageTarget(); // We lost a drone and did not recall, assume panicking and launch (if any) additional drones if (Cache.Instance.ActiveDrones.Count() < _lastDroneCount) { State = DroneState.Launch; } } break; case DroneState.Recalling: // Are we done? if (Cache.Instance.ActiveDrones.Count() == 0) { _lastRecall = DateTime.Now; State = DroneState.WaitingForTargets; break; } // Give recall command every 5 seconds if (DateTime.Now.Subtract(_lastRecallCommand).TotalSeconds > 5) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdDronesReturnToBay); _lastRecallCommand = DateTime.Now; } break; } // Update health values _shieldPctTotal = GetShieldPctTotal(); _armorPctTotal = GetArmorPctTotal(); _structurePctTotal = GetStructurePctTotal(); _lastDroneCount = Cache.Instance.ActiveDrones.Count(); }
/// <summary> /// Navigate to a solar system /// </summary> /// <param name = "solarSystemId"></param> private void NagivateToBookmarkSystem(long solarSystemId) { if (_nextTravelerAction > DateTime.Now) { return; } var undockBookmark = UndockBookmark; UndockBookmark = undockBookmark; var destination = Cache.Instance.DirectEve.Navigation.GetDestinationPath(); if (destination.Count == 0 || !destination.Any(d => d == solarSystemId)) { // We do not have the destination set var location = Cache.Instance.DirectEve.Navigation.GetLocation(solarSystemId); if (location.IsValid) { Logging.Log("Traveler: Setting destination to [" + location.Name + "]"); location.SetDestination(); } else { Logging.Log("Traveler: Error setting solar system destination [" + solarSystemId + "]"); State = TravelerState.Error; } return; } else { if (!Cache.Instance.InSpace) { if (Cache.Instance.InStation) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdExitStation); _nextTravelerAction = DateTime.Now.AddSeconds((int)Time.TravelerExitStationAmIInSpaceYet_seconds); } // We are not yet in space, wait for it return; } // Find the first waypoint var waypoint = destination.First(); // Get the name of the next systems var locationName = Cache.Instance.DirectEve.Navigation.GetLocationName(waypoint); // Find the stargate associated with it var entities = Cache.Instance.EntitiesByName(locationName).Where(e => e.GroupId == (int)Group.Stargate); if (entities.Count() == 0) { // not found, that cant be true?!?!?!?! Logging.Log("Traveler: Error [Stargate (" + locationName + ")] not found, most likely lag waiting 15 seconds."); _nextTravelerAction = DateTime.Now.AddSeconds((int)Time.TravelerNoStargatesFoundRetryDelay_seconds); return; } // Warp to, approach or jump the stargate var entity = entities.First(); if (entity.Distance < (int)Distance.DecloakRange) { Logging.Log("Traveler: Jumping to [" + locationName + "]"); entity.Jump(); _nextTravelerAction = DateTime.Now.AddSeconds((int)Time.TravelerJumpedGateNextCommandDelay_seconds); } else if (entity.Distance < (int)Distance.WarptoDistance) { entity.Approach(); //you could use a negative approach distance here but ultimately that is a bad idea.. Id like to go toward the entity without approaching it so we would end up inside the docking ring (eventually) } else { Logging.Log("Traveler: Warping to [Stargate (" + locationName + ")]"); entity.WarpTo(); _nextTravelerAction = DateTime.Now.AddSeconds((int)Time.TravelerInWarpedNextCommandDelay_seconds); } } }
public void LoadSettings() { var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var settingsPath = Path.Combine(path, Cache.Instance.FilterPath(_characterName) + ".xml"); var reloadSettings = _characterName != Cache.Instance.DirectEve.Me.Name; if (File.Exists(settingsPath)) { reloadSettings = _lastModifiedDate != File.GetLastWriteTime(settingsPath); } if (!reloadSettings) { return; } _characterName = Cache.Instance.DirectEve.Me.Name; _lastModifiedDate = File.GetLastWriteTime(settingsPath); if (!File.Exists(settingsPath)) { // Clear settings AgentName = string.Empty; AutoStart = false; waitDecline = false; RandomDelay = 0; minStandings = 10; WindowXPosition = null; WindowYPosition = null; LootHangar = string.Empty; AmmoHangar = string.Empty; MissionsPath = Path.Combine(path, "Missions"); MaximumHighValueTargets = 0; MaximumLowValueTargets = 0; Ammo.Clear(); FactionFitting.Clear(); MissionFitting.Clear(); MinimumAmmoCharges = 0; WeaponGroupId = 0; ReserveCargoCapacity = 0; MaximumWreckTargets = 0; SpeedTank = false; OrbitDistance = 0; ActivateRepairModules = 0; DeactivateRepairModules = 0; MinimumShieldPct = 0; MinimumArmorPct = 0; MinimumCapacitorPct = 0; SafeShieldPct = 0; SafeArmorPct = 0; SafeCapacitorPct = 0; UseDrones = false; DroneTypeId = 0; DroneControlRange = 0; DroneMinimumShieldPct = 0; DroneMinimumArmorPct = 0; DroneMinimumCapacitorPct = 0; DroneRecallCapacitorPct = 0; LongRangeDroneRecallCapacitorPct = 0; UseGatesInSalvage = false; Blacklist.Clear(); FactionBlacklist.Clear(); return; } var xml = XDocument.Load(settingsPath).Root; DebugStates = (bool?)xml.Element("debugStates") ?? false; DebugPerformance = (bool?)xml.Element("debugPerformance") ?? false; AutoStart = (bool?)xml.Element("autoStart") ?? false; waitDecline = (bool?)xml.Element("waitDecline") ?? false; RandomDelay = (int?)xml.Element("randomDelay") ?? 0; minStandings = (float?)xml.Element("minStandings") ?? 10; UseGatesInSalvage = (bool?)xml.Element("useGatesInSalvage") ?? false; EnableStorylines = (bool?)xml.Element("enableStorylines") ?? false; WindowXPosition = (int?)xml.Element("windowXPosition"); WindowYPosition = (int?)xml.Element("windowYPosition"); CombatShipName = (string)xml.Element("combatShipName"); SalvageShipName = (string)xml.Element("salvageShipName"); LootHangar = (string)xml.Element("lootHangar"); AmmoHangar = (string)xml.Element("ammoHangar"); CreateSalvageBookmarks = (bool?)xml.Element("createSalvageBookmarks") ?? false; BookmarkPrefix = (string)xml.Element("bookmarkPrefix") ?? "Salvage:"; MinimumWreckCount = (int?)xml.Element("minimumWreckCount") ?? 1; AfterMissionSalvaging = (bool?)xml.Element("afterMissionSalvaging") ?? false; UnloadLootAtStation = (bool?)xml.Element("unloadLootAtStation") ?? false; AgentName = (string)xml.Element("agentName"); var missionsPath = (string)xml.Element("missionsPath"); MissionsPath = !string.IsNullOrEmpty(missionsPath) ? Path.Combine(path, missionsPath) : Path.Combine(path, "Missions"); MaximumHighValueTargets = (int?)xml.Element("maximumHighValueTargets") ?? 2; MaximumLowValueTargets = (int?)xml.Element("maximumLowValueTargets") ?? 2; Ammo.Clear(); var ammoTypes = xml.Element("ammoTypes"); if (ammoTypes != null) { foreach (var ammo in ammoTypes.Elements("ammoType")) { Ammo.Add(new Ammo(ammo)); } } MinimumAmmoCharges = (int?)xml.Element("minimumAmmoCharges") ?? 0; FactionFitting.Clear(); var factionFittings = xml.Element("factionfittings"); if (factionFittings != null) { foreach (var factionfitting in factionFittings.Elements("factionfitting")) { FactionFitting.Add(new FactionFitting(factionfitting)); } if (FactionFitting.Exists(m => m.Faction.ToLower() == "default")) { DefaultFitting = FactionFitting.Find(m => m.Faction.ToLower() == "default"); if (!(DefaultFitting.Fitting == "") && !(DefaultFitting.Fitting == null)) { FittingsDefined = true; } else { Logging.Log("Settings: Error! No default fitting specified or fitting is incorrect. Fitting manager will not be used."); } } else { Logging.Log("Settings: Error! No default fitting specified or fitting is incorrect. Fitting manager will not be used."); } } else { Logging.Log("Settings: No faction fittings specified. Fitting manager will not be used."); } MissionFitting.Clear(); var missionFittings = xml.Element("missionfittings"); if (missionFittings != null) { foreach (var missionfitting in missionFittings.Elements("missionfitting")) { MissionFitting.Add(new MissionFitting(missionfitting)); } } WeaponGroupId = (int?)xml.Element("weaponGroupId") ?? 0; ReserveCargoCapacity = (int?)xml.Element("reserveCargoCapacity") ?? 0; MaximumWreckTargets = (int?)xml.Element("maximumWreckTargets") ?? 0; SpeedTank = (bool?)xml.Element("speedTank") ?? false; OrbitDistance = (int?)xml.Element("orbitDistance") ?? 0; ActivateRepairModules = (int?)xml.Element("activateRepairModules") ?? 65; DeactivateRepairModules = (int?)xml.Element("deactivateRepairModules") ?? 95; MinimumShieldPct = (int?)xml.Element("minimumShieldPct") ?? 100; MinimumArmorPct = (int?)xml.Element("minimumArmorPct") ?? 100; MinimumCapacitorPct = (int?)xml.Element("minimumCapacitorPct") ?? 50; SafeShieldPct = (int?)xml.Element("safeShieldPct") ?? 0; SafeArmorPct = (int?)xml.Element("safeArmorPct") ?? 0; SafeCapacitorPct = (int?)xml.Element("safeCapacitorPct") ?? 0; LootEverything = (bool?)xml.Element("lootEverything") ?? true; UseDrones = (bool?)xml.Element("useDrones") ?? true; DroneTypeId = (int?)xml.Element("droneTypeId") ?? 0; DroneControlRange = (int?)xml.Element("droneControlRange") ?? 0; DroneMinimumShieldPct = (int?)xml.Element("droneMinimumShieldPct") ?? 50; DroneMinimumArmorPct = (int?)xml.Element("droneMinimumArmorPct") ?? 50; DroneMinimumCapacitorPct = (int?)xml.Element("droneMinimumCapacitorPct") ?? 0; DroneRecallShieldPct = (int?)xml.Element("droneRecallShieldPct") ?? 0; DroneRecallArmorPct = (int?)xml.Element("droneRecallArmorPct") ?? 0; DroneRecallCapacitorPct = (int?)xml.Element("droneRecallCapacitorPct") ?? 0; LongRangeDroneRecallShieldPct = (int?)xml.Element("longRangeDroneRecallShieldPct") ?? 0; LongRangeDroneRecallArmorPct = (int?)xml.Element("longRangeDroneRecallArmorPct") ?? 0; LongRangeDroneRecallCapacitorPct = (int?)xml.Element("longRangeDroneRecallCapacitorPct") ?? 0; Blacklist.Clear(); var blacklist = xml.Element("blacklist"); if (blacklist != null) { foreach (var mission in blacklist.Elements("mission")) { Blacklist.Add((string)mission); } } FactionBlacklist.Clear(); var factionblacklist = xml.Element("factionblacklist"); if (factionblacklist != null) { foreach (var faction in factionblacklist.Elements("faction")) { FactionBlacklist.Add((string)faction); } } if (SettingsLoaded != null) { SettingsLoaded(this, new EventArgs()); } }
/// <summary> /// Activates tractorbeam on targeted wrecks /// </summary> private void ActivateTractorBeams() { if (_nextSalvageAction > DateTime.Now) { return; } var tractorBeams = Cache.Instance.Modules.Where(m => TractorBeams.Contains(m.TypeId)).ToList(); if (tractorBeams.Count == 0) { return; } var tractorBeamRange = tractorBeams.Min(t => t.OptimalRange); var wrecks = Cache.Instance.Targets.Where(t => (t.GroupId == (int)Group.Wreck || t.GroupId == (int)Group.CargoContainer) && t.Distance < tractorBeamRange).ToList(); Logging.Log(Cache.Instance.DirectEve.ActiveShip.Entity.Mode.ToString()); if (wrecks.FirstOrDefault() == null) { var wrecksFar = Cache.Instance.Entities.Where(t => (t.GroupId == (int)Group.Wreck || t.GroupId == (int)Group.CargoContainer) && t.Distance > tractorBeamRange).ToList(); if (wrecksFar.Count > 0) { if (Cache.Instance.DirectEve.ActiveShip.Entity.Mode != 1) { if (_nextApproachAction < DateTime.Now) { _nextApproachAction = DateTime.Now.AddSeconds((int)Time.ApproachDelay_seconds); wrecksFar.FirstOrDefault().Approach(); } } } State = SalvageState.TargetWrecks; return; } ; for (var i = tractorBeams.Count - 1; i >= 0; i--) { var tractorBeam = tractorBeams[i]; if (!tractorBeam.IsActive && !tractorBeam.IsDeactivating) { continue; } var wreck = wrecks.FirstOrDefault(w => w.Id == tractorBeam.TargetId); // If the wreck no longer exists, or its within loot range then disable the tractor beam if (tractorBeam.IsActive && (wreck == null || wreck.Distance <= (int)Distance.SafeScoopRange)) { tractorBeam.Deactivate(); _nextSalvageAction = DateTime.Now.AddMilliseconds((int)Time.SalvageDelayBetweenActions_miliseconds); return; //More human behaviour //System.Threading.Thread.Sleep(333); } // Remove the tractor beam as a possible beam to activate tractorBeams.RemoveAt(i); wrecks.RemoveAll(w => w.Id == tractorBeam.TargetId); } foreach (var wreck in wrecks) { // This velocity check solves some bugs where velocity showed up as 150000000m/s if (wreck.Velocity != 0 && wreck.Velocity < (int)Distance.SafeScoopRange) { continue; } // Is this wreck within range? if (wreck.Distance < (int)Distance.SafeScoopRange) { continue; } if (tractorBeams.Count == 0) { return; } var tractorBeam = tractorBeams[0]; tractorBeams.RemoveAt(0); tractorBeam.Activate(wreck.Id); Logging.Log("Salvage: Activating tractorbeam [" + tractorBeam.ItemId + "] on [" + wreck.Name + "][" + wreck.Id + "]"); //More human behaviour //System.Threading.Thread.Sleep(333); _nextSalvageAction = DateTime.Now.AddMilliseconds((int)Time.SalvageDelayBetweenActions_miliseconds); return; } }
private void WaitForMission() { var agentWindow = Agent.Window; if (agentWindow == null || !agentWindow.IsReady) { return; } var journalWindow = Cache.Instance.GetWindowByName("journal"); if (journalWindow == null) { if (DateTime.Now.Subtract(_lastMissionOpenRequest).TotalSeconds > 10) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenJournal); _lastMissionOpenRequest = DateTime.Now; } return; } var mission = Cache.Instance.DirectEve.AgentMissions.FirstOrDefault(m => m.AgentId == AgentId); if (mission == null) { return; } var missionName = Cache.Instance.FilterPath(mission.Name); var html = agentWindow.Objective; if (CheckFaction()) { if (Purpose != AgentInteractionPurpose.AmmoCheck) { Logging.Log("AgentInteraction: Declining blacklisted faction mission"); } State = AgentInteractionState.DeclineMission; _nextAction = DateTime.Now.AddSeconds(7); return; } if (!ForceAccept) { // Is the mission offered? if (mission.State == (int)MissionState.Offered && (mission.Type == "Courier" || mission.Type == "Mining" || mission.Type == "Trade" || Settings.Instance.Blacklist.Any(m => m.ToLower() == missionName.ToLower()))) { Logging.Log("AgentInteraction: Declining courier/mining/trade/blacklisted mission [" + missionName + "]"); State = AgentInteractionState.DeclineMission; _nextAction = DateTime.Now.AddSeconds(7); return; } } // var html = agentWindow.Objective; if (html.Contains("The route generated by current autopilot settings contains low security systems!")) { if (Purpose != AgentInteractionPurpose.AmmoCheck) { Logging.Log("AgentInteraction: Declining low-sec mission"); } State = AgentInteractionState.DeclineMission; _nextAction = DateTime.Now.AddSeconds(7); return; } var loadedAmmo = false; var missionXmlPath = Path.Combine(Settings.Instance.MissionsPath, missionName + ".xml"); if (File.Exists(missionXmlPath)) { Logging.Log("AgentInteraction: Loading mission xml [" + missionName + "]"); try { var missionXml = XDocument.Load(missionXmlPath); var damageTypes = missionXml.XPathSelectElements("//damagetype").Select(e => (DamageType)Enum.Parse(typeof(DamageType), (string)e, true)); if (damageTypes.Any()) { LoadSpecificAmmo(damageTypes.Distinct()); loadedAmmo = true; } } catch (Exception ex) { Logging.Log("AgentInteraction: Error parsing damage types for mission [" + mission.Name + "], " + ex.Message); } } if (!loadedAmmo) { Logging.Log("AgentInteraction: Detecting damage type for [" + missionName + "]"); Cache.Instance.DamageType = GetMissionDamageType(html); LoadSpecificAmmo(new[] { Cache.Instance.DamageType }); } if (Purpose == AgentInteractionPurpose.AmmoCheck) { Logging.Log("AgentInteraction: Closing conversation"); State = AgentInteractionState.CloseConversation; return; } if (mission.State == (int)MissionState.Offered) { Logging.Log("AgentInteraction: Accepting mission [" + missionName + "]"); State = AgentInteractionState.AcceptMission; _nextAction = DateTime.Now.AddSeconds(7); } else // If we already accepted the mission, close the convo { Logging.Log("AgentInteraction: Mission [" + missionName + "] already accepted"); Logging.Log("AgentInteraction: Closing conversation"); //CheckFaction(); State = AgentInteractionState.CloseConversation; _nextAction = DateTime.Now.AddSeconds(7); } }
private void ClearPocketAction(Action action) { var activeTargets = new List <EntityCache>(); activeTargets.AddRange(Cache.Instance.Targets); activeTargets.AddRange(Cache.Instance.Targeting); // Get lowest range var range = Math.Min(Cache.Instance.WeaponRange, Cache.Instance.DirectEve.ActiveShip.MaxTargetRange); // We are obviously still killing stuff that's in range if (activeTargets.Count(t => t.Distance < range && t.IsNpc && t.CategoryId == (int)CategoryID.Entity) > 0) { // Reset timeout _clearPocketTimeout = null; /*if (Cache.Instance.Approaching != null && !Settings.Instance.SpeedTank) * { * Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdStopShip); * Cache.Instance.Approaching = null; * Logging.Log("AnomalyController: ClearPocket: Stop Ship. we are in weapons range"); * }*/ return; } // Is there a priority target out of range? var target = Cache.Instance.PriorityTargets.OrderBy(t => t.Distance).Where(t => (!Cache.Instance.IgnoreTargets.Contains(t.Name.Trim()) || Cache.Instance.TargetedBy.Any(w => w.IsWarpScramblingMe))).FirstOrDefault(); // Or is there a target out of range that is targeting us? target = target ?? Cache.Instance.TargetedBy.Where(t => !t.IsSentry && !t.IsContainer && t.IsNpc && t.CategoryId == (int)CategoryID.Entity && t.GroupId != (int)Group.LargeCollidableStructure && !Cache.Instance.IgnoreTargets.Contains(t.Name.Trim()) || Cache.Instance.TargetedBy.Any(w => w.IsWarpScramblingMe)).OrderBy(t => t.Distance).FirstOrDefault(); // Or is there any target out of range? target = target ?? Cache.Instance.Entities.Where(t => !t.IsSentry && !t.IsContainer && t.IsNpc && t.CategoryId == (int)CategoryID.Entity && t.GroupId != (int)Group.LargeCollidableStructure && !Cache.Instance.IgnoreTargets.Contains(t.Name.Trim()) || Cache.Instance.TargetedBy.Any(w => w.IsWarpScramblingMe)).OrderBy(t => t.Distance).FirstOrDefault(); if (target != null) { // Reset timeout _clearPocketTimeout = null; // Lock priority target if within weapons range if (target.Distance < range) { if (Cache.Instance.DirectEve.ActiveShip.MaxLockedTargets > 0) { if (target.IsTarget || target.IsTargeting) //This target is already targeted no need to target it again { return; } else { Logging.Log("AnomalyController.ClearPocket: Targeting [" + target.Name + "][ID: " + target.Id + "][" + Math.Round(target.Distance / 1000, 0) + "k away]"); target.LockTarget(); } } return; } // Are we approaching the active (out of range) target? // Wait for it (or others) to get into range if (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != target.Id) { Logging.Log("AnomalyController.ClearPocket: Approaching target [" + target.Name + "][ID: " + target.Id + "]"); if (Settings.Instance.SpeedTank) { if ((DateTime.Now.Subtract(_lastOrbit).TotalSeconds > 15)) { target.Orbit(Cache.Instance.OrbitDistance); Logging.Log("AnomolyController: Clearpocket: initiating Orbit of [" + target.Name + "] orbiting at [" + Cache.Instance.OrbitDistance + "]"); _lastOrbit = DateTime.Now; } } else { if (target.Distance > Cache.Instance.OrbitDistance + (int)Distance.OrbitDistanceCushion) { target.Approach(Cache.Instance.OrbitDistance); } else { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdStopShip); Cache.Instance.Approaching = null; Logging.Log("AnomalyController: ClearPocket: Stop Ship. we are in weapons range"); } } } return; } // Do we have a timeout? No, set it to now + 5 seconds if (!_clearPocketTimeout.HasValue) { _clearPocketTimeout = DateTime.Now.AddSeconds(5); } // Are we in timeout? if (DateTime.Now < _clearPocketTimeout.Value) { return; } // We have cleared the Pocket, perform the next action \o/ _currentAction++; // Reset timeout _clearPocketTimeout = null; }
private void DeclineMission() { // If we are doing an ammo check then Decline Mission is an end-state! if (Purpose == AgentInteractionPurpose.AmmoCheck) { return; } var agentWindow = Agent.Window; if (agentWindow == null || !agentWindow.IsReady) { return; } var responses = agentWindow.AgentResponses; if (responses == null || responses.Count == 0) { return; } var decline = responses.FirstOrDefault(r => r.Text.Contains(Decline)); if (decline == null) { return; } // Check for agent decline timer if (waitDecline) { var html = agentWindow.Briefing; if (html.Contains("Declining a mission from this agent within the next")) { var standingRegex = new Regex("Effective Standing:\\s(?<standing>\\d+.\\d+)"); var standingMatch = standingRegex.Match(html); float standings = 0; if (standingMatch.Success) { var standingValue = standingMatch.Groups["standing"].Value; standingValue = standingValue.Replace('.', ','); // necessary for systems w/ comma-delimited number formatting standings = float.Parse(standingValue); Logging.Log("AgentInteraction: Agent decline timer detected. Current standings: " + standings + ". Minimum standings: " + minStandings); } if (standings <= minStandings) { var hourRegex = new Regex("\\s(?<hour>\\d+)\\shour"); var minuteRegex = new Regex("\\s(?<minute>\\d+)\\sminute"); var hourMatch = hourRegex.Match(html); var minuteMatch = minuteRegex.Match(html); int hours = 0; int minutes = 0; if (hourMatch.Success) { var hourValue = hourMatch.Groups["hour"].Value; hours = Convert.ToInt32(hourValue); } if (minuteMatch.Success) { var minuteValue = minuteMatch.Groups["minute"].Value; minutes = Convert.ToInt32(minuteValue); } int secondsToWait = ((hours * 3600) + (minutes * 60) + 60); State = AgentInteractionState.StartConversation; _nextAction = DateTime.Now.AddSeconds(secondsToWait); Logging.Log("AgentInteraction: Current standings at or below minimum. Waiting " + (secondsToWait / 60) + " minutes to try decline again."); CloseConversation(); return; } Logging.Log("AgentInteraction: Current standings above minimum. Declining mission."); } } // Decline and request a new mission Logging.Log("AgentInteraction: Saying [Decline]"); decline.Say(); Logging.Log("AgentInteraction: Replying to agent"); State = AgentInteractionState.ReplyToAgent; _nextAction = DateTime.Now.AddSeconds(7); }
/// <summary> /// Target wrecks within range /// </summary> private void TargetWrecks() { // We are jammed, we do not need to log (Combat does this already) if (Cache.Instance.DirectEve.ActiveShip.MaxLockedTargets == 0) { return; } var targets = new List <EntityCache>(); targets.AddRange(Cache.Instance.Targets); targets.AddRange(Cache.Instance.Targeting); var hasSalvagers = Cache.Instance.Modules.Any(m => m.GroupId == (int)Group.Salvager); var wreckTargets = targets.Where(t => (t.GroupId == (int)Group.Wreck || t.GroupId == (int)Group.CargoContainer) && t.CategoryId == (int)CategoryID.Celestial).ToList(); // Check for cargo containers foreach (var wreck in wreckTargets) { if (Cache.Instance.IgnoreTargets.Contains(wreck.Name)) { Logging.Log("Salvage: Cargo Container [" + wreck.Name + "][" + wreck.Id + "] on the ignore list, ignoring."); wreck.UnlockTarget(); continue; } if (hasSalvagers && wreck.GroupId != (int)Group.CargoContainer) { continue; } // Unlock if within loot range if (wreck.Distance < 2500) { Logging.Log("Salvage: Cargo Container [" + wreck.Name + "][" + wreck.Id + "] within loot range, unlocking container."); wreck.UnlockTarget(); } } if (wreckTargets.Count >= MaximumWreckTargets) { return; } var tractorBeams = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.TractorBeam).ToList(); var tractorBeamRange = 0d; if (tractorBeams.Count > 0) { tractorBeamRange = tractorBeams.Min(t => t.OptimalRange); } var wrecks = Cache.Instance.UnlootedContainers; foreach (var wreck in wrecks.Where(w => !Cache.Instance.IgnoreTargets.Contains(w.Name.Trim()))) { // Its already a target, ignore it if (wreck.IsTarget || wreck.IsTargeting) { continue; } if (wreck.Distance > tractorBeamRange) { continue; } if (!wreck.HaveLootRights) { continue; } // No need to tractor a non-wreck within loot range if (wreck.GroupId != (int)Group.Wreck && wreck.Distance < 2500) { continue; } if (wreck.GroupId != (int)Group.Wreck && wreck.GroupId != (int)Group.CargoContainer) { continue; } if (!hasSalvagers) { // Ignore already looted wreck if (Cache.Instance.LootedContainers.Contains(wreck.Id)) { continue; } // Ignore empty wrecks if (wreck.GroupId == (int)Group.Wreck && wreck.IsWreckEmpty) { continue; } } Logging.Log("Salvage: Locking [" + wreck.Name + "][" + wreck.Id + "]"); wreck.LockTarget(); wreckTargets.Add(wreck); if (wreckTargets.Count >= MaximumWreckTargets) { break; } } }
private void ClearPocketAction(Action action) { var activeTargets = new List <EntityCache>(); activeTargets.AddRange(Cache.Instance.Targets); activeTargets.AddRange(Cache.Instance.Targeting); // Get lowest range var range = Math.Min(Cache.Instance.WeaponRange, Cache.Instance.DirectEve.ActiveShip.MaxTargetRange); // We are obviously still killing stuff that's in range if (activeTargets.Count(t => t.Distance < range && t.IsNpc && t.CategoryId == (int)CategoryID.Entity) > 0) { // Reset timeout _clearPocketTimeout = null; // If we are still moving, stop (we do not want to 'over-agro', if possible) (unless we are speed tanking) if (Cache.Instance.Approaching != null && !Settings.Instance.SpeedTank) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdStopShip); Cache.Instance.Approaching = null; } return; } // Is there a priority target out of range? var target = Cache.Instance.PriorityTargets.OrderBy(t => t.Distance).Where(t => !Cache.Instance.IgnoreTargets.Contains(t.Name.Trim())).FirstOrDefault(); // Or is there a target out of range that is targeting us? target = target ?? Cache.Instance.TargetedBy.Where(t => !t.IsSentry && !t.IsContainer && t.IsNpc && t.CategoryId == (int)CategoryID.Entity && t.GroupId != (int)Group.LargeCollidableStructure && !Cache.Instance.IgnoreTargets.Contains(t.Name.Trim())).OrderBy(t => t.Distance).FirstOrDefault(); // Or is there any target out of range? target = target ?? Cache.Instance.Entities.Where(t => !t.IsSentry && !t.IsContainer && t.IsNpc && t.CategoryId == (int)CategoryID.Entity && t.GroupId != (int)Group.LargeCollidableStructure && !Cache.Instance.IgnoreTargets.Contains(t.Name.Trim())).OrderBy(t => t.Distance).FirstOrDefault(); if (target != null) { // Reset timeout _clearPocketTimeout = null; // Lock priority target if within weapons range if (target.Distance < range) { if (Cache.Instance.DirectEve.ActiveShip.MaxLockedTargets > 0) { Logging.Log("MissionController.ClearPocket: Targeting [" + target.Name + "][" + target.Id + "]"); target.LockTarget(); } return; } // Are we approaching the active (out of range) target? // Wait for it (or others) to get into range if (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != target.Id) { Logging.Log("MissionController.ClearPocket: Approaching target [" + target.Name + "][" + target.Id + "]"); if (Settings.Instance.SpeedTank) { target.Orbit(Settings.Instance.OrbitDistance); } else { target.Approach((int)(Cache.Instance.WeaponRange * 0.8d)); } } return; } // Do we have a timeout? No, set it to now + 5 seconds if (!_clearPocketTimeout.HasValue) { _clearPocketTimeout = DateTime.Now.AddSeconds(5); } // Are we in timeout? if (DateTime.Now < _clearPocketTimeout.Value) { return; } // We have cleared the Pocket, perform the next action \o/ _currentAction++; // Reset timeout _clearPocketTimeout = null; }
/// <summary> /// Loot any wrecks & cargo containers close by /// </summary> private void LootWrecks() { var cargo = Cache.Instance.DirectEve.GetShipsCargo(); if (cargo.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenCargoHoldOfActiveShip); return; } // Ship's cargo is not ready yet if (!cargo.IsReady) { return; } var shipsCargo = cargo.Items.Select(i => new ItemCache(i)).ToList(); var freeCargoCapacity = cargo.Capacity - cargo.UsedCapacity; var lootWindows = Cache.Instance.DirectEve.Windows.OfType <DirectContainerWindow>().Where(w => !string.IsNullOrEmpty(w.Name) && w.Name.StartsWith("loot_")); foreach (var window in lootWindows) { // The window is not ready, then continue if (!window.IsReady) { continue; } // Get the container var containerEntity = Cache.Instance.EntityById(window.ItemId); // Does it no longer exist or is it out of transfer range or its looted if (containerEntity == null || containerEntity.Distance > 2500 || Cache.Instance.LootedContainers.Contains(containerEntity.Id)) { Logging.Log("Salvage: Closing loot window [" + window.ItemId + "]"); window.Close(); continue; } // Get the container that is associated with the cargo container var container = Cache.Instance.DirectEve.GetContainer(window.ItemId); // List its items var items = container.Items.Select(i => new ItemCache(i)); // Build a list of items to loot var lootItems = new List <ItemCache>(); // Walk through the list of items ordered by highest value item first foreach (var item in items.OrderByDescending(i => i.IskPerM3)) { // We pick up loot depending on isk per m3 var isMissionItem = Cache.Instance.MissionItems.Contains((item.Name ?? string.Empty).ToLower()); // Never pick up contraband (unless its the mission item) if (!isMissionItem && item.IsContraband) { continue; } // Do we want to loot other items? if (!isMissionItem && !LootEverything) { continue; } // We are at our max, either make room or skip the item if ((freeCargoCapacity - item.TotalVolume) <= (isMissionItem ? 0 : ReserveCargoCapacity)) { // We can't drop items in this container anyway, well get it after its salvaged if (!isMissionItem && containerEntity.GroupId != (int)Group.CargoContainer) { continue; } // Make a list of items which are worth less List <ItemCache> worthLess; if (isMissionItem) { worthLess = shipsCargo; } else if (item.IskPerM3.HasValue) { worthLess = shipsCargo.Where(sc => sc.IskPerM3.HasValue && sc.IskPerM3 < item.IskPerM3).ToList(); } else { worthLess = shipsCargo.Where(sc => sc.IskPerM3.HasValue).ToList(); } // Remove mission item from this list worthLess.RemoveAll(wl => Cache.Instance.MissionItems.Contains((wl.Name ?? string.Empty).ToLower())); worthLess.RemoveAll(wl => (wl.Name ?? string.Empty).ToLower() == Cache.Instance.BringMissionItem); // Consider dropping ammo if it concerns the mission item! if (!isMissionItem) { worthLess.RemoveAll(wl => Ammo.Any(a => a.TypeId == wl.TypeId)); } // Nothing is worth less then the current item if (worthLess.Count() == 0) { continue; } // Not enough space even if we dumped the crap if ((freeCargoCapacity + worthLess.Sum(wl => wl.TotalVolume)) < item.TotalVolume) { if (isMissionItem) { Logging.Log("Salvage: Not enough space for mission item! Need [" + item.TotalVolume + "] maximum available [" + (freeCargoCapacity + worthLess.Sum(wl => wl.TotalVolume)) + "]"); } continue; } // Start clearing out items that are worth less var moveTheseItems = new List <DirectItem>(); foreach (var wl in worthLess.OrderBy(wl => wl.IskPerM3.HasValue ? wl.IskPerM3.Value : double.MaxValue).ThenByDescending(wl => wl.TotalVolume)) { // Mark this item as moved moveTheseItems.Add(wl.DirectItem); // Substract (now) free volume freeCargoCapacity += wl.TotalVolume; // We freed up enough space? if ((freeCargoCapacity - item.TotalVolume) >= ReserveCargoCapacity) { break; } } if (moveTheseItems.Count > 0) { // If this is not a cargo container, then jettison loot if (containerEntity.GroupId != (int)Group.CargoContainer || isMissionItem) { if (DateTime.Now.Subtract(_lastJettison).TotalSeconds < 185) { return; } Logging.Log("Salvage: Jettisoning [" + moveTheseItems.Count + "] items to make room for the more valuable loot"); // Note: This could (in theory) f**k up with the bot jettison an item and // then picking it up again :/ (granted it should never happen unless // mission item volume > reserved volume cargo.Jettison(moveTheseItems.Select(i => i.ItemId)); _lastJettison = DateTime.Now; return; } // Move items to the cargo container container.Add(moveTheseItems); // Remove it from the ships cargo list shipsCargo.RemoveAll(i => moveTheseItems.Any(wl => wl.ItemId == i.Id)); Logging.Log("Salvage: Moving [" + moveTheseItems.Count + "] items into the cargo container to make room for the more valuable loot"); } } // Update free space freeCargoCapacity -= item.TotalVolume; lootItems.Add(item); } // Mark container as looted Cache.Instance.LootedContainers.Add(containerEntity.Id); // Loot actual items if (lootItems.Count != 0) { Logging.Log("Salvage: Looting container [" + containerEntity.Name + "][" + containerEntity.Id + "], [" + lootItems.Count + "] valuable items"); cargo.Add(lootItems.Select(i => i.DirectItem)); } else { Logging.Log("Salvage: Container [" + containerEntity.Name + "][" + containerEntity.Id + "] contained no valuable items"); } } // Open a container in range foreach (var containerEntity in Cache.Instance.Containers.Where(e => e.Distance <= 2500)) { // Emptry wreck, ignore if (containerEntity.GroupId == (int)Group.Wreck && containerEntity.IsWreckEmpty) { continue; } // We looted this container if (Cache.Instance.LootedContainers.Contains(containerEntity.Id)) { continue; } // We already opened the loot window var window = lootWindows.FirstOrDefault(w => w.ItemId == containerEntity.Id); if (window != null) { continue; } // Ignore open request within 10 seconds if (_openedContainers.ContainsKey(containerEntity.Id) && DateTime.Now.Subtract(_openedContainers[containerEntity.Id]).TotalSeconds < 10) { continue; } // Open the container Logging.Log("Salvage: Opening container [" + containerEntity.Name + "][" + containerEntity.Id + "]"); containerEntity.OpenCargo(); _openedContainers[containerEntity.Id] = DateTime.Now; break; } }
public void ProcessState() { // What? No ship entity? if (Cache.Instance.DirectEve.ActiveShip.Entity == null) { return; } switch (State) { case MissionControllerState.Idle: case MissionControllerState.Done: case MissionControllerState.Error: break; case MissionControllerState.Start: _pocket = 0; // Reload the items needed for this mission from the XML file Cache.Instance.RefreshMissionItems(AgentId); // Update x/y/z so that NextPocket wont think we are there yet because its checking (very) old x/y/z cords _lastX = Cache.Instance.DirectEve.ActiveShip.Entity.X; _lastY = Cache.Instance.DirectEve.ActiveShip.Entity.Y; _lastZ = Cache.Instance.DirectEve.ActiveShip.Entity.Z; State = MissionControllerState.LoadPocket; break; case MissionControllerState.LoadPocket: _pocketActions.Clear(); _pocketActions.AddRange(Cache.Instance.LoadMissionActions(AgentId, _pocket)); if (_pocketActions.Count == 0) { // No Pocket action, load default actions Logging.Log("MissionController: No mission actions specified, loading default actions"); // Wait for 30 seconds to be targeted _pocketActions.Add(new Action { State = ActionState.WaitUntilTargeted }); _pocketActions[0].AddParameter("timeout", "15"); // Clear the Pocket _pocketActions.Add(new Action { State = ActionState.ClearPocket }); // Is there a gate? var gates = Cache.Instance.EntitiesByName("Acceleration Gate"); if (gates != null && gates.Count() > 0) { // Activate it (Activate action also moves to the gate) _pocketActions.Add(new Action { State = ActionState.Activate }); _pocketActions[_pocketActions.Count - 1].AddParameter("target", "Acceleration Gate"); } else // No, were done { _pocketActions.Add(new Action { State = ActionState.Done }); } // TODO: Check mission HTML to see if we need to pickup any items // Not a priority, apparently retrieving HTML causes a lot of crashes } Logging.Log("MissionController: Pocket loaded, executing the following actions"); foreach (var a in _pocketActions) { Logging.Log("MissionController: Action." + a); } // Reset pocket information _currentAction = 0; Cache.Instance.IsMissionPocketDone = false; Cache.Instance.IgnoreTargets.Clear(); State = MissionControllerState.ExecutePocketActions; break; case MissionControllerState.ExecutePocketActions: if (_currentAction >= _pocketActions.Count) { // No more actions, but we're not done?!?!?! Logging.Log("MissionController: We're out of actions but did not process a 'Done' or 'Activate' action"); State = MissionControllerState.Error; break; } var action = _pocketActions[_currentAction]; var currentAction = _currentAction; PerformAction(action); if (currentAction != _currentAction) { Logging.Log("MissionController: Finished Action." + action); if (_currentAction < _pocketActions.Count) { action = _pocketActions[_currentAction]; Logging.Log("MissionController: Starting Action." + action); } } if (Settings.Instance.DebugStates) { Logging.Log("Action.State = " + action); } break; case MissionControllerState.NextPocket: var distance = Cache.Instance.DistanceFromMe(_lastX, _lastY, _lastZ); if (distance > 100000) { Logging.Log("MissionController: We've moved to the next Pocket [" + distance + "]"); // If we moved more then 100km, assume next Pocket _pocket++; State = MissionControllerState.LoadPocket; } else if (DateTime.Now.Subtract(_lastActivateAction).TotalMinutes > 2) { Logging.Log("MissionController: We've timed out, retry last action"); // We have reached a timeout, revert to ExecutePocketActions (e.g. most likely Activate) State = MissionControllerState.ExecutePocketActions; } break; } var newX = Cache.Instance.DirectEve.ActiveShip.Entity.X; var newY = Cache.Instance.DirectEve.ActiveShip.Entity.Y; var newZ = Cache.Instance.DirectEve.ActiveShip.Entity.Z; // For some reason x/y/z returned 0 sometimes if (newX != 0 && newY != 0 && newZ != 0) { // Save X/Y/Z so that NextPocket can check if we actually went to the next Pocket :) _lastX = newX; _lastY = newY; _lastZ = newZ; } }
public void ProcessState() { // Nothing to salvage in stations if (Cache.Instance.InStation) { return; } var cargo = Cache.Instance.DirectEve.GetShipsCargo(); switch (State) { case SalvageState.TargetWrecks: TargetWrecks(); // Next state State = SalvageState.LootWrecks; break; case SalvageState.LootWrecks: LootWrecks(); State = SalvageState.SalvageWrecks; break; case SalvageState.SalvageWrecks: ActivateTractorBeams(); ActivateSalvagers(); // Default action State = SalvageState.TargetWrecks; if (cargo.IsReady && cargo.Items.Any() && _nextAction < DateTime.Now) { // Check if there are actually duplicates var duplicates = cargo.Items.Where(i => i.Quantity > 0).GroupBy(i => i.TypeId).Any(t => t.Count() > 1); if (duplicates) { State = SalvageState.StackItems; } else { _nextAction = DateTime.Now.AddSeconds(150); } } break; case SalvageState.StackItems: Logging.Log("Salvage: Stacking items"); if (cargo.IsReady) { cargo.StackAll(); } _nextAction = DateTime.Now.AddSeconds(5); State = SalvageState.WaitForStacking; break; case SalvageState.WaitForStacking: // Wait 5 seconds after stacking if (_nextAction > DateTime.Now) { break; } if (Cache.Instance.DirectEve.GetLockedItems().Count == 0) { Logging.Log("Salvage: Done stacking"); State = SalvageState.TargetWrecks; break; } if (DateTime.Now.Subtract(_nextAction).TotalSeconds > 120) { Logging.Log("Salvage: Stacking items timed out, clearing item locks"); Cache.Instance.DirectEve.UnlockItems(); Logging.Log("Salvage: Done stacking"); State = SalvageState.TargetWrecks; break; } break; default: // Unknown state, goto first state State = SalvageState.TargetWrecks; break; } }
public SolarSystemDestination(long solarSystemId) { Logging.Log("Traveler.SolarSystemDestination: Destination set to solar system id [" + solarSystemId + "]"); SolarSystemId = solarSystemId; }
/// <summary> /// Activate weapons /// </summary> private void ActivateWeapons(EntityCache target) { // Enable speed tank if (Cache.Instance.Approaching == null && Settings.Instance.SpeedTank) { target.Orbit(Cache.Instance.OrbitDistance); } // Get the weapons var weapons = Cache.Instance.Weapons; // TODO: Add check to see if there is better ammo to use! :) // Get distance of the target and compare that with the ammo currently loaded foreach (var weapon in weapons) { if (!weapon.IsActive) { continue; } // No ammo loaded if (weapon.Charge == null) { continue; } var ammo = Settings.Instance.Ammo.FirstOrDefault(a => a.TypeId == weapon.Charge.TypeId); // How can this happen? Someone manually loaded ammo if (ammo == null) { continue; } // Target is in range if (target.Distance <= ammo.Range) { continue; } // Target is out of range, stop firing weapon.Deactivate(); } // Hax for max charges returning incorrect value if (!weapons.Any(w => w.IsEnergyWeapon)) { MaxCharges = Math.Max(MaxCharges, weapons.Max(l => l.MaxCharges)); MaxCharges = Math.Max(MaxCharges, weapons.Max(l => l.CurrentCharges)); } // Activate the weapons (it not yet activated))) foreach (var weapon in weapons) { // Are we on the right target? if (weapon.IsActive) { if (weapon.TargetId != target.Id) { weapon.Deactivate(); } continue; } // Are we reloading, deactivating or changing ammo? if (weapon.IsReloadingAmmo || weapon.IsDeactivating || weapon.IsChangingAmmo) { continue; } // No, check ammo type and if thats correct, activate weapon if (ReloadAmmo(weapon, target) && CanActivate(weapon, target, true)) { Logging.Log("Combat: Activating weapon [" + weapon.ItemId + "] on [" + target.Name + "][" + target.Id + "]"); weapon.Activate(target.Id); } } }
public void ProcessState() { var cargo = Cache.Instance.DirectEve.GetShipsCargo(); var droneBay = Cache.Instance.DirectEve.GetShipsDroneBay(); var itemHangar = Cache.Instance.DirectEve.GetItemHangar(); var shipHangar = Cache.Instance.DirectEve.GetShipHangar(); DirectContainer corpHangar = null; if (!string.IsNullOrEmpty(Settings.Instance.AmmoHangar)) { corpHangar = Cache.Instance.DirectEve.GetCorporationHangar(Settings.Instance.AmmoHangar); } // Select the correct ammo hangar var ammoHangar = corpHangar ?? itemHangar; switch (State) { case ArmState.Idle: case ArmState.Done: break; case ArmState.Begin: State = ArmState.OpenShipHangar; break; case ArmState.OpenShipHangar: case ArmState.SwitchToSalvageShip: // Is the ship hangar open? if (shipHangar.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenShipHangar); break; } if (!shipHangar.IsReady) { break; } if (State == ArmState.OpenShipHangar) { Logging.Log("Arm: Activating combat ship"); State = ArmState.ActivateCombatShip; } else { Logging.Log("Arm: Activating salvage ship"); State = ArmState.ActivateSalvageShip; } break; case ArmState.ActivateCombatShip: case ArmState.ActivateSalvageShip: var shipName = State == ArmState.ActivateCombatShip ? Settings.Instance.CombatShipName : Settings.Instance.SalvageShipName; if (!string.IsNullOrEmpty(shipName) && Cache.Instance.DirectEve.ActiveShip.GivenName != shipName) { if (DateTime.Now.Subtract(_lastAction).TotalSeconds > 15) { var ships = Cache.Instance.DirectEve.GetShipHangar().Items; foreach (var ship in ships.Where(ship => ship.GivenName == shipName)) { Logging.Log("Arm: Making [" + ship.GivenName + "] active"); ship.ActivateShip(); _lastAction = DateTime.Now; return; } State = ArmState.NotEnoughAmmo; Logging.Log("Arm: Found the following ships:"); foreach (var ship in ships) { Logging.Log("Arm: [" + ship.GivenName + "]"); } Logging.Log("Arm: Could not find [" + shipName + "] ship!"); return; } return; } if (State == ArmState.ActivateSalvageShip) { Logging.Log("Arm: Done"); State = ArmState.Done; return; } _missionItemMoved = false; Cache.Instance.RefreshMissionItems(AgentId); if (AmmoToLoad.Count == 0 && string.IsNullOrEmpty(Cache.Instance.BringMissionItem)) { Logging.Log("Arm: Done"); State = ArmState.Done; } else { Logging.Log("Arm: Opening item hangar"); State = ArmState.OpenItemHangar; } break; case ArmState.OpenItemHangar: // Is the hangar open? if (itemHangar.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenHangarFloor); break; } if (!itemHangar.IsReady) { break; } if (corpHangar != null) { Logging.Log("Arm: Opening corporation hangar"); State = ArmState.OpenCorpHangar; } else { Logging.Log("Arm: Opening ship's cargo"); State = ArmState.OpenCargo; } break; case ArmState.OpenCorpHangar: // Is the hangar open? if (corpHangar != null) { if (corpHangar.Window == null) { // No, command it to open Cache.Instance.DirectEve.OpenCorporationHangar(); break; } if (!corpHangar.IsReady) { break; } } Logging.Log("Arm: Opening ship's cargo"); State = ArmState.OpenCargo; break; case ArmState.OpenCargo: // Is cargo open? if (cargo.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenCargoHoldOfActiveShip); break; } if (!cargo.IsReady) { break; } if (Settings.Instance.UseDrones && Settings.Instance.DroneTypeId > 0) { Logging.Log("Arm: Opening ship's drone bay"); State = ArmState.OpenDroneBay; } else { Logging.Log("Arm: Moving items"); State = ArmState.MoveItems; } break; case ArmState.OpenDroneBay: // Is cargo open? if (droneBay.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenDroneBayOfActiveShip); break; } if (!droneBay.IsReady) { break; } Logging.Log("Arm: Moving drones"); State = ArmState.MoveDrones; break; case ArmState.MoveDrones: var drone = ammoHangar.Items.FirstOrDefault(i => i.TypeId == Settings.Instance.DroneTypeId); if (drone == null || !drone.Stacksize.HasValue) { Logging.Log("Arm: Out of drones"); State = ArmState.NotEnoughAmmo; break; } var neededDrones = Math.Floor((droneBay.Capacity - droneBay.UsedCapacity) / drone.Volume); if (neededDrones == 0) { Logging.Log("Arm: Moving items"); State = ArmState.MoveItems; break; } // Move needed drones droneBay.Add(drone, (int)Math.Min(neededDrones, drone.Stacksize.Value)); break; case ArmState.MoveItems: var bringItem = Cache.Instance.BringMissionItem; if (string.IsNullOrEmpty(bringItem)) { _missionItemMoved = true; } if (!_missionItemMoved) { var missionItem = (corpHangar ?? itemHangar).Items.FirstOrDefault(i => (i.TypeName ?? string.Empty).ToLower() == bringItem); if (missionItem == null) { missionItem = itemHangar.Items.FirstOrDefault(i => (i.TypeName ?? string.Empty).ToLower() == bringItem); } if (missionItem != null) { Logging.Log("Arm: Moving [" + missionItem.TypeName + "]"); cargo.Add(missionItem, 1); _missionItemMoved = true; break; } } var itemMoved = false; foreach (var item in ammoHangar.Items.OrderBy(i => i.Quantity)) { if (item.ItemId <= 0) { continue; } var ammo = AmmoToLoad.FirstOrDefault(a => a.TypeId == item.TypeId); if (ammo == null) { continue; } Logging.Log("Arm: Moving [" + item.TypeName + "]"); var moveQuantity = Math.Min(item.Quantity, ammo.Quantity); moveQuantity = Math.Max(moveQuantity, 1); cargo.Add(item, moveQuantity); ammo.Quantity -= moveQuantity; if (ammo.Quantity <= 0) { AmmoToLoad.RemoveAll(a => a.TypeId == item.TypeId); } itemMoved = true; break; } if (AmmoToLoad.Count == 0 && _missionItemMoved) { _lastAction = DateTime.Now; Logging.Log("Arm: Waiting for items"); State = ArmState.WaitForItems; } else if (!itemMoved) { if (AmmoToLoad.Count > 0) { foreach (var ammo in AmmoToLoad) { Logging.Log("Arm: Missing ammo with TypeId [" + ammo.TypeId + "]"); } } if (!_missionItemMoved) { Logging.Log("Arm: Missing mission item [" + bringItem + "]"); } State = ArmState.NotEnoughAmmo; } break; case ArmState.WaitForItems: // Wait 5 seconds after moving if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 5) { break; } if (cargo.Items.Count == 0) { break; } if (Cache.Instance.DirectEve.GetLockedItems().Count == 0) { // Close the drone bay, its not required in space. if (droneBay.IsReady) { droneBay.Window.Close(); } Logging.Log("Arm: Done"); State = ArmState.Done; break; } // Note, there's no unlock here as we *always* want our ammo! break; } }
/// <summary> /// Reload correct (tm) ammo for the NPC /// </summary> /// <param name = "weapon"></param> /// <param name = "entity"></param> /// <returns>True if the (enough/correct) ammo is loaded, false if wrong/not enough ammo is loaded</returns> public bool ReloadNormalAmmo(ModuleCache weapon, EntityCache entity) { var cargo = Cache.Instance.DirectEve.GetShipsCargo(); // Get ammo based on damage type var correctAmmo = Settings.Instance.Ammo.Where(a => a.DamageType == Cache.Instance.DamageType); // Check if we still have that ammo in our cargo correctAmmo = correctAmmo.Where(a => cargo.Items.Any(i => i.TypeId == a.TypeId && i.Quantity >= Settings.Instance.MinimumAmmoCharges)); // We are out of ammo! :( if (correctAmmo.Count() == 0) { State = CombatState.OutOfAmmo; return(false); } // Get the best possible ammo var ammo = correctAmmo.Where(a => a.Range > entity.Distance).OrderBy(a => a.Range).FirstOrDefault(); // We do not have any ammo left that can hit targets at that range! if (ammo == null) { return(false); } // We have enough ammo loaded if (weapon.Charge != null && weapon.Charge.TypeId == ammo.TypeId && weapon.CurrentCharges >= Settings.Instance.MinimumAmmoCharges) { return(true); } // Retry later, assume its ok now if (weapon.MatchingAmmo.Count() == 0) { return(true); } var charge = cargo.Items.FirstOrDefault(i => i.TypeId == ammo.TypeId && i.Quantity >= Settings.Instance.MinimumAmmoCharges); // This should have shown up as "out of ammo" if (charge == null) { return(false); } // We are reloading, wait at least 11 seconds if (_lastWeaponReload.ContainsKey(weapon.ItemId) && DateTime.Now < _lastWeaponReload[weapon.ItemId].AddSeconds(22)) { return(false); } _lastWeaponReload[weapon.ItemId] = DateTime.Now; // Reload or change ammo if (weapon.Charge != null && weapon.Charge.TypeId == charge.TypeId) { Logging.Log("Combat: Reloading [" + weapon.ItemId + "] with [" + charge.TypeName + "][" + charge.TypeId + "]"); weapon.ReloadAmmo(charge); } else { Logging.Log("Combat: Changing [" + weapon.ItemId + "] with [" + charge.TypeName + "][" + charge.TypeId + "]"); weapon.ChangeAmmo(charge); } // Return false as we are reloading ammo return(false); }
public bool UseMissionShip = false; // Were we successful in activating the mission specific ship? public void ProcessState() { var cargo = Cache.Instance.DirectEve.GetShipsCargo(); var droneBay = Cache.Instance.DirectEve.GetShipsDroneBay(); var itemHangar = Cache.Instance.DirectEve.GetItemHangar(); var shipHangar = Cache.Instance.DirectEve.GetShipHangar(); DirectContainer corpHangar = null; if (!string.IsNullOrEmpty(Settings.Instance.AmmoHangar)) { corpHangar = Cache.Instance.DirectEve.GetCorporationHangar(Settings.Instance.AmmoHangar); } // Select the correct ammo hangar var ammoHangar = corpHangar ?? itemHangar; switch (State) { case ArmState.Idle: break; case ArmState.Done: break; case ArmState.Begin: //DefaultFittingChecked = false; //flag to check for the correct default fitting before using the fitting manager //DefaultFittingFound = true; //Did we find the default fitting? Cache.Instance.ArmLoadedCache = false; TryMissionShip = true; // Used in the event we can't find the ship specified in the missionfittings UseMissionShip = false; // Were we successful in activating the mission specific ship? State = ArmState.OpenShipHangar; break; case ArmState.OpenShipHangar: case ArmState.SwitchToSalvageShip: // Is the ship hangar open? if (shipHangar.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenShipHangar); break; } if (!shipHangar.IsReady) { break; } if (State == ArmState.OpenShipHangar) { Logging.Log("Arm: Activating combat ship"); State = ArmState.ActivateCombatShip; } else { Logging.Log("Arm: Activating salvage ship"); State = ArmState.ActivateSalvageShip; } break; case ArmState.ActivateCombatShip: case ArmState.ActivateSalvageShip: var shipName = State == ArmState.ActivateCombatShip ? Settings.Instance.CombatShipName.ToLower() : Settings.Instance.SalvageShipName.ToLower(); if (!Cache.Instance.ArmLoadedCache) { _missionItemMoved = false; Cache.Instance.RefreshMissionItems(AgentId); Cache.Instance.ArmLoadedCache = true; } // If we've got a mission-specific ship defined, switch to it if ((State == ArmState.ActivateCombatShip) && !(Cache.Instance.MissionShip == "" || Cache.Instance.MissionShip == null) && TryMissionShip) { shipName = Cache.Instance.MissionShip.ToLower(); } if (Settings.Instance.CombatShipName.ToLower() == shipName) // if the mission specific ship is our default combat ship, no need to do anything special { TryMissionShip = false; } if ((!string.IsNullOrEmpty(shipName) && Cache.Instance.DirectEve.ActiveShip.GivenName.ToLower() != shipName)) { if (DateTime.Now.Subtract(_lastAction).TotalSeconds > 15) { var ships = Cache.Instance.DirectEve.GetShipHangar().Items; foreach (var ship in ships.Where(ship => ship.GivenName.ToLower() == shipName)) { Logging.Log("Arm: Making [" + ship.GivenName + "] active"); ship.ActivateShip(); _lastAction = DateTime.Now; if (TryMissionShip) { UseMissionShip = true; } return; } if (TryMissionShip && !UseMissionShip) { Logging.Log("Arm: Unable to find the ship specified in the missionfitting. Using default combat ship and default fitting."); TryMissionShip = false; Cache.Instance.Fitting = Cache.Instance.DefaultFitting; return; } State = ArmState.NotEnoughAmmo; Logging.Log("Arm: Found the following ships:"); foreach (var ship in ships) { Logging.Log("Arm: [" + ship.GivenName + "]"); } Logging.Log("Arm: Could not find [" + shipName + "] ship!"); return; } return; } else if (TryMissionShip) { UseMissionShip = true; } if (State == ArmState.ActivateSalvageShip) { Logging.Log("Arm: Done"); State = ArmState.Done; return; } //_missionItemMoved = false; //Cache.Instance.RefreshMissionItems(AgentId); if (AmmoToLoad.Count == 0 && string.IsNullOrEmpty(Cache.Instance.BringMissionItem)) { Logging.Log("Arm: Done"); State = ArmState.Done; } else { Logging.Log("Arm: Opening item hangar"); State = ArmState.OpenItemHangar; } break; case ArmState.OpenItemHangar: // Is the hangar open? if (itemHangar.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenHangarFloor); break; } if (!itemHangar.IsReady) { break; } if (corpHangar != null) { Logging.Log("Arm: Opening corporation hangar"); State = ArmState.OpenCorpHangar; } else { Logging.Log("Arm: Opening ship's cargo"); State = ArmState.OpenCargo; } break; case ArmState.OpenCorpHangar: // Is the hangar open? if (corpHangar != null) { if (corpHangar.Window == null) { // No, command it to open Cache.Instance.DirectEve.OpenCorporationHangar(); break; } if (!corpHangar.IsReady) { break; } } Logging.Log("Arm: Opening ship's cargo"); State = ArmState.OpenCargo; break; case ArmState.OpenCargo: // Is cargo open? if (cargo.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenCargoHoldOfActiveShip); break; } if (!cargo.IsReady) { break; } if (Settings.Instance.UseDrones && Settings.Instance.DroneTypeId > 0) { Logging.Log("Arm: Opening ship's drone bay"); State = ArmState.OpenDroneBay; } else if ((Settings.Instance.FittingsDefined && DefaultFittingFound) && !(UseMissionShip && !(Cache.Instance.ChangeMissionShipFittings))) { Logging.Log("Arm: Fitting"); State = ArmState.OpenFittingWindow; } else { State = ArmState.MoveItems; } break; case ArmState.OpenFittingWindow: //let's check first if we need to change fitting at all Logging.Log("Arm: Fitting: " + Cache.Instance.Fitting + " - currentFit: " + Cache.Instance.currentFit); if (Cache.Instance.Fitting.Equals(Cache.Instance.currentFit)) { Logging.Log("Arm: Current fit is correct - no change necessary"); State = ArmState.MoveItems; } else { Cache.Instance.DirectEve.OpenFitingManager(); State = ArmState.WaitForFittingWindow; } break; case ArmState.WaitForFittingWindow: var fittingMgr = Cache.Instance.DirectEve.Windows.OfType <DirectFittingManagerWindow>().FirstOrDefault(); //open it again ? if (fittingMgr == null) { Logging.Log("Arm: Opening fitting manager"); Cache.Instance.DirectEve.OpenFitingManager(); } //check if it's ready else if (fittingMgr.IsReady) { State = ArmState.ChoseFitting; } break; case ArmState.ChoseFitting: fittingMgr = Cache.Instance.DirectEve.Windows.OfType <DirectFittingManagerWindow>().FirstOrDefault(); bool found = false; if (!DefaultFittingChecked) { DefaultFittingChecked = true; Logging.Log("Arm: Looking for Default Fitting " + Cache.Instance.DefaultFitting); foreach (var fitting in fittingMgr.Fittings) { //ok found it if (Cache.Instance.DefaultFitting.ToLower().Equals(fitting.Name.ToLower())) { found = true; Logging.Log("Arm: Found Default Fitting " + fitting.Name); } } if (!found) { Logging.Log("Arm: Error! Couldn't find Default Fitting. Disabling fitting manager."); DefaultFittingFound = false; Settings.Instance.FittingsDefined = false; State = ArmState.MoveItems; break; } found = false; } Logging.Log("Arm: Looking for fitting " + Cache.Instance.Fitting); foreach (var fitting in fittingMgr.Fittings) { //ok found it var ship = Cache.Instance.DirectEve.ActiveShip; if (Cache.Instance.Fitting.ToLower().Equals(fitting.Name.ToLower()) && fitting.ShipTypeId == ship.TypeId) { Logging.Log("Arm: Found fitting " + fitting.Name); //switch to the requested fitting for the current mission fitting.Fit(); _lastAction = DateTime.Now; Cache.Instance.currentFit = fitting.Name; State = ArmState.WaitForFitting; found = true; break; } } //if we didn't find it, we'll set currentfit to default //this should provide backwards compatibility without trying to fit always if (!found) { if (UseMissionShip) { Logging.Log("Arm: Couldn't find fitting for this ship typeid. Using current fitting."); State = ArmState.MoveItems; break; } else { Logging.Log("Arm: Couldn't find fitting - switching to default"); Cache.Instance.Fitting = Cache.Instance.DefaultFitting; break; } } State = ArmState.MoveItems; fittingMgr.Close(); break; case ArmState.WaitForFitting: //let's wait 10 seconds if (DateTime.Now.Subtract(_lastAction).TotalMilliseconds > 10000 && Cache.Instance.DirectEve.GetLockedItems().Count == 0) { //we should be done fitting, proceed to the next state State = ArmState.MoveItems; fittingMgr = Cache.Instance.DirectEve.Windows.OfType <DirectFittingManagerWindow>().FirstOrDefault(); fittingMgr.Close(); Logging.Log("Arm: Done fitting"); } else { Logging.Log("Arm: Waiting for fitting. time elapsed = " + DateTime.Now.Subtract(_lastAction).TotalMilliseconds + " locked items = " + Cache.Instance.DirectEve.GetLockedItems().Count); } break; case ArmState.OpenDroneBay: // Is cargo open? if (droneBay.Window == null) { // No, command it to open Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenDroneBayOfActiveShip); break; } if (!droneBay.IsReady) { break; } Logging.Log("Arm: Moving drones"); State = ArmState.MoveDrones; break; case ArmState.MoveDrones: var drone = ammoHangar.Items.FirstOrDefault(i => i.TypeId == Settings.Instance.DroneTypeId); if (drone == null || drone.Stacksize < 1) { Logging.Log("Arm: Out of drones"); State = ArmState.NotEnoughAmmo; break; } var neededDrones = Math.Floor((droneBay.Capacity - droneBay.UsedCapacity) / drone.Volume); Logging.Log("neededDrones: " + neededDrones); if (neededDrones == 0 && ((Settings.Instance.FittingsDefined && DefaultFittingFound) && !(UseMissionShip && !(Cache.Instance.ChangeMissionShipFittings)))) { Logging.Log("Arm: Fitting"); State = ArmState.OpenFittingWindow; break; } else if (neededDrones == 0) { State = ArmState.MoveItems; break; } // Move needed drones droneBay.Add(drone, (int)Math.Min(neededDrones, drone.Stacksize)); break; case ArmState.MoveItems: var bringItem = Cache.Instance.BringMissionItem; if (string.IsNullOrEmpty(bringItem)) { _missionItemMoved = true; } if (!_missionItemMoved) { var missionItem = (corpHangar ?? itemHangar).Items.FirstOrDefault(i => (i.TypeName ?? string.Empty).ToLower() == bringItem); if (missionItem == null) { missionItem = itemHangar.Items.FirstOrDefault(i => (i.TypeName ?? string.Empty).ToLower() == bringItem); } if (missionItem != null) { Logging.Log("Arm: Moving [" + missionItem.TypeName + "]"); cargo.Add(missionItem, 1); _missionItemMoved = true; break; } } var itemMoved = false; if (Cache.Instance.missionAmmo.Count() != 0) { AmmoToLoad = new List <Ammo>(Cache.Instance.missionAmmo); } foreach (var item in ammoHangar.Items.OrderBy(i => i.Quantity)) { if (item.ItemId <= 0) { continue; } var ammo = AmmoToLoad.FirstOrDefault(a => a.TypeId == item.TypeId); if (ammo == null) { continue; } Logging.Log("Arm: Moving [" + item.TypeName + "]"); var moveQuantity = Math.Min(item.Quantity, ammo.Quantity); moveQuantity = Math.Max(moveQuantity, 1); cargo.Add(item, moveQuantity); ammo.Quantity -= moveQuantity; if (ammo.Quantity <= 0) { Cache.Instance.missionAmmo.RemoveAll(a => a.TypeId == item.TypeId); AmmoToLoad.RemoveAll(a => a.TypeId == item.TypeId); } itemMoved = true; break; } if (AmmoToLoad.Count == 0 && _missionItemMoved) { _lastAction = DateTime.Now; Logging.Log("Arm: Waiting for items"); State = ArmState.WaitForItems; } else if (!itemMoved) { if (AmmoToLoad.Count > 0) { foreach (var ammo in AmmoToLoad) { Logging.Log("Arm: Missing ammo with TypeId [" + ammo.TypeId + "]"); } } if (!_missionItemMoved) { Logging.Log("Arm: Missing mission item [" + bringItem + "]"); } State = ArmState.NotEnoughAmmo; } break; case ArmState.WaitForItems: // Wait 5 seconds after moving if (DateTime.Now.Subtract(_lastAction).TotalSeconds < 5) { break; } if (cargo.Items.Count == 0) { break; } if (Cache.Instance.DirectEve.GetLockedItems().Count == 0) { // Close the drone bay, its not required in space. if (droneBay.IsReady) { droneBay.Window.Close(); } Logging.Log("Arm: Done"); //reload the ammo setting for combat try { var mission = Cache.Instance.DirectEve.AgentMissions.FirstOrDefault(m => m.AgentId == AgentId); if (mission == null) { return; } var missionName = Cache.Instance.FilterPath(mission.Name); var missionXmlPath = Path.Combine(Settings.Instance.MissionsPath, missionName + ".xml"); var missionXml = XDocument.Load(missionXmlPath); Cache.Instance.missionAmmo = new List <Ammo>(); var ammoTypes = missionXml.Root.Element("missionammo"); if (ammoTypes != null) { foreach (var ammo in ammoTypes.Elements("ammo")) { Cache.Instance.missionAmmo.Add(new Ammo(ammo)); } } } catch (Exception e) { Cache.Instance.missionAmmo = new List <Ammo>(); } State = ArmState.Done; break; } // Note, there's no unlock here as we *always* want our ammo! break; } }
/// <summary> /// Target combatants /// </summary> /// <remarks> /// This only targets ships that are targeting you /// </remarks> private void TargetCombatants() { // We are jammed, forget targeting anything... if (Cache.Instance.DirectEve.ActiveShip.MaxLockedTargets == 0) { if (!_isJammed) { Logging.Log("Combat: We are jammed and can't target anything"); } _isJammed = true; return; } if (_isJammed) { // Clear targeting list as it doesnt apply Cache.Instance.TargetingIDs.Clear(); Logging.Log("Combat: We are no longer jammed, retargeting"); } _isJammed = false; // Whats the range that we can target at var maxRange = Math.Min(Cache.Instance.DirectEve.ActiveShip.MaxTargetRange, Cache.Instance.WeaponRange); // Get a list of combat targets (combine targets + targeting) var targets = new List <EntityCache>(); targets.AddRange(Cache.Instance.Targets); targets.AddRange(Cache.Instance.Targeting); var combatTargets = targets.Where(e => e.CategoryId == (int)CategoryID.Entity && e.IsNpc && !e.IsContainer && e.GroupId != (int)Group.LargeCollidableStructure).ToList(); // Remove any target that is too far out of range (Weapon Range * 1.5) for (var i = combatTargets.Count - 1; i >= 0; i--) { var target = combatTargets[i]; if (target.Distance > maxRange * 1.5d) { Logging.Log("Combat: Target [" + target.Name + "][" + target.Id + "] out of range"); } else if (Cache.Instance.IgnoreTargets.Contains(target.Name.Trim())) { Logging.Log("Combat: Target [" + target.Name + "][" + target.Id + "] on ignore list"); } else { continue; } target.UnlockTarget(); combatTargets.RemoveAt(i); } // Get a list of current high and low value targets var highValueTargets = combatTargets.Where(t => t.TargetValue.HasValue || Cache.Instance.PriorityTargets.Any(pt => pt.Id == t.Id)).ToList(); var lowValueTargets = combatTargets.Where(t => !t.TargetValue.HasValue && !Cache.Instance.PriorityTargets.Any(pt => pt.Id == t.Id)).ToList(); // Build a list of things targeting me var targetingMe = Cache.Instance.TargetedBy.Where(t => t.IsNpc && t.CategoryId == (int)CategoryID.Entity && !t.IsContainer && t.Distance < maxRange && !targets.Any(c => c.Id == t.Id) && !Cache.Instance.IgnoreTargets.Contains(t.Name.Trim())).ToList(); var highValueTargetingMe = targetingMe.Where(t => t.TargetValue.HasValue).OrderByDescending(t => t.TargetValue.Value).ThenBy(t => t.Distance).ToList(); var lowValueTargetingMe = targetingMe.Where(t => !t.TargetValue.HasValue).OrderBy(t => t.Distance).ToList(); // Get the number of maximum targets, if there are no low or high value targets left, use the combined total of targets var maxHighValueTarget = (lowValueTargetingMe.Count + lowValueTargets.Count) == 0 ? Settings.Instance.MaximumLowValueTargets + Settings.Instance.MaximumHighValueTargets : Settings.Instance.MaximumHighValueTargets; var maxLowValueTarget = (highValueTargetingMe.Count + highValueTargets.Count) == 0 ? Settings.Instance.MaximumLowValueTargets + Settings.Instance.MaximumHighValueTargets : Settings.Instance.MaximumLowValueTargets; // Do we have too many high (none-priority) value targets targeted? while (highValueTargets.Where(t => !Cache.Instance.PriorityTargets.Any(pt => pt.Id == t.Id)).Count() > Math.Max(maxHighValueTarget - Cache.Instance.PriorityTargets.Count(), 0)) { // Unlock any target var target = highValueTargets.OrderByDescending(t => t.Distance).Where(t => !Cache.Instance.PriorityTargets.Any(pt => pt.Id == t.Id)).FirstOrDefault(); if (target == null) { break; } target.UnlockTarget(); highValueTargets.Remove(target); } // Do we have too many low value targets targeted? while (lowValueTargets.Count > maxLowValueTarget) { // Unlock any target var target = lowValueTargets.OrderByDescending(t => t.Distance).First(); target.UnlockTarget(); lowValueTargets.Remove(target); } // Do we have enough targeted? if ((highValueTargets.Count >= maxHighValueTarget && lowValueTargets.Count >= maxLowValueTarget) || ((highValueTargets.Count + lowValueTargets.Count) >= (maxHighValueTarget + maxLowValueTarget))) { return; } // Do we have any priority targets? var priority = Cache.Instance.PriorityTargets.Where(t => t.Distance < maxRange && !targets.Any(c => c.Id == t.Id) && !Cache.Instance.IgnoreTargets.Contains(t.Name.Trim())); foreach (var entity in priority) { // Have we reached the limit of high value targets? if (highValueTargets.Count >= maxHighValueTarget) { break; } Logging.Log("Combat: Targeting priority target [" + entity.Name + "][" + entity.Id + "]{" + highValueTargets.Count + "}"); entity.LockTarget(); highValueTargets.Add(entity); } foreach (var entity in highValueTargetingMe) { // Have we reached the limit of high value targets? if (highValueTargets.Count >= maxHighValueTarget) { break; } Logging.Log("Combat: Targeting high value target [" + entity.Name + "][" + entity.Id + "]{" + highValueTargets.Count + "}"); entity.LockTarget(); highValueTargets.Add(entity); } foreach (var entity in lowValueTargetingMe) { // Have we reached the limit of low value targets? if (lowValueTargets.Count >= maxLowValueTarget) { break; } Logging.Log("Combat: Targeting low value target [" + entity.Name + "][" + entity.Id + "]{" + lowValueTargets.Count + "}"); entity.LockTarget(); lowValueTargets.Add(entity); } }
public CharSchedule(XElement element) { CultureInfo enUS = new CultureInfo("en-US"); User = (string)element.Attribute("user"); PW = (string)element.Attribute("pw"); Name = (string)element.Attribute("name"); stopTimeSpecified = false; startTimeSpecified = false; string _start = (string)element.Attribute("start"); string _stop = (string)element.Attribute("stop"); DateTime _startTime = new DateTime(); DateTime _stopTime = new DateTime(); if (_start != null) { if (!DateTime.TryParseExact(_start, "HH:mm", enUS, DateTimeStyles.None, out _startTime)) { Logging.Log("[CharSchedule] " + Name + ": Couldn't parse starttime."); _startTime = DateTime.Now.AddSeconds(20); } else { startTimeSpecified = true; } } else { Logging.Log("[CharSchedule] No start time specified. Starting now."); _startTime = DateTime.Now.AddSeconds(20); } Start = _startTime; if (_stop != null) { if (!DateTime.TryParseExact(_stop, "HH:mm", enUS, DateTimeStyles.None, out _stopTime)) { Logging.Log("[CharSchedule] " + Name + ": Couldn't parse stoptime."); _stopTime = DateTime.Now.AddHours(24); } else { stopTimeSpecified = true; } } else { Logging.Log("[CharSchedule] No stop time specified."); _stopTime = DateTime.Now.AddHours(24); } Stop = _stopTime; if ((string)element.Attribute("runtime") != null) { RunTime = (double)element.Attribute("runtime"); stopTimeSpecified = true; } else { RunTime = -1; } }
/// <summary> /// Target wrecks within range /// </summary> private void TargetWrecks() { if (_nextTargetAction > DateTime.Now) { return; } // We are jammed, we do not need to log (Combat does this already) if (Cache.Instance.DirectEve.ActiveShip.MaxLockedTargets == 0) { return; } var targets = new List <EntityCache>(); targets.AddRange(Cache.Instance.Targets); targets.AddRange(Cache.Instance.Targeting); var hasSalvagers = Cache.Instance.Modules.Any(m => Salvagers.Contains(m.TypeId)); var wreckTargets = targets.Where(t => (t.GroupId == (int)Group.Wreck || t.GroupId == (int)Group.CargoContainer) && t.CategoryId == (int)CategoryID.Celestial).ToList(); // Check for cargo containers foreach (var wreck in wreckTargets) { if (Cache.Instance.IgnoreTargets.Contains(wreck.Name)) { Logging.Log("Salvage: Cargo Container [" + wreck.Name + "][" + wreck.Id + "] on the ignore list, ignoring."); wreck.UnlockTarget(); _nextTargetAction = DateTime.Now.AddMilliseconds((int)Time.TargetDelay_miliseconds); continue; } if (!Cache.Instance.SalvageAll) { if (Settings.Instance.WreckBlackList.Any(a => a == wreck.TypeId) && (wreck.Distance < (int)Distance.SafeScoopRange || wreck.IsWreckEmpty)) { wreck.UnlockTarget(); _nextTargetAction = DateTime.Now.AddMilliseconds((int)Time.TargetDelay_miliseconds); continue; } } if (hasSalvagers && wreck.GroupId != (int)Group.CargoContainer) { continue; } // Unlock if within loot range if (wreck.Distance < (int)Distance.SafeScoopRange) { Logging.Log("Salvage: Cargo Container [" + wreck.Name + "][" + wreck.Id + "] within loot range, unlocking container."); wreck.UnlockTarget(); _nextTargetAction = DateTime.Now.AddMilliseconds((int)Time.TargetDelay_miliseconds); return; } } if (Cache.Instance.MissionLoot) { if (wreckTargets.Count >= Math.Min(Cache.Instance.DirectEve.ActiveShip.MaxLockedTargets, Cache.Instance.DirectEve.Me.MaxLockedTargets)) { return; } } else if (wreckTargets.Count >= MaximumWreckTargets) { return; } var tractorBeams = Cache.Instance.Modules.Where(m => TractorBeams.Contains(m.TypeId)).ToList(); var tractorBeamRange = 0d; if (tractorBeams.Count > 0) { tractorBeamRange = tractorBeams.Min(t => t.OptimalRange); } var wrecks = Cache.Instance.UnlootedContainers; foreach (var wreck in wrecks.Where(w => !Cache.Instance.IgnoreTargets.Contains(w.Name.Trim()))) { // Its already a target, ignore it if (wreck.IsTarget || wreck.IsTargeting) { continue; } if (wreck.Distance > tractorBeamRange) { continue; } if (!wreck.HaveLootRights) { continue; } // No need to tractor a non-wreck within loot range if (wreck.GroupId != (int)Group.Wreck && wreck.Distance < (int)Distance.SafeScoopRange) { continue; } if (!Cache.Instance.SalvageAll) { if (Settings.Instance.WreckBlackList.Any(a => a == wreck.TypeId) && (wreck.IsWreckEmpty || wreck.Distance < (int)Distance.SafeScoopRange)) { continue; } } if (wreck.GroupId != (int)Group.Wreck && wreck.GroupId != (int)Group.CargoContainer) { continue; } if (!hasSalvagers) { // Ignore already looted wreck if (Cache.Instance.LootedContainers.Contains(wreck.Id)) { continue; } // Ignore empty wrecks if (wreck.GroupId == (int)Group.Wreck && wreck.IsWreckEmpty) { continue; } } Logging.Log("Salvage: Locking [" + wreck.Name + "][" + wreck.Id + "] - Distance [" + wreck.Distance + "]"); wreck.LockTarget(); wreckTargets.Add(wreck); _nextTargetAction = DateTime.Now.AddMilliseconds((int)Time.TargetDelay_miliseconds); if (Cache.Instance.MissionLoot) { if (wreckTargets.Count >= Math.Min(Cache.Instance.DirectEve.ActiveShip.MaxLockedTargets, Cache.Instance.DirectEve.Me.MaxLockedTargets)) { return; } } else if (wreckTargets.Count >= MaximumWreckTargets) { return; } return; } }