public override void Reset()
 {
     base.Reset();
     getItemObjective = null;
     goToObjective    = null;
     containedItems.Clear();
 }
示例#2
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;
     }
 }
示例#3
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;
     }
 }
示例#4
0
        public override void Update(float deltaTime)
        {
            if (isFinished)
            {
                return;
            }

            affectedNpcs = ParentEvent.GetTargets(NPCTag).Where(c => c is Character).Select(c => c as Character).ToList();

            foreach (var npc in affectedNpcs)
            {
                if (!(npc.AIController is HumanAIController humanAiController))
                {
                    continue;
                }

                if (Wait)
                {
                    gotoObjective = new AIObjectiveGoTo(npc, npc, humanAiController.ObjectiveManager, repeat: true)
                    {
                        OverridePriority = 100.0f
                    };
                    humanAiController.ObjectiveManager.AddObjective(gotoObjective);
                    humanAiController.ObjectiveManager.WaitTimer = 0.0f;
                }
                else
                {
                    if (gotoObjective != null)
                    {
                        gotoObjective.Abandon = true;
                    }
                }
            }
            isFinished = true;
        }
 public override void Reset()
 {
     base.Reset();
     getExtinguisherObjective = null;
     gotoObjective            = null;
     useExtinquisherTimer     = 0;
     sinTime = 0;
 }
示例#6
0
 public override void Reset()
 {
     base.Reset();
     goToObjective     = null;
     refuelObjective   = null;
     previousCondition = -1;
     repairTool        = null;
 }
示例#7
0
 public override void Reset()
 {
     base.Reset();
     getWeldingTool   = null;
     refuelObjective  = null;
     gotoObjective    = null;
     operateObjective = null;
 }
示例#8
0
 public override void Reset()
 {
     base.Reset();
     goToObjective          = null;
     getItemObjective       = null;
     replaceOxygenObjective = null;
     safeHull     = null;
     ignoreOxygen = false;
 }
示例#9
0
        protected override void Act(float deltaTime)
        {
            if (isCompleted)
            {
                return;
            }

            //get the item that should be contained
            Item itemToContain = null;

            foreach (string identifier in itemIdentifiers)
            {
                itemToContain = character.Inventory.FindItemByIdentifier(identifier) ?? character.Inventory.FindItemByTag(identifier);
                if (itemToContain != null && itemToContain.Condition > 0.0f)
                {
                    break;
                }
            }

            if (itemToContain == null)
            {
                getItemObjective = new AIObjectiveGetItem(character, itemIdentifiers)
                {
                    GetItemPriority             = GetItemPriority,
                    ignoredContainerIdentifiers = ignoredContainerIdentifiers
                };
                AddSubObjective(getItemObjective);
                return;
            }

            if (container.Item.ParentInventory == character.Inventory)
            {
                var containedItems = container.Inventory.Items;
                //if there's already something in the mask (empty oxygen tank?), drop it
                var existingItem = containedItems.FirstOrDefault(i => i != null);
                if (existingItem != null)
                {
                    existingItem.Drop(character);
                }

                character.Inventory.RemoveItem(itemToContain);
                container.Inventory.TryPutItem(itemToContain, null);
            }
            else
            {
                if (container.Item.CurrentHull != character.CurrentHull || (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance && !container.Item.IsInsideTrigger(character.WorldPosition)))
                {
                    goToObjective = new AIObjectiveGoTo(container.Item, character);
                    AddSubObjective(goToObjective);
                    return;
                }
                container.Combine(itemToContain);
            }

            isCompleted = true;
        }
