コード例 #1
0
 private void Engage()
 {
     if (character.LockHands || Enemy == null)
     {
         Mode = CombatMode.Retreat;
         SteeringManager.Reset();
         return;
     }
     retreatTarget = null;
     RemoveSubObjective(ref retreatObjective);
     RemoveSubObjective(ref seekAmmunition);
     if (followTargetObjective != null && followTargetObjective.Target != Enemy)
     {
         followTargetObjective = null;
     }
     TryAddSubObjective(ref followTargetObjective,
                        constructor: () => new AIObjectiveGoTo(Enemy, character, objectiveManager, repeat: true, getDivingGearIfNeeded: true)
     {
         IgnoreIfTargetDead = true,
         DialogueIdentifier = "dialogcannotreachtarget",
         TargetName         = Enemy.DisplayName
     },
                        onAbandon: () =>
     {
         Abandon = true;
         SteeringManager.Reset();
     });
     if (followTargetObjective != null)
     {
         followTargetObjective.CloseEnough =
             WeaponComponent is RangedWeapon ? 1000 :
             WeaponComponent is MeleeWeapon mw ? mw.Range :
             WeaponComponent is RepairTool rt ? rt.Range : 50;
     }
 }
コード例 #2
0
 private void Engage()
 {
     retreatTarget = null;
     RemoveSubObjective(ref retreatObjective);
     RemoveSubObjective(ref seekAmmunition);
     if (followTargetObjective != null && followTargetObjective.Target != Enemy)
     {
         followTargetObjective = null;
     }
     TryAddSubObjective(ref followTargetObjective,
                        constructor: () => new AIObjectiveGoTo(Enemy, character, objectiveManager, repeat: true, getDivingGearIfNeeded: true)
     {
         AllowGoingOutside  = true,
         IgnoreIfTargetDead = true
     },
                        onAbandon: () =>
     {
         Mode = CombatMode.Retreat;
         SteeringManager.Reset();
     });
     if (followTargetObjective != null && subObjectives.Contains(followTargetObjective))
     {
         followTargetObjective.CloseEnough =
             WeaponComponent is RangedWeapon ? 300 :
             WeaponComponent is MeleeWeapon mw ? mw.Range :
             WeaponComponent is RepairTool rt ? rt.Range : 50;
     }
 }
コード例 #3
0
        public void Wander(float deltaTime)
        {
            if (character.IsClimbing)
            {
                return;
            }
            //steer away from edges of the hull
            var currentHull = character.CurrentHull;

            if (currentHull != null)
            {
                float roomWidth = currentHull.Rect.Width;
                if (roomWidth < WallAvoidDistance * 4)
                {
                    PathSteering.Reset();
                }
                else
                {
                    float leftDist  = character.Position.X - currentHull.Rect.X;
                    float rightDist = currentHull.Rect.Right - character.Position.X;
                    if (leftDist < WallAvoidDistance && rightDist < WallAvoidDistance)
                    {
                        if (Math.Abs(rightDist - leftDist) > WallAvoidDistance / 2)
                        {
                            PathSteering.SteeringManual(deltaTime, Vector2.UnitX * Math.Sign(rightDist - leftDist));
                        }
                        else
                        {
                            PathSteering.Reset();
                        }
                    }
                    else if (leftDist < WallAvoidDistance)
                    {
                        float speed = (WallAvoidDistance - leftDist) / WallAvoidDistance;
                        PathSteering.SteeringManual(deltaTime, Vector2.UnitX * MathHelper.Clamp(speed, 0.25f, 1));
                        PathSteering.WanderAngle = 0.0f;
                    }
                    else if (rightDist < WallAvoidDistance)
                    {
                        float speed = (WallAvoidDistance - rightDist) / WallAvoidDistance;
                        PathSteering.SteeringManual(deltaTime, -Vector2.UnitX * MathHelper.Clamp(speed, 0.25f, 1));
                        PathSteering.WanderAngle = MathHelper.Pi;
                    }
                    else
                    {
                        SteeringManager.SteeringWander();
                    }
                }
            }
            else
            {
                SteeringManager.SteeringWander();
            }
            if (!character.AnimController.InWater)
            {
                //reset vertical steering to prevent dropping down from platforms etc
                character.AIController.SteeringManager.ResetY();
            }
        }
