130 lines
4.2 KiB
C#
130 lines
4.2 KiB
C#
using Microsoft.Xna.Framework;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
class AIObjectiveCombat : AIObjective
|
|
{
|
|
const float CoolDown = 10.0f;
|
|
|
|
private Character enemy;
|
|
|
|
private AIObjectiveFindSafety escapeObjective;
|
|
|
|
float coolDownTimer;
|
|
|
|
private readonly float enemyStrength;
|
|
|
|
public AIObjectiveCombat (Character character, Character enemy)
|
|
: base(character, "")
|
|
{
|
|
this.enemy = enemy;
|
|
|
|
foreach (Limb limb in enemy.AnimController.Limbs)
|
|
{
|
|
if (limb.attack == null) continue;
|
|
enemyStrength += limb.attack.GetDamage(1.0f);
|
|
}
|
|
|
|
coolDownTimer = CoolDown;
|
|
|
|
}
|
|
|
|
protected override void Act(float deltaTime)
|
|
{
|
|
coolDownTimer -= deltaTime;
|
|
|
|
var weapon = character.Inventory.FindItem("weapon");
|
|
|
|
if (weapon==null)
|
|
{
|
|
Escape(deltaTime);
|
|
}
|
|
else
|
|
{
|
|
if (!character.SelectedItems.Contains(weapon))
|
|
{
|
|
character.Inventory.TryPutItem(weapon, 3, true, false);
|
|
weapon.Equip(character);
|
|
}
|
|
character.CursorPosition = enemy.Position;
|
|
character.SetInput(InputType.Aim, false, true);
|
|
|
|
Vector2 enemyDiff = Vector2.Normalize(enemy.Position - character.Position);
|
|
float weaponAngle = ((weapon.body.Dir == 1.0f) ? weapon.body.Rotation : weapon.body.Rotation - MathHelper.Pi);
|
|
Vector2 weaponDir = new Vector2((float)Math.Cos(weaponAngle), (float)Math.Sin(weaponAngle));
|
|
|
|
if (Vector2.Dot(enemyDiff, weaponDir) < 0.9f) return;
|
|
|
|
List<FarseerPhysics.Dynamics.Body> ignoredBodies = new List<FarseerPhysics.Dynamics.Body>();
|
|
foreach (Limb limb in character.AnimController.Limbs)
|
|
{
|
|
ignoredBodies.Add(limb.body.FarseerBody);
|
|
}
|
|
|
|
var pickedBody = Submarine.PickBody(character.SimPosition, enemy.SimPosition, ignoredBodies);
|
|
if (pickedBody != null && !(pickedBody.UserData is Limb)) return;
|
|
|
|
weapon.Use(deltaTime, character);
|
|
}
|
|
}
|
|
|
|
private void Escape(float deltaTime)
|
|
{
|
|
if (escapeObjective == null)
|
|
{
|
|
escapeObjective = new AIObjectiveFindSafety(character);
|
|
}
|
|
|
|
if (enemy.AnimController.CurrentHull == character.AnimController.CurrentHull)
|
|
{
|
|
escapeObjective.OverrideCurrentHullSafety = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
escapeObjective.OverrideCurrentHullSafety = null;
|
|
}
|
|
|
|
escapeObjective.TryComplete(deltaTime);
|
|
|
|
if (Vector2.Distance(character.SimPosition, enemy.SimPosition) < 3.0f)
|
|
{
|
|
character.AIController.SteeringManager.SteeringManual(deltaTime, (character.SimPosition - enemy.SimPosition)*0.1f);
|
|
coolDownTimer = CoolDown;
|
|
}
|
|
}
|
|
|
|
public override bool IsCompleted()
|
|
{
|
|
return enemy.IsDead || coolDownTimer <= 0.0f;
|
|
}
|
|
|
|
public override float GetPriority(Character character)
|
|
{
|
|
//clamp the strength to the health of this character
|
|
//(it doesn't make a difference whether the enemy does 200 or 600 damage, it's one hit kill anyway)
|
|
|
|
float enemyDanger = Math.Min(enemyStrength, character.Health) + enemy.Health / 10.0f;
|
|
|
|
EnemyAIController enemyAI = enemy.AIController as EnemyAIController;
|
|
if (enemyAI != null)
|
|
{
|
|
if (enemyAI.SelectedAiTarget == character.AiTarget) enemyDanger *= 2.0f;
|
|
}
|
|
|
|
return Math.Max(enemyDanger, AIObjectiveManager.OrderPriority);
|
|
}
|
|
|
|
public override bool IsDuplicate(AIObjective otherObjective)
|
|
{
|
|
AIObjectiveCombat objective = otherObjective as AIObjectiveCombat;
|
|
if (objective == null) return false;
|
|
|
|
return objective.enemy == enemy;
|
|
}
|
|
}
|
|
}
|