示例#10
0
 public override void Reset()
 {
     base.Reset();
     moveInsideObjective  = null;
     moveInCaveObjective  = null;
     moveOutsideObjective = null;
     usingEscapeBehavior  = false;
     isSteeringThroughGap = false;
     HumanAIController.ResetEscape();
 }
        protected override void Act(float deltaTime)
        {
            if (isCompleted)
            {
                return;
            }

            Item itemToDecontain = null;

            //get the item that should be de-contained
            if (targetItem == null)
            {
                if (itemIdentifiers != null)
                {
                    foreach (string identifier in itemIdentifiers)
                    {
                        itemToDecontain = container.Inventory.FindItemByIdentifier(identifier) ?? container.Inventory.FindItemByTag(identifier);
                        if (itemToDecontain != null)
                        {
                            break;
                        }
                    }
                }
            }
            else
            {
                itemToDecontain = targetItem;
            }

            if (itemToDecontain == null || itemToDecontain.Container != container.Item) // Item not found or already de-contained, consider complete
            {
                isCompleted = true;
                return;
            }

            if (itemToDecontain.OwnInventory != character.Inventory && itemToDecontain.ParentInventory != character.Inventory)
            {
                if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance &&
                    !container.Item.IsInsideTrigger(character.WorldPosition))
                {
                    goToObjective = new AIObjectiveGoTo(container.Item, character);
                    AddSubObjective(goToObjective);
                    return;
                }
            }

            itemToDecontain.Drop(character);
            isCompleted = true;
        }
        public override bool IsDuplicate(AIObjective otherObjective)
        {
            AIObjectiveGoTo objective = otherObjective as AIObjectiveGoTo;

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

            if (objective.target == target)
            {
                return(true);
            }

            return(objective.targetPos == targetPos);
        }
        protected override void Act(float deltaTime)
        {
            if (isCompleted)
            {
                return;
            }

            //get the item that should be contained
            var itemToContain = character.Inventory.FindItem(itemNames);

            if (itemToContain == null)
            {
                getItemObjective = new AIObjectiveGetItem(character, itemNames);
                getItemObjective.GetItemPriority      = GetItemPriority;
                getItemObjective.IgnoreContainedItems = IgnoreAlreadyContainedItems;
                AddSubObjective(getItemObjective);
                return;
            }

            if (container.Item.ParentInventory == character.Inventory)
            {
                var containedItems = container.Inventory.Items;
                //if there's already something in the mask (empty oxygen tank?), drop it
                var existingItem = containedItems.FirstOrDefault(i => i != null);
                if (existingItem != null)
                {
                    existingItem.Drop(character);
                }

                character.Inventory.RemoveItem(itemToContain);
                container.Inventory.TryPutItem(itemToContain, null);
            }
            else
            {
                if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance &&
                    !container.Item.IsInsideTrigger(character.WorldPosition))
                {
                    goToObjective = new AIObjectiveGoTo(container.Item, character);
                    AddSubObjective(goToObjective);
                    return;
                }

                container.Combine(itemToContain);
            }

            isCompleted = true;
        }
示例#14
0
        protected override void Act(float deltaTime)
        {
            var weldingTool = character.Inventory.FindItem("Welding Tool");

            if (weldingTool == null)
            {
                AddSubObjective(new AIObjectiveGetItem(character, "Welding Tool", true));
                return;
            }
            else
            {
                var containedItems = weldingTool.ContainedItems;
                if (containedItems == null)
                {
                    return;
                }

                var fuelTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Welding Fuel Tank") && i.Condition > 0.0f);

                if (fuelTank == null)
                {
                    AddSubObjective(new AIObjectiveContainItem(character, "Welding Fuel Tank", weldingTool.GetComponent <ItemContainer>()));
                    return;
                }
            }

            var repairTool = weldingTool.GetComponent <RepairTool>();

            if (repairTool == null)
            {
                return;
            }

            Vector2 standPosition = GetStandPosition();

            if (Vector2.DistanceSquared(character.WorldPosition, leak.WorldPosition) > 100.0f * 100.0f)
            {
                var gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(standPosition), character);
                if (!gotoObjective.IsCompleted())
                {
                    AddSubObjective(gotoObjective);
                    return;
                }
            }

            AddSubObjective(new AIObjectiveOperateItem(repairTool, character, "", true, leak));
        }
示例#15
0
 private void Retreat()
 {
     RemoveSubObjective(ref followTargetObjective);
     RemoveSubObjective(ref seekAmmunition);
     if (retreatObjective != null && retreatObjective.Target != retreatTarget)
     {
         retreatObjective = null;
     }
     if (retreatTarget == null || (retreatObjective != null && !retreatObjective.CanBeCompleted))
     {
         retreatTarget = findSafety.FindBestHull(HumanAIController.VisibleHulls);
     }
     if (character.CurrentHull != retreatTarget)
     {
         TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true));
     }
 }
示例#16
0
 private void Move(float deltaTime)
 {
     // Retreat to safety
     // TODO: aggressive behaviour, chasing?
     if (retreatTarget == null || (retreatObjective != null && !retreatObjective.CanBeCompleted))
     {
         retreatTarget = HumanAIController.ObjectiveManager.GetObjective <AIObjectiveFindSafety>().FindBestHull();
     }
     if (retreatTarget != null)
     {
         if (retreatObjective == null || retreatObjective.Target != retreatTarget)
         {
             retreatObjective = new AIObjectiveGoTo(retreatTarget, character, false, true);
         }
         retreatObjective.TryComplete(deltaTime);
     }
 }