コード例 #4
0
        public BackgroundCreature(BackgroundCreaturePrefab prefab, Vector2 position)
        {
            this.Prefab   = prefab;
            this.position = position;

            drawPosition = position;

            steeringManager = new SteeringManager(this);

            velocity = new Vector3(
                Rand.Range(-prefab.Speed, prefab.Speed, Rand.RandSync.ClientOnly),
                Rand.Range(-prefab.Speed, prefab.Speed, Rand.RandSync.ClientOnly),
                Rand.Range(0.0f, prefab.WanderZAmount, Rand.RandSync.ClientOnly));

            checkWallsTimer = Rand.Range(0.0f, CheckWallsInterval, Rand.RandSync.ClientOnly);

            foreach (XElement subElement in prefab.Config.Elements())
            {
                List <SpriteDeformation> deformationList = null;
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "deformablesprite":
                    deformationList = spriteDeformations;
                    break;

                case "deformablelightsprite":
                    deformationList = lightSpriteDeformations;
                    break;

                default:
                    continue;
                }
                foreach (XElement animationElement in subElement.Elements())
                {
                    SpriteDeformation deformation = null;
                    int sync = animationElement.GetAttributeInt("sync", -1);
                    if (sync > -1)
                    {
                        string typeName = animationElement.GetAttributeString("type", "").ToLowerInvariant();
                        deformation = uniqueSpriteDeformations.Find(d => d.TypeName == typeName && d.Sync == sync);
                    }
                    if (deformation == null)
                    {
                        deformation = SpriteDeformation.Load(animationElement, prefab.Name);
                        if (deformation != null)
                        {
                            uniqueSpriteDeformations.Add(deformation);
                        }
                    }
                    if (deformation != null)
                    {
                        deformationList.Add(deformation);
                    }
                }
            }
        }
コード例 #5
0
 public HumanAIController(Character c) : base(c)
 {
     insideSteering      = new IndoorsSteeringManager(this, true, false);
     outsideSteering     = new SteeringManager(this);
     objectiveManager    = new AIObjectiveManager(c);
     reactTimer          = Rand.Range(0f, reactionTime);
     sortTimer           = Rand.Range(0f, sortObjectiveInterval);
     hullVisibilityTimer = Rand.Range(0f, hullVisibilityTimer);
     InitProjSpecific();
 }
コード例 #6
0
 protected override bool Check()
 {
     if (IsOffensiveOrArrest && Mode != initialMode)
     {
         Abandon = true;
         SteeringManager.Reset();
         return false;
     }
     return IsEnemyDisabled || (!IsOffensiveOrArrest && coolDownTimer <= 0);
 }
コード例 #7
0
        private void UpdateEscape(float deltaTime)
        {
            if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed)
            {
                state = AIState.None;
                return;
            }

            SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SimPosition - selectedAiTarget.SimPosition) * 5);
            SteeringManager.SteeringWander(1.0f);
            SteeringManager.SteeringAvoid(deltaTime, 2f);
        }
コード例 #8
0
 public HumanAIController(Character c) : base(c)
 {
     if (!c.IsHuman)
     {
         throw new System.Exception($"Tried to create a human ai controller for a non-human: {c.SpeciesName}!");
     }
     insideSteering   = new IndoorsSteeringManager(this, true, false);
     outsideSteering  = new SteeringManager(this);
     objectiveManager = new AIObjectiveManager(c);
     reactTimer       = Rand.Range(0f, reactionTime);
     sortTimer        = Rand.Range(0f, sortObjectiveInterval);
     InitProjSpecific();
 }
コード例 #9
0
        public HumanAIController(Character c) : base(c)
        {
            insideSteering  = new IndoorsSteeringManager(this, true, false);
            outsideSteering = new SteeringManager(this);

            objectiveManager = new AIObjectiveManager(c);
            objectiveManager.AddObjective(new AIObjectiveFindSafety(c));
            objectiveManager.AddObjective(new AIObjectiveIdle(c));

            updateObjectiveTimer = Rand.Range(0.0f, UpdateObjectiveInterval);

            InitProjSpecific();
        }
コード例 #10
0
 protected override void OnAbandon()
 {
     base.OnAbandon();
     SteeringManager?.Reset();
     if (character.IsOnPlayerTeam && objectiveManager.CurrentOrder == objectiveManager.CurrentObjective)
     {
         string msg = TextManager.Get("dialogcannotreturn", returnNull: true);
         if (msg != null)
         {
             character.Speak(msg, identifier: "dialogcannotreturn", minDurationBetweenSimilar: 5.0f);
         }
     }
 }
コード例 #11
0
        private void Move(float deltaTime)
        {
            switch (Mode)
            {
            case CombatMode.Offensive:
            case CombatMode.Arrest:
                Engage(deltaTime);
                break;

            case CombatMode.Defensive:
                if (character.IsOnPlayerTeam && !Enemy.IsPlayer && objectiveManager.IsCurrentOrder <AIObjectiveGoTo>())
                {
                    if ((character.CurrentHull == null || character.CurrentHull == Enemy.CurrentHull) && sqrDistance < 200 * 200)
                    {
                        Engage(deltaTime);
                    }
                    else
                    {
                        // Keep following the goto target
                        var gotoObjective = objectiveManager.GetOrder <AIObjectiveGoTo>();
                        if (gotoObjective != null)
                        {
                            gotoObjective.ForceAct(deltaTime);
                            if (!character.AnimController.InWater)
                            {
                                HumanAIController.FaceTarget(Enemy);
                                ForceWalk = true;
                                HumanAIController.AutoFaceMovement = false;
                            }
                        }
                        else
                        {
                            SteeringManager.Reset();
                        }
                    }
                }
                else
                {
                    Retreat(deltaTime);
                }
                break;

            case CombatMode.Retreat:
                Retreat(deltaTime);
                break;

            default:
                throw new NotImplementedException();
            }
        }
