Human AI improvements, minor UI tweaking
This commit is contained in:
@@ -27,7 +27,7 @@ namespace Barotrauma
|
||||
set { sightRange = value; }
|
||||
}
|
||||
|
||||
public Vector2 Position
|
||||
public Vector2 SimPosition
|
||||
{
|
||||
get { return Entity.SimPosition; }
|
||||
}
|
||||
|
||||
@@ -21,10 +21,7 @@ namespace Barotrauma
|
||||
//0.0 = doesn't attack targets of the type
|
||||
//positive values = attacks targets of this type
|
||||
//negative values = escapes targets of this type
|
||||
private float attackRooms;
|
||||
private float attackHumans;
|
||||
private float attackWeaker;
|
||||
private float attackStronger;
|
||||
private float attackRooms, attackHumans, attackWeaker, attackStronger;
|
||||
|
||||
private float updateTargetsTimer;
|
||||
|
||||
@@ -165,7 +162,7 @@ namespace Barotrauma
|
||||
|
||||
selectedTargetMemory.Priority -= deltaTime;
|
||||
|
||||
Vector2 attackPosition = selectedAiTarget.Position;
|
||||
Vector2 attackPosition = selectedAiTarget.SimPosition;
|
||||
if (wallAttackPos != Vector2.Zero) attackPosition = wallAttackPos;
|
||||
|
||||
if (coolDownTimer>0.0f)
|
||||
@@ -230,7 +227,7 @@ namespace Barotrauma
|
||||
targetEntity = null;
|
||||
//check if there's a wall between the target and the Character
|
||||
Vector2 rayStart = Character.AnimController.Limbs[0].SimPosition;
|
||||
Vector2 rayEnd = selectedAiTarget.Position;
|
||||
Vector2 rayEnd = selectedAiTarget.SimPosition;
|
||||
Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd);
|
||||
|
||||
if (Submarine.LastPickedFraction == 1.0f || closestBody == null)
|
||||
@@ -391,7 +388,7 @@ namespace Barotrauma
|
||||
|
||||
dist = Vector2.Distance(
|
||||
character.AnimController.Limbs[0].SimPosition,
|
||||
target.Position);
|
||||
target.SimPosition);
|
||||
dist = ConvertUnits.ToDisplayUnits(dist);
|
||||
|
||||
AITargetMemory targetMemory = FindTargetMemory(target);
|
||||
@@ -402,7 +399,7 @@ namespace Barotrauma
|
||||
if (Math.Abs(valueModifier) > Math.Abs(targetValue) && (dist < target.SightRange * sight || dist < target.SoundRange * hearing))
|
||||
{
|
||||
Vector2 rayStart = character.AnimController.Limbs[0].SimPosition;
|
||||
Vector2 rayEnd = target.Position;
|
||||
Vector2 rayEnd = target.SimPosition;
|
||||
|
||||
Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd);
|
||||
Structure closestStructure = (closestBody == null) ? null : closestBody.UserData as Structure;
|
||||
@@ -493,7 +490,7 @@ namespace Barotrauma
|
||||
|
||||
if (selectedAiTarget!=null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, pos, ConvertUnits.ToDisplayUnits(new Vector2(selectedAiTarget.Position.X, -selectedAiTarget.Position.Y)), Color.Red);
|
||||
GUI.DrawLine(spriteBatch, pos, ConvertUnits.ToDisplayUnits(new Vector2(selectedAiTarget.SimPosition.X, -selectedAiTarget.SimPosition.Y)), Color.Red);
|
||||
|
||||
if (wallAttackPos!=Vector2.Zero)
|
||||
{
|
||||
|
||||
@@ -13,20 +13,27 @@ namespace Barotrauma
|
||||
|
||||
private AIObjectiveManager objectiveManager;
|
||||
|
||||
private IndoorsSteeringManager indoorsSteeringManager;
|
||||
private SteeringManager outdoorsSteeringManager;
|
||||
|
||||
private AITarget selectedAiTarget;
|
||||
|
||||
private float updateObjectiveTimer;
|
||||
|
||||
public HumanAIController(Character c) : base(c)
|
||||
{
|
||||
steeringManager = new PathSteeringManager(this);
|
||||
indoorsSteeringManager = new IndoorsSteeringManager(this, true);
|
||||
outdoorsSteeringManager = new SteeringManager(this);
|
||||
|
||||
objectiveManager = new AIObjectiveManager(c);
|
||||
objectiveManager.AddObjective(new AIObjectiveFindSafety());
|
||||
objectiveManager.AddObjective(new AIObjectiveFindSafety(c));
|
||||
objectiveManager.AddObjective(new AIObjectiveIdle(c));
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
steeringManager = Character.AnimController.CurrentHull == null ? outdoorsSteeringManager : indoorsSteeringManager;
|
||||
|
||||
if (updateObjectiveTimer>0.0f)
|
||||
{
|
||||
updateObjectiveTimer -= deltaTime;
|
||||
@@ -46,12 +53,15 @@ namespace Barotrauma
|
||||
|
||||
Character.AnimController.IgnorePlatforms = (-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X));
|
||||
|
||||
if (Math.Abs(Character.AnimController.TargetMovement.X)>0.1f)
|
||||
if (Math.Abs(Character.AnimController.TargetMovement.X) > 0.1f && !Character.AnimController.InWater)
|
||||
{
|
||||
Character.AnimController.TargetDir = Character.AnimController.TargetMovement.X > 0.0f ? Direction.Right : Direction.Left;
|
||||
}
|
||||
|
||||
steeringManager.Update();
|
||||
float currObjectivePriority = objectiveManager.CurrentObjective == null ? 0.0f : objectiveManager.CurrentObjective.GetPriority(Character);
|
||||
float moveSpeed = MathHelper.Clamp(currObjectivePriority/10.0f, 1.0f, 3.0f);
|
||||
|
||||
steeringManager.Update(moveSpeed);
|
||||
}
|
||||
|
||||
public override void SelectTarget(AITarget target)
|
||||
@@ -61,13 +71,12 @@ namespace Barotrauma
|
||||
|
||||
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
||||
{
|
||||
|
||||
if (selectedAiTarget != null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, new Vector2(Character.Position.X, -Character.Position.Y), ConvertUnits.ToDisplayUnits(new Vector2(selectedAiTarget.Position.X, -selectedAiTarget.Position.Y)), Color.Red);
|
||||
GUI.DrawLine(spriteBatch, new Vector2(Character.Position.X, -Character.Position.Y), ConvertUnits.ToDisplayUnits(new Vector2(selectedAiTarget.SimPosition.X, -selectedAiTarget.SimPosition.Y)), Color.Red);
|
||||
}
|
||||
|
||||
PathSteeringManager pathSteering = steeringManager as PathSteeringManager;
|
||||
IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager;
|
||||
if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode==null) return;
|
||||
|
||||
GUI.DrawLine(spriteBatch,
|
||||
@@ -83,7 +92,6 @@ namespace Barotrauma
|
||||
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].Position.X, -pathSteering.CurrentPath.Nodes[i-1].Position.Y),
|
||||
Color.LightGreen);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,23 @@ namespace Barotrauma
|
||||
|
||||
protected float priority;
|
||||
|
||||
protected Character character;
|
||||
|
||||
public virtual bool IsCompleted()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public AIObjective()
|
||||
public virtual bool CanBeCompleted
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public AIObjective(Character character)
|
||||
{
|
||||
subObjectives = new List<AIObjective>();
|
||||
|
||||
this.character = character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -26,20 +35,20 @@ namespace Barotrauma
|
||||
/// need to be completed before this one
|
||||
/// </summary>
|
||||
/// <param name="character">the character who's trying to achieve the objective</param>
|
||||
public void TryComplete(float deltaTime, Character character)
|
||||
public void TryComplete(float deltaTime)
|
||||
{
|
||||
foreach (AIObjective objective in subObjectives)
|
||||
{
|
||||
if (objective.IsCompleted()) continue;
|
||||
|
||||
objective.TryComplete(deltaTime, character);
|
||||
objective.TryComplete(deltaTime);
|
||||
return;
|
||||
}
|
||||
|
||||
Act(deltaTime, character);
|
||||
Act(deltaTime);
|
||||
}
|
||||
|
||||
protected virtual void Act(float deltaTime, Character character) { }
|
||||
protected virtual void Act(float deltaTime) { }
|
||||
|
||||
public virtual float GetPriority(Character character)
|
||||
{
|
||||
@@ -48,7 +57,7 @@ namespace Barotrauma
|
||||
|
||||
public virtual bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
return true;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,26 @@ namespace Barotrauma
|
||||
const float MinSafety = 50.0f;
|
||||
|
||||
AIObjectiveGoTo gotoObjective;
|
||||
|
||||
private List<AITarget> unreachable;
|
||||
|
||||
float currenthullSafety;
|
||||
|
||||
float searchHullTimer;
|
||||
|
||||
protected override void Act(float deltaTime, Character character)
|
||||
public AIObjectiveFindSafety(Character character)
|
||||
: base(character)
|
||||
{
|
||||
unreachable = new List<AITarget>();
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (character.AnimController.CurrentHull == null || GetHullSafety(character.AnimController.CurrentHull) > MinSafety)
|
||||
{
|
||||
character.AIController.SteeringManager.SteeringSeek(character.AnimController.CurrentHull.Position);
|
||||
character.AIController.SteeringManager.SteeringSeek(character.AnimController.CurrentHull.SimPosition);
|
||||
|
||||
character.AIController.SelectTarget(null);
|
||||
|
||||
gotoObjective = null;
|
||||
return;
|
||||
@@ -32,34 +42,56 @@ namespace Barotrauma
|
||||
searchHullTimer -= deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
searchHullTimer = SearchHullInterval;
|
||||
|
||||
Hull bestHull = null;
|
||||
float bestValue = currenthullSafety;
|
||||
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
else
|
||||
{
|
||||
if (hull == character.AnimController.CurrentHull) continue;
|
||||
|
||||
float hullValue = GetHullSafety(hull);
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.X- hull.Position.X));
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.Y - hull.Position.Y)*2.0f);
|
||||
Hull bestHull = null;
|
||||
float bestValue = currenthullSafety;
|
||||
|
||||
if (bestHull==null || hullValue > bestValue)
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
bestHull = hull;
|
||||
bestValue = hullValue;
|
||||
if (hull == character.AnimController.CurrentHull) continue;
|
||||
if (unreachable.Contains(hull.AiTarget)) continue;
|
||||
|
||||
float hullValue = GetHullSafety(hull);
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.X- hull.Position.X));
|
||||
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.Y - hull.Position.Y)*2.0f);
|
||||
|
||||
if (bestHull==null || hullValue > bestValue)
|
||||
{
|
||||
bestHull = hull;
|
||||
bestValue = hullValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestHull != null)
|
||||
{
|
||||
gotoObjective = new AIObjectiveGoTo(bestHull.AiTarget, character);
|
||||
//character.AIController.SelectTarget(bestHull.AiTarget);
|
||||
}
|
||||
|
||||
|
||||
searchHullTimer = SearchHullInterval;
|
||||
}
|
||||
|
||||
if (gotoObjective != null)
|
||||
{
|
||||
var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
|
||||
if (pathSteering!=null && pathSteering.CurrentPath!= null &&
|
||||
pathSteering.CurrentPath.Unreachable && !unreachable.Contains(gotoObjective.Target))
|
||||
{
|
||||
unreachable.Add(gotoObjective.Target);
|
||||
}
|
||||
}
|
||||
|
||||
if (bestHull != null)
|
||||
{
|
||||
gotoObjective = new AIObjectiveGoTo(bestHull.AiTarget, character);
|
||||
//character.AIController.SelectTarget(bestHull.AiTarget);
|
||||
}
|
||||
|
||||
gotoObjective.TryComplete(deltaTime, character);
|
||||
|
||||
gotoObjective.TryComplete(deltaTime);
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
return (otherObjective is AIObjectiveFindSafety);
|
||||
}
|
||||
|
||||
public override float GetPriority(Character character)
|
||||
@@ -77,10 +109,11 @@ namespace Barotrauma
|
||||
|
||||
foreach (FireSource fireSource in hull.FireSources)
|
||||
{
|
||||
fireAmount += fireSource.Size.X;
|
||||
fireAmount += Math.Max(fireSource.Size.X,50.0f);
|
||||
}
|
||||
|
||||
float safety = 100.0f - fireAmount - waterPercentage;
|
||||
float safety = 100.0f - fireAmount;
|
||||
if (waterPercentage > 30.0f) safety -= waterPercentage;
|
||||
if (hull.OxygenPercentage < 30.0f) safety -= (30.0f-hull.OxygenPercentage)*3.0f;
|
||||
|
||||
return safety;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveFixLeak : AIObjective
|
||||
{
|
||||
Gap leak;
|
||||
|
||||
public AIObjectiveFixLeak(Gap leak, Character character)
|
||||
:base (character)
|
||||
{
|
||||
this.leak = leak;
|
||||
}
|
||||
|
||||
public override float GetPriority(Character character)
|
||||
{
|
||||
return leak.isHorizontal ? leak.Rect.Height * leak.Open : leak.Rect.Width * leak.Open;
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
AIObjectiveFixLeak fixLeak = otherObjective as AIObjectiveFixLeak;
|
||||
if (fixLeak == null) return false;
|
||||
return fixLeak.leak == leak;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
var weldingTool = character.Inventory.FindItem("Welding Tool");
|
||||
|
||||
if (weldingTool == null)
|
||||
{
|
||||
subObjectives.Add(new AIObjectiveGetItem(character, "Welding Tool"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Vector2.Distance(character.Position, leak.Position)>10.0f)
|
||||
{
|
||||
subObjectives.Add(new AIObjectiveGoTo(leak.Position,character));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveGetItem : AIObjective
|
||||
{
|
||||
private string itemName;
|
||||
|
||||
private Item targetItem;
|
||||
|
||||
private int currSearchIndex;
|
||||
|
||||
private bool canBeCompleted;
|
||||
|
||||
public override bool CanBeCompleted
|
||||
{
|
||||
get { return canBeCompleted; }
|
||||
}
|
||||
|
||||
public AIObjectiveGetItem(Character character, string itemName)
|
||||
: base (character)
|
||||
{
|
||||
canBeCompleted = true;
|
||||
|
||||
currSearchIndex = 0;
|
||||
|
||||
this.itemName = itemName;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (targetItem != null)
|
||||
{
|
||||
if (Vector2.Distance(character.SimPosition, targetItem.SimPosition) < targetItem.PickDistance)
|
||||
{
|
||||
targetItem.Pick(character, false, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (currSearchIndex >= Item.ItemList.Count)
|
||||
{
|
||||
canBeCompleted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Item.ItemList[currSearchIndex].HasTag(itemName) || Item.ItemList[currSearchIndex].Name == itemName)
|
||||
{
|
||||
targetItem = Item.ItemList[currSearchIndex];
|
||||
|
||||
while (targetItem.container != null)
|
||||
{
|
||||
targetItem = targetItem.container;
|
||||
}
|
||||
|
||||
subObjectives.Add(new AIObjectiveGoTo(targetItem.Position, character));
|
||||
}
|
||||
|
||||
currSearchIndex++;
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
AIObjectiveGetItem getItem = otherObjective as AIObjectiveGetItem;
|
||||
if (getItem == null) return false;
|
||||
return (getItem.itemName == itemName);
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return character.Inventory.Items.FirstOrDefault(i => i != null && (i.HasTag(itemName) || i.Name == itemName)) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,22 +12,46 @@ namespace Barotrauma
|
||||
{
|
||||
AITarget target;
|
||||
|
||||
private Character character;
|
||||
Vector2 targetPos;
|
||||
|
||||
public AIObjectiveGoTo(AITarget target, Character character)
|
||||
public override bool CanBeCompleted
|
||||
{
|
||||
this.character = character;
|
||||
this.target = target;
|
||||
|
||||
get
|
||||
{
|
||||
var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
|
||||
return (pathSteering.CurrentPath == null || !pathSteering.CurrentPath.Unreachable);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime, Character character)
|
||||
public AITarget Target
|
||||
{
|
||||
if (target == null) return;
|
||||
get { return target; }
|
||||
}
|
||||
|
||||
public AIObjectiveGoTo(AITarget target, Character character)
|
||||
: base (character)
|
||||
{
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
|
||||
public AIObjectiveGoTo(Vector2 targetPos, Character character)
|
||||
: base(character)
|
||||
{
|
||||
this.targetPos = targetPos;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
character.AIController.SelectTarget(target);
|
||||
|
||||
character.AIController.SteeringManager.SteeringSeek(ConvertUnits.ToDisplayUnits(target.Position));
|
||||
character.AIController.SteeringManager.SteeringSeek(
|
||||
target != null ? target.SimPosition : targetPos);
|
||||
}
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
return Vector2.Distance(target != null ? target.SimPosition : ConvertUnits.ToDisplayUnits(targetPos), character.SimPosition) < 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AIObjectiveIdle : AIObjective
|
||||
{
|
||||
AITarget currentTarget;
|
||||
private float newTargetTimer;
|
||||
|
||||
|
||||
|
||||
public AIObjectiveIdle(Character character) : base(character)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override float GetPriority(Character character)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (newTargetTimer <= 0.0f)
|
||||
{
|
||||
currentTarget = FindRandomTarget();
|
||||
|
||||
newTargetTimer = currentTarget == null ? 5.0f : 10.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
newTargetTimer -= deltaTime;
|
||||
}
|
||||
|
||||
|
||||
if (currentTarget == null) 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()
|
||||
{
|
||||
if (Rand.Int(5)==1)
|
||||
{
|
||||
var idCard = character.Inventory.FindItem("ID Card");
|
||||
if (idCard==null) return null;
|
||||
|
||||
foreach (WayPoint wp in WayPoint.WayPointList)
|
||||
{
|
||||
if (wp.SpawnType != SpawnType.Human) continue;
|
||||
|
||||
foreach (string tag in wp.IdCardTags)
|
||||
{
|
||||
if (idCard.HasTag(tag)) return wp.CurrentHull.AiTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Hull> targetHulls = new List<Hull>(Hull.hullList);
|
||||
//ignore all hulls with fires or water in them
|
||||
targetHulls.RemoveAll(h => h.FireSources.Any() || (h.Volume/h.FullVolume)>0.1f);
|
||||
if (!targetHulls.Any()) return null;
|
||||
|
||||
return targetHulls[Rand.Range(0, targetHulls.Count)].AiTarget;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,14 @@ namespace Barotrauma
|
||||
private List<AIObjective> objectives;
|
||||
|
||||
private Character character;
|
||||
|
||||
public AIObjective CurrentObjective
|
||||
{
|
||||
get
|
||||
{
|
||||
return objectives.Any() ? objectives[0] : null;
|
||||
}
|
||||
}
|
||||
|
||||
public AIObjectiveManager(Character character)
|
||||
{
|
||||
@@ -33,14 +41,24 @@ namespace Barotrauma
|
||||
objectives = objectives.FindAll(o => !o.IsCompleted());
|
||||
|
||||
//sort objectives according to priority
|
||||
objectives.Sort((x, y) => x.GetPriority(character).CompareTo(y.GetPriority(character)));
|
||||
|
||||
objectives.Sort((x, y) => y.GetPriority(character).CompareTo(x.GetPriority(character)));
|
||||
|
||||
if (character.AnimController.CurrentHull!=null)
|
||||
{
|
||||
var gaps = character.AnimController.CurrentHull.FindGaps();
|
||||
|
||||
foreach (Gap gap in gaps)
|
||||
{
|
||||
if (gap.linkedTo.Count > 1) continue;
|
||||
AddObjective(new AIObjectiveFixLeak(gap, character));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DoCurrentObjective(float deltaTime)
|
||||
{
|
||||
if (!objectives.Any()) return;
|
||||
objectives[0].TryComplete(deltaTime, character);
|
||||
objectives[0].TryComplete(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,13 @@ namespace Barotrauma
|
||||
{
|
||||
private Item targetItem;
|
||||
|
||||
public AIObjectiveOperateItem(Item item)
|
||||
public AIObjectiveOperateItem(Item item, Character character)
|
||||
:base (character)
|
||||
{
|
||||
targetItem = item;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime, Character character)
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
//item.AIOperate(float deltaTime, Character character) or something
|
||||
}
|
||||
|
||||
@@ -77,8 +77,8 @@ namespace Barotrauma
|
||||
|
||||
class PathFinder
|
||||
{
|
||||
public delegate float GetNodePenaltyHandler(PathNode node, PathNode prevNode);
|
||||
public GetNodePenaltyHandler GetNodePriority;
|
||||
public delegate float? GetNodePenaltyHandler(PathNode node, PathNode prevNode);
|
||||
public GetNodePenaltyHandler GetNodePenalty;
|
||||
|
||||
List<PathNode> nodes;
|
||||
|
||||
@@ -95,12 +95,14 @@ namespace Barotrauma
|
||||
{
|
||||
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
|
||||
float closestDist = 0.0f;
|
||||
PathNode startNode = null;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
float dist = Vector2.Distance(start,node.Position);
|
||||
float dist = System.Math.Abs(start.X-node.Position.X)+
|
||||
System.Math.Abs(start.Y - node.Position.Y)*10.0f +
|
||||
Vector2.Distance(end,node.Position)/2.0f;
|
||||
if (dist<closestDist || startNode==null)
|
||||
{
|
||||
if (insideSubmarine && Submarine.CheckVisibility(start, node.Position) != null) continue;
|
||||
@@ -173,6 +175,14 @@ namespace Barotrauma
|
||||
|
||||
private SteeringPath FindPath(PathNode start, PathNode end)
|
||||
{
|
||||
if (start == end)
|
||||
{
|
||||
var path1 = new SteeringPath();
|
||||
path1.AddNode(start.Waypoint);
|
||||
|
||||
return path1;
|
||||
}
|
||||
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
node.state = 0;
|
||||
@@ -210,7 +220,16 @@ namespace Barotrauma
|
||||
{
|
||||
nextNode.H = Vector2.DistanceSquared(nextNode.Position,end.Position);
|
||||
|
||||
if (GetNodePriority != null) nextNode.H += GetNodePriority(currNode, nextNode);
|
||||
if (GetNodePenalty != null)
|
||||
{
|
||||
float? nodePenalty =GetNodePenalty(currNode, nextNode);
|
||||
if (nodePenalty == null)
|
||||
{
|
||||
nextNode.state = -1;
|
||||
continue;
|
||||
}
|
||||
nextNode.H += (float)nodePenalty;
|
||||
}
|
||||
|
||||
nextNode.G = currNode.G + currNode.distances[i];
|
||||
nextNode.F = nextNode.G + nextNode.H;
|
||||
@@ -236,7 +255,7 @@ namespace Barotrauma
|
||||
if (end.state==0)
|
||||
{
|
||||
//path not found
|
||||
return new SteeringPath();
|
||||
return new SteeringPath(true);
|
||||
}
|
||||
|
||||
SteeringPath path = new SteeringPath();
|
||||
|
||||
@@ -8,14 +8,14 @@ using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class PathSteeringManager : SteeringManager
|
||||
class IndoorsSteeringManager : SteeringManager
|
||||
{
|
||||
private PathFinder pathFinder;
|
||||
private SteeringPath currentPath;
|
||||
|
||||
private Character character;
|
||||
private bool canOpenDoors;
|
||||
|
||||
private List<Controller> openableButtons;
|
||||
private Character character;
|
||||
|
||||
public SteeringPath CurrentPath
|
||||
{
|
||||
@@ -31,15 +31,15 @@ namespace Barotrauma
|
||||
|
||||
private float findPathTimer;
|
||||
|
||||
public PathSteeringManager(ISteerable host)
|
||||
public IndoorsSteeringManager(ISteerable host, bool canOpenDoors)
|
||||
: base(host)
|
||||
{
|
||||
pathFinder = new PathFinder(WayPoint.WayPointList.FindAll(wp => wp.SpawnType == SpawnType.Path), true);
|
||||
pathFinder.GetNodePriority = GetNodePriority;
|
||||
pathFinder.GetNodePenalty = GetNodePenalty;
|
||||
|
||||
this.canOpenDoors = canOpenDoors;
|
||||
|
||||
character = (host as AIController).Character;
|
||||
|
||||
openableButtons = new List<Controller>();
|
||||
}
|
||||
|
||||
public override void Update(float speed = 1)
|
||||
@@ -53,37 +53,22 @@ namespace Barotrauma
|
||||
protected override Vector2 DoSteeringSeek(Vector2 target, float speed = 1)
|
||||
{
|
||||
//find a new path if one hasn't been found yet or the target is different from the current target
|
||||
if (currentPath == null || Vector2.DistanceSquared(target, currentTarget)>10.0f)
|
||||
if (currentPath == null || Vector2.Distance(target, currentTarget)>1.0f || findPathTimer < -10.0f)
|
||||
{
|
||||
if (findPathTimer > 0.0f) return Vector2.Zero;
|
||||
|
||||
currentTarget = target;
|
||||
currentPath = pathFinder.FindPath(host.SimPosition, ConvertUnits.ToSimUnits(target));
|
||||
|
||||
currentPath = pathFinder.FindPath(host.SimPosition, target);
|
||||
|
||||
findPathTimer = 1.0f;
|
||||
|
||||
return DiffToCurrentNode();
|
||||
}
|
||||
|
||||
|
||||
//if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return;
|
||||
|
||||
//if (currentPath.CurrentNode.ConnectedGap != null && currentPath.CurrentNode.ConnectedGap.Open < 0.9f)
|
||||
//{
|
||||
foreach (Controller controller in openableButtons)
|
||||
{
|
||||
if (Vector2.Distance(controller.Item.SimPosition, character.SimPosition) > controller.Item.PickDistance) continue;
|
||||
|
||||
controller.Item.Pick(character, false, true);
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
|
||||
Vector2 diff = DiffToCurrentNode();
|
||||
|
||||
if (diff == Vector2.Zero) return -host.Steering;
|
||||
|
||||
|
||||
return (diff == Vector2.Zero) ? Vector2.Zero : Vector2.Normalize(diff)*speed;
|
||||
}
|
||||
|
||||
@@ -91,61 +76,77 @@ namespace Barotrauma
|
||||
{
|
||||
if (currentPath == null) return Vector2.Zero;
|
||||
|
||||
currentPath.CheckProgress(host.SimPosition, 0.45f);
|
||||
if (canOpenDoors) CheckDoorsInPath();
|
||||
|
||||
currentPath.CheckProgress(host.SimPosition, character.AnimController.InWater ? 1.0f : 0.6f);
|
||||
|
||||
if (currentPath.CurrentNode == null) return Vector2.Zero;
|
||||
|
||||
return currentPath.CurrentNode.SimPosition - host.SimPosition;
|
||||
}
|
||||
|
||||
private float GetNodePriority(PathNode node, PathNode nextNode)
|
||||
private void CheckDoorsInPath()
|
||||
{
|
||||
if (character==null) return 0.0f;
|
||||
if (nextNode.Waypoint.ConnectedGap!=null)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
WayPoint node = i == 0 ? currentPath.CurrentNode : currentPath.PrevNode;
|
||||
|
||||
if (node == null || node.ConnectedGap == null || node.ConnectedGap.ConnectedDoor == null) continue;
|
||||
|
||||
var door = node.ConnectedGap.ConnectedDoor;
|
||||
|
||||
bool open = currentPath.CurrentNode != null &&
|
||||
Math.Sign(door.Item.SimPosition.X - host.SimPosition.X) == Math.Sign(currentPath.CurrentNode.SimPosition.X - host.SimPosition.X);
|
||||
|
||||
//toggle the door if it's the previous node and open, or if it's current node and closed
|
||||
if (door.IsOpen != open)
|
||||
{
|
||||
var buttons = door.GetButtons();
|
||||
foreach (Controller controller in buttons)
|
||||
{
|
||||
if (Vector2.Distance(controller.Item.SimPosition, character.SimPosition) > controller.Item.PickDistance * 2.0f) continue;
|
||||
|
||||
controller.Item.Pick(character, false, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float? GetNodePenalty(PathNode node, PathNode nextNode)
|
||||
{
|
||||
if (character == null) return 0.0f;
|
||||
if (nextNode.Waypoint.ConnectedGap != null)
|
||||
{
|
||||
if (nextNode.Waypoint.ConnectedGap.Open > 0.9f) return 0.0f;
|
||||
if (nextNode.Waypoint.ConnectedGap.ConnectedDoor == null) return 100.0f;
|
||||
|
||||
var doorButtons = GetDoorButtons(nextNode.Waypoint.ConnectedGap.ConnectedDoor);
|
||||
if (!canOpenDoors) return null;
|
||||
|
||||
var doorButtons = nextNode.Waypoint.ConnectedGap.ConnectedDoor.GetButtons();
|
||||
foreach (Controller button in doorButtons)
|
||||
{
|
||||
if (Math.Sign(button.Item.Position.X - nextNode.Waypoint.Position.X) !=
|
||||
Math.Sign(node.Position.X - nextNode.Position.X)) continue;
|
||||
|
||||
if (!button.HasRequiredItems(character, false)) return 1000.0f;
|
||||
if (!button.HasRequiredItems(character, false)) return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.Waypoint!=null && node.Waypoint.CurrentHull!=null)
|
||||
{
|
||||
var hull = node.Waypoint.CurrentHull;
|
||||
|
||||
float penalty = hull.FireSources.Any() ? 1000.0f : 0.0f;
|
||||
|
||||
if (character.NeedsAir && hull.Volume / hull.Rect.Width > 100.0f) penalty += 500.0f;
|
||||
if (character.PressureProtection < 10.0f && hull.Volume > hull.FullVolume) penalty += 1000.0f;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
private List<Controller> GetDoorButtons(Door door)
|
||||
{
|
||||
if (door == null) return new List<Controller>();
|
||||
ConnectionPanel connectionPanel = door.Item.GetComponent<ConnectionPanel>();
|
||||
|
||||
List<Controller> doorButtons = new List<Controller>();
|
||||
|
||||
foreach (Connection c in connectionPanel.Connections)
|
||||
{
|
||||
foreach (Wire w in c.Wires)
|
||||
{
|
||||
if (w == null) continue;
|
||||
var otherConnection = w.OtherConnection(c);
|
||||
|
||||
if (otherConnection.Item == door.Item || otherConnection == null) continue;
|
||||
|
||||
var controller = otherConnection.Item.GetComponent<Controller>();
|
||||
if (controller != null)
|
||||
{
|
||||
doorButtons.Add(controller);
|
||||
if (!openableButtons.Contains(controller)) openableButtons.Add(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return doorButtons;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,9 +9,16 @@ namespace Barotrauma
|
||||
|
||||
int currentIndex;
|
||||
|
||||
public SteeringPath()
|
||||
public bool Unreachable
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public SteeringPath(bool unreachable = false)
|
||||
{
|
||||
nodes = new List<WayPoint>();
|
||||
Unreachable = unreachable;
|
||||
}
|
||||
|
||||
public void AddNode(WayPoint node)
|
||||
@@ -20,6 +27,20 @@ namespace Barotrauma
|
||||
nodes.Add(node);
|
||||
}
|
||||
|
||||
public int CurrentIndex
|
||||
{
|
||||
get { return currentIndex; }
|
||||
}
|
||||
|
||||
public WayPoint PrevNode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (currentIndex-1 < 0 || currentIndex-1 > nodes.Count - 1) return null;
|
||||
return nodes[currentIndex-1];
|
||||
}
|
||||
}
|
||||
|
||||
public WayPoint CurrentNode
|
||||
{
|
||||
get
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Barotrauma
|
||||
{
|
||||
base.DrawFront(spriteBatch);
|
||||
|
||||
if (GameMain.DebugDraw) aiController.DebugDraw(spriteBatch);
|
||||
if (GameMain.DebugDraw && !isDead) aiController.DebugDraw(spriteBatch);
|
||||
}
|
||||
|
||||
public override AttackResult AddDamage(IDamageable attacker, Vector2 position, Attack attack, float deltaTime, bool playSound = false)
|
||||
|
||||
@@ -84,6 +84,17 @@ namespace Barotrauma
|
||||
//the name of the species (e.q. human)
|
||||
public readonly string SpeciesName;
|
||||
|
||||
protected float soundTimer;
|
||||
protected float soundInterval;
|
||||
|
||||
private float bleeding;
|
||||
|
||||
private Sound[] sounds;
|
||||
private float[] soundRange;
|
||||
//which AIstate each sound is for
|
||||
private AIController.AiState[] soundStates;
|
||||
|
||||
|
||||
private CharacterInfo info;
|
||||
|
||||
public CharacterInfo Info
|
||||
@@ -99,16 +110,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
protected float soundTimer;
|
||||
protected float soundInterval;
|
||||
|
||||
private float bleeding;
|
||||
|
||||
private Sound[] sounds;
|
||||
private float[] soundRange;
|
||||
//which AIstate each sound is for
|
||||
private AIController.AiState[] soundStates;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
@@ -171,6 +172,7 @@ namespace Barotrauma
|
||||
{
|
||||
get { return aiTarget.SightRange; }
|
||||
}
|
||||
|
||||
private float pressureProtection;
|
||||
public float PressureProtection
|
||||
{
|
||||
@@ -181,11 +183,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool NeedsAir
|
||||
{
|
||||
get { return needsAir; }
|
||||
}
|
||||
|
||||
public float Oxygen
|
||||
{
|
||||
get { return oxygen; }
|
||||
set
|
||||
{
|
||||
if (!MathUtils.IsValid(value)) return;
|
||||
oxygen = MathHelper.Clamp(value, 0.0f, 100.0f);
|
||||
if (oxygen == 0.0f) Kill(CauseOfDeath.Suffocation);
|
||||
}
|
||||
@@ -567,6 +575,8 @@ namespace Barotrauma
|
||||
AnimController.TargetMovement = targetMovement;
|
||||
AnimController.IsStanding = true;
|
||||
|
||||
AnimController.IgnorePlatforms = targetMovement.Y < 0.0f;
|
||||
|
||||
if (AnimController.onGround &&
|
||||
!AnimController.InWater &&
|
||||
AnimController.Anim != AnimController.Animation.UsingConstruction)
|
||||
@@ -877,7 +887,7 @@ namespace Barotrauma
|
||||
|
||||
if (isDead) return;
|
||||
|
||||
if (!(this is AICharacter))
|
||||
if (!(AnimController is FishAnimController))
|
||||
{
|
||||
bool protectedFromPressure = PressureProtection > 0.0f;
|
||||
|
||||
@@ -993,7 +1003,7 @@ namespace Barotrauma
|
||||
AnimController.DebugDraw(spriteBatch);
|
||||
}
|
||||
|
||||
Vector2 healthBarPos = new Vector2(Position.X - 50, -Position.Y - 50.0f);
|
||||
Vector2 healthBarPos = new Vector2(Position.X - 50, -Position.Y - 100.0f);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)healthBarPos.X - 2, (int)healthBarPos.Y - 2, 100 + 4, 15 + 4), Color.Black, false);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)healthBarPos.X, (int)healthBarPos.Y, (int)(100.0f * (health / maxHealth)), 15), Color.Red, true);
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace Barotrauma
|
||||
public void UpdateCharacterItems()
|
||||
{
|
||||
pickedItems.Clear();
|
||||
foreach (Item item in Character.Inventory.items)
|
||||
foreach (Item item in Character.Inventory.Items)
|
||||
{
|
||||
pickedItems.Add(item == null ? (ushort)0 : item.ID);
|
||||
}
|
||||
|
||||
@@ -133,11 +133,7 @@ namespace Barotrauma
|
||||
stunTimer -= deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
IgnorePlatforms = (TargetMovement.Y < 0.0f);
|
||||
|
||||
|
||||
|
||||
|
||||
if (Anim != Animation.UsingConstruction) ResetPullJoints();
|
||||
|
||||
if (TargetDir != dir) Flip();
|
||||
|
||||
Reference in New Issue
Block a user