示例#17
0
 private void Retreat(float deltaTime)
 {
     if (retreatTarget == null || (retreatObjective != null && !retreatObjective.CanBeCompleted))
     {
         retreatTarget = HumanAIController.ObjectiveManager.GetObjective <AIObjectiveFindSafety>().FindBestHull(new List <Hull>()
         {
             character.CurrentHull
         });
     }
     if (retreatTarget != null)
     {
         if (retreatObjective == null || retreatObjective.Target != retreatTarget)
         {
             retreatObjective = new AIObjectiveGoTo(retreatTarget, character, false, true);
         }
         retreatObjective.TryComplete(deltaTime);
     }
 }
        protected override void Act(float deltaTime)
        {
            var currentHull = character.AnimController.CurrentHull;

            currenthullSafety = OverrideCurrentHullSafety == null?
                                GetHullSafety(currentHull, character) : (float)OverrideCurrentHullSafety;

            if (NeedsDivingGear())
            {
                if (!FindDivingGear(deltaTime))
                {
                    return;
                }
            }


            if (searchHullTimer > 0.0f)
            {
                searchHullTimer -= deltaTime;
            }
            else
            {
                var bestHull = FindBestHull();
                if (bestHull != null)
                {
                    goToObjective = new AIObjectiveGoTo(bestHull, character);
                }

                searchHullTimer = SearchHullInterval;
            }

            if (goToObjective != null)
            {
                var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
                if (pathSteering != null && pathSteering.CurrentPath != null &&
                    pathSteering.CurrentPath.Unreachable && !unreachable.Contains(goToObjective.Target))
                {
                    unreachable.Add(goToObjective.Target as Hull);
                }


                goToObjective.TryComplete(deltaTime);
            }
        }
示例#19
0
        public override void Update(float deltaTime)
        {
            if (isFinished)
            {
                return;
            }

            target = ParentEvent.GetTargets(TargetTag).FirstOrDefault();
            if (target == null)
            {
                return;
            }

            affectedNpcs = ParentEvent.GetTargets(NPCTag).Where(c => c is Character).Select(c => c as Character).ToList();
            foreach (var npc in affectedNpcs)
            {
                if (!(npc.AIController is HumanAIController humanAiController))
                {
                    continue;
                }

                if (Follow)
                {
                    var newObjective = new AIObjectiveGoTo(target, npc, humanAiController.ObjectiveManager, repeat: true)
                    {
                        OverridePriority = 100.0f
                    };
                    humanAiController.ObjectiveManager.AddObjective(newObjective);
                    humanAiController.ObjectiveManager.WaitTimer = 0.0f;
                }
                else
                {
                    foreach (var goToObjective in humanAiController.ObjectiveManager.GetActiveObjectives <AIObjectiveGoTo>())
                    {
                        if (goToObjective.Target == target)
                        {
                            goToObjective.Abandon = true;
                        }
                    }
                }
            }
            isFinished = true;
        }
示例#20
0
        protected override void Act(float deltaTime)
        {
            //target in water -> move to a dry place first
            if (targetCharacter.AnimController.InWater)
            {
                if (character.SelectedCharacter != targetCharacter)
                {
                    if (!character.CanInteractWith(targetCharacter))
                    {
                        AddSubObjective(goToObjective = new AIObjectiveGoTo(targetCharacter, character));
                    }
                    else
                    {
                        character.SelectCharacter(targetCharacter);
                    }
                }
                else
                {
                    AddSubObjective(new AIObjectiveFindSafety(character));
                }
                return;
            }

            //target not in water -> we can start applying treatment
            if (!character.CanInteractWith(targetCharacter))
            {
                AddSubObjective(goToObjective = new AIObjectiveGoTo(targetCharacter, character));
            }
            else
            {
                if (character.SelectedCharacter == null)
                {
                    character?.Speak(TextManager.Get("DialogFoundUnconsciousTarget")
                                     .Replace("[targetname]", targetCharacter.Name).Replace("[roomname]", character.CurrentHull.DisplayName),
                                     null, 1.0f,
                                     "foundunconscioustarget" + targetCharacter.Name, 60.0f);
                }

                character.SelectCharacter(targetCharacter);
                GiveTreatment(deltaTime);
            }
        }
示例#21
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));
     }
 }
