AI operating reactors & railguns, misc AI improvements
This commit is contained in:
@@ -13,6 +13,8 @@ namespace Barotrauma
|
||||
|
||||
protected Character character;
|
||||
|
||||
protected string option;
|
||||
|
||||
public virtual bool IsCompleted()
|
||||
{
|
||||
return false;
|
||||
@@ -23,11 +25,23 @@ namespace Barotrauma
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public AIObjective(Character character)
|
||||
public string Option
|
||||
{
|
||||
get { return option; }
|
||||
}
|
||||
|
||||
|
||||
public AIObjective(Character character, string option)
|
||||
{
|
||||
subObjectives = new List<AIObjective>();
|
||||
|
||||
this.character = character;
|
||||
|
||||
this.option = option;
|
||||
|
||||
#if DEBUG
|
||||
IsDuplicate(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,10 +51,10 @@ namespace Barotrauma
|
||||
/// <param name="character">the character who's trying to achieve the objective</param>
|
||||
public void TryComplete(float deltaTime)
|
||||
{
|
||||
subObjectives.RemoveAll(s => s.IsCompleted());
|
||||
|
||||
foreach (AIObjective objective in subObjectives)
|
||||
{
|
||||
if (objective.IsCompleted()) continue;
|
||||
|
||||
objective.TryComplete(deltaTime);
|
||||
return;
|
||||
}
|
||||
@@ -50,6 +64,13 @@ namespace Barotrauma
|
||||
|
||||
protected virtual void Act(float deltaTime) { }
|
||||
|
||||
public void AddSubObjective(AIObjective objective)
|
||||
{
|
||||
if (subObjectives.Find(o => o.IsDuplicate(objective)) != null) return;
|
||||
|
||||
subObjectives.Add(objective);
|
||||
}
|
||||
|
||||
public virtual float GetPriority(Character character)
|
||||
{
|
||||
return 0.0f;
|
||||
@@ -57,7 +78,12 @@ namespace Barotrauma
|
||||
|
||||
public virtual bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
#if DEBUG
|
||||
throw new NotImplementedException();
|
||||
#else
|
||||
return (this.GetType() == otherObjective.GetType());
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveContainItem: AIObjective
|
||||
{
|
||||
private string itemName;
|
||||
|
||||
private ItemContainer container;
|
||||
|
||||
bool canBeCompleted;
|
||||
|
||||
bool isCompleted;
|
||||
|
||||
|
||||
public AIObjectiveContainItem(Character character, string itemName, ItemContainer container)
|
||||
: base (character, "")
|
||||
{
|
||||
this.itemName = itemName;
|
||||
this.container = container;
|
||||
|
||||
//check if the container has room for more items
|
||||
canBeCompleted = false;
|
||||
foreach (Item contained in container.inventory.Items)
|
||||
{
|
||||
if (contained != null) continue;
|
||||
canBeCompleted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (isCompleted) return;
|
||||
|
||||
//get the item that should be contained
|
||||
var itemToContain = character.Inventory.FindItem(itemName);
|
||||
if (itemToContain == null)
|
||||
{
|
||||
AddSubObjective(new AIObjectiveGetItem(character, itemName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Vector2.Distance(character.SimPosition, container.Item.SimPosition) > container.Item.PickDistance
|
||||
|| !container.Item.IsInsideTrigger(character.Position))
|
||||
{
|
||||
AddSubObjective(new AIObjectiveGoTo(container.Item.SimPosition, character));
|
||||
return;
|
||||
}
|
||||
|
||||
container.Combine(itemToContain);
|
||||
isCompleted = true;
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
AIObjectiveContainItem objective = otherObjective as AIObjectiveContainItem;
|
||||
return (objective != null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,21 +8,21 @@ namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveFindSafety : AIObjective
|
||||
{
|
||||
const float SearchHullInterval = 1.0f;
|
||||
const float SearchHullInterval = 3.0f;
|
||||
const float MinSafety = 50.0f;
|
||||
|
||||
AIObjectiveGoTo gotoObjective;
|
||||
|
||||
private List<AITarget> unreachable;
|
||||
private List<Hull> unreachable;
|
||||
|
||||
float currenthullSafety;
|
||||
|
||||
float searchHullTimer;
|
||||
|
||||
public AIObjectiveFindSafety(Character character)
|
||||
: base(character)
|
||||
: base(character, "")
|
||||
{
|
||||
unreachable = new List<AITarget>();
|
||||
unreachable = new List<Hull>();
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
@@ -44,6 +44,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
|
||||
|
||||
Hull bestHull = null;
|
||||
float bestValue = currenthullSafety;
|
||||
@@ -51,7 +52,7 @@ namespace Barotrauma
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull == character.AnimController.CurrentHull) continue;
|
||||
if (unreachable.Contains(hull.AiTarget)) continue;
|
||||
if (unreachable.Contains(hull)) continue;
|
||||
|
||||
float hullValue = GetHullSafety(hull);
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.X- hull.Position.X));
|
||||
@@ -66,7 +67,17 @@ namespace Barotrauma
|
||||
|
||||
if (bestHull != null)
|
||||
{
|
||||
gotoObjective = new AIObjectiveGoTo(bestHull.AiTarget, character);
|
||||
var path = pathSteering.PathFinder.FindPath(character.SimPosition, bestHull.SimPosition);
|
||||
if (pathSteering.CurrentPath != null && pathSteering.CurrentPath.Cost < path.Cost && !pathSteering.CurrentPath.Unreachable && gotoObjective!=null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
pathSteering.SetPath(path);
|
||||
}
|
||||
|
||||
gotoObjective = new AIObjectiveGoTo(bestHull, character);
|
||||
//character.AIController.SelectTarget(bestHull.AiTarget);
|
||||
}
|
||||
|
||||
@@ -80,7 +91,7 @@ namespace Barotrauma
|
||||
if (pathSteering!=null && pathSteering.CurrentPath!= null &&
|
||||
pathSteering.CurrentPath.Unreachable && !unreachable.Contains(gotoObjective.Target))
|
||||
{
|
||||
unreachable.Add(gotoObjective.Target);
|
||||
unreachable.Add(gotoObjective.Target as Hull);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma
|
||||
Gap leak;
|
||||
|
||||
public AIObjectiveFixLeak(Gap leak, Character character)
|
||||
:base (character)
|
||||
:base (character, "")
|
||||
{
|
||||
this.leak = leak;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public AIObjectiveGetItem(Character character, string itemName)
|
||||
: base (character)
|
||||
: base (character, "")
|
||||
{
|
||||
canBeCompleted = true;
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Barotrauma
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return character.Inventory.Items.FirstOrDefault(i => i != null && (i.HasTag(itemName) || i.Name == itemName)) != null;
|
||||
return character.Inventory.FindItem(itemName) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveGoTo : AIObjective
|
||||
{
|
||||
AITarget target;
|
||||
Entity target;
|
||||
|
||||
Vector2 targetPos;
|
||||
|
||||
@@ -26,13 +26,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public AITarget Target
|
||||
public Entity Target
|
||||
{
|
||||
get { return target; }
|
||||
}
|
||||
|
||||
public AIObjectiveGoTo(AITarget target, Character character, bool repeat = false)
|
||||
: base (character)
|
||||
public AIObjectiveGoTo(Entity target, Character character, bool repeat = false)
|
||||
: base (character, "")
|
||||
{
|
||||
this.target = target;
|
||||
this.repeat = false;
|
||||
@@ -40,14 +40,19 @@ namespace Barotrauma
|
||||
|
||||
|
||||
public AIObjectiveGoTo(Vector2 targetPos, Character character)
|
||||
: base(character)
|
||||
: base(character, "")
|
||||
{
|
||||
this.targetPos = targetPos;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
character.AIController.SelectTarget(target);
|
||||
if (character.SelectedConstruction!=null)
|
||||
{
|
||||
character.SelectedConstruction = null;
|
||||
}
|
||||
|
||||
if (target!=null) character.AIController.SelectTarget(target.AiTarget);
|
||||
|
||||
character.AIController.SteeringManager.SteeringSeek(
|
||||
target != null ? target.SimPosition : targetPos);
|
||||
@@ -56,7 +61,22 @@ namespace Barotrauma
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
if (repeat) return false;
|
||||
return Vector2.Distance(target != null ? target.SimPosition : ConvertUnits.ToDisplayUnits(targetPos), character.SimPosition) < 0.5f;
|
||||
|
||||
float allowedDistance = 0.5f;
|
||||
var item = target as Item;
|
||||
if (item != null) allowedDistance = Math.Max(item.PickDistance,allowedDistance);
|
||||
|
||||
return Vector2.Distance(target != null ? target.SimPosition : targetPos, character.SimPosition) < allowedDistance;
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
AIObjectiveGoTo objective = otherObjective as AIObjectiveGoTo;
|
||||
if (objective == null) return false;
|
||||
|
||||
if (objective.target == target) return true;
|
||||
|
||||
return (objective.targetPos == targetPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Barotrauma
|
||||
|
||||
|
||||
|
||||
public AIObjectiveIdle(Character character) : base(character)
|
||||
public AIObjectiveIdle(Character character) : base(character, "")
|
||||
{
|
||||
|
||||
}
|
||||
@@ -26,10 +26,27 @@ namespace Barotrauma
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
|
||||
var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
|
||||
|
||||
if (newTargetTimer <= 0.0f)
|
||||
{
|
||||
currentTarget = FindRandomTarget();
|
||||
|
||||
if (currentTarget!=null)
|
||||
{
|
||||
var path = pathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition);
|
||||
if (path.Cost > 200.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
pathSteering.SetPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
newTargetTimer = currentTarget == null ? 5.0f : 10.0f;
|
||||
}
|
||||
else
|
||||
@@ -39,17 +56,27 @@ namespace Barotrauma
|
||||
|
||||
|
||||
if (currentTarget == null) return;
|
||||
|
||||
|
||||
|
||||
//wander randomly if reached the end of the path or the target is unreachable
|
||||
if (pathSteering!=null && pathSteering.CurrentPath != null &&
|
||||
(pathSteering.CurrentPath.NextNode == null || pathSteering.CurrentPath.Unreachable))
|
||||
{
|
||||
if (character.Position.X < character.AnimController.CurrentHull.Rect.X + 200.0f)
|
||||
{
|
||||
pathSteering.SteeringManual(deltaTime, Vector2.UnitX);
|
||||
}
|
||||
else if (character.Position.X > character.AnimController.CurrentHull.Rect.Right - 200.0f)
|
||||
{
|
||||
pathSteering.SteeringManual(deltaTime, -Vector2.UnitX);
|
||||
}
|
||||
|
||||
character.AIController.SteeringManager.SteeringWander(1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition);
|
||||
|
||||
var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
|
||||
if (pathSteering!=null && pathSteering.CurrentPath != null)
|
||||
{
|
||||
if (pathSteering.CurrentPath.NextNode==null || pathSteering.CurrentPath.Unreachable)
|
||||
{
|
||||
character.AIController.SteeringManager.SteeringWander(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AITarget FindRandomTarget()
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Barotrauma
|
||||
|
||||
public void UpdateObjectives()
|
||||
{
|
||||
if (currentOrder != null || !objectives.Any()) return;
|
||||
if (!objectives.Any()) return;
|
||||
|
||||
//remove completed objectives
|
||||
objectives = objectives.FindAll(o => !o.IsCompleted());
|
||||
@@ -69,7 +69,7 @@ namespace Barotrauma
|
||||
|
||||
public void DoCurrentObjective(float deltaTime)
|
||||
{
|
||||
if (currentOrder != null)
|
||||
if (currentOrder != null && (!objectives.Any() || objectives[0].GetPriority(character)<OrderPriority))
|
||||
{
|
||||
currentOrder.TryComplete(deltaTime);
|
||||
return;
|
||||
@@ -81,19 +81,18 @@ namespace Barotrauma
|
||||
|
||||
public void SetOrder(Order order, string option)
|
||||
{
|
||||
currentOrder = null;
|
||||
|
||||
switch (order.Name.ToLower())
|
||||
{
|
||||
case "follow":
|
||||
currentOrder = new AIObjectiveGoTo(Character.Controlled.AiTarget, character, true);
|
||||
break;
|
||||
case "operate reactor":
|
||||
var reactorItem = Item.ItemList.Find(i => i.GetComponent<Reactor>() != null);
|
||||
if (reactorItem == null) return;
|
||||
|
||||
currentOrder = new AIObjectiveOperateItem(reactorItem.GetComponent<Reactor>(), character);
|
||||
currentOrder = new AIObjectiveGoTo(Character.Controlled, character, true);
|
||||
break;
|
||||
default:
|
||||
currentOrder = null;
|
||||
if (order.TargetItem == null) return;
|
||||
|
||||
currentOrder = new AIObjectiveOperateItem(order.TargetItem, character, option);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,22 +10,43 @@ namespace Barotrauma
|
||||
class AIObjectiveOperateItem : AIObjective
|
||||
{
|
||||
private ItemComponent targetItem;
|
||||
private ItemComponent itemController;
|
||||
|
||||
public AIObjectiveOperateItem(ItemComponent item, Character character)
|
||||
:base (character)
|
||||
private bool isCompleted;
|
||||
|
||||
|
||||
|
||||
public AIObjectiveOperateItem(ItemComponent item, Character character, string option)
|
||||
:base (character, option)
|
||||
{
|
||||
targetItem = item;
|
||||
|
||||
var controllers = item.Item.GetConnectedComponents<Controller>();
|
||||
if (controllers.Any()) itemController = controllers[0];
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (Vector2.Distance(character.SimPosition, targetItem.Item.SimPosition) < targetItem.Item.PickDistance)
|
||||
ItemComponent target = itemController == null ? targetItem: itemController;
|
||||
|
||||
if (Vector2.Distance(character.SimPosition, target.Item.SimPosition) < target.Item.PickDistance
|
||||
|| target.Item.IsInsideTrigger(character.Position))
|
||||
{
|
||||
//targetItem.Pick(character, false, true);
|
||||
if (character.SelectedConstruction != target.Item && target.CanBeSelected)
|
||||
{
|
||||
target.Item.Pick(character, false, true);
|
||||
}
|
||||
|
||||
if (targetItem.AIOperate(deltaTime, character, this)) isCompleted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
subObjectives.Add(new AIObjectiveGoTo(targetItem.Item.SimPosition, character));
|
||||
subObjectives.Add(new AIObjectiveGoTo(target.Item, character));
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
|
||||
Reference in New Issue
Block a user