- AICharacter will mark their path unreachable if their path is blocked by a door they cant open (may happen if someone closes the door after calculating the path) - fixed exception when creating a Steering component when there's no active GameSession (i.e. in the editor)
197 lines
7.8 KiB
C#
197 lines
7.8 KiB
C#
using Microsoft.Xna.Framework;
|
|
using System;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
class HumanAIController : AIController
|
|
{
|
|
public static bool DisableCrewAI;
|
|
|
|
const float UpdateObjectiveInterval = 0.5f;
|
|
|
|
private AIObjectiveManager objectiveManager;
|
|
|
|
private AITarget selectedAiTarget;
|
|
|
|
private float updateObjectiveTimer;
|
|
|
|
public Order CurrentOrder
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public string CurrentOrderOption
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public HumanAIController(Character c) : base(c)
|
|
{
|
|
steeringManager = new IndoorsSteeringManager(this, true);
|
|
|
|
objectiveManager = new AIObjectiveManager(c);
|
|
objectiveManager.AddObjective(new AIObjectiveFindSafety(c));
|
|
objectiveManager.AddObjective(new AIObjectiveIdle(c));
|
|
|
|
updateObjectiveTimer = Rand.Range(0.0f, UpdateObjectiveInterval);
|
|
|
|
if (GameMain.GameSession!=null && GameMain.GameSession.CrewManager!=null)
|
|
{
|
|
CurrentOrder = Order.PrefabList.Find(o => o.Name.ToLowerInvariant() == "dismissed");
|
|
objectiveManager.SetOrder(CurrentOrder, "");
|
|
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, CurrentOrder);
|
|
}
|
|
|
|
}
|
|
|
|
public override void Update(float deltaTime)
|
|
{
|
|
if (DisableCrewAI || Character.IsUnconscious) return;
|
|
|
|
Character.ClearInputs();
|
|
|
|
//steeringManager = Character.AnimController.CurrentHull == null ? outdoorsSteeringManager : indoorsSteeringManager;
|
|
|
|
if (updateObjectiveTimer>0.0f)
|
|
{
|
|
updateObjectiveTimer -= deltaTime;
|
|
}
|
|
else
|
|
{
|
|
objectiveManager.UpdateObjectives();
|
|
updateObjectiveTimer = UpdateObjectiveInterval;
|
|
}
|
|
|
|
objectiveManager.DoCurrentObjective(deltaTime);
|
|
|
|
float currObjectivePriority = objectiveManager.GetCurrentPriority(Character);
|
|
float moveSpeed = MathHelper.Clamp(currObjectivePriority/10.0f, 1.0f, 3.0f);
|
|
|
|
steeringManager.Update(moveSpeed);
|
|
|
|
bool ignorePlatforms = Character.AnimController.TargetMovement.Y < -0.5f &&
|
|
(-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X));
|
|
|
|
var currPath = (steeringManager as IndoorsSteeringManager).CurrentPath;
|
|
if (currPath != null && currPath.CurrentNode != null)
|
|
{
|
|
if (currPath.CurrentNode.SimPosition.Y < Character.AnimController.GetColliderBottom().Y)
|
|
{
|
|
ignorePlatforms = true;
|
|
}
|
|
}
|
|
|
|
Character.AnimController.IgnorePlatforms = ignorePlatforms;
|
|
(Character.AnimController as HumanoidAnimController).Crouching = false;
|
|
|
|
if (!Character.AnimController.InWater)
|
|
{
|
|
Character.AnimController.TargetMovement = new Vector2(
|
|
Character.AnimController.TargetMovement.X,
|
|
MathHelper.Clamp(Character.AnimController.TargetMovement.Y, -1.0f, 1.0f)) * Character.SpeedMultiplier;
|
|
|
|
Character.SpeedMultiplier = 1.0f;
|
|
}
|
|
|
|
if (Character.SelectedConstruction != null && Character.SelectedConstruction.GetComponent<Items.Components.Ladder>()!=null)
|
|
{
|
|
if (currPath != null && currPath.CurrentNode != null && currPath.CurrentNode.Ladders != null)
|
|
{
|
|
Character.AnimController.TargetMovement = new Vector2( 0.0f, Math.Sign(Character.AnimController.TargetMovement.Y));
|
|
}
|
|
}
|
|
|
|
//suit can be taken off if there character is inside a hull and there's air in the room
|
|
bool canTakeOffSuit = Character.AnimController.CurrentHull != null &&
|
|
Character.AnimController.CurrentHull.OxygenPercentage > 30.0f &&
|
|
Character.AnimController.CurrentHull.Volume < Character.AnimController.CurrentHull.FullVolume * 0.3f;
|
|
|
|
//the suit can be taken off and the character is running out of oxygen (couldn't find a tank for the suit?) or idling
|
|
//-> take the suit off
|
|
if (canTakeOffSuit && (Character.Oxygen < 50.0f || objectiveManager.CurrentObjective is AIObjectiveIdle))
|
|
{
|
|
var divingSuit = Character.Inventory.FindItem("Diving Suit");
|
|
if (divingSuit != null) divingSuit.Drop(Character);
|
|
}
|
|
|
|
if (Character.IsKeyDown(InputType.Aim))
|
|
{
|
|
var cursorDiffX = Character.CursorPosition.X - Character.Position.X;
|
|
if (cursorDiffX > 10.0f)
|
|
{
|
|
Character.AnimController.TargetDir = Direction.Right;
|
|
}
|
|
else if (cursorDiffX < -10.0f)
|
|
{
|
|
Character.AnimController.TargetDir = Direction.Left;
|
|
}
|
|
|
|
if (Character.SelectedConstruction != null) Character.SelectedConstruction.SecondaryUse(deltaTime, Character);
|
|
|
|
}
|
|
else 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;
|
|
}
|
|
}
|
|
|
|
public override void OnAttacked(IDamageable attacker, float amount)
|
|
{
|
|
if (amount <= 0.0f) return;
|
|
|
|
var enemy = attacker as Character;
|
|
if (enemy == null || enemy == Character) return;
|
|
|
|
objectiveManager.AddObjective(new AIObjectiveCombat(Character, enemy));
|
|
}
|
|
|
|
public void SetOrder(Order order, string option)
|
|
{
|
|
CurrentOrderOption = option;
|
|
CurrentOrder = order;
|
|
objectiveManager.SetOrder(order, option);
|
|
|
|
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, order);
|
|
}
|
|
|
|
public override void SelectTarget(AITarget target)
|
|
{
|
|
selectedAiTarget = target;
|
|
}
|
|
|
|
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
|
{
|
|
if (selectedAiTarget != null)
|
|
{
|
|
GUI.DrawLine(spriteBatch,
|
|
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
|
new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red);
|
|
}
|
|
|
|
IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager;
|
|
if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode==null) return;
|
|
|
|
GUI.DrawLine(spriteBatch,
|
|
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
|
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
|
|
Color.LightGreen);
|
|
|
|
|
|
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
|
|
{
|
|
GUI.DrawLine(spriteBatch,
|
|
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
|
|
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
|
|
Color.LightGreen);
|
|
|
|
spriteBatch.DrawString(GUI.SmallFont,
|
|
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
|
|
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y - 10),
|
|
Color.LightGreen);
|
|
}
|
|
}
|
|
}
|
|
}
|