示例#22
0
        private Character SpawnWatchman(Submarine outpost)
        {
            WayPoint watchmanSpawnpoint = WayPoint.WayPointList.Find(wp => wp.Submarine == outpost);

            if (watchmanSpawnpoint == null)
            {
                DebugConsole.ThrowError("Failed to spawn a watchman at the outpost. No spawnpoints found inside the outpost.");
                return(null);
            }

            string seed = outpost == Level.Loaded.StartOutpost ? map.SelectedLocation.Name : map.CurrentLocation.Name;

            Rand.SetSyncedSeed(ToolBox.StringToInt(seed));

            JobPrefab     watchmanJob      = JobPrefab.Get("watchman");
            var           variant          = Rand.Range(0, watchmanJob.Variants, Rand.RandSync.Server);
            CharacterInfo characterInfo    = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: watchmanJob, variant: variant);
            var           spawnedCharacter = Character.Create(characterInfo, watchmanSpawnpoint.WorldPosition,
                                                              Level.Loaded.Seed + (outpost == Level.Loaded.StartOutpost ? "start" : "end"));

            InitializeWatchman(spawnedCharacter);
            var objectiveManager = (spawnedCharacter.AIController as HumanAIController)?.ObjectiveManager;

            if (objectiveManager != null)
            {
                var moveOrder = new AIObjectiveGoTo(watchmanSpawnpoint, spawnedCharacter, objectiveManager, repeat: true, getDivingGearIfNeeded: false);
                moveOrder.Completed += () =>
                {
                    // Turn towards the center of the sub. Doesn't work in all possible cases, but this is the simplest solution for now.
                    spawnedCharacter.AnimController.TargetDir = spawnedCharacter.Submarine.WorldPosition.X > spawnedCharacter.WorldPosition.X ? Direction.Right : Direction.Left;
                };
                objectiveManager.SetOrder(moveOrder);
            }
            if (watchmanJob != null)
            {
                spawnedCharacter.GiveJobItems();
            }
            return(spawnedCharacter);
        }
        protected override void Act(float deltaTime)
        {
            // Only continue when the get item sub objectives have been completed.
            if (subObjectives.Any())
            {
                return;
            }
            foreach (Repairable repairable in Item.Repairables)
            {
                if (!repairable.HasRequiredItems(character, false))
                {
                    //make sure we have all the items required to fix the target item
                    foreach (var kvp in repairable.requiredItems)
                    {
                        foreach (RelatedItem requiredItem in kvp.Value)
                        {
                            subObjectives.Add(new AIObjectiveGetItem(character, requiredItem.Identifiers, objectiveManager, true));
                        }
                    }
                    return;
                }
            }
            if (repairTool == null)
            {
                FindRepairTool();
            }
            if (repairTool != null)
            {
                var containedItems = repairTool.Item.ContainedItems;
                if (containedItems == null)
                {
#if DEBUG
                    DebugConsole.ThrowError($"{character.Name}: AIObjectiveRepairItem failed - the item \"" + repairTool + "\" has no proper inventory");
#endif
                    Abandon = true;
                    return;
                }
                // Drop empty tanks
                foreach (Item containedItem in containedItems)
                {
                    if (containedItem == null)
                    {
                        continue;
                    }
                    if (containedItem.Condition <= 0.0f)
                    {
                        containedItem.Drop(character);
                    }
                }
                RelatedItem item = null;
                Item        fuel = null;
                foreach (RelatedItem requiredItem in repairTool.requiredItems[RelatedItem.RelationType.Contained])
                {
                    item = requiredItem;
                    fuel = containedItems.FirstOrDefault(it => it.Condition > 0.0f && requiredItem.MatchesItem(it));
                    if (fuel != null)
                    {
                        break;
                    }
                }
                if (fuel == null)
                {
                    RemoveSubObjective(ref goToObjective);
                    TryAddSubObjective(ref refuelObjective, () => new AIObjectiveContainItem(character, item.Identifiers, repairTool.Item.GetComponent <ItemContainer>(), objectiveManager),
                                       onCompleted: () => RemoveSubObjective(ref refuelObjective),
                                       onAbandon: () => Abandon = true);
                    return;
                }
            }
            if (character.CanInteractWith(Item, out _, checkLinked: false))
            {
                HumanAIController.FaceTarget(Item);
                if (repairTool != null)
                {
                    OperateRepairTool(deltaTime);
                }
                foreach (Repairable repairable in Item.Repairables)
                {
                    if (repairable.CurrentFixer != null && repairable.CurrentFixer != character)
                    {
                        // Someone else is repairing the target. Abandon the objective if the other is better at this than us.
                        Abandon = repairable.DegreeOfSuccess(character) < repairable.DegreeOfSuccess(repairable.CurrentFixer);
                    }
                    if (!Abandon)
                    {
                        if (character.SelectedConstruction != Item)
                        {
                            if (!Item.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true) &&
                                !Item.TryInteract(character, ignoreRequiredItems: true, forceActionKey: true))
                            {
                                Abandon = true;
                            }
                        }
                        if (previousCondition == -1)
                        {
                            previousCondition = Item.Condition;
                        }
                        else if (Item.Condition < previousCondition)
                        {
                            // If the current condition is less than the previous condition, we can't complete the task, so let's abandon it. The item is probably deteriorating at a greater speed than we can repair it.
                            Abandon = true;
                        }
                    }
                    if (Abandon)
                    {
                        if (IsRepairing)
                        {
                            character.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f);
                        }
                        repairable.StopRepairing(character);
                    }
                    else if (repairable.CurrentFixer != character)
                    {
                        repairable.StartRepairing(character, Repairable.FixActions.Repair);
                    }
                    break;
                }
            }
            else
            {
                RemoveSubObjective(ref refuelObjective);
                // If cannot reach the item, approach it.
                TryAddSubObjective(ref goToObjective,
                                   constructor: () =>
                {
                    previousCondition = -1;
                    var objective     = new AIObjectiveGoTo(Item, character, objectiveManager)
                    {
                        // Don't stop in ladders, because we can't interact with other items while holding the ladders.
                        endNodeFilter = node => node.Waypoint.Ladders == null
                    };
                    if (repairTool != null)
                    {
                        objective.CloseEnough = repairTool.Range * 0.75f;
                    }
                    return(objective);
                },
                                   onAbandon: () =>
                {
                    Abandon = true;
                    if (IsRepairing)
                    {
                        character.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f);
                    }
                });
            }
        }
