AI operating reactors & railguns, misc AI improvements

This commit is contained in:
Regalis
2015-11-30 19:06:27 +02:00
parent 6f2db08be0
commit 11857f894b
40 changed files with 804 additions and 272 deletions
@@ -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)