Beispiel #1
0
        public bool OrderAttendedTo(float timeSinceLastCheck = 0f)
        {
            if (!HumanAIController.IsActive(OrderedCharacter))
            {
                return(false);
            }

            // accept only the highest priority order
            if (CurrentOrder != null && OrderedCharacter.GetCurrentOrderWithTopPriority()?.Order != CurrentOrder)
            {
#if DEBUG
                ShipCommandManager.ShipCommandLog($"Order {CurrentOrder.Name} did not match current order for character {OrderedCharacter} in {this}");
#endif
                return(false);
            }

            if (!shipCommandManager.AbleToTakeOrder(OrderedCharacter))
            {
#if DEBUG
                ShipCommandManager.ShipCommandLog(OrderedCharacter + " was unable to perform assigned order in " + this);
#endif
                return(false);
            }
            return(true);
        }
Beispiel #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 override float GetPriority()
        {
            if (!IsAllowed)
            {
                Priority = 0;
                Abandon  = true;
                return(Priority);
            }
            bool isOrder = objectiveManager.HasOrder <AIObjectiveExtinguishFires>();

            if (!isOrder && Character.CharacterList.Any(c => c.CurrentHull == targetHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
            {
                // Don't go into rooms with any enemies, unless it's an order
                Priority = 0;
                Abandon  = true;
            }
            else
            {
                float yDist = Math.Abs(character.WorldPosition.Y - targetHull.WorldPosition.Y);
                yDist = yDist > 100 ? yDist * 3 : 0;
                float dist           = Math.Abs(character.WorldPosition.X - targetHull.WorldPosition.X) + yDist;
                float distanceFactor = MathHelper.Lerp(1, 0.1f, MathUtils.InverseLerp(0, 5000, dist));
                if (targetHull == character.CurrentHull || HumanAIController.VisibleHulls.Contains(targetHull))
                {
                    distanceFactor = 1;
                }
                float severity = AIObjectiveExtinguishFires.GetFireSeverity(targetHull);
                if (severity > 0.5f && !isOrder)
                {
                    // Ignore severe fires unless ordered. (Let the fire drain all the oxygen instead).
                    Priority = 0;
                    Abandon  = true;
                }
                else
                {
                    float devotion = CumulatedDevotion / 100;
                    Priority = MathHelper.Lerp(0, 100, MathHelper.Clamp(devotion + (severity * distanceFactor * PriorityModifier), 0, 1));
                }
            }
            return(Priority);
        }
        protected override bool Check()
        {
            if (character.LockHands || targetCharacter == null || targetCharacter.CurrentHull == null || targetCharacter.Removed || targetCharacter.IsDead)
            {
                Abandon = true;
                return(false);
            }
            // Don't go into rooms that have enemies
            if (Character.CharacterList.Any(c => c.CurrentHull == targetCharacter.CurrentHull && !HumanAIController.IsFriendly(character, c) && HumanAIController.IsActive(c)))
            {
                Abandon = true;
                return(false);
            }
            bool isCompleted = AIObjectiveRescueAll.GetVitalityFactor(targetCharacter) >= AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager, character, targetCharacter);

            if (isCompleted && targetCharacter != character)
            {
                character.Speak(TextManager.GetWithVariable("DialogTargetHealed", "[targetname]", targetCharacter.Name),
                                null, 1.0f, "targethealed" + targetCharacter.Name, 60.0f);
            }
            return(isCompleted);
        }
Beispiel #5
0
        public override float GetPriority()
        {
            if (!objectiveManager.IsCurrentOrder <AIObjectiveExtinguishFires>() &&
                Character.CharacterList.Any(c => c.CurrentHull == targetHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
            {
                return(0);
            }
            float yDist = Math.Abs(character.WorldPosition.Y - targetHull.WorldPosition.Y);

            yDist = yDist > 100 ? yDist * 3 : 0;
            float dist           = Math.Abs(character.WorldPosition.X - targetHull.WorldPosition.X) + yDist;
            float distanceFactor = MathHelper.Lerp(1, 0.1f, MathUtils.InverseLerp(0, 5000, dist));

            if (targetHull == character.CurrentHull)
            {
                distanceFactor = 1;
            }
            float severity       = AIObjectiveExtinguishFires.GetFireSeverity(targetHull);
            float severityFactor = MathHelper.Lerp(0, 1, severity / 100);
            float devotion       = Math.Min(Priority, 10) / 100;

            return(MathHelper.Lerp(0, 100, MathHelper.Clamp(devotion + severityFactor * distanceFactor, 0, 1)));
        }
Beispiel #6
0
 protected override bool Filter(Item item)
 {
     if (!IsValidTarget(item, character))
     {
         return(false);
     }
     if (item.CurrentHull.FireSources.Count > 0)
     {
         return(false);
     }
     // Don't repair items in rooms that have enemies inside.
     if (Character.CharacterList.Any(c => c.CurrentHull == item.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
     {
         return(false);
     }
     if (!Objectives.ContainsKey(item))
     {
         if (item.Repairables.All(r => item.ConditionPercentage > r.ShowRepairUIThreshold))
         {
             return(false);
         }
     }
     if (RequireAdequateSkills)
     {
         if (item.Repairables.Any(r => !r.HasRequiredSkills(character)))
         {
             return(false);
         }
     }
     return(true);
 }
 protected override bool Filter(Item target)
 {
     // If the target was selected as a valid target, we'll have to accept it so that the objective can be completed.
     // The validity changes when a character picks the item up.
     if (!IsValidTarget(target, character, checkInventory: true))
     {
         return(Objectives.ContainsKey(target) && IsItemInsideValidSubmarine(target, character));
     }
     if (target.CurrentHull.FireSources.Count > 0)
     {
         return(false);
     }
     // Don't repair items in rooms that have enemies inside.
     if (Character.CharacterList.Any(c => c.CurrentHull == target.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
     {
         return(false);
     }
     return(true);
 }
        public override float GetPriority()
        {
            bool isOrder = objectiveManager.CurrentOrder == this;

            if (!IsAllowed || character.LockHands)
            {
                Priority = 0;
                Abandon  = !isOrder;
                return(Priority);
            }
            if (component.Item.ConditionPercentage <= 0)
            {
                Priority = 0;
            }
            else
            {
                if (isOrder)
                {
                    Priority = AIObjectiveManager.OrderPriority;
                }
                ItemComponent target     = GetTarget();
                Item          targetItem = target?.Item;
                if (targetItem == null)
                {
#if DEBUG
                    DebugConsole.ThrowError("Item or component of AI Objective Operate item was null. This shouldn't happen.");
#endif
                    Abandon  = true;
                    Priority = 0;
                    return(Priority);
                }
                var reactor = component?.Item.GetComponent <Reactor>();
                if (reactor != null)
                {
                    if (!isOrder)
                    {
                        if (reactor.LastUserWasPlayer && character.TeamID != CharacterTeamType.FriendlyNPC ||
                            HumanAIController.IsTrueForAnyCrewMember(c =>
                                                                     c.ObjectiveManager.CurrentOrder is AIObjectiveOperateItem operateOrder && operateOrder.GetTarget() == target))
                        {
                            Priority = 0;
                            return(Priority);
                        }
                    }
                    switch (Option)
                    {
                    case "shutdown":
                        if (!reactor.PowerOn)
                        {
                            Priority = 0;
                            return(Priority);
                        }
                        break;

                    case "powerup":
                        // Check that we don't already have another order that is targeting the same item.
                        // Without this the autonomous objective will tell the bot to turn the reactor on again.
                        if (objectiveManager.CurrentOrder is AIObjectiveOperateItem operateOrder && operateOrder != this && operateOrder.GetTarget() == target && operateOrder.Option != Option)
                        {
                            Priority = 0;
                            return(Priority);
                        }
                        break;
                    }
                }
                if (targetItem.CurrentHull == null ||
                    targetItem.Submarine != character.Submarine && !isOrder ||
                    targetItem.CurrentHull.FireSources.Any() ||
                    HumanAIController.IsItemOperatedByAnother(target, out _) ||
                    Character.CharacterList.Any(c => c.CurrentHull == targetItem.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)) ||
                    component.Item.IgnoreByAI || (useController && controller.Item.IgnoreByAI))
                {
                    Priority = 0;
                }
                else
                {
                    float value = CumulatedDevotion + (AIObjectiveManager.OrderPriority * PriorityModifier);
                    float max   = isOrder ? MathHelper.Min(AIObjectiveManager.OrderPriority, 90) : AIObjectiveManager.RunPriority - 1;
                    if (!isOrder && reactor != null && reactor.PowerOn && Option == "powerup")
                    {
                        // Decrease the priority when targeting a reactor that is already on.
                        value /= 2;
                    }
                    Priority = MathHelper.Clamp(value, 0, max);
                }
            }
            return(Priority);
        }
 protected override bool Filter(Item item)
 {
     if (!IsValidTarget(item, character))
     {
         return(false);
     }
     if (item.CurrentHull.FireSources.Count > 0)
     {
         return(false);
     }
     // Don't repair items in rooms that have enemies inside.
     if (Character.CharacterList.Any(c => c.CurrentHull == item.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
     {
         return(false);
     }
     if (!Objectives.ContainsKey(item))
     {
         if (item != character.SelectedConstruction)
         {
             float condition = item.ConditionPercentage;
             if (item.Repairables.All(r => condition >= r.RepairThreshold))
             {
                 return(false);
             }
         }
     }
     if (!string.IsNullOrWhiteSpace(RelevantSkill))
     {
         if (item.Repairables.None(r => r.requiredSkills.Any(s => s.Identifier.Equals(RelevantSkill, StringComparison.OrdinalIgnoreCase))))
         {
             return(false);
         }
     }
     return(true);
 }
Beispiel #10
0
 public static bool IsValidTarget(Character target, Character character)
 {
     if (target == null || target.IsDead || target.Removed)
     {
         return(false);
     }
     if (!HumanAIController.IsFriendly(character, target))
     {
         return(false);
     }
     if (character.AIController is HumanAIController humanAI)
     {
         if (GetVitalityFactor(target) > GetVitalityThreshold(humanAI.ObjectiveManager))
         {
             return(false);
         }
     }
     else
     {
         if (GetVitalityFactor(target) > vitalityThreshold)
         {
             return(false);
         }
     }
     if (target.Submarine == null || character.Submarine == null)
     {
         return(false);
     }
     if (target.Submarine.TeamID != character.Submarine.TeamID)
     {
         return(false);
     }
     if (target.CurrentHull == null)
     {
         return(false);
     }
     if (character.Submarine != null && !character.Submarine.IsEntityFoundOnThisSub(target.CurrentHull, true))
     {
         return(false);
     }
     // Don't go into rooms that have enemies
     if (Character.CharacterList.Any(c => c.CurrentHull == target.CurrentHull && !HumanAIController.IsFriendly(character, c) && HumanAIController.IsActive(c)))
     {
         return(false);
     }
     return(true);
 }
        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;
                    }
                }
            }
        }
        public override float GetPriority()
        {
            if (!IsAllowed)
            {
                Priority = 0;
                return(Priority);
            }
            if (component.Item.ConditionPercentage <= 0)
            {
                Priority = 0;
            }
            else
            {
                if (objectiveManager.CurrentOrder == this)
                {
                    Priority = AIObjectiveManager.OrderPriority;
                }
                Item targetItem = GetTarget()?.Item;
                if (targetItem == null)
                {
#if DEBUG
                    DebugConsole.ThrowError("Item or component of AI Objective Operate item wass null. This shouldn't happen.");
#endif
                    Abandon  = true;
                    Priority = 0;
                    return(0.0f);
                }
                if (targetItem.CurrentHull == null || targetItem.CurrentHull.FireSources.Any() || HumanAIController.IsItemOperatedByAnother(GetTarget(), out _))
                {
                    Priority = 0;
                }
                else if (Character.CharacterList.Any(c => c.CurrentHull == targetItem.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
                {
                    Priority = 0;
                }
                else
                {
                    float value = CumulatedDevotion + (AIObjectiveManager.OrderPriority * PriorityModifier);
                    float max   = MathHelper.Min((AIObjectiveManager.OrderPriority - 1), 90);
                    Priority = MathHelper.Clamp(value, 0, max);
                }
            }
            return(Priority);
        }
        protected override float GetPriority()
        {
            if (!IsAllowed)
            {
                Priority = 0;
                Abandon  = true;
                return(Priority);
            }
            bool isOrder = objectiveManager.HasOrder <AIObjectiveExtinguishFires>();

            if (!isOrder && Character.CharacterList.Any(c => c.CurrentHull == targetHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
            {
                // Don't go into rooms with any enemies, unless it's an order
                Priority = 0;
                Abandon  = true;
            }
            else
            {
                float yDist = Math.Abs(character.WorldPosition.Y - targetHull.WorldPosition.Y);
                yDist = yDist > 100 ? yDist * 3 : 0;
                float dist           = Math.Abs(character.WorldPosition.X - targetHull.WorldPosition.X) + yDist;
                float distanceFactor = MathHelper.Lerp(1, 0.1f, MathUtils.InverseLerp(0, 5000, dist));
                if (targetHull == character.CurrentHull || HumanAIController.VisibleHulls.Contains(targetHull))
                {
                    distanceFactor = 1;
                }
                float severity = AIObjectiveExtinguishFires.GetFireSeverity(targetHull);
                if (severity > 0.75f && !isOrder &&
                    targetHull.RoomName != null &&
                    !targetHull.RoomName.Contains("reactor", StringComparison.OrdinalIgnoreCase) &&
                    !targetHull.RoomName.Contains("engine", StringComparison.OrdinalIgnoreCase) &&
                    !targetHull.RoomName.Contains("command", StringComparison.OrdinalIgnoreCase))
                {
                    // Ignore severe fires to prevent casualities unless ordered to extinguish.
                    Priority = 0;
                    Abandon  = true;
                }
                else
                {
                    float devotion = CumulatedDevotion / 100;
                    Priority = MathHelper.Lerp(0, 100, MathHelper.Clamp(devotion + (severity * distanceFactor * PriorityModifier), 0, 1));
                }
            }
            return(Priority);
        }
        public override float GetPriority()
        {
            if (component.Item.ConditionPercentage <= 0)
            {
                return(0);
            }
            if (objectiveManager.CurrentOrder == this)
            {
                return(AIObjectiveManager.OrderPriority);
            }
            if (component.Item.CurrentHull == null)
            {
                return(0);
            }
            if (component.Item.CurrentHull.FireSources.Count > 0)
            {
                return(0);
            }
            if (IsOperatedByAnother(GetTarget()))
            {
                return(0);
            }
            if (Character.CharacterList.Any(c => c.CurrentHull == component.Item.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
            {
                return(0);
            }
            float devotion = MathHelper.Min(10, Priority);
            float value    = devotion + AIObjectiveManager.OrderPriority * PriorityModifier;
            float max      = MathHelper.Min((AIObjectiveManager.OrderPriority - 1), 90);

            return(MathHelper.Clamp(value, 0, max));
        }
Beispiel #15
0
 public static bool IsValidTarget(Character target, Character character)
 {
     if (target == null || target.IsDead || target.Removed)
     {
         return(false);
     }
     if (!HumanAIController.IsFriendly(character, target))
     {
         return(false);
     }
     if (character.AIController is HumanAIController humanAI)
     {
         if (GetVitalityFactor(target) >= GetVitalityThreshold(humanAI.ObjectiveManager, character, target))
         {
             return(false);
         }
         if (!humanAI.ObjectiveManager.IsCurrentOrder <AIObjectiveRescueAll>())
         {
             // Ignore unsafe hulls, unless ordered
             if (humanAI.UnsafeHulls.Contains(target.CurrentHull))
             {
                 return(false);
             }
         }
     }
     else
     {
         if (GetVitalityFactor(target) >= vitalityThreshold)
         {
             return(false);
         }
     }
     if (target.Submarine == null || character.Submarine == null)
     {
         return(false);
     }
     if (target.Submarine.TeamID != character.Submarine.TeamID)
     {
         return(false);
     }
     if (target.CurrentHull == null)
     {
         return(false);
     }
     if (character.Submarine != null)
     {
         if (target.Submarine.Info.Type != character.Submarine.Info.Type)
         {
             return(false);
         }
         if (character.Submarine != null && !character.Submarine.IsEntityFoundOnThisSub(target.CurrentHull, true))
         {
             return(false);
         }
     }
     if (!target.IsPlayer && HumanAIController.IsActive(target) && target.AIController is HumanAIController targetAI)
     {
         // Ignore all concious targets that are currently fighting, fleeing or treating characters
         if (targetAI.ObjectiveManager.HasActiveObjective <AIObjectiveCombat>() ||
             targetAI.ObjectiveManager.HasActiveObjective <AIObjectiveFindSafety>() ||
             targetAI.ObjectiveManager.HasActiveObjective <AIObjectiveRescue>())
         {
             return(false);
         }
     }
     // Don't go into rooms that have enemies
     if (Character.CharacterList.Any(c => c.CurrentHull == target.CurrentHull && !HumanAIController.IsFriendly(character, c) && HumanAIController.IsActive(c)))
     {
         return(false);
     }
     return(true);
 }
        protected override bool Filter(PowerContainer battery)
        {
            if (battery == null)
            {
                return(false);
            }
            var item = battery.Item;

            if (item.IgnoreByAI)
            {
                return(false);
            }
            if (!item.IsInteractable(character))
            {
                return(false);
            }
            if (item.Submarine == null)
            {
                return(false);
            }
            if (item.CurrentHull == null)
            {
                return(false);
            }
            if (item.Submarine.TeamID != character.TeamID)
            {
                return(false);
            }
            if (character.Submarine != null)
            {
                if (!character.Submarine.IsConnectedTo(item.Submarine))
                {
                    return(false);
                }
            }
            if (item.ConditionPercentage <= 0)
            {
                return(false);
            }
            if (Character.CharacterList.Any(c => c.CurrentHull == item.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
            {
                return(false);
            }
            if (IsReady(battery))
            {
                return(false);
            }
            return(true);
        }
        protected override bool Filter(PowerContainer battery)
        {
            if (battery == null)
            {
                return(false);
            }
            var item = battery.Item;

            if (item.Submarine == null)
            {
                return(false);
            }
            if (item.CurrentHull == null)
            {
                return(false);
            }
            if (item.Submarine.TeamID != character.TeamID)
            {
                return(false);
            }
            if (item.ConditionPercentage <= 0)
            {
                return(false);
            }
            if (character.Submarine != null && !character.Submarine.IsEntityFoundOnThisSub(item, true))
            {
                return(false);
            }
            if (Character.CharacterList.Any(c => c.CurrentHull == item.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
            {
                return(false);
            }
            if (IsReady(battery))
            {
                return(false);
            }
            return(true);
        }
 public static bool IsValidTarget(Character target, Character character)
 {
     if (target == null || target.IsDead || target.Removed)
     {
         return(false);
     }
     if (target.IsInstigator)
     {
         return(false);
     }
     if (!HumanAIController.IsFriendly(character, target, onlySameTeam: true))
     {
         return(false);
     }
     if (character.AIController is HumanAIController humanAI)
     {
         if (GetVitalityFactor(target) >= GetVitalityThreshold(humanAI.ObjectiveManager, character, target) ||
             target.CharacterHealth.GetAllAfflictions().All(a => a.Prefab.IsBuff || a.Strength <= a.Prefab.TreatmentThreshold))
         {
             return(false);
         }
         if (!humanAI.ObjectiveManager.HasOrder <AIObjectiveRescueAll>())
         {
             if (!character.IsMedic && target != character)
             {
                 // Don't allow to treat others autonomously
                 return(false);
             }
             // Ignore unsafe hulls, unless ordered
             if (humanAI.UnsafeHulls.Contains(target.CurrentHull))
             {
                 return(false);
             }
         }
     }
     else
     {
         if (GetVitalityFactor(target) >= vitalityThreshold)
         {
             return(false);
         }
     }
     if (target.Submarine == null || character.Submarine == null)
     {
         return(false);
     }
     // Don't allow going into another sub, unless it's connected and of the same team and type.
     if (!character.Submarine.IsEntityFoundOnThisSub(target.CurrentHull, includingConnectedSubs: true))
     {
         return(false);
     }
     if (target != character && !target.IsPlayer && HumanAIController.IsActive(target) && target.AIController is HumanAIController targetAI)
     {
         // Ignore all concious targets that are currently fighting, fleeing, fixing, or treating characters
         if (targetAI.ObjectiveManager.HasActiveObjective <AIObjectiveCombat>() ||
             targetAI.ObjectiveManager.HasActiveObjective <AIObjectiveFindSafety>() ||
             targetAI.ObjectiveManager.HasActiveObjective <AIObjectiveRescue>() ||
             targetAI.ObjectiveManager.HasActiveObjective <AIObjectiveFixLeak>())
         {
             return(false);
         }
     }
     // Don't go into rooms that have enemies
     if (Character.CharacterList.Any(c => c.CurrentHull == target.CurrentHull && !HumanAIController.IsFriendly(character, c) && HumanAIController.IsActive(c)))
     {
         return(false);
     }
     return(true);
 }
        public override float GetPriority()
        {
            if (!IsAllowed)
            {
                Priority = 0;
                return(Priority);
            }
            if (component.Item.ConditionPercentage <= 0)
            {
                Priority = 0;
            }
            else
            {
                if (objectiveManager.CurrentOrder == this)
                {
                    Priority = AIObjectiveManager.OrderPriority;
                }
                ItemComponent target     = GetTarget();
                Item          targetItem = target?.Item;
                if (targetItem == null)
                {
#if DEBUG
                    DebugConsole.ThrowError("Item or component of AI Objective Operate item was null. This shouldn't happen.");
#endif
                    Abandon  = true;
                    Priority = 0;
                    return(Priority);
                }
                var reactor = component?.Item.GetComponent <Reactor>();
                if (reactor != null)
                {
                    switch (Option)
                    {
                    case "shutdown":
                        if (!reactor.PowerOn)
                        {
                            Priority = 0;
                            return(Priority);
                        }
                        break;

                    case "powerup":
                        // Check that we don't already have another order that is targeting the same item.
                        // Without this the autonomous objective will tell the bot to turn the reactor on again.
                        if (objectiveManager.CurrentOrder is AIObjectiveOperateItem operateOrder && operateOrder != this && operateOrder.GetTarget() == target)
                        {
                            Priority = 0;
                            return(Priority);
                        }
                        break;
                    }
                }
                if (targetItem.CurrentHull == null ||
                    targetItem.Submarine != character.Submarine && objectiveManager.CurrentOrder != this ||
                    targetItem.CurrentHull.FireSources.Any() ||
                    HumanAIController.IsItemOperatedByAnother(target, out _) ||
                    Character.CharacterList.Any(c => c.CurrentHull == targetItem.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
                {
                    Priority = 0;
                }
                else
                {
                    float value = CumulatedDevotion + (AIObjectiveManager.OrderPriority * PriorityModifier);
                    float max   = objectiveManager.CurrentOrder == this ? MathHelper.Min(AIObjectiveManager.OrderPriority, 90) : AIObjectiveManager.RunPriority - 1;
                    Priority = MathHelper.Clamp(value, 0, max);
                }
            }
            return(Priority);
        }
Beispiel #20
0
 protected override bool Filter(Pump pump)
 {
     if (pump == null)
     {
         return(false);
     }
     if (pump.Item.NonInteractable)
     {
         return(false);
     }
     if (pump.Item.HasTag("ballast"))
     {
         return(false);
     }
     if (pump.Item.Submarine == null)
     {
         return(false);
     }
     if (pump.Item.CurrentHull == null)
     {
         return(false);
     }
     if (pump.Item.Submarine.TeamID != character.TeamID)
     {
         return(false);
     }
     if (pump.Item.ConditionPercentage <= 0)
     {
         return(false);
     }
     if (pump.Item.CurrentHull.FireSources.Count > 0)
     {
         return(false);
     }
     if (character.Submarine != null)
     {
         if (pump.Item.Submarine.Info.Type != character.Submarine.Info.Type)
         {
             return(false);
         }
         if (!character.Submarine.IsEntityFoundOnThisSub(pump.Item, true))
         {
             return(false);
         }
     }
     if (Character.CharacterList.Any(c => c.CurrentHull == pump.Item.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
     {
         return(false);
     }
     if (IsReady(pump))
     {
         return(false);
     }
     return(true);
 }
Beispiel #21
0
        protected override float GetPriority()
        {
            bool isOrder = objectiveManager.IsOrder(this);

            if (!IsAllowed || character.LockHands)
            {
                Priority = 0;
                Abandon  = !isOrder;
                return(Priority);
            }
            if (!isOrder && component.Item.ConditionPercentage <= 0)
            {
                Priority = 0;
            }
            else
            {
                if (isOrder)
                {
                    Priority = objectiveManager.GetOrderPriority(this);
                }
                ItemComponent target     = GetTarget();
                Item          targetItem = target?.Item;
                if (targetItem == null)
                {
#if DEBUG
                    DebugConsole.ThrowError("Item or component of AI Objective Operate item was null. This shouldn't happen.");
#endif
                    Abandon  = true;
                    Priority = 0;
                    return(Priority);
                }
                var reactor = component?.Item.GetComponent <Reactor>();
                if (reactor != null)
                {
                    if (!isOrder)
                    {
                        if (reactor.LastUserWasPlayer && character.TeamID != CharacterTeamType.FriendlyNPC)
                        {
                            // The reactor was previously operated by a player -> ignore.
                            Priority = 0;
                            return(Priority);
                        }
                    }
                    switch (Option)
                    {
                    case "shutdown":
                        if (!reactor.PowerOn)
                        {
                            Priority = 0;
                            return(Priority);
                        }
                        break;

                    case "powerup":
                        // Check that we don't already have another order that is targeting the same item.
                        // Without this the autonomous objective will tell the bot to turn the reactor on again.
                        if (IsAnotherOrderTargetingSameItem(objectiveManager.ForcedOrder) || objectiveManager.CurrentOrders.Any(o => IsAnotherOrderTargetingSameItem(o.Objective)))
                        {
                            Priority = 0;
                            return(Priority);
                        }
                        bool IsAnotherOrderTargetingSameItem(AIObjective objective)
                        {
                            return(objective is AIObjectiveOperateItem operateObjective && operateObjective != this && operateObjective.GetTarget() == target && operateObjective.Option != Option);
                        }

                        break;
                    }
                }
                else if (!isOrder)
                {
                    var steering = component?.Item.GetComponent <Steering>();
                    if (steering != null && (steering.AutoPilot || HumanAIController.IsTrueForAnyCrewMember(c => c != HumanAIController && c.Character.IsCaptain)))
                    {
                        // Ignore if already set to autopilot or if there's a captain onboard
                        Priority = 0;
                        return(Priority);
                    }
                }
                if (targetItem.CurrentHull == null ||
                    targetItem.Submarine != character.Submarine && !isOrder ||
                    targetItem.CurrentHull.FireSources.Any() ||
                    HumanAIController.IsItemOperatedByAnother(target, out _) ||
                    Character.CharacterList.Any(c => c.CurrentHull == targetItem.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)) ||
                    component.Item.IgnoreByAI(character) || useController && controller.Item.IgnoreByAI(character))
                {
                    Priority = 0;
                }
                else
                {
                    if (isOrder)
                    {
                        float max   = objectiveManager.GetOrderPriority(this);
                        float value = CumulatedDevotion + (max * PriorityModifier);
                        Priority = MathHelper.Clamp(value, 0, max);
                    }
                    else
                    {
                        float value = CumulatedDevotion + (AIObjectiveManager.LowestOrderPriority * PriorityModifier);
                        float max   = AIObjectiveManager.LowestOrderPriority - 1;
                        if (reactor != null && reactor.PowerOn && reactor.FissionRate > 1 && reactor.AutoTemp && Option == "powerup")
                        {
                            // Already on, no need to operate.
                            value = 0;
                        }
                        Priority = MathHelper.Clamp(value, 0, max);
                    }
                }
            }
            return(Priority);
        }
Beispiel #22
0
        protected override bool CheckObjectiveSpecific()
        {
            if (character.LockHands || targetCharacter == null || targetCharacter.CurrentHull == null || targetCharacter.Removed || targetCharacter.IsDead)
            {
                Abandon = true;
                return(false);
            }
            // Don't go into rooms that have enemies
            if (Character.CharacterList.Any(c => c.CurrentHull == targetCharacter.CurrentHull && !HumanAIController.IsFriendly(character, c) && HumanAIController.IsActive(c)))
            {
                Abandon = true;
                return(false);
            }
            bool isCompleted =
                AIObjectiveRescueAll.GetVitalityFactor(targetCharacter) >= AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager, character, targetCharacter) ||
                targetCharacter.CharacterHealth.GetAllAfflictions().All(a => a.Prefab.IsBuff || a.Strength <= a.Prefab.TreatmentThreshold);

            if (isCompleted && targetCharacter != character && character.IsOnPlayerTeam)
            {
                character.Speak(TextManager.GetWithVariable("DialogTargetHealed", "[targetname]", targetCharacter.Name),
                                null, 1.0f, "targethealed" + targetCharacter.Name, 60.0f);
            }
            return(isCompleted);
        }
Beispiel #23
0
        protected override void Act(float deltaTime)
        {
            if (character.LockHands)
            {
                Abandon = true;
                return;
            }
            ItemComponent target = useController ? controller : component;

            if (useController && controller == null)
            {
                character.Speak(TextManager.GetWithVariable("DialogCantFindController", "[item]", component.Item.Name, true), null, 2.0f, "cantfindcontroller", 30.0f);
                Abandon = true;
                return;
            }
            if (target.CanBeSelected)
            {
                if (character.CanInteractWith(target.Item, out _, checkLinked: false))
                {
                    HumanAIController.FaceTarget(target.Item);
                    // Don't allow to operate an item that someone already operates, unless this objective is an order
                    if (objectiveManager.CurrentOrder != this && Character.CharacterList.Any(c => c.SelectedConstruction == target.Item && c != character && HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
                    {
                        // Don't abandon
                        return;
                    }
                    if (character.SelectedConstruction != target.Item)
                    {
                        target.Item.TryInteract(character, false, true);
                    }
                    if (component.AIOperate(deltaTime, character, this))
                    {
                        IsCompleted = completionCondition == null || completionCondition();
                    }
                }
                else
                {
                    TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(target.Item, character, objectiveManager, closeEnough: 50),
                                       onAbandon: () => Abandon = true,
                                       onCompleted: () => RemoveSubObjective(ref goToObjective));
                }
            }
            else
            {
                if (component.Item.GetComponent <Pickable>() == null)
                {
                    //controller/target can't be selected and the item cannot be picked -> objective can't be completed
                    Abandon = true;
                    return;
                }
                else if (!character.Inventory.Items.Contains(component.Item))
                {
                    TryAddSubObjective(ref getItemObjective, () => new AIObjectiveGetItem(character, component.Item, objectiveManager, equip: true),
                                       onAbandon: () => Abandon = true,
                                       onCompleted: () => RemoveSubObjective(ref getItemObjective));
                }
                else
                {
                    if (requireEquip && !character.HasEquippedItem(component.Item))
                    {
                        //the item has to be equipped before using it if it's holdable
                        var holdable = component.Item.GetComponent <Holdable>();
                        if (holdable == null)
                        {
#if DEBUG
                            DebugConsole.ThrowError($"{character.Name}: AIObjectiveOperateItem failed - equipping item " + component.Item + " is required but the item has no Holdable component");
#endif
                            return;
                        }
                        for (int i = 0; i < character.Inventory.Capacity; i++)
                        {
                            if (character.Inventory.SlotTypes[i] == InvSlotType.Any || !holdable.AllowedSlots.Any(s => s.HasFlag(character.Inventory.SlotTypes[i])))
                            {
                                continue;
                            }
                            //equip slot already taken
                            if (character.Inventory.Items[i] != null)
                            {
                                //try to put the item in an Any slot, and drop it if that fails
                                if (!character.Inventory.Items[i].AllowedSlots.Contains(InvSlotType.Any) ||
                                    !character.Inventory.TryPutItem(character.Inventory.Items[i], character, new List <InvSlotType>()
                                {
                                    InvSlotType.Any
                                }))
                                {
                                    character.Inventory.Items[i].Drop(character);
                                }
                            }
                            if (character.Inventory.TryPutItem(component.Item, i, true, false, character))
                            {
                                component.Item.Equip(character);
                                break;
                            }
                        }
                        return;
                    }
                    if (component.AIOperate(deltaTime, character, this))
                    {
                        IsCompleted = completionCondition == null || completionCondition();
                    }
                }
            }
        }