示例#24
0
        public AIObjective CreateObjective(Order order, string option, Character orderGiver, float priorityModifier = 1)
        {
            if (order == null)
            {
                return(null);
            }
            AIObjective newObjective;

            switch (order.AITag.ToLowerInvariant())
            {
            case "follow":
                if (orderGiver == null)
                {
                    return(null);
                }
                newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier)
                {
                    CloseEnough               = 100,
                    AllowGoingOutside         = true,
                    IgnoreIfTargetDead        = true,
                    followControlledCharacter = orderGiver == character,
                    mimic = true
                };
                break;

            case "wait":
                newObjective = new AIObjectiveGoTo(character, character, this, repeat: true, priorityModifier: priorityModifier)
                {
                    AllowGoingOutside = true
                };
                break;

            case "fixleaks":
                newObjective = new AIObjectiveFixLeaks(character, this, priorityModifier);
                break;

            case "chargebatteries":
                newObjective = new AIObjectiveChargeBatteries(character, this, option, priorityModifier);
                break;

            case "rescue":
                newObjective = new AIObjectiveRescueAll(character, this, priorityModifier);
                break;

            case "repairsystems":
                newObjective = new AIObjectiveRepairItems(character, this, priorityModifier)
                {
                    RequireAdequateSkills = option == "jobspecific"
                };
                break;

            case "pumpwater":
                newObjective = new AIObjectivePumpWater(character, this, option, priorityModifier: priorityModifier);
                break;

            case "extinguishfires":
                newObjective = new AIObjectiveExtinguishFires(character, this, priorityModifier);
                break;

            case "fightintruders":
                newObjective = new AIObjectiveFightIntruders(character, this, priorityModifier);
                break;

            case "steer":
                var steering = (order?.TargetEntity as Item)?.GetComponent <Steering>();
                if (steering != null)
                {
                    steering.PosToMaintain = steering.Item.Submarine?.WorldPosition;
                }
                if (order.TargetItemComponent == null)
                {
                    return(null);
                }
                newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, priorityModifier: priorityModifier)
                {
                    IsLoop = true
                };
                break;

            default:
                if (order.TargetItemComponent == null)
                {
                    return(null);
                }
                newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, priorityModifier: priorityModifier)
                {
                    IsLoop = true
                };
                break;
            }
            return(newObjective);
        }
示例#25
0
        protected override void Act(float deltaTime)
        {
            FindTargetItem();
            if (targetItem == null || moveToTarget == null)
            {
                HumanAIController.ObjectiveManager.GetObjective <AIObjectiveIdle>().Wander(deltaTime);
                //SteeringManager.SteeringWander();
                return;
            }

            if (moveToTarget.CurrentHull == character.CurrentHull &&
                Vector2.DistanceSquared(character.Position, moveToTarget.Position) < MathUtils.Pow(targetItem.InteractDistance * 2, 2))
            {
                int targetSlot = -1;
                if (equip)
                {
                    var pickable = targetItem.GetComponent <Pickable>();
                    if (pickable == null)
                    {
                        canBeCompleted = false;
                        return;
                    }

                    //check if all the slots required by the item are free
                    foreach (InvSlotType slots in pickable.AllowedSlots)
                    {
                        if (slots.HasFlag(InvSlotType.Any))
                        {
                            continue;
                        }

                        for (int i = 0; i < character.Inventory.Items.Length; i++)
                        {
                            //slot not needed by the item, continue
                            if (!slots.HasFlag(character.Inventory.SlotTypes[i]))
                            {
                                continue;
                            }

                            targetSlot = i;

                            //slot free, continue
                            if (character.Inventory.Items[i] == null)
                            {
                                continue;
                            }

                            //try to move the existing item to LimbSlot.Any and continue if successful
                            if (character.Inventory.TryPutItem(character.Inventory.Items[i], character, new List <InvSlotType>()
                            {
                                InvSlotType.Any
                            }))
                            {
                                continue;
                            }

                            //if everything else fails, simply drop the existing item
                            character.Inventory.Items[i].Drop(character);
                        }
                    }
                }

                targetItem.TryInteract(character, false, true);

                if (targetSlot > -1 && !character.HasEquippedItem(targetItem))
                {
                    character.Inventory.TryPutItem(targetItem, targetSlot, false, false, character);
                }
            }
            else
            {
                if (goToObjective == null || moveToTarget != goToObjective.Target)
                {
                    //check if we're already looking for a diving gear
                    bool gettingDivingGear = (targetItem != null && targetItem.Prefab.Identifier == "divingsuit" || targetItem.HasTag("diving")) ||
                                             (itemIdentifiers != null && (itemIdentifiers.Contains("diving") || itemIdentifiers.Contains("divingsuit")));

                    //don't attempt to get diving gear to reach the destination if the item we're trying to get is diving gear
                    goToObjective = new AIObjectiveGoTo(moveToTarget, character, false, !gettingDivingGear);
                }

                goToObjective.TryComplete(deltaTime);
                if (!goToObjective.CanBeCompleted)
                {
                    targetItem   = null;
                    moveToTarget = null;
                    ignoredItems.Add(targetItem);
                }
            }
        }
