Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs
Joonas Rikkonen 63eb4d64e5 f8b0295...0671290
2019-03-18 23:30:58 +02:00

199 lines
7.2 KiB
C#

using Barotrauma.Items.Components;
using System;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
class AIObjectiveManager
{
// TODO: expose
public const float OrderPriority = 50.0f;
// Constantly increases the priority of the selected objective, unless overridden
public const float baseDevotion = 2;
public List<AIObjective> Objectives { get; private set; }
private Character character;
/// <summary>
/// When set above zero, the character will stand still doing nothing until the timer runs out (assuming they don't a high priority order active)
/// </summary>
public float WaitTimer;
public AIObjective CurrentOrder { get; private set; }
public AIObjective CurrentObjective { get; private set; }
public AIObjectiveManager(Character character)
{
this.character = character;
Objectives = new List<AIObjective>();
}
public void AddObjective(AIObjective objective)
{
if (Objectives.Find(o => o.IsDuplicate(objective)) != null) return;
Objectives.Add(objective);
}
public Dictionary<AIObjective, CoroutineHandle> DelayedObjectives { get; private set; } = new Dictionary<AIObjective, CoroutineHandle>();
public void AddObjective(AIObjective objective, float delay, Action callback = null)
{
if (DelayedObjectives.TryGetValue(objective, out CoroutineHandle coroutine))
{
CoroutineManager.StopCoroutines(coroutine);
DelayedObjectives.Remove(objective);
}
coroutine = CoroutineManager.InvokeAfter(() =>
{
DelayedObjectives.Remove(objective);
AddObjective(objective);
callback?.Invoke();
}, delay);
DelayedObjectives.Add(objective, coroutine);
}
public T GetObjective<T>() where T : AIObjective
{
foreach (AIObjective objective in Objectives)
{
if (objective is T) return (T)objective;
}
return null;
}
private AIObjective GetCurrentObjective()
{
var previousObjective = CurrentObjective;
var firstObjective = Objectives.FirstOrDefault();
if (CurrentOrder != null && firstObjective != null && CurrentOrder.GetPriority(this) > firstObjective.GetPriority(this))
{
CurrentObjective = CurrentOrder;
}
else
{
CurrentObjective = firstObjective;
}
if (previousObjective != CurrentObjective)
{
CurrentObjective?.OnSelected();
}
return CurrentObjective;
}
public float GetCurrentPriority()
{
return CurrentObjective == null ? 0.0f : CurrentObjective.GetPriority(this);
}
public void UpdateObjectives(float deltaTime)
{
CurrentOrder?.Update(this, deltaTime);
for (int i = 0; i < Objectives.Count; i++)
{
var objective = Objectives[i];
if (objective.IsCompleted())
{
#if DEBUG
DebugConsole.NewMessage($"Removing objective {objective.DebugTag}, because it is completed.");
#endif
Objectives.Remove(objective);
}
else if (!objective.CanBeCompleted)
{
#if DEBUG
DebugConsole.NewMessage($"Removing objective {objective.DebugTag}, because it cannot be completed.");
#endif
Objectives.Remove(objective);
}
else
{
objective.Update(this, deltaTime);
}
}
GetCurrentObjective();
}
public void SortObjectives()
{
if (Objectives.Any())
{
Objectives.Sort((x, y) => y.GetPriority(this).CompareTo(x.GetPriority(this)));
}
CurrentObjective?.SortSubObjectives(this);
}
public void DoCurrentObjective(float deltaTime)
{
if (CurrentObjective == null || (CurrentObjective.GetPriority(this) < OrderPriority && WaitTimer > 0.0f))
{
WaitTimer -= deltaTime;
character.AIController.SteeringManager.Reset();
return;
}
CurrentObjective?.TryComplete(deltaTime);
}
public void SetOrder(AIObjective objective)
{
CurrentOrder = objective;
}
public void SetOrder(Order order, string option, Character orderGiver)
{
CurrentOrder = null;
if (order == null) return;
switch (order.AITag.ToLowerInvariant())
{
case "follow":
CurrentOrder = new AIObjectiveGoTo(orderGiver, character, true)
{
CloseEnough = 1.5f,
AllowGoingOutside = true,
IgnoreIfTargetDead = true,
FollowControlledCharacter = orderGiver == character
};
break;
case "wait":
CurrentOrder = new AIObjectiveGoTo(character, character, true)
{
AllowGoingOutside = true
};
break;
case "fixleaks":
CurrentOrder = new AIObjectiveFixLeaks(character);
break;
case "chargebatteries":
CurrentOrder = new AIObjectiveChargeBatteries(character, option);
break;
case "rescue":
CurrentOrder = new AIObjectiveRescueAll(character);
break;
case "repairsystems":
CurrentOrder = new AIObjectiveRepairItems(character) { RequireAdequateSkills = option != "all" };
break;
case "pumpwater":
CurrentOrder = new AIObjectivePumpWater(character, option);
break;
case "extinguishfires":
CurrentOrder = new AIObjectiveExtinguishFires(character);
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);
break;
default:
if (order.TargetItemComponent == null) return;
CurrentOrder = new AIObjectiveOperateItem(order.TargetItemComponent, character, option, false, null, order.UseController);
break;
}
}
}
}