コード例 #12
0
        protected override void Act(float deltaTime)
        {
            if (abortCondition != null && abortCondition())
            {
                Abandon = true;
                return;
            }
            if (AllowCoolDown)
            {
                coolDownTimer -= deltaTime;
            }
            if (seekAmmunitionObjective == null && seekWeaponObjective == null)
            {
                if (Mode != CombatMode.Retreat && TryArm() && !IsEnemyDisabled)
                {
                    OperateWeapon(deltaTime);
                }
                if (HoldPosition)
                {
                    SteeringManager.Reset();
                }
                else if (seekAmmunitionObjective == null && seekWeaponObjective == null)
                {
                    Move(deltaTime);
                }
                switch (Mode)
                {
                case CombatMode.Offensive:
                    if (TargetEliminated && objectiveManager.IsCurrentOrder <AIObjectiveFightIntruders>())
                    {
                        character.Speak(TextManager.Get("DialogTargetDown"), null, 3.0f, "targetdown", 30.0f);
                    }
                    break;

                case CombatMode.Arrest:
                    if (HumanAIController.HasItem(Enemy, "handlocker", out _, requireEquipped: true))
                    {
                        IsCompleted = true;
                    }
                    else if (Enemy.IsKnockedDown &&
                             !objectiveManager.IsCurrentObjective <AIObjectiveFightIntruders>() &&
                             !HumanAIController.HasItem(character, "handlocker", out _, requireEquipped: false))
                    {
                        IsCompleted = true;
                    }
                    break;
                }
            }
        }
コード例 #13
0
        public BackgroundCreature(BackgroundCreaturePrefab prefab, Vector2 position)
        {
            this.prefab = prefab;

            this.position = position;

            drawPosition = position;

            steeringManager = new SteeringManager(this);

            velocity = new Vector3(
                Rand.Range(-prefab.Speed, prefab.Speed),
                Rand.Range(-prefab.Speed, prefab.Speed),
                Rand.Range(0.0f, prefab.WanderZAmount));

            checkWallsTimer = Rand.Range(0.0f, CheckWallsInterval);
        }
コード例 #14
0
 /// <summary>
 /// Seeks for more ammunition. Creates a new subobjective.
 /// </summary>
 private void SeekAmmunition(string[] ammunitionIdentifiers)
 {
     retreatTarget = null;
     RemoveSubObjective(ref retreatObjective);
     RemoveSubObjective(ref followTargetObjective);
     TryAddSubObjective(ref seekAmmunition,
                        constructor: () => new AIObjectiveContainItem(character, ammunitionIdentifiers, Weapon.GetComponent <ItemContainer>(), objectiveManager)
     {
         targetItemCount = Weapon.GetComponent <ItemContainer>().Capacity,
         checkInventory  = false
     },
                        onAbandon: () =>
     {
         Weapon = null;
         Mode   = CombatMode.Retreat;
         SteeringManager.Reset();
     });
 }
コード例 #15
0
        private void UpdateEscape(float deltaTime)
        {
            if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed)
            {
                state = AIState.None;
                return;
            }

            Vector2 escapeDir = Vector2.Normalize(SimPosition - selectedAiTarget.SimPosition);

            if (!MathUtils.IsValid(escapeDir))
            {
                escapeDir = Vector2.UnitY;
            }
            SteeringManager.SteeringManual(deltaTime, escapeDir * 5);
            SteeringManager.SteeringWander(1.0f);
            SteeringManager.SteeringAvoid(deltaTime, 2f);
        }
コード例 #16
0
        public EnemyAIController(Character c, string file) : base(c)
        {
            targetMemories = new Dictionary <AITarget, AITargetMemory>();

            XDocument doc = ToolBox.TryLoadXml(file);

            if (doc == null || doc.Root == null)
            {
                return;
            }

            XElement aiElement = doc.Root.Element("ai");

            if (aiElement == null)
            {
                return;
            }

            attackRooms     = ToolBox.GetAttributeFloat(aiElement, 0.0f, "attackrooms", "attackpriorityrooms") / 100.0f;
            attackHumans    = ToolBox.GetAttributeFloat(aiElement, 0.0f, "attackhumans", "attackpriorityhumans") / 100.0f;
            attackWeaker    = ToolBox.GetAttributeFloat(aiElement, 0.0f, "attackweaker", "attackpriorityweaker") / 100.0f;
            attackStronger  = ToolBox.GetAttributeFloat(aiElement, 0.0f, "attackstronger", "attackprioritystronger") / 100.0f;
            eatDeadPriority = ToolBox.GetAttributeFloat(aiElement, "eatpriority", 0.0f) / 100.0f;

            combatStrength = ToolBox.GetAttributeFloat(aiElement, "combatstrength", 1.0f);

            attackCoolDown = ToolBox.GetAttributeFloat(aiElement, "attackcooldown", 5.0f);

            sight   = ToolBox.GetAttributeFloat(aiElement, "sight", 0.0f);
            hearing = ToolBox.GetAttributeFloat(aiElement, "hearing", 0.0f);

            attackWhenProvoked = ToolBox.GetAttributeBool(aiElement, "attackwhenprovoked", false);

            fleeHealthThreshold = ToolBox.GetAttributeFloat(aiElement, "fleehealththreshold", 0.0f);

            attachToWalls = ToolBox.GetAttributeBool(aiElement, "attachtowalls", false);

            outsideSteering = new SteeringManager(this);
            insideSteering  = new IndoorsSteeringManager(this, false);

            steeringManager = outsideSteering;

            state = AIState.None;
        }
