public override float GetPriority()
 {
     if (!IsAllowed)
     {
         Priority = 0;
         return(Priority);
     }
     if (!objectiveManager.IsCurrentOrder <AIObjectiveExtinguishFires>() &&
         Character.CharacterList.Any(c => c.CurrentHull == targetHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
     {
         Priority = 0;
     }
     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)
         {
             distanceFactor = 1;
         }
         float severity       = AIObjectiveExtinguishFires.GetFireSeverity(targetHull);
         float severityFactor = MathHelper.Lerp(0, 1, severity / 100);
         float devotion       = CumulatedDevotion / 100;
         Priority = MathHelper.Lerp(0, 100, MathHelper.Clamp(devotion + (severityFactor * distanceFactor * PriorityModifier), 0, 1));
     }
     return(Priority);
 }
예제 #2
0
 public static bool IsValidTarget(Character target, Character character)
 {
     if (target == null || target.IsDead || target.Removed)
     {
         return(false);
     }
     if (target == character)
     {
         return(false);
     }
     if (HumanAIController.IsFriendly(character, target))
     {
         return(false);
     }
     if (target.Submarine == null)
     {
         return(false);
     }
     if (target.Submarine.TeamID != character.TeamID)
     {
         return(false);
     }
     if (target.CurrentHull == null)
     {
         return(false);
     }
     if (character.Submarine != null)
     {
         if (!character.Submarine.IsConnectedTo(target.Submarine))
         {
             return(false);
         }
     }
     return(true);
 }
 private bool IsOperatedByAnother(ItemComponent target)
 {
     foreach (var c in Character.CharacterList)
     {
         if (c == character)
         {
             continue;
         }
         if (!HumanAIController.IsFriendly(c))
         {
             continue;
         }
         if (c.SelectedConstruction != target.Item)
         {
             continue;
         }
         // If the other character is player, don't try to operate
         if (c.IsRemotePlayer || Character.Controlled == c)
         {
             return(true);
         }
         if (c.AIController is HumanAIController humanAi)
         {
             // If the other character is ordered to operate the item, let him do it
             if (humanAi.ObjectiveManager.IsCurrentOrder <AIObjectiveOperateItem>())
             {
                 return(true);
             }
             else
             {
                 if (target is Steering)
                 {
                     // Steering is hard-coded -> cannot use the required skills collection defined in the xml
                     return(character.GetSkillLevel("helm") <= c.GetSkillLevel("helm"));
                 }
                 else
                 {
                     return(target.DegreeOfSuccess(character) <= target.DegreeOfSuccess(c));
                 }
             }
         }
         else
         {
             // Shouldn't go here, unless we allow non-humans to operate items
             return(false);
         }
     }
     return(false);
 }
예제 #4
0
        public override float GetPriority()
        {
            if (Character.CharacterList.Any(c => c.CurrentHull == targetHull && !HumanAIController.IsFriendly(c)))
            {
                return(0);
            }
            // Vertical distance matters more than horizontal (climbing up/down is harder than moving horizontally)
            float dist           = Math.Abs(character.WorldPosition.X - targetHull.WorldPosition.X) + Math.Abs(character.WorldPosition.Y - targetHull.WorldPosition.Y) * 2.0f;
            float distanceFactor = MathHelper.Lerp(1, 0.1f, MathUtils.InverseLerp(0, 10000, dist));
            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)));
        }
예제 #5
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);
 }
 public static bool IsValidTarget(Character target, Character character)
 {
     if (target == null || target.Removed)
     {
         return(false);
     }
     if (target.IsDead)
     {
         return(false);
     }
     if (target.IsUnconscious && target.Params.Health.ConstantHealthRegeneration <= 0.0f)
     {
         return(false);
     }
     if (target == character)
     {
         return(false);
     }
     if (target.Submarine == null)
     {
         return(false);
     }
     if (character.Submarine == null)
     {
         return(false);
     }
     if (target.CurrentHull == null)
     {
         return(false);
     }
     if (HumanAIController.IsFriendly(character, target))
     {
         return(false);
     }
     if (!character.Submarine.IsConnectedTo(target.Submarine))
     {
         return(false);
     }
     if (target.HasAbilityFlag(AbilityFlags.IgnoredByEnemyAI))
     {
         return(false);
     }
     return(true);
 }
 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 (target.Bleeding < 1 && target.Vitality / target.MaxVitality > GetVitalityThreshold(humanAI.ObjectiveManager))
         {
             return(false);
         }
     }
     else
     {
         if (target.Bleeding < 1 && target.Vitality / target.MaxVitality > vitalityThreshold)
         {
             return(false);
         }
     }
     if (target.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);
     }
     return(true);
 }
예제 #8
0
        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);
        }
