/// <summary> /// Activate target painters /// </summary> public void ActivateStasisWeb(EntityCache target) { var webs = Cache.Instance.Modules.Where(m => m.GroupId == (int) Group.StasisWeb).ToList(); // Find the first active weapon // Assist this weapon foreach (var web in webs) { // Are we on the right target? if (web.IsActive) { if (web.TargetId != target.Id) web.Deactivate(); continue; } // Are we deactivating? if (web.IsDeactivating) continue; // Target is out of web range if (target.Distance >= web.OptimalRange) continue; if (CanActivate(web, target, false)) { Logging.Log("Combat: Activating stasis web [" + web.ItemId + "] on [" + target.Name + "][" + target.Id + "]"); web.Activate(target.Id); } } }
/// <summary> Activate StasisWeb /// </summary> public void ActivateStasisWeb(EntityCache target) { if (DateTime.Now < _nextWeaponAction) //if we just did something wait a fraction of a second { return; } var webs = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.StasisWeb).ToList(); // Find the first active weapon // Assist this weapon foreach (var web in webs) { // Are we on the right target? if (web.IsActive) { if (web.TargetId != target.Id) { web.Deactivate(); } continue; } // Are we deactivating? if (web.IsDeactivating) { continue; } // Target is out of web range if (target.Distance >= web.OptimalRange) { continue; } if (CanActivate(web, target, false)) { Logging.Log("Combat: Activating stasis web [" + web.ItemId + "] on [" + target.Name + "][ID: " + target.Id + "]"); web.Activate(target.Id); _nextWebAction = DateTime.Now.AddMilliseconds((int)Time.WebDelay_miliseconds); return; } } }
/// <summary> /// Returns the target we need to activate everything on /// </summary> /// <returns></returns> private EntityCache GetTarget() { // Find the first active weapon's target EntityCache weaponTarget = null; foreach (var weapon in Cache.Instance.Weapons.Where(m => m.IsActive)) { // Find the target associated with the weapon weaponTarget = Cache.Instance.EntityById(weapon.TargetId); if (weaponTarget != null) { break; } } // Return best possible target return(Cache.Instance.GetBestTarget(weaponTarget, Cache.Instance.WeaponRange, false)); }
/// <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 ReloadAmmo(ModuleCache weapon, EntityCache entity) { // We need the cargo bay open for both reload actions var cargo = Cache.Instance.DirectEve.GetShipsCargo(); if (cargo.Window == null) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenCargoHoldOfActiveShip); return(false); } if (!cargo.IsReady) { return(false); } return(weapon.IsEnergyWeapon ? ReloadEnergyWeaponAmmo(weapon, entity) : ReloadNormalAmmo(weapon, entity)); }
/// <summary> /// Invalidate the cached items /// </summary> public void InvalidateCache() { _windows = null; _unlootedContainers = null; _star = null; _stations = null; _modules = null; _targets = null; _targeting = null; _targetedBy = null; _entities = null; _agent = null; _approaching = null; _activeDrones = null; _containers = null; _priorityTargets.ForEach(pt => pt.ClearCache()); _entitiesById.Clear(); }
/// <summary> /// Activate Nos /// </summary> public void ActivateNos(EntityCache target) { var noses = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.nos).ToList(); //Logging.Log("Combat: we have " + noses.Count.ToString() + " Nos modules"); // Find the first active weapon // Assist this weapon foreach (var nos in noses) { // Are we on the right target? if (nos.IsActive) { if (nos.TargetId != target.Id) { nos.Deactivate(); } continue; } // Are we deactivating? if (nos.IsDeactivating) { continue; } //Logging.Log("Combat: Distances Target[ " + target.Distance + " Optimal[" + nos.OptimalRange.ToString()+"]"); // Target is out of Nos range if (target.Distance >= Settings.Instance.NosDistance) { continue; } if (CanActivate(nos, target, false)) { Logging.Log("Combat: Nos [" + nos.ItemId + "] on [" + target.Name + "][" + target.Id + "]"); nos.Activate(target.Id); } else { Logging.Log("Combat: Cannot Activate Nos [" + nos.ItemId + "] on [" + target.Name + "][" + target.Id + "]"); } } }
/// <summary> Activate Nos /// </summary> public void ActivateNos(EntityCache target) { if (DateTime.Now < _nextWeaponAction) //if we just did something wait a fraction of a second return; var noses = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.nos).ToList(); //Logging.Log("Combat: we have " + noses.Count.ToString() + " Nos modules"); // Find the first active weapon // Assist this weapon foreach (var nos in noses) { // Are we on the right target? if (nos.IsActive) { if (nos.TargetId != target.Id) nos.Deactivate(); continue; } // Are we deactivating? if (nos.IsDeactivating) continue; //Logging.Log("Combat: Distances Target[ " + Math.Round(target.Distance,0) + " Optimal[" + nos.OptimalRange.ToString()+"]"); // Target is out of Nos range if (target.Distance >= Settings.Instance.NosDistance) continue; if (CanActivate(nos, target, false)) { Logging.Log("Combat: Nos [" + nos.ItemId + "] on [" + target.Name + "][ID: " + target.Id + "][" + Math.Round(target.Distance/1000,0) + "k away]"); nos.Activate(target.Id); _nextNosAction = DateTime.Now.AddMilliseconds((int)Time.NosDelay_miliseconds); return; } else { Logging.Log("Combat: Cannot Activate Nos [" + nos.ItemId + "] on [" + target.Name + "][ID: " + target.Id + "][" + Math.Round(target.Distance / 1000, 0) + "k away]"); } } }
/// <summary> Activate target painters /// </summary> public void ActivateTargetPainters(EntityCache target) { if (DateTime.Now < _nextWeaponAction) //if we just did something wait a fraction of a second { return; } var targetPainters = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.TargetPainter).ToList(); // Find the first active weapon // Assist this weapon foreach (var painter in targetPainters) { // Are we on the right target? if (painter.IsActive) { if (painter.TargetId != target.Id) { painter.Deactivate(); } continue; } // Are we deactivating? if (painter.IsDeactivating) { continue; } if (CanActivate(painter, target, false)) { Logging.Log("Combat: Activating painter [" + painter.ItemId + "] on [" + target.Name + "][ID: " + target.Id + "][" + Math.Round(target.Distance / 1000, 0) + "k away]"); painter.Activate(target.Id); _nextPainterAction = DateTime.Now.AddMilliseconds((int)Time.PainterDelay_miliseconds); return; } } }
/// <summary> /// Activate StasisWeb /// </summary> public void ActivateStasisWeb(EntityCache target) { var webs = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.StasisWeb).ToList(); // Find the first active weapon // Assist this weapon foreach (var web in webs) { // Are we on the right target? if (web.IsActive) { if (web.TargetId != target.Id) { web.Deactivate(); } continue; } // Are we deactivating? if (web.IsDeactivating) { continue; } // Target is out of web range if (target.Distance >= web.OptimalRange) { continue; } if (CanActivate(web, target, false)) { Logging.Log("Combat: Activating stasis web [" + web.ItemId + "] on [" + target.Name + "][" + target.Id + "]"); web.Activate(target.Id); } } }
/// <summary> /// Activate Nos /// </summary> public void ActivateNos(EntityCache target) { var noses = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.nos).ToList(); //Logging.Log("Combat: we have " + noses.Count.ToString() + " Nos modules"); // Find the first active weapon // Assist this weapon foreach (var nos in noses) { // Are we on the right target? if (nos.IsActive) { if (nos.TargetId != target.Id) nos.Deactivate(); continue; } // Are we deactivating? if (nos.IsDeactivating) continue; //Logging.Log("Combat: Distances Target[ " + target.Distance + " Optimal[" + nos.OptimalRange.ToString()+"]"); // Target is out of Nos range if (target.Distance >= Settings.Instance.NosDistance) continue; if (CanActivate(nos, target, false)) { Logging.Log("Combat: Nos [" + nos.ItemId + "] on [" + target.Name + "][" + target.Id + "]"); nos.Activate(target.Id); } else { Logging.Log("Combat: Cannot Activate Nos [" + nos.ItemId + "] on [" + target.Name + "][" + target.Id + "]"); } } }
/// <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); //use mission specific ammo if (Cache.Instance.missionAmmo.Count() != 0) { ammo = Cache.Instance.missionAmmo.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); } } }
/// <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)); //check if mission specific ammo is defined if (Cache.Instance.missionAmmo.Count() != 0) { correctAmmo = Cache.Instance.missionAmmo.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)); if (Cache.Instance.missionAmmo.Count() != 0) { correctAmmo = Cache.Instance.missionAmmo; } // 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 ReloadEnergyWeaponAmmo(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)); // 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; var charge = cargo.Items.OrderBy(i => i.Quantity).FirstOrDefault(i => i.TypeId == ammo.TypeId); // We do not have any ammo left that can hit targets at that range! if (charge == null) return false; // We have enough ammo loaded if (weapon.Charge != null && weapon.Charge.TypeId == ammo.TypeId) return true; // We are reloading, wait at least 5 seconds if (_lastWeaponReload.ContainsKey(weapon.ItemId) && DateTime.Now < _lastWeaponReload[weapon.ItemId].AddSeconds(5)) 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; }
/// <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 ReloadAmmo(ModuleCache weapon, EntityCache entity) { // We need the cargo bay open for both reload actions var cargo = Cache.Instance.DirectEve.GetShipsCargo(); if (cargo.Window == null) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.OpenCargoHoldOfActiveShip); return false; } if (!cargo.IsReady) return false; return weapon.IsEnergyWeapon ? ReloadEnergyWeaponAmmo(weapon, entity) : ReloadNormalAmmo(weapon, entity); }
/// <summary> /// Returns true if it can activate the weapon on the target /// </summary> /// <remarks> /// The idea behind this function is that a target that explodes isnt being fired on within 5 seconds /// </remarks> /// <param name = "module"></param> /// <param name = "entity"></param> /// <param name = "isWeapon"></param> /// <returns></returns> public bool CanActivate(ModuleCache module, EntityCache entity, bool isWeapon) { // We have changed target, allow activation if (entity.Id != module.LastTargetId) return true; // We have reloaded, allow activation if (isWeapon && module.CurrentCharges == MaxCharges) return true; // We havent reloaded, insert a wait-time if (_lastModuleActivation.ContainsKey(module.ItemId)) { if (DateTime.Now.Subtract(_lastModuleActivation[module.ItemId]).TotalSeconds < 3) return false; _lastModuleActivation.Remove(module.ItemId); return true; } _lastModuleActivation.Add(module.ItemId, DateTime.Now); return false; }
/// <summary> /// Activate target painters /// </summary> public void ActivateTargetPainters(EntityCache target) { var targetPainters = Cache.Instance.Modules.Where(m => m.GroupId == (int) Group.TargetPainter).ToList(); // Find the first active weapon // Assist this weapon foreach (var painter in targetPainters) { // Are we on the right target? if (painter.IsActive) { if (painter.TargetId != target.Id) painter.Deactivate(); continue; } // Are we deactivating? if (painter.IsDeactivating) continue; if (CanActivate(painter, target, false)) { Logging.Log("Combat: Activating painter [" + painter.ItemId + "] on [" + target.Name + "][" + target.Id + "]"); painter.Activate(target.Id); } } }
/// <summary> /// Return the best possible target (based on current target, distance and low value first) /// </summary> /// <param name="currentTarget"></param> /// <param name="distance"></param> /// <param name="lowValueFirst"></param> /// <returns></returns> public EntityCache GetBestTarget(EntityCache currentTarget, double distance, bool lowValueFirst) { // Is our current target a warp scrambling priority target? if (currentTarget != null && PriorityTargets.Any(pt => pt.Id == currentTarget.Id && pt.IsWarpScramblingMe)) return currentTarget; // Get the closest warp scrambling priority target var target = PriorityTargets.OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(pt => pt.Distance < distance && pt.IsWarpScramblingMe && Targets.Any(t => t.Id == pt.Id)); if (target != null) return target; // Is our current target any other priority target? if (currentTarget != null && PriorityTargets.Any(pt => pt.Id == currentTarget.Id)) return currentTarget; // Get the closest priority target target = PriorityTargets.OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(pt => pt.Distance < distance && Targets.Any(t => t.Id == pt.Id)); if (target != null) return target; // Do we have a target? if (currentTarget != null) return currentTarget; // Get all entity targets var targets = Targets.Where(e => e.CategoryId == (int)CategoryID.Entity && e.IsNpc && !e.IsContainer && e.GroupId != (int)Group.LargeCollidableStructure); // Get the closest high value target var highValueTarget = targets.Where(t => t.TargetValue.HasValue && t.Distance < distance).OrderByDescending(t => t.TargetValue.Value).ThenBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(); // Get the closest low value target var lowValueTarget = targets.Where(t => !t.TargetValue.HasValue && t.Distance < distance).OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(); if (lowValueFirst && lowValueTarget != null) return lowValueTarget; if (!lowValueFirst && highValueTarget != null) return highValueTarget; // Return either one or the other return lowValueTarget ?? highValueTarget; }
public bool ReloadEnergyWeaponAmmo(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)); // We are out of ammo! :( if (correctAmmo.Count() == 0) { State = CombatState.OutOfAmmo; return(false); } // Get the best possible ammo - energy weapons change ammo near instantly var ammo = correctAmmo.Where(a => a.Range > (entity.Distance)).OrderBy(a => a.Range).FirstOrDefault(); //default // We do not have any ammo left that can hit targets at that range! if (ammo == null) { return(false); } var charge = cargo.Items.OrderBy(i => i.Quantity).FirstOrDefault(i => i.TypeId == ammo.TypeId); // We do not have any ammo left that can hit targets at that range! if (charge == null) { return(false); } // We have enough ammo loaded if (weapon.Charge != null && weapon.Charge.TypeId == ammo.TypeId) { return(true); } // We are reloading, wait at least 5 seconds if (_lastWeaponReload.ContainsKey(weapon.ItemId) && DateTime.Now < _lastWeaponReload[weapon.ItemId].AddSeconds(5)) { 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); }
/// <summary> Activate weapons /// </summary> private void ActivateWeapons(EntityCache target) { if (DateTime.Now < _nextWeaponAction) //if we just did something wait a fraction of a second return; var DontMoveMyShip = true; // This may become an XML setting at some point. // // Do we really want a non-mission action moving the ship around at all!! (other than speed tanking)? // // Get lowest range var range = Math.Min(Cache.Instance.WeaponRange, Cache.Instance.DirectEve.ActiveShip.MaxTargetRange); if (Settings.Instance.SpeedTank && (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != target.Id)) { if ((DateTime.Now.Subtract(_lastOrbit).TotalSeconds > 15)) { target.Orbit(Cache.Instance.OrbitDistance); Logging.Log("Combat.ActivateWeapons: Initiating Orbit [" + target.Name + "][ID: " + target.Id + "]"); _lastOrbit = DateTime.Now; } } if (!DontMoveMyShip) //why would we want the ship to move if we aren't speed tanking and the mission XML isn't telling us to move? { if (!Settings.Instance.SpeedTank) //we need to make sure that orbitrange is set to the range of the ship if it isn't specified in the character XML!!!! { if (Settings.Instance.OptimalRange != 0) { if (target.Distance > Settings.Instance.OptimalRange + (int)Distance.OptimalRangeCushion && (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != target.Id)) { target.Approach(Settings.Instance.OptimalRange); Logging.Log("Combat.ActivateWeapons:: Using Optimal Range: Approaching target [" + target.Name + "][ID: " + target.Id + "]"); } if (target.Distance <= Settings.Instance.OptimalRange && Cache.Instance.Approaching != null) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdStopShip); Cache.Instance.Approaching = null; Logging.Log("Combat.ActivateWeapons: Using Optimal Range: Stop ship, target is in orbit range"); } } else { if (target.Distance > range && (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != target.Id)) { target.Approach((int)(Cache.Instance.WeaponRange * 0.8d)); Logging.Log("Combat.ActivateWeapons: Using Weapons Range: Approaching target [" + target.Name + "][ID: " + target.Id + "]"); } if (target.Distance <= range && Cache.Instance.Approaching != null) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdStopShip); Cache.Instance.Approaching = null; Logging.Log("Combat.ActivateWeapons: Using Weapons Range: Stop ship, target is in orbit range"); } } } } // 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) { // don't waste ammo on small target if you use autocannon or siege i hope you use drone if (Settings.Instance.DontShootFrigatesWithSiegeorAutoCannons) //this defaults to false and needs to be changed in your characters settings xml file if you want to enable this option { if (Settings.Instance.WeaponGroupId == 55 || Settings.Instance.WeaponGroupId == 508 || Settings.Instance.WeaponGroupId == 506) { if (target.Distance <= (int)Distance.InsideThisRangeIsLIkelyToBeMostlyFrigates && !target.TargetValue.HasValue && target.GroupId != (int)Group.LargeCollidableStructure) { weapon.Deactivate(); } } } if (!weapon.IsActive) continue; if (weapon.IsReloadingAmmo || weapon.IsDeactivating || weapon.IsChangingAmmo) continue; // No ammo loaded if (weapon.Charge == null) continue; var ammo = Settings.Instance.Ammo.FirstOrDefault(a => a.TypeId == weapon.Charge.TypeId); //use mission specific ammo if (Cache.Instance.missionAmmo.Count() != 0) { ammo = Cache.Instance.missionAmmo.FirstOrDefault(a => a.TypeId == weapon.Charge.TypeId); } // How can this happen? Someone manually loaded ammo if (ammo == null) continue; // If we have already activated warp, deactivate the weapons if (!Cache.Instance.DirectEve.ActiveShip.Entity.IsWarping) { // 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 reloading, deactivating or changing ammo? if (weapon.IsReloadingAmmo || weapon.IsDeactivating || weapon.IsChangingAmmo) continue; // Are we on the right target? if (weapon.IsActive) { if (weapon.TargetId != target.Id) weapon.Deactivate(); continue; } // No, check ammo type and if that is correct, activate weapon if (ReloadAmmo(weapon, target) && CanActivate(weapon, target, true)) { Logging.Log("Combat: Activating weapon [" + weapon.ItemId + "] on [" + target.Name + "][ID: " + target.Id + "][" + Math.Round(target.Distance/1000,0) + "k away]"); weapon.Activate(target.Id); _nextWeaponAction = DateTime.Now.AddMilliseconds((int)Time.WeaponDelay_miliseconds); //we know we are connected if we were able to get this far - update the lastknownGoodConnectedTime Cache.Instance.lastKnownGoodConnectedTime = DateTime.Now; Cache.Instance.MyWalletBalance = Cache.Instance.DirectEve.Me.Wealth; return; } } }
/// <summary> Activate weapons /// </summary> private void ActivateWeapons(EntityCache target) { var DontMoveMyShip = true; // This may become an XML setting at some point. // // Do we really want a non-mission action moving the ship around at all!! (other than speed tanking)? // // Get lowest range var range = Math.Min(Cache.Instance.WeaponRange, Cache.Instance.DirectEve.ActiveShip.MaxTargetRange); if (Settings.Instance.SpeedTank && (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != target.Id)) { if ((DateTime.Now.Subtract(_lastOrbit).TotalSeconds > 15)) { target.Orbit(Cache.Instance.OrbitDistance); Logging.Log("Combat.ActivateWeapons: Initiating Orbit [" + target.Name + "][" + target.Id + "]"); _lastOrbit = DateTime.Now; } } if (!DontMoveMyShip) //why would we want the ship to move if we arent speed tanking and the mission XML isnt telling us to move? { if (!Settings.Instance.SpeedTank) //we need to make sure that orbitrange is set to the range of the ship if it isnt specified in the character XML!!!! { if (Settings.Instance.OptimalRange != 0) { if (target.Distance > Settings.Instance.OptimalRange + (int)Distance.OptimalRangeCushion && (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != target.Id)) { target.Approach(Settings.Instance.OptimalRange); Logging.Log("Combat.ActivateWeapons:: Using Optimal Range: Approaching target [" + target.Name + "][" + target.Id + "]"); } if (target.Distance <= Settings.Instance.OptimalRange && Cache.Instance.Approaching != null) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdStopShip); Cache.Instance.Approaching = null; Logging.Log("Combat.ActivateWeapons: Using Optimal Range: Stop ship, target is in orbit range"); } } else { if (target.Distance > range && (Cache.Instance.Approaching == null || Cache.Instance.Approaching.Id != target.Id)) { target.Approach((int)(Cache.Instance.WeaponRange * 0.8d)); Logging.Log("Combat.ActivateWeapons: Using Weapons Range: Approaching target [" + target.Name + "][" + target.Id + "]"); } if (target.Distance <= range && Cache.Instance.Approaching != null) { Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdStopShip); Cache.Instance.Approaching = null; Logging.Log("Combat.ActivateWeapons: Using Weapons Range: Stop ship, target is in orbit range"); } } } } // 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) { // dont waste ammo on small target if you use autocannon or siege i hope you use drone if (Settings.Instance.DontShootFrigatesWithSiegeorAutoCannons) //this defaults to false and needs to be changed in your characters settings xml file if you want to enable this option { if (Settings.Instance.WeaponGroupId == 55 || Settings.Instance.WeaponGroupId == 508 || Settings.Instance.WeaponGroupId == 506) { if (target.Distance <= (int)Distance.InsideThisRangeIsLIkelyToBeMostlyFrigates && !target.TargetValue.HasValue && target.GroupId != (int)Group.LargeCollidableStructure) { weapon.Deactivate(); } } } if (!weapon.IsActive) { continue; } if (weapon.IsReloadingAmmo || weapon.IsDeactivating || weapon.IsChangingAmmo) { continue; } // No ammo loaded if (weapon.Charge == null) { continue; } var ammo = Settings.Instance.Ammo.FirstOrDefault(a => a.TypeId == weapon.Charge.TypeId); //use mission specific ammo if (Cache.Instance.missionAmmo.Count() != 0) { ammo = Cache.Instance.missionAmmo.FirstOrDefault(a => a.TypeId == weapon.Charge.TypeId); } // How can this happen? Someone manually loaded ammo if (ammo == null) { continue; } // If we have already activated warp, deactivate the weapons if (!Cache.Instance.DirectEve.ActiveShip.Entity.IsWarping) { // 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 reloading, deactivating or changing ammo? if (weapon.IsReloadingAmmo || weapon.IsDeactivating || weapon.IsChangingAmmo) { continue; } // Are we on the right target? if (weapon.IsActive) { if (weapon.TargetId != target.Id) { weapon.Deactivate(); } 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); //More human behaviour //System.Threading.Thread.Sleep(333); //we know we are connected if we were able to get this far - update the lastknownGoodConnectedTime Cache.Instance.lastKnownGoodConnectedTime = DateTime.Now; Cache.Instance.MyWalletBalance = Cache.Instance.DirectEve.Me.Wealth; } } }
/// <summary> /// Invalidate the cached items /// </summary> public void InvalidateCache() { _windows = null; _unlootedContainers = null; _star = null; _stations = null; _stargates = null; _modules = null; _targets = null; _targeting = null; _targetedBy = null; _entities = null; _agent = null; _approaching = null; _activeDrones = null; _containers = null; _priorityTargets.ForEach(pt => pt.ClearCache()); _entitiesById.Clear(); }
/// <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); } } }
/// <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); }
/// <summary> /// Return the best possible target (based on current target, distance and low value first) /// </summary> /// <param name="currentTarget"></param> /// <param name="distance"></param> /// <param name="lowValueFirst"></param> /// <returns></returns> public EntityCache GetBestTarget(EntityCache currentTarget, double distance, bool lowValueFirst) { // Do we have a 'current target' and if so, is it an actual target? // If not, clear current target if (currentTarget != null && !currentTarget.IsTarget) { currentTarget = null; } // Is our current target a warp scrambling priority target? if (currentTarget != null && PriorityTargets.Any(pt => pt.Id == currentTarget.Id && pt.IsWarpScramblingMe && pt.IsTarget)) { return(currentTarget); } // Get the closest warp scrambling priority target var target = PriorityTargets.OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(pt => pt.Distance < distance && pt.IsWarpScramblingMe && pt.IsTarget); if (target != null) { return(target); } // Is our current target any other priority target? if (currentTarget != null && PriorityTargets.Any(pt => pt.Id == currentTarget.Id)) { return(currentTarget); } // Get the closest priority target target = PriorityTargets.OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(pt => pt.Distance < distance && pt.IsTarget); if (target != null) { return(target); } // Do we have a target? if (currentTarget != null) { return(currentTarget); } // Get all entity targets var targets = Targets.Where(e => e.CategoryId == (int)CategoryID.Entity && e.IsNpc && !e.IsContainer && e.GroupId != (int)Group.LargeCollidableStructure); // Get the closest high value target var highValueTarget = targets.Where(t => t.TargetValue.HasValue && t.Distance < distance).OrderByDescending(t => t.TargetValue.Value).ThenBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(); // Get the closest low value target var lowValueTarget = targets.Where(t => !t.TargetValue.HasValue && t.Distance < distance).OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(); if (Settings.Instance.DontShootFrigatesWithSiegeorAutoCannons) { if (Cache.Instance.MissionWeaponGroupId == 55 || Cache.Instance.MissionWeaponGroupId == 508) { if (lowValueTarget != null && !lowValueFirst && lowValueTarget.Distance > (int)Distance.InsideThisRangeIsLIkelyToBeMostlyFrigates) { return(targets.Where(t => !t.TargetValue.HasValue && t.Distance > (int)Distance.InsideThisRangeIsLIkelyToBeMostlyFrigates && t.Distance < distance).OrderByDescending(t => t.Distance).FirstOrDefault()); } if (lowValueTarget != null && !lowValueFirst && lowValueTarget.Distance < (int)Distance.InsideThisRangeIsLIkelyToBeMostlyFrigates) { lowValueTarget = null; } } } if (lowValueFirst && lowValueTarget != null) { return(lowValueTarget); } if (!lowValueFirst && highValueTarget != null) { return(highValueTarget); } // Return either one or the other return(lowValueTarget ?? highValueTarget); }
/// <summary> Activate StasisWeb /// </summary> public void ActivateStasisWeb(EntityCache target) { if (DateTime.Now < _nextWeaponAction) //if we just did something wait a fraction of a second return; var webs = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.StasisWeb).ToList(); // Find the first active weapon // Assist this weapon foreach (var web in webs) { // Are we on the right target? if (web.IsActive) { if (web.TargetId != target.Id) web.Deactivate(); continue; } // Are we deactivating? if (web.IsDeactivating) continue; // Target is out of web range if (target.Distance >= web.OptimalRange) continue; if (CanActivate(web, target, false)) { Logging.Log("Combat: Activating stasis web [" + web.ItemId + "] on [" + target.Name + "][ID: " + target.Id + "]"); web.Activate(target.Id); _nextWebAction = DateTime.Now.AddMilliseconds((int)Time.WebDelay_miliseconds); return; } } }
/// <summary> /// Return the best possible target (based on current target, distance and low value first) /// </summary> /// <param name="currentTarget"></param> /// <param name="distance"></param> /// <param name="lowValueFirst"></param> /// <returns></returns> public EntityCache GetBestTarget(EntityCache currentTarget, double distance, bool lowValueFirst) { // Do we have a 'current target' and if so, is it an actual target? // If not, clear current target if (currentTarget != null && !currentTarget.IsTarget) currentTarget = null; // Is our current target a warp scrambling priority target? if (currentTarget != null && PriorityTargets.Any(pt => pt.Id == currentTarget.Id && pt.IsWarpScramblingMe && pt.IsTarget)) return currentTarget; // Get the closest warp scrambling priority target var target = PriorityTargets.OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(pt => pt.Distance < distance && pt.IsWarpScramblingMe && pt.IsTarget); if (target != null) return target; // Is our current target any other priority target? if (currentTarget != null && PriorityTargets.Any(pt => pt.Id == currentTarget.Id)) return currentTarget; // Get the closest priority target target = PriorityTargets.OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(pt => pt.Distance < distance && pt.IsTarget); if (target != null) return target; // Do we have a target? if (currentTarget != null) return currentTarget; // Get all entity targets var targets = Targets.Where(e => e.CategoryId == (int)CategoryID.Entity && e.IsNpc && !e.IsContainer && e.GroupId != (int)Group.LargeCollidableStructure); // Get the closest high value target var highValueTarget = targets.Where(t => t.TargetValue.HasValue && t.Distance < distance).OrderByDescending(t => t.TargetValue.Value).ThenBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(); // Get the closest low value target var lowValueTarget = targets.Where(t => !t.TargetValue.HasValue && t.Distance < distance).OrderBy(OrderByLowestHealth()).ThenBy(t => t.Distance).FirstOrDefault(); if (Settings.Instance.DontShootFrigatesWithSiegeorAutoCannons) { if (Cache.Instance.MissionWeaponGroupId == 55 || Cache.Instance.MissionWeaponGroupId == 508) { if (lowValueTarget != null && !lowValueFirst && lowValueTarget.Distance > (int)Distance.InsideThisRangeIsLIkelyToBeMostlyFrigates) return targets.Where(t => !t.TargetValue.HasValue && t.Distance > (int)Distance.InsideThisRangeIsLIkelyToBeMostlyFrigates && t.Distance < distance).OrderByDescending(t => t.Distance).FirstOrDefault(); if (lowValueTarget != null && !lowValueFirst && lowValueTarget.Distance < (int)Distance.InsideThisRangeIsLIkelyToBeMostlyFrigates) lowValueTarget = null; } } if (lowValueFirst && lowValueTarget != null) return lowValueTarget; if (!lowValueFirst && highValueTarget != null) return highValueTarget; // Return either one or the other return lowValueTarget ?? highValueTarget; }
/// <summary> Activate target painters /// </summary> public void ActivateTargetPainters(EntityCache target) { if (DateTime.Now < _nextWeaponAction) //if we just did something wait a fraction of a second return; var targetPainters = Cache.Instance.Modules.Where(m => m.GroupId == (int)Group.TargetPainter).ToList(); // Find the first active weapon // Assist this weapon foreach (var painter in targetPainters) { // Are we on the right target? if (painter.IsActive) { if (painter.TargetId != target.Id) painter.Deactivate(); continue; } // Are we deactivating? if (painter.IsDeactivating) continue; if (CanActivate(painter, target, false)) { Logging.Log("Combat: Activating painter [" + painter.ItemId + "] on [" + target.Name + "][ID: " + target.Id + "][" + Math.Round(target.Distance/1000,0) + "k away]"); painter.Activate(target.Id); _nextPainterAction = DateTime.Now.AddMilliseconds((int)Time.PainterDelay_miliseconds); return; } } }