Questor.Modules.Combat.Drones.ProcessState C# (CSharp) Method

ProcessState() public static method

public static ProcessState ( ) : void
return void
        public static void ProcessState()
        {
            if (_nextDroneAction > DateTime.UtcNow || Settings.Instance.DebugDisableDrones) return;

            if (Settings.Instance.DebugDrones) Logging.Log("Drones.ProcessState", "Entering Drones.ProcessState", Logging.Debug);
            _nextDroneAction = DateTime.UtcNow.AddMilliseconds(800);

            if (Cache.Instance.InStation ||                             // There is really no combat in stations (yet)
                !Cache.Instance.InSpace ||                              // if we are not in space yet, wait...
                Cache.Instance.MyShipEntity == null ||   // What? No ship entity?
                Cache.Instance.ActiveShip.Entity.IsCloaked || // There is no combat when cloaked
                !Cache.Instance.UseDrones                               // if UseDrones is false
                )
            {
                _States.CurrentDroneState = DroneState.Idle;
                return;
            }

            if (Cache.Instance.MyShipEntity.IsShipWithNoDroneBay)
            {
                _States.CurrentDroneState = DroneState.Idle;
                return;
            }

            if ((!Cache.Instance.ActiveDrones.Any() && Cache.Instance.InWarp) || !Cache.Instance.EntitiesOnGrid.Any())
            {
                Cache.Instance.RemoveDronePriorityTargets(Cache.Instance.DronePriorityEntities.ToList());
                _States.CurrentDroneState = DroneState.Idle;
                return;
            }

            switch (_States.CurrentDroneState)
            {
                case DroneState.WaitingForTargets:

                    // Are we in the right state ?
                    if (Cache.Instance.ActiveDrones.Any())
                    {
                        // Apparently not, we have drones out, go into fight mode
                        _States.CurrentDroneState = DroneState.Fighting;
                        break;
                    }

                    if (Cache.Instance.Targets.Any() || Settings.Instance.DronesDontNeedTargetsBecauseWehaveThemSetOnAggressive)
                    {
                        // Should we launch drones?
                        bool launch = true;

                        // Always launch if we're scrambled
                        if (!Cache.Instance.PotentialCombatTargets.Any(pt => pt.IsWarpScramblingMe))
                        {
                            if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "Launch is [" + launch + "]", Logging.Debug);
                            launch &= Cache.Instance.UseDrones;
                            if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", " launch &= Cache.Instance.UseDrones; Launch is [" + launch + "]", Logging.Debug);
                            // Are we done with this mission pocket?
                            launch &= !Cache.Instance.IsMissionPocketDone;
                            if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "!Cache.Instance.IsMissionPocketDone; Launch is [" + launch + "]", Logging.Debug);
                            // If above minimums
                            launch &= Cache.Instance.ActiveShip.ShieldPercentage >= Settings.Instance.DroneMinimumShieldPct;
                            if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "ActiveShip.ShieldPercentage; Launch is [" + launch + "]", Logging.Debug);
                            launch &= Cache.Instance.ActiveShip.ArmorPercentage >= Settings.Instance.DroneMinimumArmorPct;
                            if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "ActiveShip.ArmorPercentage; Launch is [" + launch + "]", Logging.Debug);
                            launch &= Cache.Instance.ActiveShip.CapacitorPercentage >= Settings.Instance.DroneMinimumCapacitorPct;
                            if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "ActiveShip.CapacitorPercentage; Launch is [" + launch + "]", Logging.Debug);

                            // yes if there are targets to kill
                            launch &= (Cache.Instance.Aggressed.Count(e => e.Distance < Cache.Instance.MaxDroneRange && (!e.IsSentry || (e.IsSentry && Settings.Instance.KillSentries) || (e.IsSentry && e.IsEwarTarget) )) > 0 || Cache.Instance.Targets.Count(e => e.IsLargeCollidable) > 0);
                            if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "Cache.Instance.Aggressed.Count; Launch is [" + launch + "] MaxDroneRange [" + Cache.Instance.MaxDroneRange + "] DroneControlrange [" + Settings.Instance.DroneControlRange + "] TargetingRange [" + Cache.Instance.MaxTargetRange + "]", Logging.Debug);

                            if (_States.CurrentQuestorState != QuestorState.CombatMissionsBehavior)
                            {
                                launch &= Cache.Instance.EntitiesOnGrid.Count(e => !e.IsSentry && !e.IsBadIdea && e.CategoryId == (int)CategoryID.Entity && e.IsNpc && !e.IsContainer && !e.IsLargeCollidable && e.Distance < Cache.Instance.MaxDroneRange) > 0;
                                if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "Cache.Instance.Entities.Count; Launch is [" + launch + "]", Logging.Debug);
                            }

                            if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "Launch is [" + launch + "]", Logging.Debug);
                            // If drones get aggro'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.UtcNow)
                                {
                                    // 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
                                    if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "We are still in _lastRecall delay. Launch is [" + launch + "]", Logging.Debug);
                                    launch = false;
                                }
                            }
                            else // Drones have been out for more then 30s
                                _recallCount = 0;
                        }
                        if (Settings.Instance.DebugDrones) Logging.Log("Drones.WaitingForTargets", "Launch is [" + launch + "]", Logging.Debug);
                        if (launch)
                        {
                            // Reset launch tries
                            _launchTries = 0;
                            _lastLaunch = DateTime.UtcNow;
                            _States.CurrentDroneState = DroneState.Launch;
                        }
                    }
                    break;

                case DroneState.Launch:
                    if (Settings.Instance.DebugDrones) Logging.Log("Drones.Launch", "LaunchAllDrones", Logging.Debug);
                    // Launch all drones
                    Recall = false;
                    _launchTimeout = DateTime.UtcNow;
                    Cache.Instance.ActiveShip.LaunchAllDrones();
                    _States.CurrentDroneState = DroneState.Launching;
                    break;

                case DroneState.Launching:
                    if (Settings.Instance.DebugDrones) Logging.Log("Drones.Launching", "Entering Launching State...", Logging.Debug);
                    // We haven't launched anything yet, keep waiting
                    if (!Cache.Instance.ActiveDrones.Any())
                    {
                        if (Settings.Instance.DebugDrones) Logging.Log("Drones.Launching", "No Drones in space yet. waiting", Logging.Debug);
                        if (DateTime.UtcNow.Subtract(_launchTimeout).TotalSeconds > 10)
                        {
                            // Relaunch if tries < 5
                            if (_launchTries < 5)
                            {
                                _launchTries++;
                                _States.CurrentDroneState = DroneState.Launch;
                                break;
                            }

                            _States.CurrentDroneState = DroneState.OutOfDrones;
                        }
                        break;
                    }

                    // Are we done launching?
                    if (_lastDroneCount == Cache.Instance.ActiveDrones.Count())
                    {
                        Logging.Log("Drones", "[" + Cache.Instance.ActiveDrones.Count() + "] Drones Launched", Logging.Magenta);
                        _States.CurrentDroneState = DroneState.Fighting;
                    }
                    break;

                case DroneState.OutOfDrones:

                    if (Cache.Instance.UseDrones && Settings.Instance.CharacterMode == "CombatMissions" && _States.CurrentCombatMissionBehaviorState == CombatMissionsBehaviorState.ExecuteMission)
                    {
                        if (Statistics.Instance.OutOfDronesCount >= 3)
                        {
                            Logging.Log("Drones", "We are Out of Drones! AGAIN - Headed back to base to stay!", Logging.Red);
                            _States.CurrentCombatMissionBehaviorState = CombatMissionsBehaviorState.GotoBase;
                            Statistics.Instance.MissionCompletionErrors = 10; //this effectively will stop questor in station so we do not try to do this mission again, this needs human intervention if we have lots this many drones
                            Statistics.Instance.OutOfDronesCount++;
                        }

                        Logging.Log("Drones","We are Out of Drones! - Headed back to base to Re-Arm",Logging.Red);
                        _States.CurrentCombatMissionBehaviorState = CombatMissionsBehaviorState.GotoBase;
                        Statistics.Instance.OutOfDronesCount++;
                        return;
                    }

                    break;

                case DroneState.Fighting:
                    if (Settings.Instance.DebugDrones) Logging.Log("Drones.Fighting", "Should we recall our drones? This is a possible list of reasons why we should", Logging.Debug);

                    if (!Cache.Instance.ActiveDrones.Any())
                    {
                        Logging.Log("Drones", "Apparently we have lost all our drones", Logging.Orange);
                        Recall = true;
                    }
                    else
                    {
                        if (Cache.Instance.PotentialCombatTargets.Any(pt => pt.IsWarpScramblingMe))
                        {
                            EntityCache WarpScrambledBy = Cache.Instance.Targets.OrderBy(d => d.Distance).ThenByDescending(i => i.IsWarpScramblingMe).FirstOrDefault();
                            if (WarpScrambledBy != null && DateTime.UtcNow > _nextWarpScrambledWarning)
                            {
                                _nextWarpScrambledWarning = DateTime.UtcNow.AddSeconds(20);
                                Logging.Log("Drones", "We are scrambled by: [" + Logging.White + WarpScrambledBy.Name + Logging.Orange + "][" + Logging.White + Math.Round(WarpScrambledBy.Distance, 0) + Logging.Orange + "][" + Logging.White + WarpScrambledBy.Id + Logging.Orange + "]", Logging.Orange);
                                Recall = false;
                                WarpScrambled = true;
                            }
                        }
                        else
                        {
                            //Logging.Log("Drones: We are not warp scrambled at the moment...");
                            WarpScrambled = false;
                        }
                    }

                    if (!Recall)
                    {
                        // Are we done (for now) ?
                        if (
                            Cache.Instance.TargetedBy.Count(e => (!e.IsSentry || (e.IsSentry && Settings.Instance.KillSentries) || (e.IsSentry && e.IsEwarTarget))
                                                               && (e.IsNpc || e.IsNpcByGroupID)
                                                               && e.Distance < Cache.Instance.MaxDroneRange) == 0)
                        {
                            int TargtedByCount = 0;
                            if (Cache.Instance.TargetedBy.Any())
                            {
                                TargtedByCount = Cache.Instance.TargetedBy.Count();
                            }
                            Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones because no NPC is targeting us within [" + Cache.Instance.MaxDroneRange + "] DroneControlRange Is [" + Settings.Instance.DroneControlRange + "] Targeting Range Is [" + Cache.Instance.MaxTargetRange + "] We have [" + TargtedByCount + "] total things targeting us", Logging.Magenta);
                            Recall = true;
                        }

                        if (!Recall & (Cache.Instance.IsMissionPocketDone) && !WarpScrambled)
                        {
                            Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones because we are done with this pocket.", Logging.Magenta);
                            Recall = true;
                        }
                        else if (!Recall & (_shieldPctTotal > GetShieldPctTotal()))
                        {
                            Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones because drones have lost some shields! [Old: " +
                                        _shieldPctTotal.ToString("N2") + "][New: " + GetShieldPctTotal().ToString("N2") +
                                        "]", Logging.Magenta);
                            Recall = true;
                        }
                        else if (!Recall & (_armorPctTotal > GetArmorPctTotal()))
                        {
                            Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones because drones have lost some armor! [Old:" +
                                        _armorPctTotal.ToString("N2") + "][New: " + GetArmorPctTotal().ToString("N2") +
                                        "]", Logging.Magenta);
                            Recall = true;
                        }
                        else if (!Recall & (_structurePctTotal > GetStructurePctTotal()))
                        {
                            Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones because drones have lost some structure! [Old:" +
                                        _structurePctTotal.ToString("N2") + "][New: " +
                                        GetStructurePctTotal().ToString("N2") + "]", Logging.Magenta);
                            Recall = true;
                        }
                        else if (!Recall & (Cache.Instance.ActiveDrones.Count() < _lastDroneCount))
                        {
                            // Did we lose a drone? (this should be covered by total's as well though)
                            Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones because we have lost a drone! [Old:" + _lastDroneCount +
                                        "][New: " + Cache.Instance.ActiveDrones.Count() + "]", Logging.Orange);
                            Recall = true;
                        }
                        else if (!Recall)
                        {
                            // Default to long range recall
                            int lowShieldWarning = Settings.Instance.LongRangeDroneRecallShieldPct;
                            int lowArmorWarning = Settings.Instance.LongRangeDroneRecallArmorPct;
                            int lowCapWarning = Settings.Instance.LongRangeDroneRecallCapacitorPct;

                            if (Cache.Instance.ActiveDrones.Average(d => d.Distance) <
                                (Cache.Instance.MaxDroneRange / 2d))
                            {
                                lowShieldWarning = Settings.Instance.DroneRecallShieldPct;
                                lowArmorWarning = Settings.Instance.DroneRecallArmorPct;
                                lowCapWarning = Settings.Instance.DroneRecallCapacitorPct;
                            }

                            if (!Cache.Instance.Targets.Any() && !Settings.Instance.DronesDontNeedTargetsBecauseWehaveThemSetOnAggressive)
                            {
                                Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to [" + Cache.Instance.Targets.Count() + "] targets being locked. Locking [" + Cache.Instance.Targeting.Count() + "] targets atm", Logging.Orange);
                                Recall = true;
                            }

                            if (Cache.Instance.ActiveShip.ShieldPercentage < lowShieldWarning && !WarpScrambled)
                            {
                                Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to shield [" +
                                            Math.Round(Cache.Instance.ActiveShip.ShieldPercentage, 0) + "%] below [" +
                                            lowShieldWarning + "%] minimum", Logging.Orange);
                                Recall = true;
                            }
                            else if (Cache.Instance.ActiveShip.ArmorPercentage < lowArmorWarning && !WarpScrambled)
                            {
                                Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to armor [" +
                                            Math.Round(Cache.Instance.ActiveShip.ArmorPercentage, 0) + "%] below [" +
                                            lowArmorWarning + "%] minimum", Logging.Orange);
                                Recall = true;
                            }
                            else if (Cache.Instance.ActiveShip.CapacitorPercentage < lowCapWarning && !WarpScrambled)
                            {
                                Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to capacitor [" +
                                            Math.Round(Cache.Instance.ActiveShip.CapacitorPercentage, 0) + "%] below [" +
                                            lowCapWarning + "%] minimum", Logging.Orange);
                                Recall = true;
                            }
                            else if (_States.CurrentQuestorState == QuestorState.CombatMissionsBehavior && !WarpScrambled)
                            {
                                if (_States.CurrentCombatMissionBehaviorState == CombatMissionsBehaviorState.GotoBase && !WarpScrambled)
                                {
                                    Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to gotobase state", Logging.Orange);
                                    Recall = true;
                                }
                                else if (_States.CurrentCombatMissionBehaviorState == CombatMissionsBehaviorState.GotoMission && !WarpScrambled)
                                {
                                    Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to gotomission state", Logging.Orange);
                                    Recall = true;
                                }
                                else if (_States.CurrentCombatMissionBehaviorState == CombatMissionsBehaviorState.Panic && !WarpScrambled)
                                {
                                    Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to panic state", Logging.Orange);
                                    Recall = true;
                                }
                            }
                            else if (_States.CurrentQuestorState == QuestorState.CombatHelperBehavior && !WarpScrambled)
                            {
                                if (_States.CurrentCombatHelperBehaviorState == CombatHelperBehaviorState.Panic && !WarpScrambled)
                                {
                                    Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to panic state", Logging.Orange);
                                    Recall = true;
                                }
                                else if (_States.CurrentCombatHelperBehaviorState == CombatHelperBehaviorState.GotoBase && !WarpScrambled)
                                {
                                    Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to panic state", Logging.Orange);
                                    Recall = true;
                                }
                            }
                            else if (_States.CurrentQuestorState == QuestorState.DedicatedBookmarkSalvagerBehavior && !WarpScrambled)
                            {
                                if (_States.CurrentDedicatedBookmarkSalvagerBehaviorState == DedicatedBookmarkSalvagerBehaviorState.GotoBase && !WarpScrambled)
                                {
                                    Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to gotobase state", Logging.Orange);
                                    Recall = true;
                                }
                                else if (_States.CurrentDedicatedBookmarkSalvagerBehaviorState == DedicatedBookmarkSalvagerBehaviorState.Panic && !WarpScrambled)
                                {
                                    Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to panic state", Logging.Orange);
                                    Recall = true;
                                }
                                else if (_States.CurrentDedicatedBookmarkSalvagerBehaviorState == DedicatedBookmarkSalvagerBehaviorState.GotoNearestStation && !WarpScrambled)
                                {
                                    Logging.Log("Drones", "Recalling [ " + Cache.Instance.ActiveDrones.Count() + " ] drones due to GotoNearestStation state", Logging.Orange);
                                    Recall = true;
                                }
                            }
                        }
                    }

                    // Recall or engage
                    if (Recall)
                    {
                        Statistics.Instance.DroneRecalls++;
                        _States.CurrentDroneState = DroneState.Recalling;
                    }
                    else
                    {
                        if (Settings.Instance.DebugDrones) Logging.Log("Drones.Fighting", "EngageTarget(); - before", Logging.Debug);

                        EngageTarget();

                        if (Settings.Instance.DebugDrones) Logging.Log("Drones.Fighting", "EngageTarget(); - after", Logging.Debug);
                        // We lost a drone and did not recall, assume panicking and launch (if any) additional drones
                        if (Cache.Instance.ActiveDrones.Count() < _lastDroneCount)
                        {
                            _States.CurrentDroneState = DroneState.Launch;
                        }
                    }
                    break;

                case DroneState.Recalling:

                    // Are we done?
                    if (!Cache.Instance.ActiveDrones.Any())
                    {
                        _lastRecall = DateTime.UtcNow;
                        Recall = false;
                        _nextDroneAction = DateTime.UtcNow.AddSeconds(3);
                        _States.CurrentDroneState = DroneState.WaitingForTargets;
                        break;
                    }

                    // Give recall command every x seconds (default is 15)
                    if (DateTime.UtcNow.Subtract(_lastRecallCommand).TotalSeconds > Time.Instance.RecallDronesDelayBetweenRetries + Cache.Instance.RandomNumber(0,2))
                    {
                        Cache.Instance.DirectEve.ExecuteCommand(DirectCmd.CmdDronesReturnToBay);
                        _lastRecallCommand = DateTime.UtcNow;
                    }
                    break;

                case DroneState.Idle:

                    //
                    // below is the reasons we will start the combat state(s) - if the below is not met do nothing
                    //
                    if (Cache.Instance.InSpace &&
                        Cache.Instance.ActiveShip.Entity != null &&
                        !Cache.Instance.ActiveShip.Entity.IsCloaked &&
                        Cache.Instance.ActiveShip.GivenName.ToLower() != Settings.Instance.CombatShipName &&
                        Cache.Instance.UseDrones &&
                        !Cache.Instance.InWarp)
                    {
                        _States.CurrentDroneState = DroneState.WaitingForTargets;
                        return;
                    }

                    break;
            }

            // Update health values
            _shieldPctTotal = GetShieldPctTotal();
            _armorPctTotal = GetArmorPctTotal();
            _structurePctTotal = GetStructurePctTotal();
            _lastDroneCount = Cache.Instance.ActiveDrones.Count();
            GetDamagedDrones();
        }