(7d7e17231) Implement reversing and make it as an option for attacks. Detach latching with "F" (debug feature).

This commit is contained in:
Joonas Rikkonen
2019-03-29 17:20:54 +02:00
parent b9574dde2d
commit c0cf060526
15 changed files with 271 additions and 201 deletions
@@ -70,17 +70,28 @@ namespace Barotrauma
private float raycastTimer;
private bool IsCoolDownRunning => attackingLimb != null && attackingLimb.attack.CoolDownTimer > 0;
private bool IsCoolDownRunning => AttackingLimb != null && AttackingLimb.attack.CoolDownTimer > 0;
private bool aggressiveBoarding;
private LatchOntoAI latchOntoAI;
//a point in a wall which the Character is currently targeting
private WallTarget wallTarget;
//the limb selected for the current attack
private Limb attackingLimb;
private Limb _attackingLimb;
public Limb AttackingLimb
{
get { return _attackingLimb; }
private set
{
_attackingLimb = value;
Reverse = _attackingLimb != null && _attackingLimb.attack.Reverse;
if (Character.AnimController is FishAnimController fishController)
{
fishController.reverse = Reverse;
}
}
}
//flee when the health is below this value
private float fleeHealthThreshold;
@@ -103,6 +114,8 @@ namespace Barotrauma
private readonly float priorityFearIncreasement = 2;
private readonly float memoryFadeTime = 0.5f;
public LatchOntoAI LatchOntoAI { get; private set; }
public bool AttackHumans
{
get
@@ -121,11 +134,6 @@ namespace Barotrauma
}
}
public Limb AttackingLimb
{
get { return attackingLimb; }
}
public float CombatStrength
{
get { return combatStrength; }
@@ -136,7 +144,7 @@ namespace Barotrauma
get
{
//can't enter a submarine when attached to something
return latchOntoAI == null || !latchOntoAI.IsAttached;
return LatchOntoAI == null || !LatchOntoAI.IsAttached;
}
}
@@ -144,11 +152,13 @@ namespace Barotrauma
{
get
{
//can't flip when attached to something
return latchOntoAI == null || !latchOntoAI.IsAttached;
//can't flip when attached to something or when reversing
return !Reverse && (LatchOntoAI == null || !LatchOntoAI.IsAttached);
}
}
public bool Reverse { get; private set; }
public EnemyAIController(Character c, string file, string seed) : base(c)
{
targetMemories = new Dictionary<AITarget, AITargetMemory>();
@@ -196,7 +206,7 @@ namespace Barotrauma
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "latchonto":
latchOntoAI = new LatchOntoAI(subElement, this);
LatchOntoAI = new LatchOntoAI(subElement, this);
break;
case "targetpriority":
targetingPriorities.Add(subElement.GetAttributeString("tag", "").ToLowerInvariant(), new TargetingPriority(subElement));
@@ -305,7 +315,7 @@ namespace Barotrauma
}
}
latchOntoAI?.Update(this, deltaTime);
LatchOntoAI?.Update(this, deltaTime);
if (SelectedAiTarget != null && (SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed))
{
@@ -561,7 +571,7 @@ namespace Barotrauma
if (Character.WorldPosition.Y < door.Item.WorldRect.Y && Character.WorldPosition.Y > door.Item.WorldRect.Y - door.Item.Rect.Height)
{
velocity.Y = 0;
latchOntoAI?.DeattachFromBody();
LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs();
steeringManager.SteeringManual(deltaTime, velocity);
return;
@@ -572,7 +582,7 @@ namespace Barotrauma
if (Character.WorldPosition.X < door.Item.WorldRect.X && Character.WorldPosition.X > door.Item.WorldRect.Right)
{
velocity.X = 0;
latchOntoAI?.DeattachFromBody();
LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs();
steeringManager.SteeringManual(deltaTime, velocity);
return;
@@ -585,14 +595,14 @@ namespace Barotrauma
bool canAttack = true;
if (IsCoolDownRunning)
{
switch (attackingLimb.attack.AfterAttack)
switch (AttackingLimb.attack.AfterAttack)
{
case AIBehaviorAfterAttack.Pursue:
case AIBehaviorAfterAttack.PursueIfCanAttack:
if (attackingLimb.attack.SecondaryCoolDown <= 0)
if (AttackingLimb.attack.SecondaryCoolDown <= 0)
{
// No (valid) secondary cooldown defined.
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
{
canAttack = false;
}
@@ -604,33 +614,33 @@ namespace Barotrauma
}
else
{
if (attackingLimb.attack.SecondaryCoolDownTimer <= 0)
if (AttackingLimb.attack.SecondaryCoolDownTimer <= 0)
{
// Don't allow attacking when the attack target has just changed.
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
{
canAttack = false;
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
{
// Fall back if cannot attack.
UpdateFallBack(attackWorldPos, deltaTime);
return;
}
attackingLimb = null;
AttackingLimb = null;
}
else
{
// If the secondary cooldown is defined and expired, check if we can switch the attack
var previousLimb = attackingLimb;
var previousLimb = AttackingLimb;
var newLimb = GetAttackLimb(attackWorldPos, previousLimb);
if (newLimb != null)
{
attackingLimb = newLimb;
AttackingLimb = newLimb;
}
else
{
// No new limb was found.
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
{
canAttack = false;
}
@@ -657,20 +667,20 @@ namespace Barotrauma
}
}
if (attackingLimb == null || _previousAiTarget != SelectedAiTarget)
if (AttackingLimb == null || _previousAiTarget != SelectedAiTarget)
{
attackingLimb = GetAttackLimb(attackWorldPos);
AttackingLimb = GetAttackLimb(attackWorldPos);
}
if (canAttack)
{
canAttack = attackingLimb != null && attackingLimb.attack.CoolDownTimer <= 0;
canAttack = AttackingLimb != null && AttackingLimb.attack.CoolDownTimer <= 0;
}
float distance = 0;
if (canAttack)
{
// Check that we can reach the target
distance = Vector2.Distance(attackingLimb.WorldPosition, attackWorldPos);
canAttack = distance < attackingLimb.attack.Range;
distance = Vector2.Distance(AttackingLimb.WorldPosition, attackWorldPos);
canAttack = distance < AttackingLimb.attack.Range;
}
// If the attacking limb is a hand or claw, for example, using it as the steering limb can end in the result where the character circles around the target. For example the Hammerhead steering with the claws when it should use the torso.
@@ -679,7 +689,7 @@ namespace Barotrauma
Limb steeringLimb;
var torso = Character.AnimController.GetLimb(LimbType.Torso);
var head = Character.AnimController.GetLimb(LimbType.Head);
if (attackingLimb == null)
if (AttackingLimb == null)
{
steeringLimb = head ?? torso;
}
@@ -687,7 +697,7 @@ namespace Barotrauma
{
if (head != null && torso != null)
{
steeringLimb = Vector2.DistanceSquared(attackingLimb.SimPosition, head.SimPosition) < Vector2.DistanceSquared(attackingLimb.SimPosition, torso.SimPosition) ? head : torso;
steeringLimb = Vector2.DistanceSquared(AttackingLimb.SimPosition, head.SimPosition) < Vector2.DistanceSquared(AttackingLimb.SimPosition, torso.SimPosition) ? head : torso;
}
else
{
@@ -738,7 +748,7 @@ namespace Barotrauma
if (canAttack)
{
UpdateLimbAttack(deltaTime, attackingLimb, attackSimPos, distance);
UpdateLimbAttack(deltaTime, AttackingLimb, attackSimPos, distance);
}
}
@@ -755,7 +765,7 @@ namespace Barotrauma
{
targetWorldPos.X = targetHull.WorldRect.Center.X;
}
latchOntoAI?.DeattachFromBody();
LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs();
if (steeringManager is IndoorsSteeringManager)
{
@@ -778,6 +788,7 @@ namespace Barotrauma
.Where(l =>
l != ignoredLimb &&
l.attack != null &&
l.attack.CoolDownTimer <= 0 &&
!l.IsSevered &&
!l.IsStuck &&
l.attack.IsValidContext(currentContext) &&
@@ -846,7 +857,7 @@ namespace Barotrauma
attachTargetNormal = new Vector2(Math.Sign(WorldPosition.X - wall.WorldPosition.X), 0.0f);
sectionPos.X += (wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2 * attachTargetNormal.X;
}
latchOntoAI?.SetAttachTarget(wall.Submarine.PhysicsBody.FarseerBody, wall.Submarine, ConvertUnits.ToSimUnits(sectionPos), attachTargetNormal);
LatchOntoAI?.SetAttachTarget(wall.Submarine.PhysicsBody.FarseerBody, wall.Submarine, ConvertUnits.ToSimUnits(sectionPos), attachTargetNormal);
wallTarget = new WallTarget(sectionPos, wall, sectionIndex);
}
}
@@ -864,7 +875,7 @@ namespace Barotrauma
}
}
latchOntoAI?.DeattachFromBody();
LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs();
if (attacker == null || attacker.AiTarget == null) return;
@@ -974,7 +985,7 @@ namespace Barotrauma
#region Targeting
private bool IsProperlyLatched => latchOntoAI != null && latchOntoAI.IsAttached && SelectedAiTarget?.Entity == wallTarget?.Structure;
private bool IsProperlyLatched => LatchOntoAI != null && LatchOntoAI.IsAttached && SelectedAiTarget?.Entity == wallTarget?.Structure;
//goes through all the AItargets, evaluates how preferable it is to attack the target,
//whether the Character can see/hear the target and chooses the most preferable target within
@@ -1232,10 +1243,11 @@ namespace Barotrauma
protected override void OnStateChanged(AIState from, AIState to)
{
latchOntoAI?.DeattachFromBody();
LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs();
escapePoint = Vector2.Zero;
wallTarget = null;
AttackingLimb = null;
}
private int GetMinimumPassableHoleCount()
@@ -344,6 +344,8 @@ namespace Barotrauma
}
}
public bool reverse;
void UpdateSineAnim(float deltaTime)
{
if (CurrentSwimParams == null) { return; }
@@ -367,8 +369,8 @@ namespace Barotrauma
return;
}
float movementAngle = MathUtils.VectorToAngle(movement) - MathHelper.PiOver2;
Vector2 transformedMovement = reverse ? -movement : movement;
float movementAngle = MathUtils.VectorToAngle(transformedMovement) - MathHelper.PiOver2;
float mainLimbAngle = 0;
if (MainLimb.type == LimbType.Torso && TorsoAngle.HasValue)
{
@@ -386,7 +388,7 @@ namespace Barotrauma
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) < -MathHelper.Pi)
{
movementAngle -= MathHelper.TwoPi;
}
}
if (CurrentSwimParams.RotateTowardsMovement)
{
@@ -410,16 +412,19 @@ namespace Barotrauma
if (TailAngle.HasValue)
{
Limb tail = GetLimb(LimbType.Tail);
//tail?.body.SmoothRotate(movementAngle + TailAngle.Value * Dir, TailTorque);
if (tail != null)
{
SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, MainLimb, TailTorque);
}
}
}
else
else if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
{
movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2;
if (reverse)
{
movementAngle = MathUtils.WrapAngleTwoPi(movementAngle - MathHelper.Pi);
}
if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
{
Collider.SmoothRotate(HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque);
@@ -449,7 +454,7 @@ namespace Barotrauma
var waveAmplitude = Math.Abs(CurrentSwimParams.WaveAmplitude);
if (waveLength > 0 && waveAmplitude > 0)
{
WalkPos -= movement.Length() / Math.Abs(waveLength);
WalkPos -= transformedMovement.Length() / Math.Abs(waveLength);
WalkPos = MathUtils.WrapAngleTwoPi(WalkPos);
}
@@ -81,6 +81,9 @@ namespace Barotrauma
[Serialize(AIBehaviorAfterAttack.FallBack, true), Editable(ToolTip = "The preferred AI behavior after the attack.")]
public AIBehaviorAfterAttack AfterAttack { get; private set; }
[Serialize(false, true), Editable(ToolTip = "Should the ai try to reverse when aiming with this attack?")]
public bool Reverse { get; private set; }
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2000.0f, ToolTip = "Min distance from the attack limb to the target before the AI tries to attack.")]
public float Range { get; private set; }
@@ -1186,6 +1186,10 @@ namespace Barotrauma
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.F))
{
AnimController.ReleaseStuckLimbs();
if (AIController != null && AIController is EnemyAIController enemyAI)
{
enemyAI.LatchOntoAI?.DeattachFromBody();
}
}
#endif
@@ -1652,8 +1656,7 @@ namespace Barotrauma
#if CLIENT
if (isLocalPlayer)
{
if (GUI.MouseOn == null &&
(!CharacterInventory.IsMouseOnInventory() || CharacterInventory.DraggingItemToWorld))
if (GUI.MouseOn == null && !CharacterInventory.IsMouseOnInventory())
{
if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen)
{