示例#26
0
        public AIObjective CreateObjective(Order order, string option, Character orderGiver, bool isAutonomous, float priorityModifier = 1)
        {
            if (order == null || order.Identifier == "dismissed")
            {
                return(null);
            }
            AIObjective newObjective;

            switch (order.Identifier.ToLowerInvariant())
            {
            case "follow":
                if (orderGiver == null)
                {
                    return(null);
                }
                newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier)
                {
                    CloseEnough                = Rand.Range(90, 100) + Rand.Range(50, 70) * Math.Min(HumanAIController.CountCrew(c => c.ObjectiveManager.CurrentOrder is AIObjectiveGoTo gotoOrder && gotoOrder.Target == orderGiver, onlyBots: true), 4),
                    extraDistanceOutsideSub    = 100,
                    extraDistanceWhileSwimming = 100,
                    AllowGoingOutside          = true,
                    IgnoreIfTargetDead         = true,
                    followControlledCharacter  = true,
                    mimic = true,
                    DialogueIdentifier = "dialogcannotreachplace"
                };
                break;

            case "wait":
                newObjective = new AIObjectiveGoTo(order.TargetSpatialEntity ?? character, character, this, repeat: true, priorityModifier: priorityModifier)
                {
                    AllowGoingOutside = character.Submarine == null || (order.TargetSpatialEntity != null && character.Submarine != order.TargetSpatialEntity.Submarine)
                };
                break;

            case "fixleaks":
                newObjective = new AIObjectiveFixLeaks(character, this, priorityModifier: priorityModifier, prioritizedHull: order.TargetEntity as Hull);
                break;

            case "chargebatteries":
                newObjective = new AIObjectiveChargeBatteries(character, this, option, priorityModifier);
                break;

            case "rescue":
                newObjective = new AIObjectiveRescueAll(character, this, priorityModifier);
                break;

            case "repairsystems":
            case "repairmechanical":
            case "repairelectrical":
                newObjective = new AIObjectiveRepairItems(character, this, priorityModifier: priorityModifier, prioritizedItem: order.TargetEntity as Item)
                {
                    RelevantSkill         = order.AppropriateSkill,
                    RequireAdequateSkills = isAutonomous
                };
                break;

            case "pumpwater":
                if (order.TargetItemComponent is Pump targetPump)
                {
                    if (!order.TargetItemComponent.Item.IsInteractable(character))
                    {
                        return(null);
                    }
                    newObjective = new AIObjectiveOperateItem(targetPump, character, this, option, false, priorityModifier: priorityModifier)
                    {
                        IsLoop   = true,
                        Override = orderGiver != null && orderGiver.IsPlayer
                    };
                    // ItemComponent.AIOperate() returns false by default -> We'd have to set IsLoop = false and implement a custom override of AIOperate for the Pump.cs,
                    // if we want that the bot just switches the pump on/off and continues doing something else.
                    // If we want that the bot does the objective and then forgets about it, I think we could do the same plus dismiss when the bot is done.
                }
                else
                {
                    newObjective = new AIObjectivePumpWater(character, this, option, priorityModifier: priorityModifier);
                }
                break;

            case "extinguishfires":
                newObjective = new AIObjectiveExtinguishFires(character, this, priorityModifier);
                break;

            case "fightintruders":
                newObjective = new AIObjectiveFightIntruders(character, this, priorityModifier);
                break;

            case "steer":
                var steering = (order?.TargetEntity as Item)?.GetComponent <Steering>();
                if (steering != null)
                {
                    steering.PosToMaintain = steering.Item.Submarine?.WorldPosition;
                }
                if (order.TargetItemComponent == null)
                {
                    return(null);
                }
                if (!order.TargetItemComponent.Item.IsInteractable(character))
                {
                    return(null);
                }
                newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option,
                                                          requireEquip: false, useController: order.UseController, controller: order.ConnectedController, priorityModifier: priorityModifier)
                {
                    IsLoop = true,
                    // Don't override unless it's an order by a player
                    Override = orderGiver != null && orderGiver.IsPlayer
                };
                break;

            case "setchargepct":
                newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, false, priorityModifier: priorityModifier)
                {
                    IsLoop              = false,
                    Override            = !character.IsDismissed,
                    completionCondition = () =>
                    {
                        if (float.TryParse(option, out float pct))
                        {
                            var targetRatio  = Math.Clamp(pct, 0f, 1f);
                            var currentRatio = (order.TargetItemComponent as PowerContainer).RechargeRatio;
                            return(Math.Abs(targetRatio - currentRatio) < 0.05f);
                        }
                        return(true);
                    }
                };
                break;

            case "getitem":
                newObjective = new AIObjectiveGetItem(character, order.TargetEntity as Item ?? order.TargetItemComponent?.Item, this, false, priorityModifier: priorityModifier)
                {
                    MustBeSpecificItem = true
                };
                break;

            case "cleanupitems":
                if (order.TargetEntity is Item targetItem)
                {
                    if (targetItem.HasTag("allowcleanup") && targetItem.ParentInventory == null && targetItem.OwnInventory != null)
                    {
                        // Target all items inside the container
                        newObjective = new AIObjectiveCleanupItems(character, this, targetItem.OwnInventory.AllItems, priorityModifier);
                    }
                    else
                    {
                        newObjective = new AIObjectiveCleanupItems(character, this, targetItem, priorityModifier);
                    }
                }
                else
                {
                    newObjective = new AIObjectiveCleanupItems(character, this, priorityModifier: priorityModifier);
                }
                break;

            default:
                if (order.TargetItemComponent == null)
                {
                    return(null);
                }
                if (!order.TargetItemComponent.Item.IsInteractable(character))
                {
                    return(null);
                }
                newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option,
                                                          requireEquip: false, useController: order.UseController, controller: order.ConnectedController, priorityModifier: priorityModifier)
                {
                    IsLoop = true,
                    // Don't override unless it's an order by a player
                    Override = orderGiver != null && orderGiver.IsPlayer
                };
                if (newObjective.Abandon)
                {
                    return(null);
                }
                break;
            }
            return(newObjective);
        }
 public override void Reset()
 {
     base.Reset();
     goToObjective    = null;
     getItemObjective = null;
 }
