private static void LootWrecks()
{
if (Cache.Instance.NextLootAction > DateTime.UtcNow)
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage", "Debug: Cache.Instance.NextLootAction is still in the future, waiting", Logging.Teal);
return;
}
List<ItemCache> shipsCargo = Cache.Instance.CurrentShipsCargo.Items.Select(i => new ItemCache(i)).ToList();
double freeCargoCapacity = Cache.Instance.CurrentShipsCargo.Capacity - Cache.Instance.CurrentShipsCargo.UsedCapacity;
// Open a container in range
int containersProcessedThisTick = 0;
List<EntityCache> containersInRange = Cache.Instance.Containers.Where(e => e.Distance <= (int)Distances.SafeScoopRange).ToList();
if (Settings.Instance.DebugLootWrecks)
{
int containersInRangeCount = 0;
if (containersInRange.Any())
{
containersInRangeCount = containersInRange.Count();
}
List<EntityCache> containersOutOfRange = Cache.Instance.Containers.Where(e => e.Distance >= (int)Distances.SafeScoopRange).ToList();
int containersOutOfRangeCount = 0;
if (containersOutOfRange.Any())
{
containersOutOfRangeCount = containersOutOfRange.Count();
}
if (containersInRangeCount < 1) Logging.Log("Salvage", "Debug: containersInRange count [" + containersInRangeCount + "]", Logging.Teal);
if (containersOutOfRangeCount < 1) Logging.Log("Salvage", "Debug: containersOutOfRange count [" + containersOutOfRangeCount + "]", Logging.Teal);
}
foreach (EntityCache containerEntity in containersInRange.OrderByDescending(i => i.IsLootTarget))
{
containersProcessedThisTick++;
// Empty wreck, ignore
if (containerEntity.IsWreckEmpty) //this only returns true if it is a wreck, not for cargo containers, spawn containers, etc.
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "Ignoring Empty Wreck", Logging.Teal);
continue;
}
// We looted this container
if (Cache.Instance.LootedContainers.Contains(containerEntity.Id))
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "We have already looted [" + containerEntity.Id + "]", Logging.White);
continue;
}
// We should not loot this container
//if (Settings.Instance.FleetSupportSlave && Cache.Instance.ListofContainersToLoot.Contains(containerEntity.Id))
//{
// if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "We are not supposed to loot [" + containerEntity.Id + "]. Leaving it for the Master.", Logging.White);
// continue;
//}
// Ignore open request within 10 seconds
if (OpenedContainers.ContainsKey(containerEntity.Id) && DateTime.UtcNow.Subtract(OpenedContainers[containerEntity.Id]).TotalSeconds < 10)
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "We attempted to open [" + containerEntity.Id + "] less than 10 sec ago, ignoring", Logging.White);
continue;
}
// Don't even try to open a wreck if you are speed tanking and you are not processing a loot action
if (Settings.Instance.SpeedTank && !Cache.Instance.MyShipEntity.IsBattleship && Cache.Instance.OpenWrecks == false)
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "SpeedTank is true and OpenWrecks is false [" + containerEntity.Id + "]", Logging.White);
continue;
}
// Don't even try to open a wreck if you are specified LootEverything as false and you are not 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
Cache.Instance.ContainerInSpace = Cache.Instance.DirectEve.GetContainer(containerEntity.Id);
if (Cache.Instance.ContainerInSpace == null)
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "if (Cache.Instance.ContainerInSpace == null)", Logging.White);
continue;
}
if (Cache.Instance.ContainerInSpace.Window == null)
{
containerEntity.OpenCargo();
Cache.Instance.NextLootAction = DateTime.UtcNow.AddMilliseconds(Time.Instance.LootingDelay_milliseconds);
return;
}
if (!Cache.Instance.ContainerInSpace.Window.IsReady)
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage", "LootWrecks: Cache.Instance.ContainerInSpace.Window is not ready", Logging.White);
return;
}
if (Cache.Instance.ContainerInSpace.Window.IsReady)
{
Logging.Log("Salvage", "Opened container [" + containerEntity.Name + "][" + Math.Round(containerEntity.Distance / 1000, 0) + "k][ID: " + Cache.Instance.MaskedID(containerEntity.Id) + "]", Logging.White);
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage", "LootWrecks: Cache.Instance.ContainerInSpace.Window is ready", Logging.White);
OpenedContainers[containerEntity.Id] = DateTime.UtcNow;
Cache.Instance.NextLootAction = DateTime.UtcNow.AddMilliseconds(Time.Instance.LootingDelay_milliseconds);
// List its items
IEnumerable<ItemCache> items = Cache.Instance.ContainerInSpace.Items.Select(i => new ItemCache(i)).ToList();
if (Settings.Instance.DebugLootWrecks && items.Any()) Logging.Log("Salvage.LootWrecks", "Found [" + items.Count() + "] items in [" + containerEntity.Name + "][" + Math.Round(containerEntity.Distance / 1000,0) + "k][" + Cache.Instance.MaskedID(containerEntity.Id) + "]", Logging.Teal);
// Build a list of items to loot
List<ItemCache> lootItems = new List<ItemCache>();
// log wreck contents to file
if (!Statistics.WreckStatistics(items, containerEntity)) break;
//
// when full return to base and unloadloot
//
if (Settings.Instance.UnloadLootAtStation && Cache.Instance.CurrentShipsCargo.IsValid && Cache.Instance.CurrentShipsCargo.Capacity > 150 && (Cache.Instance.CurrentShipsCargo.Capacity - Cache.Instance.CurrentShipsCargo.UsedCapacity) < 50)
{
if (_States.CurrentCombatMissionBehaviorState == CombatMissionsBehaviorState.ExecuteMission)
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "(mission) We are full, heading back to base to dump loot ", Logging.Teal);
_States.CurrentCombatHelperBehaviorState = States.CombatHelperBehaviorState.GotoBase;
break;
}
if (_States.CurrentDedicatedBookmarkSalvagerBehaviorState == States.DedicatedBookmarkSalvagerBehaviorState.Salvage)
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "(salvage) We are full, heading back to base to dump loot ", Logging.Teal);
_States.CurrentDedicatedBookmarkSalvagerBehaviorState = DedicatedBookmarkSalvagerBehaviorState.GotoBase;
Cache.Instance.NextSalvageTrip = DateTime.UtcNow;
break;
}
Logging.Log("Salvage.LootWrecks", "We are full: we are using a behavior that does not have a supported place to auto dump loot: error!", Logging.Orange);
break;
}
// Walk through the list of items ordered by highest value item first
foreach (ItemCache item in items.OrderByDescending(i => i.IsContraband).ThenByDescending(i => i.IskPerM3))
{
if (freeCargoCapacity < 1000) //this should allow BSs to not pickup large low value items but haulers and noctis' to scoop everything
{
// We never want to pick up a cap booster
if (item.GroupID == (int)Group.CapacitorGroupCharge)
{
continue;
}
}
// We pick up loot depending on isk per m3
bool _isMissionItem = Cache.Instance.MissionItems.Contains((item.Name ?? string.Empty).ToLower());
if (Settings.Instance.FleetSupportSlave && !Settings.Instance.FleetSupportMaster)
{
if (Cache.Instance.ListofMissionCompletionItemsToLoot.Contains(item.Name))
{
if (Settings.Instance.DebugFleetSupportSlave) Logging.Log("Salvage.LootWrecks", "[" + item.Name + "] is an item specified in a lootitem action. Do not loot it here. Let the Master loot this.", Logging.Teal);
Cache.Instance.LootedContainers.Add(containerEntity.Id);
continue;
}
}
// Never pick up contraband (unless its the mission item)
if (item.IsContraband) //is the mission item EVER contraband?!
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "[" + item.Name + "] is not the mission item and is considered Contraband: ignore it", Logging.Teal);
Cache.Instance.LootedContainers.Add(containerEntity.Id);
continue;
}
if (!Settings.Instance.LootOnlyWhatYouCanWithoutSlowingDownMissionCompletion)
{
// 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) <= (item.IsMissionItem ? 0 : ReserveCargoCapacity))
{
Logging.Log("Salvage.LootWrecks","We Need More m3: FreeCargoCapacity [" + freeCargoCapacity + "] - [" + item.Name + "][" + item.TotalVolume + "total][" + item.Volume + "each]",Logging.Debug);
//
// I have no idea what problem this solved (a long long time ago, but its not doing anything useful that I can tell)
//
// We can't drop items in this container anyway, well get it after its salvaged
//if (!_isMissionItem && containerEntity.GroupId != (int)Group.CargoContainer)
//{
// if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "[" + item.Name + "] is not the mission item and this appears to be a container (in a container!): ignore it until after its salvaged", Logging.Teal);
// Cache.Instance.LootedContainers.Add(containerEntity.Id);
// continue;
//}
// Make a list of items which are worth less
List<ItemCache> worthLess = null;
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.IsMissionItem && sc.IskPerM3.HasValue).ToList();
}
if (_States.CurrentQuestorState == QuestorState.CombatMissionsBehavior)
{
// Remove mission item from this list
worthLess.RemoveAll(wl => Cache.Instance.MissionItems.Contains((wl.Name ?? string.Empty).ToLower()));
if (!string.IsNullOrEmpty(Cache.Instance.BringMissionItem))
{
worthLess.RemoveAll(wl => (wl.Name ?? string.Empty).ToLower() == Cache.Instance.BringMissionItem.ToLower());
}
// 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.Any())
{
if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "[" + item.Name + "] ::: if (!worthLess.Any()) continue ", Logging.Teal);
continue;
}
// Not enough space even if we dumped the crap
if ((freeCargoCapacity + worthLess.Sum(wl => wl.TotalVolume)) < item.TotalVolume)
{
if (item.IsMissionItem)
{
Logging.Log("Salvage", "Not enough space for [" + item.Name + "] Need [" + item.TotalVolume + "] maximum available [" + (freeCargoCapacity + worthLess.Sum(wl => wl.TotalVolume)) + "]", Logging.White);
//
// partially loot the mission item if possible.
//
}
continue;
}
// Start clearing out items that are worth less
List<DirectItem> moveTheseItems = new List<DirectItem>();
foreach (ItemCache 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);
// Subtract (now) free volume
freeCargoCapacity += wl.TotalVolume;
// We freed up enough space?
if ((freeCargoCapacity - item.TotalVolume) >= ReserveCargoCapacity)
{
break;
}
}
if (moveTheseItems.Count > 0)
{
// jettison loot
if (DateTime.UtcNow.Subtract(Cache.Instance.LastJettison).TotalSeconds < Time.Instance.DelayBetweenJetcans_seconds)
{
return;
}
Logging.Log("Salvage", "Jettisoning [" + moveTheseItems.Count + "] items to make room for the more valuable loot", Logging.White);
// Note: This could (in theory) fuck up with the bot jettison an item and
// then picking it up again :/ (granted it should never happen unless
// mission item volume > reserved volume
Cache.Instance.CurrentShipsCargo.Jettison(moveTheseItems.Select(i => i.ItemId));
Cache.Instance.NextLootAction = DateTime.UtcNow.AddMilliseconds(Time.Instance.LootingDelay_milliseconds);
Cache.Instance.LastJettison = DateTime.UtcNow;
return;
}
return;
}
// Update free space
freeCargoCapacity -= item.TotalVolume;
lootItems.Add(item);
//if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "We just added 1 more item to lootItems for a total of [" + lootItems.Count() + "] items we will loot from [" + containerID + "]", Logging.Teal);
}
// Mark container as looted
Cache.Instance.LootedContainers.Add(containerEntity.Id);
// Loot actual items
if (lootItems.Count != 0)
{
Logging.Log("Salvage.LootWrecks", "Looting container [" + containerEntity.Name + "][" + Math.Round(containerEntity.Distance / 1000, 0) + "k][ID: " + Cache.Instance.MaskedID(containerEntity.Id) + "], [" + lootItems.Count + "] valuable items", Logging.White);
if(Settings.Instance.DebugLootWrecks)
{
int icount = 0;
if (lootItems != null && lootItems.Any())
{
foreach (var lootItem in lootItems)
{
icount++;
Logging.Log("Salvage.LootWrecks", "[" + icount + "]LootItems Contains: [" + lootItem.Name + "] Quantity[" + lootItem.Quantity + "k] isContraband [" + lootItem.IsContraband + "] groupID [" + lootItem.GroupID + "] typeID [" + lootItem.TypeId + "] isCommonMissionItem [" + lootItem.IsCommonMissionItem + "]", Logging.White);
if (lootItem.GroupID == (int)Group.Drugs ||
lootItem.GroupID == (int)Group.ToxicWaste ||
lootItem.TypeId == (int)TypeID.Small_Arms ||
lootItem.TypeId == (int)TypeID.Ectoplasm)
{
lootItems.Remove(lootItem);
Logging.Log("Salvage.LootWrecks", "[" + icount + "] Removed this from LootItems before looting [" + lootItem.Name + "] Quantity[" + lootItem.Quantity + "k] isContraband [" + lootItem.IsContraband + "] groupID [" + lootItem.GroupID + "] typeID [" + lootItem.TypeId + "] isCommonMissionItem [" + lootItem.IsCommonMissionItem + "]", Logging.White);
}
}
}
}
Cache.Instance.CurrentShipsCargo.Add(lootItems.Select(i => i.DirectItem));
}
else
{
Logging.Log("Salvage.LootWrecks", "Container [" + containerEntity.Name + "][" + Math.Round(containerEntity.Distance / 1000, 0) + "k][ID: " + Cache.Instance.MaskedID(containerEntity.Id) + "] contained no valuable items", Logging.White);
}
return;
}
//add cont proceed this tick
//if (containersProcessedThisTick < Settings.Instance.NumberOfModulesToActivateInCycle)
//{
// if (Settings.Instance.DebugLootWrecks) Logging.Log("Salvage.LootWrecks", "if (containersProcessedThisTick < Settings.Instance.NumberOfModulesToActivateInCycle)", Logging.White);
// continue;
//}
return;
}
}