From 55eecc49d883d31d96e58dde9e6eb847c3482c51 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 8 Apr 2019 11:58:50 +0300 Subject: [PATCH] (842e6af33) Human AI needs AITargets too (not much, but they are still useful). Therefor add Type property to AITargets, so that certain targets can be treated human only and others enemy only. Implement target filtering in the Enemy AI Controller. --- .../Source/Characters/AI/AITarget.cs | 21 ++++ .../Source/Characters/AI/EnemyAIController.cs | 1 + .../AI/Objectives/AIObjectiveIdle.cs | 105 +++++++++--------- 3 files changed, 77 insertions(+), 50 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs index 42f9d6515..166f89537 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs @@ -66,6 +66,22 @@ namespace Barotrauma public float MinSoundRange, MinSightRange; public float MaxSoundRange = float.MaxValue, MaxSightRange = float.MaxValue; + public TargetType Type { get; private set; } + + public enum TargetType + { + Any, + HumanOnly, + EnemyOnly + } + + public string SonarLabel; + + public bool Enabled = true; + + public float MinSoundRange, MinSightRange; + public float MaxSoundRange = float.MaxValue, MaxSightRange = float.MaxValue; + public Vector2 WorldPosition { get @@ -113,6 +129,11 @@ namespace Barotrauma MaxSightRange = element.GetAttributeFloat("maxsightrange", SightRange); MaxSoundRange = element.GetAttributeFloat("maxsoundrange", SoundRange); SonarLabel = element.GetAttributeString("sonarlabel", ""); + string typeString = element.GetAttributeString("type", "Any"); + if (Enum.TryParse(typeString, out TargetType t)) + { + Type = t; + } } public AITarget(Entity e, float sightRange = -1, float soundRange = 0) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs index fab1137c8..6a3befb3c 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs @@ -1062,6 +1062,7 @@ namespace Barotrauma { continue; } + if (target.Type == AITarget.TargetType.HumanOnly) { continue; } // Don't attack outposts. if (target.Entity.Submarine != null && target.Entity.Submarine.IsOutpost) { continue; } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs index 34d03462d..ac684c3cb 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -21,8 +21,6 @@ namespace Barotrauma private Hull currentTarget; private float newTargetTimer; - private bool searchingNewHull; - private float standStillTimer; private float walkDuration; @@ -68,41 +66,11 @@ namespace Barotrauma } 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; - } + currentTarget = FindRandomHull(); if (currentTarget != null) { + character.AIController.SelectTarget(currentTarget.AiTarget); string errorMsg = null; #if DEBUG bool isRoomNameFound = currentTarget.RoomName != null; @@ -195,27 +163,24 @@ namespace Barotrauma private readonly List targetHulls = new List(20); private readonly List hullWeights = new List(20); - private void FindTargetHulls() + private Hull FindRandomHull() { var idCard = character.Inventory.FindItemByIdentifier("idcard"); + Hull targetHull = null; bool isCurrentHullOK = !HumanAIController.UnsafeHulls.Contains(character.CurrentHull) && !IsForbidden(character.CurrentHull); - - targetHulls.Clear(); - hullWeights.Clear(); - foreach (var hull in Hull.hullList) + //random chance of navigating back to the room where the character spawned + if (Rand.Int(5) == 1 && idCard != null) { - if (HumanAIController.UnsafeHulls.Contains(hull)) { continue; } - if (hull.Submarine == null) { continue; } - if (hull.Submarine.TeamID != character.TeamID) { continue; } - // If the character is inside, only take connected hulls into account. - if (character.Submarine != null && !character.Submarine.IsEntityFoundOnThisSub(hull, true)) { continue; } - if (IsForbidden(hull)) { continue; } - // Ignore hulls that are too low to stand inside - if (character.AnimController is HumanoidAnimController animController) + foreach (WayPoint wp in WayPoint.WayPointList) { - if (hull.CeilingHeight < ConvertUnits.ToDisplayUnits(animController.HeadPosition.Value)) + if (wp.SpawnType != SpawnType.Human || wp.CurrentHull == null) { continue; } + + foreach (string tag in wp.IdCardTags) { - continue; + if (idCard.HasTag(tag)) + { + targetHull = wp.CurrentHull; + } } } if (!targetHulls.Contains(hull)) @@ -224,7 +189,47 @@ namespace Barotrauma hullWeights.Add(hull.Volume); } } - + if (targetHull == null) + { + targetHulls.Clear(); + hullWeights.Clear(); + foreach (var hull in Hull.hullList) + { + if (HumanAIController.UnsafeHulls.Contains(hull)) { continue; } + if (hull.Submarine == null) { continue; } + if (hull.Submarine.TeamID != character.TeamID) { continue; } + // If the character is inside, only take connected hulls into account. + if (character.Submarine != null && !character.Submarine.IsEntityFoundOnThisSub(hull, true)) { continue; } + if (IsForbidden(hull)) { continue; } + // Ignore hulls that are too low to stand inside + if (character.AnimController is HumanoidAnimController animController) + { + if (hull.CeilingHeight < ConvertUnits.ToDisplayUnits(animController.HeadPosition.Value)) + { + continue; + } + } + 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, hull.SimPosition); + if (path.Unreachable) { continue; } + if (path.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull) || IsForbidden(n.CurrentHull))) { continue; } + } + + // If we want to do a steering check, we should do it here, before setting the path + //if (path.Cost > 1000.0f) { continue; } + + if (!targetHulls.Contains(hull)) + { + targetHulls.Add(hull); + hullWeights.Add(hull.Volume); + } + } + return ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced); + } + return targetHull; } private bool IsForbidden(Hull hull)