diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs index 3c5e54192..21fbeea06 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs @@ -331,8 +331,6 @@ namespace Barotrauma } } - LatchOntoAI?.Update(this, deltaTime); - if (SelectedAiTarget != null && (SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed)) { State = AIState.Idle; @@ -372,6 +370,9 @@ namespace Barotrauma } SwarmBehavior?.Update(deltaTime); + + LatchOntoAI?.Update(this, deltaTime); + IsSteeringThroughGap = false; steeringManager.Update(Character.AnimController.GetCurrentSpeed(run)); } @@ -794,9 +795,21 @@ namespace Barotrauma } } + public bool IsSteeringThroughGap { get; private set; } private bool SteerThroughGap(Structure wall, WallSection section, Vector2 targetWorldPos, float deltaTime) { + IsSteeringThroughGap = true; + SelectedAiTarget = wall.AiTarget; + wallTarget = null; + LatchOntoAI?.DeattachFromBody(); + Character.AnimController.ReleaseStuckLimbs(); Hull targetHull = section.gap?.FlowTargetHull; + float distance = Vector2.Distance(Character.WorldPosition, targetWorldPos); + float maxDistance = Math.Min(wall.Rect.Width, wall.Rect.Height); + if (distance > maxDistance) + { + return false; + } if (targetHull != null) { if (wall.IsHorizontal) @@ -807,16 +820,7 @@ namespace Barotrauma { targetWorldPos.X = targetHull.WorldRect.Center.X; } - LatchOntoAI?.DeattachFromBody(); - Character.AnimController.ReleaseStuckLimbs(); - if (steeringManager is IndoorsSteeringManager) - { - steeringManager.SteeringManual(deltaTime, Vector2.Normalize(targetWorldPos - Character.WorldPosition)); - } - else - { - steeringManager.SteeringSeek(ConvertUnits.ToSimUnits(targetWorldPos)); - } + steeringManager.SteeringManual(deltaTime, Vector2.Normalize(targetWorldPos - Character.WorldPosition)); return true; } return false; @@ -1053,9 +1057,13 @@ namespace Barotrauma //sight/hearing range public AITarget UpdateTargets(Character character, out TargetingPriority priority) { - if (IsLatchedOnSub) + if ((SelectedAiTarget != null || wallTarget != null) && IsLatchedOnSub) { var wall = SelectedAiTarget.Entity as Structure; + if (wall == null) + { + wall = wallTarget.Structure; + } // The target is not a wall or it's not the same as we are attached to -> release bool releaseTarget = wall == null || !wall.Bodies.Contains(LatchOntoAI.AttachJoints[0].BodyB); if (!releaseTarget) @@ -1071,9 +1079,10 @@ namespace Barotrauma if (releaseTarget) { SelectedAiTarget = null; + wallTarget = null; LatchOntoAI.DeattachFromBody(); } - else if (SelectedAiTarget.Entity == wallTarget?.Structure) + else if (SelectedAiTarget?.Entity == wallTarget?.Structure) { // If attached to a valid target, just keep the target. // Priority not used in this case. @@ -1195,26 +1204,33 @@ namespace Barotrauma { continue; } + if (character.CurrentHull != null) + { + // Ignore walls when inside. + continue; + } + valueModifier = 1; float wallMaxHealth = 400; // Anything more than this is ignored -> 200 = 1 // Prefer weaker targets. - valueModifier = MathHelper.Lerp(2, 0, MathHelper.Clamp(s.Health / wallMaxHealth, 0, 1)); - // Ignore walls when inside. - valueModifier = character.CurrentHull == null ? 1 : 0; + valueModifier *= MathHelper.Lerp(1.5f, 0.5f, MathUtils.InverseLerp(0, 1, s.Health / wallMaxHealth)); if (aggressiveBoarding) { + var hulls = s.Submarine.GetHulls(false); for (int i = 0; i < s.Sections.Length; i++) { var section = s.Sections[i]; - if (CanPassThroughHole(s, i)) + if (section.gap != null) { - // Ignore walls that can be passed through - valueModifier = 0; - break; - } - else if (section.gap != null) - { - // up to 100% priority increase for every gap in the wall - valueModifier *= 1 + section.gap.Open; + if (CanPassThroughHole(s, i)) + { + bool leadsInside = !section.gap.IsRoomToRoom && section.gap.FlowTargetHull != null && hulls.Any(h => h.Rect.Intersects(section.rect)); + valueModifier *= leadsInside ? 5 : 0; + } + else + { + // up to 100% priority increase for every gap in the wall + valueModifier *= 1 + section.gap.Open; + } } } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/LatchOntoAI.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/LatchOntoAI.cs index c85b2caa7..e68f9a3a2 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/LatchOntoAI.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/LatchOntoAI.cs @@ -54,7 +54,7 @@ namespace Barotrauma get { return attachJoints.Count > 0; } } - public bool IsAttachedToSub => IsAttached && attachTargetBody?.UserData is Entity entity && (entity is Submarine sub || entity?.Submarine != null); + public bool IsAttachedToSub => IsAttached && (attachTargetBody?.UserData is Submarine || attachTargetBody?.UserData is Entity entity && entity.Submarine != null); public LatchOntoAI(XElement element, EnemyAIController enemyAI) { @@ -190,7 +190,7 @@ namespace Barotrauma case AIController.AIState.Attack: if (enemyAI.AttackingLimb != null) { - if (attachToSub && wallAttachPos != Vector2.Zero && attachTargetBody != null) + if (attachToSub && !enemyAI.IsSteeringThroughGap && wallAttachPos != Vector2.Zero && attachTargetBody != null) { // is not attached or is attached to something else if (!IsAttached || IsAttached && attachJoints[0].BodyB == attachTargetBody) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index 435f0fd7d..ba902de7f 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -2555,6 +2555,10 @@ namespace Barotrauma GameMain.GameSession?.CrewManager?.RemoveCharacter(this); #endif +#if CLIENT + GameMain.GameSession?.CrewManager?.RemoveCharacter(this); +#endif + #if CLIENT GameMain.GameSession?.CrewManager?.RemoveCharacter(this); #endif