2f107db...5202af9

This commit is contained in:
Joonas Rikkonen
2019-03-18 21:42:26 +02:00
parent 58c92888b7
commit 044fd3344b
395 changed files with 27417 additions and 19754 deletions
@@ -88,9 +88,7 @@ namespace Barotrauma
private AITargetMemory selectedTargetMemory;
private float targetValue;
private float eatTimer;
private Dictionary<AITarget, AITargetMemory> targetMemories;
//the eyesight of the NPC (0.0 = blind, 1.0 = sees every target within sightRange)
@@ -250,7 +248,7 @@ namespace Barotrauma
public override void SelectTarget(AITarget target)
{
selectedAiTarget = target;
SelectedAiTarget = target;
selectedTargetMemory = FindTargetMemory(target);
targetValue = 100.0f;
@@ -292,7 +290,7 @@ namespace Barotrauma
UpdateTargets(Character, out targetingPriority);
updateTargetsTimer = UpdateTargetsInterval;
if (selectedAiTarget == null)
if (SelectedAiTarget == null)
{
State = AIState.Idle;
}
@@ -308,7 +306,7 @@ namespace Barotrauma
latchOntoAI?.Update(this, deltaTime);
if (selectedAiTarget != null && (selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed))
if (SelectedAiTarget != null && (SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed))
{
State = AIState.Idle;
return;
@@ -368,9 +366,9 @@ namespace Barotrauma
if (wallTarget != null) return;
if (selectedAiTarget != null)
if (SelectedAiTarget != null)
{
Vector2 targetSimPos = Character.Submarine == null ? ConvertUnits.ToSimUnits(selectedAiTarget.WorldPosition) : selectedAiTarget.SimPosition;
Vector2 targetSimPos = Character.Submarine == null ? ConvertUnits.ToSimUnits(SelectedAiTarget.WorldPosition) : SelectedAiTarget.SimPosition;
steeringManager.SteeringAvoid(deltaTime, colliderSize * 3.0f, speed);
steeringManager.SteeringSeek(targetSimPos, speed);
@@ -392,13 +390,13 @@ namespace Barotrauma
private void UpdateEscape(float deltaTime)
{
if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed)
if (SelectedAiTarget == null || SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed)
{
State = AIState.Idle;
return;
}
Vector2 escapeDir = Vector2.Normalize(SimPosition - selectedAiTarget.SimPosition);
Vector2 escapeDir = Vector2.Normalize(SimPosition - SelectedAiTarget.SimPosition);
if (!MathUtils.IsValid(escapeDir)) escapeDir = Vector2.UnitY;
float speed = Character.AnimController.GetCurrentSpeed(useMaxSpeed: true);
SteeringManager.SteeringManual(deltaTime, escapeDir * speed);
@@ -415,7 +413,7 @@ namespace Barotrauma
private void UpdateAttack(float deltaTime)
{
if (selectedAiTarget == null)
if (SelectedAiTarget == null)
{
State = AIState.Idle;
return;
@@ -425,23 +423,23 @@ namespace Barotrauma
selectedTargetMemory.Priority -= deltaTime * 0.1f;
Vector2 attackSimPosition = Character.Submarine == null ? ConvertUnits.ToSimUnits(selectedAiTarget.WorldPosition) : selectedAiTarget.SimPosition;
Vector2 attackSimPosition = Character.Submarine == null ? ConvertUnits.ToSimUnits(SelectedAiTarget.WorldPosition) : SelectedAiTarget.SimPosition;
if (Character.Submarine != null && selectedAiTarget.Entity.Submarine != null && Character.Submarine != selectedAiTarget.Entity.Submarine)
if (Character.Submarine != null && SelectedAiTarget.Entity.Submarine != null && Character.Submarine != SelectedAiTarget.Entity.Submarine)
{
attackSimPosition = ConvertUnits.ToSimUnits(selectedAiTarget.WorldPosition - Character.Submarine.Position);
attackSimPosition = ConvertUnits.ToSimUnits(SelectedAiTarget.WorldPosition - Character.Submarine.Position);
}
if (selectedAiTarget.Entity is Item item)
if (SelectedAiTarget.Entity is Item item)
{
// If the item is held by a character, attack the character instead.
var pickable = item.components.Select(c => c as Pickable).FirstOrDefault();
var pickable = item.GetComponent<Pickable>();
if (pickable != null)
{
var target = pickable.Picker?.AiTarget;
if (target != null)
{
selectedAiTarget = target;
SelectedAiTarget = target;
}
}
}
@@ -449,13 +447,13 @@ namespace Barotrauma
if (wallTarget != null)
{
attackSimPosition = ConvertUnits.ToSimUnits(wallTarget.Position);
if (Character.Submarine == null && selectedAiTarget.Entity?.Submarine != null) attackSimPosition += ConvertUnits.ToSimUnits(selectedAiTarget.Entity.Submarine.Position);
if (Character.Submarine == null && SelectedAiTarget.Entity?.Submarine != null) attackSimPosition += ConvertUnits.ToSimUnits(SelectedAiTarget.Entity.Submarine.Position);
}
else if (selectedAiTarget.Entity is Character)
else if (SelectedAiTarget.Entity is Character)
{
//target the closest limb if the target is a character
float closestDist = Vector2.DistanceSquared(selectedAiTarget.SimPosition, SimPosition) * 10.0f;
foreach (Limb limb in ((Character)selectedAiTarget.Entity).AnimController.Limbs)
float closestDist = Vector2.DistanceSquared(SelectedAiTarget.SimPosition, SimPosition) * 10.0f;
foreach (Limb limb in ((Character)SelectedAiTarget.Entity).AnimController.Limbs)
{
if (limb == null) continue;
float dist = Vector2.DistanceSquared(limb.SimPosition, SimPosition) / Math.Max(limb.AttackPriority, 0.1f);
@@ -514,9 +512,9 @@ namespace Barotrauma
return;
}
}
else if (selectedAiTarget.Entity is Item)
else if (SelectedAiTarget.Entity is Item)
{
var door = ((Item)selectedAiTarget.Entity).GetComponent<Door>();
var door = ((Item)SelectedAiTarget.Entity).GetComponent<Door>();
//steer through the door manually if it's open or broken
if (door?.LinkedGap?.FlowTargetHull != null && !door.LinkedGap.IsRoomToRoom && (door.IsOpen || door.Item.Condition <= 0.0f))
{
@@ -566,24 +564,39 @@ namespace Barotrauma
{
if (attackingLimb.attack.SecondaryCoolDownTimer <= 0)
{
// If the secondary cooldown is defined and expired, check if we can switch the attack
var previousLimb = attackingLimb;
var newLimb = GetAttackLimb(attackSimPosition, previousLimb);
if (newLimb != null)
// Don't allow attacking when the attack target has changed.
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
{
attackingLimb = newLimb;
canAttack = false;
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
{
// Fall back if cannot attack.
UpdateFallBack(attackSimPosition, deltaTime);
return;
}
attackingLimb = null;
}
else
{
// No new limb was found.
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
// If the secondary cooldown is defined and expired, check if we can switch the attack
var previousLimb = attackingLimb;
var newLimb = GetAttackLimb(attackSimPosition, previousLimb);
if (newLimb != null)
{
canAttack = false;
attackingLimb = newLimb;
}
else
{
UpdateFallBack(attackSimPosition, deltaTime);
return;
// No new limb was found.
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
{
canAttack = false;
}
else
{
UpdateFallBack(attackSimPosition, deltaTime);
return;
}
}
}
}
@@ -648,12 +661,12 @@ namespace Barotrauma
else if (indoorsSteering.CurrentPath.CurrentNode?.ConnectedDoor != null)
{
wallTarget = null;
selectedAiTarget = indoorsSteering.CurrentPath.CurrentNode.ConnectedDoor.Item.AiTarget;
SelectedAiTarget = indoorsSteering.CurrentPath.CurrentNode.ConnectedDoor.Item.AiTarget;
}
else if (indoorsSteering.CurrentPath.NextNode?.ConnectedDoor != null)
{
wallTarget = null;
selectedAiTarget = indoorsSteering.CurrentPath.NextNode.ConnectedDoor.Item.AiTarget;
SelectedAiTarget = indoorsSteering.CurrentPath.NextNode.ConnectedDoor.Item.AiTarget;
}
}
}
@@ -668,7 +681,7 @@ namespace Barotrauma
private Limb GetAttackLimb(Vector2 attackSimPosition, Limb ignoredLimb = null)
{
AttackContext currentContext = Character.GetAttackContext();
var target = wallTarget != null ? wallTarget.Structure : selectedAiTarget.Entity;
var target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget.Entity;
var limbs = Character.AnimController.Limbs
.Where(l =>
l != ignoredLimb &&
@@ -677,7 +690,7 @@ namespace Barotrauma
!l.IsStuck &&
l.attack.IsValidContext(currentContext) &&
l.attack.IsValidTarget(target) &&
l.attack.Conditionals.All(c => (target is ISerializableEntity se && c.Matches(se)) || !(target is ISerializableEntity)))
l.attack.Conditionals.All(c => (target is ISerializableEntity se && c.Matches(se)) || !(target is ISerializableEntity) || !(target is Character)))
.OrderByDescending(l => l.attack.Priority)
.ThenBy(l => ConvertUnits.ToDisplayUnits(Vector2.Distance(l.SimPosition, attackSimPosition)));
// TODO: priority should probably not override the distance -> use values instead of booleans
@@ -695,11 +708,11 @@ namespace Barotrauma
//check if there's a wall between the target and the Character
Vector2 rayStart = Character.SimPosition;
Vector2 rayEnd = selectedAiTarget.SimPosition;
Vector2 rayEnd = SelectedAiTarget.SimPosition;
if (selectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
if (SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
{
rayStart -= ConvertUnits.ToSimUnits(selectedAiTarget.Entity.Submarine.Position);
rayStart -= ConvertUnits.ToSimUnits(SelectedAiTarget.Entity.Submarine.Position);
}
Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd);
@@ -795,7 +808,7 @@ namespace Barotrauma
private void UpdateLimbAttack(float deltaTime, Limb limb, Vector2 attackPosition, float distance = -1)
{
var damageTarget = wallTarget != null ? wallTarget.Structure : selectedAiTarget.Entity as IDamageable;
var damageTarget = wallTarget != null ? wallTarget.Structure : SelectedAiTarget.Entity as IDamageable;
if (damageTarget == null) return;
float prevHealth = damageTarget.Health;
@@ -834,7 +847,7 @@ namespace Barotrauma
private void UpdateEating(float deltaTime)
{
if (selectedAiTarget == null)
if (SelectedAiTarget == null)
{
State = AIState.Idle;
return;
@@ -850,13 +863,13 @@ namespace Barotrauma
}
Vector2 mouthPos = Character.AnimController.GetMouthPosition().Value;
Vector2 attackSimPosition = Character.Submarine == null ? ConvertUnits.ToSimUnits(selectedAiTarget.WorldPosition) : selectedAiTarget.SimPosition;
Vector2 attackSimPosition = Character.Submarine == null ? ConvertUnits.ToSimUnits(SelectedAiTarget.WorldPosition) : SelectedAiTarget.SimPosition;
Vector2 limbDiff = attackSimPosition - mouthPos;
float limbDist = limbDiff.Length();
if (limbDist < 2.0f)
{
Character.SelectCharacter(selectedAiTarget.Entity as Character);
Character.SelectCharacter(SelectedAiTarget.Entity as Character);
steeringManager.SteeringManual(deltaTime, limbDiff);
Character.AnimController.Collider.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f, mouthPos);
}
@@ -875,10 +888,8 @@ namespace Barotrauma
//sight/hearing range
public void UpdateTargets(Character character, out TargetingPriority targetingPriority)
{
var prevAiTarget = selectedAiTarget;
targetingPriority = null;
selectedAiTarget = null;
SelectedAiTarget = null;
selectedTargetMemory = null;
targetValue = 0.0f;
@@ -936,11 +947,9 @@ namespace Barotrauma
//skip the target if it's a room and the character is already inside a sub
if (character.CurrentHull != null && target.Entity is Hull) continue;
//multiply the priority of the target if it's a door from outside to inside and the AI is an aggressive boarder
Door door = null;
if (target.Entity is Item item)
{
//item inside and we're outside -> attack the hull
if (item.CurrentHull != null && character.CurrentHull == null)
{
@@ -963,21 +972,20 @@ namespace Barotrauma
}
if (door != null)
{
{
//increase priority if the character is outside and an aggressive boarder, and the door is from outside to inside
if (character.CurrentHull == null && aggressiveBoarding && !door.LinkedGap.IsRoomToRoom)
{
valueModifier = door.IsOpen ? 5.0f : 3.0f;
valueModifier = door.IsOpen ? 10 : 5;
}
else if (door.IsOpen || door.Item.Condition <= 0.0f) //ignore broken and open doors
{
continue;
}
}
else
else if (target.Entity is IDamageable targetDamageable && targetDamageable.Health <= 0.0f)
{
IDamageable targetDamageable = target.Entity as IDamageable;
if (targetDamageable != null && targetDamageable.Health <= 0.0f) continue;
continue;
}
}
@@ -988,7 +996,8 @@ namespace Barotrauma
if (valueModifier == 0.0f) continue;
dist = Vector2.Distance(character.WorldPosition, target.WorldPosition);
Vector2 toTarget = target.WorldPosition - character.WorldPosition;
dist = toTarget.Length();
//if the target has been within range earlier, the character will notice it more easily
//(i.e. remember where the target was)
@@ -1003,21 +1012,27 @@ namespace Barotrauma
dist = Math.Max(dist, 100.0f);
AITargetMemory targetMemory = FindTargetMemory(target);
if (Character.CurrentHull != null && Math.Abs(toTarget.Y) > Character.CurrentHull.Size.Y)
{
// Inside the sub, treat objects that are up or down, as they were farther away.
dist *= 3;
}
valueModifier = valueModifier * targetMemory.Priority / (float)Math.Sqrt(dist);
if (valueModifier > targetValue)
{
selectedAiTarget = target;
SelectedAiTarget = target;
selectedTargetMemory = targetMemory;
targetingPriority = targetingPriorities[targetingTag];
targetValue = valueModifier;
}
}
if (selectedAiTarget != prevAiTarget)
if (SelectedAiTarget != _previousAiTarget)
{
wallTarget = null;
}
}
_previousAiTarget = SelectedAiTarget;
}
//find the targetMemory that corresponds to some AItarget or create if there isn't one yet