示例#28
0
        public AIObjective CreateObjective(Order order, string option, Character orderGiver, bool isAutonomous, float priorityModifier = 1)
        {
            if (order == null)
            {
                return(null);
            }
            AIObjective newObjective;

            switch (order.Identifier.ToLowerInvariant())
            {
            case "follow":
                if (orderGiver == null)
                {
                    return(null);
                }
                newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier)
                {
                    CloseEnough               = 100,
                    AllowGoingOutside         = true,
                    IgnoreIfTargetDead        = true,
                    followControlledCharacter = orderGiver == character,
                    mimic = true,
                    DialogueIdentifier = "dialogcannotreachplace"
                };
                break;

            case "wait":
                newObjective = new AIObjectiveGoTo(order.TargetEntity ?? character, character, this, repeat: true, priorityModifier: priorityModifier)
                {
                    AllowGoingOutside = character.CurrentHull == null
                };
                break;

            case "fixleaks":
                newObjective = new AIObjectiveFixLeaks(character, this, priorityModifier: priorityModifier, prioritizedHull: order.TargetEntity as Hull);
                break;

            case "chargebatteries":
                newObjective = new AIObjectiveChargeBatteries(character, this, option, priorityModifier);
                break;

            case "rescue":
                newObjective = new AIObjectiveRescueAll(character, this, priorityModifier);
                break;

            case "repairsystems":
            case "repairmechanical":
            case "repairelectrical":
                newObjective = new AIObjectiveRepairItems(character, this, priorityModifier: priorityModifier, prioritizedItem: order.TargetEntity as Item)
                {
                    RelevantSkill         = order.AppropriateSkill,
                    RequireAdequateSkills = isAutonomous
                };
                break;

            case "pumpwater":
                if (order.TargetItemComponent is Pump targetPump)
                {
                    if (order.TargetItemComponent.Item.NonInteractable)
                    {
                        return(null);
                    }
                    newObjective = new AIObjectiveOperateItem(targetPump, character, this, option, false, priorityModifier: priorityModifier)
                    {
                        IsLoop   = true,
                        Override = orderGiver != null && orderGiver.IsPlayer
                    };
                    // ItemComponent.AIOperate() returns false by default -> We'd have to set IsLoop = false and implement a custom override of AIOperate for the Pump.cs,
                    // if we want that the bot just switches the pump on/off and continues doing something else.
                    // If we want that the bot does the objective and then forgets about it, I think we could do the same plus dismiss when the bot is done.
                }
                else
                {
                    newObjective = new AIObjectivePumpWater(character, this, option, priorityModifier: priorityModifier);
                }
                break;

            case "extinguishfires":
                newObjective = new AIObjectiveExtinguishFires(character, this, priorityModifier);
                break;

            case "fightintruders":
                newObjective = new AIObjectiveFightIntruders(character, this, priorityModifier);
                break;

            case "steer":
                var steering = (order?.TargetEntity as Item)?.GetComponent <Steering>();
                if (steering != null)
                {
                    steering.PosToMaintain = steering.Item.Submarine?.WorldPosition;
                }
                if (order.TargetItemComponent == null)
                {
                    return(null);
                }
                if (order.TargetItemComponent.Item.NonInteractable)
                {
                    return(null);
                }
                newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option,
                                                          requireEquip: false, useController: order.UseController, controller: order.ConnectedController, priorityModifier: priorityModifier)
                {
                    IsLoop = true,
                    // Don't override unless it's an order by a player
                    Override = orderGiver != null && orderGiver.IsPlayer
                };
                break;

            default:
                if (order.TargetItemComponent == null)
                {
                    return(null);
                }
                if (order.TargetItemComponent.Item.NonInteractable)
                {
                    return(null);
                }
                newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option,
                                                          requireEquip: false, useController: order.UseController, controller: order.ConnectedController, priorityModifier: priorityModifier)
                {
                    IsLoop = true,
                    // Don't override unless it's an order by a player
                    Override = orderGiver != null && orderGiver.IsPlayer
                };
                if (newObjective.Abandon)
                {
                    return(null);
                }
                break;
            }
            return(newObjective);
        }