コード例 #17
0
 private void Retreat(float deltaTime)
 {
     RemoveSubObjective(ref followTargetObjective);
     RemoveSubObjective(ref seekAmmunition);
     if (retreatObjective != null && retreatObjective.Target != retreatTarget)
     {
         retreatObjective = null;
     }
     if (retreatTarget == null || (retreatObjective != null && !retreatObjective.CanBeCompleted))
     {
         if (findHullTimer > 0)
         {
             findHullTimer -= deltaTime;
         }
         else
         {
             retreatTarget = findSafety.FindBestHull(HumanAIController.VisibleHulls);
             findHullTimer = findHullInterval * Rand.Range(0.9f, 1.1f);
         }
     }
     if (retreatTarget != null && character.CurrentHull != retreatTarget)
     {
         TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true),
                            onAbandon: () =>
         {
             if (Enemy != null && HumanAIController.VisibleHulls.Contains(Enemy.CurrentHull))
             {
                 // If in the same room with an enemy -> don't try to escape because we'd want to fight it
                 SteeringManager.Reset();
                 RemoveSubObjective(ref retreatObjective);
             }
             else
             {
                 // else abandon and fall back to find safety mode
                 Abandon = true;
             }
         },
                            onCompleted: () => RemoveSubObjective(ref retreatObjective));
     }
 }
コード例 #18
0
        protected override bool Check()
        {
            if (initialMode == CombatMode.Offensive && Mode != CombatMode.Offensive)
            {
                Abandon = true;
                SteeringManager.Reset();
                return(false);
            }
            bool completed = (Enemy != null && (Enemy.Removed || Enemy.IsDead)) || (initialMode != CombatMode.Offensive && coolDownTimer <= 0);

            if (completed)
            {
                if (objectiveManager.CurrentOrder == this && Enemy != null && Enemy.IsDead)
                {
                    character.Speak(TextManager.Get("DialogTargetDown"), null, 3.0f, "targetdown", 30.0f);
                }
                if (Weapon != null)
                {
                    Unequip();
                }
            }
            return(completed);
        }
コード例 #19
0
        public EnemyAIController(Character c, string file) : base(c)
        {
            targetMemories = new Dictionary <AITarget, AITargetMemory>();

            XDocument doc = ToolBox.TryLoadXml(file);

            if (doc == null || doc.Root == null)
            {
                return;
            }

            XElement aiElement = doc.Root.Element("ai");

            if (aiElement == null)
            {
                return;
            }

            attackRooms    = ToolBox.GetAttributeFloat(aiElement, "attackrooms", 0.0f) / 100.0f;
            attackHumans   = ToolBox.GetAttributeFloat(aiElement, "attackhumans", 0.0f) / 100.0f;
            attackWeaker   = ToolBox.GetAttributeFloat(aiElement, "attackweaker", 0.0f) / 100.0f;
            attackStronger = ToolBox.GetAttributeFloat(aiElement, "attackstronger", 0.0f) / 100.0f;

            attackCoolDown = ToolBox.GetAttributeFloat(aiElement, "attackcooldown", 5.0f);

            sight   = ToolBox.GetAttributeFloat(aiElement, "sight", 0.0f);
            hearing = ToolBox.GetAttributeFloat(aiElement, "hearing", 0.0f);

            attackWhenProvoked = ToolBox.GetAttributeBool(aiElement, "attackwhenprovoked", false);

            outsideSteering = new SteeringManager(this);
            insideSteering  = new IndoorsSteeringManager(this, false);

            steeringManager = outsideSteering;

            state = AiState.None;
        }
