(3dc4135ce) v0.9.5.1

This commit is contained in:
Regalis
2019-11-21 18:22:25 +01:00
parent b39922a074
commit 5c95c53118
287 changed files with 12655 additions and 5048 deletions
@@ -1,5 +1,6 @@
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
@@ -9,7 +10,7 @@ namespace Barotrauma
public override string DebugTag => "go to";
private AIObjectiveFindDivingGear findDivingGear;
private bool repeat;
private readonly bool repeat;
//how long until the path to the target is declared unreachable
private float waitUntilPathUnreachable;
private bool getDivingGearIfNeeded;
@@ -21,13 +22,23 @@ namespace Barotrauma
public bool followControlledCharacter;
public bool mimic;
private float _closeEnough = 50;
/// <summary>
/// Display units
/// </summary>
public float CloseEnough { get; set; } = 50;
public float CloseEnough
{
get { return _closeEnough; }
set
{
_closeEnough = Math.Max(_closeEnough, value);
}
}
public bool IgnoreIfTargetDead { get; set; }
public bool AllowGoingOutside { get; set; }
public override bool AbandonWhenCannotCompleteSubjectives => !repeat;
public ISpatialEntity Target { get; private set; }
public override float GetPriority()
@@ -42,14 +53,18 @@ namespace Barotrauma
return 1.0f;
}
public AIObjectiveGoTo(ISpatialEntity target, Character character, AIObjectiveManager objectiveManager, bool repeat = false, bool getDivingGearIfNeeded = true, float priorityModifier = 1)
public AIObjectiveGoTo(ISpatialEntity target, Character character, AIObjectiveManager objectiveManager, bool repeat = false, bool getDivingGearIfNeeded = true, float priorityModifier = 1, float closeEnough = 0)
: base (character, objectiveManager, priorityModifier)
{
this.Target = target;
this.repeat = repeat;
waitUntilPathUnreachable = 3.0f;
this.getDivingGearIfNeeded = getDivingGearIfNeeded;
CalculateCloseEnough();
CloseEnough = closeEnough;
if (Target is Item i)
{
CloseEnough = Math.Max(CloseEnough, i.InteractDistance + Math.Max(i.Rect.Width, i.Rect.Height) / 2);
}
}
protected override void Act(float deltaTime)
@@ -58,17 +73,17 @@ namespace Barotrauma
{
if (Character.Controlled == null)
{
abandon = true;
Abandon = true;
return;
}
Target = Character.Controlled;
}
if (Target == character)
{
// Wait
character.AIController.SteeringManager.Reset();
abandon = true;
return;
}
}
waitUntilPathUnreachable -= deltaTime;
if (!character.IsClimbing)
{
@@ -78,24 +93,37 @@ namespace Barotrauma
{
if (e.Removed)
{
abandon = true;
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;
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;
Abandon = true;
}
else if (waitUntilPathUnreachable < 0)
{
if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable)
if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable && !PathSteering.IsPathDirty)
{
if (repeat)
{
@@ -103,139 +131,147 @@ namespace Barotrauma
}
else
{
abandon = true;
Abandon = true;
}
}
}
if (abandon)
if (Abandon)
{
#if DEBUG
DebugConsole.NewMessage($"{character.Name}: Cannot reach the target: {Target.ToString()}", Color.Yellow);
#endif
if (objectiveManager.CurrentOrder != null)
if (objectiveManager.CurrentOrder != null && objectiveManager.CurrentOrder.ReportFailures)
{
character.Speak(TextManager.Get("DialogCannotReach"), identifier: "cannotreach", minDurationBetweenSimilar: 10.0f);
}
character.AIController.SteeringManager.Reset();
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;
}
}
if (PathSteering != null)
{
PathSteering.startNodeFilter = startNodeFilter;
PathSteering.endNodeFilter = endNodeFilter;
}
SteeringManager.SteeringSeek(currTargetSimPos);
if (SteeringManager != PathSteering)
{
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1, heading: VectorExtensions.Forward(character.AnimController.Collider.Rotation));
}
if (getDivingGearIfNeeded)
if (getDivingGearIfNeeded && !character.LockHands)
{
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 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);
needsEquipment = !HumanAIController.HasDivingSuit(character, AIObjectiveFindDivingGear.lowOxygenThreshold);
}
else if (needsDivingGear)
{
needsEquipment = !HumanAIController.HasDivingMask(character);
needsEquipment = !HumanAIController.HasDivingGear(character, AIObjectiveFindDivingGear.lowOxygenThreshold);
}
if (needsEquipment)
{
TryAddSubObjective(ref findDivingGear, () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager));
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);
}
}
}
private bool isCompleted;
public override bool IsCompleted()
private bool IsCloseEnough
{
// First check the distance
// Then the custom condition
// And finally check if can interact (heaviest)
if (isCompleted) { return true; }
if (Target == null)
{
abandon = true;
return false;
}
bool closeEnough = Vector2.DistanceSquared(Target.WorldPosition, character.WorldPosition) < CloseEnough * CloseEnough;
if (repeat)
get
{
bool closeEnough = Vector2.DistanceSquared(Target.WorldPosition, character.WorldPosition) < CloseEnough * CloseEnough;
if (closeEnough)
{
closeEnough = !(Target is Character) || Target is Character c && c.CurrentHull == character.CurrentHull;
}
if (closeEnough)
{
OnCompleted();
}
return closeEnough;
}
}
protected override bool Check()
{
if (IsCompleted) { return true; }
// First check the distance
// Then the custom condition
// And finally check if can interact (heaviest)
if (Target == null)
{
Abandon = true;
return false;
}
else if (closeEnough)
if (repeat)
{
if (requiredCondition == null || requiredCondition())
return false;
}
else
{
if (IsCloseEnough)
{
if (Target is Item item)
if (requiredCondition == null || requiredCondition())
{
if (character.CanInteractWith(item, out _, checkLinked: false)) { isCompleted = true; }
}
else if (Target is Character targetCharacter)
{
if (character.CanInteractWith(targetCharacter, CloseEnough)) { isCompleted = true; }
}
else
{
isCompleted = true;
if (Target is Item item)
{
if (character.CanInteractWith(item, out _, checkLinked: false)) { IsCompleted = true; }
}
else if (Target is Character targetCharacter)
{
if (character.CanInteractWith(targetCharacter, CloseEnough)) { IsCompleted = true; }
}
else
{
IsCompleted = true;
}
}
}
}
return isCompleted;
return IsCompleted;
}
public override bool IsDuplicate(AIObjective otherObjective)
{
if (!(otherObjective is AIObjectiveGoTo objective)) { return false; }
return objective.Target == Target;
}
private void CalculateCloseEnough()
{
float interactionDistance = Target is Item i ? i.InteractDistance + Math.Max(i.Rect.Width, i.Rect.Height) / 2 : 0;
CloseEnough = Math.Max(interactionDistance, CloseEnough);
}
protected override void OnCompleted()
private void StopMovement()
{
character.AIController.SteeringManager.Reset();
if (Target != null)
{
character.AnimController.TargetDir = Target.WorldPosition.X > character.WorldPosition.X ? Direction.Right : Direction.Left;
}
}
protected override void OnCompleted()
{
StopMovement();
HumanAIController.FaceTarget(Target);
base.OnCompleted();
}
}