(551008fc1) Abandon FixLeakObjective when the goto subobjective cannot be completed. Reset AIObjectiveLoops when the objective is activated or added. Don't clear ignored targets periodically by default. Calculate AIObjectiveGoTo CloseEnough when the objective is created. Don't use arm length in CloseEnough, because it's not used in range checks. Partial fixes to #1343.

This commit is contained in:
Joonas Rikkonen
2019-04-08 12:01:54 +03:00
parent 55eecc49d8
commit 47ee14227e
6 changed files with 56 additions and 28 deletions
@@ -140,6 +140,7 @@ namespace Barotrauma
protected virtual bool ShouldInterruptSubObjective(AIObjective subObjective) => false; protected virtual bool ShouldInterruptSubObjective(AIObjective subObjective) => false;
public virtual void OnSelected() { } public virtual void OnSelected() { }
public virtual void Reset() { }
protected abstract void Act(float deltaTime); protected abstract void Act(float deltaTime);
@@ -101,7 +101,8 @@ namespace Barotrauma
HumanAIController.AnimController.Crouching = true; HumanAIController.AnimController.Crouching = true;
} }
float reach = HumanAIController.AnimController.ArmLength + ConvertUnits.ToSimUnits(repairTool.Range); //float reach = HumanAIController.AnimController.ArmLength + ConvertUnits.ToSimUnits(repairTool.Range);
float reach = ConvertUnits.ToSimUnits(repairTool.Range);
bool cannotReach = ConvertUnits.ToSimUnits(gapDiff.Length()) > reach; bool cannotReach = ConvertUnits.ToSimUnits(gapDiff.Length()) > reach;
if (cannotReach) if (cannotReach)
{ {
@@ -110,14 +111,19 @@ namespace Barotrauma
// Check if the objective is already removed -> completed/impossible // Check if the objective is already removed -> completed/impossible
if (!subObjectives.Contains(gotoObjective)) if (!subObjectives.Contains(gotoObjective))
{ {
if (!gotoObjective.CanBeCompleted)
{
abandon = true;
}
gotoObjective = null; gotoObjective = null;
return;
} }
} }
else else
{ {
gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character) gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character)
{ {
CloseEnough = reach * 0.75f CloseEnough = reach
}; };
if (!subObjectives.Contains(gotoObjective)) if (!subObjectives.Contains(gotoObjective))
{ {
@@ -66,9 +66,12 @@ namespace Barotrauma
if (!canComplete) if (!canComplete)
{ {
#if DEBUG #if DEBUG
DebugConsole.NewMessage($"{character.Name}: Cannot reach the target."); DebugConsole.NewMessage($"{character.Name}: Cannot reach the target: {(Target != null ? Target.ToString() : TargetPos.ToString())}", Color.Yellow);
#endif #endif
character.Speak(TextManager.Get("DialogCannotReach"), identifier: "cannotreach", minDurationBetweenSimilar: 10.0f); if (HumanAIController.ObjectiveManager.CurrentOrder != null)
{
character.Speak(TextManager.Get("DialogCannotReach"), identifier: "cannotreach", minDurationBetweenSimilar: 10.0f);
}
character.AIController.SteeringManager.Reset(); character.AIController.SteeringManager.Reset();
} }
return canComplete; return canComplete;
@@ -89,6 +92,7 @@ namespace Barotrauma
waitUntilPathUnreachable = 1.0f; waitUntilPathUnreachable = 1.0f;
this.getDivingGearIfNeeded = getDivingGearIfNeeded; this.getDivingGearIfNeeded = getDivingGearIfNeeded;
CalculateCloseEnough();
} }
@@ -100,6 +104,7 @@ namespace Barotrauma
waitUntilPathUnreachable = 5.0f; waitUntilPathUnreachable = 5.0f;
this.getDivingGearIfNeeded = getDivingGearIfNeeded; this.getDivingGearIfNeeded = getDivingGearIfNeeded;
CalculateCloseEnough();
} }
protected override void Act(float deltaTime) protected override void Act(float deltaTime)
@@ -149,9 +154,10 @@ namespace Barotrauma
} }
else else
{ {
bool targetIsOutside = (Target != null && Target.Submarine == null) || bool isInside = character.CurrentHull != null;
(SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.HasOutdoorsNodes); bool insideSteering = SteeringManager == PathSteering && PathSteering.CurrentPath != null;
if (targetIsOutside && character.CurrentHull != null && !AllowGoingOutside) bool targetIsOutside = (Target != null && Target.Submarine == null) || (insideSteering && PathSteering.CurrentPath.HasOutdoorsNodes);
if (isInside && targetIsOutside && !AllowGoingOutside)
{ {
cannotReach = true; cannotReach = true;
} }
@@ -186,11 +192,8 @@ namespace Barotrauma
bool completed = false; bool completed = false;
float allowedDistance = CloseEnough;
if (Target is Item item) if (Target is Item item)
{ {
allowedDistance = Math.Max(ConvertUnits.ToSimUnits(item.InteractDistance), CloseEnough);
if (item.IsInsideTrigger(character.WorldPosition)) completed = true; if (item.IsInsideTrigger(character.WorldPosition)) completed = true;
} }
else if (Target is Character targetCharacter) else if (Target is Character targetCharacter)
@@ -198,7 +201,7 @@ namespace Barotrauma
if (character.CanInteractWith(targetCharacter)) completed = true; if (character.CanInteractWith(targetCharacter)) completed = true;
} }
completed = completed || Vector2.DistanceSquared(Target != null ? Target.SimPosition : targetPos, character.SimPosition) < allowedDistance * allowedDistance; completed = completed || Vector2.DistanceSquared(Target != null ? Target.SimPosition : targetPos, character.SimPosition) < CloseEnough * CloseEnough;
if (completed) character.AIController.SteeringManager.Reset(); if (completed) character.AIController.SteeringManager.Reset();
@@ -214,5 +217,11 @@ namespace Barotrauma
return (objective.targetPos == targetPos); return (objective.targetPos == targetPos);
} }
private void CalculateCloseEnough()
{
float interactionDistance = Target is Item i ? ConvertUnits.ToSimUnits(i.InteractDistance) : 0;
CloseEnough = Math.Max(interactionDistance, CloseEnough);
}
} }
} }
@@ -10,15 +10,16 @@ namespace Barotrauma
protected List<T> targets = new List<T>(); protected List<T> targets = new List<T>();
protected Dictionary<T, AIObjective> objectives = new Dictionary<T, AIObjective>(); protected Dictionary<T, AIObjective> objectives = new Dictionary<T, AIObjective>();
protected HashSet<T> ignoreList = new HashSet<T>(); protected HashSet<T> ignoreList = new HashSet<T>();
protected readonly float ignoreListClearInterval = 30;
private float ignoreListTimer; private float ignoreListTimer;
protected readonly float targetUpdateInterval = 2;
private float targetUpdateTimer; private float targetUpdateTimer;
// By default, doesn't clear the list automatically
protected virtual float IgnoreListClearInterval => 0;
protected virtual float TargetUpdateInterval => 2;
public AIObjectiveLoop(Character character, string option) : base(character, option) public AIObjectiveLoop(Character character, string option) : base(character, option)
{ {
FindTargets(); Reset();
CreateObjectives();
} }
protected override void Act(float deltaTime) { } protected override void Act(float deltaTime) { }
@@ -28,15 +29,18 @@ namespace Barotrauma
public override void Update(AIObjectiveManager objectiveManager, float deltaTime) public override void Update(AIObjectiveManager objectiveManager, float deltaTime)
{ {
base.Update(objectiveManager, deltaTime); base.Update(objectiveManager, deltaTime);
if (ignoreListTimer > ignoreListClearInterval) if (IgnoreListClearInterval > 0)
{ {
Reset(); if (ignoreListTimer > IgnoreListClearInterval)
{
Reset();
}
else
{
ignoreListTimer += deltaTime;
}
} }
else if (targetUpdateTimer >= TargetUpdateInterval)
{
ignoreListTimer += deltaTime;
}
if (targetUpdateTimer > targetUpdateInterval)
{ {
targetUpdateTimer = 0; targetUpdateTimer = 0;
UpdateTargets(); UpdateTargets();
@@ -52,6 +56,7 @@ namespace Barotrauma
if (!objective.Value.CanBeCompleted) if (!objective.Value.CanBeCompleted)
{ {
ignoreList.Add(target); ignoreList.Add(target);
targetUpdateTimer = TargetUpdateInterval;
} }
if (!targets.Contains(target)) if (!targets.Contains(target))
{ {
@@ -59,13 +64,13 @@ namespace Barotrauma
} }
} }
SyncRemovedObjectives(objectives, GetList()); SyncRemovedObjectives(objectives, GetList());
if (objectives.None()) if (objectives.None() && targets.Any())
{ {
CreateObjectives(); CreateObjectives();
} }
} }
private void Reset() public override void Reset()
{ {
ignoreList.Clear(); ignoreList.Clear();
ignoreListTimer = 0; ignoreListTimer = 0;
@@ -34,9 +34,15 @@ namespace Barotrauma
public void AddObjective(AIObjective objective) public void AddObjective(AIObjective objective)
{ {
if (Objectives.Find(o => o.IsDuplicate(objective)) != null) return; var duplicate = Objectives.Find(o => o.IsDuplicate(objective));
if (duplicate != null)
Objectives.Add(objective); {
duplicate.Reset();
}
else
{
Objectives.Add(objective);
}
} }
public Dictionary<AIObjective, CoroutineHandle> DelayedObjectives { get; private set; } = new Dictionary<AIObjective, CoroutineHandle>(); public Dictionary<AIObjective, CoroutineHandle> DelayedObjectives { get; private set; } = new Dictionary<AIObjective, CoroutineHandle>();
@@ -131,7 +131,8 @@ namespace Barotrauma
goToObjective = new AIObjectiveGoTo(Item, character); goToObjective = new AIObjectiveGoTo(Item, character);
if (repairTool != null) if (repairTool != null)
{ {
goToObjective.CloseEnough = (HumanAIController.AnimController.ArmLength + ConvertUnits.ToSimUnits(repairTool.Range)) * 0.75f; //goToObjective.CloseEnough = (HumanAIController.AnimController.ArmLength + ConvertUnits.ToSimUnits(repairTool.Range)) * 0.75f;
goToObjective.CloseEnough = ConvertUnits.ToSimUnits(repairTool.Range);
} }
AddSubObjective(goToObjective); AddSubObjective(goToObjective);
} }