コード例 #20
0
        protected override void Act(float deltaTime)
        {
            if (followControlledCharacter)
            {
                if (Character.Controlled == null)
                {
                    abandon = true;
                    return;
                }
                Target = Character.Controlled;
            }
            if (Target == character)
            {
                character.AIController.SteeringManager.Reset();
                abandon = true;
                return;
            }
            waitUntilPathUnreachable -= deltaTime;
            if (!character.IsClimbing)
            {
                character.SelectedConstruction = null;
            }
            if (Target is Entity e)
            {
                if (e.Removed)
                {
                    abandon = true;
                }
                else
                {
                    character.AIController.SelectTarget(e.AiTarget);
                }
            }
            bool isInside        = character.CurrentHull != null;
            bool insideSteering  = SteeringManager == PathSteering && PathSteering.CurrentPath != null && !PathSteering.IsPathDirty;
            var  targetHull      = Target is Hull h ? h : Target is Item i ? i.CurrentHull : Target is Character c ? c.CurrentHull : character.CurrentHull;
            bool targetIsOutside = (Target != null && targetHull == null) || (insideSteering && PathSteering.CurrentPath.HasOutdoorsNodes);

            if (isInside && targetIsOutside && !AllowGoingOutside)
            {
                abandon = true;
            }
            else if (waitUntilPathUnreachable < 0)
            {
                if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable)
                {
                    if (repeat)
                    {
                        SteeringManager.Reset();
                    }
                    else
                    {
                        abandon = true;
                    }
                }
            }
            if (abandon)
            {
#if DEBUG
                DebugConsole.NewMessage($"{character.Name}: Cannot reach the target: {Target.ToString()}", Color.Yellow);
#endif
                if (objectiveManager.CurrentOrder != null)
                {
                    character.Speak(TextManager.Get("DialogCannotReach"), identifier: "cannotreach", minDurationBetweenSimilar: 10.0f);
                }
                character.AIController.SteeringManager.Reset();
            }
            else
            {
                Vector2 currTargetSimPos = Vector2.Zero;
                currTargetSimPos = Target.SimPosition;
                // Take the sub position into account in the sim pos
                if (SteeringManager != PathSteering && character.Submarine == null && Target.Submarine != null)
                {
                    currTargetSimPos += Target.Submarine.SimPosition;
                }
                else if (character.Submarine != null && Target.Submarine == null)
                {
                    currTargetSimPos -= character.Submarine.SimPosition;
                }
                else if (character.Submarine != Target.Submarine)
                {
                    if (character.Submarine != null && Target.Submarine != null)
                    {
                        Vector2 diff = character.Submarine.SimPosition - Target.Submarine.SimPosition;
                        currTargetSimPos -= diff;
                    }
                }
                character.AIController.SteeringManager.SteeringSeek(currTargetSimPos);
                if (SteeringManager != PathSteering)
                {
                    SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1, heading: VectorExtensions.Forward(character.AnimController.Collider.Rotation));
                }
                if (getDivingGearIfNeeded)
                {
                    Character followTarget    = Target as Character;
                    bool      needsDivingGear = HumanAIController.NeedsDivingGear(targetHull) || mimic && HumanAIController.HasDivingMask(followTarget);
                    bool      needsDivingSuit = needsDivingGear && (targetHull == null || targetIsOutside || targetHull.WaterPercentage > 90) || mimic && HumanAIController.HasDivingSuit(followTarget);
                    bool      needsEquipment  = false;
                    if (needsDivingSuit)
                    {
                        needsEquipment = !HumanAIController.HasDivingSuit(character);
                    }
                    else if (needsDivingGear)
                    {
                        needsEquipment = !HumanAIController.HasDivingMask(character);
                    }
                    if (needsEquipment)
                    {
                        TryAddSubObjective(ref findDivingGear, () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager));
                    }
                }
            }
        }
