void UpdateCommandDecision(float timeSinceLastUpdate) { #if DEBUG ShipCommandLog("Updating command for character " + character); #endif shipGlobalIssues.ForEach(c => c.CalculateGlobalIssue()); AlliedCharacters.Clear(); EnemyCharacters.Clear(); bool isEmergency = false; foreach (Character potentialCharacter in Character.CharacterList) { if (!HumanAIController.IsActive(character)) { continue; } if (HumanAIController.IsFriendly(character, potentialCharacter, true) && potentialCharacter.AIController is HumanAIController) { if (AbleToTakeOrder(potentialCharacter)) { AlliedCharacters.Add(potentialCharacter); } } else { EnemyCharacters.Add(potentialCharacter); if (potentialCharacter.Submarine == CommandedSubmarine) // if enemies are on board, don't issue normal orders anymore { isEmergency = true; } } } attendedIssues.Clear(); availableIssues.Clear(); foreach (ShipIssueWorker shipIssueWorker in ShipIssueWorkers) { float importance = shipIssueWorker.CalculateImportance(isEmergency); if (shipIssueWorker.OrderAttendedTo(timeSinceLastUpdate)) { #if DEBUG ShipCommandLog("Current importance for " + shipIssueWorker + " was " + importance + " and it was already being attended by " + shipIssueWorker.OrderedCharacter); #endif attendedIssues.Add(shipIssueWorker); } else { #if DEBUG ShipCommandLog("Current importance for " + shipIssueWorker + " was " + importance + " and it is not attended to"); #endif shipIssueWorker.RemoveOrder(); availableIssues.Add(shipIssueWorker); } } availableIssues.Sort((x, y) => y.Importance.CompareTo(x.Importance)); attendedIssues.Sort((x, y) => x.Importance.CompareTo(y.Importance)); ShipIssueWorker mostImportantIssue = availableIssues.FirstOrDefault(); float bestValue = 0f; Character bestCharacter = null; if (mostImportantIssue != null && mostImportantIssue.Importance > MinimumIssueThreshold) { IEnumerable <Character> bestCharacters = CrewManager.GetCharactersSortedForOrder(mostImportantIssue.SuggestedOrderPrefab, AlliedCharacters, character, true); foreach (Character orderedCharacter in bestCharacters) { float issueApplicability = mostImportantIssue.Importance; // prefer not to switch if not qualified issueApplicability *= mostImportantIssue.SuggestedOrderPrefab.AppropriateJobs.Contains(orderedCharacter.Info.Job.Prefab.Identifier) ? 1f : 0.75f; ShipIssueWorker occupiedIssue = attendedIssues.FirstOrDefault(i => i.OrderedCharacter == orderedCharacter); if (occupiedIssue != null) { if (occupiedIssue.GetType() == mostImportantIssue.GetType() && mostImportantIssue is ShipIssueWorkerGlobal && occupiedIssue is ShipIssueWorkerGlobal) { continue; } // reverse redundancy to ensure certain issues can be switched over easily (operating weapons) if (mostImportantIssue.AllowEasySwitching && occupiedIssue.AllowEasySwitching) { issueApplicability /= mostImportantIssue.CurrentRedundancy; } // give slight preference if not qualified for current job issueApplicability += occupiedIssue.SuggestedOrderPrefab.AppropriateJobs.Contains(orderedCharacter.Info.Job.Prefab.Identifier) ? 0 : 7.5f; // prefer not to switch orders unless considerably more important issueApplicability -= IssueDevotionBuffer; if (issueApplicability + IssueDevotionBuffer < occupiedIssue.Importance) { continue; } } // prefer first one in bestCharacters in tiebreakers if (issueApplicability > bestValue) { bestValue = issueApplicability; bestCharacter = orderedCharacter; } } } if (bestCharacter != null && mostImportantIssue != null) { #if DEBUG ShipCommandLog("Setting " + mostImportantIssue + " for character " + bestCharacter); #endif mostImportantIssue.SetOrder(bestCharacter); } else // if we didn't give an order, let's try to dismiss someone instead { foreach (ShipIssueWorker shipIssueWorker in ShipIssueWorkers) { if (shipIssueWorker.Importance <= 0f && shipIssueWorker.OrderAttendedTo()) { #if DEBUG ShipCommandLog("Dismissing " + shipIssueWorker + " for character " + shipIssueWorker.OrderedCharacter); #endif Order orderPrefab = Order.GetPrefab("dismissed"); character.Speak(orderPrefab.GetChatMessage(shipIssueWorker.OrderedCharacter.Name, "", givingOrderToSelf: false)); shipIssueWorker.OrderedCharacter.SetOrder(Order.GetPrefab("dismissed"), orderOption: null, priority: 3, character); shipIssueWorker.RemoveOrder(); break; } } } }