示例#29
0
        protected override void Act(float deltaTime)
        {
            var currentHull = character.AnimController.CurrentHull;

            if (HumanAIController.NeedsDivingGear(currentHull) && divingGearObjective == null)
            {
                bool needsDivingSuit = currentHull == null || currentHull.WaterPercentage > 90;
                bool hasEquipment    = needsDivingSuit ? HumanAIController.HasDivingSuit(character) : HumanAIController.HasDivingGear(character);
                if (!hasEquipment)
                {
                    divingGearObjective = new AIObjectiveFindDivingGear(character, needsDivingSuit);
                }
            }
            if (divingGearObjective != null)
            {
                divingGearObjective.TryComplete(deltaTime);
                if (divingGearObjective.IsCompleted())
                {
                    divingGearObjective = null;
                    Priority            = 0;
                }
                else if (divingGearObjective.CanBeCompleted)
                {
                    // If diving gear objective is active and can be completed, wait for it to complete.
                    return;
                }
                else
                {
                    divingGearObjective = null;
                    // Reset the timer so that we get a safe hull target.
                    searchHullTimer = 0;
                }
            }

            if (unreachableClearTimer > 0)
            {
                unreachableClearTimer -= deltaTime;
            }
            else
            {
                unreachableClearTimer = clearUnreachableInterval;
                unreachable.Clear();
            }

            if (searchHullTimer > 0.0f)
            {
                searchHullTimer -= deltaTime;
            }
            else if (currenthullSafety < HumanAIController.HULL_SAFETY_THRESHOLD)
            {
                var bestHull = FindBestHull();
                if (bestHull != null && bestHull != currentHull)
                {
                    if (goToObjective != null)
                    {
                        if (goToObjective.Target != bestHull)
                        {
                            // If we need diving gear, we should already have it, if possible.
                            goToObjective = new AIObjectiveGoTo(bestHull, character, getDivingGearIfNeeded: false)
                            {
                                AllowGoingOutside = HumanAIController.HasDivingSuit(character)
                            };
                        }
                    }
                    else
                    {
                        goToObjective = new AIObjectiveGoTo(bestHull, character, getDivingGearIfNeeded: false)
                        {
                            AllowGoingOutside = HumanAIController.HasDivingSuit(character)
                        };
                    }
                }
                searchHullTimer = SearchHullInterval;
            }

            if (goToObjective != null)
            {
                goToObjective.TryComplete(deltaTime);
                if (!goToObjective.CanBeCompleted)
                {
                    if (!unreachable.Contains(goToObjective.Target))
                    {
                        unreachable.Add(goToObjective.Target as Hull);
                    }
                    goToObjective = null;
                    HumanAIController.ObjectiveManager.GetObjective <AIObjectiveIdle>().Wander(deltaTime);
                    //SteeringManager.SteeringWander();
                }
            }
            else if (currentHull != null)
            {
                //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;
                foreach (FireSource fireSource in currentHull.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)
                {
                    //don't run from friendly NPCs
                    if (enemy.TeamID == Character.TeamType.FriendlyNPC)
                    {
                        continue;
                    }
                    //friendly NPCs don't run away from anything but characters controlled by EnemyAIController (= monsters)
                    if (character.TeamID == Character.TeamType.FriendlyNPC && !(enemy.AIController is EnemyAIController))
                    {
                        continue;
                    }

                    if (enemy.CurrentHull == currentHull && !enemy.IsDead && !enemy.IsUnconscious &&
                        (enemy.AIController is EnemyAIController || enemy.TeamID != character.TeamID))
                    {
                        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)
                {
                    //only move if we haven't reached the edge of the room
                    if ((escapeVel.X < 0 && character.Position.X > currentHull.Rect.X + 50) ||
                        (escapeVel.X > 0 && character.Position.X < currentHull.Rect.Right - 50))
                    {
                        character.AIController.SteeringManager.SteeringManual(deltaTime, escapeVel);
                    }
                    else
                    {
                        character.AnimController.TargetDir = escapeVel.X < 0.0f ? Direction.Right : Direction.Left;
                        character.AIController.SteeringManager.Reset();
                    }
                }
                else
                {
                    character.AIController.SteeringManager.Reset();
                }
            }
        }
示例#30
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);
                }
            }
        }