(e0d673b0d) Test: Don't calculate the distance to the buttons when seeking path. Instead, check the distance when checking the doors. Allows the bots to access the Remora ballast through the door where the button is a bit farther from the door than usually.
This commit is contained in:
@@ -9,27 +9,29 @@ namespace Barotrauma
|
||||
class AIObjectiveManager
|
||||
{
|
||||
// TODO: expose
|
||||
public const float OrderPriority = 50.0f;
|
||||
public const float OrderPriority = 70;
|
||||
public const float RunPriority = 50;
|
||||
// Constantly increases the priority of the selected objective, unless overridden
|
||||
public const float baseDevotion = 2;
|
||||
|
||||
public List<AIObjective> Objectives { get; private set; }
|
||||
public List<AIObjective> Objectives { get; private set; } = new List<AIObjective>();
|
||||
|
||||
private Character character;
|
||||
|
||||
/// <summary>
|
||||
/// When set above zero, the character will stand still doing nothing until the timer runs out. Only affects idling.
|
||||
/// When set above zero, the character will stand still doing nothing until the timer runs out. Does not affect orders.
|
||||
/// </summary>
|
||||
public float WaitTimer;
|
||||
|
||||
public AIObjective CurrentOrder { get; private set; }
|
||||
public AIObjective CurrentObjective { get; private set; }
|
||||
|
||||
public bool IsCurrentObjective<T>() where T : AIObjective => CurrentObjective is T;
|
||||
|
||||
public AIObjectiveManager(Character character)
|
||||
{
|
||||
this.character = character;
|
||||
|
||||
Objectives = new List<AIObjective>();
|
||||
CreateAutonomousObjectives();
|
||||
}
|
||||
|
||||
public void AddObjective(AIObjective objective)
|
||||
@@ -46,6 +48,30 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public Dictionary<AIObjective, CoroutineHandle> DelayedObjectives { get; private set; } = new Dictionary<AIObjective, CoroutineHandle>();
|
||||
|
||||
public void CreateAutonomousObjectives()
|
||||
{
|
||||
Objectives.Clear();
|
||||
AddObjective(new AIObjectiveFindSafety(character, this), delay: Rand.Value() / 2);
|
||||
AddObjective(new AIObjectiveIdle(character, this), delay: Rand.Value() / 2);
|
||||
int objectiveCount = Objectives.Count;
|
||||
foreach (var automaticOrder in character.Info.Job.Prefab.AutomaticOrders)
|
||||
{
|
||||
var orderPrefab = Order.PrefabList.Find(o => o.AITag == automaticOrder.aiTag);
|
||||
if (orderPrefab == null) { throw new Exception("Could not find a matching prefab by ai tag: " + automaticOrder.aiTag); }
|
||||
// TODO: Similar code is used in CrewManager:815-> DRY
|
||||
var matchingItems = orderPrefab.ItemIdentifiers.Any() ?
|
||||
Item.ItemList.FindAll(it => orderPrefab.ItemIdentifiers.Contains(it.Prefab.Identifier) || it.HasTag(orderPrefab.ItemIdentifiers)) :
|
||||
Item.ItemList.FindAll(it => it.Components.Any(ic => ic.GetType() == orderPrefab.ItemComponentType));
|
||||
matchingItems.RemoveAll(it => it.Submarine != character.Submarine);
|
||||
var item = matchingItems.GetRandom();
|
||||
var order = new Order(orderPrefab, item ?? character.CurrentHull as Entity, item?.Components.FirstOrDefault(ic => ic.GetType() == orderPrefab.ItemComponentType));
|
||||
AddObjective(CreateObjective(order, automaticOrder.option, character, automaticOrder.priorityModifier), delay: Rand.Value() / 2);
|
||||
objectiveCount++;
|
||||
}
|
||||
WaitTimer = Math.Max(WaitTimer, Rand.Range(0.5f, 1f) * objectiveCount);
|
||||
}
|
||||
|
||||
public void AddObjective(AIObjective objective, float delay, Action callback = null)
|
||||
{
|
||||
if (DelayedObjectives.TryGetValue(objective, out CoroutineHandle coroutine))
|
||||
@@ -75,7 +101,7 @@ namespace Barotrauma
|
||||
{
|
||||
var previousObjective = CurrentObjective;
|
||||
var firstObjective = Objectives.FirstOrDefault();
|
||||
if (CurrentOrder != null && firstObjective != null && CurrentOrder.GetPriority(this) > firstObjective.GetPriority(this))
|
||||
if (CurrentOrder != null && firstObjective != null && CurrentOrder.GetPriority() > firstObjective.GetPriority())
|
||||
{
|
||||
CurrentObjective = CurrentOrder;
|
||||
}
|
||||
@@ -86,18 +112,24 @@ namespace Barotrauma
|
||||
if (previousObjective != CurrentObjective)
|
||||
{
|
||||
CurrentObjective?.OnSelected();
|
||||
GetObjective<AIObjectiveIdle>()?.SetRandom();
|
||||
}
|
||||
return CurrentObjective;
|
||||
}
|
||||
|
||||
public float GetCurrentPriority()
|
||||
{
|
||||
return CurrentObjective == null ? 0.0f : CurrentObjective.GetPriority(this);
|
||||
return CurrentObjective == null ? 0.0f : CurrentObjective.GetPriority();
|
||||
}
|
||||
|
||||
public void UpdateObjectives(float deltaTime)
|
||||
{
|
||||
CurrentOrder?.Update(this, deltaTime);
|
||||
CurrentOrder?.Update(deltaTime);
|
||||
if (WaitTimer > 0)
|
||||
{
|
||||
WaitTimer -= deltaTime;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < Objectives.Count; i++)
|
||||
{
|
||||
var objective = Objectives[i];
|
||||
@@ -117,7 +149,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
objective.Update(this, deltaTime);
|
||||
objective.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
GetCurrentObjective();
|
||||
@@ -127,15 +159,41 @@ namespace Barotrauma
|
||||
{
|
||||
if (Objectives.Any())
|
||||
{
|
||||
Objectives.Sort((x, y) => y.GetPriority(this).CompareTo(x.GetPriority(this)));
|
||||
Objectives.Sort((x, y) => y.GetPriority().CompareTo(x.GetPriority()));
|
||||
}
|
||||
CurrentObjective?.SortSubObjectives(this);
|
||||
CurrentObjective?.SortSubObjectives();
|
||||
}
|
||||
|
||||
public void DoCurrentObjective(float deltaTime)
|
||||
{
|
||||
if (WaitTimer > 0.0f) { WaitTimer -= deltaTime; }
|
||||
CurrentObjective?.TryComplete(deltaTime);
|
||||
if (WaitTimer <= 0)
|
||||
{
|
||||
CurrentObjective?.TryComplete(deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CurrentOrder != null)
|
||||
{
|
||||
CurrentOrder.TryComplete(deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (character.AIController is HumanAIController humanAI && humanAI.SteeringManager != null)
|
||||
{
|
||||
if (!character.AnimController.InWater &&
|
||||
!character.IsClimbing &&
|
||||
!humanAI.UnsafeHulls.Contains(character.CurrentHull) &&
|
||||
!AIObjectiveIdle.IsForbidden(character.CurrentHull))
|
||||
{
|
||||
humanAI.SteeringManager.Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentObjective?.TryComplete(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetOrder(AIObjective objective)
|
||||
@@ -145,13 +203,22 @@ namespace Barotrauma
|
||||
|
||||
public void SetOrder(Order order, string option, Character orderGiver)
|
||||
{
|
||||
CurrentOrder = null;
|
||||
if (order == null) return;
|
||||
CurrentOrder = CreateObjective(order, option, orderGiver);
|
||||
if (CurrentOrder == null)
|
||||
{
|
||||
// Recreate objectives, because some of them may be removed, if impossible to complete (e.g. due to path finding)
|
||||
CreateAutonomousObjectives();
|
||||
}
|
||||
}
|
||||
|
||||
public AIObjective CreateObjective(Order order, string option, Character orderGiver, float priorityModifier = 1)
|
||||
{
|
||||
if (order == null) { return null; }
|
||||
AIObjective newObjective;
|
||||
switch (order.AITag.ToLowerInvariant())
|
||||
{
|
||||
case "follow":
|
||||
CurrentOrder = new AIObjectiveGoTo(orderGiver, character, true)
|
||||
newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier)
|
||||
{
|
||||
CloseEnough = 1.5f,
|
||||
AllowGoingOutside = true,
|
||||
@@ -160,38 +227,41 @@ namespace Barotrauma
|
||||
};
|
||||
break;
|
||||
case "wait":
|
||||
CurrentOrder = new AIObjectiveGoTo(character, character, true)
|
||||
newObjective = new AIObjectiveGoTo(character, character, this, repeat: true, priorityModifier: priorityModifier)
|
||||
{
|
||||
AllowGoingOutside = true
|
||||
};
|
||||
break;
|
||||
case "fixleaks":
|
||||
CurrentOrder = new AIObjectiveFixLeaks(character);
|
||||
newObjective = new AIObjectiveFixLeaks(character, this, priorityModifier);
|
||||
break;
|
||||
case "chargebatteries":
|
||||
CurrentOrder = new AIObjectiveChargeBatteries(character, option);
|
||||
newObjective = new AIObjectiveChargeBatteries(character, this, option, priorityModifier);
|
||||
break;
|
||||
case "rescue":
|
||||
CurrentOrder = new AIObjectiveRescueAll(character);
|
||||
newObjective = new AIObjectiveRescueAll(character, this, priorityModifier);
|
||||
break;
|
||||
case "repairsystems":
|
||||
CurrentOrder = new AIObjectiveRepairItems(character) { RequireAdequateSkills = option != "all" };
|
||||
newObjective = new AIObjectiveRepairItems(character, this, priorityModifier) { RequireAdequateSkills = option != "all" };
|
||||
break;
|
||||
case "pumpwater":
|
||||
CurrentOrder = new AIObjectivePumpWater(character, option);
|
||||
newObjective = new AIObjectivePumpWater(character, this, option, priorityModifier: priorityModifier);
|
||||
break;
|
||||
case "extinguishfires":
|
||||
CurrentOrder = new AIObjectiveExtinguishFires(character);
|
||||
newObjective = new AIObjectiveExtinguishFires(character, this, priorityModifier);
|
||||
break;
|
||||
case "fightintruders":
|
||||
newObjective = new AIObjectiveFightIntruders(character, this, priorityModifier);
|
||||
break;
|
||||
case "steer":
|
||||
var steering = (order?.TargetEntity as Item)?.GetComponent<Steering>();
|
||||
if (steering != null) steering.PosToMaintain = steering.Item.Submarine?.WorldPosition;
|
||||
if (order.TargetItemComponent == null) return;
|
||||
CurrentOrder = new AIObjectiveOperateItem(order.TargetItemComponent, character, option, false, null, order.UseController);
|
||||
if (order.TargetItemComponent == null) { return null; }
|
||||
newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, priorityModifier: priorityModifier) { IsLoop = true };
|
||||
break;
|
||||
default:
|
||||
if (order.TargetItemComponent == null) return;
|
||||
CurrentOrder = new AIObjectiveOperateItem(order.TargetItemComponent, character, option, false, null, order.UseController);
|
||||
if (order.TargetItemComponent == null) { return null; }
|
||||
newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, priorityModifier: priorityModifier) { IsLoop = true };
|
||||
break;
|
||||
}
|
||||
return newObjective;
|
||||
|
||||
Reference in New Issue
Block a user