예제 #9
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 != 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);
 }
 protected override bool Filter(Pump pump)
 {
     if (pump == null)
     {
         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 && !character.Submarine.IsEntityFoundOnThisSub(pump.Item, true))
     {
         return(false);
     }
     if (Character.CharacterList.Any(c => c.CurrentHull == pump.Item.CurrentHull && !HumanAIController.IsFriendly(c)))
     {
         return(false);
     }
     if (Option == "stoppumping")
     {
         if (!pump.IsActive || MathUtils.NearlyEqual(pump.FlowPercentage, 0))
         {
             return(false);
         }
     }
     else
     {
         if (!pump.Item.InWater)
         {
             return(false);
         }
         if (pump.IsActive && pump.FlowPercentage <= -99.9f)
         {
             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);
        }
        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);
        }
        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));
        }
 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);
 }
예제 #15
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;
                    }
                }
            }
        }
예제 #16
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);
 }
        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);
        }
예제 #18
0
        protected override void Act(float deltaTime)
        {
            var  currentHull     = character.AnimController.CurrentHull;
            bool needsDivingGear = HumanAIController.NeedsDivingGear(currentHull);
            bool needsDivingSuit = needsDivingGear && (currentHull == null || currentHull.WaterPercentage > 90);
            bool needsEquipment  = false;

            if (needsDivingSuit)
            {
                needsEquipment = !HumanAIController.HasDivingSuit(character);
            }
            else if (needsDivingGear)
            {
                needsEquipment = !HumanAIController.HasDivingMask(character);
            }
            if (needsEquipment)
            {
                TryAddSubObjective(ref divingGearObjective,
                                   () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager),
                                   onAbandon: () => searchHullTimer = Math.Min(1, searchHullTimer));
            }
            else
            {
                if (divingGearObjective != null && divingGearObjective.IsCompleted())
                {
                    // Reset the devotion.
                    Priority            = 0;
                    divingGearObjective = null;
                }
                if (currenthullSafety < HumanAIController.HULL_SAFETY_THRESHOLD)
                {
                    searchHullTimer = Math.Min(1, searchHullTimer);
                }
                if (searchHullTimer > 0.0f)
                {
                    searchHullTimer -= deltaTime;
                }
                else
                {
                    searchHullTimer  = SearchHullInterval;
                    previousSafeHull = currentSafeHull;
                    currentSafeHull  = FindBestHull();
                    if (currentSafeHull == null)
                    {
                        currentSafeHull = previousSafeHull;
                    }
                    if (currentSafeHull != null && currentSafeHull != currentHull)
                    {
                        if (goToObjective?.Target != currentSafeHull)
                        {
                            goToObjective = null;
                        }
                        TryAddSubObjective(ref goToObjective,
                                           constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: true)
                        {
                            AllowGoingOutside = HumanAIController.HasDivingSuit(character)
                        },
                                           onAbandon: () => unreachable.Add(goToObjective.Target as Hull));
                    }
                    else
                    {
                        goToObjective = null;
                    }
                }
                if (goToObjective != null)
                {
                    if (goToObjective.IsCompleted())
                    {
                        objectiveManager.GetObjective <AIObjectiveIdle>()?.Wander(deltaTime);
                    }
                    Priority = 0;
                    return;
                }
                if (currentHull == null)
                {
                    return;
                }
                //goto objective doesn't exist (a safe hull not found, or a path to a safe hull not found)
                // -> attempt to manually steer away from hazards
                Vector2 escapeVel = Vector2.Zero;
                // TODO: optimize
                foreach (FireSource fireSource in HumanAIController.VisibleHulls.SelectMany(h => h.FireSources))
                {
                    Vector2 dir            = character.Position - fireSource.Position;
                    float   distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(fireSource.Position, character.Position), 0.1f, 10.0f);
                    escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
                }
                foreach (Character enemy in Character.CharacterList)
                {
                    if (enemy.IsDead || enemy.IsUnconscious || enemy.Removed || HumanAIController.IsFriendly(enemy))
                    {
                        continue;
                    }
                    if (HumanAIController.VisibleHulls.Contains(enemy.CurrentHull))
                    {
                        Vector2 dir            = character.Position - enemy.Position;
                        float   distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(enemy.Position, character.Position), 0.1f, 10.0f);
                        escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
                    }
                }
                if (escapeVel != Vector2.Zero)
                {
                    float left  = currentHull.Rect.X + 50;
                    float right = currentHull.Rect.Right - 50;
                    //only move if we haven't reached the edge of the room
                    if (escapeVel.X < 0 && character.Position.X > left || escapeVel.X > 0 && character.Position.X < right)
                    {
                        character.AIController.SteeringManager.SteeringManual(deltaTime, escapeVel);
                    }
                    else
                    {
                        character.AnimController.TargetDir = escapeVel.X < 0.0f ? Direction.Right : Direction.Left;
                        character.AIController.SteeringManager.Reset();
                    }
                }
                else
                {
                    Priority = 0;
                    objectiveManager.GetObjective <AIObjectiveIdle>()?.Wander(deltaTime);
                }
            }
        }
예제 #19
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);
        }
예제 #20
0
        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);
        }
예제 #21
0
        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)))
            {
                return(false);
            }
            if (Option == "charge")
            {
                if (battery.RechargeRatio >= PowerContainer.aiRechargeTargetRatio - 0.01f)
                {
                    return(false);
                }
            }
            else
            {
                if (battery.RechargeRatio <= 0)
                {
                    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);
        }
