Release v0.15.12.0
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -94,14 +97,31 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
protected bool HasValidPath(bool requireNonDirty = false) =>
|
||||
steeringManager is IndoorsSteeringManager pathSteering && pathSteering.CurrentPath != null && !pathSteering.CurrentPath.Finished && !pathSteering.CurrentPath.Unreachable && (!requireNonDirty || !pathSteering.IsPathDirty);
|
||||
public bool HasValidPath(bool requireNonDirty = false, bool requireUnfinished = true) =>
|
||||
steeringManager is IndoorsSteeringManager pathSteering &&
|
||||
pathSteering.CurrentPath != null &&
|
||||
(!requireUnfinished || !pathSteering.CurrentPath.Finished) &&
|
||||
!pathSteering.CurrentPath.Unreachable &&
|
||||
(!requireNonDirty || !pathSteering.IsPathDirty);
|
||||
|
||||
public bool IsCurrentPathUnreachable => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Unreachable;
|
||||
public bool IsCurrentPathFinished => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Finished;
|
||||
|
||||
protected readonly float colliderWidth;
|
||||
protected readonly float minGapSize;
|
||||
protected readonly float colliderLength;
|
||||
protected readonly float avoidLookAheadDistance;
|
||||
|
||||
public AIController (Character c)
|
||||
{
|
||||
Character = c;
|
||||
hullVisibilityTimer = Rand.Range(0f, hullVisibilityTimer);
|
||||
Enabled = true;
|
||||
var size = Character.AnimController.Collider.GetSize();
|
||||
colliderWidth = size.X;
|
||||
colliderLength = size.Y;
|
||||
avoidLookAheadDistance = Math.Max(Math.Max(colliderWidth, colliderLength) * 3, 1.5f);
|
||||
minGapSize = ConvertUnits.ToDisplayUnits(Math.Min(colliderWidth, colliderLength));
|
||||
}
|
||||
|
||||
public virtual void OnAttacked(Character attacker, AttackResult attackResult) { }
|
||||
@@ -326,7 +346,148 @@ namespace Barotrauma
|
||||
unequippedItems.Clear();
|
||||
}
|
||||
|
||||
#region Escape
|
||||
public abstract bool Escape(float deltaTime);
|
||||
|
||||
public Gap EscapeTarget { get; private set; }
|
||||
|
||||
private readonly float escapeTargetSeekInterval = 2;
|
||||
private float escapeTimer;
|
||||
protected bool allGapsSearched;
|
||||
protected readonly HashSet<Gap> unreachableGaps = new HashSet<Gap>();
|
||||
protected bool UpdateEscape(float deltaTime, bool canAttackDoors)
|
||||
{
|
||||
IndoorsSteeringManager pathSteering = SteeringManager as IndoorsSteeringManager;
|
||||
if (allGapsSearched)
|
||||
{
|
||||
escapeTimer -= deltaTime;
|
||||
if (escapeTimer <= 0)
|
||||
{
|
||||
allGapsSearched = false;
|
||||
}
|
||||
}
|
||||
if (Character.CurrentHull != null && pathSteering != null)
|
||||
{
|
||||
// Seek exit if inside
|
||||
if (!allGapsSearched)
|
||||
{
|
||||
float closestDistance = 0;
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
{
|
||||
if (gap == null || gap.Removed) { continue; }
|
||||
if (EscapeTarget == gap) { continue; }
|
||||
if (unreachableGaps.Contains(gap)) { continue; }
|
||||
if (gap.Submarine != Character.Submarine) { continue; }
|
||||
if (gap.IsRoomToRoom) { continue; }
|
||||
float multiplier = 1;
|
||||
var door = gap.ConnectedDoor;
|
||||
if (door != null)
|
||||
{
|
||||
if (!door.CanBeTraversed)
|
||||
{
|
||||
if (!door.HasAccess(Character))
|
||||
{
|
||||
if (!canAttackDoors) { continue; }
|
||||
// Treat doors that don't have access to like they were farther, because it will take time to break them.
|
||||
multiplier = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gap.Open < 1) { continue; }
|
||||
if (gap.Size < minGapSize) { continue; }
|
||||
}
|
||||
if (gap.FlowTargetHull == Character.CurrentHull)
|
||||
{
|
||||
// If the gap is in the same room, it's close enough.
|
||||
EscapeTarget = gap;
|
||||
break;
|
||||
}
|
||||
float distance = Vector2.DistanceSquared(Character.WorldPosition, gap.WorldPosition) * multiplier;
|
||||
if (EscapeTarget == null || distance < closestDistance)
|
||||
{
|
||||
EscapeTarget = gap;
|
||||
closestDistance = distance;
|
||||
}
|
||||
}
|
||||
allGapsSearched = true;
|
||||
escapeTimer = escapeTargetSeekInterval;
|
||||
}
|
||||
else if (EscapeTarget != null && EscapeTarget.FlowTargetHull != Character.CurrentHull)
|
||||
{
|
||||
if (IsCurrentPathUnreachable)
|
||||
{
|
||||
unreachableGaps.Add(EscapeTarget);
|
||||
EscapeTarget = null;
|
||||
allGapsSearched = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (EscapeTarget != null)
|
||||
{
|
||||
var door = EscapeTarget.ConnectedDoor;
|
||||
bool isClosedDoor = door != null && !door.IsOpen;
|
||||
Vector2 diff = EscapeTarget.WorldPosition - Character.WorldPosition;
|
||||
float sqrDist = diff.LengthSquared();
|
||||
bool isClose = sqrDist < MathUtils.Pow2(100);
|
||||
if (Character.CurrentHull == null || isClose && !isClosedDoor || pathSteering == null || IsCurrentPathUnreachable || IsCurrentPathFinished)
|
||||
{
|
||||
// Very close to the target, outside, or at the end of the path -> try to steer through the gap
|
||||
SteeringManager.Reset();
|
||||
pathSteering?.ResetPath();
|
||||
Vector2 dir = Vector2.Normalize(diff);
|
||||
if (Character.CurrentHull == null || isClose)
|
||||
{
|
||||
// Outside -> steer away from the target
|
||||
if (EscapeTarget.FlowTargetHull != null)
|
||||
{
|
||||
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(EscapeTarget.WorldPosition - EscapeTarget.FlowTargetHull.WorldPosition));
|
||||
}
|
||||
else
|
||||
{
|
||||
SteeringManager.SteeringManual(deltaTime, -dir);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Still inside -> steer towards the target
|
||||
SteeringManager.SteeringManual(deltaTime, dir);
|
||||
}
|
||||
return sqrDist < MathUtils.Pow2(250);
|
||||
}
|
||||
else if (pathSteering != null)
|
||||
{
|
||||
pathSteering.SteeringSeek(EscapeTarget.SimPosition, weight: 1, minGapSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
SteeringManager.SteeringSeek(EscapeTarget.SimPosition, 10);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't find the target
|
||||
EscapeTarget = null;
|
||||
allGapsSearched = false;
|
||||
unreachableGaps.Clear();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ResetEscape()
|
||||
{
|
||||
EscapeTarget = null;
|
||||
allGapsSearched = false;
|
||||
unreachableGaps.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected virtual void OnStateChanged(AIState from, AIState to) { }
|
||||
protected virtual void OnTargetChanged(AITarget previousTarget, AITarget newTarget) { }
|
||||
|
||||
public virtual void ClientRead(IReadMessage msg) { }
|
||||
public virtual void ServerWrite(IWriteMessage msg) { }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user