コード例 #21
0
        private void GiveTreatment(float deltaTime)
        {
            if (targetCharacter == null)
            {
                string errorMsg = $"{character.Name}: Attempted to update a Rescue objective with no target!";
                DebugConsole.ThrowError(errorMsg);
                Abandon = true;
                return;
            }

            SteeringManager?.Reset();

            if (!targetCharacter.IsPlayer)
            {
                // If the target is a bot, don't let it move
                targetCharacter.AIController?.SteeringManager?.Reset();
            }
            if (treatmentTimer > 0.0f)
            {
                treatmentTimer -= deltaTime;
                return;
            }
            treatmentTimer = TreatmentDelay;

            float cprSuitability = targetCharacter.Oxygen < 0.0f ? -targetCharacter.Oxygen * 100.0f : 0.0f;

            //find which treatments are the most suitable to treat the character's current condition
            targetCharacter.CharacterHealth.GetSuitableTreatments(currentTreatmentSuitabilities, normalize: false);

            //check if we already have a suitable treatment for any of the afflictions
            foreach (Affliction affliction in GetSortedAfflictions(targetCharacter))
            {
                if (affliction == null)
                {
                    throw new Exception("Affliction was null");
                }
                if (affliction.Prefab == null)
                {
                    throw new Exception("Affliction prefab was null");
                }
                foreach (KeyValuePair <string, float> treatmentSuitability in affliction.Prefab.TreatmentSuitability)
                {
                    if (currentTreatmentSuitabilities.ContainsKey(treatmentSuitability.Key) && currentTreatmentSuitabilities[treatmentSuitability.Key] > 0.0f)
                    {
                        Item matchingItem = character.Inventory.FindItemByIdentifier(treatmentSuitability.Key, true);
                        if (matchingItem == null)
                        {
                            continue;
                        }
                        if (targetCharacter != character)
                        {
                            character.SelectCharacter(targetCharacter);
                        }
                        ApplyTreatment(affliction, matchingItem);
                        //wait a bit longer after applying a treatment to wait for potential side-effects to manifest
                        treatmentTimer = TreatmentDelay * 4;
                        return;
                    }
                }
            }
            // Find treatments outside of own inventory only if inside the own sub.
            if (character.Submarine != null && character.Submarine.TeamID == character.TeamID)
            {
                //didn't have any suitable treatments available, try to find some medical items
                if (currentTreatmentSuitabilities.Any(s => s.Value > cprSuitability))
                {
                    itemNameList.Clear();
                    suitableItemIdentifiers.Clear();
                    foreach (KeyValuePair <string, float> treatmentSuitability in currentTreatmentSuitabilities)
                    {
                        if (treatmentSuitability.Value <= cprSuitability)
                        {
                            continue;
                        }
                        if (MapEntityPrefab.Find(null, treatmentSuitability.Key, showErrorMessages: false) is ItemPrefab itemPrefab)
                        {
                            if (!Item.ItemList.Any(it => it.prefab.Identifier == treatmentSuitability.Key))
                            {
                                continue;
                            }
                            suitableItemIdentifiers.Add(treatmentSuitability.Key);
                            //only list the first 4 items
                            if (itemNameList.Count < 4)
                            {
                                itemNameList.Add(itemPrefab.Name);
                            }
                        }
                    }
                    if (itemNameList.Any())
                    {
                        string itemListStr = "";
                        if (itemNameList.Count == 1)
                        {
                            itemListStr = itemNameList[0];
                        }
                        else
                        {
                            itemListStr = string.Join(" or ", string.Join(", ", itemNameList.Take(itemNameList.Count - 1)), itemNameList.Last());
                        }
                        if (targetCharacter != character && character.IsOnPlayerTeam)
                        {
                            character.Speak(TextManager.GetWithVariables("DialogListRequiredTreatments", new string[2] {
                                "[targetname]", "[treatmentlist]"
                            },
                                                                         new string[2] {
                                targetCharacter.Name, itemListStr
                            }, new bool[2] {
                                false, true
                            }),
                                            null, 2.0f, "listrequiredtreatments" + targetCharacter.Name, 60.0f);
                        }
                        RemoveSubObjective(ref getItemObjective);
                        TryAddSubObjective(ref getItemObjective,
                                           constructor: () => new AIObjectiveGetItem(character, suitableItemIdentifiers.ToArray(), objectiveManager, equip: true, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC),
                                           onCompleted: () => RemoveSubObjective(ref getItemObjective),
                                           onAbandon: () =>
                        {
                            Abandon = true;
                            if (character != targetCharacter && character.IsOnPlayerTeam)
                            {
                                character.Speak(TextManager.GetWithVariable("dialogcannottreatpatient", "[name]", targetCharacter.DisplayName, formatCapitals: false), identifier: "cannottreatpatient", minDurationBetweenSimilar: 20.0f);
                            }
                        });
                    }
                    else if (cprSuitability <= 0)
                    {
                        character.Speak(TextManager.GetWithVariable("dialogcannottreatpatient", "[name]", targetCharacter.DisplayName, formatCapitals: false), identifier: "cannottreatpatient", minDurationBetweenSimilar: 20.0f);
                        Abandon = true;
                    }
                }
            }
            else if (!targetCharacter.IsUnconscious)
            {
                //no suitable treatments found, not inside our own sub (= can't search for more treatments), the target isn't unconscious (= can't give CPR)
                character.Speak(TextManager.GetWithVariable("dialogcannottreatpatient", "[name]", targetCharacter.DisplayName, formatCapitals: false), identifier: "cannottreatpatient", minDurationBetweenSimilar: 20.0f);
                Abandon = true;
                return;
            }
            if (character != targetCharacter)
            {
                if (cprSuitability > 0.0f)
                {
                    character.SelectCharacter(targetCharacter);
                    character.AnimController.Anim = AnimController.Animation.CPR;
                }
                else
                {
                    character.DeselectCharacter();
                }
            }
        }