예제 #23
0
 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);
 }
        protected override void Act(float deltaTime)
        {
            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))
                {
                    // 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)))
                    {
                        abandon = true;
                        return;
                    }
                    if (character.SelectedConstruction != target.Item)
                    {
                        target.Item.TryInteract(character, false, true);
                    }
                    if (component.AIOperate(deltaTime, character, this))
                    {
                        isCompleted = true;
                    }
                }
                else
                {
                    TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(target.Item, character, objectiveManager));
                }
            }
            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));
                }
                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("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 = true;
                    }
                }
            }
        }
예제 #25
0
        private void Attack(float deltaTime)
        {
            character.CursorPosition = Enemy.Position;
            if (!character.CanSeeCharacter(Enemy))
            {
                return;
            }
            if (Weapon.RequireAimToUse)
            {
                bool isOperatingButtons = false;
                if (SteeringManager == PathSteering)
                {
                    var door = PathSteering.CurrentPath?.CurrentNode?.ConnectedDoor;
                    if (door != null && !door.IsOpen && !door.IsBroken)
                    {
                        isOperatingButtons = door.HasIntegratedButtons || door.Item.GetConnectedComponents <Controller>(true).Any();
                    }
                }
                if (!isOperatingButtons)
                {
                    character.SetInput(InputType.Aim, false, true);
                }
            }
            bool isFacing = character.AnimController.Dir > 0 && Enemy.WorldPosition.X > character.WorldPosition.X || character.AnimController.Dir < 0 && Enemy.WorldPosition.X < character.WorldPosition.X;

            if (!isFacing)
            {
                aimTimer = Rand.Range(1f, 1.5f);
            }
            if (aimTimer > 0)
            {
                aimTimer -= deltaTime;
                return;
            }
            if (WeaponComponent is MeleeWeapon meleeWeapon)
            {
                if (Vector2.DistanceSquared(character.Position, Enemy.Position) <= meleeWeapon.Range * meleeWeapon.Range)
                {
                    character.SetInput(InputType.Shoot, false, true);
                    Weapon.Use(deltaTime, character);
                }
            }
            else
            {
                if (WeaponComponent is RepairTool repairTool)
                {
                    if (Vector2.DistanceSquared(character.Position, Enemy.Position) > repairTool.Range * repairTool.Range)
                    {
                        return;
                    }
                }
                if (VectorExtensions.Angle(VectorExtensions.Forward(Weapon.body.TransformedRotation), Enemy.Position - Weapon.Position) < MathHelper.PiOver4)
                {
                    if (myBodies == null)
                    {
                        myBodies = character.AnimController.Limbs.Select(l => l.body.FarseerBody);
                    }

                    var collisionCategories = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel;
                    var pickedBody          = Submarine.PickBody(Weapon.SimPosition, Enemy.SimPosition, myBodies, collisionCategories);
                    if (pickedBody != null)
                    {
                        Character target = null;
                        if (pickedBody.UserData is Character c)
                        {
                            target = c;
                        }
                        else if (pickedBody.UserData is Limb limb)
                        {
                            target = limb.character;
                        }
                        if (target != null && (target == Enemy || !HumanAIController.IsFriendly(target)))
                        {
                            character.SetInput(InputType.Shoot, false, true);
                            Weapon.Use(deltaTime, character);
                            float reloadTime = 0;
                            if (WeaponComponent is RangedWeapon rangedWeapon)
                            {
                                reloadTime = rangedWeapon.Reload;
                            }
                            if (WeaponComponent is MeleeWeapon mw)
                            {
                                reloadTime = mw.Reload;
                            }
                            aimTimer = reloadTime * Rand.Range(1f, 1.5f);
                        }
                    }
                }
            }
        }
        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);
        }
예제 #27
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);
 }
예제 #28
0
        public override float GetPriority()
        {
            if (targetCharacter == null)
            {
                return(0);
            }
            if (targetCharacter.CurrentHull == null || targetCharacter.Removed || targetCharacter.IsDead)
            {
                abandon = true;
                return(0);
            }
            // Don't go into rooms that have enemies
            if (Character.CharacterList.Any(c => c.CurrentHull == targetCharacter.CurrentHull && !HumanAIController.IsFriendly(c)))
            {
                abandon = true;
                return(0);
            }
            // Vertical distance matters more than horizontal (climbing up/down is harder than moving horizontally)
            float dist           = Math.Abs(character.WorldPosition.X - targetCharacter.WorldPosition.X) + Math.Abs(character.WorldPosition.Y - targetCharacter.WorldPosition.Y) * 2.0f;
            float distanceFactor = MathHelper.Lerp(1, 0.5f, MathUtils.InverseLerp(0, 10000, dist));
            float vitalityFactor = AIObjectiveRescueAll.GetVitalityFactor(targetCharacter);
            float devotion       = Math.Min(Priority, 10) / 100;

            return(MathHelper.Lerp(0, 100, MathHelper.Clamp(devotion + vitalityFactor * distanceFactor, 0, 1)));
        }
예제 #29
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);
        }
        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);
        }