v1.5.7.0 (Summer Update)
This commit is contained in:
+48
-25
@@ -4,21 +4,34 @@ using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
/// <summary>
|
||||
/// An objective that creates specific kinds of subobjectives for specific types of targets, and loops through those targets.
|
||||
/// For example, a cleanup objective that loops through items that need to be cleaned up, or a "fix leaks" objective that loops through leaks that need welding.
|
||||
/// </summary>
|
||||
abstract class AIObjectiveLoop<T> : AIObjective
|
||||
{
|
||||
public HashSet<T> Targets { get; private set; } = new HashSet<T>();
|
||||
public Dictionary<T, AIObjective> Objectives { get; private set; } = new Dictionary<T, AIObjective>();
|
||||
protected HashSet<T> ignoreList = new HashSet<T>();
|
||||
private float ignoreListTimer;
|
||||
private float ignoreListClearTimer;
|
||||
protected float targetUpdateTimer;
|
||||
protected virtual float TargetUpdateTimeMultiplier { get; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How often are the subobjectives synced based on the available targets?
|
||||
/// </summary>
|
||||
private float syncTimer;
|
||||
private readonly float syncTime = 1;
|
||||
|
||||
// By default, doesn't clear the list automatically
|
||||
/// <summary>
|
||||
/// By default, doesn't clear the list automatically
|
||||
/// </summary>
|
||||
protected virtual float IgnoreListClearInterval => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Contains targets that anyone in the same crew has reported about. Used for automatic the target has to be reported before it can be can be targeted, so characters don't magically know where e.g. enemies are.
|
||||
/// Ignored on orders: a bot explicitly ordered to repair leaks or fight intruders can find targets that haven't been reported.
|
||||
/// </summary>
|
||||
public HashSet<T> ReportedTargets { get; private set; } = new HashSet<T>();
|
||||
|
||||
public bool AddTarget(T target)
|
||||
@@ -28,7 +41,7 @@ namespace Barotrauma
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Filter(target))
|
||||
if (IsValidTarget(target))
|
||||
{
|
||||
ReportedTargets.Add(target);
|
||||
return true;
|
||||
@@ -42,24 +55,27 @@ namespace Barotrauma
|
||||
protected override void Act(float deltaTime) { }
|
||||
protected override bool CheckObjectiveSpecific() => false;
|
||||
public override bool CanBeCompleted => true;
|
||||
public override bool AbandonWhenCannotCompleteSubjectives => false;
|
||||
public override bool AbandonWhenCannotCompleteSubObjectives => false;
|
||||
public override bool AllowSubObjectiveSorting => true;
|
||||
public override bool AllowWhileHandcuffed => false;
|
||||
protected override bool AllowWhileHandcuffed => false;
|
||||
protected override bool AbandonIfDisallowed => false;
|
||||
|
||||
public virtual bool InverseTargetEvaluation => false;
|
||||
/// <summary>
|
||||
/// Makes the priority inversely proportional to the value returned by <see cref="GetTargetPriority"/>.
|
||||
/// In other words, gives this objective a high priority when priority of the targets is low.
|
||||
/// </summary>
|
||||
public virtual bool InverseTargetPriority => false;
|
||||
protected virtual bool ResetWhenClearingIgnoreList => true;
|
||||
protected virtual bool ForceOrderPriority => true;
|
||||
|
||||
protected virtual int MaxTargets => int.MaxValue;
|
||||
|
||||
public override bool IsLoop { get => true; set => throw new Exception("Trying to set the value for IsLoop from: " + System.Environment.StackTrace.CleanupStackTrace()); }
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
if (IgnoreListClearInterval > 0)
|
||||
{
|
||||
if (ignoreListTimer > IgnoreListClearInterval)
|
||||
if (ignoreListClearTimer > IgnoreListClearInterval)
|
||||
{
|
||||
if (ResetWhenClearingIgnoreList)
|
||||
{
|
||||
@@ -68,12 +84,12 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
ignoreList.Clear();
|
||||
ignoreListTimer = 0;
|
||||
ignoreListClearTimer = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ignoreListTimer += deltaTime;
|
||||
ignoreListClearTimer += deltaTime;
|
||||
}
|
||||
}
|
||||
if (targetUpdateTimer <= 0)
|
||||
@@ -104,14 +120,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// the timer is set between 1 and 10 seconds, depending on the priority modifier and a random +-25%
|
||||
//
|
||||
/// <summary>
|
||||
/// The timer is set between 1 and 10 seconds, depending on the priority modifier and a random +-25%
|
||||
/// </summary>
|
||||
private float CalculateTargetUpdateTimer() => targetUpdateTimer = 1 / MathHelper.Clamp(PriorityModifier * Rand.Range(0.75f, 1.25f), 0.1f, 1) * TargetUpdateTimeMultiplier;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
ignoreList.Clear();
|
||||
ignoreListTimer = 0;
|
||||
ignoreListClearTimer = 0;
|
||||
UpdateTargets();
|
||||
}
|
||||
|
||||
@@ -119,25 +138,25 @@ namespace Barotrauma
|
||||
{
|
||||
if (!IsAllowed)
|
||||
{
|
||||
HandleNonAllowed();
|
||||
HandleDisallowed();
|
||||
return Priority;
|
||||
}
|
||||
// Allow the target value to be more than 100.
|
||||
float targetValue = TargetEvaluation();
|
||||
if (InverseTargetEvaluation)
|
||||
float targetPriority = GetTargetPriority();
|
||||
if (InverseTargetPriority)
|
||||
{
|
||||
targetValue = 100 - targetValue;
|
||||
targetPriority = 100 - targetPriority;
|
||||
}
|
||||
var currentSubObjective = CurrentSubObjective;
|
||||
if (currentSubObjective != null && currentSubObjective.Priority > targetValue)
|
||||
if (currentSubObjective != null && currentSubObjective.Priority > targetPriority)
|
||||
{
|
||||
// If the priority is higher than the target value, let's just use it.
|
||||
// The priority calculation is more precise, but it takes into account things like distances,
|
||||
// so it's better not to use it if it's lower than the rougher targetValue.
|
||||
targetValue = currentSubObjective.Priority;
|
||||
targetPriority = currentSubObjective.Priority;
|
||||
}
|
||||
// If the target value is less than 1% of the max value, let's just treat it as zero.
|
||||
if (targetValue < 1)
|
||||
if (targetPriority < 1)
|
||||
{
|
||||
Priority = 0;
|
||||
}
|
||||
@@ -145,7 +164,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (objectiveManager.IsOrder(this))
|
||||
{
|
||||
Priority = ForceOrderPriority ? objectiveManager.GetOrderPriority(this) : targetValue;
|
||||
Priority = ForceOrderPriority ? objectiveManager.GetOrderPriority(this) : targetPriority;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -155,7 +174,7 @@ namespace Barotrauma
|
||||
// Allow higher prio
|
||||
max = AIObjectiveManager.EmergencyObjectivePriority;
|
||||
}
|
||||
float value = MathHelper.Clamp((CumulatedDevotion + (targetValue * PriorityModifier)) / 100, 0, 1);
|
||||
float value = MathHelper.Clamp((CumulatedDevotion + (targetPriority * PriorityModifier)) / 100, 0, 1);
|
||||
Priority = MathHelper.Lerp(0, max, value);
|
||||
}
|
||||
}
|
||||
@@ -181,7 +200,7 @@ namespace Barotrauma
|
||||
bool ignore = this is AIObjectiveChargeBatteries || this is AIObjectivePumpWater || this is AIObjectiveFindThieves;
|
||||
if (!ignore && !ReportedTargets.Contains(target)) { continue; }
|
||||
}
|
||||
if (!Filter(target)) { continue; }
|
||||
if (!IsValidTarget(target)) { continue; }
|
||||
if (!ignoreList.Contains(target))
|
||||
{
|
||||
Targets.Add(target);
|
||||
@@ -228,9 +247,13 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
protected abstract IEnumerable<T> GetList();
|
||||
|
||||
protected abstract float TargetEvaluation();
|
||||
/// <summary>
|
||||
/// Returns a priority value based on the current targets (e.g. high prio when there's lots of severe fires or leaks).
|
||||
/// The priority of this objective is based on the target priority.
|
||||
/// </summary>
|
||||
protected abstract float GetTargetPriority();
|
||||
|
||||
protected abstract AIObjective ObjectiveConstructor(T target);
|
||||
protected abstract bool Filter(T target);
|
||||
protected abstract bool IsValidTarget(T target);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user