コード例 #22
0
        protected override void Act(float deltaTime)
        {
            if (PathSteering == null)
            {
                return;
            }

            //don't keep dragging others when idling
            if (character.SelectedCharacter != null)
            {
                character.DeselectCharacter();
            }
            if (!character.IsClimbing)
            {
                character.SelectedConstruction = null;
            }

            bool currentHullForbidden = IsForbidden(character.CurrentHull);

            if (!currentHullForbidden && !character.AnimController.InWater && !character.IsClimbing && HumanAIController.ObjectiveManager.WaitTimer > 0)
            {
                SteeringManager.Reset();
                return;
            }

            bool currentTargetIsInvalid = currentTarget == null || IsForbidden(currentTarget) ||
                                          (PathSteering.CurrentPath != null && PathSteering.CurrentPath.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull)));

            if (currentTargetIsInvalid || (currentTarget == null && currentHullForbidden))
            {
                newTargetTimer  = 0;
                standStillTimer = 0;
            }
            else if (character.IsClimbing)
            {
                if (currentTarget == null)
                {
                    newTargetTimer = 0;
                }
                else
                {
                    // Don't allow new targets when climbing.
                    newTargetTimer = Math.Max(newTargetIntervalMin, newTargetTimer);
                }
            }
            else if (character.AnimController.InWater)
            {
                if (currentTarget == null)
                {
                    newTargetTimer = 0;
                }
            }
            if (newTargetTimer <= 0.0f)
            {
                if (!searchingNewHull)
                {
                    //find all available hulls first
                    FindTargetHulls();
                    searchingNewHull = true;
                    return;
                }
                else if (targetHulls.Count > 0)
                {
                    //choose a random available hull
                    var randomHull = ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced);

                    bool isCurrentHullOK = !HumanAIController.UnsafeHulls.Contains(character.CurrentHull) && !IsForbidden(character.CurrentHull);
                    if (isCurrentHullOK)
                    {
                        // Check that there is no unsafe or forbidden hulls on the way to the target
                        // Only do this when the current hull is ok, because otherwise the would block all paths from the current hull to the target hull.
                        var path = PathSteering.PathFinder.FindPath(character.SimPosition, randomHull.SimPosition);
                        if (path.Unreachable ||
                            path.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull) || IsForbidden(n.CurrentHull)))
                        {
                            //can't go to this room, remove it from the list and try another room next frame
                            int index = targetHulls.IndexOf(randomHull);
                            targetHulls.RemoveAt(index);
                            hullWeights.RemoveAt(index);
                            PathSteering.Reset();
                            return;
                        }
                    }
                    currentTarget    = randomHull;
                    searchingNewHull = false;
                }

                if (currentTarget != null)
                {
                    character.AIController.SelectTarget(currentTarget.AiTarget);
                    string errorMsg = null;
#if DEBUG
                    bool isRoomNameFound = currentTarget.RoomName != null;
                    errorMsg = "(Character " + character.Name + " idling, target " + (isRoomNameFound ? currentTarget.RoomName : currentTarget.ToString()) + ")";
#endif
                    var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsg);
                    PathSteering.SetPath(path);
                }

                newTargetTimer = currentTarget != null && character.AnimController.InWater ? newTargetIntervalMin : Rand.Range(newTargetIntervalMin, newTargetIntervalMax);
            }

            newTargetTimer -= deltaTime;

            //wander randomly
            // - if reached the end of the path
            // - if the target is unreachable
            // - if the path requires going outside
            if (!character.IsClimbing)
            {
                if (SteeringManager != PathSteering || (PathSteering.CurrentPath != null &&
                                                        (PathSteering.CurrentPath.NextNode == null || PathSteering.CurrentPath.Unreachable || PathSteering.CurrentPath.HasOutdoorsNodes)))
                {
                    if (!character.AnimController.InWater)
                    {
                        standStillTimer -= deltaTime;
                        if (standStillTimer > 0.0f)
                        {
                            walkDuration = Rand.Range(walkDurationMin, walkDurationMax);
                            PathSteering.Reset();
                            return;
                        }
                        if (standStillTimer < -walkDuration)
                        {
                            standStillTimer = Rand.Range(standStillMin, standStillMax);
                        }
                    }
                    Wander(deltaTime);
                    return;
                }
            }

            if (currentTarget != null)
            {
                character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition);
            }
        }
コード例 #23
0
 private void Escape(float deltaTime)
 {
     abandon = true;
     SteeringManager.Reset();
     HumanAIController.ObjectiveManager.GetObjective <AIObjectiveFindSafety>().Priority = 100;
 }
コード例 #24
0
 private void Abandon(float deltaTime)
 {
     abandon = true;
     SteeringManager.Reset();
 }
コード例 #25
0
 private void UpdateEscape(float deltaTime)
 {
     SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SimPosition - selectedAiTarget.SimPosition) * 5);
     SteeringManager.SteeringWander(1.0f);
     SteeringManager.SteeringAvoid(deltaTime, 2f);
 }
