public void SetOrder(Order order, string option, Character orderGiver, bool speak)
        {
            if (character.IsDead)
            {
#if DEBUG
                DebugConsole.ThrowError("Attempted to set an order for a dead character");
#else
                return;
#endif
            }
            ClearIgnored();
            CurrentOrder = CreateObjective(order, option, orderGiver, isAutonomous: false);
            if (CurrentOrder == null)
            {
                // Recreate objectives, because some of them may be removed, if impossible to complete (e.g. due to path finding)
                CreateAutonomousObjectives();
            }
            else
            {
                // This should be redundant, because all the objectives are reset when they are selected as active.
                CurrentOrder.Reset();
                if (speak)
                {
                    character.Speak(TextManager.Get("DialogAffirmative"), null, 1.0f);
                    if (speakRoutine != null)
                    {
                        CoroutineManager.StopCoroutines(speakRoutine);
                    }
                    speakRoutine = CoroutineManager.InvokeAfter(() =>
                    {
                        if (GameMain.GameSession == null || Level.Loaded == null)
                        {
                            return;
                        }
                        if (CurrentOrder != null && character.SpeechImpediment < 100.0f)
                        {
                            if (CurrentOrder is AIObjectiveRepairItems repairItems && repairItems.Targets.None())
                            {
                                character.Speak(TextManager.Get("DialogNoRepairTargets"), null, 3.0f, "norepairtargets");
                            }
                            else if (CurrentOrder is AIObjectiveChargeBatteries chargeBatteries && chargeBatteries.Targets.None())
                            {
                                character.Speak(TextManager.Get("DialogNoBatteries"), null, 3.0f, "nobatteries");
                            }
                            else if (CurrentOrder is AIObjectiveExtinguishFires extinguishFires && extinguishFires.Targets.None())
                            {
                                character.Speak(TextManager.Get("DialogNoFire"), null, 3.0f, "nofire");
                            }
예제 #2
0
        public bool CreateCombatBehavior(MentalType mentalType)
        {
            Character mentalAttackTarget = Character.CharacterList.Where(
                possibleTarget => HumanAIController.IsActive(possibleTarget) &&
                (possibleTarget.TeamID != character.TeamID || mentalType == MentalType.Berserk) &&
                humanAIController.VisibleHulls.Contains(possibleTarget.CurrentHull) &&
                possibleTarget != character).GetRandom();

            if (mentalAttackTarget == null)
            {
                return(false);
            }

            var  combatMode = AIObjectiveCombat.CombatMode.None;
            bool holdFire   = mentalType == MentalType.Afraid && character.IsSecurity;

            switch (mentalType)
            {
            case MentalType.Afraid:
                combatMode = character.IsSecurity ? AIObjectiveCombat.CombatMode.Arrest : AIObjectiveCombat.CombatMode.Retreat;
                break;

            case MentalType.Desperate:
                // might be unnecessary to explicitly declare as arrest against non-humans
                combatMode = character.IsSecurity && mentalAttackTarget.IsHuman ? AIObjectiveCombat.CombatMode.Arrest : AIObjectiveCombat.CombatMode.Defensive;
                break;

            case MentalType.Berserk:
                combatMode = AIObjectiveCombat.CombatMode.Offensive;
                break;
            }

            // using this as an explicit time-out for the behavior. it's possible it will never run out because of the manager being disabled, but combat objective has failsafes for that
            mentalBehaviorTimer = MentalBehaviorInterval;
            humanAIController.AddCombatObjective(combatMode, mentalAttackTarget, allowHoldFire: holdFire, abortCondition: obj => mentalBehaviorTimer <= 0f);
            string textIdentifier = $"dialogmentalstatereaction{combatMode.ToString().ToLowerInvariant()}";

            character.Speak(TextManager.Get(textIdentifier), delay: Rand.Range(0.5f, 1.0f), identifier: textIdentifier, minDurationBetweenSimilar: 25f);

            if (mentalType == MentalType.Berserk && !character.HasTeamChange(MentalTeamChange))
            {
                // TODO: could this be handled in the switch block above?
                character.TryAddNewTeamChange(MentalTeamChange, new ActiveTeamChange(CharacterTeamType.None, ActiveTeamChange.TeamChangePriorities.Absolute, aggressiveBehavior: true));
            }

            return(true);
        }
        public void SetOrder(Order order, string option, Character orderGiver, bool speak = true)
        {
            CurrentOrderOption = option;
            CurrentOrder       = order;
            objectiveManager.SetOrder(order, option, orderGiver);
            if (speak && Character.SpeechImpediment < 100.0f)
            {
                Character.Speak(TextManager.Get("DialogAffirmative"), null, 1.0f);
            }

            SetOrderProjSpecific(order);
        }
예제 #4
0
 public void SetOrder(Order order, string option, Character orderGiver, bool speak = true)
 {
     CurrentOrderOption = option;
     CurrentOrder       = order;
     objectiveManager.SetOrder(order, option, orderGiver);
     if (ObjectiveManager.CurrentOrder != null && speak && Character.SpeechImpediment < 100.0f)
     {
         if (ObjectiveManager.CurrentOrder is AIObjectiveRepairItems repairItems && repairItems.Targets.None())
         {
             Character.Speak(TextManager.Get("DialogNoRepairTargets"), null, 3.0f, "norepairtargets");
         }
         else if (ObjectiveManager.CurrentOrder is AIObjectiveChargeBatteries chargeBatteries && chargeBatteries.Targets.None())
         {
             Character.Speak(TextManager.Get("DialogNoBatteries"), null, 3.0f, "nobatteries");
         }
예제 #5
0
        private void UpdateSpeaking()
        {
            if (Character.Oxygen < 20.0f)
            {
                Character.Speak(TextManager.Get("DialogLowOxygen"), null, 0, "lowoxygen", 30.0f);
            }

            if (Character.Bleeding > 2.0f)
            {
                Character.Speak(TextManager.Get("DialogBleeding"), null, 0, "bleeding", 30.0f);
            }

            if (Character.PressureTimer > 50.0f && Character.CurrentHull != null)
            {
                Character.Speak(TextManager.GetWithVariable("DialogPressure", "[roomname]", Character.CurrentHull.DisplayName, true), null, 0, "pressure", 30.0f);
            }
        }
        protected void ReportProblems()
        {
            Order newOrder = null;

            if (Character.CurrentHull != null)
            {
                if (Character.CurrentHull.FireSources.Count > 0)
                {
                    var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportfire");
                    newOrder = new Order(orderPrefab, Character.CurrentHull, null);
                }

                if (Character.CurrentHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.ConnectedDoor == null && g.Open > 0.0f))
                {
                    var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach");
                    newOrder = new Order(orderPrefab, Character.CurrentHull, null);
                }

                foreach (Character c in Character.CharacterList)
                {
                    if (c.CurrentHull == Character.CurrentHull && !c.IsDead &&
                        (c.AIController is EnemyAIController || (c.TeamID != Character.TeamID && Character.TeamID != Character.TeamType.FriendlyNPC && c.TeamID != Character.TeamType.FriendlyNPC)))
                    {
                        var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportintruders");
                        newOrder = new Order(orderPrefab, Character.CurrentHull, null);
                    }
                }
            }

            if (Character.CurrentHull != null && (Character.Bleeding > 1.0f || Character.Vitality < Character.MaxVitality * 0.1f))
            {
                var orderPrefab = Order.PrefabList.Find(o => o.AITag == "requestfirstaid");
                newOrder = new Order(orderPrefab, Character.CurrentHull, null);
            }

            if (newOrder != null)
            {
                if (GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime))
                {
                    Character.Speak(
                        newOrder.GetChatMessage("", Character.CurrentHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order);
                }
            }
        }
예제 #7
0
        public void SetOrder(Order order, string option, int priority, Character orderGiver, bool speak)
        {
            if (character.IsDead)
            {
#if DEBUG
                DebugConsole.ThrowError("Attempted to set an order for a dead character");
#else
                return;
#endif
            }
            ClearIgnored();

            if (order == null || order.Identifier == "dismissed")
            {
                if (!string.IsNullOrEmpty(option))
                {
                    if (CurrentOrders.Any(o => o.MatchesDismissedOrder(option)))
                    {
                        var dismissedOrderInfo = CurrentOrders.First(o => o.MatchesDismissedOrder(option));
                        CurrentOrders.Remove(dismissedOrderInfo);
                    }
                }
                else
                {
                    CurrentOrders.Clear();
                }
            }

            // Make sure the order priorities reflect those set by the player
            for (int i = CurrentOrders.Count - 1; i >= 0; i--)
            {
                var currentOrder = CurrentOrders[i];
                if (currentOrder.Objective == null || currentOrder.MatchesOrder(order, option))
                {
                    CurrentOrders.RemoveAt(i);
                    continue;
                }
                var currentOrderInfo = character.GetCurrentOrder(currentOrder.Order, currentOrder.OrderOption);
                if (currentOrderInfo.HasValue)
                {
                    int currentPriority = currentOrderInfo.Value.ManualPriority;
                    if (currentOrder.ManualPriority != currentPriority)
                    {
                        CurrentOrders[i] = new OrderInfo(currentOrder, currentPriority);
                    }
                }
                else
                {
                    CurrentOrders.RemoveAt(i);
                }
            }

            var newCurrentOrder = CreateObjective(order, option, orderGiver, isAutonomous: false);
            if (newCurrentOrder != null)
            {
                CurrentOrders.Add(new OrderInfo(order, option, priority, newCurrentOrder));
            }
            if (!HasOrders())
            {
                // Recreate objectives, because some of them may be removed, if impossible to complete (e.g. due to path finding)
                CreateAutonomousObjectives();
            }
            else
            {
                // This should be redundant, because all the objectives are reset when they are selected as active.
                newCurrentOrder?.Reset();

                if (speak && character.IsOnPlayerTeam)
                {
                    character.Speak(TextManager.Get("DialogAffirmative"), null, 1.0f);
                    //if (speakRoutine != null)
                    //{
                    //    CoroutineManager.StopCoroutines(speakRoutine);
                    //}
                    //speakRoutine = CoroutineManager.InvokeAfter(() =>
                    //{
                    //    if (GameMain.GameSession == null || Level.Loaded == null) { return; }
                    //    if (newCurrentOrder != null && character.SpeechImpediment < 100.0f)
                    //    {
                    //        if (newCurrentOrder is AIObjectiveRepairItems repairItems && repairItems.Targets.None())
                    //        {
                    //            character.Speak(TextManager.Get("DialogNoRepairTargets"), null, 3.0f, "norepairtargets");
                    //        }
                    //        else if (newCurrentOrder is AIObjectiveChargeBatteries chargeBatteries && chargeBatteries.Targets.None())
                    //        {
                    //            character.Speak(TextManager.Get("DialogNoBatteries"), null, 3.0f, "nobatteries");
                    //        }
                    //        else if (newCurrentOrder is AIObjectiveExtinguishFires extinguishFires && extinguishFires.Targets.None())
                    //        {
                    //            character.Speak(TextManager.Get("DialogNoFire"), null, 3.0f, "nofire");
                    //        }
                    //        else if (newCurrentOrder is AIObjectiveFixLeaks fixLeaks && fixLeaks.Targets.None())
                    //        {
                    //            character.Speak(TextManager.Get("DialogNoLeaks"), null, 3.0f, "noleaks");
                    //        }
                    //        else if (newCurrentOrder is AIObjectiveFightIntruders fightIntruders && fightIntruders.Targets.None())
                    //        {
                    //            character.Speak(TextManager.Get("DialogNoEnemies"), null, 3.0f, "noenemies");
                    //        }
                    //        else if (newCurrentOrder is AIObjectiveRescueAll rescueAll && rescueAll.Targets.None())
                    //        {
                    //            character.Speak(TextManager.Get("DialogNoRescueTargets"), null, 3.0f, "norescuetargets");
                    //        }
                    //        else if (newCurrentOrder is AIObjectivePumpWater pumpWater && pumpWater.Targets.None())
                    //        {
                    //            character.Speak(TextManager.Get("DialogNoPumps"), null, 3.0f, "nopumps");
                    //        }
                    //    }
                    //}, 3);
                }
            }
        }
예제 #8
0
        protected void ReportProblems()
        {
            Order newOrder = null;

            if (Character.CurrentHull != null)
            {
                foreach (var hull in VisibleHulls)
                {
                    foreach (Character c in Character.CharacterList)
                    {
                        if (c.CurrentHull != hull)
                        {
                            continue;
                        }
                        if (AIObjectiveFightIntruders.IsValidTarget(c, Character))
                        {
                            AddTargets <AIObjectiveFightIntruders, Character>(Character, c);
                            if (newOrder == null)
                            {
                                var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportintruders");
                                newOrder = new Order(orderPrefab, c.CurrentHull, null, orderGiver: Character);
                            }
                        }
                    }
                    if (AIObjectiveExtinguishFires.IsValidTarget(hull, Character))
                    {
                        AddTargets <AIObjectiveExtinguishFires, Hull>(Character, hull);
                        if (newOrder == null)
                        {
                            var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportfire");
                            newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
                        }
                    }
                    foreach (Character c in Character.CharacterList)
                    {
                        if (c.CurrentHull != hull)
                        {
                            continue;
                        }
                        if (AIObjectiveRescueAll.IsValidTarget(c, Character))
                        {
                            if (AddTargets <AIObjectiveRescueAll, Character>(c, Character))
                            {
                                if (newOrder == null)
                                {
                                    var orderPrefab = Order.PrefabList.Find(o => o.AITag == "requestfirstaid");
                                    newOrder = new Order(orderPrefab, c.CurrentHull, null, orderGiver: Character);
                                }
                            }
                        }
                    }
                    foreach (var gap in hull.ConnectedGaps)
                    {
                        if (AIObjectiveFixLeaks.IsValidTarget(gap, Character))
                        {
                            AddTargets <AIObjectiveFixLeaks, Gap>(Character, gap);
                            if (newOrder == null && !gap.IsRoomToRoom)
                            {
                                var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach");
                                newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
                            }
                        }
                    }
                    foreach (Item item in Item.ItemList)
                    {
                        if (item.CurrentHull != hull)
                        {
                            continue;
                        }
                        if (AIObjectiveRepairItems.IsValidTarget(item, Character))
                        {
                            if (item.Repairables.All(r => item.Condition > r.ShowRepairUIThreshold))
                            {
                                continue;
                            }
                            AddTargets <AIObjectiveRepairItems, Item>(Character, item);
                            if (newOrder == null)
                            {
                                var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbrokendevices");
                                newOrder = new Order(orderPrefab, item.CurrentHull, item.Repairables?.FirstOrDefault(), orderGiver: Character);
                            }
                        }
                    }
                }
            }
            if (newOrder != null)
            {
                if (GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime))
                {
                    Character.Speak(newOrder.GetChatMessage("", Character.CurrentHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order);
#if SERVER
                    GameMain.Server.SendOrderChatMessage(new OrderChatMessage(newOrder, "", Character.CurrentHull, null, Character));
#endif
                }
            }
        }
예제 #9
0
        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;
                    }
                }
            }
        }