protected override float TargetEvaluation()
        {
            if (Targets.None())
            {
                return(100);
            }
            if (!objectiveManager.IsOrder(this))
            {
                if (!character.IsMedic && HumanAIController.IsTrueForAnyCrewMember(c => c != HumanAIController && c.Character.IsMedic && !c.Character.IsUnconscious))
                {
                    // Don't do anything if there's a medic on board and we are not a medic
                    return(100);
                }
            }
            float worstCondition = Targets.Min(t => GetVitalityFactor(t));

            if (Targets.Contains(character))
            {
                if (character.Bleeding > 10)
                {
                    // Enforce the highest priority when bleeding out.
                    worstCondition = 0;
                }
                // Boost the priority when wounded.
                worstCondition /= 2;
            }
            return(worstCondition);
        }
Beispiel #2
0
 public override float GetPriority()
 {
     if (!IsAllowed)
     {
         Priority = 0;
         Abandon  = true;
     }
     else if (HumanAIController.IsTrueForAnyCrewMember(other => other != HumanAIController && other.Character.IsBot && other.ObjectiveManager.GetActiveObjective <AIObjectiveFixLeak>()?.Leak == Leak))
     {
         Priority = 0;
         Abandon  = true;
     }
     else
     {
         float xDist = Math.Abs(character.WorldPosition.X - Leak.WorldPosition.X);
         float yDist = Math.Abs(character.WorldPosition.Y - Leak.WorldPosition.Y);
         // Vertical distance matters more than horizontal (climbing up/down is harder than moving horizontally).
         // If the target is close, ignore the distance factor alltogether so that we keep fixing the leaks that are nearby.
         float distanceFactor = isPriority || xDist < 200 && yDist < 100 ? 1 : MathHelper.Lerp(1, 0.1f, MathUtils.InverseLerp(0, 3000, xDist + yDist * 3.0f));
         float severity       = isPriority ? 1 : AIObjectiveFixLeaks.GetLeakSeverity(Leak) / 100;
         float reduction      = isPriority ? 1 : 2;
         float max            = AIObjectiveManager.LowestOrderPriority - reduction;
         float devotion       = CumulatedDevotion / 100;
         Priority = MathHelper.Lerp(0, max, MathHelper.Clamp(devotion + (severity * distanceFactor * PriorityModifier), 0, 1));
     }
     return(Priority);
 }
        protected override float TargetEvaluation()
        {
            if (!character.IsOnPlayerTeam)
            {
                return(Targets.None() ? 0 : 100);
            }
            int totalEnemies = Targets.Count();

            if (totalEnemies == 0)
            {
                return(0);
            }
            if (character.IsSecurity)
            {
                return(100);
            }
            if (objectiveManager.IsOrder(this))
            {
                return(100);
            }
            return(HumanAIController.IsTrueForAnyCrewMember(c => c.Character.IsSecurity && !c.Character.IsIncapacitated && c.Character.Submarine == character.Submarine) ? 0 : 100);
        }
Beispiel #4
0
        protected override float TargetEvaluation()
        {
            int   otherRescuers = HumanAIController.CountCrew(c => c != HumanAIController && c.ObjectiveManager.IsCurrentObjective <AIObjectiveRescueAll>(), onlyBots: true);
            int   targetCount   = Targets.Count;
            bool  anyRescuers   = otherRescuers > 0;
            float ratio         = anyRescuers ? targetCount / (float)otherRescuers : 1;

            if (objectiveManager.CurrentOrder == this)
            {
                return(Targets.Min(t => GetVitalityFactor(t)) / ratio);
            }
            else
            {
                float multiplier = 1;
                if (anyRescuers)
                {
                    float mySkill        = character.GetSkillLevel("medical");
                    int   betterRescuers = HumanAIController.CountCrew(c => c != HumanAIController && c.Character.Info.Job.GetSkillLevel("medical") >= mySkill, onlyBots: true);
                    if (targetCount / (float)betterRescuers <= 1)
                    {
                        // Enough rescuers
                        return(100);
                    }
                    else
                    {
                        bool foundOtherMedics = HumanAIController.IsTrueForAnyCrewMember(c => c != HumanAIController && c.Character.Info.Job.Prefab.Identifier == "medicaldoctor");
                        if (foundOtherMedics)
                        {
                            if (character.Info.Job.Prefab.Identifier != "medicaldoctor")
                            {
                                // Double the vitality factor -> less likely to take action
                                multiplier = 2;
                            }
                        }
                    }
                }
                return(Targets.Min(t => GetVitalityFactor(t)) / ratio * multiplier);
            }
        }
Beispiel #5
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);
        }