コード例 #26
0
        protected override void Act(float deltaTime)
        {
            if (followControlledCharacter)
            {
                if (Character.Controlled == null)
                {
                    Abandon = true;
                    return;
                }
                Target = Character.Controlled;
            }
            if (Target == character)
            {
                // Wait
                character.AIController.SteeringManager.Reset();
                return;
            }
            waitUntilPathUnreachable -= deltaTime;
            if (!character.IsClimbing)
            {
                character.SelectedConstruction = null;
            }
            if (Target is Entity e)
            {
                if (e.Removed)
                {
                    Abandon = true;
                }
                else
                {
                    character.AIController.SelectTarget(e.AiTarget);
                }
            }
            var targetHull = Target is Hull h ? h : Target is Item i ? i.CurrentHull : Target is Character c ? c.CurrentHull : character.CurrentHull;

            if (!followControlledCharacter)
            {
                // Abandon if going through unsafe paths. Note ignores unsafe nodes when following an order or when the objective is set to ignore unsafe hulls.
                bool containsUnsafeNodes = HumanAIController.CurrentOrder == null && !HumanAIController.ObjectiveManager.CurrentObjective.IgnoreUnsafeHulls &&
                                           PathSteering != null && PathSteering.CurrentPath != null &&
                                           PathSteering.CurrentPath.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull));
                if (containsUnsafeNodes || HumanAIController.UnreachableHulls.Contains(targetHull))
                {
                    Abandon = true;
                    SteeringManager.Reset();
                    return;
                }
            }
            bool insideSteering  = SteeringManager == PathSteering && PathSteering.CurrentPath != null && !PathSteering.IsPathDirty;
            bool isInside        = character.CurrentHull != null;
            bool targetIsOutside = (Target != null && targetHull == null) || (insideSteering && PathSteering.CurrentPath.HasOutdoorsNodes);

            if (isInside && targetIsOutside && !AllowGoingOutside)
            {
                Abandon = true;
            }
            else if (waitUntilPathUnreachable < 0)
            {
                if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable && !PathSteering.IsPathDirty)
                {
                    if (repeat)
                    {
                        SteeringManager.Reset();
                    }
                    else
                    {
                        Abandon = true;
                    }
                }
            }
            if (Abandon)
            {
#if DEBUG
                DebugConsole.NewMessage($"{character.Name}: Cannot reach the target: {Target.ToString()}", Color.Yellow);
#endif
                if (objectiveManager.CurrentOrder != null && objectiveManager.CurrentOrder.ReportFailures)
                {
                    character.Speak(TextManager.Get("DialogCannotReach"), identifier: "cannotreach", minDurationBetweenSimilar: 10.0f);
                }
                SteeringManager.Reset();
            }
            else
            {
                if (getDivingGearIfNeeded && !character.LockHands)
                {
                    Character followTarget    = Target as Character;
                    bool      needsDivingSuit = targetIsOutside;
                    bool      needsDivingGear = needsDivingSuit || HumanAIController.NeedsDivingGear(character, targetHull, out needsDivingSuit);
                    if (!needsDivingGear && mimic)
                    {
                        if (HumanAIController.HasDivingSuit(followTarget))
                        {
                            needsDivingGear = true;
                            needsDivingSuit = true;
                        }
                        else if (HumanAIController.HasDivingMask(followTarget))
                        {
                            needsDivingGear = true;
                        }
                    }
                    bool needsEquipment = false;
                    if (needsDivingSuit)
                    {
                        needsEquipment = !HumanAIController.HasDivingSuit(character, AIObjectiveFindDivingGear.lowOxygenThreshold);
                    }
                    else if (needsDivingGear)
                    {
                        needsEquipment = !HumanAIController.HasDivingGear(character, AIObjectiveFindDivingGear.lowOxygenThreshold);
                    }
                    if (needsEquipment)
                    {
                        TryAddSubObjective(ref findDivingGear, () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager),
                                           onAbandon: () => Abandon = true,
                                           onCompleted: () => RemoveSubObjective(ref findDivingGear));
                        return;
                    }
                }
                if (repeat && IsCloseEnough)
                {
                    OnCompleted();
                    return;
                }
                if (SteeringManager == PathSteering)
                {
                    Func <PathNode, bool> nodeFilter = null;
                    if (isInside && !AllowGoingOutside)
                    {
                        nodeFilter = node => node.Waypoint.CurrentHull != null;
                    }
                    PathSteering.SteeringSeek(character.GetRelativeSimPosition(Target), 1, startNodeFilter, endNodeFilter, nodeFilter);
                }
                else
                {
                    SteeringManager.SteeringSeek(character.GetRelativeSimPosition(Target), 10);
                }
                if (!insideSteering)
                {
                    SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1);
                }
            }
        }
コード例 #27
0
 private void Engage()
 {
     if (character.LockHands || Enemy == null)
     {
         Mode = CombatMode.Retreat;
         SteeringManager.Reset();
         return;
     }
     retreatTarget = null;
     RemoveSubObjective(ref retreatObjective);
     RemoveSubObjective(ref seekAmmunition);
     if (followTargetObjective != null && followTargetObjective.Target != Enemy)
     {
         RemoveFollowTarget();
     }
     TryAddSubObjective(ref followTargetObjective,
                        constructor: () => new AIObjectiveGoTo(Enemy, character, objectiveManager, repeat: true, getDivingGearIfNeeded: true, closeEnough: 50)
     {
         IgnoreIfTargetDead = true,
         DialogueIdentifier = "dialogcannotreachtarget",
         TargetName         = Enemy.DisplayName
     },
                        onAbandon: () =>
     {
         Abandon = true;
         SteeringManager.Reset();
     });
     if (followTargetObjective == null)
     {
         return;
     }
     if (Mode == CombatMode.Arrest && Enemy.Stun > 2)
     {
         if (HumanAIController.HasItem(character, "handlocker", out Item handCuffs))
         {
             if (!arrestingRegistered)
             {
                 arrestingRegistered              = true;
                 followTargetObjective.Completed += OnArrestTargetReached;
             }
             followTargetObjective.CloseEnough = 100;
         }
         else
         {
             RemoveFollowTarget();
             SteeringManager.Reset();
         }
     }
     else if (WeaponComponent == null)
     {
         RemoveFollowTarget();
         SteeringManager.Reset();
     }
     else
     {
         followTargetObjective.CloseEnough =
             WeaponComponent is RangedWeapon ? 1000 :
             WeaponComponent is MeleeWeapon mw ? mw.Range :
             WeaponComponent is RepairTool rt ? rt.Range : 50;
     }
 }